删不动的存储,改主意的方式
SELFDESTRUCT 的原始语义是清空账户:余额转走、存储全部抹掉、代码消失。麻烦从 Verkle 树开始——新状态结构里没法再像旧 Merkle 树那样遍历一个账户的全部存储键,“删掉所有键”这件事从顺手变成昂贵甚至做不干净。多数提案于是给自毁加清扫义务,比如用专门的清理机制把残留逐条抹掉,见 自毁合约留下的存储,谁来清:EIP-2936 与它的操作码之争。2022 年 11 月 25 日提交的 EIP-6046 走了完全相反的方向:干脆一个键都不删,把”销毁”重新定义成”停用”,指令名字也一并改成 DEACTIVATE。

规格:一块用 nonce 刻的墓碑
按提案,改完之后 SELFDESTRUCT/DEACTIVATE 的执行效果变成四件事:不删任何存储键,账户原地保留;余额全额转给目标地址;把账户 nonce 设为 2 的 64 次方减 1;照 EIP-3529 之后的规矩没有任何退款。为了让这个顶格值真正可用,提案同时把常规 nonce 递增的上限从 2 的 64 次方减 1 压到减 2(追溯自创世生效),这直接改写了 EIP-2681 的既有钳位线——顶格值从”理论可达但事实上碰不到”变成”专门留给墓碑的记号”。这个预留思路与 EIP-6188 的序号封顶属于同一族设计,见 序号用尽之前:EIP-6188 把 nonce 顶上的两个值留了出来。
调用一个墓碑账户会发生什么
这是全套设计里最微妙的一条:被停用的账户仍然在账本上、仍然有余额入账通道,但任何调用它的外部交易或 CALL 系列指令都会直接执行成功,并返回一段空数据。注意语义组合——成功,但空。它不会像调用不存在账户那样失败,也不会回滚。靠”有没有返回数据""调用是否成功”判断合约活性的代码,会在这里读到一具会点头的尸体。同时规则允许 CREATE2 对墓碑账户重新部署代码,也就是说复活合法存在,但新代码从第一行起就要假设仓库里堆着上辈子留下的旧存储。
复活语义的分量
提案标题把重点放在”改名”上,正在于此:销毁时代结束后,账户回生不再是清理后重建,而是旧物仍在、只换住户。对一个曾经记录用户余额、权限或订单状态的合约尤其危险——停用没有抹掉任何一页账,复活上去的新实现只要漏检一项旧键,就可能把几十年前的遗留状态当成新逻辑的初始状态来读。这正是提案在动机部分强调”新部署的代码必须意识到这一点”的原因:把清理成本从协议里删掉,等于把核对成本转移给每一个复活者。
停在哪、与谁分道
这条路线停在 Stagnant。它与清理派的分歧可以概括成一句话:2936 式的方案问”残留谁来清”,6046 的回答是”残留不清、绕着走”。两条路线都为 Verkle 探路,也都在后续年份里被更新的自毁限制提案(比如禁止在特定条件下自毁、要求先声明销毁意图的路线)边缘化。它依赖的 nonce 钳位改动也从未生效,今天主网上碰不到这套语义。
余额通道为什么还开着
规格里有一句容易一带而过的话:被停用的账户”仍可接收不可执行的转账”,比如出块奖励的 coinbase 发放或其他合约自毁时的余额倾倒。设计者保留这条通道不是仁慈,而是不得不为——协议层的余额入账路径(矿工或验证者收益、自毁转账)并不会先去查收款账户的 nonce 再决定打不打款,强行在这些路径上追加”跳过墓碑账户”的判断,等于把改动扩散到共识各处。接受”墓碑还能收钱”这个副作用,换来的是改动范围被压缩在执行与创建两条规则里。对用户而言的推论很实际:往一个已自毁地址转账在 6046 的世界里不会被拒绝,钱停在一个谁的话都不听的账户里,想取回来只能等一次合法的 CREATE2 复活并且新代码愿意处理旧余额。
给钱包用户的提醒
读这类提案时把住一条线:SELFDESTRUCT 在现实主网上的行为以当前升级的规范为准,任何关于”停用""复活""空返回”的讨论都是提案语境。对钱包与合约交互脚本真正要紧的通用纪律是:永远不要只用”调用成功”判断对方账户的状态,把余额、代码、存储槽存在性一起看。本文只提供技术机制信息,不构成任何投资建议。
发表评论
还没有评论,来说两句吧。
评论区为展示样式,提交不会被处理。