Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EIP-1283: Net gas metering for SSTORE without dirty maps #1

Open
sorpaas opened this issue Aug 1, 2018 · 14 comments
Open

EIP-1283: Net gas metering for SSTORE without dirty maps #1

sorpaas opened this issue Aug 1, 2018 · 14 comments

Comments

@sorpaas
Copy link
Owner

sorpaas commented Aug 1, 2018

eip: 1283
title: Net gas metering for SSTORE without dirty maps
author: Wei Tang (@sorpaas)
status: Draft
type: Standards Track
category: Core
created: 2018-08-01

Abstract: This EIP proposes net gas metering changes for SSTORE opcode. Rendered

Note on Undefined Behavior

In this specification, we assert that contract creations are always on empty account with empty storage. This is true for Ethereum and all Ethereum-based networks. As a result, contract creations on empty account with non-empty storage is considered undefined behavior.

@veox
Copy link

veox commented Aug 9, 2018

A small style note: gas in this case is an uncountable noun, if used in a "vehicle fuel" metaphor.

I.e.,

s/gases/gas/g

@sorpaas
Copy link
Owner Author

sorpaas commented Aug 10, 2018

Thanks. Fixed!

@fulldecent
Copy link

Here is my complete review on the current proposal draft.

Complicated

The state diagram and explanation are too complicated. This table may or may not help:

A is any non-zero value and B is any-zero value that is not equal to A.

Original value Current value New value Outcome
ANY ANY = current value Deduct 200 gas
0 0 A Deduct 20,000 gas
0 A 0 Deduct 200 gas, add 19,800 to refund
0 A B Deduct 200 gas
A 0 A or B Deduct 200 gas, remove 15,000 from refund
A A 0 Deduct 5,000 gas, add 15,000 to refund
A A B Deduct 5,000 gas
A B 0 Deduct 200 gas, add 15,000 to refund
A B A Deduct 200 gas, add 4,800 to refund

Review alternatives considered

There are several obvious alternatives to consider:

  • Increase cost of SLOAD because now it must check the local cache AND the storage state.
  • Choose a different value than 200.
  • Charge 200 for all SSTORE and then charge and refund more gas at the end of a transaction based on whether the writes are necessary.

Please explain the level of review that was performed to evaluate the fitness of the proposed solution versus these options and other considered options.

Review economics

The value 200 is a new constant. Please explain this choice.

The price to store a word and then erase it from storage is a fixed 400 gas including refunds. At some point this will be cheaper than the memory expansion function, which is variable priced based on the amount of memory used. This means optimizers will do well to instantiate dummy storage variables as overflow memory registers. Before we encourage this perverse behavior, I would like to see this proposal provide an analysis of the break even point where this optimization saves gas.

@sorpaas
Copy link
Owner Author

sorpaas commented Oct 16, 2018

Hi @fulldecent, thanks for the review!

Regarding the state diagram, I would encourage you to look deeper into the state diagram provided by Nick Johnson in the explanation section. By separating what the original value of the storage is, we can make everything look much clearer.

Regarding "review alternatives considered":

Increase cost of SLOAD because now it must check the local cache AND the storage state.

Check local cache and the storage state is the current behavior. The reason is that checking storage state is much more expensive compared with checking cache. That's why we have cache in the first place!

Choose a different value than 200.

The reason we have 200 is because it aligns with SLOAD gas cost. That fits current assumption of how much gas a storage cache read/write would take.

Charge 200 for all SSTORE and then charge and refund more gas at the end of a transaction based on whether the writes are necessary.

That's EIP-1087, if you want to take a look. You can also see EIP-1283's motivation section for more explanation of why it doesn't work for some clients.

Regarding "review economics":

At some point this will be cheaper than the memory expansion function, which is variable priced based on the amount of memory used.

This "economics" is present right now on mainnet, and either EIP-1283 or EIP-1087 does not affect it. An initial SSTORE operation which creates a new cache slot on execution would cost just as much as it currently does. So I think this discussion would fit more on topics of "storage rent", but not probably not here.

@fulldecent
Copy link

Isn't the local cache is currently an implementation detail? This proposal creates a read/write storage layer. So I believe this is additive.


Regarding 1087, any notes leading to the decisions in this EIP should be discussed here so that this document can stand on its own.


I am not concerned with creating new cache slots. I am concerned with a contract that initializes with 60016fff55 60016ffe55 ... and then uses (and resets) these storage locations as an alternative to using memory. Presently this approach would cost 5000 per word stored. But this proposal reduces that to 200 per access plus 200 to reset. So I'd like to understand the breakeven.


New issue. Was there a consideration to make STATICCALL compatible with storage where a word is set and then reset before the transaction finishes? This might be valuable to people doing formal verification where they use *CALL more than the average bear.

ping @jacqueswww

@sorpaas
Copy link
Owner Author

sorpaas commented Oct 16, 2018

Isn't the local cache is currently an implementation detail?

Many things in EVM can be argued to be implementation detail. That's true. The goal for having gas cost is to make it matches the most common implementation structure's actual cost.

This proposal creates a read/write storage layer. So I believe this is additive.

We have some explanations in the Motivation section that we don't introduce any unnecessary new concepts compared with what all current client implementations have. The only thing added is to make refund counter able to be reduced. All other structures discussed are needed to be kept by clients anyway due to reasons like transaction reverts, etc.

Regarding 1087, any notes leading to the decisions in this EIP should be discussed here so that this document can stand on its own.

Yeah sure. Right now most of the explanations of this are in EIP-1283's motivation section, if you want to take a look. I would also appreciate help fetching relevant link to this discussion issue.

Presently this approach would cost 5000 per word stored. But this proposal reduces that to 200 per access plus 200 to reset.

Memory cost is only calculated when the memory is expanded, meaning only the first time when MSTORE is called on an upper address. For SSTORE, we charge the same gas as present the first time when an address is allocated, and this is the only time when we need to allocate cache for the storage item. If someone wants to maximize the memory allocated, he or she would want to touch upper address only once -- because subsequent touches of those address would have no memory expansion cost, but individual cost would be more for SSTORE compared with MSTORE. For this case, using either MSTORE or SSTORE would make no difference before or after this EIP, because (whenever storage cache item allocation is needed) we charge the same gas when SSTORE first touches an address.

Was there a consideration to make STATICCALL compatible with storage where a word is set and then reset before the transaction finishes?

That would change the semantic of STATICCALL and I would think it's too much for this EIP. I don't have opinion whether that would be a useful feature, but if it indeed does, we probably would want to use another EIP to track that.

@fulldecent
Copy link

fulldecent commented Oct 18, 2018

I don't disagree with your points, but I believe that at least some of this analysis belongs in the EIP proper.

Regarding memory cost. The current cost of memory at large quantities is quadratic.

screen shot 2018-10-17 at 10 21 00 pm

But the proposed SSTORE cost is linear and much lower than before.

Abusing SSTORE (with pre-paid dirty blocks) allows SSTORE to work effectively like memory. SSTORE usage is linear. Therefore this EIP reduces some large memory store costs from quadratic to linear.

I do not know if this leads to any practical problems. However this topic should be studied to its logical conclusion and presented inside the EIP.

@sorpaas
Copy link
Owner Author

sorpaas commented Oct 18, 2018

With this EIP, whenever we're allocating memory for storage cache, the cost is always the same as current. Yes, indeed later we can add more gas to refund counter compared with current, but that doesn't present attack vector -- you cannot use gas from refund counter in the current transaction.

I think if we want to provide any analysis, it's basically this: Given a block gas limit, it is not possible to allocate more memory using SSTORE comparing EIP-1283 and current scheme. It is, however, possible to have (potentially a lot of) transaction fee reduction comparing EIP-1283 and current scheme.

sorpaas pushed a commit that referenced this issue Jan 15, 2019
* Proposed EIP for address and ERC20 transfer rules

* Update eip-X.md

Updating creation date

* Update eip-X.md (#1)

* Update eip-X.md

* Update eip-X.md

* Update eip-X.md

Rule -> IRule consistently
fix missing links
improve abstract

* Update eip-X.md

typos
small improvements
adds implementation section
@forshtat
Copy link

forshtat commented Jan 16, 2019

I've created a pull request to modify the proposal with regard to reentrancy issue, but I think this is a correct place for a discussion.

Here is a link:
ethereum#1706

In short, I propose to revert any attempt to perform SSTORE if gasleft <= 2300, which makes an assumption that 'gas stipend' is not enough to modify storage more explicit.

@wighawag
Copy link

FYI, unless extra precaution is taken for eth_estimateGas such gasleft() requirement will break existing application that use eth_estimateGas with contract that use SSTORE for which less than 2300 is enough to complete the call. See comment here

And see general proposal for fixing eth_estimateGas in ethereum#2075

@wighawag
Copy link

Sorry false alert, the issues was discovered in ganache and I assumed it was the case everywhere.

Geth and parity use binary search to find the minimum gas amount and will work with 1706 keeping backward compatibility

@chfast
Copy link

chfast commented Jul 26, 2019

@sorpaas @AlexeyAkhunov I did quick analysis of @AlexeyAkhunov alternative proposal to charge min 2300 for SSTORE but add 1500 refund more. None of the EIPs list use cases for it, so I took a simple lock/mutex which is

SLOAD  # check the lock status
SSTORE 0 -> 1 # lock
... # do something, e.g. make a call
SSTORE 1 -> 0 # unlock

@AlexeyAkhunov's proposal (let's call it variant 2) looks pretty solid because SSTORE / SLOAD will cost 800 now (I still have 200 in my mind).
In simplest operation of a CALL costing 700 the variant 2 is less than 7% more expensive in the end.
For the case where in variant 1 we get full refund and the protected operation cost ~17k the difference is less than 4%.
In the final case where variant 2 also get full refund the protected operation cost ~20k (and the end costs are the same obviously).

https://docs.google.com/spreadsheets/d/1l6HHVAEcmJyb76J-trNQQFD1lipjkBkl5-QYx3ME2mc/edit?usp=sharing

@gumb0
Copy link

gumb0 commented Aug 1, 2019

Here's the updated test cases table repriced according to EIP-2200

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

@fulldecent
Copy link

I have reviewed this EIP. Just one comment but otherwise everything is great.

SLOAD repricing is not necessary or explained

This EIP changes the price of SLOAD from 200 to 800. I suppose the reason why is because EIP-1884 (DRAFT) and EIP-2200 (DRAFT) are both dependencies of EIP-1679 (DRAFT) and the former changes G_SLOAD from 200 to 800.

The reasoning in EIP-2200 (DRAFT) is opaque and is:

  1. not cited in EIP-2200 (DRAFT); and
  2. not referenced as a dependency in EIP-2200 (DRAFT)

I request that the specification remove the requirement that SLOAD_GAS be changed from 200 to 800. Or alternatively, include arguments of why such a change is necessary, using rigor comparable to EIP-1884 (DRAFT).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants