> ## Documentation Index
> Fetch the complete documentation index at: https://docs.monad.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# Opcode 定价

## 摘要

Monad 是一个高度优化的系统,在所有维度上都引入了效率提升 —— 计算、状态访问和带宽利用。 然而,相对于传统 EVM 系统的乘数在所有维度上并不相等。因此,需要一些 opcode 的 gas 价格 调整,以便应用程序能够充分释放链的全部潜力。

为了尽量减少 gas 价格变更的数量,Monad 没有下调几乎所有 opcode 的 gas 定价, 而是上调了少数 opcode 的价格。这与打折几乎所有 opcode 具有相同的相对效果。

以下费用发生了变化:

* [冷访问状态](#cold-access-cost)
* [存储页](#storage-pages)
* [几个预编译](#precompiles)
* [内存扩展](#memory-expansion)

所有其他费用与以太坊相同;[evm.codes](https://www.evm.codes/) 是一个有用的参考。

<Note>
  这些变更在 [Monad 初始规范提案](https://category-labs.github.io/category-research/monad-initial-spec-proposal.pdf)中涵盖。
</Note>

## 为什么需要变更?

EVM 当前的定价模型需要调整以支持高性能、低费用的模式。定价模型根据每个 opcode 对系统感知的 成本为其分配权重(gas 数量),然后仅根据计算出的权重总和向用户收费。随着资源稀缺性的变化 —— 特别是在完全新系统的情况下 —— 这些权重必须进行修订。

本页面描述的变更做出了最小限度的调整,以允许 Monad 提供高性能和低费用, 同时最大限度地减少对用户的干扰,并保护系统免受 DOS 攻击。

## 冷访问成本

为了考虑 Monad 执行客户端中从磁盘读取状态与计算相比相对较高的成本, "冷"账户和存储访问成本发生了变化:

| 访问类型 | 以太坊          | Monad                |
| ---- | ------------ | -------------------- |
| 账户   | 2600         | 10100                |
| 存储   | 每个 slot 2100 | 每 128 个 slot 一页 8100 |

由于 gas 成本的差异,以下 opcode 受到影响:

* 账户访问:`BALANCE`、`EXTCODESIZE`、`EXTCODECOPY`、`EXTCODEHASH`、`CALL`、`CALLCODE`、 `DELEGATECALL`、`STATICCALL`、`SELFDESTRUCT`
* 存储访问:`SLOAD`、`SSTORE`

存储的 warm 单位是每 128 个连续 slot 一页,而不是每个 slot,因此冷成本按页支付一次。 参见[存储页](#storage-pages)。

<Note>
  Monad 中的暖账户访问(100 gas)和存储访问(100 gas)的 gas 成本与以太坊相同。
</Note>

## 存储页

存储 slot 被分组为每页 128 个连续 slot。一个 slot 所在的页,是把 slot 索引最低 7 位剥除后的值:

```text theme={null}
page_index = slot >> 7
```

在一次交易期间,warm 状态按 (账户, 页) 记录:某页的任意一个 slot 被访问后,该页的其他每个 slot 都为 warm。 warm 状态会向子调用传播,并会回传给调用者;当某个 call frame 被 revert 时,warm 状态也会随之回滚,这与以太坊 跟踪账户和 slot 访问的方式一致。

顺序声明的状态变量、结构体的字段以及数组的元素占据连续 slot,因此共享页。`mapping` 的每个 key 仍然解析到自己的页,但该 key 下存储的结构体字段共享同一页。

### `SLOAD`

| 情况     | Gas  |
| ------ | ---- |
| 首次访问该页 | 8100 |
| 该页已被访问 | 100  |

### `SSTORE`

`SSTORE` 对页 I/O 和状态增长分别收费。所适用的组成部分累加:

| 组成部分 | Gas    | 收取时机                   |
| ---- | ------ | ---------------------- |
| 基础   | 100    | 每次 `SSTORE`            |
| 页加载  | 8000   | 该页首次被访问时(无论是读还是写)      |
| 页写入  | 2800   | 该页首次通过 `SSTORE` 改变某个值时 |
| 状态增长 | 17,000 | 每当该页的 slot 净数量创下新高时    |

状态增长在交易内按页取历史最高水位统计,因此在同一页中新建一个 slot 来替代此前清零的 slot 时,不会因增长而收费。 以太坊为写入全新 slot 收取的 20,000 gas 和为覆盖已有 slot 收取的 2900 gas 都不再适用。

### 成本示例

一次交易内针对同一账户的连续操作的成本:

| 序列                            | MIP-8 之前 | MIP-8 之后 |
| ----------------------------- | -------- | -------- |
| `SLOAD` 一个 slot,首次访问其所在页      | 8100     | 8100     |
| `SLOAD` 同一页中的另一个 slot         | 8100     | 100      |
| `SSTORE` 一个全新 slot,首次访问其所在页   | 28,100   | 27,900   |
| `SSTORE` 一个全新 slot,该页已被写过     | 28,100   | 17,100   |
| `SSTORE` 覆盖一个非零 slot,首次访问其所在页 | 11,000   | 10,900   |
| `SSTORE` 覆盖一个非零 slot,该页已被写过   | 11,000   | 100      |

一条 [EIP-2930](https://eips.ethereum.org/EIPS/eip-2930) 访问列表条目会将所列 key 所在的整个页 预热,而 `eth_createAccessList` 会按页对存储 key 去重。

<Note>
  这些改动在 [`MONAD_TEN`](/zh/developer-essentials/changelog#revisions) 版本中启用, 在 [MIP-8](https://mips.monad.xyz/MIPs/MIP-8) 中定义。各网络的启用时间戳请参见 [发布](/zh/developer-essentials/changelog/releases)。
</Note>

## 预编译

一些[预编译](/zh/developer-essentials/precompiles)被重新定价,以准确反映其在执行中的相对成本。

| 预编译          | 地址     | 以太坊                 | Monad                 | 乘数 |
| ------------ | ------ | ------------------- | --------------------- | -- |
| `ecRecover`  | `0x01` | 3000                | 6000                  | 2  |
| `ecAdd`      | `0x06` | 150                 | 300                   | 2  |
| `ecMul`      | `0x07` | 6000                | 30,000                | 5  |
| `ecPairing`  | `0x08` | 45,000 + 每个点 34,000 | 225,000 + 每个点 170,000 | 5  |
| `blake2f`    | `0x09` | $\text{rounds} * 1$ | $\text{rounds} * 2$   | 2  |
| `point eval` | `0x0a` | 50,000              | 200,000               | 4  |

一个点是由 `G1` 和 `G2` 元素组成的 192 字节对,如 [EIP-1108](https://eips.ethereum.org/EIPS/eip-1108) 所定义。

## 内存扩展

内存扩展按线性定价,并且交易可以使用的内存上限为 8 MB(8,388,608 字节)。

| 项目   | 以太坊              | Monad     |
| ---- | ---------------- | --------- |
| 扩展成本 | $3w + w^2 / 512$ | $w / 2$   |
| 内存限制 | 受 gas 限制约束       | 每笔交易 8 MB |

其中 $w$ 是以 32 字节字为单位的内存大小。扩展到 8 MB 上限花费 131,072 gas。

内存在 call frame 之间累计:子调用可用的内存为 8 MB 减去当前调用及其父调用已使用的内存。 一旦调用返回,内存就返回到池中。

超出限制会异常终止 call frame,消耗该帧所获得的所有 gas 并回滚其状态变更。从调用者的角度来看, 这与普通的 gas 耗尽无法区分。

<Note>
  这些变更在 [`MONAD_NINE`](/zh/developer-essentials/changelog/releases#v0-13-0-monad_nine) 修订版本中激活。
</Note>
