Skip to content

fix(executor): wait for chain head advance between setup and test steps - #154

Closed
qu0b wants to merge 1 commit into
ethpandaops:masterfrom
qu0b:qu0b/fix/wait-chain-head-after-setup
Closed

fix(executor): wait for chain head advance between setup and test steps#154
qu0b wants to merge 1 commit into
ethpandaops:masterfrom
qu0b:qu0b/fix/wait-chain-head-after-setup

Conversation

@qu0b

@qu0b qu0b commented Mar 17, 2026

Copy link
Copy Markdown
Member

Summary

When running multi-block EEST fixtures (e.g., BAL scenario benchmarks), the executor runs setup and test steps sequentially. The setup step deploys contracts via engine_newPayload + engine_forkchoiceUpdated, and the test step immediately sends the benchmark block.

Problem: The test block's engine_newPayload returns SYNCING because the node hasn't committed the setup block as the canonical head yet. The engine_forkchoiceUpdated from the setup step returns VALID, but the internal state update is asynchronous — the chain head hasn't actually advanced when the next engine_newPayload arrives milliseconds later.

Fix: After the setup step completes successfully and before the test step begins, poll eth_blockNumber until the chain head advances beyond the pre-setup block number. This ensures the node has fully committed the setup block before receiving the test block.

  • Polls every 200ms with a 30s timeout
  • Falls back to a 500ms sleep if no baseline block info is available
  • Non-blocking: logs a warning on timeout but doesn't fail the test (the existing retry_new_payloads_syncing_state mechanism can still recover)

Context

This is needed for EEST fixtures with setup+execution blocks, such as the BAL scenario benchmarks which test:

  • Parallel execution (serial keccak chains)
  • State root computation (disjoint SSTOREs)
  • Cold storage prefetching (SLOAD linked-list chains)
  • Deploy-then-interact (cross-tx code dependencies)
  • Mixed dependency graphs (partial-order parallel scheduling)

These tests deploy contracts in a setup block and benchmark calls to them in the execution block. Without this fix, all multi-block tests fail with SYNCING.

Test plan

  • Compiles successfully
  • Run multi-block EEST BAL fixtures and verify setup blocks are committed before test blocks execute
  • Verify single-block fixtures (no setup step) are unaffected
  • Verify the wait doesn't add latency when chain head advances immediately

🤖 Generated with Claude Code

When running multi-block EEST fixtures, the setup step deploys contracts
via engine_newPayload + forkchoiceUpdated, and the test step immediately
sends the benchmark block. Without waiting for the node to commit the
setup block as canonical head, the test block's engine_newPayload returns
SYNCING because the parent block isn't recognized yet.

This adds a waitForChainHeadAdvance poll between setup and test steps
that checks eth_blockNumber until it advances beyond the pre-setup block.
Polls every 200ms with a 30s timeout. Falls back to a 500ms sleep if no
baseline block info is available.

This is needed for any EEST fixture with setup+execution blocks, such as
the BAL scenario benchmarks (parallel execution, state root computation,
deploy-then-interact, mixed dependency graphs).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@qu0b

qu0b commented Mar 17, 2026

Copy link
Copy Markdown
Member Author

Closing — the multi-block SYNCING issue was caused by genesis hash mismatch between EELS and geth, not by missing chain head synchronization. With the genesis fixes in jochem-brouwer/execution-specs#3 and fselmo/go-ethereum#1, all 44 BAL scenario tests (including multi-block deploy_then_interact) pass on upstream benchmarkoor without this change.

@qu0b qu0b closed this Mar 17, 2026
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.

1 participant