# 计算预算

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

## 预算概览

| 模式        | 最大 CU          | 说明                 |
| --------- | -------------- | ------------------ |
| 原子式（VmAt） | \~1,400,000 CU | 单笔 Solana 交易       |
| 迭代式（VmIt） | 无限制（多笔交易）      | 每次迭代步骤约 \~500 条操作码 |

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

## CU 成本估算

### EVM 操作

| 操作              | 大致 CU                | 说明                            |
| --------------- | -------------------- | ----------------------------- |
| 签名验证（ecrecover） | \~5,000 CU           | 通过 Solana syscall 的 secp256k1 |
| 简单转账            | \~50,000-100,000 CU  | 仅更新余额                         |
| ERC-20 转账       | \~100,000-150,000 CU | 包含 SPL 预编译调用                  |
| 合约部署（小型）        | \~200,000-400,000 CU | 取决于字节码大小                      |
| 存储写入（SSTORE）    | \~5,000-20,000 CU    | 冷访问与热访问                       |

### CPI 操作

| 操作             | 大致 CU      | 说明             |
| -------------- | ---------- | -------------- |
| 转账钩子基础开销       | 100,000 CU | 每次转账           |
| 原生子钩子          | 50,000 CU  | 每个原生 Solana 钩子 |
| EVM 子钩子        | 200,000 CU | 每个 EVM 钩子      |
| 推荐的带钩子的 EVM 转账 | 800,000 CU | 适用于带钩子转账的安全预算  |

### 预编译操作

| 预编译             | 大致 CU            |
| --------------- | ---------------- |
| ecrecover       | \~3,000-5,000 CU |
| SHA-256         | \~1,000 CU       |
| BN254 ecAdd     | \~10,000 CU      |
| BN254 ecMul     | \~40,000 CU      |
| BN254 ecPairing | \~200,000+ CU    |

## 优化技巧

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

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

```solidity
// 之前：~600K CU
function createPairAccount(bytes32 token0, bytes32 token1) external {
    // Solidity 级别的操作
}

// 之后：~150K 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. 使用优化器设置

```javascript
// hardhat.config.js
solidity: {
  version: "0.8.28",
  settings: {
    optimizer: { enabled: true, runs: 200 },
  },
}
```

## 衡量 CU 消耗

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

```bash
cast estimate --rpc-url http://localhost:9090 \
  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) — 限制和边界的完整列表
* [CU 优化指南](https://github.com/rome-protocol/docs/blob/main/developer-guides/cu-optimization.md) — 详细的优化手册


---

# Agent Instructions: Querying This Documentation

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

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

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

The question should be specific, self-contained, and written in natural language.
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.
