该EIP提议为以太坊的initcode(合约创建代码)引入最大尺寸限制(49152字节)和新的Gas费用(每32字节2个Gas),以更公平地计量合约创建过程中跳跃目标分析(jumpdest-analysis)的成本。此举旨在提高EVM的效率和安全性,并简化客户端实现。
我们通过引入 initcode 的最大大小限制(MAX_INITCODE_SIZE = 2 * MAX_CODE_SIZE = 49152)来扩展 EIP-170。
此外,我们对每 32 字节的 initcode 块收取 2 gas 的费用,以代表 jumpdest-analysis 的成本。
最后,大小限制带来了 EVM 代码大小、代码偏移量(PC)和跳转偏移量适合 16 位值的实用特性。
在合约创建期间,客户端必须在执行前对 initcode 执行 jumpdest-analysis。所执行的工作量与 initcode 的大小呈线性关系。这项工作目前既未被计量,也没有协议强制规定其大小上限。
目前有三种费用:
initcode)的费用:零值字节为 4 gas,其他为 16 gas。CREATE2 情况下,地址计算(代码哈希)的费用:每字 6 gas。只有第一项费用适用于 initcode,但仅限于合约创建交易。对于 CREATE/CREATE2 的情况,没有此类费用,并且可以相对廉价地以编程方式生成 initcode 的变体。过去,由于 geth 1.6.5 在 2017 年修复的一个漏洞,有可能制造恶意的 initcode。
此外,缺乏限制导致了一些 EVM 提案的漫长讨论,影响了设计,甚至导致某个功能的延迟或取消。
我们的动机有三个原因:
initcode 公平收费(最重要的是成本与 initcode 的长度成比例),以最大程度地降低未来的风险。PC)和跳转偏移量适合 16 位)来简化 EVM 引擎。| 常量 | 值 |
|---|---|
INITCODE_WORD_COST |
2 |
MAX_INITCODE_SIZE |
2 * MAX_CODE_SIZE |
其中 MAX_CODE_SIZE 由 EIP-170 定义为 24576。
我们将 initcode_cost(initcode) 定义为等于 INITCODE_WORD_COST * ceil(len(initcode) / 32)。
initcode)长度超过 MAX_INITCODE_SIZE,则交易无效。(注意:这类似于因不满足固有 gas 成本要求而被视为无效的交易。)initcode_cost(initcode)。(注意:这包含在交易固有成本中,即 gas 不足以支付 initcode 成本的交易无效。)CREATE 或 CREATE2 指令的 initcode 长度超过 MAX_INITCODE_SIZE,则指令执行异常中止(如同 gas 耗尽)。CREATE 和 CREATE2 指令,额外收取等于 initcode_cost(initcode) 的 gas 费用。此费用在计算生成的合约地址和执行 initcode 之前扣除。(注意:这意味着在 CREATE2 中应用哈希成本之前或同时。)INITCODE_WORD_COST 的值是根据不同实现的最坏情况性能基准选择的。基准是 geth 1.10.9 中 KECCAK256 哈希的性能,它在 4.0 GHz x86_64 CPU 上符合 70 Mgas/s 的 gas 限制目标。
| EVM | 版本 | MB/s | B/CPUcycle | CPUcycle/B | 1 B 的成本 | 32 B 的成本 |
|---|---|---|---|---|---|---|
| geth/KECCAK256 | 1.10.9 | 357 | 1.8 | 0.6 | 0.2 | 6.0 |
| geth | 1.10.9 | 1091 | 5.5 | 0.2 | 0.1 | 2.0 |
| evmone/Baseline | 0.8.2 | 727 | 3.7 | 0.3 | 0.1 | 2.9 |
| evmone/Advanced | 0.8.2 | 155 | 0.8 | 1.3 | 0.4 | 13.8 |
我们选择每字 2 gas 的成本是基于 Geth 的实现并与 KECCAK256 性能进行比较。这意味着每字节成本为 0.0625。虽然 EVM 不允许分数 gas 成本,但我们可以通过按字收费来近似。
此外,按字计算 gas 与 EIP-1014 中 CREATE2 的 哈希成本 计算兼容。因此,CREATE 和 CREATE2 可以使用相同的实现,但成本常数不同:激活前 CREATE 为 0,CREATE2 为 6;激活后 CREATE 为 2,CREATE2 为 6 + 2。
在有上限的情况下,估计和创建最坏情况场景更容易,因为搜索的一个参数大大减少了。这允许选择更乐观的每字节 gas。
如果不存在上限,则成本需要更高,以应对未知因素。鉴于大多数 initcode(待办:在此处说明主网上看到的导致部署的最大 initcode 大小)不超过建议的限制,通过过于保守的成本来惩罚合约似乎没有必要。
在大多数(如果不是所有)新合约创建的情况下,生成的运行时代码是从 initcode 本身复制的。对于基本情况,2 * MAX_CODE_SIZE 限制允许 MAX_CODE_SIZE 用于运行时代码,另一个 MAX_CODE_SIZE 用于合约构造函数代码。然而,对于在一个创建交易中部署多个合约的情况,该限制可能具有实际影响。
创建交易数据(每字节 0.0625 gas)的 initcode 成本与交易数据成本(每字节 4 或 16 gas)相比可忽略不计。尽管如此,我们决定将其包含在规范中以保持一致性,更重要的是为了向前兼容。
我们规定 CREATE/CREATE2 的 initcode 大小限制违规会导致执行异常中止。这将其归入早期 out-of-gas 检查的组,包括:堆栈下溢、内存扩展、静态调用违规、initcode 哈希成本以及本 EIP 引入的 initcode 成本。它们先于后面的“轻量级”检查:调用深度和余额。这种选择为检查顺序提供了一致性,并降低了实现复杂性(out-of-gas 检查可以按任何顺序执行)。
此 EIP 需要“网络升级”,因为它修改了共识规则。
已部署的合约不应受影响,但某些交易(initcode 超出建议限制的交易)仍可包含在区块中,但会导致异常中止。
测试应包含以下情况:
CREATE/CREATE2/创建交易,其中 len(initcode) 等于 MAX_INITCODE_SIZECREATE/CREATE2/创建交易,其中 len(initcode) 等于 MAX_INITCODE_SIZE+1对于客户端实现,此 EIP 使基于 jumpdest-analysis 的攻击问题减少,因此应提高客户端的鲁棒性。
对于 Layer 2,此 EIP 引入了以前不存在的失败模式。可能存在部署多层合约层次结构的工厂合约,使得多个合约的代码包含在第一个合约的 initcode 中。本 EIP 的作者不了解任何此类合约。
目前,在 London 升级后,如果 gas 限制为 30M,则可能触发总计 ~1.3GB initcode 的 jumpdest-analysis。通过此 EIP,此类攻击的成本将增加约 80M gas。
版权及相关权利通过 CC0 放弃。
- 原文链接: github.com/nerolation/EI...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!