LOADING...
LOADING...
LOADING...
当前位置: 玩币族首页 > 新闻观点 > 【Substrate开发教程】16 - Substrate声明存储宏decl_storage!的使用

【Substrate开发教程】16 - Substrate声明存储宏decl_storage!的使用

2020-10-30 松果 来源:区块链网络


上一篇文章使用decl_module!宏创建了Substrate版本的Hello World,decl_module!宏用于定义处理业务逻辑的外部调用函数,并没有涉及到数据存储。

Substrate模块通过decl_storage!宏来声明数据存储,下面介绍decl_storage!宏的相关用法。

声明一个StorageMap

StorageMap是Substrate中的HashMap(哈希表),是一种使用键值对(key-value)存储数据的数据结构,使用如下代码声明一个StorageMap:

decl_storage! { trait Store for Module<T: Trait> as SimpleMap { SimpleMap get(fn simple_map): map hasher(blake2_128_concat) T::AccountId => u32; } }

这段代码包含的要点有:

SimpleMap:存储数据的HashMap名称;get(fn simple_map):一个getter函数,返回从哈希表中获取的值;map hasher(blake2_128_concat):声明使用的哈希表类型,这里使用的是blake2_128_concat hasher;T::AccountId => u32:哈希表的键和值的数据类型,这里是键的类型是AccountId,值的类型是u32;

Substrate提供三种哈希表类型:blake2_128_concat、twox_64_concat、identity,一般使用blake2_128_concat即可。

StorageMap API

下面是一些StorageMap常用的API。

添加数据

<SimpleMap<T>>::insert(&user, entry);

获取数据

let entry = <SimpleMap<T>>::get(account); let entry = <SimpleMap<T>>::take(&user);

检查数据

<SimpleMap<T>>::contains_key(&user)

更多API可参考StorageMap文档,StorageMap不需要显式使用,decl_storage!已经完成了这部分工作。

编写模块代码

修改pallets/template/src/lib.rs代码如下:

#![cfg_attr(not(feature = "std"), no_std)] use frame_support::{decl_module, decl_storage, dispatch::DispatchResult}; use frame_system::ensure_signed; pub trait Trait: frame_system::Trait {} decl_storage! { trait Store for Module<T: Trait> as SimpleMap { SimpleMap get(fn simple_map): map hasher(blake2_128_concat) T::AccountId => u32; } } decl_module! { pub struct Module<T: Trait> for enum Call where origin: T::Origin { #[weight = 10_000] fn set_single_entry(origin, entry: u32) -> DispatchResult { let user = ensure_signed(origin)?; <SimpleMap<T>>::insert(&user, entry); Ok(()) } } }

这段模块代码在decl_storage!中定义了一个StorageMap,在decl_module!中定义了一个模块函数set_single_entry用于存储一个u32类型的数据。

No std

#![cfg_attr(not(feature = "std"), no_std)]

这句代码放在模块代码的最开头,表示除非明确告知,否则此模块不使用Rust标准库,因为Substrate runtime会把代码编译为Rust标准库不可用的Wasm二进制文件。

Weight注解

#[weight = 10_000]

配置默认调用权重,权重会影响用户调用该函数将要支付的费用。

修改runtime配置

runtime/src/lib.rs文件包含有关构成runtime的所有模块细节,对于每个模块都有如下处理流程:

1、导入包含该模块的Rust文件


2、实现其Trait


3、将该模块包含在construct_runtime!宏中


此处在construct_runtime!宏中添加了三种类型(Module、Call、Storage):

TemplateModule: pallet_template::{Module, Call, Storage},

所有这些类型都是由模板中定义的宏生成的。

编译

编译命令如下:

cd substrate-node-template cargo +nightly-2020-08-23 build --release

使用了nightly-2020-08-23这个较稳定的cargo nightly版本以避免编译过程中出现bug。


测试

启动node-template

./target/release/node-template --dev

打开https://polkadot.js.org/apps,切换网络为DEVELOPMENT-Local Node:


选项卡选择开发者-交易,“提交下面的外部信息”选择templateModule,会自动获取到定义的函数saySingleEntry(entry):


可以设置函数参数entry的值,这里我设置了123。

点击右下角“提交交易”按钮,点击“签名并提交”:


就会调用decl_module!中定义的set_single_entry函数,存储123这个值到decl_storage!中定义的SimpleMap中。

选项卡选择开发者-链状态-存储,“查询所选状态”选择templateModule,会自动获取到定义的哈希表SimpleMap,AccountId选择ALICE,点击右侧加号可以获取刚刚存储的值:


下一篇文章介绍如何定义和触发事件(Event)。

—-

编译者/作者:松果

玩币族申明:玩币族作为开放的资讯翻译/分享平台,所提供的所有资讯仅代表作者个人观点,与玩币族平台立场无关,且不构成任何投资理财建议。文章版权归原作者所有。

LOADING...
LOADING...