// Copyright 2018 The dexon-consensus Authors // This file is part of the dexon-consensus library. // // The dexon-consensus library is free software: you can redistribute it // and/or modify it under the terms of the GNU Lesser General Public License as // published by the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // The dexon-consensus library is distributed in the hope that it will be // useful, but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser // General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with the dexon-consensus library. If not, see // . // A simple monkey that sends random transactions into the network. package main import ( "context" "crypto/ecdsa" "flag" "fmt" "math" "math/big" "math/rand" "time" dexon "github.com/dexon-foundation/dexon" "github.com/dexon-foundation/dexon/common" "github.com/dexon-foundation/dexon/core/types" "github.com/dexon-foundation/dexon/crypto" "github.com/dexon-foundation/dexon/ethclient" ) var key = flag.String("key", "", "private key path") var endpoint = flag.String("endpoint", "http://127.0.0.1:8545", "JSON RPC endpoint") var n = flag.Int("n", 100, "number of random accounts") var gambler = flag.Bool("gambler", false, "make this monkey a gambler") var parallel = flag.Bool("parallel", false, "monkeys will send transaction in parallel") var sleep = flag.Int("sleep", 500, "time in millisecond that monkeys sleep between each transaction") type Monkey struct { client *ethclient.Client source *ecdsa.PrivateKey keys []*ecdsa.PrivateKey networkID *big.Int } func New(ep string, source *ecdsa.PrivateKey, num int) *Monkey { client, err := ethclient.Dial(ep) if err != nil { panic(err) } var keys []*ecdsa.PrivateKey for i := 0; i < num; i++ { key, err := crypto.GenerateKey() if err != nil { panic(err) } keys = append(keys, key) } networkID, err := client.NetworkID(context.Background()) if err != nil { panic(err) } return &Monkey{ client: client, source: source, keys: keys, networkID: networkID, } } func (m *Monkey) transfer( key *ecdsa.PrivateKey, toAddress common.Address, amount *big.Int, nonce uint64) { if nonce == math.MaxUint64 { var err error address := crypto.PubkeyToAddress(key.PublicKey) nonce, err = m.client.PendingNonceAt(context.Background(), address) if err != nil { panic(err) } } tx := types.NewTransaction( uint64(nonce), toAddress, amount, uint64(21000), big.NewInt(1e9), nil) signer := types.NewEIP155Signer(m.networkID) tx, err := types.SignTx(tx, signer, key) if err != nil { panic(err) } fmt.Println("Sending TX", "fullhash", tx.Hash().String()) err = m.client.SendTransaction(context.Background(), tx) if err != nil { panic(err) } } func (m *Monkey) deploy( key *ecdsa.PrivateKey, code string, ctors []string, amount *big.Int, nonce uint64) common.Address { if nonce == math.MaxUint64 { var err error address := crypto.PubkeyToAddress(key.PublicKey) nonce, err = m.client.PendingNonceAt(context.Background(), address) if err != nil { panic(err) } } var input string for _, ctor := range ctors { input += fmt.Sprintf("%064s", ctor) } data := common.Hex2Bytes(code + input) gas, err := m.client.EstimateGas(context.Background(), dexon.CallMsg{ Data: data, }) if err != nil { panic(err) } tx := types.NewContractCreation( uint64(nonce), amount, gas, big.NewInt(1e9), data) signer := types.NewEIP155Signer(m.networkID) tx, err = types.SignTx(tx, signer, key) if err != nil { panic(err) } fmt.Println("Sending TX", "fullhash", tx.Hash().String()) err = m.client.SendTransaction(context.Background(), tx) if err != nil { panic(err) } for { time.Sleep(500 * time.Millisecond) recp, err := m.client.TransactionReceipt(context.Background(), tx.Hash()) if err != nil { if err == dexon.NotFound { continue } panic(err) } return recp.ContractAddress } } func (m *Monkey) call( key *ecdsa.PrivateKey, contract common.Address, input []byte, amount *big.Int, gas uint64, nonce uint64) { address := crypto.PubkeyToAddress(key.PublicKey) if nonce == math.MaxUint64 { var err error nonce, err = m.client.PendingNonceAt(context.Background(), address) if err != nil { panic(err) } } if gas == uint64(0) { var err error gas, err = m.client.EstimateGas(context.Background(), dexon.CallMsg{ From: address, To: &contract, Value: amount, Data: input, }) if err != nil { panic(err) } } tx := types.NewTransaction( uint64(nonce), contract, amount, gas, big.NewInt(1e9), input) signer := types.NewEIP155Signer(m.networkID) tx, err := types.SignTx(tx, signer, key) if err != nil { panic(err) } fmt.Println("Sending TX", "fullhash", tx.Hash().String()) err = m.client.SendTransaction(context.Background(), tx) if err != nil { panic(err) } } func (m *Monkey) Distribute() { fmt.Println("Distributing DEX to random accounts ...") address := crypto.PubkeyToAddress(m.source.PublicKey) nonce, err := m.client.PendingNonceAt(context.Background(), address) if err != nil { panic(err) } for _, key := range m.keys { address := crypto.PubkeyToAddress(key.PublicKey) amount := new(big.Int) amount.SetString("1000000000000000000", 10) m.transfer(m.source, address, amount, nonce) nonce += 1 } time.Sleep(20 * time.Second) } func (m *Monkey) Crazy() { fmt.Println("Performing random transfers ...") nonce := uint64(0) transfer := func(key *ecdsa.PrivateKey, to common.Address, nonce uint64) { m.transfer(key, to, big.NewInt(1), nonce) } for { fmt.Println("nonce", nonce) for _, key := range m.keys { to := crypto.PubkeyToAddress(m.keys[rand.Int()%len(m.keys)].PublicKey) if *parallel { go transfer(key, to, nonce) } else { transfer(key, to, nonce) } } nonce += 1 time.Sleep(time.Duration(*sleep) * time.Millisecond) } } func main() { flag.Parse() privKey, err := crypto.LoadECDSA(*key) if err != nil { panic(err) } m := New(*endpoint, privKey, *n) m.Distribute() if *gambler { m.Gamble() } else { m.Crazy() } }