Alert Source Discuss
⚠️ Draft Standards Track: Core

EIP-7907: Meter 合约代码大小和增加限制

增加 EIP-170 中引入的合约代码大小限制,并为代码加载添加 gas 计量

Authors Charles Cooper (@charles-cooper), Qi Zhou (@qizhou)
Created 2025-03-14
Discussion Link https://ethereum-magicians.org/t/eip-remove-contract-size-limit/23156
Requires EIP-170, EIP-2929, EIP-3860

摘要

本 EIP 大幅增加了硬合约代码大小限制,从 EIP-170 中引入的 24KB(24576 字节)增加到 256KB,并增加了 gas 计量。它为超过 24KB 的合约代码引入了每个(32 字节)字 2 gas 的成本,允许部署任何大小的合约,同时通过适当的 gas 计量防止 DoS 攻击。最后,它还相应地将 EIP-3860 中引入的 initcode 大小限制从 48KB 增加到 512KB。

动机

EIP-170 引入了 24KB 的合约代码大小限制,以防止潜在的 DoS 攻击,因为大的合约代码需要在磁盘读取、VM 预处理和 Merkle 证明大小方面花费 O(n) 的资源成本,而所有这些都没有被 gas 费用直接补偿。然而,这个限制限制了大型合约的合法用例。

本 EIP 提出了一种基于 gas 的解决方案,允许更大尺寸的合约,同时确保加载大型合约的用户支付与他们消耗的额外资源成比例的 gas。这种方法符合 Ethereum 的 gas 模型理念,即为消耗的资源付费。新的限制已设置为 256KB,因此提高 gas 限制不会破坏 p2p 层的假设。

提高开发者体验是增加合约大小限制的主要动机。当前 24KB 的上限迫使开发者将功能拆分到多个合约中,引入代理或基于 delegatecall 的间接调用,并依赖于像 Diamond Standard 这样的架构模式——即使这些模式在其他情况下不是必需的。这些解决方法会增加代码复杂性、部署成本和审计范围。通过提高限制,开发者可以将更多逻辑保存在单个合约中,从而提高可读性,并通过避免不必要的跨合约调用来降低 gas 使用量。这也使得智能合约开发对新开发者来说更容易,他们可以从想法到部署,而无需首先学习高级合约组合模式。

规范

本文档中的关键词“必须”,“不得”,“必需”,“应该”,“不应该”,“推荐”,“不推荐”,“可以”和“可选”应按照 RFC 2119RFC 8174 中描述的进行解释。

  1. EIP-170 的合约代码大小限制从 24KB(0x6000 字节)更新为 256KB(0x40000 字节)。
  2. 更改加载代码的操作码的 gas 计划。具体来说,修改操作码 CALLSTATICCALLDELEGATECALLCALLCODEEXTCODECOPY,以便如果代码是冷的,则将 largeContractCost = ceil32(excess_contract_size) * GAS_INIT_CODE_WORD_COST // 32 gas 添加到访问成本,其中 excess_contract_size = max(0, contract_size - 0x6000),并且 GAS_INIT_CODE_WORD_COST = 2。(参见 initcode 计量:EELS)。这为合约代码引入了一种新的 warm 状态 - 如果代码已加载,则为 warm,如果未加载,则为 cold。
合约 Gas 更改(仅加载代码的操作码) 方式?
冷帐户和代码 largeContractCost 添加到 COLD_ACCOUNT_ACCESS_COST=2600 合约不在访问列表中,也未在交易中先前访问过
Warm 帐户,冷代码 largeContractCost 添加到 WARM_STORAGE_READ_COST=100 已经访问了余额、存储,或包含在访问列表中 (EIP-2930)
Warm 帐户和代码 现有 gas 计划没有变化。WARM_STORAGE_READ_COST=100 使用 CREATE/CREATE2 创建的合约,或先前在交易中对该合约进行了 CALLSTATICCALLDELEGATECALLCALLCODEEXTCODECOPY(加载合约代码的操作码)

COLD_ACCOUNT_ACCESS_COSTWARM_STORAGE_READ_COSTEIP-2929 中定义。

  1. EIP-3860 的合约 initcode 大小限制从 48KB(0xc000 字节)更新为 512KB(0x80000 字节)。

理由

每个字的 gas 成本选择为 2,与 EIP-3860 一致。这解释了:

  1. 用于检索更大合约代码的额外磁盘 I/O
  2. 用于预处理较大代码以执行的计算资源增加(即“JUMPDEST 分析”)。
  3. 包含非常大的合约的区块的 Merkle 证明大小的增长

本 EIP 将 gas 成本作为超过 24KB 的合约的额外成本引入。它可以被指定为更简单的 ceil32(contract_size) * 2 // 32,而无需硬编码现有的合约大小限制。然而,为了保守起见,并避免降低加载现有合约的成本(这些合约可能很小,低于 24KB 的限制),将 24KB 的下限添加到公式中。

理论上,EXTCODECOPY 操作码可以免除此限制,因为客户端可以只加载实际请求的字节码部分。然而,这可能需要在协议级别进行更改,因为区块见证需要完整的代码。因此,EXTCODECOPY 包含在定价方案中,并且可以稍后考虑例外情况。

新的限制已设置为 256KB。这比当前区块 gas 限制 35mm(约 170KB)所隐含的限制要大得多。设置此限制是为了增加 gas 限制不会在 db 或 p2p 层产生意外的副作用。例如,在 devp2p 中,最大数据包大小为 10MB(https://github.com/ethereum/devp2p/blob/5713591d0366da78a913a811c7502d9ca91d29a8/caps/eth.md#basic-operation)。在撰写本文时,snap sync 中的最大数据包大小甚至更低,为 512KB。

initcode 的限制也已增加到 512KB,遵循 EIP-3860 中设置的模式,即 initcode 限制是运行时代码限制的两倍。虽然 initcode 与已部署的代码不同,因为它不驻留在状态中,因此在 devp2p 或 db 中不可见,但完全删除该限制可能会产生不可预见的后果。

向后兼容性

本 EIP 与现有合约向后兼容。在本 EIP 之前有效的所有合约,在本 EIP 之后仍然有效,并且它们的 gas 成本不会改变。

唯一的改变是,将允许大于 24KB 的新合约,而以前无论可用 gas 如何,都会拒绝它们。

测试用例

参考实现

安全考虑

客户端应添加一种有效的方法来确定代码大小,而无需加载整个代码,例如将其存储在以代码哈希为键的单独表中。这样,他们可以在实际加载代码之前收取访问成本。否则,客户端可能会加载合约,即使没有足够的 gas 来支付代码加载费用。

版权

版权和相关权利已通过 CC0 放弃。

Citation

Please cite this document as:

Charles Cooper (@charles-cooper), Qi Zhou (@qizhou), "EIP-7907: Meter 合约代码大小和增加限制 [DRAFT]," Ethereum Improvement Proposals, no. 7907, March 2025. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-7907.