You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

168 lines
4.4 KiB

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
  1. package main
  2. import (
  3. "encoding/hex"
  4. "flag"
  5. "fmt"
  6. acm "github.com/tendermint/tendermint/account"
  7. . "github.com/tendermint/tendermint/common"
  8. "github.com/tendermint/tendermint/rpc/client"
  9. ctypes "github.com/tendermint/tendermint/rpc/core/types"
  10. cclient "github.com/tendermint/tendermint/rpc/core_client"
  11. "github.com/tendermint/tendermint/types"
  12. )
  13. const Version = "0.0.1"
  14. const sleepSeconds = 1 // Every second
  15. // Parse command-line options
  16. func parseFlags() (privKeyHex string, numAccounts int, remote string) {
  17. var version bool
  18. flag.StringVar(&privKeyHex, "priv-key", "", "Private key bytes in HEX")
  19. flag.IntVar(&numAccounts, "num-accounts", 1000, "Deterministically generates this many sub-accounts")
  20. flag.StringVar(&remote, "remote", "localhost:46657", "Remote RPC host:port")
  21. flag.BoolVar(&version, "version", false, "Version")
  22. flag.Parse()
  23. if version {
  24. Exit(Fmt("sim_txs version %v", Version))
  25. }
  26. return
  27. }
  28. func main() {
  29. // Read options
  30. privKeyHex, numAccounts, remote := parseFlags()
  31. // Print args.
  32. // fmt.Println(privKeyHex, numAccounts, remote)
  33. privKeyBytes, err := hex.DecodeString(privKeyHex)
  34. if err != nil {
  35. panic(err)
  36. }
  37. root := acm.GenPrivAccountFromPrivKeyBytes(privKeyBytes)
  38. fmt.Println("Computed address: %X", root.Address)
  39. // Get root account.
  40. rootAccount, err := getAccount(remote, root.Address)
  41. if err != nil {
  42. fmt.Println(Fmt("Root account %X does not exist: %v", root.Address, err))
  43. return
  44. } else {
  45. fmt.Println("Root account", rootAccount)
  46. }
  47. // Load all accounts
  48. accounts := make([]*acm.Account, numAccounts+1)
  49. accounts[0] = rootAccount
  50. privAccounts := make([]*acm.PrivAccount, numAccounts+1)
  51. privAccounts[0] = root
  52. for i := 1; i < numAccounts+1; i++ {
  53. privAccounts[i] = root.Generate(i)
  54. account, err := getAccount(remote, privAccounts[i].Address)
  55. if err != nil {
  56. fmt.Println("Error", err)
  57. return
  58. } else {
  59. accounts[i] = account
  60. }
  61. }
  62. // Test: send from root to accounts[1]
  63. sendTx := makeRandomTransaction(10, rootAccount.Sequence+1, root, 2, accounts)
  64. fmt.Println(sendTx)
  65. wsClient := cclient.NewWSClient("ws://" + remote + "/websocket")
  66. _, err = wsClient.Start()
  67. if err != nil {
  68. Exit(Fmt("Failed to establish websocket connection: %v", err))
  69. }
  70. wsClient.Subscribe(types.EventStringAccInput(sendTx.Inputs[0].Address))
  71. go func() {
  72. for {
  73. foo := <-wsClient.EventsCh
  74. fmt.Println("!!", foo)
  75. }
  76. }()
  77. err = broadcastSendTx(remote, sendTx)
  78. if err != nil {
  79. Exit(Fmt("Failed to broadcast SendTx: %v", err))
  80. return
  81. }
  82. // Trap signal
  83. TrapSignal(func() {
  84. fmt.Println("sim_txs shutting down")
  85. })
  86. }
  87. func getAccount(remote string, address []byte) (*acm.Account, error) {
  88. // var account *acm.Account = new(acm.Account)
  89. account, err := rpcclient.Call("http://"+remote, "get_account", []interface{}{address}, (*acm.Account)(nil))
  90. if err != nil {
  91. return nil, err
  92. }
  93. if account.(*acm.Account) == nil {
  94. return &acm.Account{Address: address}, nil
  95. } else {
  96. return account.(*acm.Account), nil
  97. }
  98. }
  99. func broadcastSendTx(remote string, sendTx *types.SendTx) error {
  100. receipt, err := rpcclient.Call("http://"+remote, "broadcast_tx", []interface{}{sendTx}, (*ctypes.Receipt)(nil))
  101. if err != nil {
  102. return err
  103. }
  104. fmt.Println("Broadcast receipt:", receipt)
  105. return nil
  106. }
  107. // Make a random send transaction from srcIndex to N other accounts.
  108. // balance: balance to send from input
  109. // sequence: sequence to sign with
  110. // inputPriv: input privAccount
  111. func makeRandomTransaction(balance int64, sequence int, inputPriv *acm.PrivAccount, sendCount int, accounts []*acm.Account) *types.SendTx {
  112. if sendCount >= len(accounts) {
  113. PanicSanity("Cannot make tx with sendCount >= len(accounts)")
  114. }
  115. // Remember which accounts were chosen
  116. accMap := map[string]struct{}{}
  117. accMap[string(inputPriv.Address)] = struct{}{}
  118. // Find a selection of accounts to send to
  119. outputs := []*acm.Account{}
  120. for i := 0; i < sendCount; i++ {
  121. for {
  122. idx := RandInt() % len(accounts)
  123. account := accounts[idx]
  124. if _, ok := accMap[string(account.Address)]; ok {
  125. continue
  126. }
  127. accMap[string(account.Address)] = struct{}{}
  128. outputs = append(outputs, account)
  129. break
  130. }
  131. }
  132. // Construct SendTx
  133. sendTx := types.NewSendTx()
  134. err := sendTx.AddInputWithNonce(inputPriv.PubKey, balance, sequence)
  135. if err != nil {
  136. panic(err)
  137. }
  138. for _, output := range outputs {
  139. sendTx.AddOutput(output.Address, balance/int64(len(outputs)))
  140. }
  141. // Sign SendTx
  142. sendTx.SignInput("tendermint_testnet_9", 0, inputPriv)
  143. return sendTx
  144. }