EIP-6189: 别名合约
允许创建将调用转发到其他合约的合约
Authors | Gavin John (@Pandapip1) |
---|---|
Created | 2022-12-20 |
Discussion Link | https://ethereum-magicians.org/t/eip-6190-functional-selfdestruct/12232 |
Requires | EIP-2929, EIP-6188 |
摘要
本 EIP 允许使用一个魔法 nonce 将合约转换为“别名合约”。别名合约会自动将调用转发到其他合约。
动机
本 EIP 本身并不是非常有用,因为它增加了额外的计算和 gas 成本,而没有任何有用的副作用。但是,与 EIP-6190 结合使用,它可以用于使 SELFDESTRUCT 与 Verkle 树兼容。
规范
本文档中使用的关键词“MUST”,“MUST NOT”,“REQUIRED”,“SHALL”,“SHALL NOT”,“SHOULD”,“SHOULD NOT”,“RECOMMENDED”,“MAY”和“OPTIONAL”应按照 RFC 2119 和 RFC 8174 中的描述进行解释。
定义
如果一个合约的 nonce 为 2^64-1
,并且其合约代码等于 0x1
,则该合约为别名合约。
前提条件
必须使用 EIP-6188 来保护魔法 nonce 值 2^64-1
。
操作码变更
CALL
, CALLCODE
, DELEGATECALL
, STATICCALL
, PAY
和 EOA 交易
“callee”指的是被调用或被支付的帐户。
如果 callee 的 nonce 是 2^64-1
,则调用必须被转发到存储在 callee 的第 0
个存储槽中的地址(就像 callee 是存储在 callee 的第 0
个存储槽中的地址一样)。这必须重复,直到到达非别名合约。CALLER
必须保持不变。
如果链中有多个别名合约,则原始 callee 和所有后续 callees(除了最后一个)必须将其第 0
个存储槽设置为最终非别名合约的地址。然后,调用必须像往常一样转发。即使在像 STATICCALL
这样的只读上下文中,也必须发生这种情况。
例如,如果 A
是一个将调用转发到 B
的别名合约,而 B
是一个将调用转发到 C
的别名合约,那么 A
的第 0
个存储槽将被设置为 C
的地址。然后,调用将被转发到 C
。
最后,操作码必须像往常一样进行,使用最终的非别名合约。
CALL
、CALLCODE
、DELEGATECALL
和 STATICCALL
操作码和 EOA 交易必须为此类访问的每个帐户(包括最后一个帐户,以及是否未使用别名帐户)花费 25
gas,此外还要加上访问帐户所产生的所有常规成本(参见 EIP-2929)。对于每个更新了第 0
个存储槽的账户,这些操作码还必须花费额外的 5000
gas。
如果发生无限循环,则交易必须耗尽 gas 并回滚。
EXTCODEHASH
, EXTCODECOPY
, EXTCODESIZE
和 BALANCE
“访问的帐户”指的是正在访问的帐户(即,正在访问其代码的帐户,或者正在访问其余额的帐户)。
与 CALL
系列操作码类似,如果被访问的帐户的 nonce 为 2^64-1
,则被访问的帐户的地址必须替换为存储在被访问的帐户的第 0
个存储槽中的地址。这必须重复,直到到达非别名合约。
如果链中有多个别名合约,则原始被访问的帐户和所有后续被访问的帐户(除了最后一个)必须将其第 0
个存储槽设置为最终非别名合约的地址。然后,必须像往常一样替换被访问的帐户。即使在像 STATICCALL
这样的只读上下文中,也必须发生这种情况。
最后,操作码必须像往常一样进行,使用最终的非别名合约。
EXTCODEHASH
、EXTCODECOPY
、EXTCODESIZE
和 BALANCE
操作码必须为此类访问的每个帐户(包括最后一个帐户,以及是否未使用别名帐户)花费 25
gas,此外还要加上访问帐户所产生的所有常规成本(参见 EIP-2929)。对于每个更新了第 0
个存储槽的账户,这些操作码还必须花费额外的 5000
gas。
如果发生无限循环,则交易必须耗尽 gas 并回滚。
CREATE
和 CREATE2
如果 CREATE
或 CREATE2
将在某个地址创建一个帐户(或未能创建,取决于使用的 EIP),并且该帐户的代码是 0x1
,并且其 nonce 是 2^64-1
,那么不是回滚,而是必须尝试在现有帐户的第 0
个存储槽中存储的地址处创建一个合约。这必须重复,直到到达非别名合约。
如果链中有多个别名合约,则原始被访问的帐户和所有后续被访问的帐户(除了最后一个)必须将其第 0
个存储槽设置为最终非别名合约的地址。
最后,操作码必须像往常一样进行,返回新创建的合约的地址。
CREATE
和 CREATE2
操作码必须为此类访问的每个帐户(包括最后一个帐户,以及是否未使用别名帐户)花费 25
gas,此外还要加上访问帐户所产生的所有常规成本(参见 EIP-2929)。对于每个更新了第 0
个存储槽的账户,这些操作码还必须花费额外的 5000
gas。
如果发生无限循环,则交易将耗尽 gas 并回滚。
ADDRESS
此操作码保持不变;ADDRESS
指向没有 nonce 为 2^64-1
的地址。
转移到零地址
转移到零地址继续具有与 CREATE
操作码相同的效果,并且将花费额外的 gas,如 CREATE
和 CREATE2
部分中所讨论的那样。
交易有效性
“origin”指的是将交易发送以进行验证的帐户。
如果 origin 的 nonce 是 2^64-1
,则必须将 origin 更新为存储在当前 origin 的第 0
个存储槽中的地址(就像 origin 是存储在当前 origin 的第 0
个存储槽中的地址一样)。这必须重复,直到到达非别名合约。
如果链中有多个别名合约,则原始 origin 和所有后续 origins(除了最后一个)必须将其第 0
个存储槽设置为最终非别名合约的地址。然后,必须像往常一样转发调用。
为此类访问的每个帐户(包括最后一个帐户,以及是否未使用别名帐户)额外添加 25
gas,此外还要加上访问帐户所产生的所有常规成本(参见 EIP-2929)被添加到验证成本中。对于每个更新了第 0
个存储槽的账户,它还会花费额外的 5000
gas。
最后,验证照常进行。
RPC 端点变更
eth_getStorageAt
如果目标合约的合约代码为 0x1
且 nonce 为 2^64-1
,则 eth_getStorageAt
RPC 端点必须出错。
理由
25
的额外 gas 成本表示获取 nonce 并将其与给定值进行比较的成本。
修改了 eth_getStorageAt
以抛出错误,因为别名合约的特殊行为。
选择 nonce 2^64-1
是因为它是由 EIP-6188 保护的 nonce。
合约代码 0x1
是任意选择的。选择非零代码是为了防止 nonce 为 2^64-1
的非别名合约以某种方式将其代码设置为 0x0
,或者 EOA 将其 nonce 设置为 2^64-1
。
向后兼容性
此 EIP 需要一个协议升级,因为它修改了共识规则。不应影响任何现有合约,因为它们不会具有 2^64-1
的 nonce,也不会具有合约代码 0x1
。
安全注意事项
如果额外的 gas 成本访问任意合约的数据或频繁停用合约,则可能导致潜在的 DoS 攻击。合约作者必须注意并相应地设计合约。可能会对执行自主销毁和复兴的现有已部署代码产生影响。
版权
在 CC0 下放弃版权及相关权利。
Citation
Please cite this document as:
Gavin John (@Pandapip1), "EIP-6189: 别名合约 [DRAFT]," Ethereum Improvement Proposals, no. 6189, December 2022. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-6189.