This is an EIP that implements net gas metering. It's a combined version of EIP-1283 and EIP-1706, with a structured definition so as to make it interoperable with other gas changes such as EIP-1884.
This EIP provides a structured definition of net gas metering changes
for SSTORE
opcode, enabling new usages for contract storage, and
reducing excessive gas costs where it doesn’t match how most
implementation works.
This is a combination of EIP-1283 and EIP-1706.
This EIP proposes a way for gas metering on SSTORE
, using information
that is more universally available to most implementations, and
require as little change in implementation structures as possible.
Usages that benefits from this EIP’s gas reduction scheme includes:
The original definition of EIP-1283 created a danger of a new kind of
reentrancy attacks on existing contracts as Solidity by default grants
a "stipend" of 2300 gas to simple transfer calls. This danger is
easily mitigated if SSTORE
is not allowed in low gasleft state,
without breaking the backward compatibility and the original intention
of EIP-1283.
This EIP also replaces the original EIP-1283 value definitions of gas by parameters, so that it's more structured, and easier to define changes in the future.
Define variables SLOAD_GAS
, SSTORE_SET_GAS
, SSTORE_RESET_GAS
and
SSTORE_CLEARS_SCHEDULE
. The old and new values for those variables
are:
SLOAD_GAS
: changed from 200
to 800
.SSTORE_SET_GAS
: 20000
, not changed.SSTORE_RESET_GAS
: 5000
, not changed.SSTORE_CLEARS_SCHEDULE
: 15000
, not changed.Change the definition of EIP-1283 using those variables. The new specification, combining EIP-1283 and EIP-1706, will look like below. The terms original value, current value and new value are defined in EIP-1283.
Replace SSTORE
opcode gas cost calculation (including refunds) with
the following logic:
SLOAD_GAS
is deducted.SSTORE_SET_GAS
is deducted.SSTORE_RESET_GAS
gas is deducted. If new value is
0, add SSTORE_CLEARS_SCHEDULE
gas to refund counter.SLOAD_GAS
gas is deducted. Apply both of the
following clauses.SSTORE_CLEARS_SCHEDULE
gas from refund
counter.SSTORE_CLEARS_SCHEDULE
gas to refund counter.SSTORE_SET_GAS - SLOAD_GAS
to
refund counter.SSTORE_RESET_GAS - SLOAD_GAS
gas to refund
counter.An implementation should also note that with the above definition, if the implementation uses call-frame refund counter, the counter can go negative. If the implementation uses transaction-wise refund counter, the counter always stays positive.
This EIP mostly achieves what a transient storage tries to do (EIP-1087 and EIP-1153), but without the complexity of introducing the concept of "dirty maps", or an extra storage struct.
Regarding SSTORE
gas cost and refunds, see Appendix for proofs of
properties that this EIP satisfies.
Examine examples provided in EIP-1087's Motivation (with SLOAD_GAS
being
200
):
20000 + 200 - 19800 = 400
gas.20000 + 5 * 200 = 21000
gas.5000 * 3 + 200 - 4800 = 10400
gas.In order to keep in place the implicit reentrancy protection of existing contracts, transactions should not be allowed to modify state if the remaining gas is lower then the gas stipend given to "transfer"/"send" in Solidity. These are other proposed remediations and objections to implementing them:
SSTORE
costSSTORE
to dirty slots to >=2300 gasSSTORE
changes to contracts deployed with the new version.This EIP requires a hard fork to implement. No gas cost increase is anticipated, and many contracts will see gas reduction.
Performing SSTORE
has never been possible with less than 5000 gas, so
it does not introduce incompatibility to the Ethereum Mainnet. Gas
estimation should account for this requirement.
Code | Used Gas | Refund | Original | 1st | 2nd | 3rd |
---|---|---|---|---|---|---|
0x60006000556000600055 |
1612 | 0 | 0 | 0 | 0 | |
0x60006000556001600055 |
20812 | 0 | 0 | 0 | 1 | |
0x60016000556000600055 |
20812 | 19200 | 0 | 1 | 0 | |
0x60016000556002600055 |
20812 | 0 | 0 | 1 | 2 | |
0x60016000556001600055 |
20812 | 0 | 0 | 1 | 1 | |
0x60006000556000600055 |
5812 | 15000 | 1 | 0 | 0 | |
0x60006000556001600055 |
5812 | 4200 | 1 | 0 | 1 | |
0x60006000556002600055 |
5812 | 0 | 1 | 0 | 2 | |
0x60026000556000600055 |
5812 | 15000 | 1 | 2 | 0 | |
0x60026000556003600055 |
5812 | 0 | 1 | 2 | 3 | |
0x60026000556001600055 |
5812 | 4200 | 1 | 2 | 1 | |
0x60026000556002600055 |
5812 | 0 | 1 | 2 | 2 | |
0x60016000556000600055 |
5812 | 15000 | 1 | 1 | 0 | |
0x60016000556002600055 |
5812 | 0 | 1 | 1 | 2 | |
0x60016000556001600055 |
1612 | 0 | 1 | 1 | 1 | |
0x600160005560006000556001600055 |
40818 | 19200 | 0 | 1 | 0 | 1 |
0x600060005560016000556000600055 |
10818 | 19200 | 1 | 0 | 1 | 0 |
To be added.
Because the storage slot's original value is defined as the value
when a reversion happens on the current transaction, it's easy to
see that call frames won't interfere SSTORE
gas calculation. So
although the below proof is discussed without call frames, it applies
to all situations with call frames. We will discuss the case
separately for original value being zero and not zero, and use
induction to prove some properties of SSTORE
gas cost.
Final value is the value of a particular storage slot at the end of
a transaction. Absolute gas used is the absolute value of gas used
minus refund. We use N
to represent the total number of SSTORE
operations on a storage slot. For states discussed below, refer to
State Transition in Explanation section.
Below we do the proof under the assumption that all parameters are
unchanged, meaning SLOAD_GAS
is 200
. However, note that the proof
still applies no matter how SLOAD_GAS
is changed.
When original value is 0, we want to prove that:
200 *
N
gases, because no disk write is needed.20000 + 200 * (N-1)
gas, because it requires writing this
slot to disk.We always start at state A. The first SSTORE
can:
200 * N == 200 * 1
.20000 + 200 * (N-1) == 20000 + 200 * 0
.200 * (N-1)
. The current
gas cost is 200 + 200 * (N-1)
. It satisfy Case I.200 * (N-1)
. The current
gas cost is 20000 + 200 * (N-1)
. It satisfy Case II.20000 + 200 * (N-2)
. The
current gas cost is 200 + 20000 + 200 * (N-2)
. It satisfy
Case II.20000 + 200 * (N-2)
. The
current gas cost is 200 - 19800 + 20000 + 200 * (N-2)
. It satisfy
Case I.When original value is not 0, we want to prove that:
200 * N
gases, because no disk write is needed.5000 - 15000 + 200 * (N-1)
gas. Note that 15000
is the
refund in actual definition.5000 + 200 * (N-1)
gas.We always start at state X. The first SSTORE
can:
200 * N == 200 * 1
.5000 + 200 * (N-1) == 5000 + 200 * 0
.5000 - 15000
where 15000
is the refund. We satisfy Case II because 5000 - 15000 + 200 *
(N-1) == 5000 - 15000 + 200 * 0
.200 * (N-1)
. The current gas
cost is 200 + 200 * (N-1)
. It satisfy Case I.200 * (N-1)
. The current gas
cost is 5000 + 200 * (N-1)
. It satisfy Case III.200 * (N-1)
. The current
absolute gas cost is 5000 - 15000 + 200 * (N-1)
. It satisfy Case
II.5000 + 200 * (N-2)
. The
absolute current gas cost is 200 - 4800 + 5000 + 200 * (N-2)
. It
satisfy Case I.5000 + 200 * (N-2)
. The
current gas cost is 200 + 5000 + 200 * (N-2)
. It satisfy Case
III.5000 + 200 * (N-2)
. The
current absolute gas cost is 200 - 15000 + 5000 + 200 * (N-2)
. It
satisfy Case II.5000 - 15000 + 200 *
(N-2)
. The current absolute gas cost is 200 + 10200 + 5000 -
15000 + 200 * (N-2)
. It satisfy Case I.5000 - 15000 + 200 *
(N-2)
. The current absolute gas cost is 200 + 15000 + 5000 -
15000 + 200 * (N-2)
. It satisfy Case III.5000 - 15000 + 200 *
(N-2)
. The current absolute gas cost is 200 + 5000 - 15000 + 200 *
(N-2)
. It satisfy Case II.Copyright and related rights waived via CC0.