在runtime中声明一个常量值是定义固定值或定义根据某些因素动态变化的值的有用工具。
接下来一起看看,如何创建用于重置u32存储值的pallet常量。这个值,我们称之为SingleValue
,也可以使用一个名为add_value
的方法来修改。
配置pallet的类型、事件和错误
1.定义pallet中的常量
-
MaxAddend
将是元数据中显示的值。 -
ClearFrequency
跟踪块编号并将用于重置SingleValue
。
#[pallet::config]
pub trait Config: frame_system::Config {
type Event: From<Event<Self>> + IsType<<Self as frame_system::Config>::Event>;
#[pallet::constant] // put the constant in metadata
/// Maximum amount added per invocation.
type MaxAddend: Get<u32>;
/// Frequency with which the stored value is deleted.
type ClearFrequency: Get<Self::BlockNumber>;
}
2.声明存储项目和事件。
使用存储属性宏,声明SingleValue
每个块周期都会修改的值。
#[pallet::storage]
#[pallet::getter(fn single_value)]
pub(super) type SingleValue<T: Config> = StorageValue<_, u32, ValueQuery>;
3.定义pallet的事件。
#[pallet::event]
#[pallet::generate_deposit(pub(super) fn deposit_event)]
pub enum Event<T: Config> {
/// The value has been added to. The parameters are
/// (initial amount, amount added, final amount).
Added(u32, u32, u32),
/// The value has been cleared. The parameter is the value before clearing.
Cleared(u32)
}
4. 添加处理操作溢出的错误:
#[pallet::error]
pub enum Error<T> {
/// An operation would lead to an overflow.
Overflow
}
创建pallet方法和运行时常量
1.配置on_finalize.
在块执行结束时运行的 on_finalize 函数中的每个 ClearFrequency 块数将 SingleValue 设置为 0。 在 #[pallet::hooks] 属性下指定此逻辑
#[pallet::hooks]
impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
fn on_finalize(n: T::BlockNumber) {
if (n % T::ClearFrequency::get()).is_zero() {
let current_value = <SingleValue<T>>::get();
<SingleValue<T>>::put(0u32);
Self::deposit_event(Event::Cleared(current_value));
}
}
}
2.创建一个允许用户指定值的方法。
只要每次调用增加的值小于 MaxAddend 值,add_value 方法就会增加 SingleValue
。
对于此方法,必须遵循以下:
- Include checks.
- Keep track of the previous value.
- Check for overflow.
- Update SingleValue.
// Extrinsics callable from outside the runtime.
#[pallet::call]
impl<T: Config> Pallet<T> {
#[pallet::weight(1_000)]
fn add_value(
origin: OriginFor<T>,
val_to_add: u32
) -> DispatchResultWithPostInfo {
let _ = ensure_signed(origin)?;
ensure!(val_to_add <= T::MaxAddend::get(), "value must be <= maximum add amount constant");
// previous value got
let c_val = SingleValue::<T>::get();
// checks for overflow when new value added
let result = c_val.checked_add(val_to_add).ok_or(Error::<T>::Overflow)?;
<SingleValue<T>>::put(result);
Self::deposit_event(Event::Added(c_val, val_to_add, result));
Ok(().into())
}
}
3.为runtime提供常量值。
在 runtime/src/lib.rs
中,为您的托盘的 MaxAddend
和 ClearFrequency
的运行时实现声明值:
parameter_types! {
pub const MaxAddend: u32 = 1738;
pub const ClearFrequency: u32 = 10;
}
impl constant_config::Config for Runtime {
type Event = Event;
type MaxAddend = MaxAddend;
type ClearFrequency = ClearFrequency;
}
例子
#![cfg_attr(not(feature = "std"), no_std)]
pub use pallet::*;
#[frame_support::pallet]
pub mod pallet {
use frame_support::{dispatch::DispatchResultWithPostInfo, pallet_prelude::*};
use frame_system::pallet_prelude::*;
use frame_support::sp_runtime::traits::Zero;
#[pallet::config]
pub trait Config: frame_system::Config {
type Event: From<Event<Self>> + IsType<<Self as frame_system::Config>::Event>;
#[pallet::constant] // put the constant in metadata
/// Maximum amount added per invocation.
type MaxAddend: Get<u32>;
/// Frequency with which the stored value is deleted.
type ClearFrequency: Get<Self::BlockNumber>;
}
#[pallet::pallet]
#[pallet::generate_store(pub(super) trait Store)]
pub struct Pallet<T>(_);
#[pallet::storage]
#[pallet::getter(fn single_value)]
pub(super) type SingleValue<T: Config> = StorageValue<_, u32, ValueQuery>;
#[pallet::event]
#[pallet::generate_deposit(pub(super) fn deposit_event)]
pub enum Event<T: Config> {
/// The value has ben added to. The parameters are
/// (initial amount, amount added, final amount).
Added(u32, u32, u32),
/// The value has been cleared. The parameter is the value before clearing.
Cleared(u32)
}
#[pallet::error]
pub enum Error<T> {
/// An operation would lead to an overflow.
Overflow
}
#[pallet::hooks]
impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
fn on_finalize(n: T::BlockNumber) {
if (n % T::ClearFrequency::get()).is_zero() {
let current_value = <SingleValue<T>>::get();
<SingleValue<T>>::put(0u32);
Self::deposit_event(Event::Cleared(current_value));
}
}
}
// Extrinsics callable from outside the runtime.
#[pallet::call]
impl<T: Config> Pallet<T> {
#[pallet::weight(1_000)]
fn add_value(
origin: OriginFor<T>,
val_to_add: u32
) -> DispatchResultWithPostInfo {
let _ = ensure_signed(origin)?;
ensure!(val_to_add <= T::MaxAddend::get(), "value must be <= maximum add amount constant");
// previous value got
let c_val = SingleValue::<T>::get();
// checks for overflow when new value added
let result = c_val.checked_add(val_to_add).ok_or(Error::<T>::Overflow)?;
<SingleValue<T>>::put(result);
Self::deposit_event(Event::Added(c_val, val_to_add, result));
Ok(().into())
}
}
}