Automatically merged updates to draft EIP(s) 1283

Hi, I'm a bot! This change was automatically merged because:

 - It only modifies existing Draft or Last Call EIP(s)
 - The PR was approved or written by at least one author of each modified EIP
 - The build is passing
This commit is contained in:
Wei Tang 2018-10-18 10:42:33 +08:00 committed by EIP Automerge Bot
parent f2f879361e
commit 001ccad32d
1 changed files with 145 additions and 22 deletions

View File

@ -12,30 +12,20 @@ created: 2018-08-01
## Abstract
This EIP proposes net gas metering changes for SSTORE opcode, as an
alternative for EIP-1087. It tries to be friendlier to implementations
that use different optimization strategies for storage change
caches.
This EIP proposes 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 acts as an alternative for EIP-1087, where it tries to be
friendlier to implementations that use different optimization
strategies for storage change caches.
## Motivation
EIP-1087 proposes a way to adjust gas metering for SSTORE opcode,
enabling new usages on these opcodes where it is previously too
expensive. However, EIP-1087 requires keeping a dirty map for storage
changes, and implicitly makes the assumption that a transaction's
storage changes are committed to the storage trie at the end of a
transaction. This works well for some implementations, but not for
others. After EIP-658, an efficient storage cache implementation would
probably use an in-memory trie (without RLP encoding/decoding) or
other immutable data structures to keep track of storage changes, and
only commit changes at the end of a block. For them, it is possible to
know a storage's original value and current value, but it is not
possible to iterate over all storage changes without incurring additional
memory or processing costs.
This EIP proposes an alternative way for gas metering on SSTORE, using
information that is more universally available to most
implementations:
This EIP proposes a way for gas metering on SSTORE (as an alternative
for EIP-1087 and EIP-1153), using information that is more universally
available to most implementations, and require as little change in
implementation structures as possible.
* *Storage slot's original value*.
* *Storage slot's current value*.
@ -97,7 +87,18 @@ the following logic:
* Otherwise, add 4800 gas to refund counter.
Refund counter works as before -- it is limited to half of the gas
consumed.
consumed. On a transaction level, refund counter will never go below
zero. However, there are some important notes depending on the
implementation details:
* If an implementation uses "transaction level" refund counter (refund
is checkpointed at each call frame), then the refund counter
continues to be unsigned.
* If an implementation uses "execution-frame level" refund counter
(a new refund counter is created at each call frame, and then merged
back to parent when the call frame finishes), then the refund
counter needs to be changed to signed -- at internal calls, a child
refund can go below zero.
## Explanation
@ -169,6 +170,28 @@ This EIP mostly archives 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.
* We don't suffer from the optimization limitation of
EIP-1087. EIP-1087 requires keeping a dirty map for storage changes,
and implicitly makes the assumption that a transaction's storage
changes are committed to the storage trie at the end of a
transaction. This works well for some implementations, but not for
others. After EIP-658, an efficient storage cache implementation
would probably use an in-memory trie (without RLP encoding/decoding)
or other immutable data structures to keep track of storage changes,
and only commit changes at the end of a block. For them, it is
possible to know a storage's original value and current value, but
it is not possible to iterate over all storage changes without
incurring additional memory or processing costs.
* It never costs more gas compared with the current scheme.
* It covers all usages for a transient storage. Clients that are easy
to implement EIP-1087 will also be easy to implement this
specification. Some other clients might require a little bit extra
refactoring on this. Nonetheless, no extra memory or processing cost
is needed on runtime.
Regarding SSTORE gas cost and refunds, see Appendix for proofs of
properties that this EIP satisfies.
* For *absolute gas used* (that is, actual *gas used* minus *refund*),
this EIP is equivalent to EIP-1087 for all cases.
* For one particular case, where a storage slot is changed, reset to
@ -218,6 +241,106 @@ slot is reset and then set again.
| `0x600160005560006000556001600055` | 40218 | 19800 | 0 | 1 | 0 | 1 |
| `0x600060005560016000556000600055` | 10218 | 19800 | 1 | 0 | 1 | 0 |
## Appendix: Proof
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. Below 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.
### Original Value Being Zero
When *original value* is 0, we want to prove that:
* **Case I**: If the *final value* ends up still being 0, we want to charge `200 *
N` gases, because no disk write is needed.
* **Case II**: If the *final value* ends up being a non-zero value, we want to
charge `20000 + 200 * (N-1)` gas, because it requires writing this
slot to disk.
#### Base Case
We always start at state A. The first SSTORE can:
* Go to state A: 200 gas is deducted. We satisfy *Case I* because
`200 * N == 200 * 1`.
* Go to state B: 20000 gas is deducted. We satisfy *Case II* because
`20000 + 200 * (N-1) == 20000 + 200 * 0`.
#### Inductive Step
* From A to A. The previous gas cost is `200 * (N-1)`. The current
gas cost is `200 + 200 * (N-1)`. It satisfy *Case I*.
* From A to B. The previous gas cost is `200 * (N-1)`. The current
gas cost is `20000 + 200 * (N-1)`. It satisfy *Case II*.
* From B to B. The previous gas cost is `20000 + 200 * (N-2)`. The
current gas cost is `200 + 20000 + 200 * (N-2)`. It satisfy
*Case II*.
* From B to A. The previous gas cost is `20000 + 200 * (N-2)`. The
current gas cost is `200 - 19800 + 20000 + 200 * (N-2)`. It satisfy
*Case I*.
### Original Value Not Being Zero
When *original value* is not 0, we want to prove that:
* **Case I**: If the *final value* ends up unchanged, we want to
charge `200 * N` gases, because no disk write is needed.
* **Case II**: If the *final value* ends up being zero, we want to
charge `5000 - 15000 + 200 * (N-1)` gas. Note that `15000` is the
refund in actual defintion.
* **Case III**: If the *final value* ends up being a changed non-zero
value, we want to charge `5000 + 200 * (N-1)` gas.
#### Base Case
We always start at state X. The first SSTORE can:
* Go to state X: 200 gas is deducted. We satisfy *Case I* because
`200 * N == 200 * 1`.
* Go to state Y: 5000 gas is deducted. We satisfy *Case III* because
`5000 + 200 * (N-1) == 5000 + 200 * 0`.
* Go to state Z: The absolute gas used is `5000 - 15000` where 15000
is the refund. We satisfy *Case II* because `5000 - 15000 + 200 *
(N-1) == 5000 - 15000 + 200 * 0`.
#### Inductive Step
* From X to X. The previous gas cost is `200 * (N-1)`. The current gas
cost is `200 + 200 * (N-1)`. It satisfy *Case I*.
* From X to Y. The previous gas cost is `200 * (N-1)`. The current gas
cost is `5000 + 200 * (N-1)`. It satisfy *Case III*.
* From X to Z. The previous gas cost is `200 * (N-1)`. The current
absolute gas cost is `5000 - 15000 + 200 * (N-1)`. It satisfy *Case
II*.
* From Y to X. The previous gas cost is `5000 + 200 * (N-2)`. The
absolute current gas cost is `200 - 4800 + 5000 + 200 * (N-2)`. It
satisfy *Case I*.
* From Y to Y. The previous gas cost is `5000 + 200 * (N-2)`. The
current gas cost is `200 + 5000 + 200 * (N-2)`. It satisfy *Case
III*.
* From Y to Z. The previous gas cost is `5000 + 200 * (N-2)`. The
current absolute gas cost is `200 - 15000 + 5000 + 200 * (N-2)`. It
satisfy *Case II*.
* From Z to X. The previous gas cost is `5000 - 15000 + 200 *
(N-2)`. The current absolute gas cost is `200 + 10200 + 5000 -
15000 + 200 * (N-2)`. It satisfy *Case I*.
* From Z to Y. The previous gas cost is `5000 - 15000 + 200 *
(N-2)`. The current absolute gas cost is `200 + 15000 + 5000 -
15000 + 200 * (N-2)`. It satisfy *Case III*.
* From Z to Z. The previous gas cost is `5000 - 15000 + 200 *
(N-2)`. The current absolute gas cost is `200 + 5000 - 15000 + 200 *
(N-2)`. It satisfy *Case II*.
## Copyright
Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).