EIP-2930 Optional access lists

Final · Fees & gas · EIP status Final · created 2020-08-29

Adds a new transaction type (type 1) that lets a transaction pre-declare the addresses and storage keys it will access. Accesses listed in advance pay a discounted gas cost upfront, while accesses outside the list are still possible but cost more.

Why it is needed

EIP-2929 raised the gas cost of first-time access to accounts and storage. However, existing contracts that call with a fixed amount of gas are at risk of breaking from this increase. This EIP lets a transaction pre-declare the accounts and storage slots it will use and prepay their cost, so that during actual execution SLOAD and the EXT family of instructions cost only 100 gas. As a result, it not only prevents breakage caused by EIP-2929, but also lets contracts that stopped working due to the earlier cost increase in EIP-1884 function again. Another goal is to introduce the access list format itself and its processing logic. The original text states that this format can be reused for various purposes, such as per-block witnesses, ReGenesis, and the gradual shift toward static state access over time.

What changes

Today

After EIP-2930

Who is affected

In depth

Format of a type 1 transaction

Introduced as EIP-2718 TransactionType 1. TransactionPayload is rlp([chainId, nonce, gasPrice, gasLimit, to, value, data, accessList, signatureYParity, signatureR, signatureS]). The signature elements signatureYParity, signatureR, signatureS are the secp256k1 signature over keccak256(0x01 || rlp([chainId, nonce, gasPrice, gasLimit, to, value, data, accessList])). YParity is the parity (even 0, odd 1) of the signature's y value, and chainId makes the transaction valid only on that chain. ReceiptPayload is rlp([status, cumulativeGasUsed, logsBloom, logs]). Applies from FORK_BLOCK 12244000.

Structure and validation of the access list

The accessList must have the format [[{20 bytes}, [{32 bytes}...]]...]. Each item consists of one 20-byte address and zero or more 32-byte storage keys. The process_access_list Python code in the original text serves as both the validation logic and the spec as code. The addresses and keys in the list are registered immediately into the accessed_addresses and accessed_storage_keys global sets introduced by EIP-2929 at the start of execution. Duplicate entries of the same address or key are also allowed, and gas must be paid for each duplicate, but there is otherwise no difference in execution flow or outcome.

Gas accounting

The access list cost is charged in addition at the start of execution, that is, at the same time the EIP-2028-based intrinsic gas of 21000 + 4 * zeroes + 16 * nonzeroes is charged. It is ACCESS_LIST_ADDRESS_COST (2400 gas) per address and ACCESS_LIST_STORAGE_KEY_COST (1900 gas) per storage key. As in the original example, including 2 addresses and 2 keys costs ACCESS_LIST_ADDRESS_COST * 2 + ACCESS_LIST_STORAGE_KEY_COST * 2. Unlike transaction data, there is no per-byte charge. This is because the per-item cost bundles both the bandwidth cost of the list data and the cost of actually accessing the account or key.

Why accesses within the list are discounted

There are two reasons. First, to encourage transactions to make maximal use of access lists. Second, because knowing storage reads in advance makes transaction processing easier. Clients can pre-read the relevant data from the database when they receive the transaction, or request a witness, and even otherwise can read data in parallel when they receive the block. The design is that predictable state access improves processing efficiency across the network.

Design of allowing duplicates and the scope of signing

Duplicates are allowed to maximize simplicity. Preventing duplicates raises the question of scope: whether to block duplicates only among items within the list, or also against the transaction's sender, recipient, and newly created contracts. Since gas is charged per item, entering the same value twice only increases cost with no benefit, so it is expected that chains will not actually grow unnecessarily in practice. Also, because the signature covers not just the transaction data but also the transaction type, it prevents a signed transaction from being reinterpreted as a transaction of a different type.

Backward compatibility

This EIP makes unexpected SLOADs and account accesses not listed in the list more expensive. However, because gas is charged upfront, it does not affect local calls that send a fixed amount of gas. So it does not break contracts in the way past gas increases could have. Still, the original text notes that applications heavily dependent on storage access may see a significant drop in economic viability.

Security considerations

Building an access list in real time is often difficult, and it is even harder in environments where there is a large gap between transaction creation and signing, or where simplicity of the generator matters (such as hardware wallets). However, since the initial discount is set at 10%, sending a plain transaction without building a list carries almost no burden. The original text expects that as tooling improves and list generation matures, the cost of state access outside the list will gradually rise in later hard forks. In terms of block size, using lists increases the average block size, but because the per-byte cost is far higher than calldata (1900 / 32 = 59.375 for a storage key, 2400 / 20 = 120 for an address), block size will not increase in the worst case. The increase in average size is also partly offset by pre-reading and parallel loading at the time a transaction is received.

Original EIP · ← EIPs