EIP-6913: SETCODE 指令
用于原地替换代码的新指令
Authors | William Morriss (@wjmelements) |
---|---|
Created | 2023-04-20 |
Discussion Link | https://ethereum-magicians.org/t/eip-6913-setcode-instruction/13898 |
摘要
引入 SETCODE
(0xfc
) 指令,该指令从内存中替换正在执行的帐户的代码。
动机
许多合约都是可升级的,以便于改进或推迟决策,而无需迁移到新地址。 目前,合约通过以下几种方式实现这一点:
最古老的方法是使用 CALL
。
这种方法的局限性在于,内部状态必须可由所有未来的实现修改。
其次,DELEGATECALL
可以代理实现。
一些代理是最小化的,而另一些则分支到许多单独的实现帐户。
此方法还可以绕过帐户代码大小限制。
第三种方法是使用 SELFDESTRUCT
和 CREATE2
原地替换代码。
此方法通过消除调用外部合约的需要而改进了先前的方法。
此方法的一个限制是任何内部状态都会被 SELFDESTRUCT
删除。
另一个限制是 SELFDESTRUCT
不会删除代码,直到交易结束,从而牺牲了可用性,直到 CREATE2
可以完成升级。
鉴于即将弃用 SELFDESTRUCT
,SETCODE
引入了一种原地替换代码的更好方法。
规范
当在只读执行范围内(例如由 STATICCALL
创建的递归类型),SETCODE
会导致异常中止。
当当前执行的代码不等于正在执行的帐户的代码时,例如在 DELEGATECALL
或 CREATE
内部发生时,SETCODE
会导致异常中止。
否则,SETCODE
从堆栈中消耗两个字:偏移量和长度。
这些指定了包含新代码的内存范围。
将对 CREATE
或 CREATE2
的结果执行的任何验证都会立即发生,可能会因异常中止而导致失败。
现在,EXTCODESIZE
和 EXTCODECOPY
操作查询更新后的代码,并且诸如 DELEGATECALL
、CALLCODE
、CALL
和 STATICCALL
之类的消息调用现在执行更新后的代码。
任何已经执行替换代码的执行范围(包括 SETCODE
的执行范围)将继续执行先前的代码。
在此类范围内,CODESIZE
和 CODECOPY
继续查询正在执行的代码。
与 SSTORE
类似,如果当前范围或任何父范围恢复或中止,则此帐户修改将被恢复。
与 SELFDESTRUCT
不同,SETCODE
不会清除帐户余额、nonce 或存储。
Gas
此操作的 gas 成本是 Gselfdestruct
与 Gcodedeposit
和新代码中的字节数的乘积之和。
理由
CODECOPY
、CODESIZE
、EXTCODESIZE
和 EXTCODECOPY
的行为与 DELEGATECALL
和 CREATE
的行为相匹配,在这些情况下,执行代码也可能与执行帐户的代码不同。
SETCODE
的 gas 成本与 CREATE
相当,但不包括 Gcreate
,因为没有创建执行上下文,也没有创建任何新帐户。
其他帐户修改成本在执行 gas 之外计算。
与 SELFDESTRUCT
不同,在 SETCODE
之后,执行会正常进行,以便允许验证和返回数据。
更新后验证可以使用 REVERT
或使用递归 SETCODE
撤消 SETCODE
操作,但 REVERT
使用的 gas 更少。
阻止在大多数 DELEGATECALL
中使用 SETCODE
允许静态分析轻松识别可变代码。
可以安全地假定不包含 SETCODE
操作的帐户代码是不可变的。
在非恢复上下文中观察到的不可变代码将保持不可变,从而允许链上静态分析以实现不变性。
向后兼容性
唯一先前的更改代码的操作是 SELFDESTRUCT
。
由于通过 SELFDESTRUCT
进行的代码修改会推迟到交易结束,因此它与 SETCODE
的交互是明确定义的。
测试用例
CodeStart | CallData | CodeResult | Gas |
---|---|---|---|
365f5f37365ffc00 | 365f5f37365ffc00 | 365f5f37365ffc00 | 6613 |
365f5f37365ffc00 | 00 | 00 | 5213 |
365f5f37365ffc00 | 5013 | ||
365f5f37365ffc595ffd | 365f5f37365ffc00 | 365f5f37365ffc595ffd | 6617 |
365f5f37365ffcfe | 365f5f37365ffc00 | 365f5f37365ffcfe | all |
安全考虑
与 SETCODE
相关的风险同样适用于其他升级模式。
大多数合约不应被替换,也不应是可升级的。 任何升级机制都可能导致永久性故障。 升级的可能性会使这种风险长期存在。
对升级操作的访问应受到限制。 切勿匆忙或在疲倦时执行升级。 应在尽可能接近生产的条件下测试升级;差异是出现意外结果的根源。 如果可能,多个工程师应预览并独立验证待处理的升级程序。
区块浏览器、钱包和其他界面应标记可升级的代码。 客户端软件应警告不要批准可升级帐户的 ERC-20 或 ERC-721 代币。
版权
在 CC0 下放弃版权及相关权利。
Citation
Please cite this document as:
William Morriss (@wjmelements), "EIP-6913: SETCODE 指令 [DRAFT]," Ethereum Improvement Proposals, no. 6913, April 2023. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-6913.