Replace repeated 20-byte addresses and 32-byte storage keys in EIP-7928 Block Access Lists (BALs) with compact references into one of the last eight canonical ancestor BALs. Expected reduction in BAL size is approximately 30–50%, depending on cross-block reuse.
A large share of BAL bytes are addresses and storage keys that already appeared in a recent block. Referencing the prior position is shorter than re-emitting the literal.
The key words "MUST", "MUST NOT", "SHOULD", and "MAY" in this document are to be interpreted as described in RFC 2119 and RFC 8174.
AddressKey = Address | AccountRef
StorageKeyRef = StorageKey | SlotRef
AccountRef = [ancestor_offset: uint8, account_index: uint32]
SlotRef = [ancestor_offset: uint8, account_index: uint32, slot_index: uint32]
ancestor_offset ∈ [0..7], where 0 is the parent block, 1 the grandparent, and so on up to 7 (the 8th ancestor).
AccountRef MUST be an RLP list of length 2. SlotRef MUST be an RLP list of length 3.
References and literals are disambiguated by RLP type: an Address is a 20-byte string and an AccountRef is a list; a StorageKey is an RLP-encoded 32-byte value and a SlotRef is a list.
The EIP-7928 structures are amended to accept references:
SlotChanges = [StorageKeyRef, List[StorageChange]]
AccountChanges = [AddressKey, List[SlotChanges], List[StorageKeyRef],
List[BalanceChange], List[NonceChange], List[CodeChange]]
BlockAccessList = List[AccountChanges]
All other EIP-7928 fields and semantics are unchanged.
A reference target is the expanded view of a canonical ancestor BAL: the literal-only BlockAccessList that has already passed EIP-7928 validation, with all of this EIP's references resolved. References MUST NOT target encoded ancestor BALs. References MUST NOT target the current block.
For an expanded ancestor BAL:
account_index is the position in the BAL, which EIP-7928 already requires to be sorted lexicographically by address.slot_index is the position in the account's canonical slot dictionary: the lexicographically sorted union of the storage keys appearing in the account's storage_changes and storage_reads, with duplicates removed.This EIP does not redefine ancestor BAL ordering beyond defining the per-account slot dictionary used for slot_index lookup.
Clients MUST retain or reconstruct expanded views and their per-account slot dictionaries for the last eight post-activation canonical blocks.
The targeted ancestor of a reference is the block at height block_number(B) - ancestor_offset - 1.
For any literal Address or StorageKey in the current BAL B, a valid reference is any AccountRef or SlotRef with ancestor_offset ∈ [0..7] that resolves to the same value against an expanded ancestor view available among the last eight canonical post-activation ancestor BALs. If multiple references resolve to the same literal value, all are valid candidates.
The canonical order over valid references is:
AccountRef: smallest (ancestor_offset, account_index).SlotRef: smallest (ancestor_offset, account_index, slot_index).A literal MUST NOT be used if a valid reference exists. The encoding MUST use the smallest valid reference under the canonical order.
For a block with BlockAccessList B:
ancestor_offset ∉ [0..7].block_number(B) - ancestor_offset - 1) is < 0 or < activation height.AccountRef whose account_index is out of bounds in the targeted ancestor.SlotRef whose account_index or slot_index is out of bounds in the targeted ancestor.AccountRef and SlotRef against the cached expanded view of the corresponding ancestor and replace it in B with its resolved literal to obtain the expanded B'.B'.B if any literal Address or StorageKey in it has a valid reference in the last eight expanded ancestor views.B if any reference is not the smallest valid reference under the canonical order defined above.References to blocks prior to activation are invalid. References are only valid if the targeted ancestor lies within the last eight canonical post-activation blocks.
The bal_items count from EIP-7928 is computed on the expanded BAL.
Address 20 bytes → AccountRef ≈ 5 bytes (1 + 4)
StorageKey 32 bytes → SlotRef ≈ 9 bytes (1 + 4 + 4)
Eight blocks bounds the ancestor state held for validation while capturing most cross-block reuse, and fits ancestor_offset in 3 bits.
Forcing the smallest valid reference makes the encoded BAL a function of the block and its ancestors only, preventing producers from bloating the encoding by choosing literals or larger offsets.
Hard fork. Pre-activation BALs are unreachable from references and remain valid in their original literal form.
TBD
Validation requires retaining eight expanded ancestor BAL views and their per-account slot dictionaries. Reference resolution is then a bounded array lookup, with no recursion, bounding DoS risk. The EIP-7928 bal_items budget continues to bound the expanded size.
A reorg invalidates blocks whose references no longer resolve under the new canonical chain, consistent with normal handling of block-bound data.
Copyright and related rights waived via CC0.