Solidity: A Small Test of the Self-Destruct Operation
How ‘selfdestruct’ works in Solidity and how it affects the life of the freshly self-destructed smart contract
For the purpose of this article, I have read some good sources, starting with “Why Do Smart Contracts Self-Destruct? Investigating the Selfdestruct Function on Ethereum,” a recent publication that really digs into self-destruct mechanisms. The selfdestruct
command stands out in the general immutability of the blockchain: selfdestruct
renders inoperable a smart contract. A motivating example of why an immutable blockchain needs such a powerful command is reported in this paper:
“The DAO attack continued for several days and the organization even noticed that their contract had been attacked at that time. However, they could not stop the attack or transfer the Ethers because of the immutability feature of smart contracts. If the contract contains a selfdestruct function, the DAO organization can transfer all the Ethers easily, and reduce the financial loss.”
If you want to know more about the DAO attack and its consequences, you can refer to references [2] and [3] at the end of this article.
About the opcode that is generated at the compilation of the selfdestruct
method there is a nice story about the sensibility of the Ethereum community: Originally the opcode was named SUICIDE
but they decided to rename it as SELFDESTRUCT
because
“Suicide is a heavy subject and we should make every effort possible to not affect those in our development community who suffer from depression or who have recently lost someone to suicide.” — EIP6
Below you will find a small toy example that contains the smallest amount of logic to make some tests. It is easily executable using Remix, so you can try it even without installing the development environment.
pragma solidity >0.6.0;contract Storage {
address payable private owner;
uint256 number; constructor() {
owner = msg.sender;
} function store(uint256 num) public {
number = num;
} function retrieve() public view returns (uint256){
return number;
}
function close() public {
selfdestruct(owner);
}
}
Below is what happens after the deployment of the contract. In Remix, each of the methods of the smart contract is easily accessible on the left pane.
The first method to test is store
, which will just store the integer value passed as a parameter in the internal state of the smart contract. The next method to test is retrieve
, which, as the smartest among you might already have figured out, retrieves the value stored beforehand in the internal state. Calling this method before actually storing anything will just return 0
because the variable is zeroed by default.
Invoking the close
method will just execute selfdestruct
without any further notification than what is reported in the next figure, a correctly executed transaction:
From now on, each interaction with the smart contract will be successful but still will not do anything.
This is, in a way, an inconsistency: The client that invokes the smart contract is not aware of the fact that the smart contract has been destroyed. For instance, in this particular smart contract, calling the retrieve
method before and after the selfdestruct
will return no error, and in the particular case where the internal variable contains 0
, the two calls are indistinguishable (see the following figure).
The wrap up is, selfdestruct
is designed to be the extrema ratio for a malfunctioning contract. It is the emergency button, the SCRAM of your smart contract. Still, before calling it, consider adding additional logic to, for example, pass control to another smart contract.
As a further reading, I strongly suggest reference [1], below.
References
- Jiachi Chen, Xin Xia, David Lo, and John Grundy. 2016. “Why Do Smart Contracts Self-Destruct? Investigating the Selfdestruct Function on Ethereum” (January 2016), 27 pages
- https://en.wikipedia.org/wiki/The_DAO_(organization)
- https://www.coindesk.com/understanding-dao-hack-journalists