Skip to content

rpc/jsonrpc: build executionWitness access set from BAL for Amsterdam blocks#21497

Draft
awskii wants to merge 11 commits into
mainfrom
awskii/witness-bal-access-set
Draft

rpc/jsonrpc: build executionWitness access set from BAL for Amsterdam blocks#21497
awskii wants to merge 11 commits into
mainfrom
awskii/witness-bal-access-set

Conversation

@awskii
Copy link
Copy Markdown
Member

@awskii awskii commented May 28, 2026

Builds the debug_executionWitness access set from the persisted Block-Level Access List (EIP-7928) for Amsterdam blocks instead of re-executing the block. Pre-Amsterdam blocks keep the existing re-execution path byte-for-byte. Draft because end-to-end witness verification is blocked on an Amsterdam commitment-pipeline divergence (Change 4 — stub plan committed here).

Deliverable 3 of 3:

Why

The witness is a proof against parent state, built from commitment history; the post-state is already in the DB. Re-execution exists purely to recover the access set. For Amsterdam, EIP-7928 already persists that access set in the BAL, consensus-validated against header.blockAccessListHash. Consuming it removes the hand-rolled execution loop that can drift from canonical execution, and is the correct way to support Amsterdam witnesses — the serial re-exec path cannot even build a BAL.

What's in this PR

  • accessedStateFromBAL(bal, readCode) — pure mapping from types.BlockAccessList to the existing accessedState shape (addresses; storage = StorageReads ∪ StorageChanges[].Slot; code = over-approximation: include every BAL address with non-empty parent-state code).
  • buildAccessedStateFromBAL(ctx, tx, blockHash, blockNum, parentTxNum) — DB wrapper: rawdb.ReadBlockAccessListBytes + types.DecodeBlockAccessListBytes + state.NewHistoryReaderV3(tx, parentTxNum).ReadAccountCode(addr). Distinguishes pruned (nil bytes → error) from legitimately empty (zero-entry list).
  • ExecutionWitness branches on chainConfig.IsAmsterdam(header.Time) && !chainConfig.IsEIPDisabled(7928):
    • Amsterdam → BAL provider; result.Headers = [parent] (EIP-2935 BLOCKHASH is served from history-contract state captured in BAL.StorageReads).
    • Pre-Amsterdam → existing re-execution path, byte-for-byte unchanged.
  • SystemAddress: taken from the BAL as-is (BAL already encodes the consensus EIP-7928 rule).

Downstream shared backend (detectCollapseSiblings, buildWitnessTrie, verifyWitnessStateless) untouched.

Out of scope

  • Exact node-set parity for Amsterdam (State/Codes multiset matching with Geth/EEST) — blocked on Change 4 (commitment-pipeline divergence reproducible under both BAL and re-exec paths).
  • "Fewer-nodes" zkevm class (~4,128 fixtures observed during Change 2 corpus run) — partially overlaps with this PR's BAL coverage; residual deferred to Change 4.
  • zkevm test suite (execution/tests: add zkevm execution-witness suite (zkevm@v0.4.0) #21487) is a separate branch; no dependency.

Plan: docs/plans/completed/20260527-witness-bal-access-set.md.

awskii added 11 commits May 28, 2026 11:36
…gApi harness

Verifies the three pieces Task 1 depends on compose in one process:
- AllProtocolChanges (Amsterdam@genesis) chain via ExecModuleTester
  produces and persists a BAL through InsertChain
- statecfg.EnableHistoricalCommitment + WriteDBCommitmentHistoryEnabled
  satisfies debug_executionWitness's commitment-history gate
- DebugAPIImpl built from newBaseApiForTest reaches ExecutionWitness on
  the Amsterdam block

No new wiring needed for Task 1. Recipe and decisions recorded in the plan.
Adds TestExecutionWitnessAmsterdamBAL and
TestExecutionWitnessAmsterdamActivationBlock, plus a tiny
recordingStateConstructedHookForTest seam in debug_execution_witness.go so
tests can observe whether the re-exec path was taken without adding a
production counter. Both tests currently fail with state-root mismatch (the
existing re-exec path produces wrong roots for Amsterdam blocks) — RED for
the right reason; the BAL branch (Tasks 2/3) will green them.

Absorbs the Task-0 constructability spike into debug_witness_bal_test.go,
extracting the harness as setupAmsterdamBALHarness per the Task-0 decision
to keep one Amsterdam test surface.
Split into a pure mapping (accessedStateFromBAL) plus a DB-touching wrapper
(buildAccessedStateFromBAL) so the address/storage/code shaping is unit-testable
without spinning up a temporal tx. Six tests cover: empty BAL, addresses +
storage reads∪changes dedup, SystemAddress preserved as-is, code over-
approximation with EOA skip, shared-code dedup in SortedCodes, and the pruned
BAL distinct error via a never-written block hash.

The IsAmsterdam branch in ExecutionWitness lands in Task 3; Task 1's harness
tests remain RED for now and flip green once the branch is wired.
…mbing)

Wraps the existing RecordingState re-exec path in an `else`; the new
`if chainConfig.IsAmsterdam(header.Time)` branch calls
`buildAccessedStateFromBAL` and leaves `accessedBlockHashes` empty so
`collectAccessedHeaders` emits parent-only for Amsterdam. The shared
`detectCollapseSiblings` / `buildWitnessTrie` / `verifyWitnessStateless`
calls are untouched. Pre-Amsterdam `git diff -w` shows only the new `if`
plus the hoisting of `fullEngine`, `header`, and `accessedBlockHashes`
declarations needed by both paths.

Amsterdam tests keep the path-assertion (hookCount == 0) live but
t.Skip the verifyWitnessStateless-passes assertion pending Change 4
(Amsterdam commitment-pipeline divergence — Risk 1). The skip carries
the tracking link per the explicit user override of the no-skip rule.
Mark Task 4 verification gates complete in the plan: 6 BAL mapping
unit tests green, Amsterdam path assertion green (hookCount == 0
before t.Skip), pre-Amsterdam TestExecutionWitness sub-cases
unchanged, Amsterdam skip messages reference the Change 4 plan
path, make lint clean, make erigon integration builds, and
go test ./rpc/jsonrpc/... clean.
Captures Risk 1 findings from witness-bal-access-set: detectCollapseSiblings.ComputeCommitment
diverges from block.Root() for Amsterdam blocks under both BAL and force-routed re-exec
paths. Lists debug observations and sketches investigation entry points so the skipped
Amsterdam witness tests can be unblocked.
All tasks 0-5 complete. No CLAUDE.md update needed — work followed
existing fork-gate + provider patterns.
Source comments should not carry PR/plan/review references per the
project comment style guide.
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