EIP-7761: EXTCODETYPE 指令
向 EOF 添加 EXTCODETYPE 指令,以解决 EXTCODE* 指令的常见用途
Authors | Andrei Maiboroda (@gumb0), Piotr Dobaczewski (@pdobacz), Danno Ferrin (@shemnon) |
---|---|
Created | 2024-09-01 |
Requires | EIP-3540, EIP-7692 |
Table of Contents
摘要
通过引入 EXTCODETYPE
指令,允许 EOF 合约区分 EOAs(外部所有账户)和合约账户。
动机
如 EIP-7692 中所述,EOFv1 移除了 EVM 的代码自省功能,包括 EXTCODESIZE
指令(在 EIP-3540 中)。这使得 ERC-721 和 ERC-1155 标准合约难以实现,因为它们依赖于发现 Token 的 safeTransfer
调用目标是 EOA 还是合约账户:
- 对 EOA 的
safeTransfers
成功 - 对合约账户的
safeTransfers
调用它们的onERC721Received
(onERC1155Received
),并期望得到一个特殊的魔法返回值,否则转移会回滚(假设这样的接收者可能无法与 Token 交互)
应用程序和库的开发者也担心用 EOF 编写的动态代理会意外地指向无法使用 EXTDELEGATECALL
安全调用的旧账户。他们希望有一种方法来区分 EOF 合约和旧合约。
EXTCODETYPE
旨在填补这一空白,并重新实现用 EOF 轻松实现 ERC-721 和 ERC-1155 标准合约的可能性,并保持 EOF 代理合约的安全性。
规范
参数
Constant | Value |
---|---|
FORK_BLKNUM |
待定 |
GAS_COLD_ACCOUNT_ACCESS |
在 [Ethereum Execution Layer Spec Constants] 中定义为 2600 |
GAS_WARM_ACCESS |
在 [Ethereum Execution Layer Spec Constants] 中定义为 100 |
TYPE_NONE |
0 |
TYPE_LEGACY_CONTRACT |
1 |
TYPE_EOF_CONTRACT |
2 |
我们在区块号 FORK_BLKNUM
上引入一个新的 EOFv1 指令:EXTCODETYPE
(0xe9
)
在 FORK_BLKNUM
之前包含此指令的 EOF 代码被认为是无效的。从区块 FORK_BLKNUM
开始,0xe9
被添加到有效 EOFv1 指令集中。
执行语义
EXTCODETYPE
- 扣除
GAS_WARM_ACCESS
gas - 从堆栈中弹出 1 个参数
target_address
- 如果
target_address
的任何高 12 字节设置为非零值(即,它不包含 20 字节的地址),则停止并出现异常失败- 注意:EVM 地址空间的未来扩展可能会删除或减少此检查中的字节数。
- 如果
target_address
不在accessed_addresses
中,则扣除GAS_COLD_ACCOUNT_ACCESS - GAS_WARM_ACCESS
并将target_address
添加到accessed_addresses
- 从
target_address
加载代码并将其称为loaded_code
- 如果
loaded_code
为空(不存在或长度为零),则将TYPE_NONE
推送到堆栈上并停止处理该操作 - 如果
loaded_code
指示一个委托指示符(例如,如 EIP-7702 中定义的0xef0100
),- 将
loaded_code
替换为委托的代码。 - 根据委托指定规则扣除 gas
- 将
- 如果
loaded_code
指示一个 EOFv1 打包合约(以字节0xef0001
开头),则将TYPE_EOF_CONTRACT
推送到堆栈上并停止处理该操作 - 否则,将
TYPE_LEGACY_CONTRACT
推送到堆栈上并停止处理该操作
注意:如果没有足够的 gas 用于委托指定,则整个消息帧将停止,从而使得更新 accessed_addresses
无关紧要。
注意:如果 target_address
或委托指示符指向一个正在创建中的合约账户,则代码为空并返回 0
(TYPE_NONE
)。这与 EXTCODESIZE
等指令的类似行为一致。
原理
替代解决方案
已经提出了其他解决方案来缓解与 ERC-721 和 ERC-1155 标准所需的代码自省不足相关的问题:
EXT*CALL
指令的额外状态代码 - 允许区分来自调用 EOA 的结果EXT*CALL
的额外参数(“如果 EOA 则故障”标志)- 来自
EXT*CALL
的两个返回值(状态代码 + 它是否是 EOA) EXT*CALL
设置一个新的callstatus
寄存器(+ 一个新的CALLSTATUS
指令)- 重新启用 EOF 中的
EXTCODESIZE
,保持其行为与旧版本相同
EXTCODETYPE
已被选为最优雅和最小的解决方案,既满足了手头的要求,又能在 EOFv1 中引入。
重用 0x3b
(EXTCODESIZE
) 操作码作为 EXTCODETYPE
通常的策略是首选新操作码,而不是重用操作码。如果需要,EXTCODETYPE
也可以在旧版 EVM 中推出。
禁止代码自省
删除代码自省是 EOF 的原则之一,而 EXTCODETYPE
将是该原则的一个例外。如果没有 EXTCODETYPE
,ERC-721 和 ERC-1155 标准的实现必须采取以下任一方式:
- 利用一个“助推合约”,它将是旧版本,并将为它们调用
EXTCODESIZE
。从库实现者的角度来看,这被认为是不优雅和不方便的,需要他们硬编码此类合约的地址(在不同的 EVM 链上出现通常与地址相关的问题) - 继续使用旧版 EVM 本身。这是不理想的,因为 EVM 编译器很可能会在某个时候弃用旧版 EVM 作为编译目标
- 更新标准,使其不再依赖于
safeTransfer
保护中的代码自省模式。例如,可以通过利用 ERC-165 来完成此操作,仅留下那些未实现 ERC-165 并且同时具有非抛出回退函数的合约,因为它们与 EOA 无法区分。这不容易实现,因为 ERC-721 和 ERC-1155 是最终的并且已在实践中采用。
“终局账户抽象”问题
有人声称 EXTCODETYPE
(以及旧版 EVM 中提供的早期 EXTCODESIZE
)会减慢 AA 的采用,因为它们鼓励区分智能合约和 EOA 账户的模式,例如不允许前者进行交互。但是,也有相反的论点认为,是其他因素减慢了 AA 的采用(假设账户可以生成 ECDSA 签名,以及智能合约签名缺乏采用)。
包括针对代理变砖的保护
除了 ERC-721 / ERC-1155 问题之外,另一个潜在风险也引起了人们的关注。由于 EOFv1 禁止将 EXTDELEGATECALL
定向到旧版合约,因此存在 EOF 代理合约意外将其实现升级到旧版 EVM 合约的情况。由于撤消此操作或再次升级(使用当前的代理标准)需要调用实现合约,因此实际上会使合约无法使用。
因此,决定使用广义的 EXTCODETYPE
指令而不是 HASCODE
指令。这提供了针对此类情况进行保护的方法,而更简单的指令无法做到这一点。
与 EIP-7702“设置 EOA 账户代码”的关系
在 EIP-7702 激活后,使用 EXTCODESIZE
(或 EXTCODETYPE
)区分 EOA 和合约账户存在一个边缘情况:每当 EOA 将其代码设置为一个未按预期响应 onERC721Received
(onERC1155Received
) 回调的合约账户时,对它的转移将回滚,尽管接收者能够与 Token 交互。这被认为不太可能成为问题,因为对于 EIP-7702 的预期实际用途,这些回调将由设计器代码实现。
由于需要 EOF 代理合约能够确定新目标是否安全,因此我们无法返回一个用于指示账户本身已委托的值,而不同时提供委托地址。相反,我们返回具有委托代码的账户的代码,应用委托。这是因为可执行代码对于代理更新至关重要。
这与 EXTCODECOPY
和 EXTCODEHASH
的行为不同,后者确实返回一个哈希和一个指示代理的简短代码。EXTCODETYPE
的行为更接近于“代码执行操作”,因为它旨在描述账户的执行行为。
向后兼容性
EXTCODETYPE
在 0xe9
处可以以向后兼容的方式引入到 EOFv1 中(无需升级版本),因为 0xe9
在 FORK_BLKNUM
之前已经被 EOF 验证拒绝,并且链上没有 EOF 合约的 0xe9
会改变其行为。
安全考虑
需要讨论
版权
在 CC0 下放弃版权及相关权利
[Ethereum Execution Layer Spec Constants] :https://github.com/ethereum/execution-specs/blob/1adcc1bfe774798bcacc685aebc17bd9935078c3/src/ethereum/cancun/vm/gas.py#L65-L66
Citation
Please cite this document as:
Andrei Maiboroda (@gumb0), Piotr Dobaczewski (@pdobacz), Danno Ferrin (@shemnon), "EIP-7761: EXTCODETYPE 指令 [DRAFT]," Ethereum Improvement Proposals, no. 7761, September 2024. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-7761.