> For the complete documentation index, see [llms.txt](https://docs.rome.builders/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.rome.builders/zh/he-xin-gai-nian/compute-budget.md).

# 计算预算

Rome EVM 操作的 Solana 计算单元（CU）成本——原子模式与迭代模式的预算，以及如何设计更节省 CU 的 Solidity 合约。

每笔 Solana 交易都有以计算单位（CU）衡量的计算预算。理解 CU 成本有助于你设计高效的 Rome 合约。

## 预算概览

| 模式        | 最大 CU                             | 说明                                          |
| --------- | --------------------------------- | ------------------------------------------- |
| 原子式（VmAt） | 约 1,400,000 CU                    | 单笔 Solana 交易                                |
| 迭代式（VmIt） | 每段最高约 1,400,000 CU；每个会话最多 160 次迭代 | 每段都是独立的 Solana 交易；自适应操作码/步骤——按每笔交易的 CU 预算打包 |

每笔 Solana 交易的默认预算为 200,000 CU，可通过计算预算指令扩展至约 140 万 CU（由 Rome SDK 自动添加）。

迭代执行并非无限制。一个会话在 160 次迭代后结束，而 Rust 版 Rome SDK 的迭代式 composer 最多规划 128 段。由钱包自行签名的计划会经过 `rome_submitSignedV1Plan`，其每次调用最多接受 64 笔交易。大多数调用所需远少于此。迭代会话中会拒绝旧版路径的 CPI，因此发起这类调用时必须符合原子预算。参见 [代发调用和长调用](/zh/kai-fa-zhe-zhi-nan/call-evm-from-solana.md#relayed-calls-and-long-calls) 和 [约束](/zh/he-xin-gai-nian/constraints.md).

## CU 成本估算

### EVM 操作

| 操作               | 约略 CU                | 说明                                                   |
| ---------------- | -------------------- | ---------------------------------------------------- |
| 交易签名检查（EVM 密钥路径） | 约 25,000 CU          | 上面的 `secp256k1_recover` 系统调用，与下述 `ecrecover` 预编译相同成本 |
| 简单转账             | 约 50,000–100,000 CU  | 仅余额更新                                                |
| ERC-20 转账        | 约 100,000–150,000 CU | 包含 SPL 预编译调用                                         |
| 合约部署（小型）         | 约 200,000–400,000 CU | 取决于字节码大小                                             |
| 存储写入（SSTORE）     | 约 5,000–20,000 CU    | 冷访问与热访问                                              |

### 预编译操作

| 预编译             | 约略 CU                       | 说明                                                                                                                         |
| --------------- | --------------------------- | -------------------------------------------------------------------------------------------------------------------------- |
| ecrecover       | 约 25,700 CU                 |                                                                                                                            |
| SHA-256         | 按每 32 字节字计量约 257 CU         | 再加少量固定成本。该程序对 SHA-256、RIPEMD-160 和 identity 预编译采用一个共享的按字计费值，约为 2,200 CU，其大小按三者中成本最高的 RIPEMD-160 设定，因此 SHA-256 调用的收费高于其实际消耗 |
| BN254 ecAdd     | 接近 0 CU                     | 比复制 32 字节更便宜                                                                                                               |
| BN254 ecMul     | 约 4,200 CU                  |                                                                                                                            |
| BN254 ecPairing | 约 22,000 CU，外加每对约 12,800 CU | 四对检查约为 73,000 CU，完全在一次原子交易范围内                                                                                              |

这些数据来自程序自身的校准，使用的是测试网部署中从 Solana 节点读回的计算单位。此页未重新实测；请用 `computeUnitsConsumed`.

## 优化技巧

### 1. 在热点路径中使用 Yul

Solidity 的优化器能生成相当不错的代码，但 Yul（内联汇编）可在关键操作上显著降低 CU：

```solidity
// 之前：约 60 万 CU
function createPairAccount(bytes32 token0, bytes32 token1) external {
    // Solidity 层级操作
}

// 之后：约 15 万 CU（Yul 优化）
function createPairAccount(bytes32 token0, bytes32 token1) external {
    assembly {
        // 直接操作内存，跳过 ABI 编码开销
    }
}
```

### 2. 缓存 PDA 派生结果

通过 `find_program_address` 进行 PDA 派生成本较高。将已派生的 PDA 存储在合约存储中，而不是在每次调用时重新计算：

```solidity
mapping(address => bytes32) private cachedPdas;

function getPda(address user) internal returns (bytes32) {
    bytes32 cached = cachedPdas[user];
    if (cached != bytes32(0)) return cached;

    bytes32 pda = RomeEVMAccount.pda(user);
    cachedPdas[user] = pda;
    return pda;
}
```

### 3. 对已知程序 ID 进行硬编码

不要从存储中加载程序 ID——请使用常量：

```solidity
// 昂贵：从存储中读取
bytes32 splTokenProgram = storage_program_id;

// 低成本：编译期常量
bytes32 constant SPL_TOKEN_PROGRAM = 0x06ddf6e1d765a193d9cbe146ceeb79ac1cb485ed5f5b37913a8cf5857eff00a9;
```

### 4. 最小化账户数量

Solana 交易中的每个账户都会增加 CU 开销。可通过以下方式减少账户数量：

* 将共享账户的操作批量处理
* 使用更少的中间账户
* 避免冗余的 ATA 创建检查

### 5. 使用优化器设置

```typescript
// hardhat.config.ts — 在构建配置中启用优化器
solidity: {
  profiles: {
    default: { version: "0.8.28" },
    production: {
      version: "0.8.28",
      settings: { optimizer: { enabled: true, runs: 200 } },
    },
  },
}
```

使用以下命令构建 `npx hardhat compile --build-profile production`.

## 测量 CU 消耗

使用 `eth_estimateGas` 在提交前测量 CU：

```bash
cast estimate --rpc-url https://hadrian.testnet.romeprotocol.xyz/ \\
  0xCONTRACT "myFunction(uint256)" 42
```

或通过 ethers.js：

```javascript
const gas = await contract.myFunction.estimateGas(42);
console.log("Estimated gas:", gas.toString());
```

## 接下来

* [约束](/zh/he-xin-gai-nian/constraints.md) —— 完整的限制和边界列表


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.rome.builders/zh/he-xin-gai-nian/compute-budget.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
