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

Disable SELFDESTRUCT EIP #2751

Closed
wants to merge 3 commits into from
Closed

Conversation

AlexeyAkhunov
Copy link
Contributor

@AlexeyAkhunov AlexeyAkhunov commented Jun 25, 2020

Make SELFDESTRUCT EVM operation no-op (effectively disable). Contracts will not be able to delete themselves.

@MrChico
Copy link
Member

MrChico commented Jun 25, 2020

An alternative to POP semantics would be to turn its semantics into a TRANSFER. Side effect free tranfers is a legitimate use case of SELFDESTRUCT imo

@sorpaas
Copy link
Contributor

sorpaas commented Jun 25, 2020

However, SELFDESTRUCT brings significant amount of complexity to the EVM.

In practice, you cannot remove any complexity already introduced. The future complexity of EVM may be reduced, but all EVMs have to support past block executions, so they will still have the complexity.

Introduction of CREATE2 opcode in Constantinople upgrade created a new phenomenom of polymorthic contracts, i.e. contracts that can change their bytecode over time, while residing on the same address.

I think a better semantic to fix this would be to just leave a marker on-chain but keep everything else of SELFDESTRUCT. Something like this:

At the end of the transaction, instead of removing the contract from state, replace the to-be-removed contract with an empty account with nonce 1.

As @MrChico said, otherwise you'd risk breaking those time-lock contract that relies on SELFDESTRUCT to send funds. I remember they're actually quite common.

@lightclient
Copy link
Member

lightclient commented Jun 25, 2020

FYI in case you missed it, the discussion forum is: https://ethereum-magicians.org/t/eip-for-disabling-selfdestruct-opcode/4382

@AlexeyAkhunov
Copy link
Contributor Author

In practice, you cannot remove any complexity already introduced. The future complexity of EVM may be reduced, but all EVMs have to support past block executions, so they will still have the complexity.

You can, if you change the architecture of the client implementation. It is possible to construct the implementation that only uses EVM (simpler) for the current rule set, and special historical EVM (more complex) to re-trace historical transactions, as I mentioned here: https://ethereum-magicians.org/t/backwards-forwards-sync-of-ethereum-clients/2258

And yes, this discussion will disappear when PR is merged, so better discussed on the FEM link

@vbuterin
Copy link
Contributor

but all EVMs have to support past block executions, so they will still have the complexity

Is this actually true? Why can't a future ethereum client just refuse to support blocks older than block N, with its mainnet config pretending that block N is the genesis?

There are things that removing the SELFDESTRUCT refund will break; particularly, the CREATE -> do stuff -> SELFDESTRUCT workflow for combining multiple operations into one transaction. That said, that may be fine as there are other EIPs to more "naturally" support such functionality.

<!--The motivation is critical for EIPs that want to change the Ethereum protocol. It should clearly explain why the existing protocol specification is inadequate to address the problem that the EIP solves. EIP submissions without sufficient motivation may be rejected outright.-->
Operation `SELFDESTRUCT` (formerly `SUICIDE`) was in the EVM from the beginning, and its purpose was to incentivise clearing the state, by giving the
caller gas refund. In practice, this incentivisation turned out to be very limited, and the designed purpose was not archieved. However, `SELFDESTRUCT`
brings significant amount of complexity to the EVM. It is responsible for some of the most arcane edge cases in the EVM semantics.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Strongly agree on this. In particular, the existence of this opcode significantly increases the complexity of many forms of caching, as SELFDESTRUCT can potentially delete an unbounded number of storage slots.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If selfdestruct did not delete those storage slots it would empower a new kind of upgrade pattern (create2 reincarnations) while reducing SELFDESTRUCT complexity.

I don't think geth ever clears those storage slots from the state trie; it checks if there was a recent self-destruct. A reincarnation could fork the network if not enough nodes remain aware of the selfdestruct and reference a quantum storage slot.

After certain block number, the semantics of `SELFDESTRUCT` becomes the same as the combination of `POP` followed by `STOP`. Gas cost is the same as the gas cost
of `POP`, which is 2 gas. No value transfer occurs and no gas refund is given.
After certain block number, the semantics of `SELFDESTRUCT` becomes the same as the combination of `POP`, followed by transferring remaining ETH
to the address popped from the stack, followed by `STOP`. Gas cost is the same as the gas cost of non-zero value transfer, which is 9000 gas. No gas refund is given.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This gas scheme will make it cheaper to create new account via SELFDESTRUCT (which costs 30000 right now). Better either:

  • Keep the current SELFDESTRUCT gas cost: 5000 + 25000 if new account.
  • Or, increase the base to 9000 like this but also with the 25000 new account penalty: 9000 + 25000 if new account.

Also note that 9000 comes from CALL opcode, but SELFDESTRUCT is not exactly the same as CALL transfer because the former will never execute the target if it's a contract.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's currently cheapest to create an account using a regular 21000 transfer

@sorpaas
Copy link
Contributor

sorpaas commented Jun 25, 2020

Is this actually true? Why can't a future ethereum client just refuse to support blocks older than block N, with its mainnet config pretending that block N is the genesis?

I'm merely speaking as an eth1.x client implementor when talking about this complexity. Practically, right now, we cannot remove any past complexity under the assumption that we want to support all past block executions. Re-defining genesis or like Alexey proposed doing the backwards-forwards sync works around this, of course, but that does mean we drop support for past block execution.

However, putting off the hat of an Ethereum client implementor, I do agree with you and I believe this problem is already solved nicely. For example, in Substrate, all runtime execution logic is written in wasm and recorded on-chain. So client can re-define logic and remove any accidental complexity at will while still being able to execute all past blocks. I believe there's something similar in eth2 EEs, but I'm not really familiar with that.

@wjmelements
Copy link
Contributor

As a gastoken whale I'm strongly opposed. We provide stability to the gasprice and provide more space when blocks are full. Removing the SELFDESTRUCT refund would force us to use SSTORE, which is less-efficient. You would see larger swings in the gasPrice and we would consume more gas overall.

@JayeHarrill
Copy link

Really happy people are finally taking this seriously.

Been shouting this for 6 months now.

How can I help as a Comms person?

@wjmelements
Copy link
Contributor

If you were to break tokenized refunds, you should also fork the state to cleanup every contract they have created and compensate tokenholders at some "fair" gasPrice to limit migratory congestion. I'm aware of the following refund contract creators, but there may be more.

  • CHI 0x0000000000004946c0e9F43F4Dee607b0eF1fA1c
  • GST2 0x0000000000004946c0e9F43F4Dee607b0eF1fA1c
  • TrueUSD 0x0000000000085d4780B73119b644AE5ecd22b376
  • TrueCAD 0x00000100F2A2bd000715001920eB70D229700085
  • TrueAUD 0x00006100F7090010005F1bd7aE6122c3C2CF0090
  • TrueGBP 0x00000000441378008EA67F4284A57932B1c000a5
  • TrueHKD 0x0000852600CEB001E08e00bC008be620d60031F2


## Security Considerations
<!--All EIPs must contain a section that discusses the security implications/considerations relevant to the proposed change. Include information that might be important for security discussions, surfaces risks and can be used throughout the life cycle of the proposal. E.g. include security-relevant design decisions, concerns, important discussions, implementation-specific guidance and pitfalls, an outline of threats and risks and how they are being addressed. EIP submissions missing the "Security Considerations" section will be rejected. An EIP cannot proceed to status "Final" without a Security Considerations discussion deemed sufficient by the reviewers.-->
At this point, author of this EIP is not aware of any class of smart contracts that rely on `SELFDESTRUCT` for their functionality and security, with the exception of
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some projects are using a ephemeral contracts pattern to generate payment accounts, to withdraw from such accounts a contract is deployed on them (using CREATE2), the withdrawal takes place and the contract it's self-destruct.

Because of the ephemeral nature of those accounts, authentication can be skipped (either the transaction fails and the account is never created, or the transaction success and the account is emptied). This would still be a safe pattern as long as the project never reuses those addresses, but it would endanger funds otherwise.

A good example of this pattern can be found on UniswapEX (https://github.com/UniswapEx/exchange/blob/master/contracts/libs/Fabric.sol), I think that UniswapEX is not affected, because those accounts are never re-used, but we would need to check if other projects are using the same pattern while re-using accounts.

@Agusx1211
Copy link
Contributor

As a gastoken whale I'm strongly opposed. We provide stability to the gasprice and provide more space when blocks are full. Removing the SELFDESTRUCT refund would force us to use SSTORE, which is less-efficient. You would see larger swings in the gasPrice and we would consume more gas overall.

I wonder if a built-in gasToken could act as an alternative to EIP-1556, it could mimic the behaviour of GasToken without actually storing anything on the state (only mimic the refunds), so we would get the "gas stabiliser" effect of GasToken without bloating the storage.


## Abstract
<!--A short (~200 word) description of the technical issue being addressed.-->
Althouth `SELFDESTRUCT` originally came with EVM to help clean up the state, we learnt that in practice it did not achieve this objective on

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Althouth should read although

## Specification
<!--The technical specification should describe the syntax and semantics of any new feature. The specification should be detailed enough to allow competing, interoperable implementations for any of the current Ethereum platforms (go-ethereum, parity, cpp-ethereum, ethereumj, ethereumjs, and [others](https://github.com/ethereum/wiki/wiki/Clients)).-->
After certain block number, the semantics of `SELFDESTRUCT` becomes the same as the combination of `POP`, followed by transferring remaining ETH
to the address popped from the stack, followed by `STOP`. Gas cost is the same as the gas cost of non-zero value transfer, which is 9000 gas. No gas refund is given.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the address popped from the stack, followed by STOP.

This suggests selfdestruct can be executed multiple times. Is that the goal?

## Specification
<!--The technical specification should describe the syntax and semantics of any new feature. The specification should be detailed enough to allow competing, interoperable implementations for any of the current Ethereum platforms (go-ethereum, parity, cpp-ethereum, ethereumj, ethereumjs, and [others](https://github.com/ethereum/wiki/wiki/Clients)).-->
After certain block number, the semantics of `SELFDESTRUCT` becomes the same as the combination of `POP`, followed by transferring remaining ETH
to the address popped from the stack, followed by `STOP`. Gas cost is the same as the gas cost of non-zero value transfer, which is 9000 gas. No gas refund is given.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think there's any point introducing new pricing here, if the specification is that SELFDESTRUCT is replaced with CALL(<addr>, <value>, gas=0, ..) and STOP, then just state that and apply the gas rules of those two.

Copy link
Contributor

@wjmelements wjmelements Jun 30, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This operation should be cheaper than CALL because it doesn't need to load code or create an execution context.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

because it doesn't need to load code or create an execution context.

This EIP is changing the semantics of SELFDESTRUCT. From the current description it is not clear whether it turns into a non-executing transfer or not.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, turning it into an executing transfer would be a nice EVM unification/simplification. SELFDESTRUCT is currently one of the "sneakiest" ways to add funds to an address; a capability that people often forget about.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@carver Developers only "forget" about it because of deceptive Solidity syntax. Nobody should assume their contract is "nonpayable". This does not change that because miners can still break that assumption via coinbase.

@wjmelements
Copy link
Contributor

I wonder if a built-in gasToken could act as an alternative to EIP-1556, it could mimic the behaviour of GasToken without actually storing anything on the state (only mimic the refunds), so we would get the "gas stabiliser" effect of GasToken without bloating the storage.

The convenience of the storage overhead is that we free the space when the network is congested, so in exchange for the additional gas we free more storage than the additional usage fills. By outbidding low-priority transactions in low congestion, we consume less space than usage that would not zero-out, thereby smoothing the growth of the state trie.

Copy link
Member

@lightclient lightclient left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few spelling errors were keeping this PR from passing CI, I've noted them in the this review. Additionally, you should be good to assign this EIP as 2751 and update the filename to eip-2751. After that, it should be mergeable and we can avoid losing any valuable discussion in this PR!

caller gas refund. In practice, this incentivisation turned out to be very limited, and the designed purpose was not archieved. However, `SELFDESTRUCT`
brings significant amount of complexity to the EVM. It is responsible for some of the most arcane edge cases in the EVM semantics.
It is also used as a vehicle to run an efficient arbitrage of gas prices (GasToken2), which
ironically lead to the increase use of the state. Introduction of `CREATE2` opcode in Constantinople upgrade created a new phenomenom of
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
ironically lead to the increase use of the state. Introduction of `CREATE2` opcode in Constantinople upgrade created a new phenomenom of
ironically lead to the increase use of the state. Introduction of `CREATE2` opcode in Constantinople upgrade created a new phenomenon of


## Backwards Compatibility
<!--All EIPs that introduce backwards incompatibilities must include a section describing these incompatibilities and their severity. The EIP must explain how the author proposes to deal with these incompatibilities. EIP submissions without a sufficient backwards compatibility treatise may be rejected outright.-->
Backwards incompatible and requres a hard fork.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Backwards incompatible and requres a hard fork.
Backwards incompatible and requires a hard fork.


## Abstract
<!--A short (~200 word) description of the technical issue being addressed.-->
Althouth `SELFDESTRUCT` originally came with EVM to help clean up the state, we learnt that in practice it did not achieve this objective on
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Althouth `SELFDESTRUCT` originally came with EVM to help clean up the state, we learnt that in practice it did not achieve this objective on
Although `SELFDESTRUCT` originally came with EVM to help clean up the state, we learnt that in practice it did not achieve this objective on

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ooh, how did you do this @lightclient?

Copy link
Member

@lightclient lightclient Jul 17, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There should be a plus/minus button as part of the comment interface :) (something like in #6 here https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/commenting-on-a-pull-request)

@wjmelements
Copy link
Contributor

Polymorphic contracts are the superior upgrade model. If you have thousands of token balances and allowances it's much cheaper to upgrade the code in-place than to migrate to a new contract. If it's too much work for the evm to ensure all of the storage slots are cleared, just don't do it; it would save me the trouble of resetting all contract state. Most self-destructs are for contracts without state; very few contracts self-destruct with remaining state.

Instead you could incentivize other contracts to clear it out of the trie manually. A new opcode could point out external storage corresponding to an account without code and clear it for a gas refund.

@github-actions
Copy link

github-actions bot commented Nov 3, 2020

There has been no activity on this pull request for two months. It will be closed in a week if no further activity occurs. If you would like to move this EIP forward, please respond to any outstanding feedback or add a comment indicating that you have addressed all required feedback and are ready for a review.

@github-actions github-actions bot added the stale label Nov 3, 2020
@github-actions
Copy link

This pull request was closed due to inactivity. If you are still pursuing it, feel free to reopen it and respond to any feedback or request a review in a comment.

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

Successfully merging this pull request may close these issues.