26. 删除合约:selfdestruct
selfdestruct
命令可以用来删除智能合约,并将该合约剩余ETH
转到指定地址。selfdestruct
是为了应对合约出错的极端情况而设计的。它最早被命名为suicide
(自杀),但是这个词太敏感。为了保护抑郁的程序员,改名为selfdestruct
。
selfdestruct
是智能合约的紧急按钮,销毁合约并将剩余ETH
转移到指定账户。当著名的The DAO
攻击发生时,以太坊的创始人们一定后悔过没有在合约里加入selfdestruct
来停止黑客的攻击吧。
如何使用selfdestruct
selfdestruct
使用起来非常简单:
selfdestruct(_addr);
其中_addr
是接收合约中剩余ETH
的地址。
例子:
contract DeleteContract {
uint public value = 10;
constructor() payable {}
receive() external payable {}
function deleteContract() external {
// 调用selfdestruct销毁合约,并把剩余的ETH转给msg.sender
selfdestruct(payable(msg.sender));
}
function getBalance() external view returns(uint balance){
balance = address(this).balance;
}
}
在DeleteContract
合约中,我们写了一个public
状态变量value
,两个函数:getBalance()
用于获取合约ETH
余额,deleteContract()
用于自毁合约,并把ETH
转入给发起人。
部署好合约后,我们向DeleteContract
合约转入1 ETH
。这时,getBalance()
会返回1 ETH
,value
变量是10。
当我们调用deleteContract()
函数,合约将自毁,所有变量都清空,此时value
变为默认值0
,getBalance()
也返回空值。
注意事项:
- 对外提供合约销毁接口时,最好设置为只有合约所有者可以调用,可以使用函数修饰符
onlyOwner
进行函数声明。 - 当合约被销毁后与智能合约的交互也能成功,并且返回0。
- 当合约中有
selfdestruct
功能时常常会带来安全问题和信任问题,合约中的Selfdestruct功能会为攻击者打开攻击向量(例如使用selfdestruct
向一个合约频繁转入token进行攻击,这将大大节省了GAS的费用,虽然很少人这么做),此外,此功能还会降低用户对合约的信心。
在remix上验证
- 部署合约并且转入1ETH,查看合约状态
- 销毁合约,查看合约状态
从测试中观察合约状态可以发现合约销毁后的ETH返回给了指定的地址,并且在合约销毁后依然可以请求交互,所以我们不能根据这个来判断合约是否已经销毁。
习题:
- 不是所有合约创建时都必须包含“删除合约”的命令。
- 假设在合约中定义:
uint public value = 10;
则删除合约后,读取value的结果为:0 - 删除合约时,可以将合约中剩余的ETH发送出去,而不是合约中任意数量的ETH。
- 删除合约时,不是只可以将合约中的ETH发送到合约创建者的地址,指定一个地址即可。