Rob's Blog

Personal Blog

29 February 2020

Selfdestruct Pros/Cons

Calling selfdestruct(...) in a Solidity smart contract (EVM operation SELFDESTRUCT or SUICIDE, respectively) is probably a good thing:

  1. It resets all storage variables of a smart contract.
  2. Refunds Gas for this cleanup (see Appendix G. Fee Schedule in the Ethereum Yellow Paper1: $R_{\text{sclear}}$ and $R_{\text{selfdestruct}}$).
  3. Transfers the contract’s balance to a given account.

But it can be risky! And make things more complex.

Disclaimer: This pros/cons list does not claim to be complete. I’ll update it as soon as I have new points. You are welcome to mail me if you find any missing aspects.

Pros

Cons

Example: Effects on Time-Based Voting

Let’s say we have a very basic voting contract which stops counting new votes at a certain date. The following function can only be called in the following 14 days after the smart contract’s deployment. Wouldn’t it be handy to self-destruct the smart contract automatically when somebody tries to vote, but the time is over?

uint256 public end = now + 14 days;
mapping(uint256 => uint256) public votes;
address payable owner = msg.sender;

function vote(uint256 _vote) public {
  if(now < end)
    votes[_vote]++; // TODO: check for overflow
  else
    selfdestruct(owner); // owner is the account which deployed the smart contract
}

The problem here is, that selfdestruct sets all non-0 storage values of the contract to 0. Hence, all values in the votes mapping will also be set to 0. But in the case that the votings results are still relevant, it would be more complex to get back the results. For this, one would need to find out at which block the contract has been destructed, and then query that block’s predecessor state.

The following code, though, persists the voting results as events, which can be monitored by others. But the contract has two major problems: First, it is still complex to query past events of a destructed contract (one has to get an old state and therefore the block number must be known), and second, the last one who calls this function will not get back the function’s return value (because selfdestruct stops the function before it’s finished).

uint256 public end = now + 14 days;
mapping(uint256 => uint256) public votes;
address payable owner = msg.sender;

event VoteCounted(uint256 vote);

function vote(uint256 _vote) public returns (bool _successful) {
  if(now < end) {
    _successful = votes[_vote] + 1 > votes[_vote]; // This is an overflow check
    if(_successful) {
      votes[_vote]++; 
      emit VoteCounted(_vote);
    }
  } else {
    _successful = false;
    selfdestruct(owner); // owner contains the account which deployed the smart contract
  }
	
  return _succsessful; // not necessary, see following note
}

Please note here, that calling return _succsessful; at the end is not necessary, because the return variable is already specified in the function header. It would also be returned even if the return wouldn’t be the last command of the function—except in our special case with selfdestruct.

  1. ethereum.github.io/yellowpaper/paper.pdf  2

  2. for example, see eveem.org/#destruct, they look for callable selfdestructs automatically 

  3. eips.ethereum.org/EIPS/eip-20 

tags: Solidity - Ethereum - Voting