analyze-gas-optimization

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Skill: analyze-gas-optimization

Skill: analyze-gas-optimization

Analyze and optimize Aptos Move contracts for gas efficiency, identifying expensive operations and suggesting optimizations.
分析并优化Aptos Move合约的gas效率,识别高开销操作并给出优化建议。

When to Use This Skill

何时使用该技能

Trigger phrases:
  • "optimize gas", "reduce gas costs", "gas analysis"
  • "make contract cheaper", "gas efficiency"
  • "analyze gas usage", "gas optimization"
  • "reduce transaction costs"
Use cases:
  • Before mainnet deployment
  • When transaction costs are high
  • When optimizing for high-frequency operations
  • When building DeFi protocols with many transactions
触发短语:
  • "optimize gas", "reduce gas costs", "gas analysis"
  • "make contract cheaper", "gas efficiency"
  • "analyze gas usage", "gas optimization"
  • "reduce transaction costs"
使用场景:
  • 主网部署前
  • 交易成本过高时
  • 针对高频操作做优化时
  • 构建包含大量交易的DeFi协议时

Core Gas Optimization Principles

核心Gas优化原则

1. Storage Optimization

1. 存储优化

  • Minimize stored data size
  • Use efficient data structures
  • Pack struct fields efficiently
  • Remove unnecessary fields
  • 最小化存储数据大小
  • 使用高效的数据结构
  • 高效打包结构体字段
  • 移除不必要的字段

2. Computation Optimization

2. 计算优化

  • Avoid loops over large collections
  • Cache repeated calculations
  • Use bitwise operations when possible
  • Minimize vector operations
  • 避免遍历大型集合的循环
  • 缓存重复计算的结果
  • 尽可能使用位运算
  • 最小化向量操作

3. Reference Optimization

3. 引用优化

  • Prefer borrowing over moving when possible
  • Use
    &
    and
    &mut
    efficiently
  • Avoid unnecessary copies
  • 尽可能优先使用借用而非转移
  • 高效使用
    &
    &mut
  • 避免不必要的拷贝

Gas Cost Analysis

Gas成本分析

Expensive Operations

高开销操作

1. Global Storage Operations

1. 全局存储操作

move
// 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)) { ... }
move
// 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 Operations

2. 向量操作

move
// 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)
move
// 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. String Operations

3. 字符串操作

move
// EXPENSIVE: String concatenation
string::append(&mut s1, s2);

// EXPENSIVE: UTF8 validation
string::utf8(bytes);
move
// EXPENSIVE: String concatenation
string::append(&mut s1, s2);

// EXPENSIVE: UTF8 validation
string::utf8(bytes);

Optimization Patterns

优化模式

1. Batch Operations

1. 批量操作

move
// 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;
    }
}
move
// 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. Storage Packing

2. 存储打包

move
// 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)
}
move
// 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. Lazy Evaluation

3. 懒加载计算

move
// 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
    }
}
move
// 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. Event Optimization

4. 事件优化

move
// 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
}
move
// 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. Collection Optimization

5. 集合优化

move
// 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()
    }
}
move
// 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 Measurement

Gas测算

1. Transaction Simulation

1. 交易模拟

bash
undefined
bash
undefined

Simulate to get gas estimate

Simulate to get gas estimate

aptos move run-function
--function-id 0x1::module::function
--args ...
--simulate
aptos move run-function
--function-id 0x1::module::function
--args ...
--simulate

Output includes:

Output includes:

- gas_unit_price

- gas_unit_price

- max_gas_amount

- max_gas_amount

- gas_used

- gas_used

undefined
undefined

2. Gas Profiling

2. Gas性能分析

move
#[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);
}
move
#[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);
}

Optimization Checklist

优化检查清单

Storage Checklist

存储检查项

  • Pack struct fields to minimize size
  • Use appropriate integer sizes (u8, u16, u32, u64)
  • Remove unnecessary fields
  • Consider off-chain storage for large data
  • Use events instead of storage for logs
  • 打包结构体字段以最小化体积
  • 使用合适的整数类型(u8、u16、u32、u64)
  • 移除不必要的字段
  • 大型数据考虑使用链下存储
  • 日志使用事件而非存储

Computation Checklist

计算检查项

  • Cache repeated calculations
  • Minimize loops over collections
  • Use early returns to skip unnecessary work
  • Batch similar operations
  • Avoid redundant checks
  • 缓存重复计算的结果
  • 最小化遍历集合的循环
  • 使用提前返回跳过不必要的工作
  • 批量处理相似操作
  • 避免冗余检查

Collection Checklist

集合检查项

  • Use Table/TableWithLength for key-value lookups
  • Use SmartTable for large collections
  • Limit vector sizes
  • Consider pagination for large results
  • Use appropriate data structures
  • 使用Table/TableWithLength实现键值查找
  • 大型集合使用SmartTable
  • 限制向量大小
  • 大型结果考虑分页
  • 使用合适的数据结构

Best Practices

最佳实践

  • Profile before and after optimization
  • Test gas usage in unit tests
  • Document gas costs for public functions
  • Consider gas costs in contract design
  • Monitor mainnet gas usage
  • 优化前后都进行性能分析
  • 在单元测试中测试gas使用情况
  • 为公开函数标注gas成本
  • 合约设计阶段就考虑gas成本
  • 监控主网gas使用情况

Common Gas Optimizations

常见Gas优化方案

1. Replace Vectors with Tables

1. 用Table替换Vector

move
// 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
}
move
// 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. Minimize Storage Reads

2. 最小化存储读取次数

move
// 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
}
move
// 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. Use Bitwise Flags

3. 使用位标志

move
// 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
}
move
// 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 Optimization Report Template

Gas优化报告模板

markdown
undefined
markdown
undefined

Gas Optimization Report

Gas Optimization Report

Summary

Summary

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

Optimizations Applied

Optimizations Applied

1. Storage Optimization

1. Storage Optimization

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

2. Computation Optimization

2. Computation Optimization

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

3. Event Optimization

3. Event Optimization

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

Measurements

Measurements

FunctionBeforeAfterSavings
mint50,00035,00030%
transfer30,00025,00017%
swap80,00060,00025%
FunctionBeforeAfterSavings
mint50,00035,00030%
transfer30,00025,00017%
swap80,00060,00025%

Recommendations

Recommendations

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

Integration Notes

集成说明

  • Works with
    security-audit
    to ensure optimizations don't compromise security
  • Use with
    generate-tests
    to verify optimizations maintain correctness
  • Apply before
    deploy-contracts
    for mainnet deployments
  • Reference
    STORAGE_OPTIMIZATION.md
    for detailed patterns
  • 可与
    security-audit
    搭配使用,确保优化不会损害安全性
  • 可配合
    generate-tests
    使用,验证优化后逻辑正确性
  • 在主网部署的
    deploy-contracts
    步骤前应用
  • 参考
    STORAGE_OPTIMIZATION.md
    获取详细模式说明

NEVER Rules

禁止规则

  • ❌ NEVER optimize away security checks (access control, input validation)
  • ❌ NEVER deploy optimized code without re-testing
  • ❌ NEVER read
    .env
    or
    ~/.aptos/config.yaml
    during gas analysis (contain private keys)
  • ❌ 绝对不要移除安全检查(访问控制、输入校验)来优化gas
  • ❌ 绝对不要未重新测试就部署优化后的代码
  • ❌ gas分析期间绝对不要读取
    .env
    ~/.aptos/config.yaml
    (包含私钥)

References

参考资料