// 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 batch = flag.Bool("batch", false, "monkeys will send transaction in batch") var sleep = flag.Int("sleep", 500, "time in millisecond that monkeys sleep between each transaction") var feeder = flag.Bool("feeder", false, "make this monkey a feeder") 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, } } type transferContext struct { Key *ecdsa.PrivateKey ToAddress common.Address Amount *big.Int Data []byte Nonce uint64 Gas uint64 } func (m *Monkey) prepareTx(ctx *transferContext) *types.Transaction { if ctx.Nonce == math.MaxUint64 { var err error address := crypto.PubkeyToAddress(ctx.Key.PublicKey) ctx.Nonce, err = m.client.PendingNonceAt(context.Background(), address) if err != nil { panic(err) } } if ctx.Gas == uint64(0) { var err error ctx.Gas, err = m.client.EstimateGas(context.Background(), dexon.CallMsg{ Data: ctx.Data, }) if err != nil { panic(err) } } tx := types.NewTransaction( ctx.Nonce, ctx.ToAddress, ctx.Amount, ctx.Gas, big.NewInt(1e9), ctx.Data) signer := types.NewEIP155Signer(m.networkID) tx, err := types.SignTx(tx, signer, ctx.Key) if err != nil { panic(err) } return tx } func (m *Monkey) transfer(ctx *transferContext) { tx := m.prepareTx(ctx) err := m.client.SendTransaction(context.Background(), tx) if err != nil { panic(err) } } func (m *Monkey) batchTransfer(ctxs []*transferContext) { txs := make([]*types.Transaction, len(ctxs)) for i, ctx := range ctxs { txs[i] = m.prepareTx(ctx) } err := m.client.SendTransactions(context.Background(), txs) if err != nil { panic(err) } } func (m *Monkey) deploy( key *ecdsa.PrivateKey, code string, ctors []string, amount *big.Int, nonce uint64) common.Address { 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) } } 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{ From: address, Data: data, }) if err != nil { panic(err) } tx := types.NewContractCreation( 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) 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) } ctxs := make([]*transferContext, len(m.keys)) for i, key := range m.keys { address := crypto.PubkeyToAddress(key.PublicKey) amount := new(big.Int) amount.SetString("100000000000000000000", 10) ctxs[i] = &transferContext{ Key: m.source, ToAddress: address, Amount: amount, Nonce: nonce, Gas: 21000, } nonce += 1 } m.batchTransfer(ctxs) time.Sleep(20 * time.Second) } func (m *Monkey) Crazy() { fmt.Println("Performing random transfers ...") nonce := uint64(0) for { ctxs := make([]*transferContext, len(m.keys)) for i, key := range m.keys { to := crypto.PubkeyToAddress(m.keys[rand.Int()%len(m.keys)].PublicKey) amount := new(big.Int) amount.SetString(fmt.Sprintf("%d000000000000000", rand.Intn(10)+1), 10) ctx := &transferContext{ Key: key, ToAddress: to, Amount: amount, Nonce: nonce, Gas: 21000, } if *batch { ctxs[i] = ctx } else { m.transfer(ctx) } } if *batch { m.batchTransfer(ctxs) } fmt.Printf("Sent %d transactions, nonce = %d\n", len(m.keys), 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 if *feeder { m.Feed() } else { m.Crazy() } }