EIP-1283 Net gas calculation for SSTORE without a dirty map (Net gas metering for SSTORE without dirty maps)
Final · Fees & gas · EIP status Final · created 2018-08-01
Recalculates the gas cost of the storage-write opcode SSTORE based on the actual net change remaining when the transaction ends. Writing to the same slot repeatedly costs only 200 gas from the second write onward.
Why it is needed
In Ethereum, SSTORE, the opcode a contract uses to store data, charges an expensive fee of up to 20000 gas each time it is used. However, actual client implementations hold changes made during a transaction only in memory and write to disk once, later, in a single batch. Even if the same slot is changed multiple times within the same transaction, the disk write ultimately happens only once, yet the fee is charged in full every time. Because of this, uses such as a reentry lock that is briefly written and cleared only within a transaction, or passing error codes back and forth between a subcall and its caller, ended up excessively expensive. The earlier EIP-1087 tried to solve the same problem, but it required a separate dirty map recording the list of changed slots, which was a burden for clients that optimized their storage structures differently. This EIP achieves the same effect using only information that almost every implementation already has: a slot's original value, current value, and the refund counter.
What changes
Today
- Writing to the same slot multiple times within the same transaction charges 5000 or 20000 gas every time
- Temporary data that is written and deleted only within a transaction is charged the same fee as permanent storage
- Reverting a value back to its original does not refund the gas spent
After EIP-1283
- Writing again to a slot that has already been changed costs only 200 gas
- Reverting a slot back to its original value refunds 19800 or 4800 gas to the refund counter
- In no case does this cost more gas than the existing approach
Who is affected
- Contract developer: Patterns that repeatedly write to storage within a single transaction, such as reentry locks, multiple transfers within the same contract, or message passing with subcalls, become significantly cheaper.
- Users: The original text states there is no gas increase, and many contracts will see gas savings. Fees for transactions that use such contracts will decrease.
- Client teams: The SSTORE gas calculation logic needs to be replaced. Implementations that create a new refund counter per call frame need to change the counter to a signed value.
In depth
Definition of the three values
The calculation is done by comparing three values per slot. The original value is the value that remains if the current transaction is fully reverted, i.e., the value at the start of the transaction. The current value is the value immediately before this SSTORE executes, and the new value is the value after it executes. Because the original value is defined at the transaction level, changes in call frames do not affect the gas calculation.
The new gas calculation rules
If the current value and the new value are the same, it is treated as a no-op and only 200 gas is deducted. When the value changes, if the original value equals the current value (a fresh state being changed for the first time in this execution), the existing fee is charged as before: 20000 gas if the original value is 0, otherwise 5000 gas. In this case, if the new value is 0, 15000 gas is added to the refund counter. If the original value differs from the current value (an already-changed dirty state), only 200 gas is deducted. In the dirty state, two corrections are applied together. If the original value is nonzero and the current value is 0, 15000 is subtracted from the refund counter, and if the new value is 0, 15000 is added. Also, if the new value equals the original value and the slot is reset, 19800 gas is added to the refund counter if the original value is 0, or 4800 gas otherwise.
Structure viewed as state transitions
The original text divides the entire set of cases into three states. Every SSTORE that changes a value for the first time starts in the Fresh state, and becomes Dirty once the value changes. Moving from Fresh to Dirty charges the same gas as the existing fee schedule, while staying in Dirty charges only 200 gas. Reverting a dirty slot back to its original value returns it to Fresh and triggers a refund. In the dirty state, the refund given for changes to zero (R_SCLEAR) is tracked, so an already-given refund is subtracted if it no longer applies and added if it newly applies. The original text summarizes all transitions' gas and refunds in tables, split between cases where the original value is 0 and where it is not.
The refund counter and implementation caveats
As before, refunds apply only up to half of the gas consumed, and the refund counter at the transaction level never goes below 0. However, this differs by implementation approach. Implementations that manage the refund as a single transaction-level value with checkpoints per frame can simply use it as an unsigned value. On the other hand, implementations that create a new refund counter per call frame and merge it into the parent when it ends need to change it to a signed value, since a child counter in an internal call can go negative.
Comparison with EIP-1087
This EIP achieves the effect the temporary storage proposals (EIP-1087, EIP-1153) are aiming for, without a dirty map or a separate storage structure. EIP-1087 implicitly assumes that a list of storage changes is held as a dirty map and committed to the trie at the end of the transaction, but efficient implementations after EIP-658 often track changes with an in-memory trie or immutable data structures and commit only at the end of a block, making it hard to iterate over the entire set of changes. This EIP only needs the original value and the current value, so there is no additional memory or processing overhead at runtime. The absolute gas usage (gas used minus refund) is the same as EIP-1087 in every case, except for one case, changing a slot, reverting it to the original value, and then changing it again, where more of the amount shifts to the refund counter than under EIP-1087.
Cost examples and test cases
As an example from the original text, writing 1 to slot 0 in empty storage and then reverting it to 0 costs 400 gas: 20000 plus 200 minus 19800. Incrementing slot 0 five times in empty storage costs 21000 gas: 20000 plus 5 times 200. If A transfers to B and then B transfers to C, with every account's starting and ending balance nonzero, it costs 10400 gas: 5000 times 3 plus 200 minus 4800. The original text provides a total of 17 test cases, together with their gas used and refund values: 15 covering two consecutive SSTOREs, and 2 covering three writes where a slot is reset and then written again.
How it is applied and current status
This change requires a hard fork. The original text states that no gas cost increase is expected and that many contracts will see gas savings. The original text includes a proof appendix that uses induction, split between cases where the original value is 0 and where it is not, to show that the absolute gas usage for each final outcome matches the intended formula. This EIP's status is Final, a finalized specification.