需求
在存证 pallet 的基础上增加操作主币,在创建存证的时候质押 balance ,交易存证的时候返还,接收者继续质押存证,删除存证时返回。
rust docs 使用
使用自带 pallet 的功能时候可以参考其他的 pallet
pallet_assets中就使用了pallet_balances,就是通过指定前者的currency类型为后者 github.com/paritytech/…
可以通过官网的 rust docs 查询 substrate 自带类的说明
例如我们查询将要用的的 currency 的说明
paritytech.github.io/substrate/m…
我们可以通过 官网的 rust docs 来查询 Currency 的用法,
将要用到的方法
编写 pallet 代码
#![cfg_attr(not(feature = "std"), no_std)]
/// Edit this file to define custom logic or remove it if it is not needed.
/// Learn more about FRAME and the core library of Substrate FRAME pallets:
/// <https://docs.substrate.io/v3/runtime/frame>
pub use pallet::*;
/// 开始定义功能模块
#[frame_support::pallet]
pub mod pallet {
use frame_support::{pallet_prelude::*, storage::bounded_vec::BoundedVec, traits::Currency};
use frame_system::pallet_prelude::*;
use frame_support::traits::{ReservableCurrency};
type BalanceOf<T> =
<<T as Config>::Currency as Currency<<T as frame_system::Config>::AccountId>>::Balance;
#[pallet::pallet]
#[pallet::generate_store(pub(super) trait Store)]
pub struct Pallet<T>(_);
/// 模块配置接口,继承自系统模块
/// Configure the pallet by specifying the parameters and types on which it depends.
#[pallet::config]
pub trait Config: frame_system::Config {
/// Because this pallet emits events, it depends on the runtime's definition of an event.
type Event: From<Event<Self>> + IsType<<Self as frame_system::Config>::Event>;
type MaxBytesInHash: Get<u32>;
type PoeLen: AtLeast32Bit + Copy + Parameter + Default + Bounded + MaxEncodedLen;
type Currency: ReservableCurrency<Self::AccountId>;
#[pallet::constant]
type PeoPrice: Get<BalanceOf<Self>>;
}
// Pallets use events to inform users when important changes are made.
// https://docs.substrate.io/v3/runtime/events-and-errors
#[pallet::event]
#[pallet::generate_deposit(pub(super) fn deposit_event)]
pub enum Event<T: Config> {
/// Event emitted when a proof has been claimed. [who, claim]
ClaimCreated(T::AccountId, BoundedVec<T::PoeLen, T::MaxBytesInHash>),
/// Event emitted when a claim is revoked by the owner. [who, claim]
ClaimRevoked(T::AccountId, BoundedVec<T::PoeLen, T::MaxBytesInHash>),
ClaimTransaction(T::AccountId, T::AccountId, BoundedVec<T::PoeLen, T::MaxBytesInHash>),
}
// Errors inform users that something went wrong.
#[pallet::error]
pub enum Error<T> {
/// The proof has already been claimed.
ProofAlreadyClaimed,
/// The proof does not exist, so it cannot be revoked.
NoSuchProof,
/// The proof is claimed by another account, so caller can't revoke it.
NotProofOwner,
}
//可调用函数
// Dispatchable functions allows users to interact with the pallet and invoke state changes.
// These functions materialize as "extrinsics", which are often compared to transactions.
// Dispatchable functions must be annotated with a weight and must return a DispatchResult.
#[pallet::call]
impl<T: Config> Pallet<T> {
#[pallet::weight(1_000)]
pub fn create_claim(
origin:OriginFor<T>,
proof:BoundedVec<T::PoeLen,T::MaxBytesInHash>,
) -> DispatchResult {
// 检查是否签名
let sender = ensure_signed(origin)?;
//检查 proof 是否已经被 claimed, 是的话 报错 ProofAlreadyClaimed
let poe_price = T::PeoPrice::get();
ensure!(!Proofs::<T>::contains_key(&proof),Error::<T>::ProofAlreadyClaimed);
// 质押主币
T::Currency::reserve(&who, poe_price)?;
// 获得当前的块号
let current_block = <frame_system::Pallet<T>>::block_number();
// 向 StorageMap 中插入
Proofs::<T>::insert(&proof, (&sender, current_block));
// 发送 ClaimCreated 通知
Self::deposit_event(Event::ClaimCreated(sender, proof));
Ok(())
}
#[pallet::weight(1_000)]
pub fn revole_claim(
origin:OriginFor<T>,
proof:BoundedVec<T::PoeLen,T::MaxBytesInHash>
)->DispatchResult{
let sender = ensure_signed(origin)?;
ensure!(Proofs::<T>::contains_key(&proof), Error::<T>::NoSuchProof);
let poe_price = T::PeoPrice::get();
// StorageMap 获得 value
let (owner, _) = Proofs::<T>::get(&proof).expect("All proofs must have an owner!");
ensure!(sender == owner, Error::<T>::NotProofOwner);
// 释放主币
T::Currency::unreserve(&who, poe_price);
Proofs::<T>::remove(&proof);
Self::deposit_event(Event::ClaimRevoked(sender, proof));
Ok(())
}
#[pallet::weight(1_000)]
pub fn transaction_claim(
origin:OriginFor<T>,
proof:BoundedVec<T::PoeLen,T::MaxBytesInHash>,
to_address:T::AccountId
)->DispatchResult{
let sender = ensure_signed(origin)?;
let poe_price = T::PeoPrice::get();
ensure!(Proofs::<T>::contains_key(&proof), Error::<T>::NoSuchProof);
// StorageMap 获得 value
let (owner, _) = Proofs::<T>::get(&proof).expect("All proofs must have an owner!");
ensure!(sender == owner, Error::<T>::NotProofOwner);
// 获得当前的块号
let current_block = <frame_system::Pallet<T>>::block_number();
Proofs::<T>::remove(&proof);
// 向 StorageMap 中插入
Proofs::<T>::insert(&proof, (&to_address, current_block));
Self::deposit_event(Event::ClaimTransaction(sender, to_address,proof));
Ok(())
}
}
////定义存证单元 可选择get函数
#[pallet::storage]
#[pallet::getter(fn proofs)]
pub(super) type Proofs<T:Config> = StorageMap<
_,
Blake2_128Concat,//key加密方式
BoundedVec<T::PoeLen,T::MaxBytesInHash>,//key
(T::AccountId,T::BlockNumber),//value
OptionQuery,//查询方式
>;
}
修改 runtime
impl pallet_poe::Config for Runtime {
type Event = Event;
type MaxBytesInHash = frame_support::traits::ConstU32<64>;
type PoeLen = u8;
type Currency = Balances;
type PeoPrice = ConstU128<512>;
}