EIP-2200 A structural definition of net gas metering (Structured Definitions for Net Gas Metering)
Final · Fees & gas · EIP status Final · created 2019-07-18
Computes the gas for the contract storage instruction SSTORE based on the net change that actually remains when the transaction ends. The cost of repeatedly writing to the same storage slot drops significantly, and a safeguard against reentrancy attacks is included alongside it.
Why it is needed
In Ethereum, the contract storage instruction SSTORE charges an expensive fee every time a value is written. But in practice, the only thing that ends up recorded on disk is the final value after the transaction ends. Even if a slot is rewritten multiple times within the same transaction, or reset back to its original value, a large fee had to be paid each time, so the actual amount of work and the fee charged did not match. EIP-1283, which tried to fix this, introduced 'net gas metering,' comparing the value before and after the write and charging only for the net change, but because it allowed storage even within the 2300 gas that Solidity gives by default to a simple transfer call, it created a new kind of reentrancy attack risk for existing contracts. This EIP is the final version that merges EIP-1706's safeguard against that risk into EIP-1283, and reorganizes the gas figures into named parameters so they interlock with other gas changes like EIP-1884.
What changes
Today
- Rewriting the same storage slot multiple times within the same transaction still charges close to the full gas fee each time
- Even if a value is reverted back to its original value and no actual record is left behind, the cost barely decreases
- The original EIP-1283 allowed storage within the 2300 gas transfer call, creating a reentrancy attack risk
After EIP-2200
- Gas is charged based on the net change remaining when the transaction ends, and repeated writes only incur a cheap fee at the level of SLOAD_GAS
- If a value is reverted back to its original value, the difference accumulates in the refund counter and is returned
- If the remaining gas is at or below the stipend, SSTORE fails, preserving reentrancy protection
Who is affected
- Contract developer: Gas is significantly reduced for patterns that repeat storage writes within a single transaction, such as reentrancy locks, multiple transfers within the same contract, and exchanging temporary information with subcalls.
- Users: No gas increases are expected, and gas decreases for many contracts.
- Client teams: Must be applied via a hard fork, and SSTORE gas calculation and refund counter handling must be changed to match the new rules.
- Wallet and tool developers: Gas estimation must reflect the requirement that SSTORE fails below the stipend.
In depth
Four gas parameters
EIP-1283 hardcoded the gas figures as literal numbers, but this EIP replaces them with four named variables. SLOAD_GAS changes from 200 to 800, while SSTORE_SET_GAS stays at 20000, SSTORE_RESET_GAS at 5000, and SSTORE_CLEARS_SCHEDULE at 15000. Turning the figures into variables makes it possible to interoperate with other proposals that change gas prices, such as EIP-1884, and makes future changes easier to define.
SSTORE gas computed from three values
The computation uses only the original value, current value, and new value. The term definitions follow EIP-1283. If the current value and the new value are the same, it is a no-op that changes nothing, so only SLOAD_GAS is charged. If the value changes but the original value and current value are the same, meaning this is the first time the slot is touched in this execution context, SSTORE_SET_GAS is charged when the original value is 0, otherwise SSTORE_RESET_GAS is charged, and if the new value is 0, SSTORE_CLEARS_SCHEDULE is added to the refund counter. If the original value and current value differ, meaning this is a slot already touched (dirty), only SLOAD_GAS is charged and a separate refund adjustment rule applies.
Refund counter adjustment for dirty slots
When writing to a dirty slot, both sets of adjustments apply. First, if the original value is not 0 and the current value is 0 (meaning the new value is not 0), SSTORE_CLEARS_SCHEDULE is subtracted from the refund counter, and if the new value is 0 (meaning the current value is not 0), it is added. Second, if the original value and the new value are the same (the slot is restored to its original state), SSTORE_SET_GAS - SLOAD_GAS is added to the refund counter when the original value is 0, otherwise SSTORE_RESET_GAS - SLOAD_GAS is added. The original text specifies that under this definition, an implementation using a per call frame refund counter can see the counter go negative, while a per transaction counter always stays positive.
SSTORE fails at or below the stipend
If the remaining gas (gasleft) is at or below the gas stipend, the current call frame fails with an 'out of gas' exception. Solidity gives a 2300 gas stipend by default to a simple transfer call, and under the original EIP-1283, storage would have been possible even within that, creating a new kind of reentrancy attack risk for existing contracts. This check is the safeguard proposed by EIP-1706, and it blocks the risk without breaking backwards compatibility or EIP-1283's original intent. The Rationale explains that other alternatives were considered, such as deprecating EIP-1283, adding a new call context that only allows LOG without state changes, raising the cost of writing to dirty slots above 2300 gas, or reducing the stipend, but none were adopted because of their respective drawbacks.
An effect that substitutes for transient storage
This EIP achieves most of what the transient storage proposals (EIP-1087, EIP-1153) set out to do, without needing a separate data structure like a 'dirty map.' EIP-1087 requires maintaining a map of storage change history, but since EIP-658, efficient clients only commit changes at the end of a block, so iterating over all changes costs extra memory or processing. This approach only needs to know a slot's original value and current value, so there is no extra cost at execution time. There is no case where it costs more gas than the existing approach, and in terms of absolute gas (gas used minus refund), it matches EIP-1087 in every case. Only in the single case where a slot is changed, reverted back to its original value, and then changed again does the EIP-1283 approach accumulate a larger refund than EIP-1087. The appendix proves these properties by induction, splitting into cases where the original value is 0 and where it is not.
Backwards compatibility and test cases
Applying this requires a hard fork. No gas increases are expected, and gas decreases for many contracts. SSTORE originally could not be executed with less than 5000 gas, so the stipend check does not create incompatibility with existing mainnet contracts, but gas estimation must reflect this requirement. The original text provides a table of 17 test cases pairing code, gas used, refund, and the sequence of values written against the original value. For example, 0x60006000556000600055, which writes 0 twice to a slot whose original value is 0, costs 1612 gas with 0 refund. 0x60016000556000600055, which writes 1 and then reverts it to 0, costs 20812 gas with a refund of 19200. The status of this EIP is Final, meaning the specification is finalized.