EIP-8268 Add storage root to the block access list (Storage Roots in Block Access Lists)
Proposed for Inclusion · Scaling & data · EIP status Draft · created 2026-05-21
Includes the post-block-execution storage trie root for each state-changed account in the EIP-7928 block access list (BAL), so that nodes holding only part of the state can also verify a block's state root.
Why it is needed
To verify a block, an Ethereum node must compute the post-execution state root, a value summarizing all account state, and compare it against the block header. The Block Access List (BAL) of EIP-7928 tells which storage slots of which accounts a block changed and to what values, but it does not carry the storage trie root, which summarizes the entire storage of a changed account. So a partially stateful node cannot obtain the storage root of an account it does not hold when that account is modified, cannot build the state trie leaf, and therefore cannot verify the block's state root. This EIP closes that gap by including the post-execution storage root for each modified account in the BAL. Balance, nonce, and code information are already in the BAL, so once the storage root is added, any node can assemble the state trie leaves of all modified accounts, whatever part of the state it stores.
What changes
Today
- The BAL carries the values of changed storage slots but not the per-account storage trie root
- A partially stateful node cannot obtain the storage root of a modified account that it does not store
- In the end, fully verifying a block's state root effectively requires holding the entire state
After EIP-8268
- For each state-changed account, the post-execution storage root is included in the BAL entry
- Any node can assemble the state trie leaves of modified accounts from the BAL alone and verify the state root
- The added cost is capped at 32 bytes per modified account, and accounts with empty storage shrink to 1 byte
Who is affected
- Client teams: The BAL encoding and block validity rules change, so implementations must be updated and a hard fork is required to apply it.
- Node operators: Nodes that do not store the full state can verify the post-execution state root directly.
- Network: The BAL size per block grows within a limit of the number of modified accounts times 32 bytes, which is within the size range set by EIP-7928.
In depth
Add a storage_root field to AccountChanges
An AccountChanges entry in which at least one of the state change lists (storage_changes, balance_changes, nonce_changes, code_changes) is non-empty MUST have a storage_root field appended at the end. Its type is StorageRoot = bytes32, and it is the account's storage trie root evaluated against the post-block-execution state. An account that was only accessed and not changed (an entry with all change lists empty) MUST NOT include storage_root and keeps the six-field structure of EIP-7928 as is. The remaining EIP-7928 rules, including ordering, uniqueness, the block_access_list_hash computation, and Engine API encoding, are unchanged, and storage_root is included in the RLP that the hash commits to.
Encoding rule for empty storage tries
For an account whose storage trie is empty after block execution, storage_root MUST be written as an empty byte string (RLP encoding 0x80), and MUST NOT use the 32-byte standard empty trie root 0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421. The reader MUST treat an empty byte string as that standard empty trie root when reconstructing the state trie leaf. This rule depends only on whether the post-block storage trie is empty, not on the account type, so externally owned accounts (EOAs), newly created or emptied contracts, and EIP-7702 delegated accounts are all handled by the same rule without inspecting the code.
Block validity conditions
For an AccountChanges entry that has storage_root, the block is invalid if either of two cases holds. First, the post-block storage trie is non-empty but storage_root is not the 32-byte storage trie root produced by block execution. Second, the post-block storage trie is empty but storage_root is not an empty byte string. An empty trie must be encoded as an empty byte string and a non-empty trie must be encoded as a 32-byte root, so exactly one valid encoding exists for each block.
Why only the storage root is added
The storage root is the only post-block state value that cannot be reconstructed from the BAL contents alone, because it depends on the account's entire storage trie and not just the modified slots. Balance, nonce, and code can already be recovered from the BAL's change records, so committing only the storage root is enough to build a complete state trie leaf. Restricting the field to accounts whose state changed bounds the overhead at 32 bytes per modified account and adds nothing for entries that were only accessed. Most accounts that change in a block are EOAs with no storage that only have a balance or nonce change, so their post-block storage trie is empty. Encoding this case as the empty byte string (0x80) instead of the 32-byte canonical empty root saves 32 bytes for each such account, and 0x80 cannot collide with any 32-byte root, so there is no ambiguity.
Backwards compatibility and security
This proposal changes the BAL encoding introduced by EIP-7928, so it requires a hard fork. The two encodings are incompatible: a client that implements only EIP-7928 will reject blocks that follow this EIP, and the reverse also holds. storage_root is a redundant commitment to data that execution already produces, so any mismatch is caught directly by the normal BAL validation process. The additional bandwidth is bounded by 32 * modified_accounts and stays below the BAL size range described in EIP-7928. Because exactly one encoding of the empty trie is enforced, block_access_list_hash remains deterministic and clients cannot produce different commitments for the same post-block state.
Status and call discussion
This EIP is in Draft status, so the specification may still change. It was not covered in the Hegotá discussion because no one presented it on the 07.16 ACDE #241 call. Carlos has accepted it with PFI status, and the presentation has been pushed to the next ACDE.