Rust治理模块pallet-ranked-collective的使用:实现基于等级制度的链上集体决策与成员管理

Ranked collective system

这是一个提供Tally实现的成员资格模块(pallet),可用于与Referenda模块等投票系统配合使用。每个成员都有一个等级,其中0是最低等级。系统中对每个等级的成员数量或等级总数没有复杂度限制,因此允许潜在的公共成员资格。

O(1)时间内可以随机选择至少给定等级的成员,这使得可以使用它作为原语构建各种游戏。成员一次只能晋升或降级一个等级,但所有操作(除一个外)都是O(1)复杂度。唯一不是O(1)的操作是remove_member,因为他们必须从当前等级向下到0的所有等级中移除。

不同等级具有不同的投票权,并且能够参与不同的投票。一般来说,等级特权是累积的。较高等级能够参与较低等级开放的任何投票。同样,在任何给定的投票中,较高等级总是至少拥有与较低等级相同的投票权。

两个Config特性项控制这些"等级特权":MinRankOfClassVoteWeight。第一个控制哪些等级被允许参与特定类别的投票。第二个控制基于投票者等级与投票最低等级相比的投票权重。

一个源控制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);
    });
}

这个示例展示了如何:

  1. 配置pallet-ranked-collective
  2. 添加新成员
  3. 提升成员等级
  4. 降级成员
  5. 移除成员

您可以根据实际需求调整配置参数和测试用例。


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
        ));
    });
}
回到顶部