Access Lists
Source: docs/design/access-lists.md
Status: Draft Issue: chain-5alwd Date: 2026-02-03
Overview
Section titled “Overview”Access lists let a transaction declare which accounts and storage keys it
expects to touch. The chain can use these hints to prefetch state, charge
lower gas for declared (warm) keys, and improve parallel scheduling. The
current codebase already contains AccessList types, validation rules, and
strict-access checks behind a feature flag. This document formalizes the
semantics and activation plan.
- Reduce disk I/O and latency by prefetching declared state.
- Provide a deterministic warm/cold gas model for declared accesses.
- Enable strict access enforcement (reject undeclared accesses) when activated via a hard fork.
- Improve parallel execution scheduling with declared conflicts.
- Keep transaction format stable (reuse
TxBodyV1.access_list).
Non-Goals
Section titled “Non-Goals”- Full stateless execution or witness generation (future work).
- Automatic access list inference inside the VM (client-side tooling only).
- Unbounded range/prefix expansion that can DoS validators.
Current State (Already Implemented)
Section titled “Current State (Already Implemented)”TxBodyV1includesaccess_list: AccessListand it is part of the signed payload.AccessList::validate()enforces size and descriptor rules.TracedStateBackendcan track touched keys and enforce strict access (ASHEN_STRICT_ACCESS).state_keys_from_access_listderives a concrete key set for prefetch.prefetch_access_list_keysissues read requests to warm the hot cache.- Gas constants for access list accounting exist in
src/core/execution/gas.rs.
Transaction Format
Section titled “Transaction Format”No new transaction type is introduced. We keep TxBodyV1.access_list and
formalize its semantics:
accounts: declares per-account metadata accesses (balance, nonce, code, metadata) for each address.storage: declares storage descriptors per contract address.AccessDescriptorvariants:Exact: a specific 32-byte key.Prefix: a prefix (1-32 bytes).Range: inclusive/exclusive bounds.
AccessModeindicates Read / Write / ReadWrite intent for scheduling and enforcement policies.
Versioning note: we do not add an access-list version or format flag in v1.
Because the chain is greenfield (no DEPLOYED flag), we can adjust
TxBodyV1 pre-launch without adding a version flag. After deployment,
incompatible changes must use a new TxBody::V2.
Validation Rules
Section titled “Validation Rules”Validation happens at admission time and prior to execution:
AccessList::validate()must pass or the tx is rejected withInvalidAccessList.- All addresses referenced by
accountsandstorageentries must exist in state at admission time, except when the transaction is explicitly creating the address (deploy or first-fund transfer). - If strict access is enabled, any touched key not covered by the access
list causes execution to revert with
UndeclaredStateAccess. - Prefix/range descriptors are valid for access checks and scheduling, and they should also drive bounded prefetch scans.
Gas Model
Section titled “Gas Model”The gas model has three parts:
- Declaration cost: charge per declared account and descriptor to prevent DoS via huge access lists.
- Warm vs cold storage: accesses covered by the access list are charged at warm rates; undeclared keys are charged at cold rates with a punitive multiplier to discourage missing access lists.
- Prefetch accounting: prefetching declared keys incurs a small per-key cost (observational today, enforceable after activation).
Descriptor pricing guidance:
Exactdescriptors: 2_000 gas per descriptor.Prefix/Range: 3_000 gas per descriptor (slightly higher thanExact).- Warm access for
Exactuses the warm schedule fromgas-v1. - Warm access for
Prefix/Rangeuses warm * 1.25 (rounded up), still below cold pricing. - Undeclared access uses cold pricing with a punitive multiplier of 2.0.
These are starting values; tune after benchmarks.
Activation plan:
- Phase 0 (current): log-only access list gas and prefetch costs.
- Phase 1: enforce declaration costs and warm/cold price distinction.
- Phase 2: enable strict access rejection for undeclared keys.
Prefetch Strategy
Section titled “Prefetch Strategy”Prefetching should be opportunistic and bounded:
- Use
state_keys_from_access_listto derive concrete keys. - Prefetch should also honor
PrefixandRangedescriptors via bounded scans (limit by keys or bytes). Truncate when the per-tx budget is hit. - Prefetch at block construction time so the block builder pays for the I/O and can price it via gas.
- Prefetching should be disabled when the backend lacks a hot cache.
- Cap prefetch per transaction to prevent a single tx from exhausting I/O.
Initial defaults:
max_prefetch_keys_per_tx = 512max_prefetch_bytes_per_tx = 256 KiBmax_prefetch_scan_keys_per_descriptor = 64
Hot Cache Integration
Section titled “Hot Cache Integration”- Prefetch should warm the hot cache (
CachedJournalStateBackend). - If the cache is full, respect its eviction policy (LRU) and never bypass capacity limits.
- Consider cache TTL / height-based expiry for prefetched keys to avoid long-lived cache pollution.
- When
chain-5hsclands, prefetch can target the cached backend directly and rely on its size/eviction rules.
RPC: Access List Generation
Section titled “RPC: Access List Generation”Clients should be able to request access list generation during simulation:
SimulationOptions.generate_access_list = truetriggers tracing of touched keys and returns aGeneratedAccessListwith an estimated gas savings.- Expose this via an RPC method analogous to
eth_createAccessList, e.g.tx_createAccessList. - The access list is advisory; signing clients decide whether to include it. The RPC response should include the estimated gas savings.
Block-STM Integration
Section titled “Block-STM Integration”Declared access lists enable scheduler optimizations:
- Use descriptor overlap checks to precompute conflicts.
- Prefer scheduling non-overlapping transactions in parallel.
- AccessMode can inform read-only vs write conflicts.
This integrates with the Block-STM design doc (docs/design/block-stm.md).
Consensus / Hard Fork Plan
Section titled “Consensus / Hard Fork Plan”Access list enforcement is consensus-critical and must be activated at a specific block height:
- Add a
access_list_activation_heightconfig in consensus parameters. - Because the chain is not live, set this at launch time (TBD).
- After activation: declaration costs + warm/cold pricing enforced.
- Strict access rejection can be enabled later (separate height or config).
Open Questions
Section titled “Open Questions”- Finalize activation height(s) once launch planning is fixed.
- Confirm the initial prefetch caps after a quick I/O benchmark pass.
- Decide whether strict access should be a separate hard fork or a config toggle post-launch.
Deliverables
Section titled “Deliverables”docs/design/access-lists.md(this document)- Transaction format notes for access list semantics
- Gas schedule delta for warm/cold pricing and declaration costs
- RPC spec for access list generation and return type
- Activation plan (block height and phased rollout)