diff --git a/cmd/loadtest/app.go b/cmd/loadtest/app.go index 98b1476d..cd97e015 100644 --- a/cmd/loadtest/app.go +++ b/cmd/loadtest/app.go @@ -46,6 +46,7 @@ type ( TimeLimit *int64 ToRandom *bool CallOnly *bool + CallOnlyLatestBlock *bool URL *url.URL ChainID *uint64 PrivateKey *string @@ -206,6 +207,7 @@ func init() { ltp.ToAddress = LoadtestCmd.PersistentFlags().String("to-address", "0xDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF", "The address that we're going to send to") ltp.ToRandom = LoadtestCmd.PersistentFlags().Bool("to-random", false, "When doing a transfer test, should we send to random addresses rather than DEADBEEFx5") ltp.CallOnly = LoadtestCmd.PersistentFlags().Bool("call-only", false, "When using this mode, rather than sending a transaction, we'll just call. This mode is incompatible with adaptive rate limiting, summarization, and a few other features.") + ltp.CallOnlyLatestBlock = LoadtestCmd.PersistentFlags().Bool("call-only-latest", false, "When using call only mode with recall, should we execute on the latest block or on the original block") ltp.HexSendAmount = LoadtestCmd.PersistentFlags().String("send-amount", "0x38D7EA4C68000", "The amount of wei that we'll send every transaction") ltp.RateLimit = LoadtestCmd.PersistentFlags().Float64("rate-limit", 4, "An overall limit to the number of requests per second. Give a number less than zero to remove this limit all together") ltp.AdaptiveRateLimit = LoadtestCmd.PersistentFlags().Bool("adaptive-rate-limit", false, "Enable AIMD-style congestion control to automatically adjust request rate") diff --git a/cmd/loadtest/loadtest.go b/cmd/loadtest/loadtest.go index a60804db..919dd15f 100644 --- a/cmd/loadtest/loadtest.go +++ b/cmd/loadtest/loadtest.go @@ -1093,6 +1093,7 @@ func loadTestRecall(ctx context.Context, c *ethclient.Client, nonce uint64, orig log.Error().Err(err).Msg("Unable to sign transaction") return } + log.Trace().Str("txId", originalTx.Hash().String()).Bool("callOnly", *ltp.CallOnly).Msg("Attempting to replay transaction") t1 = time.Now() defer func() { t2 = time.Now() }() @@ -1100,7 +1101,19 @@ func loadTestRecall(ctx context.Context, c *ethclient.Client, nonce uint64, orig callMsg := txToCallMsg(stx) callMsg.From = originalTx.From() callMsg.Gas = originalTx.Gas() - _, err = c.CallContract(ctx, callMsg, originalTx.BlockNumber()) + if *ltp.CallOnlyLatestBlock { + _, err = c.CallContract(ctx, callMsg, nil) + } else { + callMsg.GasPrice = originalTx.GasPrice() + callMsg.GasFeeCap = new(big.Int).SetUint64(originalTx.MaxFeePerGas()) + callMsg.GasTipCap = new(big.Int).SetUint64(originalTx.MaxPriorityFeePerGas()) + _, err = c.CallContract(ctx, callMsg, originalTx.BlockNumber()) + } + if err != nil { + log.Warn().Err(err).Msg("Recall failure") + } + // we're not going to return the error in the case because there is no point retrying + err = nil } else { err = c.SendTransaction(ctx, stx) } diff --git a/cmd/loadtest/recall.go b/cmd/loadtest/recall.go index f1bdfdf6..ef035986 100644 --- a/cmd/loadtest/recall.go +++ b/cmd/loadtest/recall.go @@ -17,7 +17,11 @@ func getRecentBlocks(ctx context.Context, ec *ethclient.Client, c *ethrpc.Client if err != nil { return nil, err } - rawBlocks, err := util.GetBlockRange(ctx, bn-*inputLoadTestParams.RecallLength, bn, c) + + // FIXME the batch size of 25 is hard coded and probably should at least be a constant or a parameter. This limit is + // different than the actual json RPC batch size of 999. Because we're fetching blocks, its' more likely that we hit + // a response size limit rather than a batch length limit + rawBlocks, err := util.GetBlockRangeInPages(ctx, bn-*inputLoadTestParams.RecallLength, bn, 25, c) return rawBlocks, err } @@ -33,8 +37,8 @@ func getRecallTransactions(ctx context.Context, c *ethclient.Client, rpc *ethrpc if err != nil { return nil, err } - for _, t := range pb.Transactions { - pt := rpctypes.NewPolyTransaction(&t) + for k := range pb.Transactions { + pt := rpctypes.NewPolyTransaction(&pb.Transactions[k]) txs = append(txs, pt) } } diff --git a/cmd/rpcfuzz/usage.md b/cmd/rpcfuzz/usage.md index 5060b1e3..7c3e0098 100644 --- a/cmd/rpcfuzz/usage.md +++ b/cmd/rpcfuzz/usage.md @@ -22,7 +22,7 @@ $ erigon --chain dev --dev.period 5 --http --http.addr localhost \ --http.api 'admin,debug,web3,eth,txpool,personal,clique,miner,net' \ --verbosity 5 --rpc.gascap 50000000 \ --miner.gaslimit 10 --gpo.blocks 1 \ - --gpo.percentile 1 + --gpo.percentile 1 --mine ``` Once your Eth client is running and the RPC is functional, you'll need to transfer some amount of ether to a known account that ca be used for testing. diff --git a/doc/polycli_loadtest.md b/doc/polycli_loadtest.md index 162a91b8..2a79bf7c 100644 --- a/doc/polycli_loadtest.md +++ b/doc/polycli_loadtest.md @@ -88,6 +88,7 @@ $ polycli loadtest --app-id 0 --data-avail --verbosity 700 --chain-id 42 --concu --batch-size uint Number of batches to perform at a time for receipt fetching. Default is 999 requests at a time. (default 999) -b, --byte-count uint If we're in store mode, this controls how many bytes we'll try to store in our contract (default 1024) --call-only When using this mode, rather than sending a transaction, we'll just call. This mode is incompatible with adaptive rate limiting, summarization, and a few other features. + --call-only-latest When using call only mode with recall, should we execute on the latest block or on the original block --chain-id uint The chain id for the transactions. -c, --concurrency int Number of requests to perform concurrently. Default is one request at a time. (default 1) --contract-call-block-interval uint During deployment, this flag controls if we should check every block, every other block, or every nth block to determine that the contract has been deployed (default 1) diff --git a/doc/polycli_rpcfuzz.md b/doc/polycli_rpcfuzz.md index cf100425..3e6cc3fc 100644 --- a/doc/polycli_rpcfuzz.md +++ b/doc/polycli_rpcfuzz.md @@ -43,7 +43,7 @@ $ erigon --chain dev --dev.period 5 --http --http.addr localhost \ --http.api 'admin,debug,web3,eth,txpool,personal,clique,miner,net' \ --verbosity 5 --rpc.gascap 50000000 \ --miner.gaslimit 10 --gpo.blocks 1 \ - --gpo.percentile 1 + --gpo.percentile 1 --mine ``` Once your Eth client is running and the RPC is functional, you'll need to transfer some amount of ether to a known account that ca be used for testing. diff --git a/util/util.go b/util/util.go index 7ca12faf..40ba8a7b 100644 --- a/util/util.go +++ b/util/util.go @@ -51,6 +51,26 @@ func GetBlockRange(ctx context.Context, from, to uint64, c *ethrpc.Client) ([]*j return blocks, nil } +func GetBlockRangeInPages(ctx context.Context, from, to, pageSize uint64, c *ethrpc.Client) ([]*json.RawMessage, error) { + var allBlocks []*json.RawMessage + + for i := from; i <= to; i += pageSize { + end := i + pageSize - 1 + if end > to { + end = to + } + + blocks, err := GetBlockRange(ctx, i, end, c) + if err != nil { + return nil, err + } + + allBlocks = append(allBlocks, blocks...) + } + + return allBlocks, nil +} + func GetReceipts(ctx context.Context, rawBlocks []*json.RawMessage, c *ethrpc.Client, batchSize uint64) ([]*json.RawMessage, error) { txHashes := make([]string, 0) txHashMap := make(map[string]string, 0)