github.com/cgcardona/r-subnet-evm@v0.1.5/cmd/simulator/load/loader.go (about) 1 // Copyright (C) 2023, Ava Labs, Inc. All rights reserved. 2 // See the file LICENSE for licensing terms. 3 4 package load 5 6 import ( 7 "context" 8 "crypto/ecdsa" 9 "fmt" 10 "math/big" 11 12 "github.com/cgcardona/r-subnet-evm/cmd/simulator/config" 13 "github.com/cgcardona/r-subnet-evm/cmd/simulator/key" 14 "github.com/cgcardona/r-subnet-evm/cmd/simulator/txs" 15 "github.com/cgcardona/r-subnet-evm/core/types" 16 "github.com/cgcardona/r-subnet-evm/ethclient" 17 "github.com/cgcardona/r-subnet-evm/params" 18 "github.com/ethereum/go-ethereum/common" 19 ethcrypto "github.com/ethereum/go-ethereum/crypto" 20 "github.com/ethereum/go-ethereum/log" 21 "golang.org/x/sync/errgroup" 22 ) 23 24 // ExecuteLoader creates txSequences from [config] and has txAgents execute the specified simulation. 25 func ExecuteLoader(ctx context.Context, config config.Config) error { 26 if config.Timeout > 0 { 27 var cancel context.CancelFunc 28 ctx, cancel = context.WithTimeout(ctx, config.Timeout) 29 defer cancel() 30 } 31 32 // Construct the arguments for the load simulator 33 clients := make([]ethclient.Client, 0, len(config.Endpoints)) 34 for i := 0; i < config.Workers; i++ { 35 clientURI := config.Endpoints[i%len(config.Endpoints)] 36 client, err := ethclient.Dial(clientURI) 37 if err != nil { 38 return fmt.Errorf("failed to dial client at %s: %w", clientURI, err) 39 } 40 clients = append(clients, client) 41 } 42 43 keys, err := key.LoadAll(ctx, config.KeyDir) 44 if err != nil { 45 return err 46 } 47 // Ensure there are at least [config.Workers] keys and save any newly generated ones. 48 if len(keys) < config.Workers { 49 for i := 0; len(keys) < config.Workers; i++ { 50 newKey, err := key.Generate() 51 if err != nil { 52 return fmt.Errorf("failed to generate %d new key: %w", i, err) 53 } 54 if err := newKey.Save(config.KeyDir); err != nil { 55 return fmt.Errorf("failed to save %d new key: %w", i, err) 56 } 57 keys = append(keys, newKey) 58 } 59 } 60 61 // Each address needs: params.GWei * MaxFeeCap * params.TxGas * TxsPerWorker total wei 62 // to fund gas for all of their transactions. 63 maxFeeCap := new(big.Int).Mul(big.NewInt(params.GWei), big.NewInt(config.MaxFeeCap)) 64 minFundsPerAddr := new(big.Int).Mul(maxFeeCap, big.NewInt(int64(config.TxsPerWorker*params.TxGas))) 65 log.Info("Distributing funds", "numTxsPerWorker", config.TxsPerWorker, "minFunds", minFundsPerAddr) 66 keys, err = DistributeFunds(ctx, clients[0], keys, config.Workers, minFundsPerAddr) 67 if err != nil { 68 return err 69 } 70 log.Info("Distributed funds successfully") 71 72 pks := make([]*ecdsa.PrivateKey, 0, len(keys)) 73 senders := make([]common.Address, 0, len(keys)) 74 for _, key := range keys { 75 pks = append(pks, key.PrivKey) 76 senders = append(senders, key.Address) 77 } 78 79 bigGwei := big.NewInt(params.GWei) 80 gasTipCap := new(big.Int).Mul(bigGwei, big.NewInt(config.MaxTipCap)) 81 gasFeeCap := new(big.Int).Mul(bigGwei, big.NewInt(config.MaxFeeCap)) 82 client := clients[0] 83 chainID, err := client.ChainID(ctx) 84 if err != nil { 85 return fmt.Errorf("failed to fetch chainID: %w", err) 86 } 87 signer := types.LatestSignerForChainID(chainID) 88 89 log.Info("Creating transaction sequences...") 90 txGenerator := func(key *ecdsa.PrivateKey, nonce uint64) (*types.Transaction, error) { 91 addr := ethcrypto.PubkeyToAddress(key.PublicKey) 92 tx, err := types.SignNewTx(key, signer, &types.DynamicFeeTx{ 93 ChainID: chainID, 94 Nonce: nonce, 95 GasTipCap: gasTipCap, 96 GasFeeCap: gasFeeCap, 97 Gas: params.TxGas, 98 To: &addr, 99 Data: nil, 100 Value: common.Big0, 101 }) 102 if err != nil { 103 return nil, err 104 } 105 return tx, nil 106 } 107 txSequences, err := txs.GenerateTxSequences(ctx, txGenerator, clients[0], pks, config.TxsPerWorker) 108 if err != nil { 109 return err 110 } 111 112 log.Info("Constructing tx agents...", "numAgents", config.Workers) 113 agents := make([]txs.Agent[*types.Transaction], 0, config.Workers) 114 for i := 0; i < config.Workers; i++ { 115 agents = append(agents, txs.NewIssueNAgent[*types.Transaction](txSequences[i], NewSingleAddressTxWorker(ctx, clients[i], senders[i]), config.BatchSize)) 116 } 117 118 log.Info("Starting tx agents...") 119 eg := errgroup.Group{} 120 for _, agent := range agents { 121 agent := agent 122 eg.Go(func() error { 123 return agent.Execute(ctx) 124 }) 125 } 126 127 log.Info("Waiting for tx agents...") 128 if err := eg.Wait(); err != nil { 129 return err 130 } 131 log.Info("Tx agents completed successfully.") 132 return nil 133 }