WTF-Solidity 合约删除指南:selfdestruct 从基础用法到 EIP-6780 语义变迁
【免费下载链接】WTF-Solidity WTF Solidity 极简入门教程,供小白们使用。Now supports English! 官网: https://wtf.academy 项目地址: https://gitcode.com/GitHub_Trending/wt/WTF-Solidity
selfdestruct(自毁)是 Solidity 中唯一能真正“删除”智能合约的操作码,它同时会把合约内剩余的 ETH 强制转入指定地址,常被视为智能合约的“紧急停止按钮”。本文以 WTF-Solidity 教程第 26 讲的日文版文档 Languages/ja/26_DeleteContract_ja/readme.md 为骨架,结合仓库中 DeleteContract.sol 与 DeployContract.sol 两个可运行示例,系统讲解 selfdestruct 的语法、Cancun(坎昆)升级前后行为差异,以及编写安全的自毁逻辑时需要注意的陷阱。读完本文,你将掌握 selfdestruct 的完整用法,理解 EIP-6049 与 EIP-6780 对其语义的影响,并能亲手在 Remix 中复现“删除合约”与“同笔交易内创建-自毁”两种验证流程。
selfdestruct 是什么
selfdestruct 命令用于删除智能合约,并将该合约中剩余的 ETH 转移到指定地址。它最初被设计用来应对合约出现无法挽回的错误的极端情况,相当于合约的“紧急制动”:
selfdestruct(_addr);
其中 _addr 是接收合约剩余 ETH 的目标地址。一个容易被忽略的细节是:_addr 地址不需要拥有 receive() 或 fallback() 函数也能接收 ETH——selfdestruct 的转账是强制性的,不存在调用目标合约代码的逻辑,因此不会像普通转账那样因目标合约拒绝接收而失败。
命名历史:从 suicide 到 selfdestruct
该操作码最早被命名为 suicide(自杀),但由于这个词过于敏感,为了保护抑郁的程序员群体,以太坊社区将其改名为 selfdestruct。在 Solidity v0.8.18 版本中,selfdestruct 关键字被标记为「不再建议使用」(deprecated):它会在某些情况下导致预期之外的合约语义,但由于目前还没有替代方案,Solidity 编译器仅对开发者输出编译阶段警告,相关内容可参见 EIP-6049。
Cancun 升级与 EIP-6780:语义发生了根本性变化
在以太坊坎昆(Cancun)升级中,EIP-6780 被纳入,其初衷是为了对 Verkle Tree 提供更好的支持。EIP-6780 缩减了 SELFDESTRUCT 操作码的功能范围,导致合约删除行为的语义发生根本性变化:
换言之,升级后 SELFDESTRUCT 从一个“删除工具”退化成了一个“强制转账工具”;想要复现旧版的完整删除语义,只能借助另一个合约在单笔交易内完成 new 创建与 selfdestruct 调用。
Demo 1:DeleteContract——转移 ETH 与(升级前)自毁
仓库中的 DeleteContract.sol(中文版位于 26_DeleteContract/DeleteContract.sol)完整演示了这一用法,合约声明 pragma solidity ^0.8.34;,与仓库根目录 foundry.toml 中统一指定的 solc = "0.8.34" 编译器版本一致:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.34;
// selfdestruct: 删除合约,并强制将合约剩余的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;
}
}
合约包含三个关键部分:
- uint public value = 10;:公开状态变量,用于验证自毁后存储是否被清除。
- constructor() payable {} 与 receive() external payable {}:分别让合约在部署时和部署后都能接收 ETH。
- deleteContract():调用 selfdestruct(payable(msg.sender)),把合约内所有 ETH 转给调用者。
- getBalance():返回 address(this).balance,用于观察合约当前 ETH 余额。
操作流程与预期结果
- 坎昆升级前:合约会被彻底自毁,1 ETH 转回调用者地址,之后再调用合约函数交互会失败。
- 坎昆升级后:合约依然存在、依然可以被调用,只是其内部 ETH 余额被转移到指定地址(归零),value 等存储也不会被清除。
Remix 验证:升级前与升级后的差异
坎昆升级之前
部署合约并转入 1 ETH,查看合约状态:

调用 deleteContract() 销毁合约,再次查看合约状态:

测试中观察合约状态可以发现:销毁后 ETH 已返还给指定地址,且再次调用合约函数进行交互会失败——这正是旧版 SELFDESTRUCT 的完整删除语义。
坎昆升级之后
部署合约并转入 1 ETH,查看合约状态:

调用 deleteContract() 销毁合约,再次查看合约状态:

升级后的测试结果截然不同:合约包含的 ETH 已经清零(返还给指定地址),但再次调用合约函数交互依然可以成功。这正是 EIP-6780 生效的直接体现。
Demo 2:同笔交易内实现“合约创建-自毁”
根据 EIP-6780 提案,旧版的删除功能只有在「合约创建-自毁」这两个操作处于同一笔交易时才能生效,因此需要借助另一个合约进行控制。仓库中的 DeployContract.sol(中文版位于 26_DeleteContract/DeployContract.sol)演示了这种做法:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.34;
import "./DeleteContract.sol";
contract DeployContract {
struct DemoResult {
address addr;
uint balance;
uint value;
}
constructor() payable {}
function getBalance() external view returns(uint balance){
balance = address(this).balance;
}
function demo() public payable returns (DemoResult memory){
DeleteContract del = new DeleteContract{value:msg.value}();
DemoResult memory res = DemoResult({
addr: address(del),
balance: del.getBalance(),
value: del.value()
});
del.deleteContract();
return res;
}
}
demo() 函数在同一笔交易内依次完成以下步骤:
由于创建与自毁发生在同一笔交易内,即使坎昆升级之后,DeleteContract 也能被真正删除,其 ETH 会转移到创建它的 DeployContract。
Remix 验证
部署 DeployContract 合约,转入 1 ETH 并调用 demo() 方法,查看返回的合约状态,可确认 DeleteContract 已被正确部署,且 selfdestruct 后 ETH 已转移到 DeployContract:

将返回值中的 addr 地址作为 DeleteContract 导入 Remix,可以观察到该地址不存有 ETH,且调用其合约函数交互均失败:

注意事项:安全与信任问题
在合约中引入 selfdestruct 功能时,需要格外谨慎:
总结
selfdestruct 是智能合约的“紧急按钮”:销毁合约并将剩余 ETH 转移到指定账户。当年著名的 The DAO 攻击发生时,以太坊的创始人们或许后悔过没有在合约中加入 selfdestruct 来停止黑客的攻击。而在坎昆升级(EIP-6780)之后,selfdestruct 的作用已经逐渐发生改变——从“删除合约”退化为“强制转账”,原本的删除能力只有在单笔交易内“创建-自毁”时才能保留。技术在不断演进,什么都不是一成不变的,持续学习才是应对变化的最好方式。
【免费下载链接】WTF-Solidity WTF Solidity 极简入门教程,供小白们使用。Now supports English! 官网: https://wtf.academy 项目地址: https://gitcode.com/GitHub_Trending/wt/WTF-Solidity
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



