MultiversX智能合约缓存优化Skill mvx_cache_patterns

这个技能用于在 MultiversX 区块链平台上优化智能合约的 gas 消耗,通过实现基于 Drop trait 的回写缓存模式,减少存储操作成本,提高性能。关键词:MultiversX, 缓存, gas 优化, 智能合约, Drop trait, 回写缓存。

智能合约 0 次安装 0 次浏览 更新于 3/21/2026

name: mvx_cache_patterns description: 基于 Drop 的回写缓存用于 gas 优化。适用于读取 3+ 存储值的端点。

MultiversX 缓存模式

为什么使用缓存?

  • 在 MultiversX 合约中,存储操作是最昂贵的
  • 使用缓存:入口读取 + 出口写入,中间读取免费(内存中)

模式 1:使用 Drop Trait 的回写缓存

在入口加载状态到结构体,在内存中修改,通过 Drop 在作用域退出时提交。

pub struct StorageCache<'a, C>
where
    C: crate::storage::StorageModule,
{
    sc_ref: &'a C,
    pub field_a: BigUint<C::Api>,
    pub field_b: BigUint<C::Api>,
    pub field_c: BigUint<C::Api>,
}

impl<'a, C> StorageCache<'a, C>
where
    C: crate::storage::StorageModule,
{
    pub fn new(sc_ref: &'a C) -> Self {
        StorageCache {
            field_a: sc_ref.field_a().get(),
            field_b: sc_ref.field_b().get(),
            field_c: sc_ref.field_c().get(),
            sc_ref,
        }
    }
}

impl<C> Drop for StorageCache<'_, C>
where
    C: crate::storage::StorageModule,
{
    fn drop(&mut self) {
        self.sc_ref.field_a().set(&self.field_a);
        self.sc_ref.field_b().set(&self.field_b);
        self.sc_ref.field_c().set(&self.field_c);
    }
}

模式 2:带计算方法的缓存

在缓存结构体上添加派生值方法——使用缓存字段和合约模块方法,无需额外存储读取:

impl<C> StateCache<'_, C>
where
    C: crate::storage::StorageModule + crate::math::MathModule,
{
    pub fn exchange_rate(&self) -> BigUint<C::Api> {
        if self.total_shares == 0u64 { return BigUint::from(1u64); }
        &self.total_deposited / &self.total_shares
    }
}

选择性回写

仅回写可变字段——在 Drop 中跳过配置/只读字段以节省 gas。

何时使用 vs 直接存储

场景 方法
端点读取 3+ 存储值 使用缓存
单个存储读取/写入 直接访问即可
视图函数读取多个值 只读缓存(无 Drop)
异步调用边界 在异步调用前手动删除缓存

反模式

1. 跨越异步边界的缓存

// 错误 - async_call_and_exit() 终止执行,drop() 永远不会运行!
fn bad_async(&self) {
    let mut cache = StorageCache::new(self);
    cache.balance += &deposit;
    self.tx().to(&other).typed(Proxy).call()
        .callback(self.callbacks().on_done())
        .async_call_and_exit();
}

// 正确 - 在异步调用前手动删除缓存
fn good_async(&self) {
    {
        let mut cache = StorageCache::new(self);
        cache.balance += &deposit;
    } // cache.drop() 在此处触发
    self.tx().to(&other).typed(Proxy).call()
        .callback(self.callbacks().on_done())
        .async_call_and_exit();
}

2. 在 Drop 中忘记字段

3. 回写不可变配置