// 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 monkey import ( "context" "crypto/ecdsa" "encoding/hex" "fmt" "math/big" "math/rand" "os" "time" "github.com/dexon-foundation/dexon/cmd/zoo/client" "github.com/dexon-foundation/dexon/crypto" ) var config *MonkeyConfig type MonkeyConfig struct { Key string Endpoint string N int Gambler bool Feeder bool Batch bool Sleep int Timeout int } func Init(cfg *MonkeyConfig) { config = cfg } type Monkey struct { client.Client source *ecdsa.PrivateKey keys []*ecdsa.PrivateKey timer <-chan time.Time } func New(ep string, source *ecdsa.PrivateKey, num int, timeout time.Duration) *Monkey { client, err := client.New(ep) if err != nil { panic(err) } file := func() *os.File { for i := 0; i < 100; i++ { name := fmt.Sprintf("zoo-%d.keys", i) file, err := os.OpenFile(name, os.O_CREATE|os.O_WRONLY|os.O_EXCL, 0600) if err != nil { continue } fmt.Printf("Save keys to file %s\n", name) return file } return nil }() if file == nil { panic(fmt.Errorf("Failed to create file for zoo keys")) } defer file.Close() var keys []*ecdsa.PrivateKey for i := 0; i < num; i++ { key, err := crypto.GenerateKey() if err != nil { panic(err) } _, err = file.Write([]byte(hex.EncodeToString(crypto.FromECDSA(key)) + "\n")) if err != nil { panic(err) } keys = append(keys, key) } monkey := &Monkey{ Client: *client, source: source, keys: keys, } if timeout > 0 { monkey.timer = time.After(timeout * time.Second) } return monkey } func (m *Monkey) Distribute() { fmt.Println("Distributing DEX to random accounts ...") address := crypto.PubkeyToAddress(m.source.PublicKey) nonce, err := m.PendingNonceAt(context.Background(), address) if err != nil { panic(err) } ctxs := make([]*client.TransferContext, len(m.keys)) for i, key := range m.keys { address := crypto.PubkeyToAddress(key.PublicKey) amount := new(big.Int) amount.SetString("1000000000000000000", 10) ctxs[i] = &client.TransferContext{ Key: m.source, ToAddress: address, Amount: amount, Nonce: nonce, Gas: 21000, } nonce++ } m.BatchTransfer(ctxs) time.Sleep(20 * time.Second) } func (m *Monkey) Crazy() uint64 { fmt.Println("Performing random transfers ...") nonce := uint64(0) loop: for { ctxs := make([]*client.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("%d0000000000000", rand.Intn(10)+1), 10) ctx := &client.TransferContext{ Key: key, ToAddress: to, Amount: amount, Nonce: nonce, Gas: 21000, } if config.Batch { ctxs[i] = ctx } else { m.Transfer(ctx) } } if config.Batch { m.BatchTransfer(ctxs) } fmt.Printf("Sent %d transactions, nonce = %d\n", len(m.keys), nonce) if m.timer != nil { select { case <-m.timer: break loop default: } } nonce++ time.Sleep(time.Duration(config.Sleep) * time.Millisecond) } return nonce } func (m *Monkey) Keys() []*ecdsa.PrivateKey { return m.keys } func Exec() (*Monkey, uint64) { privKey, err := crypto.LoadECDSA(config.Key) if err != nil { panic(err) } m := New(config.Endpoint, privKey, config.N, time.Duration(config.Timeout)) m.Distribute() var finalNonce uint64 if config.Gambler { finalNonce = m.Gamble() } else if config.Feeder { finalNonce = m.Feed() } else { finalNonce = m.Crazy() } return m, finalNonce }