Rust区块链插件库pallet-collator-selection的使用,实现波卡平行链节点选择与治理功能
Rust区块链插件库pallet-collator-selection的使用,实现波卡平行链节点选择与治理功能
安装
在项目目录中运行以下Cargo命令:
cargo add pallet-collator-selection
或者在Cargo.toml中添加以下行:
pallet-collator-selection = "23.0.0"
示例代码
以下是如何使用pallet-collator-selection实现波卡平行链节点选择与治理功能的完整示例:
// 引入必要的依赖和模块
use frame_support::{
traits::{Currency, OnInitialize},
weights::Weight,
};
use frame_system::Config as SystemConfig;
use pallet_collator_selection::{Config, Error};
use sp_runtime::traits::Convert;
use sp_std::prelude::*;
// 定义Runtime配置
pub trait Config: frame_system::Config {
/// 用于抵押的货币类型
type Currency: Currency<Self::AccountId>;
/// 事件类型
type Event: From<Event<Self>> + Into<<Self as frame_system::Config>::Event>;
/// 将金额转换为权重
type CurrencyToVote: Convert<BalanceOf<Self>, VoteWeight>;
/// 候选人数量上限
#[pallet::constant]
type MaxCandidates: Get<u32>;
/// 候选人最低抵押金额
#[pallet::constant]
type MinCollatorStake: Get<BalanceOf<Self>>;
/// 最大候选人数
#[pallet::constant]
type MaxInvulnerables: Get<u32>;
/// 踢出不活跃的收集者
type KickThreshold: Get<Self::BlockNumber>;
}
// 实现收集者选择模块
#[frame_support::pallet]
pub mod pallet {
use super::*;
#[pallet::config]
pub trait Config: frame極system::Config {
// 同上配置
}
#[pallet::pallet]
#[pallet::generate_store(pub(super) trait Store)]
pub struct Pallet<T>(_);
#[pallet::storage]
#[pallet::getter(fn candidates)]
pub type Candidates<T: Config> = StorageValue<_, Vec<T::AccountId>, ValueQuery>;
#[pallet::storage]
#[pallet::getter(fn invulnerables)]
pub type Invulnerables<T: Config> = StorageValue<_, Vec<T::AccountId>, ValueQuery>;
#[pallet::event]
#[pallet::metadata(T::AccountId = "AccountId")]
#[pallet::generate_deposit(pub(super) fn deposit_event)]
pub enum Event<T: Config> {
/// 新的收集者被添加
NewInvulnerable(T::AccountId),
/// 收集者被移除
InvulnerableRemoved(T::AccountId),
/// 新的候选人
CandidateAdded(T::AccountId),
/// 候选人被移除
CandidateRemoved(T::AccountId),
}
#[pallet::error]
pub enum Error<T> {
/// 账户已经是收集者
AlreadyInvulnerable,
/// 账户已经是候选人
AlreadyCandidate,
/// 账户不是收集者
NotInvulnerable,
/// 账户不是候选人
NotCandidate,
/// 候选人数量已达上限
TooManyCandidates,
/// 抵押金额不足
InsufficientStake,
}
#[pallet::call]
impl<T: Config> Pallet<T> {
/// 添加固定收集者
#[pallet::weight(10_000)]
pub fn add_invulnerable(origin: OriginFor<T>, account: T::AccountId) -> DispatchResult {
ensure_root(origin)?;
let mut invulnerables = Self::invulnerables();
if invulnerables.contains(&account) {
return Err(Error::<T>::AlreadyInvulnerable.into());
}
invulnerables.push(account.clone());
<Invulnerables<T>>::put(invulnerables);
Self::deposit_event(Event::NewInvulnerable(account));
Ok(().into())
}
/// 移除固定收集者
#[pallet::weight极10_000)]
pub fn remove_invulnerable(origin: OriginFor<T>, account: T::AccountId) -> DispatchResult {
ensure_root(origin)?;
let mut invulnerables = Self::invulnerables();
if !invulnerables.contains(&account) {
return Err(Error::<T>::NotInvulnerable.into());
}
invulnerables.retain(|a| a != &account);
<Invulnerables<T>>::put(invulnerables);
Self::deposit_event(Event::InvulnerableRemoved(account));
Ok(().into())
}
/// 注册为候选人
#[pallet::weight(10_000)]
pub fn register_as_candidate(origin: OriginFor<T>) -> DispatchResult {
let who = ensure_signed(origin)?;
// 检查是否已经是候选人
let mut candidates = Self::candidates();
if candidates.contains(&who) {
return Err(Error::<T>::AlreadyCandidate.into());
}
// 检查候选人数量限制
if candidates.len() >= T::MaxCandidates::get() as usize {
return Err(Error::<T>::TooManyCandidates.into());
}
// 检查抵押金额是否足够
let stake = T::Currency::free_balance(&who);
if stake < T::MinCollatorStake::get() {
return Err(Error::<极T>::InsufficientStake.into());
}
candidates.push(who.clone());
<Candidates<T>>::put(candidates);
Self::deposit_event(Event::CandidateAdded(who));
Ok(().into())
}
/// 退出候选人
#[pallet::weight(10_000)]
pub fn leave_candidates(origin: OriginFor<T>) -> DispatchResult {
let who = ensure_signed(origin)?;
let mut candidates = Self::candidates();
if !candidates.contains(&who) {
return Err(Error::<T>::NotCandidate.into());
}
candidates.retain(|a| a != &who);
<Candidates<T>>::put(candidates);
Self::deposit_event(Event::CandidateRemoved(who));
Ok(().into())
}
}
#[pallet::hooks]
impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
fn on_initialize(_n: BlockNumberFor<T>) -> Weight {
// 在此可以执行定期清理或更新收集者列表的逻辑
0
}
}
}
// 实现收集者选择逻辑
impl<T: Config> pallet_collator_selection::Config for Runtime {
type Event = Event;
type Currency = Balances;
type CurrencyToVote = ();
type MaxCandidates = MaxCandidates;
type MinCollatorStake = MinCollatorStake;
type MaxInvulnerables = MaxInvulnerables;
type KickThreshold = KickThreshold;
}
// 在Runtime构建器中集成模块
construct_runtime!(
pub enum Runtime where
Block = Block,
NodeBlock = opaque::Block,
UncheckedExtrinsic = UncheckedExtrinsic
{
// 其他模块...
CollatorSelection: pallet_collator_selection::{Module, Call, Storage, Event<T>},
}
);
功能说明
- 固定收集者(Invulnerables):由治理(root)直接指定的永久收集者,通常用于链的初始阶段
- 候选人(Candidates):通过抵押代币成为候选收集者的账户,可以被选为活跃收集者
- 抵押要求:候选人需要满足最低抵押金额要求
- 动态调整:治理可以随时添加或移除固定收集者
- 自动选择:系统会根据抵押金额等因素自动选择活跃收集者
使用场景
- 链启动时添加初始收集者:
CollatorSelection::add_invulnerable(origin, account);
- 用户注册为收集者候选人:
CollatorSelection::register_as_candidate(origin);
- 治理移除不活跃收集者:
CollatorSelection::remove_invulnerable(origin, account);
- 候选人退出:
CollatorSelection::leave_candidates(origin);
这个示例展示了如何在波卡平行链中实现收集者(节点)的选择与治理功能,包括固定收集者的管理、候选人的注册与退出等核心功能。
1 回复
Rust区块链插件库pallet-collator-selection的使用指南
概述
pallet-collator-selection
是Substrate框架中的一个重要模块,专门用于波卡(Polkadot)平行链中的验证人(collator)选择与管理。该模块实现了平行链节点的选择机制和治理功能,是构建波卡平行链的关键组件。
主要功能
- 管理平行链验证人集合
- 实现验证人选择算法
- 提供验证人治理功能
- 处理验证人权益和奖励
使用方法
1. 引入依赖
[dependencies]
pallet-collator-selection = { git = "https://github.com/paritytech/substrate", branch = "polkadot-vX.Y.Z" }
2. 配置Runtime
impl pallet_collator_selection::Config for Runtime {
type Event = Event;
type Currency = Balances;
type UpdateOrigin = EnsureRoot<AccountId>;
type KickThreshold = KickThreshold;
type ValidatorId = <Self as frame_system::Config>::AccountId;
type ValidatorIdOf = pallet_collator_selection::IdentityCollator;
type WeightInfo = ();
}
3. 添加到Runtime
construct_runtime!(
pub enum Runtime where
Block = Block,
NodeBlock = opaque::Block,
UncheckedExtrinsic = UncheckedExtrinsic
{
CollatorSelection: pallet_collator_selection::{Module, Call, Storage, Event<T>},
}
);
完整示例代码
// 1. 定义Runtime配置
pub struct Runtime;
pub type AccountId = u64;
pub type Balance = u128;
// 模拟一些基础类型
mod frame_system {
pub trait Config {
type AccountId;
}
}
mod pallet_balances {
pub trait Config {
type Balance;
}
}
// 2. 实现必要的trait
impl frame_system::Config for Runtime {
type AccountId = AccountId;
}
impl pallet_balances::Config for Runtime {
type Balance = Balance;
}
// 3. 定义参数类型
parameter_types! {
pub const KickThreshold: u32 = 5;
}
// 4. 实现collator-selection配置
impl pallet_collator_selection::Config for Runtime {
type Event = ();
type Currency = pallet_balances;
type UpdateOrigin = frame_system::EnsureRoot<AccountId>;
type KickThreshold = KickThreshold;
type ValidatorId = AccountId;
type ValidatorIdOf = pallet_collator_selection::IdentityCollator;
type WeightInfo = ();
}
// 5. 测试用例
#[test]
fn test_collator_selection() {
use pallet_collator_selection::{Call, Pallet as CollatorSelection};
// 初始化测试环境
let mut ext = sp_io::TestExternalities::new_empty();
ext.execute_with(|| {
// 设置初始验证人
let initial_collators = vec![1, 2, 3]; // 账户ID
// 设置候选人保证金
let _ = Call::<Runtime>::set_candidacy_bond(100);
// 设置期望候选人数量
let _ = Call::<Runtime>::set_desired_candidates(3);
// 设置不可移除的验证人
let _ = Call::<Runtime>::set_invulnerables(initial_collators.clone());
// 查询验证人
let collators = CollatorSelection::<Runtime>::invulnerables();
assert_eq!(collators, initial_collators);
// 账户4申请成为候选人
let _ = Call::<Runtime>::register_as_candidate();
// 查询候选人
let candidates = CollatorSelection::<Runtime>::candidates();
assert!(candidates.len() > 0);
// 移除验证人(需要root权限)
let _ = Call::<Runtime>::remove_invulnerable(1);
});
}
事件监听示例
// 监听collator-selection事件
pub fn handle_collator_events(event: pallet_collator_selection::Event<Runtime>) {
match event {
pallet_collator_selection::Event::NewInvulnerable(collator) => {
println!("新的验证人加入: {:?}", collator);
},
pallet_collator_selection::Event::InvulnerableRemoved(collator) => {
println!("验证人被移除: {:?}", collator);
},
_ => {}
}
}
最佳实践
- 合理设置
desired_candidates
数量,平衡去中心化和性能 - 实现适当的抵押机制防止女巫攻击
- 定期轮换验证人以增强安全性
- 监控验证人性能并移除表现不佳的节点