Cold/warm storage access cost tracking per EIP-2929.
EIP-2929 introduced the concept of "access lists" — sets of addresses and storage keys that have already been touched during the current transaction. The first access to an address or storage slot is "cold" (expensive), and subsequent accesses are "warm" (cheap).
Cost Schedule (EIP-2929)
| Access Type | Cold Cost | Warm Cost |
|---|---|---|
| Account (BALANCE, EXTCODESIZE, etc.) | 2,600 | 100 |
| Account (CALL family, on top of its static 100) | +2,500 | +0 |
| Storage slot (SLOAD) | 2,100 | 100 |
| Storage slot (SSTORE, on top of its schedule) | +2,100 | +0 |
This module tracks which addresses and storage keys have been accessed and returns
the appropriate cost. The state's accessed_addresses and accessed_storage_keys
MapSets are updated on each cold access.
Before Berlin there is no warm/cold distinction: the opcodes' flat static
costs (EEVM.Gas.Static.static_cost/2) cover the access, so these functions
charge nothing.
References
Summary
Functions
Access cost of an account-reading opcode (BALANCE, EXTCODESIZE,
EXTCODECOPY, EXTCODEHASH), whose static cost is 0 from Berlin on:
2,600 cold, 100 warm. Marks address warm.
Extra access cost of a CALL-family target. Their static cost already
includes the warm price (100), so a cold target adds 2,500. Marks
address warm.
Extra access cost of SSTORE: 2,100 when the slot is cold, nothing when warm (the SSTORE schedule prices warm writes). Marks the slot warm.
Access cost of SLOAD: 2,100 cold, 100 warm. Marks the slot warm.
Functions
@spec address_access_cost(EEVM.Interpreter.MachineState.t(), non_neg_integer()) :: {non_neg_integer(), EEVM.Interpreter.MachineState.t()}
Access cost of an account-reading opcode (BALANCE, EXTCODESIZE,
EXTCODECOPY, EXTCODEHASH), whose static cost is 0 from Berlin on:
2,600 cold, 100 warm. Marks address warm.
@spec call_access_cost(EEVM.Interpreter.MachineState.t(), non_neg_integer()) :: {non_neg_integer(), EEVM.Interpreter.MachineState.t()}
Extra access cost of a CALL-family target. Their static cost already
includes the warm price (100), so a cold target adds 2,500. Marks
address warm.
@spec mark_address_warm(EEVM.Interpreter.MachineState.t(), non_neg_integer()) :: EEVM.Interpreter.MachineState.t()
@spec sstore_access_cost( EEVM.Interpreter.MachineState.t(), non_neg_integer(), non_neg_integer() ) :: {non_neg_integer(), EEVM.Interpreter.MachineState.t()}
Extra access cost of SSTORE: 2,100 when the slot is cold, nothing when warm (the SSTORE schedule prices warm writes). Marks the slot warm.
@spec storage_access_cost( EEVM.Interpreter.MachineState.t(), non_neg_integer(), non_neg_integer() ) :: {non_neg_integer(), EEVM.Interpreter.MachineState.t()}
Access cost of SLOAD: 2,100 cold, 100 warm. Marks the slot warm.
@spec warm_address?(EEVM.Interpreter.MachineState.t(), non_neg_integer()) :: boolean()