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

9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 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. }