Skip to content

feat: add simulator load-test payload + fix proxy batch RPC + wire flashblocks WS#185

Draft
meyer9 wants to merge 4 commits into
mainfrom
wt/benchmark-simulator-integration/main
Draft

feat: add simulator load-test payload + fix proxy batch RPC + wire flashblocks WS#185
meyer9 wants to merge 4 commits into
mainfrom
wt/benchmark-simulator-integration/main

Conversation

@meyer9
Copy link
Copy Markdown
Collaborator

@meyer9 meyer9 commented May 15, 2026

Summary

Three improvements to make the load-test payload type work correctly with the base-load-tester binary:

  1. Fix JSON-RPC batch request support in proxy — the benchmark proxy was rejecting all batch eth_sendRawTransaction calls from the load-tester with HTTP 400, silently dropping all load-test transactions
  2. Wire flashblocks_ws URL into load-test config — the load-tester requires a flashblocks_ws field but the benchmark never populated it, causing connection failures
  3. Add setup_rpc for Simulator contract deployment — direct node URL so setup transactions bypass the proxy and land immediately
  4. Example config for simulator payload — demonstrates the new type: simulator payload against the benchmark's Simulator.sol contract

Changes

runner/clients/common/proxy/proxy.go — batch RPC support

The load-tester's BatchRpcClient sends JSON arrays [{...}, {...}] per the JSON-RPC batch spec. The proxy was unmarshalling into a single struct and returning HTTP 400 for all batch requests. Added handleBatchRequest() to parse the array and route each sub-request through OverrideRequest(), returning a matching array of responses.

Impact: without this fix, zero load-test transactions reach the sequencer despite the Rust binary appearing to submit them.

runner/clients/types/types.go + all client implementations

Added FlashblocksWsURL() string to ExecutionClient interface:

  • BuilderClient: returns ws://localhost:<websocketPort> (the builder's flashblocks server)
  • GethClient, RethClient, BaseRethNodeClient: return "" (no server)

runner/payload/loadtest/load_test_worker.go + factory.go

  • Populates flashblocks_ws in the generated load-tester YAML config using sequencerClient.FlashblocksWsURL()
  • Adds setup_rpc field pointing to the direct sequencer RPC (not the proxy) so the load-tester can deploy the Simulator contract and initialize storage slots before the test run

configs/examples/load-test-simulator.yml

Example benchmark config using type: simulator driven through the load-tester. Tested locally at 1280 simulator run() calls per block (~30.5M GPS).

Local test results

numSuccess=1 numFailure=0

Block 10: txs=1281, gas=31,358,110, GPS=30,495,768
Block 13: txs=1281, gas=31,358,110, GPS=30,585,337  
Block 16: txs=1281, gas=31,358,110, GPS=30,633,922
Block 19: txs=1281, gas=31,358,110, GPS=30,532,355

Related

  • base/base PR: adds type: simulator to the load-tester and auto-deploys the Simulator contract

meyer9 and others added 4 commits May 15, 2026 12:02
The benchmark proxy previously rejected any request body starting with '['
(a JSON array) with HTTP 400. The base-load-tester sends transactions in
batches using the standard JSON-RPC batch format, so all load-test
transactions were silently dropped.

Adds handleBatchRequest() which:
- Detects batch requests by checking body[0] == '['
- Parses each sub-request and routes through OverrideRequest()
- Returns a matching JSON array of responses

This enables the load-tester's BatchRpcClient to submit transactions
through the proxy at full throughput (tested at 1280 txs/block).

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Adds FlashblocksWsURL() string to the ExecutionClient interface so the
load-test worker can discover the builder's flashblocks WebSocket URL
without needing a direct reference to the builder client type.

- builder: returns ws://localhost:<websocketPort>
- geth, reth, baserethnode: return "" (no flashblocks server)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
… config

The load-test worker now populates two additional fields in the YAML config
it writes for the Rust binary:

- flashblocks_ws: the builder's local WebSocket URL (from FlashblocksWsURL())
  so the load-tester can connect to the flashblock stream
- setup_rpc: the direct node RPC URL (bypassing the proxy) used during
  Simulator contract deployment and storage initialization

Previously flashblocks_ws was missing entirely, causing the Rust binary to
fail to connect; and setup transactions sent to the proxy were never mined.

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Demonstrates the new simulator payload type driven through the
base-load-tester binary. The Simulator contract is deployed automatically
via CREATE before the benchmark starts if not already present at the
expected address.

Tested locally: achieves 1280 simulator run() calls per block at ~30.5M GPS
with create_storage=10, create_accounts=5 per call.

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
@cb-heimdall
Copy link
Copy Markdown
Collaborator

🟡 Heimdall Review Status

Requirement Status More Info
Reviews 🟡 0/1
Denominator calculation
Show calculation
1 if user is bot 0
1 if user is external 0
2 if repo is sensitive 0
From .codeflow.yml 1
Additional review requirements
Show calculation
Max 0
0
From CODEOWNERS 0
Global minimum 0
Max 1
1
1 if commit is unverified 0
Sum 1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants