Skip to content

Commit

Permalink
pallet ranked collective: max member count per rank (paritytech#4807)
Browse files Browse the repository at this point in the history
Configuration for the maximum member count per rank, with the option for
no limit.
  • Loading branch information
muharem authored and TarekkMA committed Aug 2, 2024
1 parent 863fc17 commit a4de1fe
Show file tree
Hide file tree
Showing 9 changed files with 78 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ impl pallet_ranked_collective::Config<AmbassadorCollectiveInstance> for Runtime
type MinRankOfClass = sp_runtime::traits::Identity;
type MemberSwappedHandler = (crate::AmbassadorCore, crate::AmbassadorSalary);
type VoteWeight = pallet_ranked_collective::Linear;
type MaxMemberCount = ();
#[cfg(feature = "runtime-benchmarks")]
type BenchmarkSetup = (crate::AmbassadorCore, crate::AmbassadorSalary);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ impl pallet_ranked_collective::Config<FellowshipCollectiveInstance> for Runtime
type MinRankOfClass = tracks::MinRankOfClass;
type MemberSwappedHandler = (crate::FellowshipCore, crate::FellowshipSalary);
type VoteWeight = pallet_ranked_collective::Geometric;
type MaxMemberCount = ();
#[cfg(feature = "runtime-benchmarks")]
type BenchmarkSetup = (crate::FellowshipCore, crate::FellowshipSalary);
}
Expand Down
1 change: 1 addition & 0 deletions polkadot/runtime/rococo/src/governance/fellowship.rs
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,7 @@ impl pallet_ranked_collective::Config<FellowshipCollectiveInstance> for Runtime
type MinRankOfClass = sp_runtime::traits::Identity;
type MemberSwappedHandler = ();
type VoteWeight = pallet_ranked_collective::Geometric;
type MaxMemberCount = ();
#[cfg(feature = "runtime-benchmarks")]
type BenchmarkSetup = ();
}
11 changes: 11 additions & 0 deletions prdoc/pr_4807.prdoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
title: "pallet ranked collective: max member count per rank"

doc:
- audience: Runtime Dev
description: |
Configuration for the maximum member count per rank, with the option for no limit.

crates:
- name: pallet-ranked-collective
bump: major

1 change: 1 addition & 0 deletions substrate/bin/node/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1038,6 +1038,7 @@ impl pallet_ranked_collective::Config for Runtime {
type MinRankOfClass = traits::Identity;
type VoteWeight = pallet_ranked_collective::Geometric;
type MemberSwappedHandler = (CoreFellowship, Salary);
type MaxMemberCount = ();
#[cfg(feature = "runtime-benchmarks")]
type BenchmarkSetup = (CoreFellowship, Salary);
}
Expand Down
1 change: 1 addition & 0 deletions substrate/frame/core-fellowship/src/tests/integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ impl pallet_ranked_collective::Config for Test {
type MinRankOfClass = MinRankOfClass<MinRankOfClassDelta>;
type MemberSwappedHandler = CoreFellowship;
type VoteWeight = Geometric;
type MaxMemberCount = ();
#[cfg(feature = "runtime-benchmarks")]
type BenchmarkSetup = CoreFellowship;
}
Expand Down
19 changes: 19 additions & 0 deletions substrate/frame/ranked-collective/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,7 @@ pub mod pallet {
use super::*;
use frame_support::{pallet_prelude::*, storage::KeyLenOf};
use frame_system::pallet_prelude::*;
use sp_runtime::traits::MaybeConvert;

#[pallet::pallet]
pub struct Pallet<T, I = ()>(PhantomData<(T, I)>);
Expand Down Expand Up @@ -431,6 +432,14 @@ pub mod pallet {
/// in the poll.
type VoteWeight: Convert<Rank, Votes>;

/// The maximum number of members for a given rank in the collective.
///
/// The member at rank `x` contributes to the count at rank `x` and all ranks below it.
/// Therefore, the limit `m` at rank `x` sets the maximum total member count for rank `x`
/// and all ranks above.
/// The `None` indicates no member count limit for the given rank.
type MaxMemberCount: MaybeConvert<Rank, MemberIndex>;

/// Setup a member for benchmarking.
#[cfg(feature = "runtime-benchmarks")]
type BenchmarkSetup: BenchmarkSetup<Self::AccountId>;
Expand Down Expand Up @@ -511,6 +520,8 @@ pub mod pallet {
NoPermission,
/// The new member to exchange is the same as the old member
SameMember,
/// The max member count for the rank has been reached.
TooManyMembers,
}

#[pallet::call]
Expand Down Expand Up @@ -758,6 +769,9 @@ pub mod pallet {
ensure!(!Members::<T, I>::contains_key(&who), Error::<T, I>::AlreadyMember);
let index = MemberCount::<T, I>::get(0);
let count = index.checked_add(1).ok_or(Overflow)?;
if let Some(max) = T::MaxMemberCount::maybe_convert(0) {
ensure!(count <= max, Error::<T, I>::TooManyMembers);
}

Members::<T, I>::insert(&who, MemberRecord { rank: 0 });
IdToIndex::<T, I>::insert(0, &who, index);
Expand All @@ -784,6 +798,11 @@ pub mod pallet {
ensure!(max_rank >= rank, Error::<T, I>::NoPermission);
}
let index = MemberCount::<T, I>::get(rank);
let count = index.checked_add(1).ok_or(Overflow)?;
if let Some(max) = T::MaxMemberCount::maybe_convert(rank) {
ensure!(count <= max, Error::<T, I>::TooManyMembers);
}

MemberCount::<T, I>::insert(rank, index.checked_add(1).ok_or(Overflow)?);
IdToIndex::<T, I>::insert(rank, &who, index);
IndexToId::<T, I>::insert(rank, index, &who);
Expand Down
43 changes: 42 additions & 1 deletion substrate/frame/ranked-collective/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use frame_support::{
};
use sp_core::Get;
use sp_runtime::{
traits::{ReduceBy, ReplaceWithDefault},
traits::{MaybeConvert, ReduceBy, ReplaceWithDefault},
BuildStorage,
};

Expand Down Expand Up @@ -148,6 +148,17 @@ impl<Delta: Get<Rank>> Convert<Class, Rank> for MinRankOfClass<Delta> {
}
}

pub struct MaxMemberCount;
impl MaybeConvert<Rank, MemberIndex> for MaxMemberCount {
fn maybe_convert(a: Rank) -> Option<MemberIndex> {
if a == 11 {
Some(2)
} else {
None
}
}
}

parameter_types! {
pub static MinRankOfClassDelta: Rank = 0;
}
Expand Down Expand Up @@ -179,6 +190,7 @@ impl Config for Test {
type MinRankOfClass = MinRankOfClass<MinRankOfClassDelta>;
type MemberSwappedHandler = ();
type VoteWeight = Geometric;
type MaxMemberCount = MaxMemberCount;
#[cfg(feature = "runtime-benchmarks")]
type BenchmarkSetup = ();
}
Expand Down Expand Up @@ -645,3 +657,32 @@ fn exchange_member_same_noops() {
);
});
}

#[test]
fn max_member_count_works() {
ExtBuilder::default().build_and_execute(|| {
assert_ok!(Club::do_add_member_to_rank(1, 10, false));
assert_ok!(Club::do_add_member_to_rank(2, 10, false));
assert_ok!(Club::do_add_member_to_rank(3, 10, false));
assert_eq!(member_count(10), 3);
assert_eq!(member_count(11), 0);

assert_ok!(Club::promote_member(RuntimeOrigin::root(), 1));
assert_ok!(Club::promote_member(RuntimeOrigin::root(), 2));
assert_noop!(Club::promote_member(RuntimeOrigin::root(), 3), Error::<Test>::TooManyMembers);
assert_eq!(member_count(10), 3);
assert_eq!(member_count(11), 2);

assert_ok!(Club::demote_member(RuntimeOrigin::root(), 1));
assert_ok!(Club::promote_member(RuntimeOrigin::root(), 3));
assert_eq!(member_count(10), 3);
assert_eq!(member_count(11), 2);

assert_ok!(Club::promote_member(RuntimeOrigin::root(), 2));
assert_ok!(Club::promote_member(RuntimeOrigin::root(), 3));
assert_noop!(Club::promote_member(RuntimeOrigin::root(), 1), Error::<Test>::TooManyMembers);
assert_eq!(member_count(10), 3);
assert_eq!(member_count(11), 2);
assert_eq!(member_count(12), 2);
});
}
1 change: 1 addition & 0 deletions substrate/frame/salary/src/tests/integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ impl pallet_ranked_collective::Config for Test {
type MinRankOfClass = MinRankOfClass<MinRankOfClassDelta>;
type MemberSwappedHandler = Salary;
type VoteWeight = Geometric;
type MaxMemberCount = ();
#[cfg(feature = "runtime-benchmarks")]
type BenchmarkSetup = Salary;
}
Expand Down

0 comments on commit a4de1fe

Please sign in to comment.