Repository navigation
feat(evm): archive Amsterdam headers and block access lists - #596
Merged
Merged
Conversation
Blocks from the Amsterdam (Glamsterdam) upgrade carry two new header fields, blockAccessListHash (EIP-7928) and slotNumber (EIP-7843). Both now count towards block-hash verification; before, every post-upgrade block failed it. The dumper can also fetch each block's EIP-7928 access list (--with-block-access-lists) and check it against the header commitment (--verify-block-access-list-hash). The list is stored in the raw block as blockAccessList_. Only blocks whose header commits to a list are asked for one: for earlier blocks reth tries to rebuild the list by re-execution and fails. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
Persistent access-list mismatches can silently stall polling ingestion without bounded retries or an error.
1 open finding
What changed in this PR
Adds Amsterdam support to EVM archiving, including new header commitments and optional EIP-7928 block access-list retrieval and verification.
Changes:
- Encodes Amsterdam header fields and block access-list hashes.
- Adds RPC, normalization, and dumper support for access lists.
- Adds fixture-based verification and integration tests.
| File | Description |
|---|---|
evm/evm-rpc/src/verification.ts |
Encodes Amsterdam headers and access lists. |
evm/evm-rpc/src/rpc.ts |
Fetches and verifies access lists. |
evm/evm-rpc/src/rpc-data.ts |
Defines Amsterdam RPC schemas. |
evm/evm-rpc/src/types.ts |
Extends block and request types. |
evm/evm-rpc/src/chain-utils.ts |
Exposes access-list hashing. |
evm/evm-normalization/src/raw.ts |
Archives access lists in raw blocks. |
evm/evm-dump/src/dumper.ts |
Adds access-list CLI options. |
evm/evm-rpc/test/verification.test.ts |
Tests header and access-list commitments. |
evm/evm-rpc/test/rpc.block-access-list.test.ts |
Tests RPC retrieval and verification. |
evm/evm-rpc/test/helpers/fixture-loader.ts |
Loads access-list fixtures. |
common/changes/@subsquid/evm-rpc/feat-evm-amsterdam-archive_2026-10-12-05-14.json |
Records the RPC feature release. |
common/changes/@subsquid/evm-normalization/feat-evm-amsterdam-archive_2026-10-12-05-14.json |
Records the normalization release. |
common/changes/@subsquid/evm-dump/feat-evm-amsterdam-archive_2026-10-12-05-14.json |
Records the dumper release. |
🧠 Review effort: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
…valid Once caught up, the dumper reads through PollStream, which cut a batch at an invalid block and polled it again forever: no retry limit, no log, and the block's error never surfaced. A persistent verification failure (a bad access list, rejected call frames) stalled the dumper silently. Every invalid poll is now logged with its reason. On the finalized path a block still invalid after 5 retries, the budget getBlocks() gives the same case, fails the stream with that reason and the RPC URL. At the head of the latest stream a provider may still be catching up, so that path keeps polling. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A null access list, whether pruned or from an upstream that does not have the block yet, became a RetryError on the shared client. evm-dump runs that client with an effectively unbounded retry budget, so the call could hang without ever reaching a bounded retry or an error. Like a null state-diff trace, it now marks the block invalid, with a reason. getBlocks() and the finalized poll stream retry such a block 5 times, then fail with that reason. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

What
The Amsterdam (Glamsterdam) upgrade, live on Sepolia since block 11,856,337, adds two header fields and a new per-block state record. This PR makes the EVM dumper accept post-upgrade blocks and archive both.
blockAccessListHash(EIP-7928) andslotNumber(EIP-7843) are appended afterrequestsHash, each only when present. Without this, every post-upgrade block fails--verify-block-hash.--with-block-access-listsfetches each block's list witheth_getBlockAccessListByBlockHash, and stores it in the raw block asblockAccessList_.blockAccessListHashare asked for a list. For earlier blocks, reth tries to rebuild the list by re-execution and fails outside its state history.--verify-block-access-list-hashcheckskeccak256(rlp(list))against the header'sblockAccessListHash. A mismatch marks the block invalid, so it is retried like other verification failures.--verify-block-hash, this makes the access list the only state record that is verifiable end to end.BlockAccessListvalidates the JSON-RPC shape returned by reth: per account,storageChanges,storageReads,balanceChanges,nonceChangesandcodeChanges, each with a block accessindex.mapRawBlockpicks header fields one by one, so ingest output is unchanged. Normalizing the new data is left for a follow-up.getBlocks()already did. Thelatestpath keeps polling with a warning: at the chain tip, a provider may still be catching up.Testing
slotNumberfrom the header encoding fails the block-hash test.slotNumber, forgedblockAccessListHash, a changed storage write and a dropped storage read each break the relevant hash. A list missing a change kind fails the schema. The empty list hashes tokeccak256(rlp([])).Rpcintegration: a list is fetched and verified; a tampered list marks the block invalid; without verification the list is kept as is; pre-Amsterdam blocks never trigger the access-list call.evm-dumpover Sepolia 11,856,317–11,856,356 (20 blocks either side of the fork) to a local directory. Run with receipts, call traces, state diffs, every--verify-*flag,--call-frame-validation reject,--with-block-access-listsand--verify-block-access-list-hash.slotNumber,blockAccessListHashand ablockAccessList_that an independent Python RLP encoder hashes back to the header value.evm-ingestmaps all 40 blocks.evm-rpcsuite: 395 passed, 29 skipped. Every package downstream ofevm-rpcbuilds.Provider notes
As of reth v2.7.0, reth serves
eth_getBlockAccessListByBlockHash/ByBlockNumber. The Geth and Erigon 3.7.1 endpoints checked do not, so the access-list method may need to be routed to a different provider from the rest of the dump.Execution clients only have to keep access lists for about two weeks. A dumper that falls further behind than that can no longer fetch them for the oldest blocks. The response for a pruned list hasn't been observed yet. A
nullmarks the block invalid; after 5 retries the dump fails, naming the unavailable list. An error fails the batch.🤖 Generated with Claude Code