Skip to content

Access Lists Specification

Flashblock-Level Access Lists (FAL) adapt EIP-7928 Block-Level Access Lists for chains that emit flashblocks, including Base. This specification defines their data structures, recording semantics, and validation rules.

FAL records every account and storage location accessed during flashblock execution, along with post-execution values. This enables parallel disk reads, parallel transaction validation, and state reconstruction without full re-execution.

Standard BAL (EIP-7928) targets L1 Ethereum where blocks are atomic units. Base produces flashblocks — incremental sub-block deltas streamed at 200ms intervals. FAL adapts the access-list concept to this architecture by:

  • Operating on incremental flashblock deltas rather than complete blocks.
  • Handling OP Stack-specific transaction types (L1 attributes, L1-to-L2 deposits).
  • Tracking three separate fee vaults instead of a single COINBASE.
  • Omitting beacon chain features absent from the OP Stack (EIP-4895 withdrawals, EIP-4788 beacon root, EIP-7002/7251 validator operations).
AspectBAL (EIP-7928)FAL
Unit of operationComplete blockFlashblock delta (incremental)
Hash storageBlock headerFlashblock metadata
Fee recipientSingle COINBASEThree OP Stack fee vaults
Transaction typesStandard + withdrawalsStandard + L1 attributes + L1-to-L2 deposits
Beacon chain featuresIncludedOmitted

Instead of recording balance changes against COINBASE, FAL tracks three separate fee vault addresses:

VaultAddressPurpose
Sequencer Fee Vault0x4200000000000000000000000000000000000011Priority fees
Base Fee Vault0x4200000000000000000000000000000000000019Base fees
L1 Fee Vault0x420000000000000000000000000000000000001aL1 data fees

The first transaction in each block (index 0) is the L1 attributes transaction. It updates the L1Block contract (0x4200000000000000000000000000000000000015) storage slots:

SlotContent
0L1 block number
1L1 base fee
2L1 timestamp
3Batcher hash
4Sequence number
5Blob base fee
6L1 block hash

L1-to-L2 deposits are treated as regular transactions with block access indices 1..n. The FAL records sender and recipient addresses with their balance changes.


pub struct FlashblocksPayloadV1 {
pub payload_id: PayloadId,
pub index: u64,
pub base: Option<ExecutionPayloadBaseV1>,
pub diff: ExecutionPayloadFlashblockDeltaV1,
pub metadata: Value, // Contains "flashblock_access_list"
}
pub struct FlashblockAccessList {
pub min_tx_index: u64, // Inclusive starting transaction index
pub max_tx_index: u64, // Exclusive ending transaction index
pub account_changes: Vec<AccountChanges>, // All account state changes
pub fal_hash: B256, // Keccak-256 of RLP-encoded changes
}

The following Python-style type aliases define the RLP encoding:

Address = bytes # 20-byte Ethereum address
StorageKey = bytes # 32-byte storage slot key
StorageValue = bytes # 32-byte storage value
CodeData = bytes # Variable-length bytecode
BlockAccessIndex = uint16
Balance = uint256
Nonce = uint64
# Constants (OP Stack adapted)
MAX_TXS = 30_000
MAX_SLOTS = 300_000
MAX_ACCOUNTS = 300_000
MAX_CODE_SIZE = 24_576
MAX_CODE_CHANGES = 1
# Change structures
StorageChange = [BlockAccessIndex, StorageValue]
BalanceChange = [BlockAccessIndex, Balance]
NonceChange = [BlockAccessIndex, Nonce]
CodeChange = [BlockAccessIndex, CodeData]
SlotChanges = [StorageKey, List[StorageChange]]
AccountChanges = [
Address,
List[SlotChanges], # storage_changes
List[StorageKey], # storage_reads
List[BalanceChange], # balance_changes
List[NonceChange], # nonce_changes
List[CodeChange] # code_changes
]
FlashblockAccessList = List[AccountChanges]

The following must be included in the FlashblockAccessList:

  • Addresses with state changes — any account whose storage, balance, nonce, or code was modified.
  • Inspection targets — targets of BALANCE, EXTCODESIZE, EXTCODECOPY, EXTCODEHASH.
  • Call targets — targets of CALL, CALLCODE, DELEGATECALL, STATICCALL.
  • Creation targets — addresses produced by CREATE and CREATE2.
  • Transaction parties — senders and recipients of every transaction.
  • Fee vault addresses — all three OP Stack fee vaults listed above.
  • SELFDESTRUCT beneficiaries — addresses receiving self-destructed balances.
  • System contracts — L1Block contract (0x4200...0015) and EIP-2935 block hash contract.
  • L1-to-L2 deposit recipients — recipients of cross-chain deposits.
  • Precompiled contracts — when accessed during execution.
  • L1Block during L1 attributes execution — always included in the first flashblock.

Addresses without state changes must still appear with empty change lists.

To ensure deterministic encoding:

  • Addresses are sorted lexicographically (bytewise ascending).
  • Storage keys are sorted lexicographically within each account.
  • Block access indices are sorted in ascending order within each change list.
Index ValueAssigned To
0Pre-execution system contracts and L1 attributes transaction (first flashblock only, where min_tx_index = 0).
min_tx_indexmax_tx_index - 1Transactions within the flashblock, including L1-to-L2 deposits and regular transactions.
n + 1Post-execution system contracts (final flashblock only).

Writes (recorded in storage_changes):

  • Any value change where the post-execution value differs from the pre-execution value.
  • Zeroing a slot (pre-execution value exists, post-execution value is zero).

Reads (recorded in storage_reads):

  • SLOAD without a corresponding write.
  • No-op writes where SSTORE is called but the post-execution value equals the pre-execution value.

Post-transaction balances are recorded for:

  • Senders — after gas cost, transferred value, and L1 data fee are deducted (including gas refunds).
  • Recipients — only when transferred value is greater than zero.
  • Fee vaults — updated balance after each transaction.
  • SELFDESTRUCT / SENDALL beneficiaries — balance after receiving funds.
  • Deposit recipients — balance after the deposit is credited.

For zero-value transfers, the address is included but omitted from balance_changes.

Post-transaction runtime bytecode is recorded for:

  • Contracts deployed via CREATE or CREATE2.
  • Contracts modified via SELFDESTRUCT (if applicable).
  • EIP-7702 delegation indicators.

Post-transaction nonces are recorded for:

  • EOA senders (incremented by transaction execution).
  • Successful CREATE performers (nonce incremented).
  • Newly deployed contracts (nonce set to 1).
  • EIP-7702 authorities (nonce incremented on successful delegation).
  • Precompiles: Include when accessed. Record a balance change if the precompile receives value.
  • SENDALL: Record both sender (balance to zero) and beneficiary (balance increased).
  • SELFDESTRUCT: Include without nonce/code changes. Record balance-to-zero if pre-transaction balance was positive. Include storage reads.
  • Gas refunds: The final sender balance (after refunds) is the recorded value.
  • Exceptional halts (reverts/out-of-gas): Record the final nonce and balance of the sender and fee vaults. Include all accessed addresses even if execution was reverted.
  • EIP-7702: The authority address must be included with nonce/code changes after a successful delegation operation, and with empty changes if the delegation fails.

When no state changes exist in a flashblock:

  • account_changes is an empty list.
  • fal_hash equals the Keccak-256 of an empty RLP list: 0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347.

The following pseudocode describes FAL validation:

def validate_fal(flashblock, provided_fal):
# 1. Extract the FAL from flashblock metadata
fal = extract_fal(flashblock.metadata)
# 2. Verify the provided hash matches the encoded account_changes
encoded = rlp_encode(fal.account_changes)
expected_hash = keccak256(encoded)
assert fal.fal_hash == expected_hash, "FAL hash mismatch"
# 3. Execute the flashblock and collect actual accesses
actual_accesses = execute_flashblock(flashblock)
actual_encoded = rlp_encode(actual_accesses)
actual_hash = keccak256(actual_encoded)
# 4. Verify actual execution matches the provided FAL
assert actual_hash == fal.fal_hash, "Execution mismatch"
return True

FAL enables the following optimizations:

  • Parallel disk reads — storage slots and account data can be prefetched across transactions.
  • Parallel transaction validation — independent transactions can be validated concurrently.
  • State reconstruction without execution — post-state can be derived from the access list alone.
  • Compact representation — expected size is approximately 40—50 KiB compressed on average, comparable to BAL.

Canonical specification: docs/specs/access-lists.md