Update Pallet Bags List to use ListError (#11342)

* extract list error changes from kiz-revamp-sorted-list-providers-2-approval-stake

* some fixes

* weight -> score

* Update tests.rs

* Update tests.rs

* more fixes

* remove score updated event

* Update frame/bags-list/src/lib.rs

Co-authored-by: Keith Yeung <kungfukeith11@gmail.com>

Co-authored-by: Keith Yeung <kungfukeith11@gmail.com>
This commit is contained in:
Shawn Tabrizi
2022-05-03 23:13:58 +01:00
committed by GitHub
parent e397e0b634
commit 6d6f1e173b
8 changed files with 109 additions and 79 deletions
+3 -3
View File
@@ -64,19 +64,19 @@ fn main() {
Action::Insert => { Action::Insert => {
if BagsList::on_insert(id, vote_weight).is_err() { if BagsList::on_insert(id, vote_weight).is_err() {
// this was a duplicate id, which is ok. We can just update it. // this was a duplicate id, which is ok. We can just update it.
BagsList::on_update(&id, vote_weight); BagsList::on_update(&id, vote_weight).unwrap();
} }
assert!(BagsList::contains(&id)); assert!(BagsList::contains(&id));
}, },
Action::Update => { Action::Update => {
let already_contains = BagsList::contains(&id); let already_contains = BagsList::contains(&id);
BagsList::on_update(&id, vote_weight); BagsList::on_update(&id, vote_weight).unwrap();
if already_contains { if already_contains {
assert!(BagsList::contains(&id)); assert!(BagsList::contains(&id));
} }
}, },
Action::Remove => { Action::Remove => {
BagsList::on_remove(&id); BagsList::on_remove(&id).unwrap();
assert!(!BagsList::contains(&id)); assert!(!BagsList::contains(&id));
}, },
} }
+23 -17
View File
@@ -194,12 +194,14 @@ pub mod pallet {
#[pallet::error] #[pallet::error]
#[cfg_attr(test, derive(PartialEq))] #[cfg_attr(test, derive(PartialEq))]
pub enum Error<T, I = ()> { pub enum Error<T, I = ()> {
/// Attempted to place node in front of a node in another bag. /// A error in the list interface implementation.
NotInSameBag, List(ListError),
/// Id not found in list. }
IdNotFound,
/// An Id does not have a greater score than another Id. impl<T, I> From<ListError> for Error<T, I> {
NotHeavier, fn from(t: ListError) -> Self {
Error::<T, I>::List(t)
}
} }
#[pallet::call] #[pallet::call]
@@ -231,7 +233,9 @@ pub mod pallet {
#[pallet::weight(T::WeightInfo::put_in_front_of())] #[pallet::weight(T::WeightInfo::put_in_front_of())]
pub fn put_in_front_of(origin: OriginFor<T>, lighter: T::AccountId) -> DispatchResult { pub fn put_in_front_of(origin: OriginFor<T>, lighter: T::AccountId) -> DispatchResult {
let heavier = ensure_signed(origin)?; let heavier = ensure_signed(origin)?;
List::<T, I>::put_in_front_of(&lighter, &heavier).map_err(Into::into) List::<T, I>::put_in_front_of(&lighter, &heavier)
.map_err::<Error<T, I>, _>(Into::into)
.map_err::<DispatchError, _>(Into::into)
} }
} }
@@ -250,16 +254,18 @@ pub mod pallet {
impl<T: Config<I>, I: 'static> Pallet<T, I> { impl<T: Config<I>, I: 'static> Pallet<T, I> {
/// Move an account from one bag to another, depositing an event on success. /// Move an account from one bag to another, depositing an event on success.
/// ///
/// If the account changed bags, returns `Some((from, to))`. /// If the account changed bags, returns `Ok(Some((from, to)))`.
pub fn do_rebag(account: &T::AccountId, new_weight: T::Score) -> Option<(T::Score, T::Score)> { pub fn do_rebag(
// if no voter at that node, don't do anything. account: &T::AccountId,
// the caller just wasted the fee to call this. new_score: T::Score,
let maybe_movement = list::Node::<T, I>::get(account) ) -> Result<Option<(T::Score, T::Score)>, ListError> {
.and_then(|node| List::update_position_for(node, new_weight)); // If no voter at that node, don't do anything. the caller just wasted the fee to call this.
let node = list::Node::<T, I>::get(&account).ok_or(ListError::NodeNotFound)?;
let maybe_movement = List::update_position_for(node, new_score);
if let Some((from, to)) = maybe_movement { if let Some((from, to)) = maybe_movement {
Self::deposit_event(Event::<T, I>::Rebagged { who: account.clone(), from, to }); Self::deposit_event(Event::<T, I>::Rebagged { who: account.clone(), from, to });
}; };
maybe_movement Ok(maybe_movement)
} }
/// Equivalent to `ListBags::get`, but public. Useful for tests in outside of this crate. /// Equivalent to `ListBags::get`, but public. Useful for tests in outside of this crate.
@@ -296,11 +302,11 @@ impl<T: Config<I>, I: 'static> SortedListProvider<T::AccountId> for Pallet<T, I>
List::<T, I>::insert(id, score) List::<T, I>::insert(id, score)
} }
fn on_update(id: &T::AccountId, new_score: T::Score) { fn on_update(id: &T::AccountId, new_score: T::Score) -> Result<(), ListError> {
Pallet::<T, I>::do_rebag(id, new_score); Pallet::<T, I>::do_rebag(id, new_score).map(|_| ())
} }
fn on_remove(id: &T::AccountId) { fn on_remove(id: &T::AccountId) -> Result<(), ListError> {
List::<T, I>::remove(id) List::<T, I>::remove(id)
} }
+25 -14
View File
@@ -27,7 +27,10 @@
use crate::Config; use crate::Config;
use codec::{Decode, Encode, MaxEncodedLen}; use codec::{Decode, Encode, MaxEncodedLen};
use frame_election_provider_support::ScoreProvider; use frame_election_provider_support::ScoreProvider;
use frame_support::{traits::Get, DefaultNoBound}; use frame_support::{
traits::{Defensive, Get},
DefaultNoBound, PalletError,
};
use scale_info::TypeInfo; use scale_info::TypeInfo;
use sp_runtime::traits::{Bounded, Zero}; use sp_runtime::traits::{Bounded, Zero};
use sp_std::{ use sp_std::{
@@ -38,10 +41,14 @@ use sp_std::{
vec::Vec, vec::Vec,
}; };
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq, Encode, Decode, MaxEncodedLen, TypeInfo, PalletError)]
pub enum ListError { pub enum ListError {
/// A duplicate id has been detected. /// A duplicate id has been detected.
Duplicate, Duplicate,
/// An Id does not have a greater score than another Id.
NotHeavier,
/// Attempted to place node in front of a node in another bag.
NotInSameBag,
/// Given node id was not found. /// Given node id was not found.
NodeNotFound, NodeNotFound,
} }
@@ -321,9 +328,13 @@ impl<T: Config<I>, I: 'static> List<T, I> {
Ok(()) Ok(())
} }
/// Remove an id from the list. /// Remove an id from the list, returning an error if `id` does not exists.
pub(crate) fn remove(id: &T::AccountId) { pub(crate) fn remove(id: &T::AccountId) -> Result<(), ListError> {
Self::remove_many(sp_std::iter::once(id)); if !Self::contains(id) {
return Err(ListError::NodeNotFound)
}
let _ = Self::remove_many(sp_std::iter::once(id));
Ok(())
} }
/// Remove many ids from the list. /// Remove many ids from the list.
@@ -416,31 +427,31 @@ impl<T: Config<I>, I: 'static> List<T, I> {
pub(crate) fn put_in_front_of( pub(crate) fn put_in_front_of(
lighter_id: &T::AccountId, lighter_id: &T::AccountId,
heavier_id: &T::AccountId, heavier_id: &T::AccountId,
) -> Result<(), crate::pallet::Error<T, I>> { ) -> Result<(), ListError> {
use crate::pallet;
use frame_support::ensure; use frame_support::ensure;
let lighter_node = Node::<T, I>::get(lighter_id).ok_or(pallet::Error::IdNotFound)?; let lighter_node = Node::<T, I>::get(&lighter_id).ok_or(ListError::NodeNotFound)?;
let heavier_node = Node::<T, I>::get(heavier_id).ok_or(pallet::Error::IdNotFound)?; let heavier_node = Node::<T, I>::get(&heavier_id).ok_or(ListError::NodeNotFound)?;
ensure!(lighter_node.bag_upper == heavier_node.bag_upper, pallet::Error::NotInSameBag); ensure!(lighter_node.bag_upper == heavier_node.bag_upper, ListError::NotInSameBag);
// this is the most expensive check, so we do it last. // this is the most expensive check, so we do it last.
ensure!( ensure!(
T::ScoreProvider::score(heavier_id) > T::ScoreProvider::score(lighter_id), T::ScoreProvider::score(&heavier_id) > T::ScoreProvider::score(&lighter_id),
pallet::Error::NotHeavier ListError::NotHeavier
); );
// remove the heavier node from this list. Note that this removes the node from storage and // remove the heavier node from this list. Note that this removes the node from storage and
// decrements the node counter. // decrements the node counter.
Self::remove(heavier_id); // defensive: both nodes have been checked to exist.
let _ = Self::remove(&heavier_id).defensive();
// re-fetch `lighter_node` from storage since it may have been updated when `heavier_node` // re-fetch `lighter_node` from storage since it may have been updated when `heavier_node`
// was removed. // was removed.
let lighter_node = Node::<T, I>::get(lighter_id).ok_or_else(|| { let lighter_node = Node::<T, I>::get(lighter_id).ok_or_else(|| {
debug_assert!(false, "id that should exist cannot be found"); debug_assert!(false, "id that should exist cannot be found");
crate::log!(warn, "id that should exist cannot be found"); crate::log!(warn, "id that should exist cannot be found");
pallet::Error::IdNotFound ListError::NodeNotFound
})?; })?;
// insert `heavier_node` directly in front of `lighter_node`. This will update both nodes // insert `heavier_node` directly in front of `lighter_node`. This will update both nodes
+8 -8
View File
@@ -21,7 +21,7 @@ use crate::{
ListBags, ListNodes, ListBags, ListNodes,
}; };
use frame_election_provider_support::{SortedListProvider, VoteWeight}; use frame_election_provider_support::{SortedListProvider, VoteWeight};
use frame_support::{assert_ok, assert_storage_noop}; use frame_support::{assert_noop, assert_ok, assert_storage_noop};
#[test] #[test]
fn basic_setup_works() { fn basic_setup_works() {
@@ -98,7 +98,7 @@ fn remove_last_node_in_bags_cleans_bag() {
assert_eq!(List::<Runtime>::get_bags(), vec![(10, vec![1]), (1_000, vec![2, 3, 4])]); assert_eq!(List::<Runtime>::get_bags(), vec![(10, vec![1]), (1_000, vec![2, 3, 4])]);
// bump 1 to a bigger bag // bump 1 to a bigger bag
List::<Runtime>::remove(&1); List::<Runtime>::remove(&1).unwrap();
assert_ok!(List::<Runtime>::insert(1, 10_000)); assert_ok!(List::<Runtime>::insert(1, 10_000));
// then the bag with bound 10 is wiped from storage. // then the bag with bound 10 is wiped from storage.
@@ -265,10 +265,10 @@ mod list {
ExtBuilder::default().build_and_execute(|| { ExtBuilder::default().build_and_execute(|| {
// removing a non-existent id is a noop // removing a non-existent id is a noop
assert!(!ListNodes::<Runtime>::contains_key(42)); assert!(!ListNodes::<Runtime>::contains_key(42));
assert_storage_noop!(List::<Runtime>::remove(&42)); assert_noop!(List::<Runtime>::remove(&42), ListError::NodeNotFound);
// when removing a node from a bag with multiple nodes: // when removing a node from a bag with multiple nodes:
List::<Runtime>::remove(&2); List::<Runtime>::remove(&2).unwrap();
// then // then
assert_eq!(get_list_as_ids(), vec![3, 4, 1]); assert_eq!(get_list_as_ids(), vec![3, 4, 1]);
@@ -276,7 +276,7 @@ mod list {
ensure_left(2, 3); ensure_left(2, 3);
// when removing a node from a bag with only one node: // when removing a node from a bag with only one node:
List::<Runtime>::remove(&1); List::<Runtime>::remove(&1).unwrap();
// then // then
assert_eq!(get_list_as_ids(), vec![3, 4]); assert_eq!(get_list_as_ids(), vec![3, 4]);
@@ -286,11 +286,11 @@ mod list {
assert!(!ListBags::<Runtime>::contains_key(10)); assert!(!ListBags::<Runtime>::contains_key(10));
// remove remaining ids to make sure storage cleans up as expected // remove remaining ids to make sure storage cleans up as expected
List::<Runtime>::remove(&3); List::<Runtime>::remove(&3).unwrap();
ensure_left(3, 1); ensure_left(3, 1);
assert_eq!(get_list_as_ids(), vec![4]); assert_eq!(get_list_as_ids(), vec![4]);
List::<Runtime>::remove(&4); List::<Runtime>::remove(&4).unwrap();
ensure_left(4, 0); ensure_left(4, 0);
assert_eq!(get_list_as_ids(), Vec::<AccountId>::new()); assert_eq!(get_list_as_ids(), Vec::<AccountId>::new());
@@ -573,7 +573,7 @@ mod bags {
}); });
// when we make a pre-existing bag empty // when we make a pre-existing bag empty
List::<Runtime>::remove(&1); List::<Runtime>::remove(&1).unwrap();
// then // then
assert_eq!(Bag::<Runtime>::get(10), None) assert_eq!(Bag::<Runtime>::get(10), None)
+24 -24
View File
@@ -34,7 +34,7 @@ mod pallet {
vec![(10, vec![1]), (20, vec![42]), (1_000, vec![2, 3, 4])] vec![(10, vec![1]), (20, vec![42]), (1_000, vec![2, 3, 4])]
); );
// when increasing vote weight to the level of non-existent bag // when increasing score to the level of non-existent bag
StakingMock::set_score_of(&42, 2_000); StakingMock::set_score_of(&42, 2_000);
assert_ok!(BagsList::rebag(Origin::signed(0), 42)); assert_ok!(BagsList::rebag(Origin::signed(0), 42));
@@ -44,7 +44,7 @@ mod pallet {
vec![(10, vec![1]), (1_000, vec![2, 3, 4]), (2_000, vec![42])] vec![(10, vec![1]), (1_000, vec![2, 3, 4]), (2_000, vec![42])]
); );
// when decreasing weight within the range of the current bag // when decreasing score within the range of the current bag
StakingMock::set_score_of(&42, 1_001); StakingMock::set_score_of(&42, 1_001);
assert_ok!(BagsList::rebag(Origin::signed(0), 42)); assert_ok!(BagsList::rebag(Origin::signed(0), 42));
@@ -54,7 +54,7 @@ mod pallet {
vec![(10, vec![1]), (1_000, vec![2, 3, 4]), (2_000, vec![42])] vec![(10, vec![1]), (1_000, vec![2, 3, 4]), (2_000, vec![42])]
); );
// when reducing weight to the level of a non-existent bag // when reducing score to the level of a non-existent bag
StakingMock::set_score_of(&42, 30); StakingMock::set_score_of(&42, 30);
assert_ok!(BagsList::rebag(Origin::signed(0), 42)); assert_ok!(BagsList::rebag(Origin::signed(0), 42));
@@ -64,7 +64,7 @@ mod pallet {
vec![(10, vec![1]), (30, vec![42]), (1_000, vec![2, 3, 4])] vec![(10, vec![1]), (30, vec![42]), (1_000, vec![2, 3, 4])]
); );
// when increasing weight to the level of a pre-existing bag // when increasing score to the level of a pre-existing bag
StakingMock::set_score_of(&42, 500); StakingMock::set_score_of(&42, 500);
assert_ok!(BagsList::rebag(Origin::signed(0), 42)); assert_ok!(BagsList::rebag(Origin::signed(0), 42));
@@ -380,7 +380,7 @@ mod pallet {
// then // then
assert_noop!( assert_noop!(
BagsList::put_in_front_of(Origin::signed(3), 2), BagsList::put_in_front_of(Origin::signed(3), 2),
crate::pallet::Error::<Runtime>::NotHeavier crate::pallet::Error::<Runtime>::List(ListError::NotHeavier)
); );
}); });
} }
@@ -394,7 +394,7 @@ mod pallet {
// then // then
assert_noop!( assert_noop!(
BagsList::put_in_front_of(Origin::signed(3), 4), BagsList::put_in_front_of(Origin::signed(3), 4),
crate::pallet::Error::<Runtime>::NotHeavier crate::pallet::Error::<Runtime>::List(ListError::NotHeavier)
); );
}); });
} }
@@ -411,7 +411,7 @@ mod pallet {
// then // then
assert_noop!( assert_noop!(
BagsList::put_in_front_of(Origin::signed(5), 4), BagsList::put_in_front_of(Origin::signed(5), 4),
crate::pallet::Error::<Runtime>::IdNotFound crate::pallet::Error::<Runtime>::List(ListError::NodeNotFound)
); );
}); });
@@ -425,7 +425,7 @@ mod pallet {
// then // then
assert_noop!( assert_noop!(
BagsList::put_in_front_of(Origin::signed(4), 5), BagsList::put_in_front_of(Origin::signed(4), 5),
crate::pallet::Error::<Runtime>::IdNotFound crate::pallet::Error::<Runtime>::List(ListError::NodeNotFound)
); );
}); });
} }
@@ -439,7 +439,7 @@ mod pallet {
// then // then
assert_noop!( assert_noop!(
BagsList::put_in_front_of(Origin::signed(4), 1), BagsList::put_in_front_of(Origin::signed(4), 1),
crate::pallet::Error::<Runtime>::NotInSameBag crate::pallet::Error::<Runtime>::List(ListError::NotInSameBag)
); );
}); });
} }
@@ -491,12 +491,12 @@ mod sorted_list_provider {
assert_eq!(BagsList::count(), 5); assert_eq!(BagsList::count(), 5);
// when removing // when removing
BagsList::on_remove(&201); BagsList::on_remove(&201).unwrap();
// then the count goes down // then the count goes down
assert_eq!(BagsList::count(), 4); assert_eq!(BagsList::count(), 4);
// when updating // when updating
BagsList::on_update(&201, VoteWeight::MAX); assert_noop!(BagsList::on_update(&201, VoteWeight::MAX), ListError::NodeNotFound);
// then the count stays the same // then the count stays the same
assert_eq!(BagsList::count(), 4); assert_eq!(BagsList::count(), 4);
}); });
@@ -554,8 +554,8 @@ mod sorted_list_provider {
); );
assert_eq!(BagsList::count(), 5); assert_eq!(BagsList::count(), 5);
// when increasing weight to the level of non-existent bag // when increasing score to the level of non-existent bag
BagsList::on_update(&42, 2_000); BagsList::on_update(&42, 2_000).unwrap();
// then the bag is created with the id in it, // then the bag is created with the id in it,
assert_eq!( assert_eq!(
@@ -565,8 +565,8 @@ mod sorted_list_provider {
// and the id position is updated in the list. // and the id position is updated in the list.
assert_eq!(BagsList::iter().collect::<Vec<_>>(), vec![42, 2, 3, 4, 1]); assert_eq!(BagsList::iter().collect::<Vec<_>>(), vec![42, 2, 3, 4, 1]);
// when decreasing weight within the range of the current bag // when decreasing score within the range of the current bag
BagsList::on_update(&42, 1_001); BagsList::on_update(&42, 1_001).unwrap();
// then the id does not change bags, // then the id does not change bags,
assert_eq!( assert_eq!(
@@ -576,8 +576,8 @@ mod sorted_list_provider {
// or change position in the list. // or change position in the list.
assert_eq!(BagsList::iter().collect::<Vec<_>>(), vec![42, 2, 3, 4, 1]); assert_eq!(BagsList::iter().collect::<Vec<_>>(), vec![42, 2, 3, 4, 1]);
// when increasing weight to the level of a non-existent bag with the max threshold // when increasing score to the level of a non-existent bag with the max threshold
BagsList::on_update(&42, VoteWeight::MAX); BagsList::on_update(&42, VoteWeight::MAX).unwrap();
// the the new bag is created with the id in it, // the the new bag is created with the id in it,
assert_eq!( assert_eq!(
@@ -587,8 +587,8 @@ mod sorted_list_provider {
// and the id position is updated in the list. // and the id position is updated in the list.
assert_eq!(BagsList::iter().collect::<Vec<_>>(), vec![42, 2, 3, 4, 1]); assert_eq!(BagsList::iter().collect::<Vec<_>>(), vec![42, 2, 3, 4, 1]);
// when decreasing the weight to a pre-existing bag // when decreasing the score to a pre-existing bag
BagsList::on_update(&42, 1_000); BagsList::on_update(&42, 1_000).unwrap();
// then id is moved to the correct bag (as the last member), // then id is moved to the correct bag (as the last member),
assert_eq!( assert_eq!(
@@ -615,10 +615,10 @@ mod sorted_list_provider {
ExtBuilder::default().build_and_execute(|| { ExtBuilder::default().build_and_execute(|| {
// it is a noop removing a non-existent id // it is a noop removing a non-existent id
assert!(!ListNodes::<Runtime>::contains_key(42)); assert!(!ListNodes::<Runtime>::contains_key(42));
assert_storage_noop!(BagsList::on_remove(&42)); assert_noop!(BagsList::on_remove(&42), ListError::NodeNotFound);
// when removing a node from a bag with multiple nodes // when removing a node from a bag with multiple nodes
BagsList::on_remove(&2); BagsList::on_remove(&2).unwrap();
// then // then
assert_eq!(get_list_as_ids(), vec![3, 4, 1]); assert_eq!(get_list_as_ids(), vec![3, 4, 1]);
@@ -626,7 +626,7 @@ mod sorted_list_provider {
ensure_left(2, 3); ensure_left(2, 3);
// when removing a node from a bag with only one node // when removing a node from a bag with only one node
BagsList::on_remove(&1); BagsList::on_remove(&1).unwrap();
// then // then
assert_eq!(get_list_as_ids(), vec![3, 4]); assert_eq!(get_list_as_ids(), vec![3, 4]);
@@ -634,10 +634,10 @@ mod sorted_list_provider {
ensure_left(1, 2); ensure_left(1, 2);
// when removing all remaining ids // when removing all remaining ids
BagsList::on_remove(&4); BagsList::on_remove(&4).unwrap();
assert_eq!(get_list_as_ids(), vec![3]); assert_eq!(get_list_as_ids(), vec![3]);
ensure_left(4, 1); ensure_left(4, 1);
BagsList::on_remove(&3); BagsList::on_remove(&3).unwrap();
// then the storage is completely cleaned up // then the storage is completely cleaned up
assert_eq!(get_list_as_ids(), Vec::<AccountId>::new()); assert_eq!(get_list_as_ids(), Vec::<AccountId>::new());
@@ -171,7 +171,7 @@ pub mod traits;
#[cfg(feature = "std")] #[cfg(feature = "std")]
use codec::{Decode, Encode}; use codec::{Decode, Encode};
use frame_support::{weights::Weight, BoundedVec, RuntimeDebug}; use frame_support::{weights::Weight, BoundedVec, RuntimeDebug};
use sp_runtime::traits::Bounded; use sp_runtime::traits::{Bounded, Saturating, Zero};
use sp_std::{fmt::Debug, prelude::*}; use sp_std::{fmt::Debug, prelude::*};
/// Re-export the solution generation macro. /// Re-export the solution generation macro.
@@ -439,7 +439,7 @@ pub trait SortedListProvider<AccountId> {
type Error: sp_std::fmt::Debug; type Error: sp_std::fmt::Debug;
/// The type used by the list to compare nodes for ordering. /// The type used by the list to compare nodes for ordering.
type Score: Bounded; type Score: Bounded + Saturating + Zero;
/// An iterator over the list, which can have `take` called on it. /// An iterator over the list, which can have `take` called on it.
fn iter() -> Box<dyn Iterator<Item = AccountId>>; fn iter() -> Box<dyn Iterator<Item = AccountId>>;
@@ -456,13 +456,21 @@ pub trait SortedListProvider<AccountId> {
fn contains(id: &AccountId) -> bool; fn contains(id: &AccountId) -> bool;
/// Hook for inserting a new id. /// Hook for inserting a new id.
///
/// Implementation should return an error if duplicate item is being inserted.
fn on_insert(id: AccountId, score: Self::Score) -> Result<(), Self::Error>; fn on_insert(id: AccountId, score: Self::Score) -> Result<(), Self::Error>;
/// Hook for updating a single id. /// Hook for updating a single id.
fn on_update(id: &AccountId, score: Self::Score); ///
/// The `new` score is given.
///
/// Returns `Ok(())` iff it successfully updates an item, an `Err(_)` otherwise.
fn on_update(id: &AccountId, score: Self::Score) -> Result<(), Self::Error>;
/// Hook for removing am id from the list. /// Hook for removing am id from the list.
fn on_remove(id: &AccountId); ///
/// Returns `Ok(())` iff it successfully removes an item, an `Err(_)` otherwise.
fn on_remove(id: &AccountId) -> Result<(), Self::Error>;
/// Regenerate this list from scratch. Returns the count of items inserted. /// Regenerate this list from scratch. Returns the count of items inserted.
/// ///
+6 -4
View File
@@ -803,7 +803,7 @@ impl<T: Config> Pallet<T> {
pub fn do_remove_nominator(who: &T::AccountId) -> bool { pub fn do_remove_nominator(who: &T::AccountId) -> bool {
let outcome = if Nominators::<T>::contains_key(who) { let outcome = if Nominators::<T>::contains_key(who) {
Nominators::<T>::remove(who); Nominators::<T>::remove(who);
T::VoterList::on_remove(who); let _ = T::VoterList::on_remove(who).defensive();
true true
} else { } else {
false false
@@ -850,7 +850,7 @@ impl<T: Config> Pallet<T> {
pub fn do_remove_validator(who: &T::AccountId) -> bool { pub fn do_remove_validator(who: &T::AccountId) -> bool {
let outcome = if Validators::<T>::contains_key(who) { let outcome = if Validators::<T>::contains_key(who) {
Validators::<T>::remove(who); Validators::<T>::remove(who);
T::VoterList::on_remove(who); let _ = T::VoterList::on_remove(who).defensive();
true true
} else { } else {
false false
@@ -1343,11 +1343,13 @@ impl<T: Config> SortedListProvider<T::AccountId> for UseNominatorsAndValidatorsM
// nothing to do on insert. // nothing to do on insert.
Ok(()) Ok(())
} }
fn on_update(_: &T::AccountId, _weight: Self::Score) { fn on_update(_: &T::AccountId, _weight: VoteWeight) -> Result<(), Self::Error> {
// nothing to do on update. // nothing to do on update.
Ok(())
} }
fn on_remove(_: &T::AccountId) { fn on_remove(_: &T::AccountId) -> Result<(), Self::Error> {
// nothing to do on remove. // nothing to do on remove.
Ok(())
} }
fn unsafe_regenerate( fn unsafe_regenerate(
_: impl IntoIterator<Item = T::AccountId>, _: impl IntoIterator<Item = T::AccountId>,
+8 -5
View File
@@ -22,8 +22,8 @@ use frame_support::{
dispatch::Codec, dispatch::Codec,
pallet_prelude::*, pallet_prelude::*,
traits::{ traits::{
Currency, CurrencyToVote, DefensiveSaturating, EnsureOrigin, EstimateNextNewSession, Get, Currency, CurrencyToVote, Defensive, DefensiveSaturating, EnsureOrigin,
LockIdentifier, LockableCurrency, OnUnbalanced, UnixTime, EstimateNextNewSession, Get, LockIdentifier, LockableCurrency, OnUnbalanced, UnixTime,
}, },
weights::Weight, weights::Weight,
}; };
@@ -858,7 +858,8 @@ pub mod pallet {
Self::update_ledger(&controller, &ledger); Self::update_ledger(&controller, &ledger);
// update this staker in the sorted list, if they exist in it. // update this staker in the sorted list, if they exist in it.
if T::VoterList::contains(&stash) { if T::VoterList::contains(&stash) {
T::VoterList::on_update(&stash, Self::weight_of(&ledger.stash)); let _ =
T::VoterList::on_update(&stash, Self::weight_of(&ledger.stash)).defensive();
debug_assert_eq!(T::VoterList::sanity_check(), Ok(())); debug_assert_eq!(T::VoterList::sanity_check(), Ok(()));
} }
@@ -941,7 +942,8 @@ pub mod pallet {
// update this staker in the sorted list, if they exist in it. // update this staker in the sorted list, if they exist in it.
if T::VoterList::contains(&ledger.stash) { if T::VoterList::contains(&ledger.stash) {
T::VoterList::on_update(&ledger.stash, Self::weight_of(&ledger.stash)); let _ = T::VoterList::on_update(&ledger.stash, Self::weight_of(&ledger.stash))
.defensive();
} }
Self::deposit_event(Event::<T>::Unbonded(ledger.stash, value)); Self::deposit_event(Event::<T>::Unbonded(ledger.stash, value));
@@ -1426,7 +1428,8 @@ pub mod pallet {
// NOTE: ledger must be updated prior to calling `Self::weight_of`. // NOTE: ledger must be updated prior to calling `Self::weight_of`.
Self::update_ledger(&controller, &ledger); Self::update_ledger(&controller, &ledger);
if T::VoterList::contains(&ledger.stash) { if T::VoterList::contains(&ledger.stash) {
T::VoterList::on_update(&ledger.stash, Self::weight_of(&ledger.stash)); let _ = T::VoterList::on_update(&ledger.stash, Self::weight_of(&ledger.stash))
.defensive();
} }
let removed_chunks = 1u32 // for the case where the last iterated chunk is not removed let removed_chunks = 1u32 // for the case where the last iterated chunk is not removed