Skip to content

Commit 1844d54

Browse files
feat: rate limit and logging improvements (#533)
* feat: rate limit and logging improvements * Update cmd/loadtest/uniswapv3.go Co-authored-by: Léo Vincent <[email protected]> * ci: make gen * fix: shadow * fix: protoc --------- Co-authored-by: Léo Vincent <[email protected]>
1 parent 634a8f3 commit 1844d54

9 files changed

+220
-92
lines changed

cmd/loadtest/app.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ func initFlags() {
219219
ltp.ToRandom = LoadtestCmd.PersistentFlags().Bool("to-random", false, "When doing a transfer test, should we send to random addresses rather than DEADBEEFx5")
220220
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.")
221221
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")
222-
ltp.EthAmountInWei = LoadtestCmd.PersistentFlags().Float64("eth-amount", 0.001, "The amount of ether to send on every transaction")
222+
ltp.EthAmountInWei = LoadtestCmd.PersistentFlags().Float64("eth-amount", 0, "The amount of ether to send on every transaction")
223223
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")
224224
ltp.AdaptiveRateLimit = LoadtestCmd.PersistentFlags().Bool("adaptive-rate-limit", false, "Enable AIMD-style congestion control to automatically adjust request rate")
225225
ltp.SteadyStateTxPoolSize = LoadtestCmd.PersistentFlags().Uint64("steady-state-tx-pool-size", 1000, "When using adaptive rate limiting, this value sets the target queue size. If the queue is smaller than this value, we'll speed up. If the queue is smaller than this value, we'll back off.")

cmd/loadtest/loadtest.go

+170-68
Large diffs are not rendered by default.

cmd/loadtest/uniswapv3.go

+10-3
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
_ "embed"
66
"errors"
77
"fmt"
8+
ethtypes "github.com/ethereum/go-ethereum/core/types"
89
"math/big"
910
"time"
1011

@@ -130,12 +131,15 @@ func initUniswapV3Loadtest(ctx context.Context, c *ethclient.Client, tops *bind.
130131
}
131132

132133
// Run UniswapV3 loadtest.
133-
func runUniswapV3Loadtest(ctx context.Context, c *ethclient.Client, nonce uint64, uniswapV3Config uniswapv3loadtest.UniswapV3Config, poolConfig uniswapv3loadtest.PoolConfig, swapAmountIn *big.Int) (t1 time.Time, t2 time.Time, err error) {
134+
func runUniswapV3Loadtest(ctx context.Context, c *ethclient.Client, nonce uint64, uniswapV3Config uniswapv3loadtest.UniswapV3Config, poolConfig uniswapv3loadtest.PoolConfig, swapAmountIn *big.Int) (t1 time.Time, t2 time.Time, txHash common.Hash, err error) {
135+
var tops *bind.TransactOpts
136+
var tx *ethtypes.Transaction
137+
134138
ltp := inputLoadTestParams
135139
chainID := new(big.Int).SetUint64(*ltp.ChainID)
136140
privateKey := ltp.ECDSAPrivateKey
137141

138-
tops, err := bind.NewKeyedTransactorWithChainID(privateKey, chainID)
142+
tops, err = bind.NewKeyedTransactorWithChainID(privateKey, chainID)
139143
if err != nil {
140144
log.Error().Err(err).Msg("Unable create transaction signer")
141145
return
@@ -145,6 +149,9 @@ func runUniswapV3Loadtest(ctx context.Context, c *ethclient.Client, nonce uint64
145149

146150
t1 = time.Now()
147151
defer func() { t2 = time.Now() }()
148-
err = uniswapv3loadtest.ExactInputSingleSwap(tops, uniswapV3Config.SwapRouter02.Contract, poolConfig, swapAmountIn, *ltp.FromETHAddress, nonce)
152+
tx, err = uniswapv3loadtest.ExactInputSingleSwap(tops, uniswapV3Config.SwapRouter02.Contract, poolConfig, swapAmountIn, *ltp.FromETHAddress, nonce)
153+
if err == nil && tx != nil {
154+
txHash = tx.Hash()
155+
}
149156
return
150157
}

cmd/loadtest/uniswapv3/swap.go

+9-8
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package uniswapv3loadtest
22

33
import (
4+
"github.com/ethereum/go-ethereum/core/types"
45
"math/big"
56

67
"github.com/0xPolygon/polygon-cli/bindings/uniswapv3"
@@ -15,13 +16,13 @@ var SwapAmountInput = big.NewInt(1_000)
1516
// ExactInputSingleSwap performs a UniswapV3 swap using the `ExactInputSingle` method which swaps a fixed amount of
1617
// one token for a maximum possible amount of another token. The direction of the swap is determined
1718
// by the nonce value.
18-
func ExactInputSingleSwap(tops *bind.TransactOpts, swapRouter *uniswapv3.SwapRouter02, poolConfig PoolConfig, amountIn *big.Int, recipient common.Address, nonce uint64) error {
19+
func ExactInputSingleSwap(tops *bind.TransactOpts, swapRouter *uniswapv3.SwapRouter02, poolConfig PoolConfig, amountIn *big.Int, recipient common.Address, nonce uint64) (tx *types.Transaction, err error) {
1920
// Determine the direction of the swap.
2021
swapDirection := getSwapDirection(nonce, poolConfig)
2122

2223
// Perform swap.
2324
amountOut := new(big.Int).Mul(amountIn, new(big.Int).Div(big.NewInt(98), big.NewInt(100)))
24-
_, err := swapRouter.ExactInputSingle(tops, uniswapv3.IV3SwapRouterExactInputSingleParams{
25+
tx, err = swapRouter.ExactInputSingle(tops, uniswapv3.IV3SwapRouterExactInputSingleParams{
2526
// The contract address of the inbound token.
2627
TokenIn: swapDirection.tokenIn,
2728
// The contract address of the outbound token.
@@ -41,30 +42,30 @@ func ExactInputSingleSwap(tops *bind.TransactOpts, swapRouter *uniswapv3.SwapRou
4142
})
4243
if err != nil {
4344
log.Error().Err(err).Str("tokenIn", swapDirection.tokenInName).Str("tokenOut", swapDirection.tokenOutName).Interface("amountIn", amountIn).Msg("Unable to swap")
44-
return err
45+
return
4546
}
4647
log.Trace().Str("tokenIn", swapDirection.tokenInName).Str("tokenOut", swapDirection.tokenOutName).Interface("amountIn", amountIn).Msg("Successful swap")
47-
return nil
48+
return
4849
}
4950

5051
// swapDirection represents a swap direction with the inbound and outbound tokens.
51-
type swapDirection struct {
52+
type uniswapDirection struct {
5253
tokenIn, tokenOut common.Address
5354
tokenInName, tokenOutName string
5455
}
5556

5657
// Return the direction of the swap given the nonce value.
57-
func getSwapDirection(nonce uint64, poolConfig PoolConfig) swapDirection {
58+
func getSwapDirection(nonce uint64, poolConfig PoolConfig) uniswapDirection {
5859
if nonce%2 == 0 {
59-
return swapDirection{
60+
return uniswapDirection{
6061
tokenIn: poolConfig.Token0.Address,
6162
tokenInName: "token0",
6263

6364
tokenOut: poolConfig.Token1.Address,
6465
tokenOutName: "token1",
6566
}
6667
}
67-
return swapDirection{
68+
return uniswapDirection{
6869
tokenIn: poolConfig.Token1.Address,
6970
tokenInName: "token1",
7071

cmd/retest/usage.md

+12-3
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,13 @@ To try this out, first checkout https://github.com/ethereum/tests/
99
# Move into the filler directory
1010
cd tests/src
1111

12+
# at this point, it's a good time to check if you have a good version
13+
# of yq installed. If you run this command or something like it and
14+
# the values are turned into decimals or floating point numbers, this
15+
# will be a problem. This particular version of yq handles this well:
16+
# https://github.com/mikefarah/yq
17+
cat ./GeneralStateTestsFiller/stPreCompiledContracts2/ecrecoverShortBuffFiller.yml | ~/go/bin/yq -o json
18+
1219
# Convert the yaml based tests to json. There will be some failures depending on the version of yq used
1320
find . -type f -name '*.yml' | while read yaml_file ; do
1421
yq -o json '.' $yaml_file > $yaml_file.json
@@ -18,17 +25,17 @@ find . -type f -name '*.yml' | while read yaml_file ; do
1825
fi
1926
done
2027

21-
2228
# Check for duplicates... There are a few so we should be mindful of that
2329
find . -type f -name '*.json' | xargs cat | jq -r 'to_entries[].key' | uniq -c | sort
2430

2531
# Consolidate everything.. The kzg tests seem to be a different format.. So excluding them with the array check
2632
find . -type f -name '*.json' | xargs cat | jq 'select((. | type) != "array")' | jq -s 'add' > merged.json
33+
2734
# there are some fields like "//comment" that make parsing very difficult
2835
jq 'walk(if type == "object" then with_entries(select(.key | startswith("//") | not)) else . end)' merged.json > merged.nocomment.json
2936
```
3037

31-
Now we should have a giant file filled with an array of transactions. We can take that output and process it witht the `retest` command now
38+
Now we should have a giant file filled with an array of transactions. We can take that output and process it with the `retest` command now
3239

3340
```bash
3441
polycli retest -v 500 --file merged.nocomment.json > simple.json
@@ -39,7 +46,9 @@ polycli retest -v 500 --file merged.nocomment.json > simple.json
3946
This project will depend on an installation of `solc` (specifically
4047
0.8.20) and `lllc`. Installing solidity is pretty easy, but LLLC can
4148
be a little tricky.
42-
If you got multiple solc versions, you can specify full patch to the right binary to use with env var ```SOLC_PATH```.
49+
50+
If you've got multiple solc versions, you can specify full path to the
51+
right binary to use with env var ```SOLC_PATH```.
4352

4453
Since the version is pretty old, it might not build well on your host
4554
os. Building within docker might make your life easier:

cmd/root.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package cmd
33
import (
44
"fmt"
55
"github.com/0xPolygon/polygon-cli/cmd/foldtrace"
6+
"github.com/0xPolygon/polygon-cli/util"
67
"os"
78

89
"github.com/0xPolygon/polygon-cli/cmd/cdk"
@@ -13,8 +14,6 @@ import (
1314
"github.com/0xPolygon/polygon-cli/cmd/fork"
1415
"github.com/0xPolygon/polygon-cli/cmd/p2p"
1516
"github.com/0xPolygon/polygon-cli/cmd/parseethwallet"
16-
"github.com/0xPolygon/polygon-cli/util"
17-
1817
"github.com/spf13/cobra"
1918
"github.com/spf13/viper"
2019

@@ -49,6 +48,7 @@ var rootCmd *cobra.Command
4948
// Execute adds all child commands to the root command and sets flags appropriately.
5049
// This is called by main.main(). It only needs to happen once to the rootCmd.
5150
func Execute() {
51+
cobra.EnableTraverseRunHooks = true
5252
err := rootCmd.Execute()
5353
if err != nil {
5454
os.Exit(1)
@@ -91,13 +91,13 @@ func NewPolycliCommand() *cobra.Command {
9191
Use: "polycli",
9292
Short: "A Swiss Army knife of blockchain tools.",
9393
Long: "Polycli is a collection of tools that are meant to be useful while building, testing, and running block chain applications.",
94-
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
94+
PersistentPreRun: func(cmd *cobra.Command, args []string) {
9595
util.SetLogLevel(verbosity)
9696
logMode := util.JSON
9797
if pretty {
9898
logMode = util.Console
9999
}
100-
return util.SetLogMode(logMode)
100+
_ = util.SetLogMode(logMode)
101101
},
102102
}
103103

doc/polycli_loadtest.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ The codebase has a contract that used for load testing. It's written in Solidity
116116
--contract-call-payable Use this flag if the function is payable, the value amount passed will be from --eth-amount. This must be paired up with --mode contract-call and --contract-address
117117
--erc20-address string The address of a pre-deployed ERC20 contract
118118
--erc721-address string The address of a pre-deployed ERC721 contract
119-
--eth-amount float The amount of ether to send on every transaction (default 0.001)
119+
--eth-amount float The amount of ether to send on every transaction
120120
--force-contract-deploy Some load test modes don't require a contract deployment. Set this flag to true to force contract deployments. This will still respect the --lt-address flags.
121121
-f, --function uint A specific function to be called if running with --mode f or a specific precompiled contract when running with --mode a (default 1)
122122
--function-arg strings The arguments that will be passed to a contract function call. This must be paired up with "--mode contract-call" and "--contract-address". Args can be passed multiple times: "--function-arg 'test' --function-arg 999" or comma separated values "--function-arg "test",9". The ordering of the arguments must match the ordering of the function parameters.

doc/polycli_loadtest_uniswapv3.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ The command also inherits flags from parent commands.
8686
--chain-id uint The chain id for the transactions.
8787
-c, --concurrency int Number of requests to perform concurrently. Default is one request at a time. (default 1)
8888
--config string config file (default is $HOME/.polygon-cli.yaml)
89-
--eth-amount float The amount of ether to send on every transaction (default 0.001)
89+
--eth-amount float The amount of ether to send on every transaction
9090
--gas-limit uint In environments where the gas limit can't be computed on the fly, we can specify it manually. This can also be used to avoid eth_estimateGas
9191
--gas-price uint In environments where the gas price can't be determined automatically, we can specify it manually
9292
-i, --iterations uint If we're making contract calls, this controls how many times the contract will execute the instruction in a loop. If we are making ERC721 Mints, this indicates the minting batch size (default 1)

doc/polycli_retest.md

+12-3
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,13 @@ To try this out, first checkout https://github.com/ethereum/tests/
3030
# Move into the filler directory
3131
cd tests/src
3232

33+
# at this point, it's a good time to check if you have a good version
34+
# of yq installed. If you run this command or something like it and
35+
# the values are turned into decimals or floating point numbers, this
36+
# will be a problem. This particular version of yq handles this well:
37+
# https://github.com/mikefarah/yq
38+
cat ./GeneralStateTestsFiller/stPreCompiledContracts2/ecrecoverShortBuffFiller.yml | ~/go/bin/yq -o json
39+
3340
# Convert the yaml based tests to json. There will be some failures depending on the version of yq used
3441
find . -type f -name '*.yml' | while read yaml_file ; do
3542
yq -o json '.' $yaml_file > $yaml_file.json
@@ -39,17 +46,17 @@ find . -type f -name '*.yml' | while read yaml_file ; do
3946
fi
4047
done
4148

42-
4349
# Check for duplicates... There are a few so we should be mindful of that
4450
find . -type f -name '*.json' | xargs cat | jq -r 'to_entries[].key' | uniq -c | sort
4551

4652
# Consolidate everything.. The kzg tests seem to be a different format.. So excluding them with the array check
4753
find . -type f -name '*.json' | xargs cat | jq 'select((. | type) != "array")' | jq -s 'add' > merged.json
54+
4855
# there are some fields like "//comment" that make parsing very difficult
4956
jq 'walk(if type == "object" then with_entries(select(.key | startswith("//") | not)) else . end)' merged.json > merged.nocomment.json
5057
```
5158

52-
Now we should have a giant file filled with an array of transactions. We can take that output and process it witht the `retest` command now
59+
Now we should have a giant file filled with an array of transactions. We can take that output and process it with the `retest` command now
5360

5461
```bash
5562
polycli retest -v 500 --file merged.nocomment.json > simple.json
@@ -60,7 +67,9 @@ polycli retest -v 500 --file merged.nocomment.json > simple.json
6067
This project will depend on an installation of `solc` (specifically
6168
0.8.20) and `lllc`. Installing solidity is pretty easy, but LLLC can
6269
be a little tricky.
63-
If you got multiple solc versions, you can specify full patch to the right binary to use with env var ```SOLC_PATH```.
70+
71+
If you've got multiple solc versions, you can specify full path to the
72+
right binary to use with env var ```SOLC_PATH```.
6473

6574
Since the version is pretty old, it might not build well on your host
6675
os. Building within docker might make your life easier:

0 commit comments

Comments
 (0)