--- eip: 8247 title: Ancestor-Indexed BALs description: Compact references to recent block access lists for repeated addresses and storage slots author: Toni Wahrstätter (@nerolation) discussions-to: https://ethereum-magicians.org/t/eip-8247-ancestor-indexed-bals/29926 status: Draft type: Standards Track category: Core created: 2026-05-03 requires: 7928 --- ## Abstract Replace repeated 20-byte addresses and 32-byte storage keys in [EIP-7928](./eip-7928.md) 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. ## Motivation 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. ## Specification The key words "MUST", "MUST NOT", "SHOULD", and "MAY" in this document are to be interpreted as described in RFC 2119 and RFC 8174. ### Types ```text 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. ### Modified Structures The EIP-7928 structures are amended to accept references: ```text 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. ### Reference Targets 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. ### Canonical Encoding 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: - For `AccountRef`: smallest `(ancestor_offset, account_index)`. - For `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. ### Validation For a block with `BlockAccessList B`: 1. Reject any reference with `ancestor_offset ∉ [0..7]`. 2. Reject any reference whose targeted ancestor (`block_number(B) - ancestor_offset - 1`) is `< 0` or `<` activation height. 3. Reject any `AccountRef` whose `account_index` is out of bounds in the targeted ancestor. 4. Reject any `SlotRef` whose `account_index` or `slot_index` is out of bounds in the targeted ancestor. 5. Resolve each `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'`. 6. Apply EIP-7928 validation to `B'`. 7. Reject `B` if any literal `Address` or `StorageKey` in it has a valid reference in the last eight expanded ancestor views. 8. Reject `B` if any reference is not the smallest valid reference under the canonical order defined above. ### Activation 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. ### Size Constraint The `bal_items` count from EIP-7928 is computed on the expanded BAL. ## Rationale ### Encoding Savings ```text Address 20 bytes → AccountRef ≈ 5 bytes (1 + 4) StorageKey 32 bytes → SlotRef ≈ 9 bytes (1 + 4 + 4) ``` ### Window of Eight Eight blocks bounds the ancestor state held for validation while capturing most cross-block reuse, and fits `ancestor_offset` in 3 bits. ### Canonical Encoding Rule 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. ## Backwards Compatibility Hard fork. Pre-activation BALs are unreachable from references and remain valid in their original literal form. ## Test Cases TBD ## Security Considerations 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 Copyright and related rights waived via [CC0](../LICENSE.md).