[WIP] EVM RPC read benchmark script for state store load testing#3004
[WIP] EVM RPC read benchmark script for state store load testing#3004
Conversation
Hammers a node endpoint with debug_traceBlockByNumber, debug_traceTransaction, eth_getBalance, eth_getStorageAt, eth_getCode, and eth_getTransactionCount across 5 phases (sequential, concurrent, per-method, mixed workload). Reports p50/p95/p99 latencies and rps. Made-with: Cursor
|
The latest Buf updates on your PR. Results from workflow Buf / buf (pull_request).
|
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #3004 +/- ##
==========================================
- Coverage 58.17% 58.05% -0.12%
==========================================
Files 2113 2114 +1
Lines 173688 174023 +335
==========================================
Hits 101037 101037
- Misses 63622 63957 +335
Partials 9029 9029
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
| for _, s := range stats { | ||
| s.Duration = elapsed | ||
| } |
Check warning
Code scanning / CodeQL
Iteration over map Warning
| if len(s.Latencies) == 0 { | ||
| return 0 | ||
| } | ||
| idx := int(float64(len(s.Latencies)) * pct) |
Check notice
Code scanning / CodeQL
Floating point arithmetic Note
| } | ||
| return s.Latencies[idx] | ||
| } | ||
| rps := float64(s.Total) / s.Duration.Seconds() |
Check notice
Code scanning / CodeQL
Floating point arithmetic Note
| go func() { | ||
| defer wg.Done() | ||
| for idx := range work { | ||
| method, lat, err := workFn(idx) | ||
| record(method, lat, err) | ||
| } | ||
| }() |
Check notice
Code scanning / CodeQL
Spawning a Go routine Note
| totalDuration = stats[k].Duration | ||
| } | ||
| } | ||
| rps := float64(totalReqs) / totalDuration.Seconds() |
Check notice
Code scanning / CodeQL
Floating point arithmetic Note
Each RPC method is defined once in a single registry slice. Phases derive from heavy/light classification. Adding a new method is one line. Use -methods flag to run a subset. Made-with: Cursor
Traces a configurable number of txs (-trace-discover, default 5) during discovery to extract real (address, slot) pairs. eth_getStorageAt now queries actual populated slots instead of random ones. Falls back to random slots when discovery is disabled or finds nothing. Made-with: Cursor
| for addr := range addrSet { | ||
| info.Addresses = append(info.Addresses, addr) | ||
| } |
Check warning
Code scanning / CodeQL
Iteration over map Warning
| for k, v := range s { | ||
| lightStats[k] = v | ||
| } |
Check warning
Code scanning / CodeQL
Iteration over map Warning
| for addr, acct := range prestate { | ||
| for slot := range acct.Storage { | ||
| key := addr + "|" + slot | ||
| if !seen[key] { | ||
| seen[key] = true | ||
| slots = append(slots, storageSlot{Address: addr, Slot: slot}) | ||
| } | ||
| } | ||
| } |
Check warning
Code scanning / CodeQL
Iteration over map Warning
| for slot := range acct.Storage { | ||
| key := addr + "|" + slot | ||
| if !seen[key] { | ||
| seen[key] = true | ||
| slots = append(slots, storageSlot{Address: addr, Slot: slot}) | ||
| } | ||
| } |
Check warning
Code scanning / CodeQL
Iteration over map Warning
| if err != nil { | ||
| return nil, elapsed, err | ||
| } | ||
| defer resp.Body.Close() |
| {"eth_getTransactionCount", func() []interface{} { return []interface{}{randAddr(), latestHex} }, 15, false}, | ||
| {"eth_getCode", func() []interface{} { return []interface{}{randAddr(), latestHex} }, 15, false}, | ||
| {"eth_getStorageAt", func() []interface{} { return randStorageParams() }, 25, false}, | ||
| } |
There was a problem hiding this comment.
Can we add eth_getLogs? I feel only debug_traceBlockByNumber and debug_traceTransaction and eth_getLogs are really useful, others are optional
Phase 1 now traces every discovered block once and prints a table: BLOCK TXS LATENCY 196571121 97 2.5s 196571111 1 120ms Made-with: Cursor
Made-with: Cursor
| } | ||
| avgGasPerTx := 0.0 | ||
| if len(info.Transactions) > 0 { | ||
| avgGasPerTx = float64(info.GasUsed) / float64(len(info.Transactions)) |
Check notice
Code scanning / CodeQL
Floating point arithmetic Note
| } | ||
| avgGasPerTx := 0.0 | ||
| if len(b.Transactions) > 0 { | ||
| avgGasPerTx = float64(b.GasUsed) / float64(len(b.Transactions)) |
Check notice
Code scanning / CodeQL
Floating point arithmetic Note
Made-with: Cursor
Describe your changes and provide context
Testing performed to validate your change