Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion frame/bags-list/remote-tests/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ pub fn display_and_check_bags<Runtime: RuntimeT>(currency_unit: u64, currency_na
"Account {:?} can be rebagged from {:?} to {:?}",
id,
vote_weight_thresh_as_unit,
pallet_bags_list::notional_bag_for::<Runtime>(vote_weight) as f64 /
pallet_bags_list::notional_bag_for::<Runtime, _>(vote_weight) as f64 /
currency_unit as f64
);
}
Expand Down
36 changes: 18 additions & 18 deletions frame/bags-list/src/benchmarks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,29 +36,29 @@ frame_benchmarking::benchmarks! {

// clear any pre-existing storage.
// NOTE: safe to call outside block production
List::<T>::unsafe_clear();
List::<T, _>::unsafe_clear();

// define our origin and destination thresholds.
let origin_bag_thresh = T::BagThresholds::get()[0];
let dest_bag_thresh = T::BagThresholds::get()[1];

// seed items in the origin bag.
let origin_head: T::AccountId = account("origin_head", 0, 0);
assert_ok!(List::<T>::insert(origin_head.clone(), origin_bag_thresh));
assert_ok!(List::<T, _>::insert(origin_head.clone(), origin_bag_thresh));

let origin_middle: T::AccountId = account("origin_middle", 0, 0); // the node we rebag (_R_)
assert_ok!(List::<T>::insert(origin_middle.clone(), origin_bag_thresh));
assert_ok!(List::<T, _>::insert(origin_middle.clone(), origin_bag_thresh));

let origin_tail: T::AccountId = account("origin_tail", 0, 0);
assert_ok!(List::<T>::insert(origin_tail.clone(), origin_bag_thresh));
assert_ok!(List::<T, _>::insert(origin_tail.clone(), origin_bag_thresh));

// seed items in the destination bag.
let dest_head: T::AccountId = account("dest_head", 0, 0);
assert_ok!(List::<T>::insert(dest_head.clone(), dest_bag_thresh));
assert_ok!(List::<T, _>::insert(dest_head.clone(), dest_bag_thresh));

// the bags are in the expected state after initial setup.
assert_eq!(
List::<T>::get_bags(),
List::<T, _>::get_bags(),
vec![
(origin_bag_thresh, vec![origin_head.clone(), origin_middle.clone(), origin_tail.clone()]),
(dest_bag_thresh, vec![dest_head.clone()])
Expand All @@ -72,7 +72,7 @@ frame_benchmarking::benchmarks! {
verify {
// check the bags have updated as expected.
assert_eq!(
List::<T>::get_bags(),
List::<T, _>::get_bags(),
vec![
(
origin_bag_thresh,
Expand Down Expand Up @@ -104,18 +104,18 @@ frame_benchmarking::benchmarks! {

// seed items in the origin bag.
let origin_head: T::AccountId = account("origin_head", 0, 0);
assert_ok!(List::<T>::insert(origin_head.clone(), origin_bag_thresh));
assert_ok!(List::<T, _>::insert(origin_head.clone(), origin_bag_thresh));

let origin_tail: T::AccountId = account("origin_tail", 0, 0); // the node we rebag (_R_)
assert_ok!(List::<T>::insert(origin_tail.clone(), origin_bag_thresh));
assert_ok!(List::<T, _>::insert(origin_tail.clone(), origin_bag_thresh));

// seed items in the destination bag.
let dest_head: T::AccountId = account("dest_head", 0, 0);
assert_ok!(List::<T>::insert(dest_head.clone(), dest_bag_thresh));
assert_ok!(List::<T, _>::insert(dest_head.clone(), dest_bag_thresh));

// the bags are in the expected state after initial setup.
assert_eq!(
List::<T>::get_bags(),
List::<T, _>::get_bags(),
vec![
(origin_bag_thresh, vec![origin_head.clone(), origin_tail.clone()]),
(dest_bag_thresh, vec![dest_head.clone()])
Expand All @@ -129,7 +129,7 @@ frame_benchmarking::benchmarks! {
verify {
// check the bags have updated as expected.
assert_eq!(
List::<T>::get_bags(),
List::<T, _>::get_bags(),
vec![
(origin_bag_thresh, vec![origin_head.clone()]),
(dest_bag_thresh, vec![dest_head.clone(), origin_tail.clone()])
Expand All @@ -147,30 +147,30 @@ frame_benchmarking::benchmarks! {

// insert the nodes in order
let lighter: T::AccountId = account("lighter", 0, 0);
assert_ok!(List::<T>::insert(lighter.clone(), bag_thresh));
assert_ok!(List::<T, _>::insert(lighter.clone(), bag_thresh));

let heavier_prev: T::AccountId = account("heavier_prev", 0, 0);
assert_ok!(List::<T>::insert(heavier_prev.clone(), bag_thresh));
assert_ok!(List::<T, _>::insert(heavier_prev.clone(), bag_thresh));

let heavier: T::AccountId = account("heavier", 0, 0);
assert_ok!(List::<T>::insert(heavier.clone(), bag_thresh));
assert_ok!(List::<T, _>::insert(heavier.clone(), bag_thresh));

let heavier_next: T::AccountId = account("heavier_next", 0, 0);
assert_ok!(List::<T>::insert(heavier_next.clone(), bag_thresh));
assert_ok!(List::<T, _>::insert(heavier_next.clone(), bag_thresh));

T::VoteWeightProvider::set_vote_weight_of(&lighter, bag_thresh - 1);
T::VoteWeightProvider::set_vote_weight_of(&heavier, bag_thresh);

assert_eq!(
List::<T>::iter().map(|n| n.id().clone()).collect::<Vec<_>>(),
List::<T, _>::iter().map(|n| n.id().clone()).collect::<Vec<_>>(),
vec![lighter.clone(), heavier_prev.clone(), heavier.clone(), heavier_next.clone()]
);

whitelist_account!(heavier);
}: _(SystemOrigin::Signed(heavier.clone()), lighter.clone())
verify {
assert_eq!(
List::<T>::iter().map(|n| n.id().clone()).collect::<Vec<_>>(),
List::<T, _>::iter().map(|n| n.id().clone()).collect::<Vec<_>>(),
vec![heavier, lighter, heavier_prev, heavier_next]
)
}
Expand Down
55 changes: 28 additions & 27 deletions frame/bags-list/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,12 +92,12 @@ pub mod pallet {

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

#[pallet::config]
pub trait Config: frame_system::Config {
pub trait Config<I: 'static = ()>: frame_system::Config {
/// The overarching event type.
type Event: From<Event<Self>> + IsType<<Self as frame_system::Config>::Event>;
type Event: From<Event<Self, I>> + IsType<<Self as frame_system::Config>::Event>;

/// Weight information for extrinsics in this pallet.
type WeightInfo: weights::WeightInfo;
Expand Down Expand Up @@ -156,25 +156,26 @@ pub mod pallet {
///
/// Nodes store links forward and back within their respective bags.
#[pallet::storage]
pub(crate) type ListNodes<T: Config> =
CountedStorageMap<_, Twox64Concat, T::AccountId, list::Node<T>>;
pub(crate) type ListNodes<T: Config<I>, I: 'static = ()> =
CountedStorageMap<_, Twox64Concat, T::AccountId, list::Node<T, I>>;

/// A bag stored in storage.
///
/// Stores a `Bag` struct, which stores head and tail pointers to itself.
#[pallet::storage]
pub(crate) type ListBags<T: Config> = StorageMap<_, Twox64Concat, VoteWeight, list::Bag<T>>;
pub(crate) type ListBags<T: Config<I>, I: 'static = ()> =
StorageMap<_, Twox64Concat, VoteWeight, list::Bag<T, I>>;

#[pallet::event]
#[pallet::generate_deposit(pub(crate) fn deposit_event)]
pub enum Event<T: Config> {
pub enum Event<T: Config<I>, I: 'static = ()> {
/// Moved an account from one bag to another.
Rebagged { who: T::AccountId, from: VoteWeight, to: VoteWeight },
}

#[pallet::error]
#[cfg_attr(test, derive(PartialEq))]
pub enum Error<T> {
pub enum Error<T, I = ()> {
/// Attempted to place node in front of a node in another bag.
NotInSameBag,
/// Id not found in list.
Expand All @@ -184,7 +185,7 @@ pub mod pallet {
}

#[pallet::call]
impl<T: Config> Pallet<T> {
impl<T: Config<I>, I: 'static> Pallet<T, I> {
/// Declare that some `dislocated` account has, through rewards or penalties, sufficiently
/// changed its weight that it should properly fall into a different bag than its current
/// one.
Expand All @@ -197,7 +198,7 @@ pub mod pallet {
pub fn rebag(origin: OriginFor<T>, dislocated: T::AccountId) -> DispatchResult {
ensure_signed(origin)?;
let current_weight = T::VoteWeightProvider::vote_weight(&dislocated);
let _ = Pallet::<T>::do_rebag(&dislocated, current_weight);
let _ = Pallet::<T, I>::do_rebag(&dislocated, current_weight);
Ok(())
}

Expand All @@ -212,12 +213,12 @@ pub mod pallet {
#[pallet::weight(T::WeightInfo::put_in_front_of())]
pub fn put_in_front_of(origin: OriginFor<T>, lighter: T::AccountId) -> DispatchResult {
let heavier = ensure_signed(origin)?;
List::<T>::put_in_front_of(&lighter, &heavier).map_err(Into::into)
List::<T, I>::put_in_front_of(&lighter, &heavier).map_err(Into::into)
}
}

#[pallet::hooks]
impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
impl<T: Config<I>, I: 'static> Hooks<BlockNumberFor<T>> for Pallet<T, I> {
fn integrity_test() {
// ensure they are strictly increasing, this also implies that duplicates are detected.
assert!(
Expand All @@ -228,7 +229,7 @@ pub mod pallet {
}
}

impl<T: Config> Pallet<T> {
impl<T: Config<I>, I: 'static> Pallet<T, I> {
/// Move an account from one bag to another, depositing an event on success.
///
/// If the account changed bags, returns `Some((from, to))`.
Expand All @@ -238,46 +239,46 @@ impl<T: Config> Pallet<T> {
) -> Option<(VoteWeight, VoteWeight)> {
// if no voter at that node, don't do anything.
// the caller just wasted the fee to call this.
let maybe_movement = list::Node::<T>::get(&account)
let maybe_movement = list::Node::<T, I>::get(&account)
.and_then(|node| List::update_position_for(node, new_weight));
if let Some((from, to)) = maybe_movement {
Self::deposit_event(Event::<T>::Rebagged { who: account.clone(), from, to });
Self::deposit_event(Event::<T, I>::Rebagged { who: account.clone(), from, to });
};
maybe_movement
}

/// Equivalent to `ListBags::get`, but public. Useful for tests in outside of this crate.
#[cfg(feature = "std")]
pub fn list_bags_get(weight: VoteWeight) -> Option<list::Bag<T>> {
pub fn list_bags_get(weight: VoteWeight) -> Option<list::Bag<T, I>> {
ListBags::get(weight)
}
}

impl<T: Config> SortedListProvider<T::AccountId> for Pallet<T> {
impl<T: Config<I>, I: 'static> SortedListProvider<T::AccountId> for Pallet<T, I> {
type Error = Error;

fn iter() -> Box<dyn Iterator<Item = T::AccountId>> {
Box::new(List::<T>::iter().map(|n| n.id().clone()))
Box::new(List::<T, I>::iter().map(|n| n.id().clone()))
}

fn count() -> u32 {
ListNodes::<T>::count()
ListNodes::<T, I>::count()
}

fn contains(id: &T::AccountId) -> bool {
List::<T>::contains(id)
List::<T, I>::contains(id)
}

fn on_insert(id: T::AccountId, weight: VoteWeight) -> Result<(), Error> {
List::<T>::insert(id, weight)
List::<T, I>::insert(id, weight)
}

fn on_update(id: &T::AccountId, new_weight: VoteWeight) {
Pallet::<T>::do_rebag(id, new_weight);
Pallet::<T, I>::do_rebag(id, new_weight);
}

fn on_remove(id: &T::AccountId) {
List::<T>::remove(id)
List::<T, I>::remove(id)
}

fn unsafe_regenerate(
Expand All @@ -287,12 +288,12 @@ impl<T: Config> SortedListProvider<T::AccountId> for Pallet<T> {
// NOTE: This call is unsafe for the same reason as SortedListProvider::unsafe_regenerate.
// I.e. because it can lead to many storage accesses.
// So it is ok to call it as caller must ensure the conditions.
List::<T>::unsafe_regenerate(all, weight_of)
List::<T, I>::unsafe_regenerate(all, weight_of)
}

#[cfg(feature = "std")]
fn sanity_check() -> Result<(), &'static str> {
List::<T>::sanity_check()
List::<T, I>::sanity_check()
}

#[cfg(not(feature = "std"))]
Expand All @@ -304,14 +305,14 @@ impl<T: Config> SortedListProvider<T::AccountId> for Pallet<T> {
// NOTE: This call is unsafe for the same reason as SortedListProvider::unsafe_clear.
// I.e. because it can lead to many storage accesses.
// So it is ok to call it as caller must ensure the conditions.
List::<T>::unsafe_clear()
List::<T, I>::unsafe_clear()
}

#[cfg(feature = "runtime-benchmarks")]
fn weight_update_worst_case(who: &T::AccountId, is_increase: bool) -> VoteWeight {
use frame_support::traits::Get as _;
let thresholds = T::BagThresholds::get();
let node = list::Node::<T>::get(who).unwrap();
let node = list::Node::<T, I>::get(who).unwrap();
let current_bag_idx = thresholds
.iter()
.chain(sp_std::iter::once(&VoteWeight::MAX))
Expand Down
Loading