Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Removing without_storage_info from scored-pool pallet. #11996

Merged
merged 12 commits into from
Sep 8, 2022
61 changes: 43 additions & 18 deletions frame/scored-pool/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,18 +98,24 @@ mod mock;
#[cfg(test)]
mod tests;

use codec::FullCodec;
use codec::{FullCodec, MaxEncodedLen};
use frame_support::{
ensure,
traits::{ChangeMembers, Currency, Get, InitializeMembers, ReservableCurrency},
BoundedVec,
};
pub use pallet::*;
use sp_runtime::traits::{AtLeast32Bit, StaticLookup, Zero};
use sp_std::{fmt::Debug, prelude::*};

type BalanceOf<T, I> =
<<T as Config<I>>::Currency as Currency<<T as frame_system::Config>::AccountId>>::Balance;
type PoolT<T, I> = Vec<(<T as frame_system::Config>::AccountId, Option<<T as Config<I>>::Score>)>;
type PoolT<T, I> = BoundedVec<
(<T as frame_system::Config>::AccountId, Option<<T as Config<I>>::Score>),
<T as Config<I>>::MaximumMembers,
>;
type MembersT<T, I> =
BoundedVec<<T as frame_system::Config>::AccountId, <T as Config<I>>::MaximumMembers>;

/// The enum is supplied when refreshing the members set.
/// Depending on the enum variant the corresponding associated
Expand All @@ -129,14 +135,17 @@ pub mod pallet {

#[pallet::pallet]
#[pallet::generate_store(pub(super) trait Store)]
#[pallet::without_storage_info]
pub struct Pallet<T, I = ()>(_);

#[pallet::config]
pub trait Config<I: 'static = ()>: frame_system::Config {
/// The currency used for deposits.
type Currency: Currency<Self::AccountId> + ReservableCurrency<Self::AccountId>;

/// Maximum members length allowed.
#[pallet::constant]
type MaximumMembers: Get<u32>;
ggwpez marked this conversation as resolved.
Show resolved Hide resolved

/// The score attributed to a member or candidate.
type Score: AtLeast32Bit
+ Clone
Expand All @@ -145,7 +154,8 @@ pub mod pallet {
+ FullCodec
+ MaybeSerializeDeserialize
+ Debug
+ scale_info::TypeInfo;
+ scale_info::TypeInfo
+ MaxEncodedLen;

/// The overarching event type.
type Event: From<Event<Self, I>> + IsType<<Self as frame_system::Config>::Event>;
Expand Down Expand Up @@ -206,9 +216,11 @@ pub mod pallet {
InvalidIndex,
/// Index does not match requested account.
WrongAccountIndex,
/// Number of members exceeds `MaximumMembers`.
TooManyMembers,
}

/// The current pool of candidates, stored as an ordered Vec
/// The current pool of candidates, stored as an ordered Bounded Vec
/// (ordered descending by score, `None` last, highest first).
#[pallet::storage]
#[pallet::getter(fn pool)]
Expand All @@ -228,7 +240,7 @@ pub mod pallet {
#[pallet::storage]
#[pallet::getter(fn members)]
pub(crate) type Members<T: Config<I>, I: 'static = ()> =
StorageValue<_, Vec<T::AccountId>, ValueQuery>;
StorageValue<_, MembersT<T, I>, ValueQuery>;

/// Size of the `Members` set.
#[pallet::storage]
Expand Down Expand Up @@ -262,10 +274,10 @@ pub mod pallet {
});

// Sorts the `Pool` by score in a descending order. Entities which
// have a score of `None` are sorted to the beginning of the vec.
// have a score of `None` are sorted to the end of the bounded vec.
pool.sort_by_key(|(_, maybe_score)| Reverse(maybe_score.unwrap_or_default()));

<MemberCount<T, I>>::put(self.member_count);
<Pallet<T, I>>::update_member_count(self.member_count)
.expect("Number of allowed members exceeded");
<Pool<T, I>>::put(&pool);
<Pallet<T, I>>::refresh_members(pool, ChangeReceiver::MembershipInitialized);
}
Expand Down Expand Up @@ -307,7 +319,8 @@ pub mod pallet {

// can be inserted as last element in pool, since entities with
// `None` are always sorted to the end.
ggwpez marked this conversation as resolved.
Show resolved Hide resolved
<Pool<T, I>>::append((who.clone(), Option::<<T as Config<I>>::Score>::None));
<Pool<T, I>>::try_append((who.clone(), Option::<<T as Config<I>>::Score>::None))
.map_err(|_| Error::<T, I>::TooManyMembers)?;

<CandidateExists<T, I>>::insert(&who, true);

Expand Down Expand Up @@ -393,7 +406,7 @@ pub mod pallet {
Reverse(maybe_score.unwrap_or_default())
})
.unwrap_or_else(|l| l);
pool.insert(location, item);
pool.try_insert(location, item).map_err(|_| Error::<T, I>::TooManyMembers)?;

<Pool<T, I>>::put(&pool);
Self::deposit_event(Event::<T, I>::CandidateScored);
Expand All @@ -409,7 +422,7 @@ pub mod pallet {
#[pallet::weight(0)]
pub fn change_member_count(origin: OriginFor<T>, count: u32) -> DispatchResult {
ensure_root(origin)?;
MemberCount::<T, I>::put(&count);
Self::update_member_count(count).map_err(|_| Error::<T, I>::TooManyMembers)?;
ggwpez marked this conversation as resolved.
Show resolved Hide resolved
Ok(())
}
}
Expand All @@ -423,23 +436,28 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
/// type function to invoke at the end of the method.
fn refresh_members(pool: PoolT<T, I>, notify: ChangeReceiver) {
let count = MemberCount::<T, I>::get();
let old_members = <Members<T, I>>::get();

let mut new_members: Vec<T::AccountId> = pool
let new_members: Vec<T::AccountId> = pool
.into_iter()
.filter(|(_, score)| score.is_some())
.take(count as usize)
.map(|(account_id, _)| account_id)
.collect();
new_members.sort();

let old_members = <Members<T, I>>::get();
<Members<T, I>>::put(&new_members);
// It's safe to truncate_from at this point since MemberCount
// is verified that it does not exceed the MaximumMembers value
let mut new_members_bounded: MembersT<T, I> = BoundedVec::truncate_from(new_members);
ggwpez marked this conversation as resolved.
Show resolved Hide resolved

new_members_bounded.sort();

<Members<T, I>>::put(&new_members_bounded);

match notify {
ChangeReceiver::MembershipInitialized =>
T::MembershipInitialized::initialize_members(&new_members),
T::MembershipInitialized::initialize_members(&new_members_bounded),
ChangeReceiver::MembershipChanged =>
T::MembershipChanged::set_members_sorted(&new_members[..], &old_members[..]),
T::MembershipChanged::set_members_sorted(&new_members_bounded[..], &old_members[..]),
}
}

Expand Down Expand Up @@ -485,4 +503,11 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {

Ok(())
}

/// Make sure the new member count value does not exceed the MaximumMembers
fn update_member_count(new_member_count: u32) -> Result<(), Error<T, I>> {
ensure!(new_member_count < T::MaximumMembers::get(), Error::<T, I>::TooManyMembers);
ggwpez marked this conversation as resolved.
Show resolved Hide resolved
<MemberCount<T, I>>::put(new_member_count);
Ok(())
}
}
42 changes: 24 additions & 18 deletions frame/scored-pool/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use super::*;
use crate as pallet_scored_pool;

use frame_support::{
ord_parameter_types, parameter_types,
bounded_vec, construct_runtime, ord_parameter_types, parameter_types,
traits::{ConstU32, ConstU64, GenesisBuild},
};
use frame_system::EnsureSignedBy;
Expand All @@ -35,7 +35,7 @@ use std::cell::RefCell;
type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Test>;
type Block = frame_system::mocking::MockBlock<Test>;

frame_support::construct_runtime!(
construct_runtime!(
pub enum Test where
Block = Block,
NodeBlock = Block,
Expand Down Expand Up @@ -97,7 +97,9 @@ impl pallet_balances::Config for Test {
}

thread_local! {
pub static MEMBERS: RefCell<Vec<u64>> = RefCell::new(vec![]);

pub static MEMBERS: RefCell<BoundedVec<u64,ConstU32<10_u32>>> = RefCell::new(bounded_vec![0,10]);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
pub static MEMBERS: RefCell<BoundedVec<u64,ConstU32<10_u32>>> = RefCell::new(bounded_vec![0,10]);
pub static MEMBERS: RefCell<BoundedVec<u64,ConstU32<10_u32>>> = RefCell::new(bounded_vec![0,10]);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or better, ues:

parameter_types! {
    pub static Members: BoundedVec<u64,ConstU32<10_u32>> = bounded_vec![0,10]
}

and then you get Members::get() and Members::set() with the same functionality.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

great, i have removed the local thread and added the parameter_types!

}

pub struct TestChangeMembers;
Expand All @@ -113,13 +115,18 @@ impl ChangeMembers<u64> for TestChangeMembers {

assert_eq!(old_plus_incoming, new_plus_outgoing);

MEMBERS.with(|m| *m.borrow_mut() = new.to_vec());
MEMBERS.with(|m| {
*m.borrow_mut() = <BoundedVec<u64, ConstU32<10_u32>>>::truncate_from(new.to_vec())
});
}
}

impl InitializeMembers<u64> for TestChangeMembers {
fn initialize_members(new_members: &[u64]) {
MEMBERS.with(|m| *m.borrow_mut() = new_members.to_vec());
MEMBERS.with(|m| {
*m.borrow_mut() =
<BoundedVec<u64, ConstU32<10_u32>>>::truncate_from(new_members.to_vec())
});
}
}

Expand All @@ -133,25 +140,24 @@ impl Config for Test {
type Period = ConstU64<4>;
type Score = u64;
type ScoreOrigin = EnsureSignedBy<ScoreOrigin, u64>;
type MaximumMembers = ConstU32<10>;
}

pub fn new_test_ext() -> sp_io::TestExternalities {
let mut t = frame_system::GenesisConfig::default().build_storage::<Test>().unwrap();
pallet_balances::GenesisConfig::<Test> {
balances: vec![
(5, 500_000),
(10, 500_000),
(15, 500_000),
(20, 500_000),
(31, 500_000),
(40, 500_000),
(99, 1),
],
let mut balances = vec![];
for i in 1..30 {
ggwpez marked this conversation as resolved.
Show resolved Hide resolved
balances.push((i, 500_000));
}
.assimilate_storage(&mut t)
.unwrap();
balances.push((31, 500_000));
balances.push((40, 500_000));
balances.push((99, 1));

pallet_balances::GenesisConfig::<Test> { balances }
.assimilate_storage(&mut t)
.unwrap();
pallet_scored_pool::GenesisConfig::<Test> {
pool: vec![(5, None), (10, Some(1)), (20, Some(2)), (31, Some(2)), (40, Some(3))],
pool: bounded_vec![(5, None), (10, Some(1)), (20, Some(2)), (31, Some(2)), (40, Some(3))],
member_count: 2,
}
.assimilate_storage(&mut t)
Expand Down
22 changes: 21 additions & 1 deletion frame/scored-pool/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
use super::*;
use mock::*;

use frame_support::{assert_noop, assert_ok, traits::OnInitialize};
use frame_support::{assert_noop, assert_ok, dispatch::Dispatchable, traits::OnInitialize};
use sp_runtime::traits::BadOrigin;

type ScoredPool = Pallet<Test>;
Expand Down Expand Up @@ -297,3 +297,23 @@ fn candidacy_resubmitting_works() {
assert_eq!(ScoredPool::candidate_exists(who), true);
});
}

#[test]
fn pool_candidates_exceded() {
hbulgarini marked this conversation as resolved.
Show resolved Hide resolved
new_test_ext().execute_with(|| {
for i in [1, 2, 3, 4, 6] {
hbulgarini marked this conversation as resolved.
Show resolved Hide resolved
let who = i as u64;
assert_ok!(ScoredPool::submit_candidacy(Origin::signed(who)));
let index = find_in_pool(who).expect("entity must be in pool") as u32;
assert_ok!(ScoredPool::score(Origin::signed(ScoreOrigin::get()), who, index, 99));
}

let submit_candidacy_call =
mock::Call::ScoredPool(crate::Call::<Test>::submit_candidacy {});

assert_noop!(
submit_candidacy_call.dispatch(Origin::signed(8)),
ggwpez marked this conversation as resolved.
Show resolved Hide resolved
Error::<Test, _>::TooManyMembers
);
});
}