三、入門Substrate之常用存盤資料型別和它們相應的操作API
Substrate作為一個通用的區塊鏈開發框架,提供了豐富的資料型別用于在鏈上存盤資料,
運行時存盤允許您將資料存盤在區塊鏈中,這些資料在塊之間持久存在,并且可以從運行時邏輯中訪問,存盤應該是區塊鏈運行時開發人員最關心的問題之一,精心設計的存盤系統減少了網路中節點的負載,最終降低了區塊鏈參與者的間接成本,換句話說,區塊鏈運行時存盤的基本原則是盡量減少其使用,
- Storage Value 用于存盤任何單值型別,例如u8、u16
- Storage Map 用于存盤鍵值哈希映射,例如余額到帳戶的映射,
- Storage Double Map 用作具有兩個鍵的存盤映射的實作,以提供有效洗掉具有公共第一個鍵的所有條目的能力,
- Storage N Map - 用于存盤具有任意數量鍵的哈希映射,可作為構建三重存盤映射、四重存盤映射等的基礎,
1.StorageValue
1).整數型別
例如:存一個u32
//第一個引數為_固定,ValueQuery引數可填可不填,不填get獲取就是Option包裹的u32,填上就直接回傳u32
//pub(super) v2版 區塊鏈存盤始終在運行時之外公開 可見
#[pallet::storage]
#[pallet::getter(fn something)]
pub(super) type TestStorageValue<T> = StorageValue<_, u32,ValueQuery>;
//存入值
TestStorageValue::<T>::put(3);
// something() 和 TestStorageValue::<T>::get()的操作結果一樣
//獲取值
something()
TestStorageValue::<T>::get()
//數值運算存在溢位風險應該使用更加安全的api
let temp_value = TestStorageValue::<T>::get().checked_add(2).ok_or(Error::<T>::StorageOverflow)?;
KittiesCount::<T>::put(kitty_id + 1u32.into());
2).boolean
存入獲取用法同上
3).Vec
//引入
use frame_support::inherent::Vec;
#[pallet::storage]
#[pallet::getter(fn get_vec_value)]
pub type TestVecValue<T> = StorageValue<_, Vec<u8>,ValueQuery>;
//和原生Rust操作一樣
let mut test_vec = Vec::new();
test_vec.push(2);
test_vec.push(3);
test_vec.push(3);
TestVecValue::<T>::put(test_vec);
4).string &str
不支持,將字串轉成vec再存入值
//相互轉換
let str_vec = b"test".to_vec();
let vec_str = String::from_utf8(str_vec).unwrap();
5).struct
//引入
use frame_support::codec::{Encode, Decode};
//定義
#[derive(Encode, Decode, Clone, PartialEq)]
pub struct Person{
pub number: u32,
pub name: Vec<u8>,
}
//定義StorageValue
#[pallet::storage]
#[pallet::getter(fn get_struct_value)]
pub type TestStructValue<T> = StorageValue<_, Person>;
//存入值
let person = Person{
number:1,
name:name,
};
TestStructValue::<T>::put(person);
2.StorageMap
鍵值對
//定義
#[pallet::storage]
#[pallet::getter(fn get_struct_map)]
pub type StructMap<T:Config> = StorageMap<_,Blake2_128Concat,T::AccountId,Person>;
// 插入一個元素
StructMap::<T>::insert(key, value);
// 通過key獲取value
StructMap::<T>::get(key);
// 洗掉某個key對應的元素
StructMap::<T>::remove(key);
//是否包含key,回傳bool
StructMap::<T>::contains_key(key);
// 覆寫或者修改某個key對應的元素
StructMap::<T>::insert(key, new_value);
StructMap::<T>::mutate(key, |old_value| old_value+1);
3.DoubleMap
暫未使用到,后續補充
4.配置一個常量
#[pallet::config]
pub trait Config: frame_system::Config {
type Event: From<Event<Self>> + IsType<<Self as frame_system::Config>::Event>;
//配置常量
#[pallet::constant]
type MaxCardSize: Get<u32>;
}
//獲取它的值
T::MaxCardSize::get()
//在runtime的lib.rs中配置它
parameter_types! {
//設定值
pub const MaxCardSize: u32 = 1024 * 1024;
}
impl pallet_coming_id::Config for Runtime {
type Event = Event;
//添加上
type MaxCardSize = MaxCardSize;
}
5.創世配置
//先定義一個存盤它的StorageValue
#[pallet::storage]
#[pallet::getter(fn high_admin_key)]
pub(super) type HighKey<T: Config> = StorageValue<_, T::AccountId, ValueQuery>;
//創世配置
#[pallet::genesis_config]
pub struct GenesisConfig<T: Config> {
pub high_admin_key: T::AccountId,
}
//要實作Default,不然報錯
#[cfg(feature = "std")]
impl<T: Config> Default for GenesisConfig<T> {
fn default() -> Self {
Self {
high_admin_key: Default::default(),
}
}
}
#[pallet::genesis_build]
impl<T: Config> GenesisBuild<T> for GenesisConfig<T> {
fn build(&self) {
<HighKey<T>>::put(&self.high_admin_key);
}
}
//注意Runtime中的lib.rs里面要改一下
//加一個 Config<T>
TemplateModule: pallet_template::{Pallet, Call,Config<T>, Storage, Event<T>},
//最后在Node中的chain_spec.rs配置一下 注意template_module和TemplateModule關系,TemplateModuleConfig也是一個注意點,默認就叫這個名字后面加上Config
template_module: TemplateModuleConfig {
// Assign network admin rights.
high_admin_key: root_key.clone(),
},
總結:以上就是最常用到底資料型別以及常見操作,因為筆者也在學習程序中,后面也會補充在專案中常常使用到的操作,如果想廣泛學習方法建議打開檔案自己學習,
在學習完,pallet開發中基本配置和常使用的存盤資料型別之后,在下一篇文章中,會嘗試開發一個pallet-erc20實體
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/306481.html
標籤:區塊鏈
