You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何以优化方式检查BiDiMapper是否包含指定ID或值?如何节省Gas费?

优化方案:将线性遍历改为常数时间查询

当前实现通过遍历所有元素检查存在性,时间复杂度为O(n),Gas开销会随元素数量线性增长,在元素较多时极易触发Gas超限。以下是针对Substrate pallet场景的优化方案:

方案1:使用StorageMap替代集合存储

将原有的集合存储改为StorageMap,直接以Item作为键存储对应数据(比如你的Token),利用Substrate存储的键值对特性实现O(1)时间复杂度的存在性检查。

修改存储定义

use frame_support::storage::StorageMap;
use sp_runtime::traits::Blake2_128Concat;

#[storage]
pub(super) type ItemTokenMap<T: Config> = StorageMap<_, Blake2_128Concat, Item<T::Api>, Token>;

优化后的has_item实现

fn has_item(&self, item: &Item<Self::Api>) -> bool {
    ItemTokenMap::<Self>::contains_key(item)
}

方案2:额外维护哈希集合辅助查询

如果需要保留原有集合存储结构(比如需要遍历所有元素的场景),可以额外维护一个HashSet类型的存储,在添加/删除元素时同步更新该集合,查询时直接调用contains方法。

修改存储定义

use frame_support::storage::StorageValue;
use std::collections::HashSet;

#[storage]
pub(super) type ItemsTokens<T: Config> = StorageValue<_, Vec<(Item<T::Api>, Token)>>;
#[storage]
pub(super) type ItemsSet<T: Config> = StorageValue<_, HashSet<Item<T::Api>>>;

同步更新逻辑(示例:添加元素时)

fn add_item(&self, item: Item<Self::Api>, token: Token) {
    // 更新原有集合
    let mut items = ItemsTokens::<Self>::get(self);
    items.push((item.clone(), token));
    ItemsTokens::<Self>::put(items);
    
    // 同步更新哈希集合
    let mut set = ItemsSet::<Self>::get(self);
    set.insert(item);
    ItemsSet::<Self>::put(set);
}

优化后的has_item实现

fn has_item(&self, item: &Item<Self::Api>) -> bool {
    ItemsSet::<Self>::get(self).contains(item)
}

核心优化逻辑

区块链中遍历操作的Gas开销与元素数量正相关,而键值对查询(StorageMap::contains_key)或哈希集合查询(HashSet::contains)的Gas开销为常数级,不会随元素数量增加而上升,能大幅降低Gas消耗,同时避免元素过多时触发区块Gas上限。

注意:无论采用哪种方案,都需要保证添加、删除元素时同步更新对应存储结构,避免数据不一致。

内容的提问来源于stack exchange,提问作者Fargerik

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 22:15:56