需求
之前我们在自定义的 pallet 中使用了现成的 balance pallet。接下来使用自己实现的另外一个 pallet。
定义 pallet-storage 实现储存功能,并实现读写方法。然后在 pallet-poe 中使用 pallet-storage。
pallet-storage 实现
在 pallets 中新建 storage 文件,文件结构和其他 pallet 结构相同。 在 src 文件下面新建 trait 文件,定义 pallet-storage 的抽象功能,类似接口。
trait.rs
pub trait StorageInterface{
type Value;
fn get_param() -> Self::Value;
fn set_param(v: Self::Value);
}
实现 pallet_storage 功能 lib.rs
pub use pallet::*;
// 引入刚才定义的 StorageInterface
pub use traits::StorageInterface;
pub mod traits;
#[frame_support::pallet]
pub mod pallet {
use codec::Codec;
use frame_support::{
pallet_prelude::*,
sp_runtime::traits::AtLeast32BitUnsigned,
sp_std::fmt::Debug,
};
use frame_system::pallet_prelude::*;
#[pallet::pallet]
#[pallet::generate_store(pub(super) trait Store)]
pub struct Pallet<T>(_);
#[pallet::config]
pub trait Config: frame_system::Config {
type Event: From<Event<Self>>
+ IsType<<Self as frame_system::Config>::Event>;
type Value: Member
+ Parameter
+ AtLeast32BitUnsigned
+ Codec
+ From<u32>
+ Into<u32>
+ Copy
+ Debug
+ Default
+ MaxEncodedLen
+ MaybeSerializeDeserialize;
}
// 定义 StorageValue 作为最终的储存,在最后一部分 StorageInterface 实现中使用
#[pallet::storage]
pub type StorageInterfaceValue<T: Config> =
StorageValue<_, T::Value, ValueQuery>;
// event 不会用到
#[pallet::event]
#[pallet::generate_deposit(pub(super) fn deposit_event)]
pub enum Event<T: Config> {
FunctionCall,
}
// call 也不会用到,随便写一个
#[pallet::call]
impl<T: Config> Pallet<T> {
#[pallet::weight(0)]
pub fn my_function(
origin: OriginFor<T>,
) -> DispatchResultWithPostInfo {
ensure_signed(origin)?;
log::info!(target: "storage provider", "my function!");
Self::deposit_event(Event::FunctionCall);
Ok(().into())
}
}
}
// pallet实现了前面定义的 StorageInterface 这个 trait。
// type Value 的用法就是之前讲的 trait 使用占位类型
impl<T: Config> StorageInterface for Pallet<T> {
type Value = T::Value;
fn get_param() -> Self::Value {
StorageInterfaceValue::<T>::get()
}
fn set_param(v: Self::Value) {
StorageInterfaceValue::<T>::put(v);
}
}
为 pallet 实现 StorageInterface,可以参考【Substrate 第一行代码】 substrate 关键 rust 语法
pallet-poe 实现
pub use pallet::*;
#[frame_support::pallet]
pub mod pallet {
use codec::Codec;
use frame_support::{
pallet_prelude::*,
sp_runtime::traits::AtLeast32BitUnsigned,
sp_std::fmt::Debug,
};
use frame_system::pallet_prelude::*;
// 引入 StorageInterface
use pallet_storage::traits::StorageInterface;
#[pallet::pallet]
#[pallet::generate_store(pub(super) trait Store)]
pub struct Pallet<T>(_);
// 3. Runtime Configuration Trait
#[pallet::config]
pub trait Config: frame_system::Config {
type Event: From<Event<Self>>
+ IsType<<Self as frame_system::Config>::Event>;
type Value: Member
+ Parameter
+ AtLeast32BitUnsigned
+ Codec
+ From<u32>
+ Into<u32>
+ Copy
+ Debug
+ Default
+ MaxEncodedLen
+ MaybeSerializeDeserialize;
//定义了MyStorage类型,要求 实现 StorageInterface
type MyStorage: StorageInterface<Value = Self::Value>;
}
// 5. Runtime Events
// Can stringify event types to metadata.
#[pallet::event]
#[pallet::generate_deposit(pub(super) fn deposit_event)]
pub enum Event<T: Config> {
StoreEvent,
}
// 7. Extrinsics
// Functions that are callable from outside the runtime.
#[pallet::call]
impl<T: Config> Pallet<T> {
#[pallet::weight(0)]
pub fn storage_value(
origin: OriginFor<T>,
value: T::Value,
) -> DispatchResultWithPostInfo {
ensure_signed(origin)?;
//调用 StorageInterface中的函数
T::MyStorage::set_param(value);
let v = T::MyStorage::get_param();
// log 打印
log::info!(target: "poe",
"Value get from storage is: {:?}", v);
Self::deposit_event(Event::StoreEvent);
Ok(().into())
}
}
}
修改 runtime
runtime/Cargo.toml
[dependencies]
...
pallet-storage ={
version = "4.0.0-dev",
default-features = false,
path = "../pallets/storage" }
pallet-poe = {
version = "4.0.0-dev",
default-features = false,
path = "../pallets/poe"}
...
[features]
default = ["std"]
std = [
"codec/std",
"scale-info/std",
"frame-executive/std",
"frame-support/std",
"frame-system-rpc-runtime-api/std",
"frame-system/std",
"pallet-aura/std",
"pallet-balances/std",
"pallet-grandpa/std",
"pallet-randomness-collective-flip/std",
"pallet-sudo/std",
"pallet-template/std",
"pallet-simple-pallet/std",
"pallet-use-storage/std",
"pallet-use-errors/std",
"pallet-ext-example/std",
"pallet-use-hooks/std",
"pallet-use-rpc/std",
"pallet-use-config1/std",
"pallet-use-config2/std",
"pallet-storage/std",
"pallet-poe/std"
]
runtime/src/lib.rs
实现两个 pallet
impl pallet_storage::Config for Runtime {
type Event = Event;
type Value = u32;
}
impl pallet_poe::Config for Runtime {
type Event = Event;
type Value = u32;
type MyStorage = StorageProvider;
}
construct_runtime 增加 pallet
construct_runtime!(
pub enum Runtime where
Block = Block,
NodeBlock = opaque::Block,
UncheckedExtrinsic = UncheckedExtrinsic
{
System: frame_system,
...
//添加 Cargo 中配置的 pallet
StorageProvider: pallet_storage_provider,
PoePallet: pallet_poe,
}
);
总结
使用其他的 pallet 的过程其实就是 trait 的使用,要熟悉 trait 的关联类型,泛型参数的使用。