GOMTU Crypto
guidePart 29 of 41 in this guide

Ethereum Access Lists (EIP-2930): Warm Storage and Gas Explained

Learn how EIP-2930 access lists pre-warm Ethereum addresses and storage slots, how gas accounting works, and when eth_createAccessList can mislead.

GOMTU
GOMTU
Crypto Research · August 29, 2026 · 6 min read
Share𝕏in

You inspect an Ethereum transaction and find an accessList filled with contract addresses and 32-byte storage keys. Is it a permission list? A security boundary? Neither. An Ethereum access list is a gas-accounting hint that connects blockchain basics to the state a transaction expects to touch. The transaction may still access other state, and a poor list can cost more gas rather than less.

This guide explains EIP-2930 transaction access lists, the warm-versus-cold model behind them, their exact gas tradeoff, and a cautious workflow for eth_createAccessList.

What an Ethereum access list is

Advertisement

Think of the EVM as a clerk retrieving files from a large archive. Opening a cabinet for the first time is the expensive, cold access. Once the file is on the desk, later reads are cheaper, or warm. An access list is a note saying which cabinets and folders should be placed on the desk before execution begins.

EIP-2930 defines access tuples. Each tuple contains one 20-byte account address and zero or more 32-byte storage keys belonging to it. At transaction start, listed addresses and slots enter the EVM's warm sets.

The list is optional and non-enforcing. Execution does not revert merely because it touches an unlisted address or slot; that access follows normal cold-access rules. It is not a firewall, allowlist, or complete manifest. The sender, destination, and precompiles also receive special treatment under protocol rules.

Why EIP-2930 exists

EIP-2929 raised first-access costs for certain account and storage operations in the Berlin upgrade. The change better reflected client work and increased resistance to denial-of-service patterns. It also created transaction-scoped sets distinguishing already-accessed state from cold state.

EIP-2930 let senders declare and prepay for expected state. Contracts sensitive to EIP-2929 could pre-warm known locations, while clients could learn some expected reads early enough to prefetch data.

The proposal uses EIP-2718's typed envelope. Its dedicated transaction type is 0x01, and the list is included in the signed payload. The Ethereum transaction-types guide places that format beside legacy and types 0x020x04. Access lists did not disappear with dynamic fees: EIP-1559 type-0x02 transactions also carry an access_list field.

How warm and cold gas accounting works

EIP-2930 charges intrinsic gas before execution:

Declared itemIntrinsic charge
Address2,400 gas
Storage key1,900 gas

Under EIP-2929, a first cold account access costs 2,600 gas and a warm one costs 100. A first cold storage read costs 2,100 gas and a warm read costs 100. These figures explain the discount, but not every entry saves gas.

Declaring a storage key costs 1,900, then its first warm read costs 100: 2,000 rather than 2,100 gas when that read actually happens. An unused key only adds intrinsic cost. Some addresses are warm by default, and execution can take a different branch.

Duplicates are valid but charged each time. Since the warm collection behaves like a set, duplication adds cost without extra benefit.

What the transaction contains

JSON-RPC represents a list in a readable shape:

{
  "accessList": [{
    "address": "0x1111111111111111111111111111111111111111",
    "storageKeys": [
      "0x0000000000000000000000000000000000000000000000000000000000000007"
    ]
  }]
}

A storage key is a raw EVM slot, not a variable name. Solidity mappings and dynamic arrays derive slots through hashing, while proxies may run implementation code against proxy storage. Guessing a slot from a source variable's position can be wrong.

The list also does not replace Ethereum calldata. Calldata specifies the requested function and arguments; the list names state to warm for gas accounting. Both are signed data, but answer different questions.

Generate one with eth_createAccessList

The current Ethereum Execution API specifies eth_createAccessList. It accepts a transaction call object and block context, then returns an accessList, estimated gasUsed, and possibly an error.

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "eth_createAccessList",
  "params": [{
    "from": "0x2222222222222222222222222222222222222222",
    "to": "0x1111111111111111111111111111111111111111",
    "data": "0x12345678"
  }, "pending"]
}

Use this workflow:

  1. Build the exact call with the correct chain, sender, destination, value, and calldata.
  2. Select an explicit state context such as pending, latest, or a supported block number.
  3. Call the method on a trusted client or RPC endpoint.
  4. Inspect and deduplicate every address and key.
  5. Estimate or simulate both versions at the same state: with and without the list.
  6. Re-run near submission when state-dependent execution can change.
  7. Confirm the final destination, calldata, fees, and list before signing.

Geth's RPC documentation warns that generation is an estimate and adding the result does not necessarily reduce gas. It is a simulation tool, not a guaranteed optimizer.

When it helps—and when it does not

A list is most plausible when execution repeatedly follows a predictable route through known contracts and slots. Infrastructure operators may also need controlled gas behavior around cold state access.

It may be useless or expensive when:

  • entries are never touched;
  • an address is already warm by protocol rule;
  • duplicates add charges;
  • changing state selects another execution branch;
  • state changes between generation and inclusion; or
  • a broad generated list costs more than its discounts.

Compare total gas, not one opcode's discount. Also separate gas units from the ETH-denominated fee. Fewer units can still cost more ETH at a higher effective gas price. The transaction receipt guide explains how to verify actual gas afterward.

Risks and limitations

A generated list can become stale

The RPC simulates against selected state. An oracle update, prior transaction, balance change, or timestamp may lead the contract to different slots. Unlisted access still works, but estimated savings can change.

Planned access becomes public

Access lists are public transaction data. They contain no private key, but can reveal expected contracts and slots. Hexadecimal is not secrecy.

It does not make a contract safe

An accurate list says nothing about destination authenticity, intended calldata, or malicious logic. It cannot limit approvals, prevent reentrancy, or guarantee an economic result.

RPC support varies

Providers can differ in enabled methods, historical-state availability, limits, and client versions. Record the block context and response when reproducibility matters.

Warning

Never copy a list from an unrelated transaction and assume it is safe or cheaper. The correct result depends on the exact call and simulated state.

Practical checklist

  • Confirm network, sender, destination, value, and calldata
  • Generate against an explicit recent state
  • Validate address lengths and 32-byte keys
  • Remove duplicates
  • Compare estimates with and without the list
  • Re-simulate state-dependent calls
  • Leave gas-limit room for missed branches
  • Verify the receipt's gasUsed
  • Treat the list as a gas hint, never a security policy

FAQ

Does a list block unlisted state?

No. Unlisted state remains accessible and follows cold-access accounting unless another rule or earlier execution warmed it.

Is every access-list transaction type 0x01?

No. EIP-2930 introduced type 0x01, but EIP-1559 type 0x02 also has an access-list field.

Does eth_createAccessList guarantee savings?

No. It estimates one call at one state. Extra entries, default-warm addresses, changed paths, and intrinsic charges can erase or reverse savings.

Is this the same as a block-level access list?

No. EIP-2930 lists are optional sender-provided data for pre-warming state. EIP-7928 block-level access lists record actual state access and post-transaction changes across a block for parallel validation and synchronization.

Primary sources

Use access lists as measured hints

An access list is a prepaid map of expected addresses and slots. It can make first accesses warm and help clients prepare state, but it neither constrains execution nor guarantees a lower bill. Generate it from the exact transaction, compare both paths at the same state, and verify the receipt afterward.

This article is educational, not financial advice. Smart-contract calls are irreversible and crypto assets can lose value; test carefully, use only funds you can afford to lose, verify current primary documentation, and do your own research (DYOR).

Advertisement

Keep learning

Explore related topics

More from GOMTU