【Substrate 第一行代码】 pallet 通过 runtime 传递类型

170 阅读2分钟

上一篇文章编写了存证 pallet 模块,存证单元设置的是 BoundedVec<u8,u32> ,为了使 pallet 更加通用,将 poe 模块修改通过 runtime 设置存证长度限制。(类似于 java 的泛型接口)

修改 config

在 pallet 模板代码3 的位置上通过注释可以看到通过指定 Config 的参数和类型来配置pallet。

#[pallet::config] 
pub trait Config: frame_system::Config { 
    type Event: From<Event<Self>> + IsType<<Self as frame_system::Config>::Event>; 
    
    type MaxBytesInHash: Get<u32>;
    
    type PoeLen: AtLeast32Bit + Copy + Parameter + Default + Bounded + MaxEncodedLen; 
 }

使用 Config 的参数


	// 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]
        //(1)
        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>,
                        //(2)
			proof:BoundedVec<T::PoeLen,T::MaxBytesInHash>,
		) -> DispatchResult {
			// 检查是否签名
			let sender = ensure_signed(origin)?;
			//检查 proof 是否已经被 claimed, 是的话 报错 ProofAlreadyClaimed
			ensure!(!Proofs::<T>::contains_key(&proof),Error::<T>::ProofAlreadyClaimed);
			// 获得当前的块号
			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>,
                        //(2)
			proof:BoundedVec<T::PoeLen,T::MaxBytesInHash>
		)->DispatchResult{
			let sender = ensure_signed(origin)?;
			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);

			Proofs::<T>::remove(&proof);

			Self::deposit_event(Event::ClaimRevoked(sender, proof));
			Ok(())
		}
		#[pallet::weight(1_000)]
		pub fn transaction_claim(
			origin:OriginFor<T>,
                        //(2)
			proof:BoundedVec<T::PoeLen,T::MaxBytesInHash>,
			to_address:T::AccountId
		)->DispatchResult{
			let sender = ensure_signed(origin)?;
			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加密方式
                //(3)
		BoundedVec<T::PoeLen,T::MaxBytesInHash>,//key
		(T::AccountId,T::BlockNumber),//value
		OptionQuery,//查询方式
	>;

代码中分别展示了在不同位置使用 config 的实例 (1) ClaimCreated(T::AccountId, BoundedVec<u8, u32>), 改成了 ClaimCreated(T::AccountId, BoundedVec<T::PoeLen, T::MaxBytesInHash>) (2) 展示了如何在 pallet:call 中使用 (3) 展示在 storage 中使用

都是相同的 因为定义声明使用了 <T: Config> 所以可以通过 T 来使用到 Config 里的参数。

在 runtime 指定 config 的参数具体类类型

把之前

impl pallet_poe::Config for Runtime { type Event = Event; }

修改成

impl pallet_poe::Config for Runtime {
	type Event = Event;
	type MaxBytesInHash = frame_support::traits::ConstU32<64>;
        type PoeLen = u8;
}