|
|
@ -1,11 +1,9 @@ |
|
|
|
package main |
|
|
|
|
|
|
|
import ( |
|
|
|
"bytes" |
|
|
|
"encoding/hex" |
|
|
|
"flag" |
|
|
|
"fmt" |
|
|
|
"time" |
|
|
|
|
|
|
|
acm "github.com/tendermint/tendermint/account" |
|
|
|
. "github.com/tendermint/tendermint/common" |
|
|
@ -18,26 +16,26 @@ const Version = "0.0.1" |
|
|
|
const sleepSeconds = 1 // Every second
|
|
|
|
|
|
|
|
// Parse command-line options
|
|
|
|
func parseFlags() (privKeyHex string, numAccounts int, remote string, version bool) { |
|
|
|
func parseFlags() (privKeyHex string, numAccounts int, remote string) { |
|
|
|
var version bool |
|
|
|
flag.StringVar(&privKeyHex, "priv-key", "", "Private key bytes in HEX") |
|
|
|
flag.IntVar(&numAccounts, "num-accounts", 1000, "Deterministically generates this many sub-accounts") |
|
|
|
flag.StringVar(&remote, "remote", "http://localhost:46657", "Remote RPC host:port") |
|
|
|
flag.BoolVar(&version, "version", false, "Version") |
|
|
|
flag.Parse() |
|
|
|
if version { |
|
|
|
Exit(Fmt("sim_txs version %v", Version)) |
|
|
|
} |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
func main() { |
|
|
|
|
|
|
|
// Read options
|
|
|
|
privKeyHex, numAccounts, remote, version := parseFlags() |
|
|
|
if version { |
|
|
|
fmt.Println(Fmt("sim_txs version %v", Version)) |
|
|
|
return |
|
|
|
} |
|
|
|
privKeyHex, numAccounts, remote := parseFlags() |
|
|
|
|
|
|
|
// Print args.
|
|
|
|
// fmt.Println(privKeyHex, numAccounts, remote, version)
|
|
|
|
// fmt.Println(privKeyHex, numAccounts, remote)
|
|
|
|
|
|
|
|
privKeyBytes, err := hex.DecodeString(privKeyHex) |
|
|
|
if err != nil { |
|
|
@ -57,33 +55,55 @@ func main() { |
|
|
|
fmt.Println("Root account", rootAccount) |
|
|
|
} |
|
|
|
|
|
|
|
go func() { |
|
|
|
// Construct a new send Tx
|
|
|
|
accounts := make([]*acm.Account, numAccounts) |
|
|
|
privAccounts := make([]*acm.PrivAccount, numAccounts) |
|
|
|
for i := 0; i < numAccounts; i++ { |
|
|
|
privAccounts[i] = root.Generate(i) |
|
|
|
account, err := getAccount(remote, privAccounts[i].Address) |
|
|
|
if err != nil { |
|
|
|
fmt.Println("Error", err) |
|
|
|
return |
|
|
|
} else { |
|
|
|
accounts[i] = account |
|
|
|
} |
|
|
|
// Load all accounts
|
|
|
|
accounts := make([]*acm.Account, numAccounts+1) |
|
|
|
accounts[0] = rootAccount |
|
|
|
privAccounts := make([]*acm.PrivAccount, numAccounts+1) |
|
|
|
privAccounts[0] = root |
|
|
|
for i := 1; i < numAccounts; i++ { |
|
|
|
privAccounts[i] = root.Generate(i) |
|
|
|
account, err := getAccount(remote, privAccounts[i].Address) |
|
|
|
if err != nil { |
|
|
|
fmt.Println("Error", err) |
|
|
|
return |
|
|
|
} else { |
|
|
|
accounts[i] = account |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Test: send from root to accounts[1]
|
|
|
|
sendTx := makeRandomTransaction(10, rootAccount.Sequence+1, root, 2, accounts) |
|
|
|
fmt.Println(sendTx) |
|
|
|
|
|
|
|
wsClient, err := rpcclient.NewWSClient("http://localhost:46657/websocket") |
|
|
|
if err != nil { |
|
|
|
Exit(Fmt("Failed to establish websocket connection: %v", err)) |
|
|
|
} |
|
|
|
wsClient.Subscribe(types.EventStringAccInput(sendTx.Outputs[0].Address)) |
|
|
|
|
|
|
|
go func() { |
|
|
|
for { |
|
|
|
sendTx := makeRandomTransaction(rootAccount, root, accounts, privAccounts) |
|
|
|
// Broadcast it.
|
|
|
|
err := broadcastSendTx(remote, sendTx) |
|
|
|
if err != nil { |
|
|
|
Exit(Fmt("Failed to broadcast SendTx: %v", err)) |
|
|
|
return |
|
|
|
} |
|
|
|
// Broadcast 1 tx!
|
|
|
|
time.Sleep(10 * time.Millisecond) |
|
|
|
foo := <-wsClient.EventsCh |
|
|
|
fmt.Println("!!", foo) |
|
|
|
} |
|
|
|
}() |
|
|
|
|
|
|
|
/* |
|
|
|
go func() { |
|
|
|
for { |
|
|
|
sendTx := makeRandomTransaction(rootAccount, root, accounts, privAccounts) |
|
|
|
// Broadcast it.
|
|
|
|
err := broadcastSendTx(remote, sendTx) |
|
|
|
if err != nil { |
|
|
|
Exit(Fmt("Failed to broadcast SendTx: %v", err)) |
|
|
|
return |
|
|
|
} |
|
|
|
// Broadcast 1 tx!
|
|
|
|
time.Sleep(10 * time.Millisecond) |
|
|
|
} |
|
|
|
}() |
|
|
|
*/ |
|
|
|
|
|
|
|
// Trap signal
|
|
|
|
TrapSignal(func() { |
|
|
|
fmt.Println("sim_txs shutting down") |
|
|
@ -112,64 +132,43 @@ func broadcastSendTx(remote string, sendTx *types.SendTx) error { |
|
|
|
return nil |
|
|
|
} |
|
|
|
|
|
|
|
func makeRandomTransaction(rootAccount *acm.Account, rootPrivAccount *acm.PrivAccount, accounts []*acm.Account, privAccounts []*acm.PrivAccount) *types.SendTx { |
|
|
|
allAccounts := append(accounts, rootAccount) |
|
|
|
allPrivAccounts := append(privAccounts, rootPrivAccount) |
|
|
|
|
|
|
|
// Find accout with the most money
|
|
|
|
inputBalance := int64(0) |
|
|
|
inputAccount := (*acm.Account)(nil) |
|
|
|
inputPrivAccount := (*acm.PrivAccount)(nil) |
|
|
|
for i, account := range allAccounts { |
|
|
|
if account == nil { |
|
|
|
continue |
|
|
|
} |
|
|
|
if inputBalance < account.Balance { |
|
|
|
inputBalance = account.Balance |
|
|
|
inputAccount = account |
|
|
|
inputPrivAccount = allPrivAccounts[i] |
|
|
|
} |
|
|
|
} |
|
|
|
if inputAccount == nil { |
|
|
|
Exit("No accounts have any money") |
|
|
|
return nil |
|
|
|
} |
|
|
|
// Make a random send transaction from srcIndex to N other accounts.
|
|
|
|
// balance: balance to send from input
|
|
|
|
// sequence: sequence to sign with
|
|
|
|
// inputPriv: input privAccount
|
|
|
|
func makeRandomTransaction(balance int64, sequence int, inputPriv *acm.PrivAccount, sendCount int, accounts []*acm.Account) *types.SendTx { |
|
|
|
|
|
|
|
// Remember which accounts were chosen
|
|
|
|
accMap := map[string]struct{}{} |
|
|
|
accMap[string(inputPriv.Address)] = struct{}{} |
|
|
|
|
|
|
|
// Find a selection of accounts to send to
|
|
|
|
outputAccounts := map[string]*acm.Account{} |
|
|
|
for i := 0; i < 2; i++ { |
|
|
|
outputs := []*acm.Account{} |
|
|
|
for i := 0; i < sendCount; i++ { |
|
|
|
for { |
|
|
|
idx := RandInt() % len(accounts) |
|
|
|
if bytes.Equal(accounts[idx].Address, inputAccount.Address) { |
|
|
|
account := accounts[idx] |
|
|
|
if _, ok := accMap[string(account.Address)]; ok { |
|
|
|
continue |
|
|
|
} |
|
|
|
if _, ok := outputAccounts[string(accounts[idx].Address)]; ok { |
|
|
|
continue |
|
|
|
} |
|
|
|
outputAccounts[string(accounts[idx].Address)] = accounts[idx] |
|
|
|
accMap[string(account.Address)] = struct{}{} |
|
|
|
outputs = append(outputs, account) |
|
|
|
break |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Construct SendTx
|
|
|
|
sendTx := types.NewSendTx() |
|
|
|
err := sendTx.AddInputWithNonce(inputPrivAccount.PubKey, inputAccount.Balance, inputAccount.Sequence+1) |
|
|
|
err := sendTx.AddInputWithNonce(inputPriv.PubKey, balance, sequence) |
|
|
|
if err != nil { |
|
|
|
panic(err) |
|
|
|
} |
|
|
|
for _, outputAccount := range outputAccounts { |
|
|
|
sendTx.AddOutput(outputAccount.Address, inputAccount.Balance/int64(len(outputAccounts))) |
|
|
|
// XXX FIXME???
|
|
|
|
outputAccount.Balance += inputAccount.Balance / int64(len(outputAccounts)) |
|
|
|
for _, output := range outputs { |
|
|
|
sendTx.AddOutput(output.Address, balance/int64(len(outputs))) |
|
|
|
} |
|
|
|
|
|
|
|
// Sign SendTx
|
|
|
|
sendTx.SignInput("tendermint_testnet_7", 0, inputPrivAccount) |
|
|
|
|
|
|
|
// Hack: Listen for events or create a new RPC call for this.
|
|
|
|
// XXX FIXME
|
|
|
|
inputAccount.Sequence += 1 |
|
|
|
inputAccount.Balance = 0 // FIXME???
|
|
|
|
sendTx.SignInput("tendermint_testnet_9", 0, inputPriv) |
|
|
|
|
|
|
|
return sendTx |
|
|
|
} |