EIP-7686: 线性 EVM 内存限制
调整子调用的内存限制和 gas 限制,以便创建一个清晰的线性边界,限制 EVM 执行可以消耗的总内存量
Authors | Vitalik Buterin (@vbuterin) |
---|---|
Created | 2024-04-15 |
Discussion Link | https://ethereum-magicians.org/t/eip-7686-linear-evm-memory-limits/19448 |
摘要
添加一个硬性内存限制,等于当前上下文的 gas 限制。使子调用的最大 gas 成本取决于当前上下文中使用的内存。这两个规则共同确保具有 N gas 的事务最多可以使用 N 字节的内存。
动机
目前,内存定价规则很复杂:我们有扩展内存的二次成本,以及子调用可以使用的 gas 量的 63/64 规则。这也使得计算处理给定的 EVM 执行所需的最大可能内存量变得非常困难。
本文中的规则简化了这些规则,并添加了一个新的硬性限制:具有 N gas 的 EVM 执行最多需要 N 总字节的内存来处理。这个限制是严格的:N-gas 调用很容易使用 N - O(1)
字节的内存。
规范
将 memory_cost
从:
memory_size_word = (memory_byte_size + 31) / 32
memory_cost = (memory_size_word ** 2) / 512 + (3 * memory_size_word)
改为:
memory_size_word = (memory_byte_size + 31) / 32
memory_cost = 3 * memory_size_word
此外,如果内存扩展将导致 memory_byte_size
严格超过当前调用的初始 gas 限制,则恢复并报错。
在进行任何类型的调用时,将最大 gas 限制从当前的 EIP-150 定义更改为:
def max_call_gas(gas):
return gas - (gas // 64)
改为:
def max_call_gas(gas, memory_byte_size):
return gas - max(gas // 64, memory_byte_size)
理由
有了这个 EIP,就有一个简单的 EVM 实现,可以使用 N 字节的 bytearray 作为内存来处理 N-gas 调用:将所有字节分配给当前上下文,当进行子调用时,从 memory_byte_size
位置开始,将剩余的内存用于子调用的内存,以此类推,递归进行。
拥有这个清晰的不变量对于 EVM 实现非常有用,尤其是在受限环境中的 EVM 实现(例如 ZK-SNARK 证明器)。
保留每个字 3 gas 的内存扩展成本,因为它等同于 MCOPY,因此在子调用结束时清除内存的操作(在常规机器中很便宜,但在 ZK-SNARK 和其他不寻常的上下文中更昂贵)可以使用与实现 MCOPY 操作码本身相同的逻辑来实现。
保持 63/64 规则是为了维持当前大约 1 + log((gaslimit + 6300) / 6400) / log(64/63) = 537
的实际调用堆栈深度限制。
向后兼容性
如果 EVM 代码访问内存中的高索引,但以低 gas 限制调用,那么理论上,今天可以工作的 EVM 代码可能会在这个新的 EIP 下无法工作。然而,几乎所有的 EVM 执行消耗的代码都远远超过它使用的内存字节数。例如,为了使调用导致哪怕是单个状态变化,它必须至少有 5000 gas。这将允许它使用 5000 字节的内存,这大于几乎所有应用程序使用的内存。更复杂的应用程序将具有更高的限制。
安全考虑
没有提出安全问题。
版权
通过 CC0 放弃版权和相关权利。
Citation
Please cite this document as:
Vitalik Buterin (@vbuterin), "EIP-7686: 线性 EVM 内存限制 [DRAFT]," Ethereum Improvement Proposals, no. 7686, April 2024. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-7686.