mcpField
A
analyze-gas-optimization

analyze-gas-optimization

github.com/aptos-labs开发2090 次安装24 周前更新
代码仓库

关于 analyze-gas-optimization

analyze-gas-optimization 是用于分析 Aptos Move 合约 Gas 成本并寻找优化机会的技能。它指导检查存储、计算、引用和集合,并涵盖性能分析与测试注意事项。

主要功能

  1. 01识别高成本存储和向量操作
  2. 02检查存储与计算模式
  3. 03建议批处理和集合替代方案
  4. 04通过模拟或测试测量 Gas
  5. 05纳入测试与安全检查

适用场景

  1. 01在主网部署前评估 Gas 成本
  2. 02排查较高的交易成本
  3. 03检查高频操作涉及的合约
  4. 04结合安全与测试评估优化

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/aptos-labs/aptos-agent-skills --skill analyze-gas-optimization

安装后在 Claude Code 中输入/analyze-gas-optimization确认已加载。

详细介绍

技能:analyze-gas-optimization

分析并优化 Aptos Move 合约的 Gas 效率,找出高成本操作并提出优化建议。

适用场景

触发短语:

  • “优化 Gas”“降低 Gas 成本”“Gas 分析”
  • “降低合约成本”“Gas 效率”
  • “分析 Gas 用量”“Gas 优化”
  • “降低交易成本”

使用场景:

  • 主网上部署前
  • 交易成本较高时
  • 针对高频操作进行优化时
  • 构建交易频繁的 DeFi 协议时

Gas 优化核心原则

1. 存储优化
  • 尽量减少存储数据的大小
  • 使用高效的数据结构
  • 高效地打包结构体字段
  • 移除不必要的字段
2. 计算优化
  • 避免遍历大型集合
  • 缓存重复计算的结果
  • 尽可能使用位运算
  • 尽量减少 vector 操作
3. 引用优化
  • 尽可能优先借用而非移动
  • 高效使用 & 和 &mut
  • 避免不必要的副本

Gas 成本分析

高成本操作
1. 全局存储操作
// EXPENSIVE: Writing to global storage
move_to(account, large_struct);

// EXPENSIVE: Reading and writing
let data = borrow_global_mut<LargeData>(addr);

// EXPENSIVE: Checking existence
if (exists<Resource>(addr)) { ... }
2. Vector 操作
// EXPENSIVE: Growing vectors dynamically
vector::push_back(&mut vec, item); // O(n) worst case

// EXPENSIVE: Searching vectors
vector::contains(&vec, &item); // O(n)

// EXPENSIVE: Removing from middle
vector::remove(&mut vec, index); // O(n)
3. 字符串操作
// EXPENSIVE: String concatenation
string::append(&mut s1, s2);

// EXPENSIVE: UTF8 validation
string::utf8(bytes);
优化模式
1. 批量操作
// BAD: Multiple storage accesses
public fun update_values(account: &signer, updates: vector<Update>) {
    let i = 0;
    while (i < vector::length(&updates)) {
        let update = vector::borrow(&updates, i);
        let data = borrow_global_mut<Data>(update.address);
        data.value = update.value;
        i = i + 1;
    }
}

// GOOD: Single storage access with batch update
public fun batch_update(account: &signer, updates: vector<Update>) {
    let data = borrow_global_mut<Data>(signer::address_of(account));
    let i = 0;
    while (i < vector::length(&updates)) {
        let update = vector::borrow(&updates, i);
        // Update in memory
        update_memory_data(data, update);
        i = i + 1;
    }
}
2. 存储打包
// BAD: Wasteful storage
struct UserData has key {
    active: bool,      // 1 byte used, 7 wasted
    level: u8,         // 1 byte used, 7 wasted
    score: u64,        // 8 bytes
    timestamp: u64,    // 8 bytes
    // Total: 32 bytes (50% wasted)
}

// GOOD: Packed storage
struct UserData has key {
    // Pack small fields together
    flags: u8,         // Bits: [active, reserved...]
    level: u8,
    reserved: u16,     // Future use
    score: u64,
    timestamp: u64,
    // Total: 20 bytes (37.5% saved)
}
3. 延迟求值
// BAD: Always compute expensive value
struct Pool has key {
    total_shares: u64,
    total_assets: u64,
    // Computed on every update
    share_price: u64,
}

// GOOD: Compute only when needed
struct Pool has key {
    total_shares: u64,
    total_assets: u64,
    // Don't store computed values
}

public fun get_share_price(pool_addr: address): u64 {
    let pool = borrow_global<Pool>(pool_addr);
    if (pool.total_shares == 0) {
        INITIAL_SHARE_PRICE
    } else {
        pool.total_assets * PRECISION / pool.total_shares
    }
}
4. 事件优化
// BAD: Large event data
struct TradeEvent has drop, store {
    pool: Object<Pool>,
    trader: address,
    token_in: Object<Token>,
    token_out: Object<Token>,
    amount_in: u64,
    amount_out: u64,
    fees: u64,
    timestamp: u64,
    metadata: vector<u8>, // Large metadata
}

// GOOD: Minimal event data
struct TradeEvent has drop, store {
    pool_id: u64,        // Use ID instead of Object
    trader: address,
    amounts: u128,       // Pack amount_in and amount_out
    fees: u64,
    // Compute other data from state
}
5. 集合优化
// BAD: Linear search
public fun find_item(items: &vector<Item>, id: u64): Option<Item> {
    let i = 0;
    while (i < vector::length(items)) {
        let item = vector::borrow(items, i);
        if (item.id == id) {
            return option::some(*item)
        };
        i = i + 1;
    }
    option::none()
}

// GOOD: Use Table for O(1) lookup
struct Storage has key {
    items: Table<u64, Item>,
}

public fun find_item(storage: &Storage, id: u64): Option<Item> {
    if (table::contains(&storage.items, id)) {
        option::some(*table::borrow(&storage.items, id))
    } else {
        option::none()
    }
}

Gas 测量

1. 交易模拟
# Simulate to get gas estimate
aptos move run-function \
    --function-id 0x1::module::function \
    --args ... \
    --simulate

# Output includes:
# - gas_unit_price
# - max_gas_amount
# - gas_used
2. Gas 性能分析
#[test]
public fun test_gas_usage() {
    // Measure gas for operation
    let gas_before = gas::remaining_gas();
    expensive_operation();
    let gas_used = gas_before - gas::remaining_gas();

    // Assert reasonable gas usage
    assert!(gas_used < MAX_ACCEPTABLE_GAS, E_TOO_EXPENSIVE);
}

优化检查清单

存储检查清单
  • 打包结构体字段以尽量缩小体积
  • 使用合适的整数大小(u8、u16、u32、u64)
  • 移除不必要的字段
  • 考虑将大型数据存储在链下
  • 使用事件代替存储来记录日志
计算检查清单
  • 缓存重复计算的结果
  • 尽量减少对集合的遍历
  • 使用提前返回跳过不必要的工作
  • 批量执行相似操作
  • 避免冗余检查
集合检查清单
  • 使用 Table/TableWithLength 进行键值查找
  • 对大型集合使用 SmartTable
  • 限制 vector 大小
  • 对大型结果考虑使用分页
  • 使用合适的数据结构
最佳实践
  • 优化前后都进行性能分析
  • 在单元测试中测试 Gas 用量
  • 记录公开函数的 Gas 成本
  • 在合约设计中考虑 Gas 成本
  • 监控主网 Gas 用量

常见 Gas 优化

1. 用 Table 替代 Vector
// Before: O(n) search
struct Registry has key {
    users: vector<User>,
}

// After: O(1) lookup
struct Registry has key {
    users: Table<address, User>,
    user_list: vector<address>, // If iteration needed
}
2. 尽量减少存储读取
// Before: Multiple reads
public fun transfer(from: &signer, to: address, amount: u64) {
    assert!(get_balance(signer::address_of(from)) >= amount, E_INSUFFICIENT);
    let from_balance = borrow_global_mut<Balance>(signer::address_of(from));
    let to_balance = borrow_global_mut<Balance>(to);
    // ...
}

// After: Single read with validation
public fun transfer(from: &signer, to: address, amount: u64) {
    let from_addr = signer::address_of(from);
    let from_balance = borrow_global_mut<Balance>(from_addr);
    assert!(from_balance.value >= amount, E_INSUFFICIENT);
    // ... rest of logic
}
3. 使用位标志
// Before: Multiple bool fields (8 bytes each)
struct Settings has copy, drop, store {
    is_active: bool,
    is_paused: bool,
    is_initialized: bool,
    allows_deposits: bool,
}

// After: Single u8 (1 byte)
struct Settings has copy, drop, store {
    flags: u8, // Bit 0: active, 1: paused, 2: initialized, 3: deposits
}

const FLAG_ACTIVE: u8 = 1;        // 0b00000001
const FLAG_PAUSED: u8 = 2;        // 0b00000010
const FLAG_INITIALIZED: u8 = 4;   // 0b00000100
const FLAG_DEPOSITS: u8 = 8;      // 0b00001000

public fun is_active(settings: &Settings): bool {
    (settings.flags & FLAG_ACTIVE) != 0
}

Gas 优化报告模板

# Gas Optimization Report

## Summary

- Current average gas: X units
- Optimized average gas: Y units
- Savings: Z% reduction

## Optimizations Applied

### 1. Storage Optimization

- Packed struct fields (saved X bytes)
- Replaced vectors with tables (O(n) → O(1))
- Removed redundant fields

### 2. Computation Optimization

- Cached price calculations (saved X operations)
- Batched updates (N calls → 1 call)
- Early returns in validation

### 3. Event Optimization

- Reduced event size from X to Y bytes
- Removed redundant event fields

## Measurements

| Function | Before | After  | Savings |
| -------- | ------ | ------ | ------- |
| mint     | 50,000 | 35,000 | 30%     |
| transfer | 30,000 | 25,000 | 17%     |
| swap     | 80,000 | 60,000 | 25%     |

## Recommendations

1. Consider further optimizations for high-frequency functions
2. Monitor mainnet usage patterns
3. Set up gas usage alerts

集成说明

  • 与 security-audit 配合使用,确保优化不会损害安全性
  • 与 generate-tests 配合使用,验证优化后仍保持正确性
  • 主网部署前,在 deploy-contracts 之前应用
  • 详细模式请参阅 STORAGE_OPTIMIZATION.md

绝对禁止事项

  • ❌ 绝不移除安全检查(访问控制、输入验证)来进行优化
  • ❌ 绝不在未重新测试的情况下部署优化后的代码
  • ❌ Gas 分析期间绝不读取 .env 或 ~/.aptos/config.yaml(其中包含私钥)

参考资料

评论

支持 Markdown