(1)可以被安全地销毁。GasToken 的开发者已经发出了警告 “虽然对以太坊网络的变更会导致 GasToken 无法使用、不可赎回、不能互换以及/或毫无价值,但是 GasToken 的开发者极可能会拥护该变更”。移除 selfdestruct 退款只会导致有些操作的费用变得更贵(2 倍以上)。 从长远来看,(2)是没必要的,还有其他一些被广泛使用的范式可用于支持动态代码变更。最容易实现的是 DELEGATECALL 转发器,合约从一个存储插槽中获取一个代码地址,然后调用对应地址的代码;修改这个存储插槽就能更新代码。不过,从短期来看,有少数应用已经使用了(2)。 提案 1:完全移除 SELFDESTRUCT 从某个区块(用 FLAG_BLOCK 表示,比如取 PoW 链与信标链合并发生的那个区块)开始,完全停用 SELFDESTRUCT 。在这个及之后的区块里,如果 EVM 在执行时遇到 0xff 操作码,只要抛出异常直接退出即可,就像 EVM 执行时遇到不存在的操作码一样。 在完全停用前,为了警示用户避免使用 SELFDESTRUCT ,我们可以渐进式地增加其 gas 费用:如果 block.number + 10**6 >= FLAG_BLOCK ,则 SELFDESTRUCT 的 gas 费用增加到 10**10 // (FLAG_BLOCK - block.number) 。 提案 2:阉割 SELFDESTRUCT 我们也可以保留这个操作码,但是改变其行为,一方面消除其对状态树的破坏,另一方面增加一个新特性,让合约可以标识为不可自毁(un-self-destructible),从而确保代码不可变。 暂时提议新增的行为包括: 当一个合约调用 SELFDESTRUCT 时,并不会删除合约账户,而是清空代码,并且将 nonce 值增加 2**40 。没有退款。通过调用(转账)将合约中的 ETH 转移到目标地址(要么由父调用提供所需的全部 gas,要么父调用并不提供任何 gas)。可以在代码为空的地址(比如被清空过的)上创建合约。在合约里调用 SSTORE 和 SLOAD 操作地址 A 时,实际操作的是 A_offset = (A + A.nonce // 2**40) % 2**160 的存储树。注意,从 EIP-2929 的角度来看, A_offset 需要 “可达(accessed)”。如果该账户不在可达账户集合中,则需要额外支付 2600 gas 以加入可达集合。 另一种选择是调整将 storage key 转换为 tree key 的哈希函数,用 sha3(storage_key + contract_nonce // 2**40) 代替 sha3(storage_key) 。需要注意的是,无论如何都需要做一些类似的调整,以方便合约级别的无状态 key 空间扩展(expanding-key-space statelessness)。 合约可以在代码中指定 0xA8 作为第一个字节,EVM 会将其识别为无操作,但使用它来开启一个标志,在执行过程中完全禁用 SELFDESTRUCT 的功能(注意:这与 SET_INDESTRUCTIBLE 提案是一样的)。 这两种解决方案也可以结合起来:当前立即阉割,将来完全移除。或者,这个操作码也可以永远不被完全移除,但是最终只保留一个功能,即向目标地址发送合约当前的全部 ETH 余额,我们可以将这个操作码重命名为 CLEAR 。 (责任编辑:admin) |