跳转到主要内容
mip.watch
⌘K

MIP-3

Linear Memory

最终 标准轨道 核心 已打包至 MONAD_NINE GitHub ↗ 论坛 ↗
构想 草案 审核中 最终审核 最终 持续更新

Redefine memory expansion cost to be linear and enforce an explicit maximum memory usage per transaction

作者
Category Labs
创建时间
2025-12-10
更新时间
2026年6月15日

利益相关方影响

此 MIP 为各受众群体带来的变化。严重度和操作标记由模型推导得出,并按 MIP 类型/分类设定确定性下限值。

AI 摘要不可用 — 改用结构化默认值

要点速览

此 MIP 的 AI 洞察不可用 — 下方显示结构化默认值。

变更内容

  • 此 MIP 的 AI 洞察不可用 — 下方显示结构化默认值。

开发者

智能合约与 dapp 构建者、RPC 使用者、工具开发者

用户

钱包用户、EOA 持有者、dapp 访问者

验证者

节点运营者、RPC 运营者、委托者

基金会

Monad 基金会与 Category Labs 核心开发者

规范

引用
子系统 executionevm

## Abstract

Redefine memory expansion cost to be linear and enforce an explicit maximum memory usage per transaction. 

## Motivation

Currently, EVM memory usage is bounded by a quadratic expansion cost and the 63/64 rule. The theoretical memory limit of a transaction is at least 26 MB. Historical transaction analysis shows that average memory usage is ~2 KB and maximum observed memory usage is ~2 MB. 

Benchmarks also indicate that the current memory expansion formula overcharges for actual resource usage.

This update aligns cost with actual resource consumption. It makes memory usage more predictable, particularly for contracts that rely on large memory allocations.

## Specification

Memory expansion cost is redefined as:

```python
memory_size_words = (memory_byte_size + 31) // 32
memory_cost = memory_size_words // 2
```

The max memory usage is capped at 8 MB.  Memory allocation is bounded across call contexts with the following rule: 

1. Let `k` be the memory used by the current call, and `j` the memory used by parent calls.
2. The remaining memory available to a child call is: 

```python
 remaining_memory = 8 * 1024 * 1024 - j - k
```
3. Once a call returns, the memory is returned to the pool.
4. If a call exceeds the remaining memory limit, it reverts.

## Backwards Compatibility

This proposal is highly compatible with existing contracts. Almost all standard EVM operations remain valid and ERC-4337 contracts continue to function correctly, as child call memory is released upon completion. Replay testing of historical Ethereum transactions will be used to quantify compatibility.

However, contracts that allocate more than 8 MB of memory will now revert.

## Security Considerations

The cost to expand memory to the 8MB ceiling is 131,072 gas. The result is that it is cheaper to expand memory than current costs. Potentially concurrency limits for RPC nodes should be adjusted to prevent OOM issue. 

## Acknowledgements

The proposals in this MIP are based on two previous EIP documents. Additionally, conversations with Charles Cooper were instructive in developing the Monad memory model:

- [EIP-7686](https://eips.ethereum.org/EIPS/eip-7686) (@vbuterin)
- [EIP-7923](https://eips.ethereum.org/EIPS/eip-7923) (@charles-cooper, @qizhou)

MIP-3 differs from EIP-7686 in that EIP-7686 defines a direct relationship between memory limit and gas limit, and from EIP-7923 in that MIP-3 does not adopt the page-based thrashing cost model.

## Copyright

Copyright and related rights waived via [CC0](../LICENSE.md).

论坛讨论

15 个帖子 · 5 个点赞 · 4个月前
在论坛上阅读更多 ↗
  1. @John Bergschneider #1 2025年12月31日 17:21

    MIP3 - Linear EVM memory cost This proposal reprices EVM memory expansion from a quadratic cost model to a linear one. To bound total memory usage within a block, each transaction is explicitly limited by its peak memory usage. The motivation is to better align EVM gas costs with real resource usage and to introduce an explicit invariant on total memory usage at the block level. Any feedback or discussion is appreciated on: - the proposed linear memory cost model - the explicit per-transaction memory limit - potential DoS concerns - developer ergonomics and usage concerns

  2. @Pdobacz #2 2026年1月19日 16:54

    Hello, I have questions to the design and spec: 1. How does the call which exceeds memory exit? revert or exceptionally halt? If revert, does the gas to extend memory get charged before reverting? and other instruction gas charges (esp. *CALL )? exceptionally halt is more consistent with current OOM behavior (out-of-gas), but revert is more friendly. The spec says “revert” but I want to confirm that’s what was meant and spec out the fine details. 2. For all calculation related to memory limit, the memory size isn’t rounded up to the nearest word, i.e. if caller frame allocates `limit - 1byte` memory, callee frame can still allocate `1byte` of memory? This is in the spec, but want to confirm.

  3. @Pdobacz #3 2026年1月20日 11:08

    - Can we expand discussion with EIP-7686 and EIP-7923 in the Rationale section, i.e. why is MIP-3 chosen over them? (my understanding is that EIP-7686 would combine unfavorably with Monad’s “charge-gas-limit” rule, what about the paging from EIP-7923?) - Similar to EIP-7923, behavior of MSIZE after the activation should be confirmed (esp. given the lack of rounding to word in memory limit calculation.) In other words - would MSIZE return limit or limit - 1byte in the case mentioned in (2.)?

  4. @John Bergschneider #4 2026年1月21日 15:20

    Some Responses: - Exceeding the memory limit causes the current call frame to revert rather than halt. One rationale for this decision is compatibility with ERC-4337 bundlers for the following reason: if exceeding the memory limit resulted in an exceptional halt a transaction could DOS erc4337 bundlers by using the memory limit. If compatibility with erc4337 is not necessary then this can be changed to halt.

  5. @John Bergschneider #5 2026年1月23日 00:00

    - Expansion cost remains in terms of 32 byte word expansion. This will be defined more explicitly in the MIP. - EIP-7686 and EIP-7923 are designed for ethereum execution specifically. For example in EIP-7686, it defines a strict bound on memory expansion via gas. This defines the amount of expandable memory to be linearly dependent on the amount of gas forwarded in the call. This is not compatible to the constraints of Monad execution. As it would cause a higher memory footprint per transaction. - MSIZE semantics are unchanged. It returns the size of active memory in bytes. So the case where caller frame allocates limit - 1byte memory is rounded up to the limit memory. The child call would not have any remaining memory to allocate.