From 9e569f5453e86386c3e7e3d7ab486fe38e4ffe70 Mon Sep 17 00:00:00 2001 From: gpestana Date: Sat, 29 Oct 2022 17:19:33 +0200 Subject: [PATCH 01/20] Prevents max unbonding chunk slots from being filled when unbonding in the staking pallet --- frame/nomination-pools/src/lib.rs | 6 ++---- frame/staking/src/pallet/impls.rs | 5 +++++ frame/staking/src/pallet/mod.rs | 26 ++++++++++++++++-------- frame/staking/src/tests.rs | 33 +++++++++++++++++-------------- 4 files changed, 43 insertions(+), 27 deletions(-) diff --git a/frame/nomination-pools/src/lib.rs b/frame/nomination-pools/src/lib.rs index 3661a7f70b48a..b35f306a68329 100644 --- a/frame/nomination-pools/src/lib.rs +++ b/frame/nomination-pools/src/lib.rs @@ -1608,10 +1608,8 @@ pub mod pallet { /// /// # Note /// - /// If there are too many unlocking chunks to unbond with the pool account, - /// [`Call::pool_withdraw_unbonded`] can be called to try and minimize unlocking chunks. If - /// there are too many unlocking chunks, the result of this call will likely be the - /// `NoMoreChunks` error from the staking system. + /// The [`StakingInterface::unbond`] will implicitly call [`Call::pool_withdraw_unbonded`] + /// if there are no left unlocking chunk slots available. #[pallet::weight(T::WeightInfo::unbond())] #[transactional] pub fn unbond( diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index a9e9899b9761a..de67954f2e7c6 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -92,6 +92,11 @@ impl Pallet { Self::slashable_balance_of_vote_weight(who, issuance) } + /// Returns the number of filled chunks for an account. + pub fn chunk_slots_filled(who: &T::AccountId) -> Result> { + Ok(Self::ledger(&who).ok_or(Error::::NotController)?.unlocking.len()) + } + pub(super) fn do_payout_stakers( validator_stash: T::AccountId, era: EraIndex, diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index df90873ab2e59..72634f1dd8a87 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -932,8 +932,8 @@ pub mod pallet { /// the funds out of management ready for transfer. /// /// No more than a limited number of unlocking chunks (see `MaxUnlockingChunks`) - /// can co-exists at the same time. In that case, [`Call::withdraw_unbonded`] need - /// to be called first to remove some of the chunks (if possible). + /// can co-exists at the same time. If there are no unlocking chunks slots available + /// [`Call::withdraw_unbonded`] is called to remove some of the chunks (if possible). /// /// If a user encounters the `InsufficientBond` error when calling this extrinsic, /// they should call `chill` first in order to free up their bonded funds. @@ -941,17 +941,27 @@ pub mod pallet { /// Emits `Unbonded`. /// /// See also [`Call::withdraw_unbonded`]. - #[pallet::weight(T::WeightInfo::unbond())] + #[pallet::weight( + T::WeightInfo::withdraw_unbonded_kill(T::BondingDuration::get()) + + T::WeightInfo::unbond()) + ] pub fn unbond( origin: OriginFor, #[pallet::compact] value: BalanceOf, ) -> DispatchResult { - let controller = ensure_signed(origin)?; + let controller = ensure_signed(origin.clone())?; + + // ensure that there's chunk slots available by requesting the staking interface to + // withdraw chunks older than `BondingDuration`, if there are no more unlocking chunks + // slots available. + if Self::chunk_slots_filled(&controller)? == T::MaxUnlockingChunks::get() as usize { + let num_slashing_spans = T::BondingDuration::get(); + + Self::withdraw_unbonded(origin, num_slashing_spans) + .map_err(|with_post| with_post.error)?; + }; + let mut ledger = Self::ledger(&controller).ok_or(Error::::NotController)?; - ensure!( - ledger.unlocking.len() < T::MaxUnlockingChunks::get() as usize, - Error::::NoMoreChunks, - ); let mut value = value.min(ledger.active); diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 4812c105c0d80..e93cf52b17279 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -1350,12 +1350,14 @@ fn bond_extra_and_withdraw_unbonded_works() { } #[test] -fn too_many_unbond_calls_should_not_work() { +fn many_unbond_calls_should_work() { ExtBuilder::default().build_and_execute(|| { let mut current_era = 0; // locked at era MaxUnlockingChunks - 1 until 3 - for i in 0..<::MaxUnlockingChunks as Get>::get() - 1 { + let max_unlocking_chunks = <::MaxUnlockingChunks as Get>::get(); + + for i in 0..max_unlocking_chunks - 1 { // There is only 1 chunk per era, so we need to be in a new era to create a chunk. current_era = i as u32; mock::start_active_era(current_era); @@ -1369,23 +1371,24 @@ fn too_many_unbond_calls_should_not_work() { // == 3). assert_ok!(Staking::unbond(RuntimeOrigin::signed(10), 1)); assert_eq!( - Staking::ledger(&10).unwrap().unlocking.len(), + Staking::chunk_slots_filled(&10).unwrap(), <::MaxUnlockingChunks as Get>::get() as usize ); - // can't do more. - assert_noop!(Staking::unbond(RuntimeOrigin::signed(10), 1), Error::::NoMoreChunks); - - current_era += 2; - mock::start_active_era(current_era); - assert_noop!(Staking::unbond(RuntimeOrigin::signed(10), 1), Error::::NoMoreChunks); - // free up everything except the most recently added chunk. - assert_ok!(Staking::withdraw_unbonded(RuntimeOrigin::signed(10), 0)); - assert_eq!(Staking::ledger(&10).unwrap().unlocking.len(), 1); + // even though the number of unlocked chunks is the same as `MaxUnlockingChunks`, + // unbonding works as expected. + for i in current_era..(current_era + max_unlocking_chunks) - 1 { + // There is only 1 chunk per era, so we need to be in a new era to create a chunk. + current_era = i as u32; + mock::start_active_era(current_era); + assert_ok!(Staking::unbond(RuntimeOrigin::signed(10), 1)); + } - // Can add again. - assert_ok!(Staking::unbond(RuntimeOrigin::signed(10), 1)); - assert_eq!(Staking::ledger(&10).unwrap().unlocking.len(), 2); + // only slots of unbonds within last BondingDuration are filled. + assert_eq!( + Staking::chunk_slots_filled(&10).unwrap(), + <::BondingDuration>::get() as usize + ); }) } From a25ecaae56a48ce0745a27cc54f56b157489b550 Mon Sep 17 00:00:00 2001 From: gpestana Date: Tue, 8 Nov 2022 09:02:14 +0100 Subject: [PATCH 02/20] hardcode num_slashing to unlock chunks automatically --- frame/staking/src/pallet/mod.rs | 9 ++++----- frame/staking/src/tests.rs | 4 ++-- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 72634f1dd8a87..0e054fb9d5034 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -49,6 +49,7 @@ use crate::{ }; const STAKING_ID: LockIdentifier = *b"staking "; +const SLASHING_SPANS_AUTO_WITHDRAW: u32 = 0; #[frame_support::pallet] pub mod pallet { @@ -942,8 +943,7 @@ pub mod pallet { /// /// See also [`Call::withdraw_unbonded`]. #[pallet::weight( - T::WeightInfo::withdraw_unbonded_kill(T::BondingDuration::get()) + - T::WeightInfo::unbond()) + T::WeightInfo::withdraw_unbonded_kill(SLASHING_SPANS_AUTO_WITHDRAW) + T::WeightInfo::unbond()) ] pub fn unbond( origin: OriginFor, @@ -951,13 +951,12 @@ pub mod pallet { ) -> DispatchResult { let controller = ensure_signed(origin.clone())?; + // ensure that there's chunk slots available by requesting the staking interface to // withdraw chunks older than `BondingDuration`, if there are no more unlocking chunks // slots available. if Self::chunk_slots_filled(&controller)? == T::MaxUnlockingChunks::get() as usize { - let num_slashing_spans = T::BondingDuration::get(); - - Self::withdraw_unbonded(origin, num_slashing_spans) + Self::withdraw_unbonded(origin, SLASHING_SPANS_AUTO_WITHDRAW) .map_err(|with_post| with_post.error)?; }; diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index e93cf52b17279..743d61024d43a 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -1367,7 +1367,7 @@ fn many_unbond_calls_should_work() { current_era += 1; mock::start_active_era(current_era); - // This chunk is locked at `current_era` through `current_era + 2` (because BondingDuration + // This chunk is locked at `current_era` through `current_era + 2` (because `BondingDuration` // == 3). assert_ok!(Staking::unbond(RuntimeOrigin::signed(10), 1)); assert_eq!( @@ -1384,7 +1384,7 @@ fn many_unbond_calls_should_work() { assert_ok!(Staking::unbond(RuntimeOrigin::signed(10), 1)); } - // only slots of unbonds within last BondingDuration are filled. + // only slots of unbonds within last `BondingDuration` are filled. assert_eq!( Staking::chunk_slots_filled(&10).unwrap(), <::BondingDuration>::get() as usize From 6e57960ee859f510b80b8d4a0b87c89c3e4a69ca Mon Sep 17 00:00:00 2001 From: gpestana Date: Tue, 8 Nov 2022 23:07:10 +0100 Subject: [PATCH 03/20] refactor withdraw logic to do_withdraw; idiomatic rust improvements --- frame/staking/src/pallet/impls.rs | 40 +++++++++++++++++++++++++-- frame/staking/src/pallet/mod.rs | 46 +++++-------------------------- frame/staking/src/tests.rs | 4 +-- 3 files changed, 46 insertions(+), 44 deletions(-) diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index de67954f2e7c6..84a827a9ee74f 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -92,9 +92,43 @@ impl Pallet { Self::slashable_balance_of_vote_weight(who, issuance) } - /// Returns the number of filled chunks for an account. - pub fn chunk_slots_filled(who: &T::AccountId) -> Result> { - Ok(Self::ledger(&who).ok_or(Error::::NotController)?.unlocking.len()) + pub(super) fn do_withdraw_unbonded( + controller: &T::AccountId, + num_slashing_spans: u32, + ) -> DispatchResultWithPostInfo { + let mut ledger = Self::ledger(&controller).ok_or(Error::::NotController)?; + let (stash, old_total) = (ledger.stash.clone(), ledger.total); + if let Some(current_era) = Self::current_era() { + ledger = ledger.consolidate_unlocked(current_era) + } + + let post_info_weight = + if ledger.unlocking.is_empty() && ledger.active < T::Currency::minimum_balance() { + // This account must have called `unbond()` with some value that caused the active + // portion to fall below existential deposit + will have no more unlocking chunks + // left. We can now safely remove all staking-related information. + Self::kill_stash(&stash, num_slashing_spans)?; + // Remove the lock. + T::Currency::remove_lock(STAKING_ID, &stash); + // This is worst case scenario, so we use the full weight and return None + None + } else { + // This was the consequence of a partial unbond. just update the ledger and move on. + Self::update_ledger(&controller, &ledger); + + // This is only an update, so we use less overall weight. + Some(T::WeightInfo::withdraw_unbonded_update(num_slashing_spans)) + }; + + // `old_total` should never be less than the new total because + // `consolidate_unlocked` strictly subtracts balance. + if ledger.total < old_total { + // Already checked that this won't overflow by entry condition. + let value = old_total - ledger.total; + Self::deposit_event(Event::::Withdrawn { stash, amount: value }); + } + + Ok(post_info_weight.into()) } pub(super) fn do_payout_stakers( diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 0e054fb9d5034..3fd2343961720 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -950,18 +950,19 @@ pub mod pallet { #[pallet::compact] value: BalanceOf, ) -> DispatchResult { let controller = ensure_signed(origin.clone())?; - + let unlocking = Self::ledger(&controller) + .map(|l| l.unlocking.len()) + .ok_or(Error::::NotController)?; // ensure that there's chunk slots available by requesting the staking interface to // withdraw chunks older than `BondingDuration`, if there are no more unlocking chunks // slots available. - if Self::chunk_slots_filled(&controller)? == T::MaxUnlockingChunks::get() as usize { - Self::withdraw_unbonded(origin, SLASHING_SPANS_AUTO_WITHDRAW) + if unlocking == T::MaxUnlockingChunks::get() as usize { + Self::do_withdraw_unbonded(&controller, SLASHING_SPANS_AUTO_WITHDRAW) .map_err(|with_post| with_post.error)?; - }; + } let mut ledger = Self::ledger(&controller).ok_or(Error::::NotController)?; - let mut value = value.min(ledger.active); if !value.is_zero() { @@ -1035,40 +1036,7 @@ pub mod pallet { num_slashing_spans: u32, ) -> DispatchResultWithPostInfo { let controller = ensure_signed(origin)?; - let mut ledger = Self::ledger(&controller).ok_or(Error::::NotController)?; - let (stash, old_total) = (ledger.stash.clone(), ledger.total); - if let Some(current_era) = Self::current_era() { - ledger = ledger.consolidate_unlocked(current_era) - } - - let post_info_weight = if ledger.unlocking.is_empty() && - ledger.active < T::Currency::minimum_balance() - { - // This account must have called `unbond()` with some value that caused the active - // portion to fall below existential deposit + will have no more unlocking chunks - // left. We can now safely remove all staking-related information. - Self::kill_stash(&stash, num_slashing_spans)?; - // Remove the lock. - T::Currency::remove_lock(STAKING_ID, &stash); - // This is worst case scenario, so we use the full weight and return None - None - } else { - // This was the consequence of a partial unbond. just update the ledger and move on. - Self::update_ledger(&controller, &ledger); - - // This is only an update, so we use less overall weight. - Some(T::WeightInfo::withdraw_unbonded_update(num_slashing_spans)) - }; - - // `old_total` should never be less than the new total because - // `consolidate_unlocked` strictly subtracts balance. - if ledger.total < old_total { - // Already checked that this won't overflow by entry condition. - let value = old_total - ledger.total; - Self::deposit_event(Event::::Withdrawn { stash, amount: value }); - } - - Ok(post_info_weight.into()) + Self::do_withdraw_unbonded(&controller, num_slashing_spans) } /// Declare the desire to validate for the origin controller. diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 743d61024d43a..7a1f5c6f334c5 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -1371,7 +1371,7 @@ fn many_unbond_calls_should_work() { // == 3). assert_ok!(Staking::unbond(RuntimeOrigin::signed(10), 1)); assert_eq!( - Staking::chunk_slots_filled(&10).unwrap(), + Staking::ledger(&10).map(|l| l.unlocking.len()).unwrap(), <::MaxUnlockingChunks as Get>::get() as usize ); @@ -1386,7 +1386,7 @@ fn many_unbond_calls_should_work() { // only slots of unbonds within last `BondingDuration` are filled. assert_eq!( - Staking::chunk_slots_filled(&10).unwrap(), + Staking::ledger(&10).map(|l| l.unlocking.len()).unwrap(), <::BondingDuration>::get() as usize ); }) From e89a3cd8e43f05ae6d495208a2b11a388b2d58fe Mon Sep 17 00:00:00 2001 From: gpestana Date: Thu, 10 Nov 2022 00:26:39 +0100 Subject: [PATCH 04/20] a --- frame/staking/src/pallet/impls.rs | 56 ++++++++++++++++++++++--------- frame/staking/src/pallet/mod.rs | 7 ++-- 2 files changed, 43 insertions(+), 20 deletions(-) diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 84a827a9ee74f..bf9b3bfd19523 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -102,23 +102,44 @@ impl Pallet { ledger = ledger.consolidate_unlocked(current_era) } - let post_info_weight = - if ledger.unlocking.is_empty() && ledger.active < T::Currency::minimum_balance() { - // This account must have called `unbond()` with some value that caused the active - // portion to fall below existential deposit + will have no more unlocking chunks - // left. We can now safely remove all staking-related information. - Self::kill_stash(&stash, num_slashing_spans)?; - // Remove the lock. - T::Currency::remove_lock(STAKING_ID, &stash); - // This is worst case scenario, so we use the full weight and return None - None + let mut dispatch_weight = Weight::zero(); + + let num_slashing_spans = { + // if using the speculative number of spans, get real number of slashing spans and + // calculate weight associated with fetching real number of slashing spans. + if num_slashing_spans == crate::SPECULATIVE_NUM_SPANS { + let real_num_slashing_spans = Self::slashing_spans(&controller).iter().count(); + dispatch_weight = T::DbWeight::get() + .reads(1 as u64) + .saturating_mul(real_num_slashing_spans as u64); + + real_num_slashing_spans as u32 } else { - // This was the consequence of a partial unbond. just update the ledger and move on. - Self::update_ledger(&controller, &ledger); + num_slashing_spans + } + }; - // This is only an update, so we use less overall weight. - Some(T::WeightInfo::withdraw_unbonded_update(num_slashing_spans)) - }; + let post_info_weight = if ledger.unlocking.is_empty() && + ledger.active < T::Currency::minimum_balance() + { + // This account must have called `unbond()` with some value that caused the active + // portion to fall below existential deposit + will have no more unlocking chunks + // left. We can now safely remove all staking-related information. + Self::kill_stash(&stash, num_slashing_spans)?; + // Remove the lock. + T::Currency::remove_lock(STAKING_ID, &stash); + // This is worst case scenario, so we use the full weight and return None + None + } else { + // This was the consequence of a partial unbond. just update the ledger and move on. + Self::update_ledger(&controller, &ledger); + + // This is only an update, so we use less overall weight. + Some( + dispatch_weight + .saturating_add(T::WeightInfo::withdraw_unbonded_update(num_slashing_spans)), + ) + }; // `old_total` should never be less than the new total because // `consolidate_unlocked` strictly subtracts balance. @@ -128,7 +149,10 @@ impl Pallet { Self::deposit_event(Event::::Withdrawn { stash, amount: value }); } - Ok(post_info_weight.into()) + Ok(post_info_weight + .map(|weight| weight.saturating_add(dispatch_weight)) + .or_else(|| Some(dispatch_weight)) + .into()) } pub(super) fn do_payout_stakers( diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 3fd2343961720..5d990f6f5fd27 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -49,7 +49,7 @@ use crate::{ }; const STAKING_ID: LockIdentifier = *b"staking "; -const SLASHING_SPANS_AUTO_WITHDRAW: u32 = 0; +pub(crate) const SPECULATIVE_NUM_SPANS: u32 = 10_000; #[frame_support::pallet] pub mod pallet { @@ -114,7 +114,6 @@ pub mod pallet { // we only accept an election provider that has staking as data provider. DataProvider = Pallet, >; - /// Something that provides the election functionality at genesis. type GenesisElectionProvider: frame_election_provider_support::ElectionProvider< AccountId = Self::AccountId, @@ -943,7 +942,7 @@ pub mod pallet { /// /// See also [`Call::withdraw_unbonded`]. #[pallet::weight( - T::WeightInfo::withdraw_unbonded_kill(SLASHING_SPANS_AUTO_WITHDRAW) + T::WeightInfo::unbond()) + T::WeightInfo::withdraw_unbonded_kill(SPECULATIVE_NUM_SPANS).saturating_add(T::WeightInfo::unbond())) ] pub fn unbond( origin: OriginFor, @@ -958,7 +957,7 @@ pub mod pallet { // withdraw chunks older than `BondingDuration`, if there are no more unlocking chunks // slots available. if unlocking == T::MaxUnlockingChunks::get() as usize { - Self::do_withdraw_unbonded(&controller, SLASHING_SPANS_AUTO_WITHDRAW) + Self::do_withdraw_unbonded(&controller, SPECULATIVE_NUM_SPANS) .map_err(|with_post| with_post.error)?; } From 437ed300a23dcdcc86cecd0a5c265a93d28cfb7f Mon Sep 17 00:00:00 2001 From: gpestana Date: Mon, 14 Nov 2022 07:02:53 +0100 Subject: [PATCH 05/20] callable unbond() to return a DispatchWithPostInfo to dynamically update the consumed weight --- frame/staking/src/pallet/impls.rs | 2 ++ frame/staking/src/pallet/mod.rs | 10 +++++----- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index bf9b3bfd19523..715856209ef17 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -1605,6 +1605,8 @@ impl StakingInterface for Pallet { fn unbond(who: &Self::AccountId, value: Self::Balance) -> DispatchResult { let ctrl = Self::bonded(who).ok_or(Error::::NotStash)?; Self::unbond(RawOrigin::Signed(ctrl).into(), value) + .map_err(|with_post| with_post.error) + .map(|_| ()) } fn chill(who: &Self::AccountId) -> DispatchResult { diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 5d990f6f5fd27..61798dea5180e 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -947,7 +947,7 @@ pub mod pallet { pub fn unbond( origin: OriginFor, #[pallet::compact] value: BalanceOf, - ) -> DispatchResult { + ) -> DispatchResultWithPostInfo { let controller = ensure_signed(origin.clone())?; let unlocking = Self::ledger(&controller) .map(|l| l.unlocking.len()) @@ -957,8 +957,7 @@ pub mod pallet { // withdraw chunks older than `BondingDuration`, if there are no more unlocking chunks // slots available. if unlocking == T::MaxUnlockingChunks::get() as usize { - Self::do_withdraw_unbonded(&controller, SPECULATIVE_NUM_SPANS) - .map_err(|with_post| with_post.error)?; + Self::do_withdraw_unbonded(&controller, SPECULATIVE_NUM_SPANS)?; } let mut ledger = Self::ledger(&controller).ok_or(Error::::NotController)?; @@ -977,7 +976,8 @@ pub mod pallet { MinNominatorBond::::get() } else if Validators::::contains_key(&ledger.stash) { MinValidatorBond::::get() - } else { + + } else { Zero::zero() }; @@ -1011,7 +1011,7 @@ pub mod pallet { Self::deposit_event(Event::::Unbonded { stash: ledger.stash, amount: value }); } - Ok(()) + Ok(().into()) } /// Remove any unlocked chunks from the `unlocking` queue from our management. From af00da54d6a812d737a265d6f2ddde4a1a011581 Mon Sep 17 00:00:00 2001 From: gpestana Date: Mon, 14 Nov 2022 20:14:04 +0000 Subject: [PATCH 06/20] refunds overpaid fees when unbond with withdraw --- frame/staking/src/pallet/impls.rs | 5 ++--- frame/staking/src/pallet/mod.rs | 32 ++++++++++++++++++++++++------- 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 715856209ef17..d6c75166e0eb9 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -103,7 +103,6 @@ impl Pallet { } let mut dispatch_weight = Weight::zero(); - let num_slashing_spans = { // if using the speculative number of spans, get real number of slashing spans and // calculate weight associated with fetching real number of slashing spans. @@ -1605,8 +1604,8 @@ impl StakingInterface for Pallet { fn unbond(who: &Self::AccountId, value: Self::Balance) -> DispatchResult { let ctrl = Self::bonded(who).ok_or(Error::::NotStash)?; Self::unbond(RawOrigin::Signed(ctrl).into(), value) - .map_err(|with_post| with_post.error) - .map(|_| ()) + .map_err(|with_post| with_post.error) + .map(|_| ()) } fn chill(who: &Self::AccountId) -> DispatchResult { diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 61798dea5180e..c62644875ac91 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -49,7 +49,7 @@ use crate::{ }; const STAKING_ID: LockIdentifier = *b"staking "; -pub(crate) const SPECULATIVE_NUM_SPANS: u32 = 10_000; +pub(crate) const SPECULATIVE_NUM_SPANS: u32 = 100; #[frame_support::pallet] pub mod pallet { @@ -956,13 +956,24 @@ pub mod pallet { // ensure that there's chunk slots available by requesting the staking interface to // withdraw chunks older than `BondingDuration`, if there are no more unlocking chunks // slots available. - if unlocking == T::MaxUnlockingChunks::get() as usize { - Self::do_withdraw_unbonded(&controller, SPECULATIVE_NUM_SPANS)?; - } + let maybe_dispatch_weight = { + if unlocking == T::MaxUnlockingChunks::get() as usize { + Self::do_withdraw_unbonded(&controller, SPECULATIVE_NUM_SPANS)?.actual_weight + } else { + None + } + }; let mut ledger = Self::ledger(&controller).ok_or(Error::::NotController)?; let mut value = value.min(ledger.active); + // this should not happen anymore, but we want to make sure the unbonding does not + // proceed if for some reason the chunks were not freed. + ensure!( + ledger.unlocking.len() < T::MaxUnlockingChunks::get() as usize, + Error::::NoMoreChunks, + ); + if !value.is_zero() { ledger.active -= value; @@ -976,8 +987,7 @@ pub mod pallet { MinNominatorBond::::get() } else if Validators::::contains_key(&ledger.stash) { MinValidatorBond::::get() - - } else { + } else { Zero::zero() }; @@ -1011,7 +1021,15 @@ pub mod pallet { Self::deposit_event(Event::::Unbonded { stash: ledger.stash, amount: value }); } - Ok(().into()) + + if let Some(weight) = maybe_dispatch_weight { + Ok(frame_support::dispatch::PostDispatchInfo { + actual_weight: Some(weight.saturating_add(T::WeightInfo::unbond())), + pays_fee: Pays::Yes, + }) + } else { + Ok(().into()) + } } /// Remove any unlocked chunks from the `unlocking` queue from our management. From 2fe20e41577ae39b0c90b370b544822c392f4cff Mon Sep 17 00:00:00 2001 From: gpestana Date: Tue, 15 Nov 2022 16:17:03 +0000 Subject: [PATCH 07/20] fetches real slashing spans before withdrawal call --- frame/staking/src/pallet/impls.rs | 55 +++++++++---------------------- frame/staking/src/pallet/mod.rs | 4 ++- 2 files changed, 19 insertions(+), 40 deletions(-) diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index d6c75166e0eb9..b1c16631068ae 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -102,43 +102,23 @@ impl Pallet { ledger = ledger.consolidate_unlocked(current_era) } - let mut dispatch_weight = Weight::zero(); - let num_slashing_spans = { - // if using the speculative number of spans, get real number of slashing spans and - // calculate weight associated with fetching real number of slashing spans. - if num_slashing_spans == crate::SPECULATIVE_NUM_SPANS { - let real_num_slashing_spans = Self::slashing_spans(&controller).iter().count(); - dispatch_weight = T::DbWeight::get() - .reads(1 as u64) - .saturating_mul(real_num_slashing_spans as u64); - - real_num_slashing_spans as u32 + let post_info_weight = + if ledger.unlocking.is_empty() && ledger.active < T::Currency::minimum_balance() { + // This account must have called `unbond()` with some value that caused the active + // portion to fall below existential deposit + will have no more unlocking chunks + // left. We can now safely remove all staking-related information. + Self::kill_stash(&stash, num_slashing_spans)?; + // Remove the lock. + T::Currency::remove_lock(STAKING_ID, &stash); + // This is worst case scenario, so we use the full weight and return None + None } else { - num_slashing_spans - } - }; - - let post_info_weight = if ledger.unlocking.is_empty() && - ledger.active < T::Currency::minimum_balance() - { - // This account must have called `unbond()` with some value that caused the active - // portion to fall below existential deposit + will have no more unlocking chunks - // left. We can now safely remove all staking-related information. - Self::kill_stash(&stash, num_slashing_spans)?; - // Remove the lock. - T::Currency::remove_lock(STAKING_ID, &stash); - // This is worst case scenario, so we use the full weight and return None - None - } else { - // This was the consequence of a partial unbond. just update the ledger and move on. - Self::update_ledger(&controller, &ledger); + // This was the consequence of a partial unbond. just update the ledger and move on. + Self::update_ledger(&controller, &ledger); - // This is only an update, so we use less overall weight. - Some( - dispatch_weight - .saturating_add(T::WeightInfo::withdraw_unbonded_update(num_slashing_spans)), - ) - }; + // This is only an update, so we use less overall weight. + Some(T::WeightInfo::withdraw_unbonded_update(num_slashing_spans)) + }; // `old_total` should never be less than the new total because // `consolidate_unlocked` strictly subtracts balance. @@ -148,10 +128,7 @@ impl Pallet { Self::deposit_event(Event::::Withdrawn { stash, amount: value }); } - Ok(post_info_weight - .map(|weight| weight.saturating_add(dispatch_weight)) - .or_else(|| Some(dispatch_weight)) - .into()) + Ok(post_info_weight.into()) } pub(super) fn do_payout_stakers( diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index c62644875ac91..a2f2e5c8c2f43 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -957,8 +957,10 @@ pub mod pallet { // withdraw chunks older than `BondingDuration`, if there are no more unlocking chunks // slots available. let maybe_dispatch_weight = { + let real_num_slashing_spans = Self::slashing_spans(&controller).iter().count(); if unlocking == T::MaxUnlockingChunks::get() as usize { - Self::do_withdraw_unbonded(&controller, SPECULATIVE_NUM_SPANS)?.actual_weight + Self::do_withdraw_unbonded(&controller, real_num_slashing_spans as u32)? + .actual_weight } else { None } From ffeb1b0543fc753ff67b82493a2a8e45c734e819 Mon Sep 17 00:00:00 2001 From: gpestana Date: Tue, 15 Nov 2022 16:42:58 +0000 Subject: [PATCH 08/20] nits --- frame/staking/src/pallet/mod.rs | 6 +++--- frame/staking/src/tests.rs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index a2f2e5c8c2f43..965256359c62c 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -948,7 +948,7 @@ pub mod pallet { origin: OriginFor, #[pallet::compact] value: BalanceOf, ) -> DispatchResultWithPostInfo { - let controller = ensure_signed(origin.clone())?; + let controller = ensure_signed(origin)?; let unlocking = Self::ledger(&controller) .map(|l| l.unlocking.len()) .ok_or(Error::::NotController)?; @@ -956,7 +956,7 @@ pub mod pallet { // ensure that there's chunk slots available by requesting the staking interface to // withdraw chunks older than `BondingDuration`, if there are no more unlocking chunks // slots available. - let maybe_dispatch_weight = { + let maybe_withdraw_weight = { let real_num_slashing_spans = Self::slashing_spans(&controller).iter().count(); if unlocking == T::MaxUnlockingChunks::get() as usize { Self::do_withdraw_unbonded(&controller, real_num_slashing_spans as u32)? @@ -1024,7 +1024,7 @@ pub mod pallet { Self::deposit_event(Event::::Unbonded { stash: ledger.stash, amount: value }); } - if let Some(weight) = maybe_dispatch_weight { + if let Some(weight) = maybe_withdraw_weight { Ok(frame_support::dispatch::PostDispatchInfo { actual_weight: Some(weight.saturating_add(T::WeightInfo::unbond())), pays_fee: Pays::Yes, diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 7a1f5c6f334c5..c89db90dc22c5 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -1384,7 +1384,7 @@ fn many_unbond_calls_should_work() { assert_ok!(Staking::unbond(RuntimeOrigin::signed(10), 1)); } - // only slots of unbonds within last `BondingDuration` are filled. + // only slots within last `BondingDuration` are filled. assert_eq!( Staking::ledger(&10).map(|l| l.unlocking.len()).unwrap(), <::BondingDuration>::get() as usize From d6b5adc139c9bab16a9ccac94861c18a8f641923 Mon Sep 17 00:00:00 2001 From: gpestana Date: Sun, 20 Nov 2022 16:43:53 +0000 Subject: [PATCH 09/20] addresses PR comments --- frame/staking/src/pallet/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 965256359c62c..49f511fad8538 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -49,7 +49,7 @@ use crate::{ }; const STAKING_ID: LockIdentifier = *b"staking "; -pub(crate) const SPECULATIVE_NUM_SPANS: u32 = 100; +pub(crate) const SPECULATIVE_NUM_SPANS: u32 = 32; #[frame_support::pallet] pub mod pallet { @@ -957,8 +957,8 @@ pub mod pallet { // withdraw chunks older than `BondingDuration`, if there are no more unlocking chunks // slots available. let maybe_withdraw_weight = { - let real_num_slashing_spans = Self::slashing_spans(&controller).iter().count(); if unlocking == T::MaxUnlockingChunks::get() as usize { + let real_num_slashing_spans = Self::slashing_spans(&controller).iter().count(); Self::do_withdraw_unbonded(&controller, real_num_slashing_spans as u32)? .actual_weight } else { @@ -966,11 +966,11 @@ pub mod pallet { } }; + // we need to fetch the ledger again because it may have been mutated in the call + // to `Self::do_withdraw_unbonded` above. let mut ledger = Self::ledger(&controller).ok_or(Error::::NotController)?; let mut value = value.min(ledger.active); - // this should not happen anymore, but we want to make sure the unbonding does not - // proceed if for some reason the chunks were not freed. ensure!( ledger.unlocking.len() < T::MaxUnlockingChunks::get() as usize, Error::::NoMoreChunks, From add919fd69e77a8968a5e08bffb54eee7615fdcd Mon Sep 17 00:00:00 2001 From: gpestana Date: Mon, 21 Nov 2022 21:44:57 +0000 Subject: [PATCH 10/20] Adds more testing --- frame/staking/src/tests.rs | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index c89db90dc22c5..ebb36d2025eda 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -1367,8 +1367,8 @@ fn many_unbond_calls_should_work() { current_era += 1; mock::start_active_era(current_era); - // This chunk is locked at `current_era` through `current_era + 2` (because `BondingDuration` - // == 3). + // This chunk is locked at `current_era` through `current_era + 2` (because + // `BondingDuration` == 3). assert_ok!(Staking::unbond(RuntimeOrigin::signed(10), 1)); assert_eq!( Staking::ledger(&10).map(|l| l.unlocking.len()).unwrap(), @@ -1392,6 +1392,35 @@ fn many_unbond_calls_should_work() { }) } +#[test] +fn auto_withdraw_may_not_unlock_all_chunks() { + ExtBuilder::default().build_and_execute(|| { + // set `MaxUnlockingChunks` to a low number to test case when the unbonding period + // is larger than the number of unlocking chunks available, which may result on a + // `Error::NoMoreChunks`, even when the auto-withdraw tries to release locked chunks. + MaxUnlockingChunks::set(1); + + let mut current_era = 0; + + // fills the chunking slots for account + mock::start_active_era(current_era); + assert_ok!(Staking::unbond(RuntimeOrigin::signed(10), 1)); + + current_era += 1; + mock::start_active_era(current_era); + + // unbonding will fail because i) there are no remaining chunks and ii) no filled chunks + // can be released because current chunk hasn't stay in the queue for at least + // `BondingDuration` + assert!(Staking::unbond(RuntimeOrigin::signed(10), 1).is_err()); + + // fast-forward a few eras for unbond to be successful with implicit withdraw + current_era += 10; + mock::start_active_era(current_era); + assert_ok!(Staking::unbond(RuntimeOrigin::signed(10), 1)); + }) +} + #[test] fn rebond_works() { // From 90461ad8a9b02ee770ca6664b5a8f334c85e1c6a Mon Sep 17 00:00:00 2001 From: gpestana Date: Tue, 29 Nov 2022 12:08:53 +0000 Subject: [PATCH 11/20] fixes doc comments --- frame/nomination-pools/src/lib.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/frame/nomination-pools/src/lib.rs b/frame/nomination-pools/src/lib.rs index b35f306a68329..a99885853dd17 100644 --- a/frame/nomination-pools/src/lib.rs +++ b/frame/nomination-pools/src/lib.rs @@ -1608,8 +1608,14 @@ pub mod pallet { /// /// # Note /// + /// If there are too many unlocking chunks to unbond with the pool account, + /// [`Call::pool_withdraw_unbonded`] can be called to try and minimize unlocking chunks. /// The [`StakingInterface::unbond`] will implicitly call [`Call::pool_withdraw_unbonded`] - /// if there are no left unlocking chunk slots available. + /// to try to free chunks if necessary (ie. if unbound was called and no unlocking chunks + /// are available). However, it may not be possible to release the current unlocking chunks, + /// in which case, the result of this call will likely be the `NoMoreChunks` error from the + /// staking system. + #[pallet::weight(T::WeightInfo::unbond())] #[transactional] pub fn unbond( From a12d351ec9c5ff5f5be35c94de263825a6675ad4 Mon Sep 17 00:00:00 2001 From: gpestana Date: Thu, 1 Dec 2022 21:51:43 +0000 Subject: [PATCH 12/20] Fixes weight refunding logic for fn unbond --- frame/staking/src/pallet/impls.rs | 8 ++++---- frame/staking/src/pallet/mod.rs | 19 +++++++++---------- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index b1c16631068ae..c2d2d3f91df0b 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -102,7 +102,7 @@ impl Pallet { ledger = ledger.consolidate_unlocked(current_era) } - let post_info_weight = + let post_info = if ledger.unlocking.is_empty() && ledger.active < T::Currency::minimum_balance() { // This account must have called `unbond()` with some value that caused the active // portion to fall below existential deposit + will have no more unlocking chunks @@ -110,8 +110,8 @@ impl Pallet { Self::kill_stash(&stash, num_slashing_spans)?; // Remove the lock. T::Currency::remove_lock(STAKING_ID, &stash); - // This is worst case scenario, so we use the full weight and return None - None + + Some(T::WeightInfo::withdraw_unbonded_kill(num_slashing_spans)) } else { // This was the consequence of a partial unbond. just update the ledger and move on. Self::update_ledger(&controller, &ledger); @@ -128,7 +128,7 @@ impl Pallet { Self::deposit_event(Event::::Withdrawn { stash, amount: value }); } - Ok(post_info_weight.into()) + Ok(post_info.into()) } pub(super) fn do_payout_stakers( diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 49f511fad8538..d91df6d988773 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -19,7 +19,7 @@ use frame_election_provider_support::{SortedListProvider, VoteWeight}; use frame_support::{ - dispatch::Codec, + dispatch::{Codec, PostDispatchInfo}, pallet_prelude::*, traits::{ Currency, CurrencyToVote, Defensive, DefensiveResult, DefensiveSaturating, EnsureOrigin, @@ -966,8 +966,8 @@ pub mod pallet { } }; - // we need to fetch the ledger again because it may have been mutated in the call - // to `Self::do_withdraw_unbonded` above. + // we need to fetch the ledger again because it may have been mutated in the call + // to `Self::do_withdraw_unbonded` above. let mut ledger = Self::ledger(&controller).ok_or(Error::::NotController)?; let mut value = value.min(ledger.active); @@ -1024,14 +1024,13 @@ pub mod pallet { Self::deposit_event(Event::::Unbonded { stash: ledger.stash, amount: value }); } - if let Some(weight) = maybe_withdraw_weight { - Ok(frame_support::dispatch::PostDispatchInfo { - actual_weight: Some(weight.saturating_add(T::WeightInfo::unbond())), - pays_fee: Pays::Yes, - }) + let actual_weight = if let Some(withdraw_weight) = maybe_withdraw_weight { + Some(T::WeightInfo::unbond().saturating_add(withdraw_weight)) } else { - Ok(().into()) - } + Some(T::WeightInfo::unbond()) + }; + + Ok(PostDispatchInfo { actual_weight, pays_fee: Pays::Yes }) } /// Remove any unlocked chunks from the `unlocking` queue from our management. From 8cc482ac1a9cc776c81ac3bd0a8291eb7fa11903 Mon Sep 17 00:00:00 2001 From: gpestana Date: Fri, 2 Dec 2022 12:01:45 +0000 Subject: [PATCH 13/20] generalizes to return used weight or dispatch error --- frame/staking/src/pallet/impls.rs | 10 +++++----- frame/staking/src/pallet/mod.rs | 9 +++++++-- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index c2d2d3f91df0b..959346f23f96f 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -95,14 +95,14 @@ impl Pallet { pub(super) fn do_withdraw_unbonded( controller: &T::AccountId, num_slashing_spans: u32, - ) -> DispatchResultWithPostInfo { + ) -> Result { let mut ledger = Self::ledger(&controller).ok_or(Error::::NotController)?; let (stash, old_total) = (ledger.stash.clone(), ledger.total); if let Some(current_era) = Self::current_era() { ledger = ledger.consolidate_unlocked(current_era) } - let post_info = + let used_weight = if ledger.unlocking.is_empty() && ledger.active < T::Currency::minimum_balance() { // This account must have called `unbond()` with some value that caused the active // portion to fall below existential deposit + will have no more unlocking chunks @@ -111,13 +111,13 @@ impl Pallet { // Remove the lock. T::Currency::remove_lock(STAKING_ID, &stash); - Some(T::WeightInfo::withdraw_unbonded_kill(num_slashing_spans)) + T::WeightInfo::withdraw_unbonded_kill(num_slashing_spans) } else { // This was the consequence of a partial unbond. just update the ledger and move on. Self::update_ledger(&controller, &ledger); // This is only an update, so we use less overall weight. - Some(T::WeightInfo::withdraw_unbonded_update(num_slashing_spans)) + T::WeightInfo::withdraw_unbonded_update(num_slashing_spans) }; // `old_total` should never be less than the new total because @@ -128,7 +128,7 @@ impl Pallet { Self::deposit_event(Event::::Withdrawn { stash, amount: value }); } - Ok(post_info.into()) + Ok(used_weight) } pub(super) fn do_payout_stakers( diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index d91df6d988773..74532dfc1999c 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -959,8 +959,7 @@ pub mod pallet { let maybe_withdraw_weight = { if unlocking == T::MaxUnlockingChunks::get() as usize { let real_num_slashing_spans = Self::slashing_spans(&controller).iter().count(); - Self::do_withdraw_unbonded(&controller, real_num_slashing_spans as u32)? - .actual_weight + Some(Self::do_withdraw_unbonded(&controller, real_num_slashing_spans as u32)?) } else { None } @@ -1054,7 +1053,13 @@ pub mod pallet { num_slashing_spans: u32, ) -> DispatchResultWithPostInfo { let controller = ensure_signed(origin)?; + Self::do_withdraw_unbonded(&controller, num_slashing_spans) + .map(|weight| frame_support::dispatch::PostDispatchInfo { + actual_weight: Some(weight), + pays_fee: Pays::Yes, + }) + .map_err(|e| e.into()) } /// Declare the desire to validate for the origin controller. From a56794dc4bef9b0c1d4eb900e0d7f088c98c730d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Tue, 6 Dec 2022 23:30:22 +0000 Subject: [PATCH 14/20] Update frame/staking/src/pallet/mod.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> --- frame/staking/src/pallet/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 74532dfc1999c..38254e6db9b20 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -1029,7 +1029,7 @@ pub mod pallet { Some(T::WeightInfo::unbond()) }; - Ok(PostDispatchInfo { actual_weight, pays_fee: Pays::Yes }) + Ok(Some(actual_weight).into()) } /// Remove any unlocked chunks from the `unlocking` queue from our management. From e209b7fb57e0ec1e5b00d258967d876e779802da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Tue, 6 Dec 2022 23:33:19 +0000 Subject: [PATCH 15/20] Update frame/staking/src/pallet/mod.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> --- frame/staking/src/pallet/mod.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 38254e6db9b20..3d09de3793aa4 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -1054,12 +1054,8 @@ pub mod pallet { ) -> DispatchResultWithPostInfo { let controller = ensure_signed(origin)?; - Self::do_withdraw_unbonded(&controller, num_slashing_spans) - .map(|weight| frame_support::dispatch::PostDispatchInfo { - actual_weight: Some(weight), - pays_fee: Pays::Yes, - }) - .map_err(|e| e.into()) + let actualy_weight = Self::do_withdraw_unbonded(&controller, num_slashing_spans)?; + Ok(Some(actual_weight)) } /// Declare the desire to validate for the origin controller. From acaac8497a46f1ef1b0340bfe4a9f4b90df5d17c Mon Sep 17 00:00:00 2001 From: gpestana Date: Wed, 7 Dec 2022 01:00:50 +0100 Subject: [PATCH 16/20] Addresses PR comments --- frame/staking/src/pallet/mod.rs | 13 ++++++------- frame/staking/src/tests.rs | 2 +- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 3d09de3793aa4..8607cae1a157b 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -19,7 +19,7 @@ use frame_election_provider_support::{SortedListProvider, VoteWeight}; use frame_support::{ - dispatch::{Codec, PostDispatchInfo}, + dispatch::Codec, pallet_prelude::*, traits::{ Currency, CurrencyToVote, Defensive, DefensiveResult, DefensiveSaturating, EnsureOrigin, @@ -953,9 +953,8 @@ pub mod pallet { .map(|l| l.unlocking.len()) .ok_or(Error::::NotController)?; - // ensure that there's chunk slots available by requesting the staking interface to - // withdraw chunks older than `BondingDuration`, if there are no more unlocking chunks - // slots available. + // if there are no unlocking chunks available, try to withdraw chunks older than + // `BondingDuration` to proceed with the unbonding. let maybe_withdraw_weight = { if unlocking == T::MaxUnlockingChunks::get() as usize { let real_num_slashing_spans = Self::slashing_spans(&controller).iter().count(); @@ -1029,7 +1028,7 @@ pub mod pallet { Some(T::WeightInfo::unbond()) }; - Ok(Some(actual_weight).into()) + Ok(actual_weight.into()) } /// Remove any unlocked chunks from the `unlocking` queue from our management. @@ -1054,8 +1053,8 @@ pub mod pallet { ) -> DispatchResultWithPostInfo { let controller = ensure_signed(origin)?; - let actualy_weight = Self::do_withdraw_unbonded(&controller, num_slashing_spans)?; - Ok(Some(actual_weight)) + let actual_weight = Self::do_withdraw_unbonded(&controller, num_slashing_spans)?; + Ok(Some(actual_weight).into()) } /// Declare the desire to validate for the origin controller. diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index ebb36d2025eda..bc8e1da5d759c 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -1412,7 +1412,7 @@ fn auto_withdraw_may_not_unlock_all_chunks() { // unbonding will fail because i) there are no remaining chunks and ii) no filled chunks // can be released because current chunk hasn't stay in the queue for at least // `BondingDuration` - assert!(Staking::unbond(RuntimeOrigin::signed(10), 1).is_err()); + assert_noop!(Staking::unbond(RuntimeOrigin::signed(10), 1), Error::::NoMoreChunks); // fast-forward a few eras for unbond to be successful with implicit withdraw current_era += 10; From 05d98f6638d137aba4586f9c1c5dc036d5ffcb0f Mon Sep 17 00:00:00 2001 From: gpestana Date: Wed, 7 Dec 2022 01:26:04 +0100 Subject: [PATCH 17/20] Add comment to speculative num spans --- frame/staking/src/pallet/mod.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 8607cae1a157b..355460218edd0 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -49,6 +49,9 @@ use crate::{ }; const STAKING_ID: LockIdentifier = *b"staking "; +// The speculative number of spans are used as an input of the weight annotation of +// [`Call::unbond`], as the post dipatch weight may depend on the number of slashing span on the +// account which is not provided as an input. The value set should be conservative but sensible. pub(crate) const SPECULATIVE_NUM_SPANS: u32 = 32; #[frame_support::pallet] From 25317b5fa8e17124a046b06802d8d12af38d14bc Mon Sep 17 00:00:00 2001 From: gpestana Date: Wed, 14 Dec 2022 16:13:40 +0100 Subject: [PATCH 18/20] adds missing add_slashing_spans in withdraw_unbonded_kill benchmarks --- frame/staking/src/benchmarking.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/frame/staking/src/benchmarking.rs b/frame/staking/src/benchmarking.rs index 8409b5413f992..81fa0f9d81dbf 100644 --- a/frame/staking/src/benchmarking.rs +++ b/frame/staking/src/benchmarking.rs @@ -316,6 +316,7 @@ benchmarks! { let scenario = ListScenario::::new(origin_weight, true)?; let controller = scenario.origin_controller1.clone(); let stash = scenario.origin_stash1; + add_slashing_spans::(&stash, s); assert!(T::VoterList::contains(&stash)); let ed = T::Currency::minimum_balance(); From b376ad0ce7d37b7bb70f72387fa5f11ae43f2f11 Mon Sep 17 00:00:00 2001 From: command-bot <> Date: Wed, 14 Dec 2022 16:07:52 +0000 Subject: [PATCH 19/20] ".git/.scripts/bench-bot.sh" pallet dev pallet_staking --- frame/staking/src/weights.rs | 370 ++++++++++++++++++----------------- 1 file changed, 189 insertions(+), 181 deletions(-) diff --git a/frame/staking/src/weights.rs b/frame/staking/src/weights.rs index 21fc3d6f077bc..aebb8eeb9b06e 100644 --- a/frame/staking/src/weights.rs +++ b/frame/staking/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_staking //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-12-12, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-12-14, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 @@ -88,8 +88,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) // Storage: Staking Payee (r:0 w:1) fn bond() -> Weight { - // Minimum execution time: 56_034 nanoseconds. - Weight::from_ref_time(56_646_000) + // Minimum execution time: 54_402 nanoseconds. + Weight::from_ref_time(55_096_000) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -99,8 +99,8 @@ impl WeightInfo for SubstrateWeight { // Storage: VoterList ListNodes (r:3 w:3) // Storage: VoterList ListBags (r:2 w:2) fn bond_extra() -> Weight { - // Minimum execution time: 94_354 nanoseconds. - Weight::from_ref_time(95_318_000) + // Minimum execution time: 94_407 nanoseconds. + Weight::from_ref_time(95_209_000) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(7)) } @@ -114,8 +114,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Bonded (r:1 w:0) // Storage: VoterList ListBags (r:2 w:2) fn unbond() -> Weight { - // Minimum execution time: 99_960 nanoseconds. - Weight::from_ref_time(101_022_000) + // Minimum execution time: 101_046 nanoseconds. + Weight::from_ref_time(101_504_000) .saturating_add(T::DbWeight::get().reads(12)) .saturating_add(T::DbWeight::get().writes(8)) } @@ -125,10 +125,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_update(s: u32, ) -> Weight { - // Minimum execution time: 45_819 nanoseconds. - Weight::from_ref_time(48_073_614) - // Standard Error: 1_410 - .saturating_add(Weight::from_ref_time(62_881).saturating_mul(s.into())) + // Minimum execution time: 45_452 nanoseconds. + Weight::from_ref_time(47_031_537) + // Standard Error: 491 + .saturating_add(Weight::from_ref_time(67_148).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -145,12 +145,16 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: Staking Payee (r:0 w:1) + // Storage: Staking SpanSlash (r:0 w:2) /// The range of component `s` is `[0, 100]`. - fn withdraw_unbonded_kill(_s: u32, ) -> Weight { - // Minimum execution time: 86_035 nanoseconds. - Weight::from_ref_time(89_561_735) + fn withdraw_unbonded_kill(s: u32, ) -> Weight { + // Minimum execution time: 88_067 nanoseconds. + Weight::from_ref_time(93_309_587) + // Standard Error: 4_762 + .saturating_add(Weight::from_ref_time(1_114_938).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(13)) - .saturating_add(T::DbWeight::get().writes(11)) + .saturating_add(T::DbWeight::get().writes(12)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking MinValidatorBond (r:1 w:0) @@ -164,8 +168,8 @@ impl WeightInfo for SubstrateWeight { // Storage: VoterList CounterForListNodes (r:1 w:1) // Storage: Staking CounterForValidators (r:1 w:1) fn validate() -> Weight { - // Minimum execution time: 68_748 nanoseconds. - Weight::from_ref_time(69_285_000) + // Minimum execution time: 67_308 nanoseconds. + Weight::from_ref_time(68_266_000) .saturating_add(T::DbWeight::get().reads(11)) .saturating_add(T::DbWeight::get().writes(5)) } @@ -173,10 +177,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Nominators (r:1 w:1) /// The range of component `k` is `[1, 128]`. fn kick(k: u32, ) -> Weight { - // Minimum execution time: 41_641 nanoseconds. - Weight::from_ref_time(48_919_231) - // Standard Error: 11_548 - .saturating_add(Weight::from_ref_time(6_901_201).saturating_mul(k.into())) + // Minimum execution time: 40_913 nanoseconds. + Weight::from_ref_time(48_140_584) + // Standard Error: 13_396 + .saturating_add(Weight::from_ref_time(6_862_893).saturating_mul(k.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(k.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(k.into()))) @@ -194,10 +198,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking CounterForNominators (r:1 w:1) /// The range of component `n` is `[1, 16]`. fn nominate(n: u32, ) -> Weight { - // Minimum execution time: 75_097 nanoseconds. - Weight::from_ref_time(74_052_497) - // Standard Error: 6_784 - .saturating_add(Weight::from_ref_time(2_842_146).saturating_mul(n.into())) + // Minimum execution time: 73_490 nanoseconds. + Weight::from_ref_time(72_520_864) + // Standard Error: 7_090 + .saturating_add(Weight::from_ref_time(2_800_566).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(12)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(6)) @@ -210,58 +214,58 @@ impl WeightInfo for SubstrateWeight { // Storage: VoterList ListBags (r:1 w:1) // Storage: VoterList CounterForListNodes (r:1 w:1) fn chill() -> Weight { - // Minimum execution time: 67_307 nanoseconds. - Weight::from_ref_time(67_838_000) + // Minimum execution time: 66_293 nanoseconds. + Weight::from_ref_time(66_946_000) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(6)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking Payee (r:0 w:1) fn set_payee() -> Weight { - // Minimum execution time: 18_831 nanoseconds. - Weight::from_ref_time(19_047_000) + // Minimum execution time: 18_134 nanoseconds. + Weight::from_ref_time(18_497_000) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } // Storage: Staking Bonded (r:1 w:1) // Storage: Staking Ledger (r:2 w:2) fn set_controller() -> Weight { - // Minimum execution time: 27_534 nanoseconds. - Weight::from_ref_time(27_806_000) + // Minimum execution time: 26_728 nanoseconds. + Weight::from_ref_time(27_154_000) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) } // Storage: Staking ValidatorCount (r:0 w:1) fn set_validator_count() -> Weight { - // Minimum execution time: 5_211 nanoseconds. - Weight::from_ref_time(5_372_000) + // Minimum execution time: 4_877 nanoseconds. + Weight::from_ref_time(5_028_000) .saturating_add(T::DbWeight::get().writes(1)) } // Storage: Staking ForceEra (r:0 w:1) fn force_no_eras() -> Weight { - // Minimum execution time: 5_382 nanoseconds. - Weight::from_ref_time(5_654_000) + // Minimum execution time: 5_000 nanoseconds. + Weight::from_ref_time(5_290_000) .saturating_add(T::DbWeight::get().writes(1)) } // Storage: Staking ForceEra (r:0 w:1) fn force_new_era() -> Weight { - // Minimum execution time: 5_618 nanoseconds. - Weight::from_ref_time(5_714_000) + // Minimum execution time: 5_093 nanoseconds. + Weight::from_ref_time(5_378_000) .saturating_add(T::DbWeight::get().writes(1)) } // Storage: Staking ForceEra (r:0 w:1) fn force_new_era_always() -> Weight { - // Minimum execution time: 5_589 nanoseconds. - Weight::from_ref_time(5_776_000) + // Minimum execution time: 5_144 nanoseconds. + Weight::from_ref_time(5_454_000) .saturating_add(T::DbWeight::get().writes(1)) } // Storage: Staking Invulnerables (r:0 w:1) /// The range of component `v` is `[0, 1000]`. fn set_invulnerables(v: u32, ) -> Weight { - // Minimum execution time: 5_541 nanoseconds. - Weight::from_ref_time(6_479_253) - // Standard Error: 49 - .saturating_add(Weight::from_ref_time(10_125).saturating_mul(v.into())) + // Minimum execution time: 5_190 nanoseconds. + Weight::from_ref_time(5_960_962) + // Standard Error: 41 + .saturating_add(Weight::from_ref_time(10_329).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().writes(1)) } // Storage: Staking Bonded (r:1 w:1) @@ -279,10 +283,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking SpanSlash (r:0 w:2) /// The range of component `s` is `[0, 100]`. fn force_unstake(s: u32, ) -> Weight { - // Minimum execution time: 81_041 nanoseconds. - Weight::from_ref_time(88_526_481) - // Standard Error: 11_494 - .saturating_add(Weight::from_ref_time(1_095_933).saturating_mul(s.into())) + // Minimum execution time: 80_516 nanoseconds. + Weight::from_ref_time(86_317_884) + // Standard Error: 2_212 + .saturating_add(Weight::from_ref_time(1_103_962).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(11)) .saturating_add(T::DbWeight::get().writes(12)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -290,10 +294,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking UnappliedSlashes (r:1 w:1) /// The range of component `s` is `[1, 1000]`. fn cancel_deferred_slash(s: u32, ) -> Weight { - // Minimum execution time: 92_308 nanoseconds. - Weight::from_ref_time(900_351_007) - // Standard Error: 59_145 - .saturating_add(Weight::from_ref_time(4_944_988).saturating_mul(s.into())) + // Minimum execution time: 91_795 nanoseconds. + Weight::from_ref_time(904_524_900) + // Standard Error: 59_193 + .saturating_add(Weight::from_ref_time(4_944_680).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -308,10 +312,10 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:1 w:1) /// The range of component `n` is `[0, 256]`. fn payout_stakers_dead_controller(n: u32, ) -> Weight { - // Minimum execution time: 131_855 nanoseconds. - Weight::from_ref_time(197_412_779) - // Standard Error: 21_283 - .saturating_add(Weight::from_ref_time(22_093_758).saturating_mul(n.into())) + // Minimum execution time: 127_774 nanoseconds. + Weight::from_ref_time(178_857_156) + // Standard Error: 15_229 + .saturating_add(Weight::from_ref_time(22_112_174).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(2)) @@ -329,10 +333,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Balances Locks (r:1 w:1) /// The range of component `n` is `[0, 256]`. fn payout_stakers_alive_staked(n: u32, ) -> Weight { - // Minimum execution time: 163_118 nanoseconds. - Weight::from_ref_time(229_356_697) - // Standard Error: 30_740 - .saturating_add(Weight::from_ref_time(31_575_360).saturating_mul(n.into())) + // Minimum execution time: 161_910 nanoseconds. + Weight::from_ref_time(217_635_072) + // Standard Error: 30_726 + .saturating_add(Weight::from_ref_time(31_244_329).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(10)) .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(3)) @@ -346,10 +350,10 @@ impl WeightInfo for SubstrateWeight { // Storage: VoterList ListBags (r:2 w:2) /// The range of component `l` is `[1, 32]`. fn rebond(l: u32, ) -> Weight { - // Minimum execution time: 94_048 nanoseconds. - Weight::from_ref_time(95_784_236) - // Standard Error: 2_313 - .saturating_add(Weight::from_ref_time(52_798).saturating_mul(l.into())) + // Minimum execution time: 92_986 nanoseconds. + Weight::from_ref_time(94_880_481) + // Standard Error: 2_007 + .saturating_add(Weight::from_ref_time(31_421).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(8)) } @@ -368,10 +372,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking SpanSlash (r:0 w:1) /// The range of component `s` is `[1, 100]`. fn reap_stash(s: u32, ) -> Weight { - // Minimum execution time: 93_342 nanoseconds. - Weight::from_ref_time(95_756_184) - // Standard Error: 2_067 - .saturating_add(Weight::from_ref_time(1_090_785).saturating_mul(s.into())) + // Minimum execution time: 92_750 nanoseconds. + Weight::from_ref_time(95_115_568) + // Standard Error: 2_037 + .saturating_add(Weight::from_ref_time(1_086_488).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(12)) .saturating_add(T::DbWeight::get().writes(12)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -395,12 +399,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `v` is `[1, 10]`. /// The range of component `n` is `[0, 100]`. fn new_era(v: u32, n: u32, ) -> Weight { - // Minimum execution time: 506_874 nanoseconds. - Weight::from_ref_time(507_798_000) - // Standard Error: 1_802_261 - .saturating_add(Weight::from_ref_time(59_874_736).saturating_mul(v.into())) - // Standard Error: 179_585 - .saturating_add(Weight::from_ref_time(13_668_574).saturating_mul(n.into())) + // Minimum execution time: 506_543 nanoseconds. + Weight::from_ref_time(507_261_000) + // Standard Error: 1_766_631 + .saturating_add(Weight::from_ref_time(59_139_153).saturating_mul(v.into())) + // Standard Error: 176_035 + .saturating_add(Weight::from_ref_time(13_512_781).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(206)) .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(n.into()))) @@ -417,12 +421,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `v` is `[500, 1000]`. /// The range of component `n` is `[500, 1000]`. fn get_npos_voters(v: u32, n: u32, ) -> Weight { - // Minimum execution time: 24_634_585 nanoseconds. - Weight::from_ref_time(24_718_377_000) - // Standard Error: 324_839 - .saturating_add(Weight::from_ref_time(3_654_508).saturating_mul(v.into())) - // Standard Error: 324_839 - .saturating_add(Weight::from_ref_time(2_927_535).saturating_mul(n.into())) + // Minimum execution time: 24_155_382 nanoseconds. + Weight::from_ref_time(24_252_568_000) + // Standard Error: 319_250 + .saturating_add(Weight::from_ref_time(3_596_056).saturating_mul(v.into())) + // Standard Error: 319_250 + .saturating_add(Weight::from_ref_time(2_852_023).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(201)) .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(n.into()))) @@ -431,10 +435,10 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Validators (r:501 w:0) /// The range of component `v` is `[500, 1000]`. fn get_npos_targets(v: u32, ) -> Weight { - // Minimum execution time: 4_805_490 nanoseconds. - Weight::from_ref_time(118_475_494) - // Standard Error: 26_332 - .saturating_add(Weight::from_ref_time(9_635_188).saturating_mul(v.into())) + // Minimum execution time: 4_741_111 nanoseconds. + Weight::from_ref_time(113_360_179) + // Standard Error: 25_375 + .saturating_add(Weight::from_ref_time(9_494_142).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(v.into()))) } @@ -445,8 +449,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking MaxNominatorsCount (r:0 w:1) // Storage: Staking MinNominatorBond (r:0 w:1) fn set_staking_configs_all_set() -> Weight { - // Minimum execution time: 10_816 nanoseconds. - Weight::from_ref_time(11_242_000) + // Minimum execution time: 11_074 nanoseconds. + Weight::from_ref_time(11_312_000) .saturating_add(T::DbWeight::get().writes(6)) } // Storage: Staking MinCommission (r:0 w:1) @@ -456,8 +460,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking MaxNominatorsCount (r:0 w:1) // Storage: Staking MinNominatorBond (r:0 w:1) fn set_staking_configs_all_remove() -> Weight { - // Minimum execution time: 9_581 nanoseconds. - Weight::from_ref_time(10_383_000) + // Minimum execution time: 9_795 nanoseconds. + Weight::from_ref_time(10_116_000) .saturating_add(T::DbWeight::get().writes(6)) } // Storage: Staking Ledger (r:1 w:0) @@ -471,16 +475,16 @@ impl WeightInfo for SubstrateWeight { // Storage: VoterList ListBags (r:1 w:1) // Storage: VoterList CounterForListNodes (r:1 w:1) fn chill_other() -> Weight { - // Minimum execution time: 83_669 nanoseconds. - Weight::from_ref_time(84_772_000) + // Minimum execution time: 82_914 nanoseconds. + Weight::from_ref_time(83_848_000) .saturating_add(T::DbWeight::get().reads(11)) .saturating_add(T::DbWeight::get().writes(6)) } // Storage: Staking MinCommission (r:1 w:0) // Storage: Staking Validators (r:1 w:1) fn force_apply_min_commission() -> Weight { - // Minimum execution time: 20_553 nanoseconds. - Weight::from_ref_time(20_933_000) + // Minimum execution time: 20_317 nanoseconds. + Weight::from_ref_time(20_639_000) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -494,8 +498,8 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) // Storage: Staking Payee (r:0 w:1) fn bond() -> Weight { - // Minimum execution time: 56_034 nanoseconds. - Weight::from_ref_time(56_646_000) + // Minimum execution time: 54_402 nanoseconds. + Weight::from_ref_time(55_096_000) .saturating_add(RocksDbWeight::get().reads(4)) .saturating_add(RocksDbWeight::get().writes(4)) } @@ -505,8 +509,8 @@ impl WeightInfo for () { // Storage: VoterList ListNodes (r:3 w:3) // Storage: VoterList ListBags (r:2 w:2) fn bond_extra() -> Weight { - // Minimum execution time: 94_354 nanoseconds. - Weight::from_ref_time(95_318_000) + // Minimum execution time: 94_407 nanoseconds. + Weight::from_ref_time(95_209_000) .saturating_add(RocksDbWeight::get().reads(8)) .saturating_add(RocksDbWeight::get().writes(7)) } @@ -520,8 +524,8 @@ impl WeightInfo for () { // Storage: Staking Bonded (r:1 w:0) // Storage: VoterList ListBags (r:2 w:2) fn unbond() -> Weight { - // Minimum execution time: 99_960 nanoseconds. - Weight::from_ref_time(101_022_000) + // Minimum execution time: 101_046 nanoseconds. + Weight::from_ref_time(101_504_000) .saturating_add(RocksDbWeight::get().reads(12)) .saturating_add(RocksDbWeight::get().writes(8)) } @@ -531,10 +535,10 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_update(s: u32, ) -> Weight { - // Minimum execution time: 45_819 nanoseconds. - Weight::from_ref_time(48_073_614) - // Standard Error: 1_410 - .saturating_add(Weight::from_ref_time(62_881).saturating_mul(s.into())) + // Minimum execution time: 45_452 nanoseconds. + Weight::from_ref_time(47_031_537) + // Standard Error: 491 + .saturating_add(Weight::from_ref_time(67_148).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(4)) .saturating_add(RocksDbWeight::get().writes(3)) } @@ -551,12 +555,16 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: Staking Payee (r:0 w:1) + // Storage: Staking SpanSlash (r:0 w:2) /// The range of component `s` is `[0, 100]`. - fn withdraw_unbonded_kill(_s: u32, ) -> Weight { - // Minimum execution time: 86_035 nanoseconds. - Weight::from_ref_time(89_561_735) + fn withdraw_unbonded_kill(s: u32, ) -> Weight { + // Minimum execution time: 88_067 nanoseconds. + Weight::from_ref_time(93_309_587) + // Standard Error: 4_762 + .saturating_add(Weight::from_ref_time(1_114_938).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(13)) - .saturating_add(RocksDbWeight::get().writes(11)) + .saturating_add(RocksDbWeight::get().writes(12)) + .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking MinValidatorBond (r:1 w:0) @@ -570,8 +578,8 @@ impl WeightInfo for () { // Storage: VoterList CounterForListNodes (r:1 w:1) // Storage: Staking CounterForValidators (r:1 w:1) fn validate() -> Weight { - // Minimum execution time: 68_748 nanoseconds. - Weight::from_ref_time(69_285_000) + // Minimum execution time: 67_308 nanoseconds. + Weight::from_ref_time(68_266_000) .saturating_add(RocksDbWeight::get().reads(11)) .saturating_add(RocksDbWeight::get().writes(5)) } @@ -579,10 +587,10 @@ impl WeightInfo for () { // Storage: Staking Nominators (r:1 w:1) /// The range of component `k` is `[1, 128]`. fn kick(k: u32, ) -> Weight { - // Minimum execution time: 41_641 nanoseconds. - Weight::from_ref_time(48_919_231) - // Standard Error: 11_548 - .saturating_add(Weight::from_ref_time(6_901_201).saturating_mul(k.into())) + // Minimum execution time: 40_913 nanoseconds. + Weight::from_ref_time(48_140_584) + // Standard Error: 13_396 + .saturating_add(Weight::from_ref_time(6_862_893).saturating_mul(k.into())) .saturating_add(RocksDbWeight::get().reads(1)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(k.into()))) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(k.into()))) @@ -600,10 +608,10 @@ impl WeightInfo for () { // Storage: Staking CounterForNominators (r:1 w:1) /// The range of component `n` is `[1, 16]`. fn nominate(n: u32, ) -> Weight { - // Minimum execution time: 75_097 nanoseconds. - Weight::from_ref_time(74_052_497) - // Standard Error: 6_784 - .saturating_add(Weight::from_ref_time(2_842_146).saturating_mul(n.into())) + // Minimum execution time: 73_490 nanoseconds. + Weight::from_ref_time(72_520_864) + // Standard Error: 7_090 + .saturating_add(Weight::from_ref_time(2_800_566).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(12)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(6)) @@ -616,58 +624,58 @@ impl WeightInfo for () { // Storage: VoterList ListBags (r:1 w:1) // Storage: VoterList CounterForListNodes (r:1 w:1) fn chill() -> Weight { - // Minimum execution time: 67_307 nanoseconds. - Weight::from_ref_time(67_838_000) + // Minimum execution time: 66_293 nanoseconds. + Weight::from_ref_time(66_946_000) .saturating_add(RocksDbWeight::get().reads(8)) .saturating_add(RocksDbWeight::get().writes(6)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking Payee (r:0 w:1) fn set_payee() -> Weight { - // Minimum execution time: 18_831 nanoseconds. - Weight::from_ref_time(19_047_000) + // Minimum execution time: 18_134 nanoseconds. + Weight::from_ref_time(18_497_000) .saturating_add(RocksDbWeight::get().reads(1)) .saturating_add(RocksDbWeight::get().writes(1)) } // Storage: Staking Bonded (r:1 w:1) // Storage: Staking Ledger (r:2 w:2) fn set_controller() -> Weight { - // Minimum execution time: 27_534 nanoseconds. - Weight::from_ref_time(27_806_000) + // Minimum execution time: 26_728 nanoseconds. + Weight::from_ref_time(27_154_000) .saturating_add(RocksDbWeight::get().reads(3)) .saturating_add(RocksDbWeight::get().writes(3)) } // Storage: Staking ValidatorCount (r:0 w:1) fn set_validator_count() -> Weight { - // Minimum execution time: 5_211 nanoseconds. - Weight::from_ref_time(5_372_000) + // Minimum execution time: 4_877 nanoseconds. + Weight::from_ref_time(5_028_000) .saturating_add(RocksDbWeight::get().writes(1)) } // Storage: Staking ForceEra (r:0 w:1) fn force_no_eras() -> Weight { - // Minimum execution time: 5_382 nanoseconds. - Weight::from_ref_time(5_654_000) + // Minimum execution time: 5_000 nanoseconds. + Weight::from_ref_time(5_290_000) .saturating_add(RocksDbWeight::get().writes(1)) } // Storage: Staking ForceEra (r:0 w:1) fn force_new_era() -> Weight { - // Minimum execution time: 5_618 nanoseconds. - Weight::from_ref_time(5_714_000) + // Minimum execution time: 5_093 nanoseconds. + Weight::from_ref_time(5_378_000) .saturating_add(RocksDbWeight::get().writes(1)) } // Storage: Staking ForceEra (r:0 w:1) fn force_new_era_always() -> Weight { - // Minimum execution time: 5_589 nanoseconds. - Weight::from_ref_time(5_776_000) + // Minimum execution time: 5_144 nanoseconds. + Weight::from_ref_time(5_454_000) .saturating_add(RocksDbWeight::get().writes(1)) } // Storage: Staking Invulnerables (r:0 w:1) /// The range of component `v` is `[0, 1000]`. fn set_invulnerables(v: u32, ) -> Weight { - // Minimum execution time: 5_541 nanoseconds. - Weight::from_ref_time(6_479_253) - // Standard Error: 49 - .saturating_add(Weight::from_ref_time(10_125).saturating_mul(v.into())) + // Minimum execution time: 5_190 nanoseconds. + Weight::from_ref_time(5_960_962) + // Standard Error: 41 + .saturating_add(Weight::from_ref_time(10_329).saturating_mul(v.into())) .saturating_add(RocksDbWeight::get().writes(1)) } // Storage: Staking Bonded (r:1 w:1) @@ -685,10 +693,10 @@ impl WeightInfo for () { // Storage: Staking SpanSlash (r:0 w:2) /// The range of component `s` is `[0, 100]`. fn force_unstake(s: u32, ) -> Weight { - // Minimum execution time: 81_041 nanoseconds. - Weight::from_ref_time(88_526_481) - // Standard Error: 11_494 - .saturating_add(Weight::from_ref_time(1_095_933).saturating_mul(s.into())) + // Minimum execution time: 80_516 nanoseconds. + Weight::from_ref_time(86_317_884) + // Standard Error: 2_212 + .saturating_add(Weight::from_ref_time(1_103_962).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(11)) .saturating_add(RocksDbWeight::get().writes(12)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -696,10 +704,10 @@ impl WeightInfo for () { // Storage: Staking UnappliedSlashes (r:1 w:1) /// The range of component `s` is `[1, 1000]`. fn cancel_deferred_slash(s: u32, ) -> Weight { - // Minimum execution time: 92_308 nanoseconds. - Weight::from_ref_time(900_351_007) - // Standard Error: 59_145 - .saturating_add(Weight::from_ref_time(4_944_988).saturating_mul(s.into())) + // Minimum execution time: 91_795 nanoseconds. + Weight::from_ref_time(904_524_900) + // Standard Error: 59_193 + .saturating_add(Weight::from_ref_time(4_944_680).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(1)) .saturating_add(RocksDbWeight::get().writes(1)) } @@ -714,10 +722,10 @@ impl WeightInfo for () { // Storage: System Account (r:1 w:1) /// The range of component `n` is `[0, 256]`. fn payout_stakers_dead_controller(n: u32, ) -> Weight { - // Minimum execution time: 131_855 nanoseconds. - Weight::from_ref_time(197_412_779) - // Standard Error: 21_283 - .saturating_add(Weight::from_ref_time(22_093_758).saturating_mul(n.into())) + // Minimum execution time: 127_774 nanoseconds. + Weight::from_ref_time(178_857_156) + // Standard Error: 15_229 + .saturating_add(Weight::from_ref_time(22_112_174).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(9)) .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(2)) @@ -735,10 +743,10 @@ impl WeightInfo for () { // Storage: Balances Locks (r:1 w:1) /// The range of component `n` is `[0, 256]`. fn payout_stakers_alive_staked(n: u32, ) -> Weight { - // Minimum execution time: 163_118 nanoseconds. - Weight::from_ref_time(229_356_697) - // Standard Error: 30_740 - .saturating_add(Weight::from_ref_time(31_575_360).saturating_mul(n.into())) + // Minimum execution time: 161_910 nanoseconds. + Weight::from_ref_time(217_635_072) + // Standard Error: 30_726 + .saturating_add(Weight::from_ref_time(31_244_329).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(10)) .saturating_add(RocksDbWeight::get().reads((5_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(3)) @@ -752,10 +760,10 @@ impl WeightInfo for () { // Storage: VoterList ListBags (r:2 w:2) /// The range of component `l` is `[1, 32]`. fn rebond(l: u32, ) -> Weight { - // Minimum execution time: 94_048 nanoseconds. - Weight::from_ref_time(95_784_236) - // Standard Error: 2_313 - .saturating_add(Weight::from_ref_time(52_798).saturating_mul(l.into())) + // Minimum execution time: 92_986 nanoseconds. + Weight::from_ref_time(94_880_481) + // Standard Error: 2_007 + .saturating_add(Weight::from_ref_time(31_421).saturating_mul(l.into())) .saturating_add(RocksDbWeight::get().reads(9)) .saturating_add(RocksDbWeight::get().writes(8)) } @@ -774,10 +782,10 @@ impl WeightInfo for () { // Storage: Staking SpanSlash (r:0 w:1) /// The range of component `s` is `[1, 100]`. fn reap_stash(s: u32, ) -> Weight { - // Minimum execution time: 93_342 nanoseconds. - Weight::from_ref_time(95_756_184) - // Standard Error: 2_067 - .saturating_add(Weight::from_ref_time(1_090_785).saturating_mul(s.into())) + // Minimum execution time: 92_750 nanoseconds. + Weight::from_ref_time(95_115_568) + // Standard Error: 2_037 + .saturating_add(Weight::from_ref_time(1_086_488).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(12)) .saturating_add(RocksDbWeight::get().writes(12)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -801,12 +809,12 @@ impl WeightInfo for () { /// The range of component `v` is `[1, 10]`. /// The range of component `n` is `[0, 100]`. fn new_era(v: u32, n: u32, ) -> Weight { - // Minimum execution time: 506_874 nanoseconds. - Weight::from_ref_time(507_798_000) - // Standard Error: 1_802_261 - .saturating_add(Weight::from_ref_time(59_874_736).saturating_mul(v.into())) - // Standard Error: 179_585 - .saturating_add(Weight::from_ref_time(13_668_574).saturating_mul(n.into())) + // Minimum execution time: 506_543 nanoseconds. + Weight::from_ref_time(507_261_000) + // Standard Error: 1_766_631 + .saturating_add(Weight::from_ref_time(59_139_153).saturating_mul(v.into())) + // Standard Error: 176_035 + .saturating_add(Weight::from_ref_time(13_512_781).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(206)) .saturating_add(RocksDbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(RocksDbWeight::get().reads((4_u64).saturating_mul(n.into()))) @@ -823,12 +831,12 @@ impl WeightInfo for () { /// The range of component `v` is `[500, 1000]`. /// The range of component `n` is `[500, 1000]`. fn get_npos_voters(v: u32, n: u32, ) -> Weight { - // Minimum execution time: 24_634_585 nanoseconds. - Weight::from_ref_time(24_718_377_000) - // Standard Error: 324_839 - .saturating_add(Weight::from_ref_time(3_654_508).saturating_mul(v.into())) - // Standard Error: 324_839 - .saturating_add(Weight::from_ref_time(2_927_535).saturating_mul(n.into())) + // Minimum execution time: 24_155_382 nanoseconds. + Weight::from_ref_time(24_252_568_000) + // Standard Error: 319_250 + .saturating_add(Weight::from_ref_time(3_596_056).saturating_mul(v.into())) + // Standard Error: 319_250 + .saturating_add(Weight::from_ref_time(2_852_023).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(201)) .saturating_add(RocksDbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(RocksDbWeight::get().reads((4_u64).saturating_mul(n.into()))) @@ -837,10 +845,10 @@ impl WeightInfo for () { // Storage: Staking Validators (r:501 w:0) /// The range of component `v` is `[500, 1000]`. fn get_npos_targets(v: u32, ) -> Weight { - // Minimum execution time: 4_805_490 nanoseconds. - Weight::from_ref_time(118_475_494) - // Standard Error: 26_332 - .saturating_add(Weight::from_ref_time(9_635_188).saturating_mul(v.into())) + // Minimum execution time: 4_741_111 nanoseconds. + Weight::from_ref_time(113_360_179) + // Standard Error: 25_375 + .saturating_add(Weight::from_ref_time(9_494_142).saturating_mul(v.into())) .saturating_add(RocksDbWeight::get().reads(2)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(v.into()))) } @@ -851,8 +859,8 @@ impl WeightInfo for () { // Storage: Staking MaxNominatorsCount (r:0 w:1) // Storage: Staking MinNominatorBond (r:0 w:1) fn set_staking_configs_all_set() -> Weight { - // Minimum execution time: 10_816 nanoseconds. - Weight::from_ref_time(11_242_000) + // Minimum execution time: 11_074 nanoseconds. + Weight::from_ref_time(11_312_000) .saturating_add(RocksDbWeight::get().writes(6)) } // Storage: Staking MinCommission (r:0 w:1) @@ -862,8 +870,8 @@ impl WeightInfo for () { // Storage: Staking MaxNominatorsCount (r:0 w:1) // Storage: Staking MinNominatorBond (r:0 w:1) fn set_staking_configs_all_remove() -> Weight { - // Minimum execution time: 9_581 nanoseconds. - Weight::from_ref_time(10_383_000) + // Minimum execution time: 9_795 nanoseconds. + Weight::from_ref_time(10_116_000) .saturating_add(RocksDbWeight::get().writes(6)) } // Storage: Staking Ledger (r:1 w:0) @@ -877,16 +885,16 @@ impl WeightInfo for () { // Storage: VoterList ListBags (r:1 w:1) // Storage: VoterList CounterForListNodes (r:1 w:1) fn chill_other() -> Weight { - // Minimum execution time: 83_669 nanoseconds. - Weight::from_ref_time(84_772_000) + // Minimum execution time: 82_914 nanoseconds. + Weight::from_ref_time(83_848_000) .saturating_add(RocksDbWeight::get().reads(11)) .saturating_add(RocksDbWeight::get().writes(6)) } // Storage: Staking MinCommission (r:1 w:0) // Storage: Staking Validators (r:1 w:1) fn force_apply_min_commission() -> Weight { - // Minimum execution time: 20_553 nanoseconds. - Weight::from_ref_time(20_933_000) + // Minimum execution time: 20_317 nanoseconds. + Weight::from_ref_time(20_639_000) .saturating_add(RocksDbWeight::get().reads(2)) .saturating_add(RocksDbWeight::get().writes(1)) } From b9656913207638f5a08b97fbbfdfce5ad96beff3 Mon Sep 17 00:00:00 2001 From: gpestana Date: Thu, 15 Dec 2022 00:37:59 +0100 Subject: [PATCH 20/20] fix publish --- frame/staking/Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/frame/staking/Cargo.toml b/frame/staking/Cargo.toml index a7fca045cc4ba..f6b3b95d0beb9 100644 --- a/frame/staking/Cargo.toml +++ b/frame/staking/Cargo.toml @@ -62,7 +62,6 @@ std = [ "sp-runtime/std", "sp-staking/std", "pallet-session/std", - "pallet-bags-list/std", "frame-system/std", "pallet-authorship/std", "sp-application-crypto/std",