Alert Source Discuss
🚧 Stagnant Standards Track: Core

EIP-3336: EVM 的分页内存分配

Authors Nick Johnson (@arachnid)
Created 2021-03-06
Discussion Link https://ethereum-magicians.org/t/eips-3336-and-3337-improving-the-evms-memory-model/5482

简述

更改 EVM 的内存模型以使用分页。

概要

目前,EVM 对内存的收费方式是将其视为一个从地址 0 开始,延伸到已被读取或写入的最高地址的线性数组。这对于简单的使用来说已经足够,但是意味着编译器必须生成紧凑使用内存的程序,这会导致因内存元素的重新分配而浪费 gas,并使得诸如单独的堆和栈区域之类的某些内存模型变得不切实际。此 EIP 建议更改为基于页面的计费模型,该模型为实现增加了最少的复杂性,同时为 EVM 程序提供了更大的通用性。

动机

大多数现代计算机为用户空间程序实现“虚拟内存”,程序可以访问巨大的地址空间,RAM 页面由操作系统根据需要进行分配。这允许它们以最大程度减少需要进行的重新分配和复制量的方式在整个内存中分发数据,并允许灵活地使用内存来存储具有不同生存期的数据。在 EVM 内部实现一个简单的分页内存版本将为以 EVM 为目标的编译器提供相同的灵活性。

规范

参数

常量
FORK_BLOCK 待定
PAGE_BITS 10
PAGE_BASE_COST 96

对于 block.number >= FORK_BLOCK 的区块,以下更改适用。

EVM 实现中内存分配的更改

内存现在以每页 2**PAGE_BITS 字节为单位进行分配。每个内存地址的最高 256 - PAGE_BITS 位表示页码,而内存地址的最低 PAGE_BITS 位表示页内的位置。页面被初始化为包含所有零字节,并在首次读取或写入页面中的字节时进行分配。

EVM 实现建议将页表存储为关联数组(例如,哈希表或字典),该数组将页码映射到该页的字节数组。

内存扩展 gas 成本的变更

目前,将内存扩展到 a 个字的总成本为 Cmem(a) = 3 * a + floor(a ** 2 / 512)。如果内存已经有 b 个字长,则增量成本为 Cmem(a) - Cmem(b)a 是覆盖从内存地址 0 到已被 EVM 读取或写入的最后一个字的范围所需的字数。

在此 EIP 下,我们定义了一个新的内存成本函数,该函数基于已分配页面的数量。此函数为 Cmem'(p) = max(PAGE_BASE_COST * (p - 1) + floor(2 * (p - 1) ** 2), 0)。如上所述,如果内存已经包含 q 页,则增量成本为 Cmem'(p) - Cmem'(q)

MLOADMSTORE 的变更

从内存中加载一个字或将一个字存储到内存中需要实例化它所接触的任何尚不存在的页面,并产生如上所述的 gas 成本。如果要加载或存储的字位于单个页面中,则 gas 成本保持不变,为 3 gas。如果要加载的字跨越两个页面,则成本为 6 gas。

其他内存访问操作码的变更

CALLDATACOPYCODECOPYEXTCODECOPYCALLCALLCODEDELEGATECALLSTATICCALLCREATEMSTORE8 以及任何其他读取或写入内存的操作码都将按以下方式进行修改:

  • 它们接触到的任何用于读取或写入的页面,如果尚未实例化,则会实例化。
  • 如上所述,收取内存扩展 gas。

原理

内存扩展 gas 成本

新的 gas 成本与之前的 gas 成本遵循相同的曲线,同时确保新的 gas 成本始终小于或等于之前的成本。这可以防止现有的对内存分配 gas 成本做出假设的程序导致错误,而又不会不适当地降低低于当前成本的内存。直观地,一个使用到页面边界的程序所支付的费用比旧模型少一个页面,而一个使用量超出页面边界一个字的程序所支付的费用比旧模型少一个字。

我们认为,这种增量减少不会对有效的 gas 限制产生重大影响,因为随着程序使用的 RAM 增多,它所占的比例会越来越小。

跨越两个页面的 MLOAD 和 MSTORE 的额外成本

加载或存储跨越两个内存页面的数据需要 EVM 实现做更多的工作,EVM 实现必须在页面边界处拆分字并更新两个(可能是不相交的)页面。由于我们不能保证现有 EVM 程序中的加载和存储是页对齐的,因此我们不能为了效率而禁止这种行为。相反,我们建议将每个加载或存储视为两个,以进行 gas 记帐。这不鼓励使用此功能,并考虑了额外的执行成本,而没有完全禁止它。

这将导致执行这些操作的任何程序的额外 gas 成本。我们认为这是最小的,并希望进行未来的分析以确认这一点。

向后兼容性

新的内存扩展 gas 成本函数经过专门设计,可通过始终收取小于或等于当前 EVM 收取的金额来避免向后兼容性问题。在某些情况下,现有程序将因跨越页面边界的 MLOAD 和 MSTORE 而被收取更高的费用,如上所述。我们认为这些更改将影响最少的程序,并且仅对其 gas 消耗产生很小的影响。

测试用例

待定

安全注意事项

通过对非页面对齐的读取和写入收取更多费用,可以缓解由新模型下完成的额外工作引起的潜在 CPU DoS 问题。内存扩展的费用逐渐接近当前有效的费用,因此此更改不会允许程序分配比现在可以分配的内存多得多的内存。

版权

通过 CC0 放弃版权及相关权利。

Citation

Please cite this document as:

Nick Johnson (@arachnid), "EIP-3336: EVM 的分页内存分配 [DRAFT]," Ethereum Improvement Proposals, no. 3336, March 2021. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-3336.