Skip to content

Commit 01b66af

Browse files
committed
Copy sections from EIP-1283 and EIP-1706 to EIP-2200
1 parent e4d4ea3 commit 01b66af

File tree

1 file changed

+240
-18
lines changed

1 file changed

+240
-18
lines changed

EIPS/eip-2200.md

Lines changed: 240 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
eip: 2200
3-
title: Rebalance net-metered SSTORE gas cost with consideration of SLOAD gas cost change
3+
title: Structured Definitions for Net Gas Metering
44
author: Wei Tang (@sorpaas)
55
discussions-to: https://github.com/sorpaas/EIPs/issues/1
66
status: Draft
@@ -12,24 +12,54 @@ requires: 1283, 1706, 1884
1212

1313
## Simple Summary
1414

15-
A repricing effort for several trie-size-dependent opcodes are being
16-
carried out. This EIP also reprices net-metered SSTORE opcode.
15+
This is an EIP that implements net gas metering. It's a combined
16+
version of EIP-1283 and EIP-1706, with a structured definition so as
17+
to make it interoperable with other gas changes such as EIP-1884.
1718

1819
## Abstract
1920

20-
Change the intermediate write and no-op write of SSTORE to always have
21-
the same gas cost of SLOAD. Change the refund of resetting after
22-
setting for SSTORE to take consideration of gas cost of SLOAD.
21+
This EIP provides a structured definition of net gas metering changes
22+
for SSTORE opcode, enabling new usages for contract storage, and
23+
reducing excessive gas costs where it doesn’t match how most
24+
implementation works.
25+
26+
This is a combination of EIP-1283 and EIP-1706.
2327

2428
## Motivation
2529

26-
Net gas metering for SSTORE was priced according to SLOAD values. For
27-
consistency, when SLOAD is repriced, SSTORE should be as well.
30+
This EIP proposes a way for gas metering on SSTORE, using information
31+
that is more universally available to most implementations, and
32+
require as little change in implementation structures as possible.
33+
34+
* Storage slot’s original value.
35+
* Storage slot’s current value.
36+
* Refund counter.
37+
38+
Usages that benefits from this EIP’s gas reduction scheme includes:
39+
40+
* Subsequent storage write operations within the same call frame. This
41+
includes reentry locks, same-contract multi-send, etc.
42+
* Exchange storage information between sub call frame and parent call
43+
frame, where this information does not need to be persistent outside
44+
of a transaction. This includes sub-frame error codes and message
45+
passing, etc.
46+
47+
The original defintion of EIP-1283 created a danger of a new kind of
48+
reentrancy attacks on existing contracts as Solidity by default grants
49+
a "stipend" of 2300 gas to simple transfer calls. This danger is
50+
easily mitigated if SSTORE is not allowed in low gasleft state,
51+
without breaking the backward compatibility and the original intention
52+
of EIP-1283.
53+
54+
This EIP also replaces the original EIP-1283 value definitions of gas
55+
by parameters, so that it's more structured, and easier to define
56+
changes in the future.
2857

2958
## Specification
3059

3160
Define variables `SLOAD_GAS`, `SSTORE_SET_GAS`, `SSTORE_RESET_GAS` and
32-
`SSTORE_CLEARS_SCHEDULE`. The old and new values for those variables are:
61+
`SSTORE_CLEARS_SCHEDULE`. The old and new values for those variables
62+
are:
3363

3464
* `SLOAD_GAS`: changed from `200` to `800`.
3565
* `SSTORE_SET_GAS`: `20000`, not changed.
@@ -39,7 +69,7 @@ Define variables `SLOAD_GAS`, `SSTORE_SET_GAS`, `SSTORE_RESET_GAS` and
3969
Change the definition of EIP-1283 using those variables. The new
4070
specification, combining EIP-1283 and EIP-1706, will look like
4171
below. The terms *original value*, *current value* and *new value* are
42-
defined in EIP-1283.
72+
defined in EIP-1283.
4373

4474
Replace SSTORE opcode gas cost calculation (including refunds) with
4575
the following logic:
@@ -68,29 +98,221 @@ the following logic:
6898
refund counter.
6999
* Otherwise, add `SSTORE_RESET_GAS - SLOAD_GAS` gas to refund
70100
counter.
71-
* If *gasleft* is less than or equal to 2300, fail the current call
72-
frame with 'out of gas' exception.
101+
* If *gasleft* is less than or equal to gas stipend, fail the current
102+
call frame with 'out of gas' exception.
73103

74-
An implementation should also note EIP-1283's refund counter
75-
implementation details, in the *Specification* section.
104+
An implementation should also note that with the above definition, if
105+
the implementation uses call-frame refund counter, the counter can go
106+
negative. If the implementation uses transaction-wise refund counter,
107+
the counter always stays positive.
76108

77109
## Rationale
78110

79-
The same as EIP-1283's rationale. If EIP-1884 is applied, then `SLOAD_GAS`
80-
related to SSTORE opcode will also need to be changed.
111+
This EIP mostly achieves what a transient storage tries to do
112+
(EIP-1087 and EIP-1153), but without the complexity of introducing the
113+
concept of "dirty maps", or an extra storage struct.
114+
115+
* We don't suffer from the optimization limitation of
116+
EIP-1087. EIP-1087 requires keeping a dirty map for storage changes,
117+
and implicitly makes the assumption that a transaction's storage
118+
changes are committed to the storage trie at the end of a
119+
transaction. This works well for some implementations, but not for
120+
others. After EIP-658, an efficient storage cache implementation
121+
would probably use an in-memory trie (without RLP encoding/decoding)
122+
or other immutable data structures to keep track of storage changes,
123+
and only commit changes at the end of a block. For them, it is
124+
possible to know a storage's original value and current value, but
125+
it is not possible to iterate over all storage changes without
126+
incurring additional memory or processing costs.
127+
* It never costs more gas compared with the current scheme.
128+
* It covers all usages for a transient storage. Clients that are easy
129+
to implement EIP-1087 will also be easy to implement this
130+
specification. Some other clients might require a little bit extra
131+
refactoring on this. Nonetheless, no extra memory or processing cost
132+
is needed on runtime.
133+
134+
Regarding SSTORE gas cost and refunds, see Appendix for proofs of
135+
properties that this EIP satisfies.
136+
137+
* For *absolute gas used* (that is, actual *gas used* minus *refund*),
138+
this EIP is equivalent to EIP-1087 for all cases.
139+
* For one particular case, where a storage slot is changed, reset to
140+
its original value, and then changed again, EIP-1283 would move more
141+
gases to refund counter compared with EIP-1087.
142+
143+
Examine examples provided in EIP-1087's Motivation:
144+
145+
* If a contract with empty storage sets slot 0 to 1, then back to 0,
146+
it will be charged `20000 + 200 - 19800 = 400` gas.
147+
* A contract with empty storage that increments slot 0 5 times will be
148+
charged `20000 + 5 * 200 = 21000` gas.
149+
* A balance transfer from account A to account B followed by a
150+
transfer from B to C, with all accounts having nonzero starting and
151+
ending balances, it will cost `5000 * 3 + 200 - 4800 = 10400` gas.
152+
153+
In order to keep in place the implicit reentrancy protection of
154+
existing contracts, transactions should not be allowed to modify state
155+
if the remaining gas is lower then the gas stipend given to
156+
"transfer"/"send" in Solidity. These are other proposed remediations
157+
and objections to implementing them:
158+
159+
* Drop EIP-1283 and abstain from modifying SSTORE cost
160+
* EIP-1283 is an important update
161+
* It was accepted and implemented on test networks and in clients.
162+
* Add a new call context that permits LOG opcodes but not changes to state.
163+
* Adds another call type beyond existing regular/staticcall
164+
* Raise the cost of SSTORE to dirty slots to >=2300 gas
165+
* Makes net gas metering much less useful.
166+
* Reduce the gas stipend
167+
* Makes the stipend almost useless.
168+
* Increase the cost of writes to dirty slots back to 5000 gas, but add
169+
4800 gas to the refund counter
170+
* Still doesn’t make the invariant explicit.
171+
* Requires callers to supply more gas, just to have it refunded
172+
* Add contract metadata specifying per-contract EVM version, and only
173+
apply SSTORE changes to contracts deployed with the new version.
81174

82175
## Backwards Compatibility
83176

84-
This EIP has the same backward compatibility property of EIP-1283 and EIP-1706.
177+
This EIP requires a hard fork to implement. No gas cost increase is
178+
anticipated, and many contracts will see gas reduction.
179+
180+
Performing SSTORE has never been possible with less than 5000 gas, so
181+
it does not introduce incompatibility to the Ethereum mainnet. Gas
182+
estimation should account for this requirement.
85183

86184
## Test Cases
87185

88-
To be added.
186+
Below we provide 17 test cases. 15 of them covering consecutive two
187+
`SSTORE` operations are based on work [by
188+
@chfast](https://github.com/ethereum/tests/issues/483). Two additional
189+
case with three `SSTORE` operations is used to test the case when a
190+
slot is reset and then set again.
191+
192+
| Code | Used Gas | Refund | Original | 1st | 2nd | 3rd |
193+
|------------------------------------|----------|--------|----------|-----|-----|-----|
194+
| `0x60006000556000600055` | 412 | 0 | 0 | 0 | 0 | |
195+
| `0x60006000556001600055` | 20212 | 0 | 0 | 0 | 1 | |
196+
| `0x60016000556000600055` | 20212 | 19800 | 0 | 1 | 0 | |
197+
| `0x60016000556002600055` | 20212 | 0 | 0 | 1 | 2 | |
198+
| `0x60016000556001600055` | 20212 | 0 | 0 | 1 | 1 | |
199+
| `0x60006000556000600055` | 5212 | 15000 | 1 | 0 | 0 | |
200+
| `0x60006000556001600055` | 5212 | 4800 | 1 | 0 | 1 | |
201+
| `0x60006000556002600055` | 5212 | 0 | 1 | 0 | 2 | |
202+
| `0x60026000556000600055` | 5212 | 15000 | 1 | 2 | 0 | |
203+
| `0x60026000556003600055` | 5212 | 0 | 1 | 2 | 3 | |
204+
| `0x60026000556001600055` | 5212 | 4800 | 1 | 2 | 1 | |
205+
| `0x60026000556002600055` | 5212 | 0 | 1 | 2 | 2 | |
206+
| `0x60016000556000600055` | 5212 | 15000 | 1 | 1 | 0 | |
207+
| `0x60016000556002600055` | 5212 | 0 | 1 | 1 | 2 | |
208+
| `0x60016000556001600055` | 412 | 0 | 1 | 1 | 1 | |
209+
| `0x600160005560006000556001600055` | 40218 | 19800 | 0 | 1 | 0 | 1 |
210+
| `0x600060005560016000556000600055` | 10218 | 19800 | 1 | 0 | 1 | 0 |
89211

90212
## Implementation
91213

92214
To be added.
93215

216+
## Appendix: Proof
217+
218+
Because the *storage slot's original value* is defined as the value
219+
when a reversion happens on the *current transaction*, it's easy to
220+
see that call frames won't interfere SSTORE gas calculation. So
221+
although the below proof is discussed without call frames, it applies
222+
to all situations with call frames. We will discuss the case
223+
separately for *original value* being zero and not zero, and use
224+
*induction* to prove some properties of SSTORE gas cost.
225+
226+
*Final value* is the value of a particular storage slot at the end of
227+
a transaction. *Absolute gas used* is the absolute value of *gas used*
228+
minus *refund*. We use `N` to represent the total number of SSTORE
229+
operations on a storage slot. For states discussed below, refer to
230+
*State Transition* in *Explanation* section.
231+
232+
### Original Value Being Zero
233+
234+
When *original value* is 0, we want to prove that:
235+
236+
* **Case I**: If the *final value* ends up still being 0, we want to charge `200 *
237+
N` gases, because no disk write is needed.
238+
* **Case II**: If the *final value* ends up being a non-zero value, we want to
239+
charge `20000 + 200 * (N-1)` gas, because it requires writing this
240+
slot to disk.
241+
242+
#### Base Case
243+
244+
We always start at state A. The first SSTORE can:
245+
246+
* Go to state A: 200 gas is deducted. We satisfy *Case I* because
247+
`200 * N == 200 * 1`.
248+
* Go to state B: 20000 gas is deducted. We satisfy *Case II* because
249+
`20000 + 200 * (N-1) == 20000 + 200 * 0`.
250+
251+
#### Inductive Step
252+
253+
* From A to A. The previous gas cost is `200 * (N-1)`. The current
254+
gas cost is `200 + 200 * (N-1)`. It satisfy *Case I*.
255+
* From A to B. The previous gas cost is `200 * (N-1)`. The current
256+
gas cost is `20000 + 200 * (N-1)`. It satisfy *Case II*.
257+
* From B to B. The previous gas cost is `20000 + 200 * (N-2)`. The
258+
current gas cost is `200 + 20000 + 200 * (N-2)`. It satisfy
259+
*Case II*.
260+
* From B to A. The previous gas cost is `20000 + 200 * (N-2)`. The
261+
current gas cost is `200 - 19800 + 20000 + 200 * (N-2)`. It satisfy
262+
*Case I*.
263+
264+
### Original Value Not Being Zero
265+
266+
When *original value* is not 0, we want to prove that:
267+
268+
* **Case I**: If the *final value* ends up unchanged, we want to
269+
charge `200 * N` gases, because no disk write is needed.
270+
* **Case II**: If the *final value* ends up being zero, we want to
271+
charge `5000 - 15000 + 200 * (N-1)` gas. Note that `15000` is the
272+
refund in actual definition.
273+
* **Case III**: If the *final value* ends up being a changed non-zero
274+
value, we want to charge `5000 + 200 * (N-1)` gas.
275+
276+
#### Base Case
277+
278+
We always start at state X. The first SSTORE can:
279+
280+
* Go to state X: 200 gas is deducted. We satisfy *Case I* because
281+
`200 * N == 200 * 1`.
282+
* Go to state Y: 5000 gas is deducted. We satisfy *Case III* because
283+
`5000 + 200 * (N-1) == 5000 + 200 * 0`.
284+
* Go to state Z: The absolute gas used is `5000 - 15000` where 15000
285+
is the refund. We satisfy *Case II* because `5000 - 15000 + 200 *
286+
(N-1) == 5000 - 15000 + 200 * 0`.
287+
288+
#### Inductive Step
289+
290+
* From X to X. The previous gas cost is `200 * (N-1)`. The current gas
291+
cost is `200 + 200 * (N-1)`. It satisfy *Case I*.
292+
* From X to Y. The previous gas cost is `200 * (N-1)`. The current gas
293+
cost is `5000 + 200 * (N-1)`. It satisfy *Case III*.
294+
* From X to Z. The previous gas cost is `200 * (N-1)`. The current
295+
absolute gas cost is `5000 - 15000 + 200 * (N-1)`. It satisfy *Case
296+
II*.
297+
* From Y to X. The previous gas cost is `5000 + 200 * (N-2)`. The
298+
absolute current gas cost is `200 - 4800 + 5000 + 200 * (N-2)`. It
299+
satisfy *Case I*.
300+
* From Y to Y. The previous gas cost is `5000 + 200 * (N-2)`. The
301+
current gas cost is `200 + 5000 + 200 * (N-2)`. It satisfy *Case
302+
III*.
303+
* From Y to Z. The previous gas cost is `5000 + 200 * (N-2)`. The
304+
current absolute gas cost is `200 - 15000 + 5000 + 200 * (N-2)`. It
305+
satisfy *Case II*.
306+
* From Z to X. The previous gas cost is `5000 - 15000 + 200 *
307+
(N-2)`. The current absolute gas cost is `200 + 10200 + 5000 -
308+
15000 + 200 * (N-2)`. It satisfy *Case I*.
309+
* From Z to Y. The previous gas cost is `5000 - 15000 + 200 *
310+
(N-2)`. The current absolute gas cost is `200 + 15000 + 5000 -
311+
15000 + 200 * (N-2)`. It satisfy *Case III*.
312+
* From Z to Z. The previous gas cost is `5000 - 15000 + 200 *
313+
(N-2)`. The current absolute gas cost is `200 + 5000 - 15000 + 200 *
314+
(N-2)`. It satisfy *Case II*.
315+
94316
## Copyright
95317

96318
Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).

0 commit comments

Comments
 (0)