Skip to content

EIP-7928: block-level access lists - #2875

Open
anvacaru wants to merge 8 commits into
amsterdam-foundationfrom
eip-7928
Open

EIP-7928: block-level access lists#2875
anvacaru wants to merge 8 commits into
amsterdam-foundationfrom
eip-7928

Conversation

@anvacaru

Copy link
Copy Markdown
Contributor

Implements EIP-7928: the block-level access list is journaled during execution, built and RLP-encoded at #finalizeBlock, and validated against the header's blockAccessListHash (keccak256 of the RLP encoding).

Changes:

  • New <blockAccessLists> cells and journal primitives (#balTouch, #balRead, #balCapture*), plus the Ghaseip7928 flag and Gbalitemcost (2000) schedule constants.
  • Accesses are journaled at the point they happen: BALANCE/EXTCODE*, CALL*, CREATE*, SELFDESTRUCT, SLOAD/SSTORE, transaction setup, EIP-7702 authorities, withdrawals, and the pre/post-block system calls.
  • Value changes are derived as a pre/post diff rather than appended at the mutation site: each transaction journals pre-values (first write wins) and #balIncorporate diffs them against the post-state at transaction end. Changes made in reverted frames drop out on their own, and no-op writes (SSTORE of the same value, EIP-7702 re-delegation to the same target) produce no entry.
  • #balIncorporate runs at each boundary owning a BlockAccessIndex: 0 after the pre-block system calls, 1..n per transaction, n+1 after withdrawals and the post-block system calls.
  • Storage reads and changes are kept disjoint: SLOAD and no-op SSTORE slots go to storage_reads, and any slot with a recorded change is filtered out of the reads when the list is built.
  • #validateBlockAccessList builds the canonical list (addresses and slots sorted, entries in index order), RLP-encodes it, and compares its keccak against the header
    blockAccessListHash; it also rejects blocks whose item count exceeds gasLimit / ITEM_COST. The BAL carried in the block body is not consumed.
  • Deliberately excluded: EIP-2930 access-list entries, SYSTEM_ADDRESS, and precompiles warmed at transaction start, as only actual accesses are recorded.

anvacaru and others added 8 commits July 27, 2026 10:14
…primitives, schedule flag

Introduce the EIP-7928 Block-Level Access List infrastructure with no
behavior change: nothing is journaled or validated yet.

- schedule.md: add the Ghaseip7928 flag (DEFAULT false, AMSTERDAM true)
  and the Gbalitemcost constant (DEFAULT 0, AMSTERDAM 2000).
- evm.md: add the block-lifetime <blockAccessLists> cell group (index,
  touched set, reads, per-phase capture maps, accumulated change maps),
  the balE/balCE journal entries, #balTouch/#balRead/#balCapture* hooks,
  the per-phase #balIncorporate workers with total post-lookups, the
  #balAppend* / #balSortInts helpers, and a skip-only
  #validateBlockAccessList shell. Reset the cells in #startBlock.
- state-utils.md: reset the cells in clearBLOCK next to <balHash>.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Wire the EIP-7928 capture/read/touch hooks into every state-mutation and
account-access site, plus the per-phase incorporate points and block-access
index lifecycle. Validation is still off (the #validateBlockAccessList shell
remains a no-op), so all fixtures are unchanged.

- evm.md: capture balance in #transferFunds and the Amsterdam #finalizeTx
  refund/credit and #finalizeWithdrawals; capture nonce in #incrementNonce,
  #mkCreate, loadTx; capture code in #finishCodeDeposit and the EIP-8246
  #deleteAccounts reset; capture storage plus implicit read in SSTORE and the
  beacon-root / block-hash-history writes; read in SLOAD; touch in
  BALANCE / EXTCODE* / CALL-family / delegated-designation / CREATE / CREATE2 /
  SELFDESTRUCT beneficiary / #systemCall. Append #balIncorporate to #startBlock
  (idx 0) and #finalizeTx(true) (per-tx idx); bump <balIndex> to N+1 in
  #finalizeBlock.
- driver.md: capture sender balance/nonce and touch sender+recipient in both
  loadTx rules; capture blob-fee balance debit; bump <balIndex> per tx in
  startTx; touch the 7702 authority and capture its code/nonce on the
  Amsterdam #setDelegation / #addAuthority success paths.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…zeBlock

Turn on EIP-7928 validation. #validateBlockAccessList (injected into
#finalizeBlock between #processGeneralPurposeRequests and #finalizeBlockBlobs)
flushes the N+1 phase via #balIncorporate, reconstructs the canonical BAL as a
JSON value from the accumulated cells, keccak256-hashes its RLP encoding, and
enforces both the bal_items gas-limit budget and the header blockAccessListHash.

- Address universe = balTouched ∪ keys(reads) ∪ keys(change maps), sorted by
  #balSortInts; per account the JSON is
  [addr, [slotChanges], [reads], [balanceChanges], [nonceChanges], [codeChanges]]
  with reads filtered to slots without a surviving storage change.
- #balCheckItems enforces bal_items <= gasLimit / Gbalitemcost; #checkBalHash
  mirrors #checkRequestsRoot, setting EVMC_INVALID_BLOCK on mismatch.
- Validation is gated on Ghaseip7928, a nonzero <balHash>, and a
  non-INVALID_BLOCK status, so pre-Amsterdam and transition-fork blocks are
  unaffected.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…BlobGas

Both loadTx paths run #balCaptureBalance on the sender before
#deductBlobGas, and #balCaptureBalance is first-write-wins, so the
capture here was always discarded. Blob transactions are the only ones
reaching the rule; full test_bchain still 11650/0/14.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
(cherry picked from commit 8a1fc12b1ae5a4342d094984c6639f93934bc756)
#validateBlockAccessList only ran when the last transaction's status was
SUCCESS/REVERT/none, so a block whose final transaction halted
exceptionally never checked blockAccessListHash and accepted any BAL.
Exclude only EVMC_INVALID_BLOCK, matching EELS, which validates the
header unconditionally on otherwise-valid blocks.

Depends on the matching #processGeneralPurposeRequests guard change
(system-contract-hardening): without it a block ending in an exceptional
transaction skips the post-execution system calls, so the computed BAL
would be missing their index n+1 entries and the hash check would
falsely reject.

Co-Authored-By: Claude Opus 5 <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