Skip to content

Execute a submitted block and check it against its header - #532

Open
0w3n-d wants to merge 1 commit into
od/builder-sim-validation-step3from
od/builder-sim-execute-step4
Open

Execute a submitted block and check it against its header#532
0w3n-d wants to merge 1 commit into
od/builder-sim-validation-step3from
od/builder-sim-execute-step4

Conversation

@0w3n-d

@0w3n-d 0w3n-d commented Aug 28, 2026

Copy link
Copy Markdown
Collaborator

Issue: #527 (step 4 of 10)

Base branch: od/builder-sim-validation-step3 (#531, step 3). Retarget as the
stack merges.

What this PR does

BlockValidator::execute runs validate_block_pre_execution, executes the
block on its parent state through ethrex's Evm, then checks gas used, the
receipts root and logs bloom, the requests hash and the state root. validate
chains it onto prepare.

The store is read-only throughout. apply_account_updates_batch computes the
post-state root in memory without committing, and nothing calls
Blockchain::add_block.

What this PR deliberately does not do

No payment check, no blacklist. Two checks the reth simulator performs are
deliberately absent, both verified rather than assumed:

  • validate_block_body. It compares the transactions and withdrawals roots
    against the body, but the conversion computes both roots from that body, so it
    cannot fail. The relay checks the transactions root itself.
  • Block access lists. ExecutionPayloadV3 carries no BAL hash, so Amsterdam
    needs a newer payload version before this is checkable at all.

Inclusion lists are now out of scope for this simulator entirely; the issue's
step 7 is struck out. A block that violates a submitted list passes here and
fails on the reth simulator.

Tests

Written first and signed off before implementation. 8 new, 20 in the file:

  • A valid block executes and yields receipts and account updates.
  • Validating does not store the block. The latest block number stays at 0
    and the block is absent from the store afterwards. This guards the property
    that makes this a simulator and not a node.
  • Tampered state root, gas used and receipts root are each rejected.
  • Execution requests the block did not produce are rejected.
  • A bad base fee is rejected before execution, proving the pre-execution checks
    actually run.
  • A transaction with an unusable nonce fails execution.

One fixture change: bid_trace recomputes the block hash from the converted
block, so a payload-tampering test reaches execution instead of stopping at the
step 3 bid-trace check.

just fmt-check, just test and cargo clippy --all-features --no-deps -- -D warnings
are clean. 54 tests pass in helix-builder, up from 46.

Reviewer checklist

  • CI (lint, unit-test) is green
  • Matches the linked issue/step
  • No unexplained scope creep or unrelated files touched

Runs validate_block_pre_execution, executes on the parent state, then
checks gas used, receipts root, requests hash and state root. The store
is only read: the submitted block is never persisted.

Step 4 of #527.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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