1
1
---
2
2
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
4
4
author : Wei Tang (@sorpaas)
5
5
discussions-to : https://github.com/sorpaas/EIPs/issues/1
6
6
status : Draft
@@ -12,24 +12,54 @@ requires: 1283, 1706, 1884
12
12
13
13
## Simple Summary
14
14
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.
17
18
18
19
## Abstract
19
20
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.
23
27
24
28
## Motivation
25
29
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.
28
57
29
58
## Specification
30
59
31
60
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:
33
63
34
64
* ` SLOAD_GAS ` : changed from ` 200 ` to ` 800 ` .
35
65
* ` SSTORE_SET_GAS ` : ` 20000 ` , not changed.
@@ -39,7 +69,7 @@ Define variables `SLOAD_GAS`, `SSTORE_SET_GAS`, `SSTORE_RESET_GAS` and
39
69
Change the definition of EIP-1283 using those variables. The new
40
70
specification, combining EIP-1283 and EIP-1706, will look like
41
71
below. The terms * original value* , * current value* and * new value* are
42
- defined in EIP-1283.
72
+ defined in EIP-1283.
43
73
44
74
Replace SSTORE opcode gas cost calculation (including refunds) with
45
75
the following logic:
@@ -68,29 +98,221 @@ the following logic:
68
98
refund counter.
69
99
* Otherwise, add ` SSTORE_RESET_GAS - SLOAD_GAS ` gas to refund
70
100
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.
73
103
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.
76
108
77
109
## Rationale
78
110
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.
81
174
82
175
## Backwards Compatibility
83
176
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.
85
183
86
184
## Test Cases
87
185
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 |
89
211
90
212
## Implementation
91
213
92
214
To be added.
93
215
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
+
94
316
## Copyright
95
317
96
318
Copyright and related rights waived via [ CC0] ( https://creativecommons.org/publicdomain/zero/1.0/ ) .
0 commit comments