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 2119 和 RFC 8174 中描述的进行解释。
- 将 EIP-170 的合约代码大小限制从 24KB(
0x6000
字节)更新为 256KB(0x40000
字节)。 - 更改加载代码的操作码的 gas 计划。具体来说,修改操作码
CALL
、STATICCALL
、DELEGATECALL
、CALLCODE
和EXTCODECOPY
,以便如果代码是冷的,则将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 创建的合约,或先前在交易中对该合约进行了 CALL 、STATICCALL 、DELEGATECALL 、CALLCODE 或 EXTCODECOPY (加载合约代码的操作码) |
COLD_ACCOUNT_ACCESS_COST
和 WARM_STORAGE_READ_COST
在 EIP-2929 中定义。
- 将 EIP-3860 的合约 initcode 大小限制从 48KB(
0xc000
字节)更新为 512KB(0x80000
字节)。
理由
每个字的 gas 成本选择为 2,与 EIP-3860 一致。这解释了:
- 用于检索更大合约代码的额外磁盘 I/O
- 用于预处理较大代码以执行的计算资源增加(即“JUMPDEST 分析”)。
- 包含非常大的合约的区块的 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.