Alert Source Discuss
⚠️ Review Standards Track: Core

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

摘要

通过引入 EXTCODETYPE 指令,允许 EOF 合约区分 EOAs(外部所有账户)和合约账户。

动机

EIP-7692 中所述,EOFv1 移除了 EVM 的代码自省功能,包括 EXTCODESIZE 指令(在 EIP-3540 中)。这使得 ERC-721ERC-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 标准所需的代码自省不足相关的问题:

  1. EXT*CALL 指令的额外状态代码 - 允许区分来自调用 EOA 的结果
  2. EXT*CALL 的额外参数(“如果 EOA 则故障”标志)
  3. 来自 EXT*CALL 的两个返回值(状态代码 + 它是否是 EOA)
  4. EXT*CALL 设置一个新的 callstatus 寄存器(+ 一个新的 CALLSTATUS 指令)
  5. 重新启用 EOF 中的 EXTCODESIZE,保持其行为与旧版本相同

EXTCODETYPE 已被选为最优雅和最小的解决方案,既满足了手头的要求,又能在 EOFv1 中引入。

重用 0x3b (EXTCODESIZE) 操作码作为 EXTCODETYPE

通常的策略是首选新操作码,而不是重用操作码。如果需要,EXTCODETYPE 也可以在旧版 EVM 中推出。

禁止代码自省

删除代码自省是 EOF 的原则之一,而 EXTCODETYPE 将是该原则的一个例外。如果没有 EXTCODETYPE,ERC-721 和 ERC-1155 标准的实现必须采取以下任一方式:

  1. 利用一个“助推合约”,它将是旧版本,并将为它们调用 EXTCODESIZE。从库实现者的角度来看,这被认为是不优雅和不方便的,需要他们硬编码此类合约的地址(在不同的 EVM 链上出现通常与地址相关的问题)
  2. 继续使用旧版 EVM 本身。这是不理想的,因为 EVM 编译器很可能会在某个时候弃用旧版 EVM 作为编译目标
  3. 更新标准,使其不再依赖于 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 代理合约能够确定新目标是否安全,因此我们无法返回一个用于指示账户本身已委托的值,而不同时提供委托地址。相反,我们返回具有委托代码的账户的代码,应用委托。这是因为可执行代码对于代理更新至关重要。

这与 EXTCODECOPYEXTCODEHASH 的行为不同,后者确实返回一个哈希和一个指示代理的简短代码。EXTCODETYPE 的行为更接近于“代码执行操作”,因为它旨在描述账户的执行行为。

向后兼容性

EXTCODETYPE0xe9 处可以以向后兼容的方式引入到 EOFv1 中(无需升级版本),因为 0xe9FORK_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.