EIP 3298: Removal of refunds

3403 still ruins any incentive to clean up state outside of the same transaction. The misalignment of incentives should offset any perceived gains on the storage-bloat motivation, but with real storage that would need to be rented under any state rent scheme. The concerns described by @thabaptiser have only been addressed in the same-transaction case. Here are some specifically incentivized behaviors, which I listed in ACD.

  • Storage arrays should use 1-indexing such-that length-zero is stored as 1 so adding anther element does not incur SSTORE_SET. Additionally, popped elements should not be cleared for the same reason
  • UI-prompted approvals should always be infinite.
  • When selling all tokens you should leave 1 in your wallet, which will change the “Sell MAX” behavior on most DEX interfaces.

I’m also opposed to 3403’s motivation because I favor elasticity. 4x is the best part of 1559 and as a power user who transacts during congestion I don’t want to see larger spikes.

In ACD, @holiman mentioned that miners have been mining blocks that are only gas tokens. F2Pool clarified this was because this is their default candidate block and it is only mined if they have not yet sealed another.

In ACD it was mentioned that miners may increase the gas limit under 1559 to fight against the base fee. The possibility of 4x may discourage that behavior since they will struggle to capitalize on MEV if 4x exceeded their full capacity. Because of this and sync-time concerns for the node failure case, I don’t expect miners to target the gas limit above 4x their capacity.

Here is a copy of the prepared statement I read during today’s ACD. I didn’t read it very well (8 charisma), and Tim said on Twitter that some asked for the text.

First, the proposal removes any incentive to clear state, except for the same-transaction case. When smart contract engineers build around such incentives we will see more state bloat. Approving less than infinite will be phased out in the UX. Selling all of your tokens on most interfaces will leave 1 unit behind. Storage arrays will be cleared by setting the size field to 1 (which will mean 0) and leaving all entries dirty as it would be foolish to clear them. And these are only a few of the design implications.

The proposal also sacrifices current elasticity, which smooths gas price spikes during peak congestion. 1559 does not provide sufficient elasticity because peak congestion lasts hours not minutes. By sacrificing refund elasticity concurrently with 1559 we should expect a net increase in volatility that would counteract the anticipated improvements in signature-time gas price estimation. While the motivations for the proposal cite brief 4x sprints as possibly dangerous, I believe them to be the top feature of 1559. Grocers don’t raise their prices during peak hours; they hire part-time workers, so their customers don’t complain and flee to other stores. The long-term costs of potential 4x blocks are amortized during periods of lower congestion. But all nodes should be able to verify the consecutive 4x blocks smoothly, else they wouldn’t be able to sync the blockchain in any reasonable timeframe.

As proof that the network can handle 4x today I present Binance Smart Chain, which sets a higher gas limit of 30 million every 3 seconds, approximately 11 times the current Ethereum capacity. My devnode, which runs on an older low-end processor, gets 70 mgas per second in Berlin, so I would still be able to sync Binance Smart Chain even if all of their blocks were 4x.

In the previous meeting we agreed to table 3403 if 4x wasn’t a security concern. There have been some better ideas floated in the discord, such as separate markets for computation gas and storage growth. A less-rushed solution might do more good than harm, and we could free up London engineering bandwidth for more-important work.

I’m in support of this EIP. It cleans up EVM mechanics in a way that feels worth the downsides that I’ve seen thus far.

Addressing some specific points:

I am empathetic to what appears to be a significant financial downside that you may face with this change, but this type of reason isn’t compelling to me. You should probably start looking now at how you can reduce your financial risk from this change.

Refunds have been shown to not be a viable mechanism for mitigating state growth in a meaningful way. Thus, the argument that this will make state growth/bloat worse is not compelling here. See this other post on “state expiry” for how we intend to meaningfully address state growth: Resurrection-conflict-minimized state bounding, take 2 - #17 by vbuterin - Execution Layer Research - Ethereum Research . The “state expiry” plans will be effective with or without refunds or incentives to clear state.

citation needed; refuted several times with specific examples.

We have had refunds since the beginning of the chain. State growth is a problem and continues to be a problem… Removing refunds willmake the problem worse. My intuition is that the amount worse is going to be insignificant when compared to the overall rate of growth. Without firm economic bounds, state growth/bloat will continue to be a problem Refunds do not provide economic bounds for the overall state size. State expiry fully solves this. With state expiry, state clearing incentives no longer matter with respect to limiting total state size. Thus, the added benefit of having some incentive to clear state feel insignificant compared to the complexity cleanup that removal of refunds provides.

Please let me know if something is unclear here.

1 Like

I’m in support of this EIP. It cleans up EVM mechanics in a way that feels worth the downsides that I’ve seen thus far.

FWIW, I don’t have any skin in the game here (so to the extent to which anyone is looking at “these arguments are motivated”: I’m immune).

My goal is only to make it so that my contracts are as gas efficient as possible; to such end, all of my test cases report how much gas they used, so I can attempt to optimize whatever I can. I try try try to not fret tens of gas, but I consider the tradeoffs carefully for hundreds of gas, I consider thousands of gas to be worthy of going to great lengths to avoid, and when I see tens of thousands of gas I will spend a full week figuring out if I can somehow remove it.

The current specification–the status quo–thereby has a kind of beauty to it: developers like me are incentivized to minimize storage. If you think I am simply not doing that, you are being needlessly hyperbolic. Meanwhile, users are also likewise incentivized: they are encouraged to delete their accounts and clean up their state, rather than leave it to rot.

The idea that–as @wjmelements points out–users are going to get no refund (or even discount) for setting a storage slot to 0 and yet are dinged 15,000 gas for setting it from 0 to not 0 feels really horrible. It is the kind of ridiculous special case–one that absolutely will change the way I develop contracts, as that 15,000 gas “transition through 0” penalty will light up my test cases as a very large and annoyingly-avoidable (by using “1 is the new 0”) cost–that should make one pause and realize “we have incorrectly modeled this”.

If one wants to make new rules, those rules need to at least be consistent! Here is thereby another suggestion (which actively leans into the idea of what you want): if the cost for changing a storage slot away from 0 is going to somehow cost money in a way that isn’t later consistent with changes back and forth through 0, it sounds like what you actually want to charge for is something like “storage allocation”. As such, you should make it only 5000 (not 20000) to re-write to a storage slot that has ever been written to before.

Obviously, this means that nodes essentially no longer get to reallocate anything, as they will need to remember this storage slot for all time… but that’s their–and this idea of not giving people refunds–fault, and cannot just be avoided by not doing this: doing what you want without this change still does this, because “1 is the new 0”: only an idiot contract developer will ever clear a storage slot to 0 anyway in your model (due to having to pay 15,000 every time it is reset from 0), and so that storage is effectively burned.

What this alternation to your mechanism does, though, is it makes the development process a bit less “disgusting”: it internalizes to the platform this really horrible behavior you want to incentivize of avoiding clearing state–even if you semantically needed to clear state!!!–so that I don’t have to go through my contract and remove every single place where I not only purposefully, but even accidentally, set anything to 0 (which is such a sufficiently obviously “bad for the developer” incentive that I don’t understand how this proposal is getting as far as it seems to have gotten).

3 Likes

Just as @saurik described here, as a gas conscious developer, I will start avoiding setting to 0 in all contracts if this goes live. If/when I get involved in SushiSwap AMM V2 I will make sure it’s lean on gas usage, because this is a competitive advantage. In this era of very high gas prices, protocols will compete on gas efficiency. 1 will be the new 0 for me.

The constant changing of gas costs is a real PITA from a dev point of few, because many contracts can’t be changed after being deployed. With this EIP you’re helping protocols built by lazy devs and penalizing those who have taken great care to preserve gas and clean up state.

I’m all for improvements, and if gas tokens are a real issue, finding a way to get rid of them… but this proposal seems half baked.

P.S. I hold 0 gas tokens, I just like optimized code.

2 Likes

The following is the prepared statement I read in today’s ACD regarding security.

Previously we agreed that, with present gas limits, brief spurts of 4x throughput would not be an issue. But the concern was raised that miners will increase the gas limit in London to minimize the base fee, perhaps to an unsafe level. The initial proposal to fix this was to hardcode the block gas limit. That proposal was defeated in part because miners have responsibly managed the gas limit. If that is changing with 1559, a hard limit would be better DoS protection than this proposal. But if we expect miners to continue to be responsible, they would have to consider their capacity to handle brief 4x spurts in their gas limit voting, and this would limit the extent to which they could maximize the gas limit, thereby securing the base fee.

If we believe miners will push an infinite gas limit, it won’t matter if the elasticity is 2x or 4x. If this is a major security concern we should revisit the hard cap, though I would recommend a much higher limit than the original proposal.

On the other hand, if we assume miners will want to prevent each other from submitting DoS blocks, the BASE_FEE would be more secure with the possibility of 4x than just 2x.

I also read the following excerpts from this forum, citing the author.

I concluded:

Therefore, the storage bloat motivation for 3403 should be replaced with an acknowledgement that the proposal incentivizes protocols, interfaces, and users to bloat storage.

@shemnon mentioned an alternative proposal, to count gas used before refund against the total gas limit. This would eliminate what @holiman called the refund stipend, which would reduce elasticity. It may incentivize miners to reprioritize transactions according to total gas used instead of just gas price, but it would fix all currently-known issues, and seems slightly simpler than 3403. The only downside to this approach seems to be the reduced elasticity during congestion.

It seems the real issue is that the block gas limit includes long-term storage costs and rebates. If we could somehow isolate those costs from the block gas limit such that the user still pays for them but throughput gas remains constant, it would likely be the best solution.

1 Like

One alternative is to make updating storage a fixed cost and no refund for selfdestruct. This will obviously deal with the inefficiency of gas tokens for the system overall. Not ideal for coders like me who spend time optimizing their contracts, but at least if doesn’t lead to weird contracts trying to never go back to 0 (I’d probably end up writing a uint255 library, with one bit always set to 1).

As part of this it would be nice to introduce storage costing on transaction basis, so if a storage slot has the same value at the start of the tx and at the end you pay some minimal fee for updating a memory variable and an SLOAD fee.

From a developers perspective it would be nice if docs somewhere could be updated (in plain English and not math notation) to have the current gas math and approved EIP changes and when they’ll go live. It’s hard enough to optimize for gas, but even harder to keep up to date with the ever changing rules. (If this already exists, please point me in that direction…)

I see an issue with the following flow within single transaction:

  1. Write non-zero to zero storage slot
  2. Write zero to the same storage slot
  3. Revert both actions

Gas cost of the following solution would be approximately 25k without any gas refund (revert erases gas refunds). But actual job of doing nothing should not cost that high.

I propose instead of erasing gas refund on revert keep it equal to cost of all the reverted SSTORE operations.