Rust治理模块pallet-ranked-collective的使用:实现基于等级制度的链上集体决策与成员管理
Ranked collective system
这是一个提供Tally
实现的成员资格模块(pallet),可用于与Referenda模块等投票系统配合使用。每个成员都有一个等级,其中0是最低等级。系统中对每个等级的成员数量或等级总数没有复杂度限制,因此允许潜在的公共成员资格。
O(1)时间内可以随机选择至少给定等级的成员,这使得可以使用它作为原语构建各种游戏。成员一次只能晋升或降级一个等级,但所有操作(除一个外)都是O(1)复杂度。唯一不是O(1)的操作是remove_member
,因为他们必须从当前等级向下到0的所有等级中移除。
不同等级具有不同的投票权,并且能够参与不同的投票。一般来说,等级特权是累积的。较高等级能够参与较低等级开放的任何投票。同样,在任何给定的投票中,较高等级总是至少拥有与较低等级相同的投票权。
两个Config
特性项控制这些"等级特权":MinRankOfClass
和VoteWeight
。第一个控制哪些等级被允许参与特定类别的投票。第二个控制基于投票者等级与投票最低等级相比的投票权重。
一个源控制EnsureRank
确保源是至少特定等级的集体成员。
示例demo
以下是使用pallet-ranked-collective实现基于等级制度的链上集体决策与成员管理的完整示例:
// 引入必要的依赖
use frame_support::{parameter_types, traits::Everything};
use frame_system as system;
use pallet_ranked_collective as ranked_collective;
use sp_core::H256;
use sp_runtime::{
traits::{BlakeTwo256, IdentityLookup},
BuildStorage,
};
// 配置测试运行时
type Block = frame_system::mocking::MockBlock<Test>;
frame_support::construct_runtime!(
pub enum Test
{
System: frame_system,
RankedCollective: pallet_ranked_collective,
}
);
parameter_types! {
pub const BlockHashCount: u64 = 250;
pub const SS58Prefix: u8 = 42;
}
impl system::Config for Test {
type BaseCallFilter = Everything;
type BlockWeights = ();
type BlockLength = ();
type DbWeight = ();
type RuntimeOrigin = RuntimeOrigin;
type RuntimeCall = RuntimeCall;
type Nonce = u64;
type Hash = H256;
type Hashing = BlakeTwo256;
type AccountId = u64;
type Lookup = IdentityLookup<Self::AccountId>;
type Block = Block;
type RuntimeEvent = RuntimeEvent;
type BlockHashCount = BlockHashCount;
type Version = ();
type PalletInfo = PalletInfo;
type AccountData = ();
type OnNewAccount = ();
type OnKilledAccount = ();
type SystemWeightInfo = ();
type SS58Prefix = SS58Prefix;
type OnSetCode = ();
type MaxConsumers = frame_support::traits::ConstU32<16>;
}
parameter_types! {
pub const MinRankOfClass: ranked_collective::MinRankOfClass = ranked_collective::MinRankOfClass::new(0);
pub const VoteWeight: ranked_collective::VoteWeight = ranked_collective::VoteWeight::Linear;
}
impl ranked_collective::Config for Test {
type RuntimeEvent = RuntimeEvent;
type MinRankOfClass = MinRankOfClass;
type VoteWeight = VoteWeight;
type PromoteOrigin = frame_system::EnsureRoot<u64>;
type DemoteOrigin = frame_system::EnsureRoot<u64>;
type Polls = ();
}
// 测试代码
#[test]
fn test_ranked_collective() {
let mut ext = sp_io::TestExternalities::new(
frame_system::GenesisConfig::<Test>::default().build_storage().unwrap()
);
ext.execute_with(|| {
// 添加成员
assert_ok!(RankedCollective::add_member(RuntimeOrigin::root(), 1));
// 验证成员等级
assert_eq!(RankedCollective::rank_of(&1), Some(0));
// 提升成员等级
assert_ok!(RankedCollective::promote_member(RuntimeOrigin::root(), 1));
assert_eq!(RankedCollective::rank_of(&1), Some(1));
// 降级成员
assert_ok!(RankedCollective::demote_member(RuntimeOrigin::root(), 1));
assert_eq!(RankedCollective::rank_of(&1), Some(0));
// 移除成员
assert_ok!(RankedCollective::remove_member(RuntimeOrigin::root(), 1, 0));
assert_eq!(RankedCollective::rank_of(&1), None);
});
}
这个示例展示了如何:
- 配置pallet-ranked-collective
- 添加新成员
- 提升成员等级
- 降级成员
- 移除成员
您可以根据实际需求调整配置参数和测试用例。
1 回复
Rust治理模块pallet-ranked-collective使用指南
完整示例Demo
下面是一个完整的pallet-ranked-collective使用示例,展示了从模块引入到基本操作的全流程:
// 1. 在runtime中引入模块
use frame_support::{dispatch::DispatchResult, traits::EnsureOrigin};
use frame_system::Config as SystemConfig;
// 自定义Polls实现
pub struct DemoPolls;
impl pallet_ranked_collective::Polls for DemoPolls {
type Index = u32;
type Votes = u32;
type Moment = u64;
type Proposal = Box<<Runtime as frame_system::Config>::RuntimeCall>;
fn create_proposal(proposal: Self::Proposal) -> Result<Self::Index, DispatchError> {
// 简单实现:使用递增索引
static mut INDEX: u32 = 0;
unsafe {
INDEX += 1;
Ok(INDEX)
}
}
fn vote_weight(index: Self::Index) -> Result<Self::Votes, DispatchError> {
// 简单实现:每个提案权重相同
Ok(1)
}
// ...其他必要方法实现
}
// 配置RankedCollective pallet
impl pallet_ranked_collective::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type PromoteOrigin = frame_system::EnsureRoot<AccountId>; // 仅root可以晋升成员
type DemoteOrigin = frame_system::EnsureRoot<AccountId>; // 仅root可以降级成员
type Polls = DemoPolls; // 使用我们自定义的Polls实现
type WeightInfo = ();
}
// 2. 基本操作示例
fn demo() -> DispatchResult {
let root = RuntimeOrigin::root();
let alice = 1;
let bob = 2;
let charlie = 3;
// 添加初始成员
RankedCollective::add_member(root.clone(), alice)?;
RankedCollective::add_member(root.clone(), bob)?;
// 晋升Alice到等级2
RankedCollective::promote_member(root.clone(), alice)?;
// Alice创建提案
let proposal = RuntimeCall::System(frame_system::Call::remark {
remark: b"Demo proposal".to_vec()
});
let proposal_hash = proposal.blake2_256();
RankedCollective::submit_proposal(
RuntimeOrigin::signed(alice),
Box::new(proposal),
2, // 需要至少等级2的成员投票
)?;
// Bob投票赞成
RankedCollective::vote(
RuntimeOrigin::signed(bob),
proposal_hash,
0,
true,
)?;
// Charlie加入并尝试投票(会失败,因为Charlie不是成员)
assert!(RankedCollective::vote(
RuntimeOrigin::signed(charlie),
proposal_hash,
0,
true,
).is_err());
// 执行提案
RankedCollective::execute_proposal(
RuntimeOrigin::signed(alice),
proposal_hash,
0,
)?;
Ok(())
}
进阶示例:自定义治理规则
下面展示如何自定义晋升规则和投票权重:
// 自定义晋升规则 - 需要至少3个高级成员批准
pub struct PromoteOrigin;
impl<OuterOrigin, AccountId> EnsureOrigin<OuterOrigin> for PromoteOrigin
where
OuterOrigin: Into<Result<RawOrigin<AccountId>, OuterOrigin>> + From<RawOrigin<AccountId>>,
AccountId: PartialEq + Clone,
{
type Success = ();
fn try_origin(o: OuterOrigin) -> Result<Self::Success, OuterOrigin> {
// 实现自定义逻辑:检查是否至少有3个高级成员签名
// 这里简化实现,实际需要更复杂的检查
Ok(())
}
}
// 自定义投票权重 - 基于成员等级
pub struct WeightedPolls;
impl pallet_ranked_collective::Polls for WeightedPolls {
type Index = u32;
type Votes = u64; // 使用更大范围表示权重
type Moment = u64;
type Proposal = Box<<Runtime as frame_system::Config>::RuntimeCall>;
fn create_proposal(proposal: Self::Proposal) -> Result<Self::Index, DispatchError> {
// 提案创建逻辑
Ok(1)
}
fn vote_weight(index: Self::Index) -> Result<Self::Votes, DispatchError> {
// 获取投票者等级,等级越高权重越大
let voter = frame_system::Pallet::<Runtime>::caller();
let rank = RankedCollective::rank_of(&voter).unwrap_or(0);
Ok((rank * rank) as u64) // 权重=等级²
}
}
// 配置使用自定义规则
impl pallet_ranked_collective::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type PromoteOrigin = PromoteOrigin; // 使用自定义晋升规则
type DemoteOrigin = frame_system::EnsureRoot<AccountId>;
type Polls = WeightedPolls; // 使用加权投票
type WeightInfo = ();
}
测试用例示例
#[test]
fn test_ranked_collective_workflow() {
new_test_ext().execute_with(|| {
// 初始化账户
let root = Origin::root();
let alice = 1;
// 测试添加成员
assert_ok!(RankedCollective::add_member(root.clone(), alice));
assert_eq!(RankedCollective::rank_of(&alice), Some(1));
// 测试提案提交
let proposal = Box::new(Call::System(frame_system::Call::remark { remark: vec![1] }));
assert_ok!(RankedCollective::submit_proposal(
Origin::signed(alice),
proposal,
1
));
// 测试投票
let proposal_hash = BlakeTwo256::hash_of(&proposal);
assert_ok!(RankedCollective::vote(
Origin::signed(alice),
proposal_hash,
0,
true
));
// 测试提案执行
assert_ok!(RankedCollective::execute_proposal(
Origin::signed(alice),
proposal_hash,
0
));
});
}