From 03d821c49847dfcb2b80d23bcaee0f3085d5e5c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Thu, 14 Mar 2024 17:42:27 +0100 Subject: [PATCH 01/31] init --- substrate/frame/staking/src/pallet/mod.rs | 29 +++++++++++++++++++++++ substrate/frame/staking/src/tests.rs | 25 +++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 1bf8bd8b09cb..7a3f80d2ef5d 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -1980,6 +1980,35 @@ pub mod pallet { Ok(Some(T::WeightInfo::deprecate_controller_batch(controllers.len() as u32)).into()) } + + #[pallet::call_index(29)] + #[pallet::weight(0)] + pub fn clean_bad_state_bond( + origin: OriginFor, + stash: T::AccountId, + ) -> DispatchResultWithPostInfo { + T::AdminOrigin::ensure_origin(origin)?; + + let controller = Bonded::::get(&stash).ok_or(Error::::NotStash)?; + let ledger = Ledger::::get(&controller).ok_or(Error::::NotController)?; + + // ensure that this bond is in a bad state to proceed. + ensure!(ledger.stash != stash, Error::::AlreadyPaired); + + // 1. remove staking lock on the stash. + T::Currency::remove_lock(crate::STAKING_ID, &stash); + // 2. remove the bonded and payee entries of the stash to clean up. + Bonded::::remove(&stash); + Payee::::remove(&stash); + // 3. remove the validator/nominator entry for the stash. + Validators::::remove(&stash); + Nominators::::remove(&stash); + // 4. ensure the `VoterList` is cleared up. + let _ = T::VoterList::on_remove(&stash); + + Ok(Pays::No.into()) + } + } } diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 3725c9e3c2c5..434ce02d6275 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -7321,3 +7321,28 @@ mod ledger { }) } } + +mod bad_state_recovery { + use super::*; + + #[test] + fn clean_bad_state_bond_extrinsic_works() { + ExtBuilder::default().has_stakers(false).build_and_execute(|| { + // setup the bad state: + // Bonded(1, 1) + // Bonded(2, 1) + // Ledger(1) = StakingLedger { stash = 1 } + // Ledger(2) = StakingLedger { stash = 1 } + assert_ok!(Staking::bond(RuntimeOrigin::signed(1), 100, RewardDestination::Staked)); + assert_ok!(Staking::bond(RuntimeOrigin::signed(2), 100, RewardDestination::Staked)); + // TODO: nominate. + Ledger::::insert(&2, Ledger::::get(&1).unwrap()); + + // double-check bad state. + assert_eq!( + StakingLedger::::get(StakingAccount::Stash(1)).unwrap(), + Ledger::::get(&1).unwrap() + ); + }) + } +} From 68df5d29846b77b01f6533a21a475dbc63b619e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Thu, 14 Mar 2024 23:41:54 +0100 Subject: [PATCH 02/31] adds clean bad state bond --- substrate/frame/staking/src/pallet/mod.rs | 11 ++++++---- substrate/frame/staking/src/tests.rs | 26 +++++++++++++++++------ 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 7a3f80d2ef5d..aa25b7e10914 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -1990,10 +1990,14 @@ pub mod pallet { T::AdminOrigin::ensure_origin(origin)?; let controller = Bonded::::get(&stash).ok_or(Error::::NotStash)?; - let ledger = Ledger::::get(&controller).ok_or(Error::::NotController)?; - // ensure that this bond is in a bad state to proceed. - ensure!(ledger.stash != stash, Error::::AlreadyPaired); + // ensure that this bond is in a bad state to proceed. i.e. one of two states: either + // the ledger for the controller does not exist or it exists but the stash is different + // than expected. + ensure!( + Ledger::::get(&controller).map(|l| l.stash != stash).unwrap_or(true), + Error::::AlreadyPaired + ); // 1. remove staking lock on the stash. T::Currency::remove_lock(crate::STAKING_ID, &stash); @@ -2008,7 +2012,6 @@ pub mod pallet { Ok(Pays::No.into()) } - } } diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 434ce02d6275..98cb42302fd1 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -7327,22 +7327,36 @@ mod bad_state_recovery { #[test] fn clean_bad_state_bond_extrinsic_works() { - ExtBuilder::default().has_stakers(false).build_and_execute(|| { + ExtBuilder::default().has_stakers(true).build_and_execute(|| { // setup the bad state: // Bonded(1, 1) // Bonded(2, 1) // Ledger(1) = StakingLedger { stash = 1 } // Ledger(2) = StakingLedger { stash = 1 } assert_ok!(Staking::bond(RuntimeOrigin::signed(1), 100, RewardDestination::Staked)); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(1), vec![11])); assert_ok!(Staking::bond(RuntimeOrigin::signed(2), 100, RewardDestination::Staked)); - // TODO: nominate. + assert_ok!(Staking::nominate(RuntimeOrigin::signed(2), vec![11])); + Ledger::::insert(&2, Ledger::::get(&1).unwrap()); + Ledger::::remove(&2); // double-check bad state. - assert_eq!( - StakingLedger::::get(StakingAccount::Stash(1)).unwrap(), - Ledger::::get(&1).unwrap() - ); + assert!(StakingLedger::::get(StakingAccount::Stash(2)).is_err()); + assert_eq!(Ledger::::get(&2), None); + assert_eq!(Bonded::::iter().count(), 7); + assert_eq!(Payee::::iter().count(), 7); + assert_eq!(Ledger::::iter().count(), 6); + // in sum, try-state checks won't pass. + assert!(Staking::do_try_state(System::block_number()).is_err()); + + assert_ok!(Staking::clean_bad_state_bond(RuntimeOrigin::root(), 2)); + + // bad ledger was unbonded. + assert_eq!(Bonded::::get(&2), None); + assert_eq!(Ledger::::get(&2), None); + // try-state checks are ok now. + assert_ok!(Staking::do_try_state(System::block_number())); }) } } From fc571129e529c322038adfe290e67b81257bde38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Thu, 14 Mar 2024 23:47:06 +0100 Subject: [PATCH 03/31] adds more checks to the test --- substrate/frame/staking/src/tests.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 98cb42302fd1..0d2373381ef1 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -7350,6 +7350,14 @@ mod bad_state_recovery { // in sum, try-state checks won't pass. assert!(Staking::do_try_state(System::block_number()).is_err()); + // ledger bonded by stash 1 is OK and cannot be cleaned. + assert_noop!( + Staking::clean_bad_state_bond(RuntimeOrigin::root(), 1), + Error::::AlreadyPaired + ); + assert!(Staking::do_try_state(System::block_number()).is_err()); + + // ledger from stash 2 is corrupted and can be cleaned. assert_ok!(Staking::clean_bad_state_bond(RuntimeOrigin::root(), 2)); // bad ledger was unbonded. From 4038ca1ee62129f9a4f9a56de829629dcd26484c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Fri, 15 Mar 2024 00:15:47 +0100 Subject: [PATCH 04/31] do not clean validator ledgers --- substrate/frame/staking/src/pallet/mod.rs | 16 ++++++++++++---- substrate/frame/staking/src/tests.rs | 2 +- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index aa25b7e10914..22acc931f97e 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -37,8 +37,9 @@ use sp_runtime::{ }; use sp_staking::{ - EraIndex, Page, SessionIndex, + EraIndex, Page, SessionIndex, StakerStatus, StakingAccount::{self, Controller, Stash}, + StakingInterface, }; use sp_std::prelude::*; @@ -855,6 +856,8 @@ pub mod pallet { BoundNotMet, /// Used when attempting to use deprecated controller account logic. ControllerDeprecated, + /// Cannot force clean the ledger. + CannotCleanLedger, } #[pallet::hooks] @@ -1996,7 +1999,13 @@ pub mod pallet { // than expected. ensure!( Ledger::::get(&controller).map(|l| l.stash != stash).unwrap_or(true), - Error::::AlreadyPaired + Error::::CannotCleanLedger + ); + + // validator ledgers, even if corrupted, cannot be cleaned through this extrinsic. + ensure!( + Self::status(&stash) != Ok(StakerStatus::Validator), + Error::::CannotCleanLedger ); // 1. remove staking lock on the stash. @@ -2004,8 +2013,7 @@ pub mod pallet { // 2. remove the bonded and payee entries of the stash to clean up. Bonded::::remove(&stash); Payee::::remove(&stash); - // 3. remove the validator/nominator entry for the stash. - Validators::::remove(&stash); + // 3. remove the nominator entry for the stash. Nominators::::remove(&stash); // 4. ensure the `VoterList` is cleared up. let _ = T::VoterList::on_remove(&stash); diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 0d2373381ef1..ef7ee2c96750 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -7353,7 +7353,7 @@ mod bad_state_recovery { // ledger bonded by stash 1 is OK and cannot be cleaned. assert_noop!( Staking::clean_bad_state_bond(RuntimeOrigin::root(), 1), - Error::::AlreadyPaired + Error::::CannotCleanLedger, ); assert!(Staking::do_try_state(System::block_number()).is_err()); From af010de1daa5915ff9cdeefb50c46ff6045adeda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Mon, 18 Mar 2024 10:11:04 +0100 Subject: [PATCH 05/31] Adds non-destructive ledger recover call --- substrate/frame/staking/src/pallet/mod.rs | 32 +++++++++++++++ substrate/frame/staking/src/tests.rs | 50 +++++++++++++++++++++++ 2 files changed, 82 insertions(+) diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 22acc931f97e..82413a544c07 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -2020,6 +2020,38 @@ pub mod pallet { Ok(Pays::No.into()) } + + #[pallet::call_index(30)] + #[pallet::weight(0)] + pub fn fix_bad_state_bond( + origin: OriginFor, + stash: T::AccountId, + total: BalanceOf, + ) -> DispatchResultWithPostInfo { + T::AdminOrigin::ensure_origin(origin)?; + + let controller = Bonded::::get(&stash).ok_or(Error::::NotStash)?; + + // ensure that this bond is in a bad state to proceed. i.e. one of two states: either + // the ledger for the controller does not exist or it exists but the stash is different + // than expected. + ensure!( + Ledger::::get(&controller).map(|l| l.stash != stash).unwrap_or(true), + Error::::CannotCleanLedger + ); + + // 1. recreate new ledger. + let ledger = StakingLedger::::new(stash.clone(), total); + + // 2. restore the bond manually. + >::insert(&stash, &stash); + // 3. restore ledger, which will update the staking lock. + ledger.update()?; + + ensure!(>::get(&stash).is_some(), Error::::BadState); + + Ok(Pays::No.into()) + } } } diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index ef7ee2c96750..e3fb66f38d7d 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -7324,6 +7324,7 @@ mod ledger { mod bad_state_recovery { use super::*; + use sp_staking::StakingInterface; #[test] fn clean_bad_state_bond_extrinsic_works() { @@ -7367,4 +7368,53 @@ mod bad_state_recovery { assert_ok!(Staking::do_try_state(System::block_number())); }) } + + #[test] + fn fix_bad_state_bond_extrinsic_works() { + ExtBuilder::default().has_stakers(true).build_and_execute(|| { + // setup the bad state: + // Bonded(1, 1) + // Bonded(2, 1) + // Ledger(1) = StakingLedger { stash = 1 } + // Ledger(2) = StakingLedger { stash = 1 } + assert_ok!(Staking::bond(RuntimeOrigin::signed(1), 100, RewardDestination::Staked)); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(1), vec![11])); + assert_ok!(Staking::bond(RuntimeOrigin::signed(2), 100, RewardDestination::Staked)); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(2), vec![11])); + assert_eq!(Staking::status(&2), Ok(StakerStatus::Nominator(vec![11]))); + + Ledger::::insert(&2, Ledger::::get(&1).unwrap()); + Ledger::::remove(&2); + + // double-check bad state. + assert!(StakingLedger::::get(StakingAccount::Stash(2)).is_err()); + assert_eq!(Ledger::::get(&2), None); + assert_eq!(Bonded::::iter().count(), 7); + assert_eq!(Payee::::iter().count(), 7); + assert_eq!(Ledger::::iter().count(), 6); + // in sum, try-state checks won't pass. + assert!(Staking::do_try_state(System::block_number()).is_err()); + + // ledger bonded by stash 1 is OK and does not need fixing. + assert_noop!( + Staking::fix_bad_state_bond(RuntimeOrigin::root(), 1, 100), + Error::::CannotCleanLedger, + ); + assert!(Staking::do_try_state(System::block_number()).is_err()); + + // ledger from stash 2 is corrupted and can be fixed. + assert_ok!(Staking::fix_bad_state_bond(RuntimeOrigin::root(), 2, 100)); + + // bad ledger has been fixed. + assert_eq!(Staking::status(&2), Ok(StakerStatus::Nominator(vec![11]))); + assert_eq!(Bonded::::get(&2), Some(2)); + let recovered_ledger = Ledger::::get(&2).unwrap(); + assert_eq!(recovered_ledger.stash, 2); + assert_eq!(recovered_ledger.total, 100); + assert_eq!(recovered_ledger.active, 100); + + // try-state checks are ok now. + assert_ok!(Staking::do_try_state(System::block_number())); + }) + } } From 87ad1e5872581b8cc869167ec1804f5a0c46e4fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Wed, 20 Mar 2024 00:07:07 +0000 Subject: [PATCH 06/31] Rethinks the clean/reset extrinsics --- substrate/frame/staking/src/lib.rs | 6 ++ substrate/frame/staking/src/pallet/mod.rs | 104 +++++++++++++++++----- substrate/frame/staking/src/tests.rs | 27 ++---- 3 files changed, 97 insertions(+), 40 deletions(-) diff --git a/substrate/frame/staking/src/lib.rs b/substrate/frame/staking/src/lib.rs index 5a92b6c855f2..0b06285668fb 100644 --- a/substrate/frame/staking/src/lib.rs +++ b/substrate/frame/staking/src/lib.rs @@ -719,6 +719,12 @@ pub struct Nominations { pub suppressed: bool, } +impl Default for Nominations { + fn default() -> Self { + Self { targets: Default::default(), submitted_in: 0, suppressed: false } + } +} + /// Facade struct to encapsulate `PagedExposureMetadata` and a single page of `ExposurePage`. /// /// This is useful where we need to take into account the validator's own stake and total exposure diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 82413a544c07..2fb8d7188cbf 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -39,7 +39,6 @@ use sp_runtime::{ use sp_staking::{ EraIndex, Page, SessionIndex, StakerStatus, StakingAccount::{self, Controller, Stash}, - StakingInterface, }; use sp_std::prelude::*; @@ -856,8 +855,10 @@ pub mod pallet { BoundNotMet, /// Used when attempting to use deprecated controller account logic. ControllerDeprecated, - /// Cannot force clean the ledger. - CannotCleanLedger, + /// Cannot force clean a ledger. + CannotForceCleanLedger, + /// Cannot reset a ledger. + CannotResetLedger, } #[pallet::hooks] @@ -1984,9 +1985,20 @@ pub mod pallet { Ok(Some(T::WeightInfo::deprecate_controller_batch(controllers.len() as u32)).into()) } + /// Force cleans all the data and metadata related to a stash. + /// + /// The requirements to force clean a stash are the following: + /// * The stash is bonded; + /// * If the stash has an associated ledger, its state must be inconsistent. + /// + /// Upon successful execution, this extrinsic will clear all the data and metadata related + /// to a stash and its ledger. + /// + /// NOTE: The ledger associated with his stash will be completely removed and the stash + /// will be completely unstaked from the system. #[pallet::call_index(29)] #[pallet::weight(0)] - pub fn clean_bad_state_bond( + pub fn force_clean_ledger( origin: OriginFor, stash: T::AccountId, ) -> DispatchResultWithPostInfo { @@ -1999,56 +2011,104 @@ pub mod pallet { // than expected. ensure!( Ledger::::get(&controller).map(|l| l.stash != stash).unwrap_or(true), - Error::::CannotCleanLedger + Error::::CannotForceCleanLedger ); - // validator ledgers, even if corrupted, cannot be cleaned through this extrinsic. - ensure!( - Self::status(&stash) != Ok(StakerStatus::Validator), - Error::::CannotCleanLedger - ); + // TODO: verify what are other side effects (e.g. era points) of force cleaning a + // validator. // 1. remove staking lock on the stash. T::Currency::remove_lock(crate::STAKING_ID, &stash); // 2. remove the bonded and payee entries of the stash to clean up. Bonded::::remove(&stash); Payee::::remove(&stash); - // 3. remove the nominator entry for the stash. + // 3. remove the nominator and validator entries for the stash. Nominators::::remove(&stash); + Validators::::remove(&stash); // 4. ensure the `VoterList` is cleared up. let _ = T::VoterList::on_remove(&stash); Ok(Pays::No.into()) } + /// Reset the state of a ledger which is in an inconsistent state. + /// + /// The requirements to reset a ledger are the following: + /// * The stash is bonded; + /// * If the stash has an associated ledger, its state must be inconsistent; + /// * The reset ledger must become either a nominator or validator. + /// + /// The `maybe_*` input parameters will overwrite the corresponding data and metadata of the + /// ledger associated with the stash. If the input parameters are not set, the ledger will + /// be reset with the current values. + /// + /// Upon successful execution, this extrinsic will *recreate* the ledger based on its past + /// state and/or the `maybe_controller`, `maybe_total` and `maybe_unlocking` and + /// `maybe_payee` input parameters. + /// + /// NOTE: if the stash does not have an associated ledger and the `maybe_nominations` or + /// `maybe_validator_prefs` are not given, the ledger will be reset as a nominator. #[pallet::call_index(30)] #[pallet::weight(0)] - pub fn fix_bad_state_bond( + pub fn reset_ledger( origin: OriginFor, stash: T::AccountId, - total: BalanceOf, + maybe_controller: Option, + maybe_total: Option>, + maybe_unlocking: Option>, T::MaxUnlockingChunks>>, + maybe_payee: Option>, + maybe_nominations: Option>, + maybe_validator_prefs: Option, ) -> DispatchResultWithPostInfo { T::AdminOrigin::ensure_origin(origin)?; let controller = Bonded::::get(&stash).ok_or(Error::::NotStash)?; + // a stash cannot be reset as both validator and nominator. + ensure!( + maybe_nominations.is_none() || maybe_validator_prefs.is_none(), + Error::::CannotResetLedger + ); + // ensure that this bond is in a bad state to proceed. i.e. one of two states: either // the ledger for the controller does not exist or it exists but the stash is different // than expected. + let maybe_ledger = Ledger::::get(&controller); ensure!( - Ledger::::get(&controller).map(|l| l.stash != stash).unwrap_or(true), - Error::::CannotCleanLedger + maybe_ledger.as_ref().map(|l| l.stash != stash).unwrap_or(true), + Error::::CannotResetLedger, ); - // 1. recreate new ledger. - let ledger = StakingLedger::::new(stash.clone(), total); - - // 2. restore the bond manually. - >::insert(&stash, &stash); - // 3. restore ledger, which will update the staking lock. + // get new ledger data. + let new_controller = maybe_controller.unwrap_or(controller); + //TODO: get current lock for stash and staking + //let new_total = maybe_total.unwrap_or(T::Currency::lock(crate::STAKING_ID, &stash)); + let new_total = maybe_total.unwrap_or_default(); + let new_unlocking = maybe_unlocking + .unwrap_or_else(|| maybe_ledger.map(|l| l.unlocking).unwrap_or(Default::default())); + + // reset ledger state. + let mut ledger = StakingLedger::::new(stash.clone(), new_total); + ledger.unlocking = new_unlocking; + ledger.controller = Some(new_controller); ledger.update()?; - ensure!(>::get(&stash).is_some(), Error::::BadState); + // get and reset ledger's metadata. + let new_payee = + maybe_payee.unwrap_or(Payee::::get(&stash).unwrap_or(RewardDestination::Staked)); + Payee::::insert(&stash, new_payee); + + if let Some(validator_prefs) = maybe_validator_prefs { + // reset as validator. + Self::do_remove_nominator(&stash); + Self::do_add_validator(&stash, validator_prefs); + } else { + // reset as nominator. + let nominations = + maybe_nominations.unwrap_or(Nominators::::get(&stash).unwrap_or_default()); + Self::do_remove_validator(&stash); + Self::do_add_nominator(&stash, nominations); + }; Ok(Pays::No.into()) } diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index e3fb66f38d7d..a85f7b4bcc6e 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -7327,7 +7327,7 @@ mod bad_state_recovery { use sp_staking::StakingInterface; #[test] - fn clean_bad_state_bond_extrinsic_works() { + fn force_clean_works() { ExtBuilder::default().has_stakers(true).build_and_execute(|| { // setup the bad state: // Bonded(1, 1) @@ -7353,13 +7353,13 @@ mod bad_state_recovery { // ledger bonded by stash 1 is OK and cannot be cleaned. assert_noop!( - Staking::clean_bad_state_bond(RuntimeOrigin::root(), 1), - Error::::CannotCleanLedger, + Staking::force_clean_ledger(RuntimeOrigin::root(), 1), + Error::::CannotForceCleanLedger, ); assert!(Staking::do_try_state(System::block_number()).is_err()); // ledger from stash 2 is corrupted and can be cleaned. - assert_ok!(Staking::clean_bad_state_bond(RuntimeOrigin::root(), 2)); + assert_ok!(Staking::force_clean_ledger(RuntimeOrigin::root(), 2)); // bad ledger was unbonded. assert_eq!(Bonded::::get(&2), None); @@ -7370,7 +7370,7 @@ mod bad_state_recovery { } #[test] - fn fix_bad_state_bond_extrinsic_works() { + fn reset_ledger() { ExtBuilder::default().has_stakers(true).build_and_execute(|| { // setup the bad state: // Bonded(1, 1) @@ -7397,24 +7397,15 @@ mod bad_state_recovery { // ledger bonded by stash 1 is OK and does not need fixing. assert_noop!( - Staking::fix_bad_state_bond(RuntimeOrigin::root(), 1, 100), - Error::::CannotCleanLedger, + Staking::reset_ledger(RuntimeOrigin::root(), 1, None, None, None, None, None, None), + Error::::CannotResetLedger, ); assert!(Staking::do_try_state(System::block_number()).is_err()); - // ledger from stash 2 is corrupted and can be fixed. - assert_ok!(Staking::fix_bad_state_bond(RuntimeOrigin::root(), 2, 100)); - - // bad ledger has been fixed. - assert_eq!(Staking::status(&2), Ok(StakerStatus::Nominator(vec![11]))); - assert_eq!(Bonded::::get(&2), Some(2)); - let recovered_ledger = Ledger::::get(&2).unwrap(); - assert_eq!(recovered_ledger.stash, 2); - assert_eq!(recovered_ledger.total, 100); - assert_eq!(recovered_ledger.active, 100); + // TODO: cover all cases. // try-state checks are ok now. - assert_ok!(Staking::do_try_state(System::block_number())); + //assert_ok!(Staking::do_try_state(System::block_number())); }) } } From 03cf845e335ec3cb1d3af1edf64fe1ff381be898 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Wed, 20 Mar 2024 15:05:41 +0000 Subject: [PATCH 07/31] Adds InspectLockableCurrency and impls it for Balances pallet --- substrate/frame/balances/src/impl_currency.rs | 12 ++++- .../balances/src/tests/currency_tests.rs | 44 ++++++++++++++++++- substrate/frame/support/src/traits.rs | 4 +- .../support/src/traits/tokens/currency.rs | 2 +- .../src/traits/tokens/currency/lockable.rs | 9 ++++ 5 files changed, 64 insertions(+), 7 deletions(-) diff --git a/substrate/frame/balances/src/impl_currency.rs b/substrate/frame/balances/src/impl_currency.rs index 1ac882ade70d..38b700dc49ef 100644 --- a/substrate/frame/balances/src/impl_currency.rs +++ b/substrate/frame/balances/src/impl_currency.rs @@ -28,8 +28,8 @@ use frame_support::{ tokens::{fungible, BalanceStatus as Status, Fortitude::Polite, Precision::BestEffort}, Currency, DefensiveSaturating, ExistenceRequirement, ExistenceRequirement::AllowDeath, - Get, Imbalance, LockIdentifier, LockableCurrency, NamedReservableCurrency, - ReservableCurrency, SignedImbalance, TryDrop, WithdrawReasons, + Get, Imbalance, InspectLockableCurrency, LockIdentifier, LockableCurrency, + NamedReservableCurrency, ReservableCurrency, SignedImbalance, TryDrop, WithdrawReasons, }, }; use frame_system::pallet_prelude::BlockNumberFor; @@ -918,3 +918,11 @@ where Self::update_locks(who, &locks[..]); } } + +impl, I: 'static> InspectLockableCurrency for Pallet { + type Lock = BalanceLock; + + fn get_lock(id: LockIdentifier, who: &T::AccountId) -> Option { + Self::locks(who).into_iter().filter(|l| l.id == id).collect::>().pop() + } +} diff --git a/substrate/frame/balances/src/tests/currency_tests.rs b/substrate/frame/balances/src/tests/currency_tests.rs index 46a4c4caefc3..d9fdada7a681 100644 --- a/substrate/frame/balances/src/tests/currency_tests.rs +++ b/substrate/frame/balances/src/tests/currency_tests.rs @@ -24,8 +24,8 @@ use frame_support::{ BalanceStatus::{Free, Reserved}, Currency, ExistenceRequirement::{self, AllowDeath, KeepAlive}, - Hooks, LockIdentifier, LockableCurrency, NamedReservableCurrency, ReservableCurrency, - WithdrawReasons, + Hooks, InspectLockableCurrency, LockIdentifier, LockableCurrency, NamedReservableCurrency, + ReservableCurrency, WithdrawReasons, }, StorageNoopGuard, }; @@ -88,6 +88,46 @@ fn basic_locking_should_work() { }); } +#[test] +fn inspect_lock_should_work() { + ExtBuilder::default() + .existential_deposit(1) + .monied(true) + .build_and_execute_with(|| { + Balances::set_lock(ID_1, &1, 10, WithdrawReasons::all()); + Balances::set_lock(ID_2, &1, 10, WithdrawReasons::all()); + Balances::set_lock(ID_1, &2, 20, WithdrawReasons::all()); + + assert_eq!( + >::get_lock(ID_1, &1), + Some(crate::BalanceLock { + id: ID_1, + amount: 10, + reasons: WithdrawReasons::all().into() + }) + ); + assert_eq!( + >::get_lock(ID_2, &1), + Some(crate::BalanceLock { + id: ID_2, + amount: 10, + reasons: WithdrawReasons::all().into() + }) + ); + assert_eq!( + >::get_lock(ID_1, &2), + Some(crate::BalanceLock { + id: ID_1, + amount: 20, + reasons: WithdrawReasons::all().into() + }) + ); + + assert_eq!(>::get_lock(ID_2, &2), None,); + assert_eq!(>::get_lock(ID_1, &3), None,); + }) +} + #[test] fn account_should_be_reaped() { ExtBuilder::default() diff --git a/substrate/frame/support/src/traits.rs b/substrate/frame/support/src/traits.rs index 1997d8fc223e..24e7e1c8a65c 100644 --- a/substrate/frame/support/src/traits.rs +++ b/substrate/frame/support/src/traits.rs @@ -22,8 +22,8 @@ pub mod tokens; pub use tokens::{ currency::{ - ActiveIssuanceOf, Currency, LockIdentifier, LockableCurrency, NamedReservableCurrency, - ReservableCurrency, TotalIssuanceOf, VestingSchedule, + ActiveIssuanceOf, Currency, InspectLockableCurrency, LockIdentifier, LockableCurrency, + NamedReservableCurrency, ReservableCurrency, TotalIssuanceOf, VestingSchedule, }, fungible, fungibles, imbalance::{Imbalance, OnUnbalanced, SignedImbalance}, diff --git a/substrate/frame/support/src/traits/tokens/currency.rs b/substrate/frame/support/src/traits/tokens/currency.rs index 8b773115011d..282e7f644733 100644 --- a/substrate/frame/support/src/traits/tokens/currency.rs +++ b/substrate/frame/support/src/traits/tokens/currency.rs @@ -27,7 +27,7 @@ use sp_runtime::{traits::MaybeSerializeDeserialize, DispatchError}; mod reservable; pub use reservable::{NamedReservableCurrency, ReservableCurrency}; mod lockable; -pub use lockable::{LockIdentifier, LockableCurrency, VestingSchedule}; +pub use lockable::{InspectLockableCurrency, LockIdentifier, LockableCurrency, VestingSchedule}; /// Abstraction over a fungible assets system. pub trait Currency { diff --git a/substrate/frame/support/src/traits/tokens/currency/lockable.rs b/substrate/frame/support/src/traits/tokens/currency/lockable.rs index 955814f5aa9d..188f6c10754b 100644 --- a/substrate/frame/support/src/traits/tokens/currency/lockable.rs +++ b/substrate/frame/support/src/traits/tokens/currency/lockable.rs @@ -64,6 +64,15 @@ pub trait LockableCurrency: Currency { fn remove_lock(id: LockIdentifier, who: &AccountId); } +/// A inspect interface for a currency whose accounts can have liquidity restrictions. +pub trait InspectLockableCurrency: LockableCurrency { + // The lock type. + type Lock; + + /// Retrieves the lock information of a lock ID for a given account `who`, if it exists. + fn get_lock(id: LockIdentifier, who: &AccountId) -> Option; +} + /// A vesting schedule over a currency. This allows a particular currency to have vesting limits /// applied to it. pub trait VestingSchedule { From 9eea773648149bdf6983d871eb441ad6057eded6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Wed, 20 Mar 2024 15:15:39 +0000 Subject: [PATCH 08/31] uses InspectLockableCurrency in staking pallet to fetch lock of a stash --- substrate/frame/staking/Cargo.toml | 2 +- substrate/frame/staking/src/pallet/mod.rs | 24 +++++++++++++++-------- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/substrate/frame/staking/Cargo.toml b/substrate/frame/staking/Cargo.toml index d2a46146931b..eed2a50147f2 100644 --- a/substrate/frame/staking/Cargo.toml +++ b/substrate/frame/staking/Cargo.toml @@ -30,6 +30,7 @@ frame-system = { path = "../system", default-features = false } pallet-session = { path = "../session", default-features = false, features = [ "historical", ] } +pallet-balances = { path = "../balances" } pallet-authorship = { path = "../authorship", default-features = false } sp-application-crypto = { path = "../../primitives/application-crypto", default-features = false, features = ["serde"] } frame-election-provider-support = { path = "../election-provider-support", default-features = false } @@ -43,7 +44,6 @@ rand_chacha = { version = "0.2", default-features = false, optional = true } sp-tracing = { path = "../../primitives/tracing" } sp-core = { path = "../../primitives/core" } sp-npos-elections = { path = "../../primitives/npos-elections" } -pallet-balances = { path = "../balances" } pallet-timestamp = { path = "../timestamp" } pallet-staking-reward-curve = { path = "reward-curve" } pallet-bags-list = { path = "../bags-list" } diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 2fb8d7188cbf..61907cf00e19 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -25,7 +25,7 @@ use frame_support::{ pallet_prelude::*, traits::{ Currency, Defensive, DefensiveSaturating, EnsureOrigin, EstimateNextNewSession, Get, - LockableCurrency, OnUnbalanced, UnixTime, + InspectLockableCurrency, LockableCurrency, OnUnbalanced, UnixTime, }, weights::Weight, BoundedVec, @@ -88,10 +88,13 @@ pub mod pallet { pub trait Config: frame_system::Config { /// The staking balance. type Currency: LockableCurrency< - Self::AccountId, - Moment = BlockNumberFor, - Balance = Self::CurrencyBalance, - >; + Self::AccountId, + Moment = BlockNumberFor, + Balance = Self::CurrencyBalance, + > + InspectLockableCurrency< + Self::AccountId, + Lock = pallet_balances::BalanceLock, + >; /// Just the `Currency::Balance` type; we have this item to allow us to constrain it to /// `From`. type CurrencyBalance: sp_runtime::traits::AtLeast32BitUnsigned @@ -2081,9 +2084,14 @@ pub mod pallet { // get new ledger data. let new_controller = maybe_controller.unwrap_or(controller); - //TODO: get current lock for stash and staking - //let new_total = maybe_total.unwrap_or(T::Currency::lock(crate::STAKING_ID, &stash)); - let new_total = maybe_total.unwrap_or_default(); + let new_total = maybe_total.unwrap_or_else(|| { + >::get_lock( + crate::STAKING_ID, + &stash, + ) + .map(|l| l.amount) + .unwrap_or(Zero::zero()) + }); let new_unlocking = maybe_unlocking .unwrap_or_else(|| maybe_ledger.map(|l| l.unlocking).unwrap_or(Default::default())); From fbbf7f894ad828da3556a55d8fc6af86124778ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Wed, 20 Mar 2024 16:27:38 +0000 Subject: [PATCH 09/31] Adds simple tests for reset ledger --- substrate/frame/staking/src/mock.rs | 89 +++++++------- substrate/frame/staking/src/pallet/mod.rs | 2 +- substrate/frame/staking/src/tests.rs | 137 ++++++++++++++-------- 3 files changed, 135 insertions(+), 93 deletions(-) diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index 65e660f248dd..fb8160ed138b 100644 --- a/substrate/frame/staking/src/mock.rs +++ b/substrate/frame/staking/src/mock.rs @@ -787,54 +787,63 @@ pub(crate) fn bond_controller_stash(controller: AccountId, stash: AccountId) -> } pub(crate) fn setup_double_bonded_ledgers() { - assert_ok!(Staking::bond(RuntimeOrigin::signed(1), 10, RewardDestination::Staked)); - assert_ok!(Staking::bond(RuntimeOrigin::signed(2), 20, RewardDestination::Staked)); - assert_ok!(Staking::bond(RuntimeOrigin::signed(3), 20, RewardDestination::Staked)); + let init_ledgers = Ledger::::iter().count(); + + let _ = Balances::make_free_balance_be(&333, 2000); + let _ = Balances::make_free_balance_be(&444, 2000); + let _ = Balances::make_free_balance_be(&555, 2000); + let _ = Balances::make_free_balance_be(&777, 2000); + + assert_ok!(Staking::bond(RuntimeOrigin::signed(333), 10, RewardDestination::Staked)); + assert_ok!(Staking::bond(RuntimeOrigin::signed(444), 20, RewardDestination::Staked)); + assert_ok!(Staking::bond(RuntimeOrigin::signed(555), 20, RewardDestination::Staked)); // not relevant to the test case, but ensures try-runtime checks pass. - [1, 2, 3] + [333, 444, 555] .iter() .for_each(|s| Payee::::insert(s, RewardDestination::Staked)); // we want to test the case where a controller can also be a stash of another ledger. // for that, we change the controller/stash bonding so that: - // * 2 becomes controller of 1. - // * 3 becomes controller of 2. - // * 4 becomes controller of 3. - let ledger_1 = Ledger::::get(1).unwrap(); - let ledger_2 = Ledger::::get(2).unwrap(); - let ledger_3 = Ledger::::get(3).unwrap(); - - // 4 becomes controller of 3. - Bonded::::mutate(3, |controller| *controller = Some(4)); - Ledger::::insert(4, ledger_3); - - // 3 becomes controller of 2. - Bonded::::mutate(2, |controller| *controller = Some(3)); - Ledger::::insert(3, ledger_2); - - // 2 becomes controller of 1 - Bonded::::mutate(1, |controller| *controller = Some(2)); - Ledger::::insert(2, ledger_1); - // 1 is not controller anymore. - Ledger::::remove(1); + // * 444 becomes controller of 333. + // * 555 becomes controller of 444. + // * 777 becomes controller of 555. + let ledger_333 = Ledger::::get(333).unwrap(); + let ledger_444 = Ledger::::get(444).unwrap(); + let ledger_555 = Ledger::::get(555).unwrap(); + + // 777 becomes controller of 555. + Bonded::::mutate(555, |controller| *controller = Some(777)); + Ledger::::insert(777, ledger_555); + + // 555 becomes controller of 444. + Bonded::::mutate(444, |controller| *controller = Some(555)); + Ledger::::insert(555, ledger_444); + + // 444 becomes controller of 333. + Bonded::::mutate(333, |controller| *controller = Some(444)); + Ledger::::insert(444, ledger_333); + + // 333 is not controller anymore. + Ledger::::remove(333); // checks. now we have: - // * 3 ledgers - assert_eq!(Ledger::::iter().count(), 3); - // * stash 1 has controller 2. - assert_eq!(Bonded::::get(1), Some(2)); - assert_eq!(StakingLedger::::paired_account(StakingAccount::Stash(1)), Some(2)); - assert_eq!(Ledger::::get(2).unwrap().stash, 1); - - // * stash 2 has controller 3. - assert_eq!(Bonded::::get(2), Some(3)); - assert_eq!(StakingLedger::::paired_account(StakingAccount::Stash(2)), Some(3)); - assert_eq!(Ledger::::get(3).unwrap().stash, 2); - - // * stash 3 has controller 4. - assert_eq!(Bonded::::get(3), Some(4)); - assert_eq!(StakingLedger::::paired_account(StakingAccount::Stash(3)), Some(4)); - assert_eq!(Ledger::::get(4).unwrap().stash, 3); + // * +3 ledgers + assert_eq!(Ledger::::iter().count(), 3 + init_ledgers); + + // * stash 333 has controller 444. + assert_eq!(Bonded::::get(333), Some(444)); + assert_eq!(StakingLedger::::paired_account(StakingAccount::Stash(333)), Some(444)); + assert_eq!(Ledger::::get(444).unwrap().stash, 333); + + // * stash 444 has controller 555. + assert_eq!(Bonded::::get(444), Some(555)); + assert_eq!(StakingLedger::::paired_account(StakingAccount::Stash(444)), Some(555)); + assert_eq!(Ledger::::get(555).unwrap().stash, 444); + + // * stash 555 has controller 777. + assert_eq!(Bonded::::get(555), Some(777)); + assert_eq!(StakingLedger::::paired_account(StakingAccount::Stash(555)), Some(777)); + assert_eq!(Ledger::::get(777).unwrap().stash, 555); } #[macro_export] diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 61907cf00e19..15da2f02a903 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -37,7 +37,7 @@ use sp_runtime::{ }; use sp_staking::{ - EraIndex, Page, SessionIndex, StakerStatus, + EraIndex, Page, SessionIndex, StakingAccount::{self, Controller, Stash}, }; use sp_std::prelude::*; diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index a85f7b4bcc6e..9cee3e80ec47 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -6933,40 +6933,43 @@ mod ledger { setup_double_bonded_ledgers(); // Case 1: double bonded but not corrupted: - // stash 2 has controller 3: - assert_eq!(Bonded::::get(2), Some(3)); - assert_eq!(Ledger::::get(3).unwrap().stash, 2); + // stash 444 has controller 555: + assert_eq!(Bonded::::get(444), Some(555)); + assert_eq!(Ledger::::get(555).unwrap().stash, 444); - // stash 2 is also a controller of 1: - assert_eq!(Bonded::::get(1), Some(2)); - assert_eq!(StakingLedger::::paired_account(StakingAccount::Stash(1)), Some(2)); - assert_eq!(Ledger::::get(2).unwrap().stash, 1); + // stash 444 is also a controller of 333: + assert_eq!(Bonded::::get(333), Some(444)); + assert_eq!( + StakingLedger::::paired_account(StakingAccount::Stash(333)), + Some(444) + ); + assert_eq!(Ledger::::get(444).unwrap().stash, 333); - // although 2 is double bonded (it is a controller and a stash of different ledgers), + // although 444 is double bonded (it is a controller and a stash of different ledgers), // we can safely retrieve the ledger and mutate it since the correct ledger is // returned. - let ledger_result = StakingLedger::::get(StakingAccount::Stash(2)); - assert_eq!(ledger_result.unwrap().stash, 2); // correct ledger. + let ledger_result = StakingLedger::::get(StakingAccount::Stash(444)); + assert_eq!(ledger_result.unwrap().stash, 444); // correct ledger. - let ledger_result = StakingLedger::::get(StakingAccount::Controller(2)); - assert_eq!(ledger_result.unwrap().stash, 1); // correct ledger. + let ledger_result = StakingLedger::::get(StakingAccount::Controller(444)); + assert_eq!(ledger_result.unwrap().stash, 333); // correct ledger. - // fetching ledger 1 by its stash works. - let ledger_result = StakingLedger::::get(StakingAccount::Stash(1)); - assert_eq!(ledger_result.unwrap().stash, 1); + // fetching ledger 333 by its stash works. + let ledger_result = StakingLedger::::get(StakingAccount::Stash(333)); + assert_eq!(ledger_result.unwrap().stash, 333); // Case 2: corrupted ledger bonding. // in this case, we simulate what happens when fetching a ledger by stash returns a // ledger with a different stash. when this happens, we return an error instead of the // ledger to prevent ledger mutations. - let mut ledger = Ledger::::get(2).unwrap(); - assert_eq!(ledger.stash, 1); - ledger.stash = 2; - Ledger::::insert(2, ledger); + let mut ledger = Ledger::::get(444).unwrap(); + assert_eq!(ledger.stash, 333); + ledger.stash = 444; + Ledger::::insert(444, ledger); // now, we are prevented from fetching the ledger by stash from 1. It's associated // controller (2) is now bonding a ledger with a different stash (2, not 1). - assert!(StakingLedger::::get(StakingAccount::Stash(1)).is_err()); + assert!(StakingLedger::::get(StakingAccount::Stash(333)).is_err()); }) } @@ -7253,7 +7256,7 @@ mod ledger { let bounded_controllers: BoundedVec< _, ::MaxControllersInDeprecationBatch, - > = BoundedVec::try_from(vec![1, 2, 3, 4]).unwrap(); + > = BoundedVec::try_from(vec![333, 444, 555, 777]).unwrap(); assert_ok!(Staking::deprecate_controller_batch( RuntimeOrigin::root(), @@ -7276,7 +7279,7 @@ mod ledger { let bounded_controllers: BoundedVec< _, ::MaxControllersInDeprecationBatch, - > = BoundedVec::try_from(vec![4, 3, 2, 1]).unwrap(); + > = BoundedVec::try_from(vec![777, 555, 444, 333]).unwrap(); assert_ok!(Staking::deprecate_controller_batch( RuntimeOrigin::root(), @@ -7296,9 +7299,9 @@ mod ledger { setup_double_bonded_ledgers(); // in this case, setting controller works due to the ordering of the calls. - assert_ok!(Staking::set_controller(RuntimeOrigin::signed(1))); - assert_ok!(Staking::set_controller(RuntimeOrigin::signed(2))); - assert_ok!(Staking::set_controller(RuntimeOrigin::signed(3))); + assert_ok!(Staking::set_controller(RuntimeOrigin::signed(333))); + assert_ok!(Staking::set_controller(RuntimeOrigin::signed(444))); + assert_ok!(Staking::set_controller(RuntimeOrigin::signed(555))); }) } @@ -7307,24 +7310,24 @@ mod ledger { ExtBuilder::default().has_stakers(false).try_state(false).build_and_execute(|| { setup_double_bonded_ledgers(); - // setting the controller of ledger associated with stash 3 fails since its stash is a + // setting the controller of ledger associated with stash 555 fails since its stash is a // controller of another ledger. assert_noop!( - Staking::set_controller(RuntimeOrigin::signed(3)), + Staking::set_controller(RuntimeOrigin::signed(555)), Error::::BadState ); assert_noop!( - Staking::set_controller(RuntimeOrigin::signed(2)), + Staking::set_controller(RuntimeOrigin::signed(444)), Error::::BadState ); - assert_ok!(Staking::set_controller(RuntimeOrigin::signed(1))); + assert_ok!(Staking::set_controller(RuntimeOrigin::signed(333))); }) } } mod bad_state_recovery { use super::*; - use sp_staking::StakingInterface; + use frame_support::traits::InspectLockableCurrency; #[test] fn force_clean_works() { @@ -7370,42 +7373,72 @@ mod bad_state_recovery { } #[test] - fn reset_ledger() { + fn reset_ledge_default_works() { ExtBuilder::default().has_stakers(true).build_and_execute(|| { - // setup the bad state: - // Bonded(1, 1) - // Bonded(2, 1) - // Ledger(1) = StakingLedger { stash = 1 } - // Ledger(2) = StakingLedger { stash = 1 } - assert_ok!(Staking::bond(RuntimeOrigin::signed(1), 100, RewardDestination::Staked)); - assert_ok!(Staking::nominate(RuntimeOrigin::signed(1), vec![11])); - assert_ok!(Staking::bond(RuntimeOrigin::signed(2), 100, RewardDestination::Staked)); - assert_ok!(Staking::nominate(RuntimeOrigin::signed(2), vec![11])); - assert_eq!(Staking::status(&2), Ok(StakerStatus::Nominator(vec![11]))); + setup_double_bonded_ledgers(); - Ledger::::insert(&2, Ledger::::get(&1).unwrap()); - Ledger::::remove(&2); + let ledger_before_corruption = + StakingLedger::::get(StakingAccount::Stash(444)).unwrap(); + let lock_before_corruption = Balances::get_lock(crate::STAKING_ID, &444).unwrap(); + + // remove ledger 444 (controlled by 555) to simulate a corruption with deletion. + assert_eq!(Bonded::::get(&444), Some(555)); + Ledger::::remove(&555); // double-check bad state. - assert!(StakingLedger::::get(StakingAccount::Stash(2)).is_err()); - assert_eq!(Ledger::::get(&2), None); - assert_eq!(Bonded::::iter().count(), 7); - assert_eq!(Payee::::iter().count(), 7); - assert_eq!(Ledger::::iter().count(), 6); + assert!(StakingLedger::::get(StakingAccount::Stash(444)).is_err()); + assert_eq!(Bonded::::iter().count(), 8); + assert_eq!(Payee::::iter().count(), 8); + assert_eq!(Ledger::::iter().count(), 7); // in sum, try-state checks won't pass. assert!(Staking::do_try_state(System::block_number()).is_err()); - // ledger bonded by stash 1 is OK and does not need fixing. + // ledger bonded by stash 333 is OK and does not need fixing. assert_noop!( - Staking::reset_ledger(RuntimeOrigin::root(), 1, None, None, None, None, None, None), + Staking::reset_ledger( + RuntimeOrigin::root(), + 333, + None, + None, + None, + None, + None, + None + ), Error::::CannotResetLedger, ); assert!(Staking::do_try_state(System::block_number()).is_err()); - // TODO: cover all cases. + // 444 is in a bad state and we can reset it. let's reset it to the default, on-chain + // state. + assert_ok!(Staking::reset_ledger( + RuntimeOrigin::root(), + 444, + None, + None, + None, + None, + None, + None + )); + + // now the ledger can be feteched though the stash and the correct controller. + let ledger_reset = StakingLedger::::get(StakingAccount::Stash(444)).unwrap(); + assert_eq!( + ledger_reset.clone(), + StakingLedger::::get(StakingAccount::Controller(555)).unwrap() + ); + // reset lock is the same before corruption. + assert_eq!( + lock_before_corruption, + Balances::get_lock(crate::STAKING_ID, &444).unwrap() + ); + + // ledger is the same before corruption. + assert_eq!(ledger_reset, ledger_before_corruption); // try-state checks are ok now. - //assert_ok!(Staking::do_try_state(System::block_number())); + assert_ok!(Staking::do_try_state(System::block_number())); }) } } From 64cbee15cb8512d0b26e446fc3070dcbca1c97a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Thu, 21 Mar 2024 08:02:28 +0000 Subject: [PATCH 10/31] removes call::force_clean and replaces it with fast_unstake --- substrate/frame/staking/src/pallet/impls.rs | 2 +- substrate/frame/staking/src/pallet/mod.rs | 78 ++++++++------------- substrate/frame/staking/src/tests.rs | 20 +++--- 3 files changed, 40 insertions(+), 60 deletions(-) diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index d42456e53b13..673a9eef0892 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -1761,7 +1761,7 @@ impl StakingInterface for Pallet { fn force_unstake(who: Self::AccountId) -> sp_runtime::DispatchResult { let num_slashing_spans = Self::slashing_spans(&who).map_or(0, |s| s.iter().count() as u32); - Self::force_unstake(RawOrigin::Root.into(), who.clone(), num_slashing_spans) + Self::force_unstake(RawOrigin::Root.into(), who.clone(), num_slashing_spans, false) } fn is_exposed_in_era(who: &Self::AccountId, era: &EraIndex) -> bool { diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 15da2f02a903..4e37691ccd54 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -1490,6 +1490,10 @@ pub mod pallet { /// Force a current staker to become completely unstaked, immediately. /// + /// If `force_clean` flag is set, resort to manually clean all the storage items associated + /// with the stash *even* if calling kill ledger fails. Before proceeding witht the force + /// clean, we must ensure that the ledger associated with `stash` is in a corrupted state. + /// /// The dispatch origin must be Root. /// /// ## Parameters @@ -1502,11 +1506,35 @@ pub mod pallet { origin: OriginFor, stash: T::AccountId, num_slashing_spans: u32, + force_clean: bool, ) -> DispatchResult { ensure_root(origin)?; // Remove all staking-related information and lock. - Self::kill_stash(&stash, num_slashing_spans)?; + let killed = Self::kill_stash(&stash, num_slashing_spans); + + if killed.is_err() && !force_clean { + return killed; + } + + // From here on, we will force unstake the stash by manually cleaning up all the + // storage items associated with the stash's ledger. + + // Double check that stash is corrupted before proceeding. + let controller = Bonded::::get(&stash).ok_or(Error::::NotStash)?; + let maybe_ledger = Ledger::::get(&controller); + ensure!( + maybe_ledger.as_ref().map(|l| l.stash != stash).unwrap_or(true), + Error::::CannotResetLedger, + ); + + // TODO: clean based on num_slashing_spans (check the ledger.kill) + T::Currency::remove_lock(crate::STAKING_ID, &stash); + Bonded::::remove(&stash); + Payee::::remove(&stash); + Nominators::::remove(&stash); + Validators::::remove(&stash); + let _ = T::VoterList::on_remove(&stash); Ok(()) } @@ -1988,52 +2016,6 @@ pub mod pallet { Ok(Some(T::WeightInfo::deprecate_controller_batch(controllers.len() as u32)).into()) } - /// Force cleans all the data and metadata related to a stash. - /// - /// The requirements to force clean a stash are the following: - /// * The stash is bonded; - /// * If the stash has an associated ledger, its state must be inconsistent. - /// - /// Upon successful execution, this extrinsic will clear all the data and metadata related - /// to a stash and its ledger. - /// - /// NOTE: The ledger associated with his stash will be completely removed and the stash - /// will be completely unstaked from the system. - #[pallet::call_index(29)] - #[pallet::weight(0)] - pub fn force_clean_ledger( - origin: OriginFor, - stash: T::AccountId, - ) -> DispatchResultWithPostInfo { - T::AdminOrigin::ensure_origin(origin)?; - - let controller = Bonded::::get(&stash).ok_or(Error::::NotStash)?; - - // ensure that this bond is in a bad state to proceed. i.e. one of two states: either - // the ledger for the controller does not exist or it exists but the stash is different - // than expected. - ensure!( - Ledger::::get(&controller).map(|l| l.stash != stash).unwrap_or(true), - Error::::CannotForceCleanLedger - ); - - // TODO: verify what are other side effects (e.g. era points) of force cleaning a - // validator. - - // 1. remove staking lock on the stash. - T::Currency::remove_lock(crate::STAKING_ID, &stash); - // 2. remove the bonded and payee entries of the stash to clean up. - Bonded::::remove(&stash); - Payee::::remove(&stash); - // 3. remove the nominator and validator entries for the stash. - Nominators::::remove(&stash); - Validators::::remove(&stash); - // 4. ensure the `VoterList` is cleared up. - let _ = T::VoterList::on_remove(&stash); - - Ok(Pays::No.into()) - } - /// Reset the state of a ledger which is in an inconsistent state. /// /// The requirements to reset a ledger are the following: @@ -2051,7 +2033,7 @@ pub mod pallet { /// /// NOTE: if the stash does not have an associated ledger and the `maybe_nominations` or /// `maybe_validator_prefs` are not given, the ledger will be reset as a nominator. - #[pallet::call_index(30)] + #[pallet::call_index(29)] #[pallet::weight(0)] pub fn reset_ledger( origin: OriginFor, diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 9cee3e80ec47..96e9038b3602 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -112,14 +112,14 @@ fn force_unstake_works() { TokenError::Frozen, ); // Force unstake requires root. - assert_noop!(Staking::force_unstake(RuntimeOrigin::signed(11), 11, 2), BadOrigin); + assert_noop!(Staking::force_unstake(RuntimeOrigin::signed(11), 11, 2, false), BadOrigin); // Force unstake needs correct number of slashing spans (for weight calculation) assert_noop!( - Staking::force_unstake(RuntimeOrigin::root(), 11, 0), + Staking::force_unstake(RuntimeOrigin::root(), 11, 0, false), Error::::IncorrectSlashingSpans ); // We now force them to unstake - assert_ok!(Staking::force_unstake(RuntimeOrigin::root(), 11, 2)); + assert_ok!(Staking::force_unstake(RuntimeOrigin::root(), 11, 2, false)); // No longer bonded. assert_eq!(Staking::bonded(&11), None); // Transfer works. @@ -7330,7 +7330,7 @@ mod bad_state_recovery { use frame_support::traits::InspectLockableCurrency; #[test] - fn force_clean_works() { + fn fast_unstake_force_clean_works() { ExtBuilder::default().has_stakers(true).build_and_execute(|| { // setup the bad state: // Bonded(1, 1) @@ -7354,15 +7354,13 @@ mod bad_state_recovery { // in sum, try-state checks won't pass. assert!(Staking::do_try_state(System::block_number()).is_err()); - // ledger bonded by stash 1 is OK and cannot be cleaned. + // calling force unstake without `force_clean` will fail since the ledger is corrupted. assert_noop!( - Staking::force_clean_ledger(RuntimeOrigin::root(), 1), - Error::::CannotForceCleanLedger, + Staking::force_unstake(RuntimeOrigin::root(), 2, 0, false), + Error::::NotController ); - assert!(Staking::do_try_state(System::block_number()).is_err()); - - // ledger from stash 2 is corrupted and can be cleaned. - assert_ok!(Staking::force_clean_ledger(RuntimeOrigin::root(), 2)); + // however it works and cleans up all lingering state if `force_clean` flag is set. + assert_ok!(Staking::force_unstake(RuntimeOrigin::root(), 2, 0, true)); // bad ledger was unbonded. assert_eq!(Bonded::::get(&2), None); From a6cb3922c0e1a9230f2f9c02688af3d26ea07bfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Thu, 21 Mar 2024 08:26:54 +0000 Subject: [PATCH 11/31] nits --- substrate/frame/staking/src/pallet/mod.rs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 4e37691ccd54..5daf3d8b3fdd 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -1511,16 +1511,19 @@ pub mod pallet { ensure_root(origin)?; // Remove all staking-related information and lock. - let killed = Self::kill_stash(&stash, num_slashing_spans); - - if killed.is_err() && !force_clean { - return killed; + if let Err(err) = Self::kill_stash(&stash, num_slashing_spans) { + if !force_clean { + return Err(err); + } + // proceed to force clean. + } else { + return Ok(()); } // From here on, we will force unstake the stash by manually cleaning up all the // storage items associated with the stash's ledger. - // Double check that stash is corrupted before proceeding. + // But first, double check that stash is corrupted before proceeding. let controller = Bonded::::get(&stash).ok_or(Error::::NotStash)?; let maybe_ledger = Ledger::::get(&controller); ensure!( @@ -1528,7 +1531,7 @@ pub mod pallet { Error::::CannotResetLedger, ); - // TODO: clean based on num_slashing_spans (check the ledger.kill) + // TODO: clean slashing related data. T::Currency::remove_lock(crate::STAKING_ID, &stash); Bonded::::remove(&stash); Payee::::remove(&stash); From 8f52d0a7a4927741fa1b14f6040a4598ec8ee075 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Thu, 21 Mar 2024 08:33:37 +0000 Subject: [PATCH 12/31] nits2 --- substrate/frame/staking/src/pallet/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 5daf3d8b3fdd..3cd119c9763a 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -1528,7 +1528,7 @@ pub mod pallet { let maybe_ledger = Ledger::::get(&controller); ensure!( maybe_ledger.as_ref().map(|l| l.stash != stash).unwrap_or(true), - Error::::CannotResetLedger, + Error::::CannotForceCleanLedger, ); // TODO: clean slashing related data. From c3ed2c33fd8eaeedfb04e6f01319fd18862039c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Thu, 21 Mar 2024 09:41:30 +0000 Subject: [PATCH 13/31] removes clean ledger --- substrate/frame/staking/src/pallet/impls.rs | 2 +- substrate/frame/staking/src/pallet/mod.rs | 33 +-------------- substrate/frame/staking/src/tests.rs | 47 ++------------------- 3 files changed, 5 insertions(+), 77 deletions(-) diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index 673a9eef0892..d42456e53b13 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -1761,7 +1761,7 @@ impl StakingInterface for Pallet { fn force_unstake(who: Self::AccountId) -> sp_runtime::DispatchResult { let num_slashing_spans = Self::slashing_spans(&who).map_or(0, |s| s.iter().count() as u32); - Self::force_unstake(RawOrigin::Root.into(), who.clone(), num_slashing_spans, false) + Self::force_unstake(RawOrigin::Root.into(), who.clone(), num_slashing_spans) } fn is_exposed_in_era(who: &Self::AccountId, era: &EraIndex) -> bool { diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 3cd119c9763a..4bcbcaf10f2e 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -1490,10 +1490,6 @@ pub mod pallet { /// Force a current staker to become completely unstaked, immediately. /// - /// If `force_clean` flag is set, resort to manually clean all the storage items associated - /// with the stash *even* if calling kill ledger fails. Before proceeding witht the force - /// clean, we must ensure that the ledger associated with `stash` is in a corrupted state. - /// /// The dispatch origin must be Root. /// /// ## Parameters @@ -1506,38 +1502,11 @@ pub mod pallet { origin: OriginFor, stash: T::AccountId, num_slashing_spans: u32, - force_clean: bool, ) -> DispatchResult { ensure_root(origin)?; // Remove all staking-related information and lock. - if let Err(err) = Self::kill_stash(&stash, num_slashing_spans) { - if !force_clean { - return Err(err); - } - // proceed to force clean. - } else { - return Ok(()); - } - - // From here on, we will force unstake the stash by manually cleaning up all the - // storage items associated with the stash's ledger. - - // But first, double check that stash is corrupted before proceeding. - let controller = Bonded::::get(&stash).ok_or(Error::::NotStash)?; - let maybe_ledger = Ledger::::get(&controller); - ensure!( - maybe_ledger.as_ref().map(|l| l.stash != stash).unwrap_or(true), - Error::::CannotForceCleanLedger, - ); - - // TODO: clean slashing related data. - T::Currency::remove_lock(crate::STAKING_ID, &stash); - Bonded::::remove(&stash); - Payee::::remove(&stash); - Nominators::::remove(&stash); - Validators::::remove(&stash); - let _ = T::VoterList::on_remove(&stash); + Self::kill_stash(&stash, num_slashing_spans)?; Ok(()) } diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 96e9038b3602..3d4571fb0835 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -112,14 +112,14 @@ fn force_unstake_works() { TokenError::Frozen, ); // Force unstake requires root. - assert_noop!(Staking::force_unstake(RuntimeOrigin::signed(11), 11, 2, false), BadOrigin); + assert_noop!(Staking::force_unstake(RuntimeOrigin::signed(11), 11, 2), BadOrigin); // Force unstake needs correct number of slashing spans (for weight calculation) assert_noop!( - Staking::force_unstake(RuntimeOrigin::root(), 11, 0, false), + Staking::force_unstake(RuntimeOrigin::root(), 11, 0), Error::::IncorrectSlashingSpans ); // We now force them to unstake - assert_ok!(Staking::force_unstake(RuntimeOrigin::root(), 11, 2, false)); + assert_ok!(Staking::force_unstake(RuntimeOrigin::root(), 11, 2)); // No longer bonded. assert_eq!(Staking::bonded(&11), None); // Transfer works. @@ -7329,47 +7329,6 @@ mod bad_state_recovery { use super::*; use frame_support::traits::InspectLockableCurrency; - #[test] - fn fast_unstake_force_clean_works() { - ExtBuilder::default().has_stakers(true).build_and_execute(|| { - // setup the bad state: - // Bonded(1, 1) - // Bonded(2, 1) - // Ledger(1) = StakingLedger { stash = 1 } - // Ledger(2) = StakingLedger { stash = 1 } - assert_ok!(Staking::bond(RuntimeOrigin::signed(1), 100, RewardDestination::Staked)); - assert_ok!(Staking::nominate(RuntimeOrigin::signed(1), vec![11])); - assert_ok!(Staking::bond(RuntimeOrigin::signed(2), 100, RewardDestination::Staked)); - assert_ok!(Staking::nominate(RuntimeOrigin::signed(2), vec![11])); - - Ledger::::insert(&2, Ledger::::get(&1).unwrap()); - Ledger::::remove(&2); - - // double-check bad state. - assert!(StakingLedger::::get(StakingAccount::Stash(2)).is_err()); - assert_eq!(Ledger::::get(&2), None); - assert_eq!(Bonded::::iter().count(), 7); - assert_eq!(Payee::::iter().count(), 7); - assert_eq!(Ledger::::iter().count(), 6); - // in sum, try-state checks won't pass. - assert!(Staking::do_try_state(System::block_number()).is_err()); - - // calling force unstake without `force_clean` will fail since the ledger is corrupted. - assert_noop!( - Staking::force_unstake(RuntimeOrigin::root(), 2, 0, false), - Error::::NotController - ); - // however it works and cleans up all lingering state if `force_clean` flag is set. - assert_ok!(Staking::force_unstake(RuntimeOrigin::root(), 2, 0, true)); - - // bad ledger was unbonded. - assert_eq!(Bonded::::get(&2), None); - assert_eq!(Ledger::::get(&2), None); - // try-state checks are ok now. - assert_ok!(Staking::do_try_state(System::block_number())); - }) - } - #[test] fn reset_ledge_default_works() { ExtBuilder::default().has_stakers(true).build_and_execute(|| { From 11920e483f4d83bd7272d5bd4673e1c1261ea149 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Thu, 21 Mar 2024 09:43:53 +0000 Subject: [PATCH 14/31] remove unecessary CannotForceCleanLedger error variant --- substrate/frame/staking/src/pallet/mod.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 4bcbcaf10f2e..392608dc442f 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -858,8 +858,6 @@ pub mod pallet { BoundNotMet, /// Used when attempting to use deprecated controller account logic. ControllerDeprecated, - /// Cannot force clean a ledger. - CannotForceCleanLedger, /// Cannot reset a ledger. CannotResetLedger, } From c9aba77c5df932bd5ec66f98efd1ea2f59e77325 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Thu, 21 Mar 2024 10:35:15 +0000 Subject: [PATCH 15/31] Adds benchmarks --- substrate/frame/staking/src/benchmarking.rs | 11 ++++++++++- substrate/frame/staking/src/pallet/mod.rs | 2 +- substrate/frame/staking/src/weights.rs | 11 +++++++++++ 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/substrate/frame/staking/src/benchmarking.rs b/substrate/frame/staking/src/benchmarking.rs index a83060873973..44aa322d7168 100644 --- a/substrate/frame/staking/src/benchmarking.rs +++ b/substrate/frame/staking/src/benchmarking.rs @@ -32,7 +32,7 @@ use sp_runtime::{ traits::{Bounded, One, StaticLookup, TrailingZeroInput, Zero}, Perbill, Percent, Saturating, }; -use sp_staking::{currency_to_vote::CurrencyToVote, SessionIndex}; +use sp_staking::{currency_to_vote::CurrencyToVote, SessionIndex, StakingInterface}; use sp_std::prelude::*; pub use frame_benchmarking::v1::{ @@ -953,6 +953,15 @@ benchmarks! { assert_eq!(MinCommission::::get(), Perbill::from_percent(100)); } + reset_ledger { + let (stash, controller) = create_stash_controller::(0, 100, RewardDestination::Staked)?; + // corrupt ledger. + Ledger::::remove(controller); + }: _(RawOrigin::Root, stash.clone(), None, None, None, None, None, None) + verify { + assert_eq!(Staking::::status(&stash).unwrap(), StakerStatus::Nominator(vec![])); + } + impl_benchmark_test_suite!( Staking, crate::mock::ExtBuilder::default().has_stakers(true), diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 392608dc442f..5f44a816d2d7 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -2004,7 +2004,7 @@ pub mod pallet { /// NOTE: if the stash does not have an associated ledger and the `maybe_nominations` or /// `maybe_validator_prefs` are not given, the ledger will be reset as a nominator. #[pallet::call_index(29)] - #[pallet::weight(0)] + #[pallet::weight(T::WeightInfo::reset_ledger())] pub fn reset_ledger( origin: OriginFor, stash: T::AccountId, diff --git a/substrate/frame/staking/src/weights.rs b/substrate/frame/staking/src/weights.rs index 6f729e08ba5c..cb5595190956 100644 --- a/substrate/frame/staking/src/weights.rs +++ b/substrate/frame/staking/src/weights.rs @@ -80,6 +80,7 @@ pub trait WeightInfo { fn chill_other() -> Weight; fn force_apply_min_commission() -> Weight; fn set_min_commission() -> Weight; + fn reset_ledger() -> Weight; } /// Weights for `pallet_staking` using the Substrate node and recommended hardware. @@ -802,6 +803,11 @@ impl WeightInfo for SubstrateWeight { Weight::from_parts(3_334_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } + + /// to be re-written by CI bot. + fn reset_ledger() -> Weight { + Default::default() + } } // For backwards compatibility and tests. @@ -1523,4 +1529,9 @@ impl WeightInfo for () { Weight::from_parts(3_334_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } + + /// to be re-written by CI bot. + fn reset_ledger() -> Weight { + Default::default() + } } From ae4a1925306ca490d4527e5f388b8a3e707cc520 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Thu, 21 Mar 2024 14:10:09 +0000 Subject: [PATCH 16/31] removes metadata from ledger reset --- substrate/frame/staking/src/benchmarking.rs | 2 +- substrate/frame/staking/src/pallet/mod.rs | 27 +-------------------- substrate/frame/staking/src/tests.rs | 24 +++--------------- 3 files changed, 5 insertions(+), 48 deletions(-) diff --git a/substrate/frame/staking/src/benchmarking.rs b/substrate/frame/staking/src/benchmarking.rs index 44aa322d7168..efcab8d0a713 100644 --- a/substrate/frame/staking/src/benchmarking.rs +++ b/substrate/frame/staking/src/benchmarking.rs @@ -957,7 +957,7 @@ benchmarks! { let (stash, controller) = create_stash_controller::(0, 100, RewardDestination::Staked)?; // corrupt ledger. Ledger::::remove(controller); - }: _(RawOrigin::Root, stash.clone(), None, None, None, None, None, None) + }: _(RawOrigin::Root, stash.clone(), None, None, None) verify { assert_eq!(Staking::::status(&stash).unwrap(), StakerStatus::Nominator(vec![])); } diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 5f44a816d2d7..a988d070b3fd 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -2011,20 +2011,11 @@ pub mod pallet { maybe_controller: Option, maybe_total: Option>, maybe_unlocking: Option>, T::MaxUnlockingChunks>>, - maybe_payee: Option>, - maybe_nominations: Option>, - maybe_validator_prefs: Option, ) -> DispatchResultWithPostInfo { T::AdminOrigin::ensure_origin(origin)?; let controller = Bonded::::get(&stash).ok_or(Error::::NotStash)?; - // a stash cannot be reset as both validator and nominator. - ensure!( - maybe_nominations.is_none() || maybe_validator_prefs.is_none(), - Error::::CannotResetLedger - ); - // ensure that this bond is in a bad state to proceed. i.e. one of two states: either // the ledger for the controller does not exist or it exists but the stash is different // than expected. @@ -2051,25 +2042,9 @@ pub mod pallet { let mut ledger = StakingLedger::::new(stash.clone(), new_total); ledger.unlocking = new_unlocking; ledger.controller = Some(new_controller); + ledger.total = new_total; ledger.update()?; - // get and reset ledger's metadata. - let new_payee = - maybe_payee.unwrap_or(Payee::::get(&stash).unwrap_or(RewardDestination::Staked)); - Payee::::insert(&stash, new_payee); - - if let Some(validator_prefs) = maybe_validator_prefs { - // reset as validator. - Self::do_remove_nominator(&stash); - Self::do_add_validator(&stash, validator_prefs); - } else { - // reset as nominator. - let nominations = - maybe_nominations.unwrap_or(Nominators::::get(&stash).unwrap_or_default()); - Self::do_remove_validator(&stash); - Self::do_add_nominator(&stash, nominations); - }; - Ok(Pays::No.into()) } } diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 3d4571fb0835..29fe6b22d5e1 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -7330,7 +7330,7 @@ mod bad_state_recovery { use frame_support::traits::InspectLockableCurrency; #[test] - fn reset_ledge_default_works() { + fn reset_ledger_default_works() { ExtBuilder::default().has_stakers(true).build_and_execute(|| { setup_double_bonded_ledgers(); @@ -7352,32 +7352,14 @@ mod bad_state_recovery { // ledger bonded by stash 333 is OK and does not need fixing. assert_noop!( - Staking::reset_ledger( - RuntimeOrigin::root(), - 333, - None, - None, - None, - None, - None, - None - ), + Staking::reset_ledger(RuntimeOrigin::root(), 333, None, None, None), Error::::CannotResetLedger, ); assert!(Staking::do_try_state(System::block_number()).is_err()); // 444 is in a bad state and we can reset it. let's reset it to the default, on-chain // state. - assert_ok!(Staking::reset_ledger( - RuntimeOrigin::root(), - 444, - None, - None, - None, - None, - None, - None - )); + assert_ok!(Staking::reset_ledger(RuntimeOrigin::root(), 444, None, None, None)); // now the ledger can be feteched though the stash and the correct controller. let ledger_reset = StakingLedger::::get(StakingAccount::Stash(444)).unwrap(); From df0cf743992816e32a7454df2c27f75eaa597422 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Thu, 21 Mar 2024 23:19:54 +0000 Subject: [PATCH 17/31] simplify InspectLockableCurrency trait --- substrate/frame/balances/src/impl_currency.rs | 12 ++++--- .../balances/src/tests/currency_tests.rs | 32 +++---------------- substrate/frame/staking/src/pallet/mod.rs | 16 ++++------ substrate/frame/staking/src/tests.rs | 7 ++-- .../src/traits/tokens/currency/lockable.rs | 7 ++-- 5 files changed, 23 insertions(+), 51 deletions(-) diff --git a/substrate/frame/balances/src/impl_currency.rs b/substrate/frame/balances/src/impl_currency.rs index 38b700dc49ef..6a3c64614bbc 100644 --- a/substrate/frame/balances/src/impl_currency.rs +++ b/substrate/frame/balances/src/impl_currency.rs @@ -920,9 +920,13 @@ where } impl, I: 'static> InspectLockableCurrency for Pallet { - type Lock = BalanceLock; - - fn get_lock(id: LockIdentifier, who: &T::AccountId) -> Option { - Self::locks(who).into_iter().filter(|l| l.id == id).collect::>().pop() + fn balance_locked(id: LockIdentifier, who: &T::AccountId) -> Self::Balance { + Self::locks(who) + .into_iter() + .filter(|l| l.id == id) + .collect::>() + .pop() + .map(|l| l.amount) + .unwrap_or(Zero::zero()) } } diff --git a/substrate/frame/balances/src/tests/currency_tests.rs b/substrate/frame/balances/src/tests/currency_tests.rs index d9fdada7a681..7e4017aead9b 100644 --- a/substrate/frame/balances/src/tests/currency_tests.rs +++ b/substrate/frame/balances/src/tests/currency_tests.rs @@ -98,33 +98,11 @@ fn inspect_lock_should_work() { Balances::set_lock(ID_2, &1, 10, WithdrawReasons::all()); Balances::set_lock(ID_1, &2, 20, WithdrawReasons::all()); - assert_eq!( - >::get_lock(ID_1, &1), - Some(crate::BalanceLock { - id: ID_1, - amount: 10, - reasons: WithdrawReasons::all().into() - }) - ); - assert_eq!( - >::get_lock(ID_2, &1), - Some(crate::BalanceLock { - id: ID_2, - amount: 10, - reasons: WithdrawReasons::all().into() - }) - ); - assert_eq!( - >::get_lock(ID_1, &2), - Some(crate::BalanceLock { - id: ID_1, - amount: 20, - reasons: WithdrawReasons::all().into() - }) - ); - - assert_eq!(>::get_lock(ID_2, &2), None,); - assert_eq!(>::get_lock(ID_1, &3), None,); + assert_eq!(>::balance_locked(ID_1, &1), 10); + assert_eq!(>::balance_locked(ID_2, &1), 10); + assert_eq!(>::balance_locked(ID_1, &2), 20); + assert_eq!(>::balance_locked(ID_2, &2), 0); + assert_eq!(>::balance_locked(ID_1, &3), 0); }) } diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index a988d070b3fd..70e0aef16c2e 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -91,10 +91,7 @@ pub mod pallet { Self::AccountId, Moment = BlockNumberFor, Balance = Self::CurrencyBalance, - > + InspectLockableCurrency< - Self::AccountId, - Lock = pallet_balances::BalanceLock, - >; + > + InspectLockableCurrency; /// Just the `Currency::Balance` type; we have this item to allow us to constrain it to /// `From`. type CurrencyBalance: sp_runtime::traits::AtLeast32BitUnsigned @@ -1998,8 +1995,8 @@ pub mod pallet { /// be reset with the current values. /// /// Upon successful execution, this extrinsic will *recreate* the ledger based on its past - /// state and/or the `maybe_controller`, `maybe_total` and `maybe_unlocking` and - /// `maybe_payee` input parameters. + /// state and/or the `maybe_controller`, `maybe_total` and `maybe_unlocking` input + /// parameters. /// /// NOTE: if the stash does not have an associated ledger and the `maybe_nominations` or /// `maybe_validator_prefs` are not given, the ledger will be reset as a nominator. @@ -2027,22 +2024,21 @@ pub mod pallet { // get new ledger data. let new_controller = maybe_controller.unwrap_or(controller); + let new_total = maybe_total.unwrap_or_else(|| { - >::get_lock( + >::balance_locked( crate::STAKING_ID, &stash, ) - .map(|l| l.amount) - .unwrap_or(Zero::zero()) }); let new_unlocking = maybe_unlocking .unwrap_or_else(|| maybe_ledger.map(|l| l.unlocking).unwrap_or(Default::default())); // reset ledger state. let mut ledger = StakingLedger::::new(stash.clone(), new_total); + ledger.total = new_total; ledger.unlocking = new_unlocking; ledger.controller = Some(new_controller); - ledger.total = new_total; ledger.update()?; Ok(Pays::No.into()) diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 29fe6b22d5e1..5d83368a5ff6 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -7336,7 +7336,7 @@ mod bad_state_recovery { let ledger_before_corruption = StakingLedger::::get(StakingAccount::Stash(444)).unwrap(); - let lock_before_corruption = Balances::get_lock(crate::STAKING_ID, &444).unwrap(); + let locked_before_corruption = Balances::balance_locked(crate::STAKING_ID, &444); // remove ledger 444 (controlled by 555) to simulate a corruption with deletion. assert_eq!(Bonded::::get(&444), Some(555)); @@ -7368,10 +7368,7 @@ mod bad_state_recovery { StakingLedger::::get(StakingAccount::Controller(555)).unwrap() ); // reset lock is the same before corruption. - assert_eq!( - lock_before_corruption, - Balances::get_lock(crate::STAKING_ID, &444).unwrap() - ); + assert_eq!(locked_before_corruption, Balances::balance_locked(crate::STAKING_ID, &444)); // ledger is the same before corruption. assert_eq!(ledger_reset, ledger_before_corruption); diff --git a/substrate/frame/support/src/traits/tokens/currency/lockable.rs b/substrate/frame/support/src/traits/tokens/currency/lockable.rs index 188f6c10754b..51a48dd15ce8 100644 --- a/substrate/frame/support/src/traits/tokens/currency/lockable.rs +++ b/substrate/frame/support/src/traits/tokens/currency/lockable.rs @@ -66,11 +66,8 @@ pub trait LockableCurrency: Currency { /// A inspect interface for a currency whose accounts can have liquidity restrictions. pub trait InspectLockableCurrency: LockableCurrency { - // The lock type. - type Lock; - - /// Retrieves the lock information of a lock ID for a given account `who`, if it exists. - fn get_lock(id: LockIdentifier, who: &AccountId) -> Option; + /// Amount of funds locked for `who` associated with `id`. + fn balance_locked(id: LockIdentifier, who: &AccountId) -> Self::Balance; } /// A vesting schedule over a currency. This allows a particular currency to have vesting limits From a57a6991c2eaac8566725ef4d9a5c9c38d7a9c79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Fri, 22 Mar 2024 00:13:18 +0000 Subject: [PATCH 18/31] Ensures there's 0 imbalance on locks after ledger reset --- .../westend/src/weights/pallet_staking.rs | 4 ++ substrate/frame/staking/src/benchmarking.rs | 3 +- substrate/frame/staking/src/pallet/mod.rs | 49 ++++++++++++------- substrate/frame/staking/src/tests.rs | 4 +- 4 files changed, 39 insertions(+), 21 deletions(-) diff --git a/polkadot/runtime/westend/src/weights/pallet_staking.rs b/polkadot/runtime/westend/src/weights/pallet_staking.rs index 7a641e36a126..82abfb0c6e32 100644 --- a/polkadot/runtime/westend/src/weights/pallet_staking.rs +++ b/polkadot/runtime/westend/src/weights/pallet_staking.rs @@ -800,4 +800,8 @@ impl pallet_staking::WeightInfo for WeightInfo { .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } + /// to be re-written by CI bot. + fn reset_ledger() -> Weight { + Default::default() + } } diff --git a/substrate/frame/staking/src/benchmarking.rs b/substrate/frame/staking/src/benchmarking.rs index efcab8d0a713..a99e1b3d8072 100644 --- a/substrate/frame/staking/src/benchmarking.rs +++ b/substrate/frame/staking/src/benchmarking.rs @@ -957,7 +957,8 @@ benchmarks! { let (stash, controller) = create_stash_controller::(0, 100, RewardDestination::Staked)?; // corrupt ledger. Ledger::::remove(controller); - }: _(RawOrigin::Root, stash.clone(), None, None, None) + // TODO: None, None parameter inputs may not be the worst case scenario. + }: _(RawOrigin::Root, stash.clone(), None, None) verify { assert_eq!(Staking::::status(&stash).unwrap(), StakerStatus::Nominator(vec![])); } diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 70e0aef16c2e..d639a0f180e8 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -1995,11 +1995,7 @@ pub mod pallet { /// be reset with the current values. /// /// Upon successful execution, this extrinsic will *recreate* the ledger based on its past - /// state and/or the `maybe_controller`, `maybe_total` and `maybe_unlocking` input - /// parameters. - /// - /// NOTE: if the stash does not have an associated ledger and the `maybe_nominations` or - /// `maybe_validator_prefs` are not given, the ledger will be reset as a nominator. + /// state and/or the `maybe_controller` and `maybe_total` input parameters. #[pallet::call_index(29)] #[pallet::weight(T::WeightInfo::reset_ledger())] pub fn reset_ledger( @@ -2007,7 +2003,6 @@ pub mod pallet { stash: T::AccountId, maybe_controller: Option, maybe_total: Option>, - maybe_unlocking: Option>, T::MaxUnlockingChunks>>, ) -> DispatchResultWithPostInfo { T::AdminOrigin::ensure_origin(origin)?; @@ -2016,28 +2011,46 @@ pub mod pallet { // ensure that this bond is in a bad state to proceed. i.e. one of two states: either // the ledger for the controller does not exist or it exists but the stash is different // than expected. - let maybe_ledger = Ledger::::get(&controller); + let maybe_other_ledger = Ledger::::get(&controller); ensure!( - maybe_ledger.as_ref().map(|l| l.stash != stash).unwrap_or(true), + maybe_other_ledger.as_ref().map(|l| l.stash != stash).unwrap_or(true), Error::::CannotResetLedger, ); - // get new ledger data. - let new_controller = maybe_controller.unwrap_or(controller); - - let new_total = maybe_total.unwrap_or_else(|| { + let current_lock = >::balance_locked( crate::STAKING_ID, &stash, - ) - }); - let new_unlocking = maybe_unlocking - .unwrap_or_else(|| maybe_ledger.map(|l| l.unlocking).unwrap_or(Default::default())); + ); + + let new_total = if let Some(new_total) = maybe_total { + match maybe_other_ledger { + // if there is a ledger associated with this stash, it is the *wrong* ledger. + // Ensure that the "other" ledger has their locks/total updated so that the + // imbalance in the locks between ledgers is 0 (i.e. no more locks are + // created/deleted). + Some(mut other_ledger) => { + // note: ledger.total == ledger's staking lock amount. + other_ledger.total = new_total + .checked_sub(¤t_lock) + .ok_or(Error::::CannotResetLedger)?; + other_ledger.update()?; + + new_total + }, + // no ledger associated with this stash, force the new total. + None => new_total, + } + } else { + // keep the current lock/total of the ledger. + current_lock + }; // reset ledger state. + let new_controller = maybe_controller.unwrap_or(controller); + Bonded::::insert(&stash, &new_controller); + let mut ledger = StakingLedger::::new(stash.clone(), new_total); - ledger.total = new_total; - ledger.unlocking = new_unlocking; ledger.controller = Some(new_controller); ledger.update()?; diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 5d83368a5ff6..6a1f1b8d24c7 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -7352,14 +7352,14 @@ mod bad_state_recovery { // ledger bonded by stash 333 is OK and does not need fixing. assert_noop!( - Staking::reset_ledger(RuntimeOrigin::root(), 333, None, None, None), + Staking::reset_ledger(RuntimeOrigin::root(), 333, None, None), Error::::CannotResetLedger, ); assert!(Staking::do_try_state(System::block_number()).is_err()); // 444 is in a bad state and we can reset it. let's reset it to the default, on-chain // state. - assert_ok!(Staking::reset_ledger(RuntimeOrigin::root(), 444, None, None, None)); + assert_ok!(Staking::reset_ledger(RuntimeOrigin::root(), 444, None, None)); // now the ledger can be feteched though the stash and the correct controller. let ledger_reset = StakingLedger::::get(StakingAccount::Stash(444)).unwrap(); From e0bcbd3782c3c0d0f769f39a7890c035206196a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Fri, 22 Mar 2024 00:23:43 +0000 Subject: [PATCH 19/31] Adds guards for option to reset controller of the ledger --- substrate/frame/staking/src/pallet/mod.rs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index d639a0f180e8..fb1b669bf3e0 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -2024,7 +2024,7 @@ pub mod pallet { ); let new_total = if let Some(new_total) = maybe_total { - match maybe_other_ledger { + match maybe_other_ledger.clone() { // if there is a ledger associated with this stash, it is the *wrong* ledger. // Ensure that the "other" ledger has their locks/total updated so that the // imbalance in the locks between ledgers is 0 (i.e. no more locks are @@ -2046,10 +2046,15 @@ pub mod pallet { current_lock }; - // reset ledger state. - let new_controller = maybe_controller.unwrap_or(controller); - Bonded::::insert(&stash, &new_controller); + // re-bond stash and controller tuple. + let new_controller = if maybe_other_ledger.is_some() { + Bonded::::insert(&stash, &stash); + stash.clone() + } else { + maybe_controller.unwrap_or(controller) + }; + // reset ledger state. let mut ledger = StakingLedger::::new(stash.clone(), new_total); ledger.controller = Some(new_controller); ledger.update()?; From 209f3b0ba65c6b0245492ab58a8a1ba32086fe59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Sat, 23 Mar 2024 12:49:14 +0000 Subject: [PATCH 20/31] Implements inspect_bond_state and refactors recover_ledger with tests to recover all corrupted cases --- .../westend/src/weights/pallet_staking.rs | 2 +- substrate/frame/staking/src/benchmarking.rs | 2 +- substrate/frame/staking/src/lib.rs | 9 + substrate/frame/staking/src/mock.rs | 9 + substrate/frame/staking/src/pallet/impls.rs | 69 ++++- substrate/frame/staking/src/pallet/mod.rs | 104 ++++--- substrate/frame/staking/src/tests.rs | 283 ++++++++++++++++-- substrate/frame/staking/src/weights.rs | 6 +- 8 files changed, 395 insertions(+), 89 deletions(-) diff --git a/polkadot/runtime/westend/src/weights/pallet_staking.rs b/polkadot/runtime/westend/src/weights/pallet_staking.rs index 82abfb0c6e32..a27262146306 100644 --- a/polkadot/runtime/westend/src/weights/pallet_staking.rs +++ b/polkadot/runtime/westend/src/weights/pallet_staking.rs @@ -801,7 +801,7 @@ impl pallet_staking::WeightInfo for WeightInfo { .saturating_add(T::DbWeight::get().writes(1)) } /// to be re-written by CI bot. - fn reset_ledger() -> Weight { + fn restore_ledger() -> Weight { Default::default() } } diff --git a/substrate/frame/staking/src/benchmarking.rs b/substrate/frame/staking/src/benchmarking.rs index a99e1b3d8072..4c7e39ad16df 100644 --- a/substrate/frame/staking/src/benchmarking.rs +++ b/substrate/frame/staking/src/benchmarking.rs @@ -953,7 +953,7 @@ benchmarks! { assert_eq!(MinCommission::::get(), Perbill::from_percent(100)); } - reset_ledger { + restore_ledger { let (stash, controller) = create_stash_controller::(0, 100, RewardDestination::Staked)?; // corrupt ledger. Ledger::::remove(controller); diff --git a/substrate/frame/staking/src/lib.rs b/substrate/frame/staking/src/lib.rs index 0b06285668fb..c7d18d60dc25 100644 --- a/substrate/frame/staking/src/lib.rs +++ b/substrate/frame/staking/src/lib.rs @@ -491,6 +491,15 @@ pub struct StakingLedger { controller: Option, } +/// State of a ledger with regards with its data and metadata integrity. +#[derive(PartialEq, Debug)] +enum LedgerIntegrityState { + /// Ledger and corresponding staking lock is OK. + Ok, + Corrupted, + CorruptedKilled, +} + impl StakingLedger { /// Remove entries from `unlocking` that are sufficiently old and reduce the /// total by the sum of their balances. diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index e3a61a8356f0..c87807f019a4 100644 --- a/substrate/frame/staking/src/mock.rs +++ b/substrate/frame/staking/src/mock.rs @@ -786,6 +786,15 @@ pub(crate) fn bond_controller_stash(controller: AccountId, stash: AccountId) -> Ok(()) } +pub(crate) fn set_controller_simulate(stash: &AccountId) { + let controller = Bonded::::get(stash).expect("testing stash should be bonded"); + let ledger = Ledger::::get(&controller).expect("testing ledger should exist"); + + Ledger::::remove(&controller); + Ledger::::insert(stash, ledger); + Bonded::::insert(stash, stash); +} + pub(crate) fn setup_double_bonded_ledgers() { let init_ledgers = Ledger::::iter().count(); diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index d42456e53b13..9b803c3329c3 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -27,8 +27,8 @@ use frame_support::{ dispatch::WithPostDispatchInfo, pallet_prelude::*, traits::{ - Currency, Defensive, DefensiveSaturating, EstimateNextNewSession, Get, Imbalance, Len, - OnUnbalanced, TryCollect, UnixTime, + Currency, Defensive, DefensiveSaturating, EstimateNextNewSession, Get, Imbalance, + InspectLockableCurrency, Len, OnUnbalanced, TryCollect, UnixTime, }, weights::Weight, }; @@ -50,8 +50,8 @@ use sp_std::prelude::*; use crate::{ election_size_tracker::StaticTracker, log, slashing, weights::WeightInfo, ActiveEraInfo, BalanceOf, EraInfo, EraPayout, Exposure, ExposureOf, Forcing, IndividualExposure, - MaxNominationsOf, MaxWinnersOf, Nominations, NominationsQuota, PositiveImbalanceOf, - RewardDestination, SessionInterface, StakingLedger, ValidatorPrefs, + LedgerIntegrityState, MaxNominationsOf, MaxWinnersOf, Nominations, NominationsQuota, + PositiveImbalanceOf, RewardDestination, SessionInterface, StakingLedger, ValidatorPrefs, }; use super::pallet::*; @@ -84,6 +84,37 @@ impl Pallet { StakingLedger::::paired_account(Stash(stash.clone())) } + /// Inspects and returns the corruption state of a ledger and bond, if any. + /// + /// Note: all operations in this method access directly the `Bonded` and `Ledger` storage maps + /// instead of using the [`StakingLedger`] API since the bond and/or ledger may be corrupted. + pub(crate) fn inspect_bond_state( + stash: &T::AccountId, + ) -> Result> { + let controller = >::get(stash).ok_or_else(|| { + let lock = >::balance_locked( + crate::STAKING_ID, + &stash, + ); + + if lock == Zero::zero() { + Error::::NotStash + } else { + Error::::BadState + } + })?; + + match Ledger::::get(controller) { + Some(ledger) => + if ledger.stash != *stash { + Ok(LedgerIntegrityState::Corrupted) + } else { + Ok(LedgerIntegrityState::Ok) + }, + None => Ok(LedgerIntegrityState::CorruptedKilled), + } + } + /// The total balance that can be slashed from a stash account as of right now. pub fn slashable_balance_of(stash: &T::AccountId) -> BalanceOf { // Weight note: consider making the stake accessible through stash. @@ -1843,14 +1874,44 @@ impl Pallet { Self::check_exposures()?; Self::check_paged_exposures()?; Self::check_ledgers()?; + Self::check_locks()?; Self::check_count() } + /// Invariants: + /// + /// * Staking locked funds for every bonded stash should be the same as its ledger's total. + /// + /// NOTE: some of these checks result in warnings only. Once + /// is resolved, turn warns into check + /// failures. + fn check_locks() -> Result<(), TryRuntimeError> { + for (_, controller) in >::iter() { + if let Some(ledger) = >::get(&controller) { + let lock = >::balance_locked( + crate::STAKING_ID, + &ledger.stash, + ); + + if lock != ledger.total { + // TODO before merging: use warn + //log!(warn, "ledger.total != ledger.stash staking lock"); + return Err("ledger.total != ledger.stash staking lock".into()); + } + } else { + log!(warn, "bonded ledger does not exist"); + } + } + + Ok(()) + } + /// Invariants: /// * A controller should not be associated with more than one ledger. /// * A bonded (stash, controller) pair should have only one associated ledger. I.e. if the /// ledger is bonded by stash, the controller account must not bond a different ledger. /// * A bonded (stash, controller) pair must have an associated ledger. + /// /// NOTE: these checks result in warnings only. Once /// is resolved, turn warns into check /// failures. diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index fb1b669bf3e0..ead313eca6a5 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -48,9 +48,9 @@ pub use impls::*; use crate::{ slashing, weights::WeightInfo, AccountIdLookupOf, ActiveEraInfo, BalanceOf, EraPayout, - EraRewardPoints, Exposure, ExposurePage, Forcing, MaxNominationsOf, NegativeImbalanceOf, - Nominations, NominationsQuota, PositiveImbalanceOf, RewardDestination, SessionInterface, - StakingLedger, UnappliedSlash, UnlockChunk, ValidatorPrefs, + EraRewardPoints, Exposure, ExposurePage, Forcing, LedgerIntegrityState, MaxNominationsOf, + NegativeImbalanceOf, Nominations, NominationsQuota, PositiveImbalanceOf, RewardDestination, + SessionInterface, StakingLedger, UnappliedSlash, UnlockChunk, ValidatorPrefs, }; // The speculative number of spans are used as an input of the weight annotation of @@ -796,6 +796,7 @@ pub mod pallet { } #[pallet::error] + #[derive(PartialEq)] pub enum Error { /// Not a controller account. NotController, @@ -1983,9 +1984,9 @@ pub mod pallet { Ok(Some(T::WeightInfo::deprecate_controller_batch(controllers.len() as u32)).into()) } - /// Reset the state of a ledger which is in an inconsistent state. + /// Restores the state of a ledger which is in an inconsistent state. /// - /// The requirements to reset a ledger are the following: + /// The requirements to restore a ledger are the following: /// * The stash is bonded; /// * If the stash has an associated ledger, its state must be inconsistent; /// * The reset ledger must become either a nominator or validator. @@ -1997,8 +1998,8 @@ pub mod pallet { /// Upon successful execution, this extrinsic will *recreate* the ledger based on its past /// state and/or the `maybe_controller` and `maybe_total` input parameters. #[pallet::call_index(29)] - #[pallet::weight(T::WeightInfo::reset_ledger())] - pub fn reset_ledger( + #[pallet::weight(T::WeightInfo::restore_ledger())] + pub fn restore_ledger( origin: OriginFor, stash: T::AccountId, maybe_controller: Option, @@ -2006,59 +2007,64 @@ pub mod pallet { ) -> DispatchResultWithPostInfo { T::AdminOrigin::ensure_origin(origin)?; - let controller = Bonded::::get(&stash).ok_or(Error::::NotStash)?; + // closure to call before return from extrinsic to ensure the restore was successful. + let integrity_checks = || { + let lock = T::Currency::balance_locked(crate::STAKING_ID, &stash); - // ensure that this bond is in a bad state to proceed. i.e. one of two states: either - // the ledger for the controller does not exist or it exists but the stash is different - // than expected. - let maybe_other_ledger = Ledger::::get(&controller); - ensure!( - maybe_other_ledger.as_ref().map(|l| l.stash != stash).unwrap_or(true), - Error::::CannotResetLedger, - ); - - let current_lock = - >::balance_locked( - crate::STAKING_ID, - &stash, - ); - - let new_total = if let Some(new_total) = maybe_total { - match maybe_other_ledger.clone() { - // if there is a ledger associated with this stash, it is the *wrong* ledger. - // Ensure that the "other" ledger has their locks/total updated so that the - // imbalance in the locks between ledgers is 0 (i.e. no more locks are - // created/deleted). - Some(mut other_ledger) => { - // note: ledger.total == ledger's staking lock amount. - other_ledger.total = new_total - .checked_sub(¤t_lock) - .ok_or(Error::::CannotResetLedger)?; - other_ledger.update()?; - - new_total - }, - // no ledger associated with this stash, force the new total. - None => new_total, + if let Some(ledger) = Bonded::::get(&stash).and_then(|c| Ledger::::get(&c)) { + ensure!(lock == ledger.total, Error::::BadState); + ensure!(Payee::::get(&stash).is_some(), Error::::BadState); + ensure!(Bonded::::get(&stash).is_some(), Error::::BadState); + } else { + ensure!(lock == Zero::zero(), Error::::BadState); } - } else { - // keep the current lock/total of the ledger. - current_lock + + Ok::<_, Error>(()) }; + let current_lock = T::Currency::balance_locked(crate::STAKING_ID, &stash); + + let (new_controller, new_total) = match Self::inspect_bond_state(&stash) { + Ok(LedgerIntegrityState::Corrupted) => { + let new_controller = maybe_controller.unwrap_or(stash.clone()); + let new_total = maybe_total.unwrap_or(current_lock); + + Ok((new_controller, new_total)) + }, + Ok(LedgerIntegrityState::CorruptedKilled) => { + if current_lock == Zero::zero() { + // this case needs to recover both lock and ledger, so the new total needs + // to be given by the called since there's no way to recover the total + // on-chain. + ensure!(maybe_total.is_some(), Error::::CannotResetLedger); + Ok(( + stash.clone(), + maybe_total.expect("total exists as per the check above; qed."), + )) + } else { + Ok((stash.clone(), current_lock)) + } + }, + Err(Error::::BadState) => { + // the stash and ledger do not exist but lock is lingering. + T::Currency::remove_lock(crate::STAKING_ID, &stash); + integrity_checks()?; + + return Ok(Pays::No.into()); + }, + Ok(LedgerIntegrityState::Ok) | Err(_) => Err(Error::::CannotResetLedger), + }?; + // re-bond stash and controller tuple. - let new_controller = if maybe_other_ledger.is_some() { - Bonded::::insert(&stash, &stash); - stash.clone() - } else { - maybe_controller.unwrap_or(controller) - }; + Bonded::::insert(&stash, &new_controller); // reset ledger state. let mut ledger = StakingLedger::::new(stash.clone(), new_total); ledger.controller = Some(new_controller); ledger.update()?; + integrity_checks()?; + Ok(Pays::No.into()) } } diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 6a1f1b8d24c7..c2462a211762 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -7072,7 +7072,7 @@ mod ledger { #[test] fn deprecate_controller_batch_works_full_weight() { - ExtBuilder::default().build_and_execute(|| { + ExtBuilder::default().try_state(false).build_and_execute(|| { // Given: let start = 1001; @@ -7325,56 +7325,277 @@ mod ledger { } } -mod bad_state_recovery { +mod ledger_recovery { use super::*; use frame_support::traits::InspectLockableCurrency; #[test] - fn reset_ledger_default_works() { - ExtBuilder::default().has_stakers(true).build_and_execute(|| { + fn inspect_recovery_ledger_simple_works() { + ExtBuilder::default().has_stakers(true).try_state(false).build_and_execute(|| { setup_double_bonded_ledgers(); - let ledger_before_corruption = - StakingLedger::::get(StakingAccount::Stash(444)).unwrap(); - let locked_before_corruption = Balances::balance_locked(crate::STAKING_ID, &444); + // non corrupted ledger. + assert_eq!(Staking::inspect_bond_state(&11).unwrap(), LedgerIntegrityState::Ok); + + // non bonded stash. + assert!(Bonded::::get(&1111).is_none()); + assert!(Staking::inspect_bond_state(&1111).is_err()); + + // double bonded but not corrupted. + assert_eq!(Staking::inspect_bond_state(&333).unwrap(), LedgerIntegrityState::Ok); + }) + } - // remove ledger 444 (controlled by 555) to simulate a corruption with deletion. - assert_eq!(Bonded::::get(&444), Some(555)); - Ledger::::remove(&555); + #[test] + fn inspect_recovery_ledger_corupted_killed_works() { + ExtBuilder::default().has_stakers(true).try_state(false).build_and_execute(|| { + setup_double_bonded_ledgers(); - // double-check bad state. - assert!(StakingLedger::::get(StakingAccount::Stash(444)).is_err()); - assert_eq!(Bonded::::iter().count(), 8); - assert_eq!(Payee::::iter().count(), 8); - assert_eq!(Ledger::::iter().count(), 7); - // in sum, try-state checks won't pass. + let lock_333_before = Balances::balance_locked(crate::STAKING_ID, &333); + + // get into corrupted and killed ledger state by killing a corrupted ledger: + // init state: + // (333, 444) + // (444, 555) + // set_controller(444) to 444 + // (333, 444) -> corrupted + // (444, 444) + // kill(333) + // (444, 444) -> corrupted and None. + assert_eq!(Staking::inspect_bond_state(&333).unwrap(), LedgerIntegrityState::Ok); + set_controller_simulate(&444); + + // now try-state fails. assert!(Staking::do_try_state(System::block_number()).is_err()); - // ledger bonded by stash 333 is OK and does not need fixing. - assert_noop!( - Staking::reset_ledger(RuntimeOrigin::root(), 333, None, None), - Error::::CannotResetLedger, + // 333 is corrupted since it's controller is linking 444 ledger. + assert_eq!(Staking::inspect_bond_state(&333).unwrap(), LedgerIntegrityState::Corrupted); + // 444 however is OK. + assert_eq!(Staking::inspect_bond_state(&444).unwrap(), LedgerIntegrityState::Ok); + + // kill the corrupted ledger that is associated with stash 333. + assert_ok!(StakingLedger::::kill(&333)); + + // 333 bond is no more but it returns `BadState` because the lock on this stash is + // still set (see checks below). + assert_eq!(Staking::inspect_bond_state(&333), Err(Error::::BadState)); + // now the *other* ledger associated with 444 has been corrupted and killed (None). + assert_eq!( + Staking::inspect_bond_state(&444), + Ok(LedgerIntegrityState::CorruptedKilled) ); + + // side effects on 333 - ledger, bonded, payee, lock should be completely empty. + // however, 333 lock remains. + assert_eq!(Balances::balance_locked(crate::STAKING_ID, &333), lock_333_before); // NOK + assert!(Bonded::::get(&333).is_none()); // OK + assert!(Payee::::get(&333).is_none()); // OK + assert!(Ledger::::get(&444).is_none()); // OK + + // side effects on 444 - ledger, bonded, payee, lock should remain be intact. + // however, 444 lock was removed. + assert_eq!(Balances::balance_locked(crate::STAKING_ID, &444), 0); // NOK + assert!(Bonded::::get(&444).is_some()); // OK + assert!(Payee::::get(&444).is_some()); // OK + assert!(Ledger::::get(&555).is_none()); // NOK + assert!(Staking::do_try_state(System::block_number()).is_err()); + }) + } - // 444 is in a bad state and we can reset it. let's reset it to the default, on-chain - // state. - assert_ok!(Staking::reset_ledger(RuntimeOrigin::root(), 444, None, None)); + #[test] + fn inspect_recovery_ledger_corupted_killed_other_works() { + ExtBuilder::default().has_stakers(true).try_state(false).build_and_execute(|| { + setup_double_bonded_ledgers(); - // now the ledger can be feteched though the stash and the correct controller. - let ledger_reset = StakingLedger::::get(StakingAccount::Stash(444)).unwrap(); + let lock_333_before = Balances::balance_locked(crate::STAKING_ID, &333); + + // get into corrupted and killed ledger state by killing a corrupted ledger: + // init state: + // (333, 444) + // (444, 555) + // set_controller(444) to 444 + // (333, 444) -> corrupted + // (444, 444) + // kill(444) + // (333, 444) -> corrupted and None + assert_eq!(Staking::inspect_bond_state(&333).unwrap(), LedgerIntegrityState::Ok); + set_controller_simulate(&444); + + // now try-state fails. + assert!(Staking::do_try_state(System::block_number()).is_err()); + + // 333 is corrupted since it's controller is linking 444 ledger. + assert_eq!(Staking::inspect_bond_state(&333).unwrap(), LedgerIntegrityState::Corrupted); + // 444 however is OK. + assert_eq!(Staking::inspect_bond_state(&444).unwrap(), LedgerIntegrityState::Ok); + + // kill the *other* ledger that is double bonded but not corrupted. + assert_ok!(StakingLedger::::kill(&444)); + + // now 333 is corrupted and None through the *other* ledger being killed. assert_eq!( - ledger_reset.clone(), - StakingLedger::::get(StakingAccount::Controller(555)).unwrap() + Staking::inspect_bond_state(&333).unwrap(), + LedgerIntegrityState::CorruptedKilled, + ); + // 444 is cleaned and not a stash anymore; no lock left behind. + assert_eq!(Ledger::::get(&444), None); + assert_eq!(Staking::inspect_bond_state(&444), Err(Error::::NotStash)); + + // side effects on 333 - ledger, bonded, payee, lock should be intact. + assert_eq!(Balances::balance_locked(crate::STAKING_ID, &333), lock_333_before); // OK + assert_eq!(Bonded::::get(&333), Some(444)); // OK + assert!(Payee::::get(&333).is_some()); // OK + // however, ledger associated with its controller was killed. + assert!(Ledger::::get(&444).is_none()); // NOK + + // side effects on 444 - ledger, bonded, payee, lock should be completely removed. + assert_eq!(Balances::balance_locked(crate::STAKING_ID, &444), 0); // OK + assert!(Bonded::::get(&444).is_none()); // OK + assert!(Payee::::get(&444).is_none()); // OK + assert!(Ledger::::get(&555).is_none()); // OK + + assert!(Staking::do_try_state(System::block_number()).is_err()); + }) + } + + // Corrupted ledger restore. + // + // * Double bonded and corrupted ledger. + #[test] + fn restore_ledger_corrupted_works() { + ExtBuilder::default().has_stakers(true).build_and_execute(|| { + setup_double_bonded_ledgers(); + + // get into corrupted and killed ledger state. + // init state: + // (333, 444) + // (444, 555) + // set_controller(444) to 444 + // (333, 444) -> corrupted + // (444, 444) + assert_eq!(Staking::inspect_bond_state(&333).unwrap(), LedgerIntegrityState::Ok); + set_controller_simulate(&444); + + assert_eq!(Staking::inspect_bond_state(&333).unwrap(), LedgerIntegrityState::Corrupted); + + // now try-state fails. + assert!(Staking::do_try_state(System::block_number()).is_err()); + + // recover the ledger bonded by 333 stash. + assert_ok!(Staking::restore_ledger(RuntimeOrigin::root(), 333, None, None)); + + // try-state checks are ok now. + assert_ok!(Staking::do_try_state(System::block_number())); + }) + } + + // Corrupted and killed ledger restore. + // + // * Double bonded and corrupted ledger. + // * Ledger killed by own controller. + #[test] + fn restore_ledger_corrupted_killed_works() { + ExtBuilder::default().has_stakers(true).build_and_execute(|| { + setup_double_bonded_ledgers(); + + // ledger.total == lock + let total_444_before_corruption = Balances::balance_locked(crate::STAKING_ID, &444); + + // get into corrupted and killed ledger state by killing a corrupted ledger: + // init state: + // (333, 444) + // (444, 555) + // set_controller(444) to 444 + // (333, 444) -> corrupted + // (444, 444) + // kill(333) + // (444, 444) -> corrupted and None. + assert_eq!(Staking::inspect_bond_state(&333).unwrap(), LedgerIntegrityState::Ok); + set_controller_simulate(&444); + + // kill the corrupted ledger that is associated with stash 333. + assert_ok!(StakingLedger::::kill(&333)); + + // 333 bond is no more but it returns `BadState` because the lock on this stash is + // still set (see checks below). + assert_eq!(Staking::inspect_bond_state(&333), Err(Error::::BadState)); + // now the *other* ledger associated with 444 has been corrupted and killed (None). + assert!(Staking::ledger(StakingAccount::Stash(444)).is_err()); + + // try-state should fail. + assert!(Staking::do_try_state(System::block_number()).is_err()); + + // recover the ledger bonded by 333 stash. + assert_ok!(Staking::restore_ledger(RuntimeOrigin::root(), 333, None, None)); + + // for the try-state checks to pass, we also need to recover the stash 444 which is + // corrupted too by proxy of kill(333). Currently, both the lock and the ledger of 444 + // have been cleared so we need to provide the new amount to restore the ledger. + assert_noop!( + Staking::restore_ledger(RuntimeOrigin::root(), 444, None, None,), + Error::::CannotResetLedger ); - // reset lock is the same before corruption. - assert_eq!(locked_before_corruption, Balances::balance_locked(crate::STAKING_ID, &444)); - // ledger is the same before corruption. - assert_eq!(ledger_reset, ledger_before_corruption); + assert_ok!(Staking::restore_ledger( + RuntimeOrigin::root(), + 444, + None, + Some(total_444_before_corruption) + )); // try-state checks are ok now. assert_ok!(Staking::do_try_state(System::block_number())); }) } + + // Corrupted and killed by *other* ledger restore. + // + // * Double bonded and corrupted ledger. + // * Ledger killed by own controller. + #[test] + fn restore_ledger_corrupted_killed_other_works() { + ExtBuilder::default().has_stakers(true).build_and_execute(|| { + setup_double_bonded_ledgers(); + + // get into corrupted and killed ledger state by killing a corrupted ledger: + // init state: + // (333, 444) + // (444, 555) + // set_controller(444) to 444 + // (333, 444) -> corrupted + // (444, 444) + // kill(444) + // (333, 444) -> corrupted and None + assert_eq!(Staking::inspect_bond_state(&333).unwrap(), LedgerIntegrityState::Ok); + set_controller_simulate(&444); + + // now try-state fails. + assert!(Staking::do_try_state(System::block_number()).is_err()); + + // 333 is corrupted since it's controller is linking 444 ledger. + assert_eq!(Staking::inspect_bond_state(&333).unwrap(), LedgerIntegrityState::Corrupted); + // 444 however is OK. + assert_eq!(Staking::inspect_bond_state(&444).unwrap(), LedgerIntegrityState::Ok); + + // kill the *other* ledger that is double bonded but not corrupted. + assert_ok!(StakingLedger::::kill(&444)); + + // recover the ledger bonded by 333 stash. + assert_ok!(Staking::restore_ledger(RuntimeOrigin::root(), 333, None, None)); + + // 444 does not need recover in this case since it's been killed successfully. + assert_eq!(Staking::inspect_bond_state(&444), Err(Error::::NotStash)); + + // try-state checks are ok now. + assert_ok!(Staking::do_try_state(System::block_number())); + }) + } + + #[test] + fn restore_ledger_inconsistent_locks_works() { + ExtBuilder::default().has_stakers(true).build_and_execute(|| { + setup_double_bonded_ledgers(); + }) + } } diff --git a/substrate/frame/staking/src/weights.rs b/substrate/frame/staking/src/weights.rs index cb5595190956..cb82598c40bd 100644 --- a/substrate/frame/staking/src/weights.rs +++ b/substrate/frame/staking/src/weights.rs @@ -80,7 +80,7 @@ pub trait WeightInfo { fn chill_other() -> Weight; fn force_apply_min_commission() -> Weight; fn set_min_commission() -> Weight; - fn reset_ledger() -> Weight; + fn restore_ledger() -> Weight; } /// Weights for `pallet_staking` using the Substrate node and recommended hardware. @@ -805,7 +805,7 @@ impl WeightInfo for SubstrateWeight { } /// to be re-written by CI bot. - fn reset_ledger() -> Weight { + fn restore_ledger() -> Weight { Default::default() } } @@ -1531,7 +1531,7 @@ impl WeightInfo for () { } /// to be re-written by CI bot. - fn reset_ledger() -> Weight { + fn restore_ledger() -> Weight { Default::default() } } From b3e4a73058e867380f4d3559e71334f0e2469ab1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Sun, 24 Mar 2024 21:18:49 +0000 Subject: [PATCH 21/31] Adds bond_extra ledger recovery --- substrate/frame/staking/src/lib.rs | 1 + substrate/frame/staking/src/mock.rs | 19 +++- substrate/frame/staking/src/pallet/impls.rs | 13 ++- substrate/frame/staking/src/pallet/mod.rs | 29 ++++- substrate/frame/staking/src/tests.rs | 117 +++++++++++++++++++- 5 files changed, 162 insertions(+), 17 deletions(-) diff --git a/substrate/frame/staking/src/lib.rs b/substrate/frame/staking/src/lib.rs index c7d18d60dc25..8dd68b192357 100644 --- a/substrate/frame/staking/src/lib.rs +++ b/substrate/frame/staking/src/lib.rs @@ -498,6 +498,7 @@ enum LedgerIntegrityState { Ok, Corrupted, CorruptedKilled, + LockCorrupted, } impl StakingLedger { diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index c87807f019a4..6db462c1a70f 100644 --- a/substrate/frame/staking/src/mock.rs +++ b/substrate/frame/staking/src/mock.rs @@ -25,8 +25,8 @@ use frame_election_provider_support::{ use frame_support::{ assert_ok, derive_impl, ord_parameter_types, parameter_types, traits::{ - ConstU64, Currency, EitherOfDiverse, FindAuthor, Get, Hooks, Imbalance, OnUnbalanced, - OneSessionHandler, + ConstU64, Currency, EitherOfDiverse, FindAuthor, Get, Hooks, Imbalance, LockableCurrency, + OnUnbalanced, OneSessionHandler, WithdrawReasons, }, weights::constants::RocksDbWeight, }; @@ -786,7 +786,8 @@ pub(crate) fn bond_controller_stash(controller: AccountId, stash: AccountId) -> Ok(()) } -pub(crate) fn set_controller_simulate(stash: &AccountId) { +// simulates `set_controller` without corrupted ledger checks for testing purposes. +pub(crate) fn set_controller_no_checks(stash: &AccountId) { let controller = Bonded::::get(stash).expect("testing stash should be bonded"); let ledger = Ledger::::get(&controller).expect("testing ledger should exist"); @@ -795,6 +796,18 @@ pub(crate) fn set_controller_simulate(stash: &AccountId) { Bonded::::insert(stash, stash); } +// simulates `bond_extra` without corrupted ledger checks for testing purposes. +pub(crate) fn bond_extra_no_checks(stash: &AccountId, amount: Balance) { + let controller = Bonded::::get(stash).expect("bond must exist to bond_extra"); + let mut ledger = Ledger::::get(&controller).expect("ledger must exist to bond_extra"); + + let new_total = ledger.total + amount; + Balances::set_lock(crate::STAKING_ID, stash, new_total, WithdrawReasons::all()); + ledger.total = new_total; + ledger.active = new_total; + Ledger::::insert(controller, ledger); +} + pub(crate) fn setup_double_bonded_ledgers() { let init_ledgers = Ledger::::iter().count(); diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index 9b803c3329c3..5556e86c93ba 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -91,12 +91,9 @@ impl Pallet { pub(crate) fn inspect_bond_state( stash: &T::AccountId, ) -> Result> { - let controller = >::get(stash).ok_or_else(|| { - let lock = >::balance_locked( - crate::STAKING_ID, - &stash, - ); + let lock = T::Currency::balance_locked(crate::STAKING_ID, &stash); + let controller = >::get(stash).ok_or_else(|| { if lock == Zero::zero() { Error::::NotStash } else { @@ -109,7 +106,11 @@ impl Pallet { if ledger.stash != *stash { Ok(LedgerIntegrityState::Corrupted) } else { - Ok(LedgerIntegrityState::Ok) + if lock != ledger.total { + Ok(LedgerIntegrityState::LockCorrupted) + } else { + Ok(LedgerIntegrityState::Ok) + } }, None => Ok(LedgerIntegrityState::CorruptedKilled), } diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index ead313eca6a5..74d8e4c1fe4a 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -25,7 +25,7 @@ use frame_support::{ pallet_prelude::*, traits::{ Currency, Defensive, DefensiveSaturating, EnsureOrigin, EstimateNextNewSession, Get, - InspectLockableCurrency, LockableCurrency, OnUnbalanced, UnixTime, + InspectLockableCurrency, LockableCurrency, OnUnbalanced, UnixTime, WithdrawReasons, }, weights::Weight, BoundedVec, @@ -2027,7 +2027,19 @@ pub mod pallet { let (new_controller, new_total) = match Self::inspect_bond_state(&stash) { Ok(LedgerIntegrityState::Corrupted) => { let new_controller = maybe_controller.unwrap_or(stash.clone()); - let new_total = maybe_total.unwrap_or(current_lock); + + let new_total = if let Some(new_total) = maybe_total { + // enforce lock == ledger.amount. + T::Currency::set_lock( + crate::STAKING_ID, + &stash, + new_total, + WithdrawReasons::all(), + ); + new_total + } else { + current_lock + }; Ok((new_controller, new_total)) }, @@ -2045,6 +2057,19 @@ pub mod pallet { Ok((stash.clone(), current_lock)) } }, + Ok(LedgerIntegrityState::LockCorrupted) => { + // ledger is not corrupted but its locks are out of sync. In this case, we need + // to enforce a new ledger.total and staking lock for this stash. + let new_total = maybe_total.ok_or(Error::::CannotResetLedger)?; + T::Currency::set_lock( + crate::STAKING_ID, + &stash, + new_total, + WithdrawReasons::all(), + ); + + Ok((stash.clone(), new_total)) + }, Err(Error::::BadState) => { // the stash and ledger do not exist but lock is lingering. T::Currency::remove_lock(crate::STAKING_ID, &stash); diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index c2462a211762..f59712d2c54d 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -7363,7 +7363,7 @@ mod ledger_recovery { // kill(333) // (444, 444) -> corrupted and None. assert_eq!(Staking::inspect_bond_state(&333).unwrap(), LedgerIntegrityState::Ok); - set_controller_simulate(&444); + set_controller_no_checks(&444); // now try-state fails. assert!(Staking::do_try_state(System::block_number()).is_err()); @@ -7420,7 +7420,7 @@ mod ledger_recovery { // kill(444) // (333, 444) -> corrupted and None assert_eq!(Staking::inspect_bond_state(&333).unwrap(), LedgerIntegrityState::Ok); - set_controller_simulate(&444); + set_controller_no_checks(&444); // now try-state fails. assert!(Staking::do_try_state(System::block_number()).is_err()); @@ -7459,6 +7459,37 @@ mod ledger_recovery { }) } + #[test] + fn inspect_recovery_ledger_lock_corrupted_works() { + ExtBuilder::default().has_stakers(true).try_state(false).build_and_execute(|| { + setup_double_bonded_ledgers(); + + // get into lock corrupted ledger state by bond_extra on a ledger that is double bonded + // with a corrupted ledger. + // init state: + // (333, 444) + // (444, 555) + // set_controller(444) to 444 + // (333, 444) -> corrupted + // (444, 444) + // bond_extra(333, 10) -> lock corrupted on 444 + assert_eq!(Staking::inspect_bond_state(&333).unwrap(), LedgerIntegrityState::Ok); + set_controller_no_checks(&444); + bond_extra_no_checks(&333, 10); + + // now try-state fails. + assert!(Staking::do_try_state(System::block_number()).is_err()); + + // 333 is corrupted since it's controller is linking 444 ledger. + assert_eq!(Staking::inspect_bond_state(&333).unwrap(), LedgerIntegrityState::Corrupted); + // 444 ledger is not corrupted but locks got out of sync. + assert_eq!( + Staking::inspect_bond_state(&444).unwrap(), + LedgerIntegrityState::LockCorrupted + ); + }) + } + // Corrupted ledger restore. // // * Double bonded and corrupted ledger. @@ -7475,7 +7506,7 @@ mod ledger_recovery { // (333, 444) -> corrupted // (444, 444) assert_eq!(Staking::inspect_bond_state(&333).unwrap(), LedgerIntegrityState::Ok); - set_controller_simulate(&444); + set_controller_no_checks(&444); assert_eq!(Staking::inspect_bond_state(&333).unwrap(), LedgerIntegrityState::Corrupted); @@ -7512,7 +7543,7 @@ mod ledger_recovery { // kill(333) // (444, 444) -> corrupted and None. assert_eq!(Staking::inspect_bond_state(&333).unwrap(), LedgerIntegrityState::Ok); - set_controller_simulate(&444); + set_controller_no_checks(&444); // kill the corrupted ledger that is associated with stash 333. assert_ok!(StakingLedger::::kill(&333)); @@ -7568,7 +7599,7 @@ mod ledger_recovery { // kill(444) // (333, 444) -> corrupted and None assert_eq!(Staking::inspect_bond_state(&333).unwrap(), LedgerIntegrityState::Ok); - set_controller_simulate(&444); + set_controller_no_checks(&444); // now try-state fails. assert!(Staking::do_try_state(System::block_number()).is_err()); @@ -7592,10 +7623,84 @@ mod ledger_recovery { }) } + // Corrupted with bond_extra. + // + // * Double bonded and corrupted ledger. + // * Corrupted ledger calls `bond_extra` #[test] - fn restore_ledger_inconsistent_locks_works() { + fn restore_ledger_corrupted_bond_extra_works() { ExtBuilder::default().has_stakers(true).build_and_execute(|| { setup_double_bonded_ledgers(); + + let lock_333_before = Balances::balance_locked(crate::STAKING_ID, &333); + let lock_444_before = Balances::balance_locked(crate::STAKING_ID, &444); + + // get into corrupted and killed ledger state by killing a corrupted ledger: + // init state: + // (333, 444) + // (444, 555) + // set_controller(444) to 444 + // (333, 444) -> corrupted + // (444, 444) + // bond_extra(444, 40) -> OK + // bond_extra(333, 30) -> locks out of sync + + assert_eq!(Staking::inspect_bond_state(&333).unwrap(), LedgerIntegrityState::Ok); + set_controller_no_checks(&444); + + // now try-state fails. + assert!(Staking::do_try_state(System::block_number()).is_err()); + + // if 444 bonds extra, the locks remain in sync. + bond_extra_no_checks(&444, 40); + assert_eq!(Balances::balance_locked(crate::STAKING_ID, &333), lock_333_before); + assert_eq!(Balances::balance_locked(crate::STAKING_ID, &444), lock_444_before + 40); + + // however if 333 bonds extra, the wrong lock is updated. + bond_extra_no_checks(&333, 30); + assert_eq!( + Balances::balance_locked(crate::STAKING_ID, &333), + lock_444_before + 40 + 30 + ); //not OK + assert_eq!(Balances::balance_locked(crate::STAKING_ID, &444), lock_444_before + 40); // OK + + // recover the ledger bonded by 333 stash. Note that the total/lock needs to be + // re-written since on-chain data lock has become out of sync. + assert_ok!(Staking::restore_ledger( + RuntimeOrigin::root(), + 333, + None, + Some(lock_333_before + 30) + )); + + // now recover 444 that although it's not corrupted, its lock and ledger.total are out + // of sync. in which case, we need to explicitly set the ledger's lock and amount, + // otherwise the ledger recover will fail. + assert_noop!( + Staking::restore_ledger(RuntimeOrigin::root(), 444, None, None,), + Error::::CannotResetLedger + ); + + //and enforcing a new ledger lock/total on this non-corrupted ledger will work. + assert_ok!(Staking::restore_ledger( + RuntimeOrigin::root(), + 444, + None, + Some(lock_444_before + 40) + )); + + // double-check that ledgers got to expected state and bond_extra done during the + // corrupted state is part of the recovered ledgers. + let ledger_333 = Bonded::::get(&333).and_then(Ledger::::get).unwrap(); + let ledger_444 = Bonded::::get(&444).and_then(Ledger::::get).unwrap(); + + assert_eq!(ledger_333.total, lock_333_before + 30); + assert_eq!(Balances::balance_locked(crate::STAKING_ID, &333), ledger_333.total); + assert_eq!(ledger_444.total, lock_444_before + 40); + assert_eq!(Balances::balance_locked(crate::STAKING_ID, &444), ledger_444.total); + + // try-state checks are ok now. + assert_ok!(Staking::do_try_state(System::block_number())); }) } } From 42bb49dc336b069f67d1961e8cac61095a700178 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Sun, 24 Mar 2024 21:48:20 +0000 Subject: [PATCH 22/31] Adds more integrity checks to restore_ledger --- substrate/frame/staking/src/pallet/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 74d8e4c1fe4a..52a8377f48d9 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -2011,10 +2011,10 @@ pub mod pallet { let integrity_checks = || { let lock = T::Currency::balance_locked(crate::STAKING_ID, &stash); - if let Some(ledger) = Bonded::::get(&stash).and_then(|c| Ledger::::get(&c)) { + if let Some(ledger) = Bonded::::get(&stash).and_then(Ledger::::get) { ensure!(lock == ledger.total, Error::::BadState); ensure!(Payee::::get(&stash).is_some(), Error::::BadState); - ensure!(Bonded::::get(&stash).is_some(), Error::::BadState); + ensure!(ledger.stash == stash, Error::::BadState); } else { ensure!(lock == Zero::zero(), Error::::BadState); } @@ -2045,8 +2045,8 @@ pub mod pallet { }, Ok(LedgerIntegrityState::CorruptedKilled) => { if current_lock == Zero::zero() { - // this case needs to recover both lock and ledger, so the new total needs - // to be given by the called since there's no way to recover the total + // this case needs to restore both lock and ledger, so the new total needs + // to be given by the called since there's no way to restore the total // on-chain. ensure!(maybe_total.is_some(), Error::::CannotResetLedger); Ok(( From 709976349c5a7a8c935bd75012f226eb789e8329 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Sun, 24 Mar 2024 22:12:26 +0000 Subject: [PATCH 23/31] comment nit --- substrate/frame/staking/src/pallet/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 52a8377f48d9..de574e9609e0 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -1989,7 +1989,7 @@ pub mod pallet { /// The requirements to restore a ledger are the following: /// * The stash is bonded; /// * If the stash has an associated ledger, its state must be inconsistent; - /// * The reset ledger must become either a nominator or validator. + /// * If the ledger is not corrupted *but* its staking lock is out of sync. /// /// The `maybe_*` input parameters will overwrite the corresponding data and metadata of the /// ledger associated with the stash. If the input parameters are not set, the ledger will From aaba944ee3df93460ce4c3c972bda836f6bfc9b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Tue, 26 Mar 2024 20:02:43 +0100 Subject: [PATCH 24/31] Update substrate/frame/staking/src/pallet/mod.rs --- substrate/frame/staking/src/pallet/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index de574e9609e0..2bd5a96034fc 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -1988,6 +1988,7 @@ pub mod pallet { /// /// The requirements to restore a ledger are the following: /// * The stash is bonded; + /// * The stash is not bonded but it has a staking lock left behind; /// * If the stash has an associated ledger, its state must be inconsistent; /// * If the ledger is not corrupted *but* its staking lock is out of sync. /// From 5da7bc81b1738d011f9e053d77d4613feff1eb36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Tue, 26 Mar 2024 23:24:56 +0000 Subject: [PATCH 25/31] Addresses PR comments --- substrate/frame/balances/src/impl_currency.rs | 5 +- substrate/frame/staking/src/benchmarking.rs | 2 +- substrate/frame/staking/src/lib.rs | 12 ++-- substrate/frame/staking/src/pallet/impls.rs | 45 +++------------ substrate/frame/staking/src/pallet/mod.rs | 55 ++++++++----------- substrate/frame/staking/src/tests.rs | 23 ++++---- 6 files changed, 50 insertions(+), 92 deletions(-) diff --git a/substrate/frame/balances/src/impl_currency.rs b/substrate/frame/balances/src/impl_currency.rs index 6a3c64614bbc..d5fe9934e239 100644 --- a/substrate/frame/balances/src/impl_currency.rs +++ b/substrate/frame/balances/src/impl_currency.rs @@ -924,9 +924,6 @@ impl, I: 'static> InspectLockableCurrency for Pallet< Self::locks(who) .into_iter() .filter(|l| l.id == id) - .collect::>() - .pop() - .map(|l| l.amount) - .unwrap_or(Zero::zero()) + .fold(Zero::zero(), |acc, l| acc + l.amount) } } diff --git a/substrate/frame/staking/src/benchmarking.rs b/substrate/frame/staking/src/benchmarking.rs index 4c7e39ad16df..1fb0a1a29633 100644 --- a/substrate/frame/staking/src/benchmarking.rs +++ b/substrate/frame/staking/src/benchmarking.rs @@ -958,7 +958,7 @@ benchmarks! { // corrupt ledger. Ledger::::remove(controller); // TODO: None, None parameter inputs may not be the worst case scenario. - }: _(RawOrigin::Root, stash.clone(), None, None) + }: _(RawOrigin::Root, stash.clone(), None, None, None) verify { assert_eq!(Staking::::status(&stash).unwrap(), StakerStatus::Nominator(vec![])); } diff --git a/substrate/frame/staking/src/lib.rs b/substrate/frame/staking/src/lib.rs index 8dd68b192357..f5b7e3eca3de 100644 --- a/substrate/frame/staking/src/lib.rs +++ b/substrate/frame/staking/src/lib.rs @@ -494,10 +494,14 @@ pub struct StakingLedger { /// State of a ledger with regards with its data and metadata integrity. #[derive(PartialEq, Debug)] enum LedgerIntegrityState { - /// Ledger and corresponding staking lock is OK. + /// Ledger, bond and corresponding staking lock is OK. Ok, + /// Ledger and/or bond is corrupted. This means that the bond has a ledger with a different + /// stash than the bonded stash. Corrupted, + /// Ledger was corrupted and it has been killed. CorruptedKilled, + /// Ledger and bond are OK, however the ledger's stash lock is out of sync. LockCorrupted, } @@ -729,12 +733,6 @@ pub struct Nominations { pub suppressed: bool, } -impl Default for Nominations { - fn default() -> Self { - Self { targets: Default::default(), submitted_in: 0, suppressed: false } - } -} - /// Facade struct to encapsulate `PagedExposureMetadata` and a single page of `ExposurePage`. /// /// This is useful where we need to take into account the validator's own stake and total exposure diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index 5556e86c93ba..471ba29ff3ce 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -1869,44 +1869,15 @@ impl Pallet { "VoterList contains non-staker" ); + Self::check_ledgers()?; Self::check_bonded_consistency()?; Self::check_payees()?; Self::check_nominators()?; Self::check_exposures()?; Self::check_paged_exposures()?; - Self::check_ledgers()?; - Self::check_locks()?; Self::check_count() } - /// Invariants: - /// - /// * Staking locked funds for every bonded stash should be the same as its ledger's total. - /// - /// NOTE: some of these checks result in warnings only. Once - /// is resolved, turn warns into check - /// failures. - fn check_locks() -> Result<(), TryRuntimeError> { - for (_, controller) in >::iter() { - if let Some(ledger) = >::get(&controller) { - let lock = >::balance_locked( - crate::STAKING_ID, - &ledger.stash, - ); - - if lock != ledger.total { - // TODO before merging: use warn - //log!(warn, "ledger.total != ledger.stash staking lock"); - return Err("ledger.total != ledger.stash staking lock".into()); - } - } else { - log!(warn, "bonded ledger does not exist"); - } - } - - Ok(()) - } - /// Invariants: /// * A controller should not be associated with more than one ledger. /// * A bonded (stash, controller) pair should have only one associated ledger. I.e. if the @@ -2007,19 +1978,19 @@ impl Pallet { } /// Invariants: - /// * `ledger.controller` is not stored in the storage (but populated at retrieval). /// * Stake consistency: ledger.total == ledger.active + sum(ledger.unlocking). /// * The controller keyeing the ledger and the ledger stash matches the state of the `Bonded` + /// * Staking locked funds for every bonded stash should be the same as its ledger's total. + /// * Staking ledger and bond are not corrupted. /// storage. fn check_ledgers() -> Result<(), TryRuntimeError> { Bonded::::iter() .map(|(stash, ctrl)| { - // `ledger.controller` is never stored in raw storage. - let raw = Ledger::::get(stash).unwrap_or_else(|| { - Ledger::::get(ctrl.clone()) - .expect("try_check: bonded stash/ctrl does not have an associated ledger") - }); - ensure!(raw.controller.is_none(), "raw storage controller should be None"); + // ensure locks consistency. + ensure!( + Self::inspect_bond_state(&stash) == Ok(LedgerIntegrityState::Ok), + "bond, ledger and/or staking lock inconsistent for a bonded stash." + ); // ensure ledger consistency. Self::ensure_ledger_consistent(ctrl) diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 2bd5a96034fc..73c6bf72901a 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -857,7 +857,7 @@ pub mod pallet { /// Used when attempting to use deprecated controller account logic. ControllerDeprecated, /// Cannot reset a ledger. - CannotResetLedger, + CannotRestoreLedger, } #[pallet::hooks] @@ -1987,17 +1987,14 @@ pub mod pallet { /// Restores the state of a ledger which is in an inconsistent state. /// /// The requirements to restore a ledger are the following: - /// * The stash is bonded; - /// * The stash is not bonded but it has a staking lock left behind; - /// * If the stash has an associated ledger, its state must be inconsistent; + /// * The stash is bonded; or + /// * The stash is not bonded but it has a staking lock left behind; or + /// * If the stash has an associated ledger and its state is inconsistent; or /// * If the ledger is not corrupted *but* its staking lock is out of sync. /// /// The `maybe_*` input parameters will overwrite the corresponding data and metadata of the /// ledger associated with the stash. If the input parameters are not set, the ledger will - /// be reset with the current values. - /// - /// Upon successful execution, this extrinsic will *recreate* the ledger based on its past - /// state and/or the `maybe_controller` and `maybe_total` input parameters. + /// be reset values from on-chain state. #[pallet::call_index(29)] #[pallet::weight(T::WeightInfo::restore_ledger())] pub fn restore_ledger( @@ -2005,24 +2002,10 @@ pub mod pallet { stash: T::AccountId, maybe_controller: Option, maybe_total: Option>, - ) -> DispatchResultWithPostInfo { + maybe_unlocking: Option>, T::MaxUnlockingChunks>>, + ) -> DispatchResult { T::AdminOrigin::ensure_origin(origin)?; - // closure to call before return from extrinsic to ensure the restore was successful. - let integrity_checks = || { - let lock = T::Currency::balance_locked(crate::STAKING_ID, &stash); - - if let Some(ledger) = Bonded::::get(&stash).and_then(Ledger::::get) { - ensure!(lock == ledger.total, Error::::BadState); - ensure!(Payee::::get(&stash).is_some(), Error::::BadState); - ensure!(ledger.stash == stash, Error::::BadState); - } else { - ensure!(lock == Zero::zero(), Error::::BadState); - } - - Ok::<_, Error>(()) - }; - let current_lock = T::Currency::balance_locked(crate::STAKING_ID, &stash); let (new_controller, new_total) = match Self::inspect_bond_state(&stash) { @@ -2049,7 +2032,7 @@ pub mod pallet { // this case needs to restore both lock and ledger, so the new total needs // to be given by the called since there's no way to restore the total // on-chain. - ensure!(maybe_total.is_some(), Error::::CannotResetLedger); + ensure!(maybe_total.is_some(), Error::::CannotRestoreLedger); Ok(( stash.clone(), maybe_total.expect("total exists as per the check above; qed."), @@ -2061,7 +2044,7 @@ pub mod pallet { Ok(LedgerIntegrityState::LockCorrupted) => { // ledger is not corrupted but its locks are out of sync. In this case, we need // to enforce a new ledger.total and staking lock for this stash. - let new_total = maybe_total.ok_or(Error::::CannotResetLedger)?; + let new_total = maybe_total.ok_or(Error::::CannotRestoreLedger)?; T::Currency::set_lock( crate::STAKING_ID, &stash, @@ -2074,24 +2057,30 @@ pub mod pallet { Err(Error::::BadState) => { // the stash and ledger do not exist but lock is lingering. T::Currency::remove_lock(crate::STAKING_ID, &stash); - integrity_checks()?; + ensure!( + Self::inspect_bond_state(&stash) == Err(Error::::NotStash), + Error::::BadState + ); - return Ok(Pays::No.into()); + return Ok(()); }, - Ok(LedgerIntegrityState::Ok) | Err(_) => Err(Error::::CannotResetLedger), + Ok(LedgerIntegrityState::Ok) | Err(_) => Err(Error::::CannotRestoreLedger), }?; // re-bond stash and controller tuple. Bonded::::insert(&stash, &new_controller); - // reset ledger state. + // resoter ledger state. let mut ledger = StakingLedger::::new(stash.clone(), new_total); ledger.controller = Some(new_controller); + ledger.unlocking = maybe_unlocking.unwrap_or_default(); ledger.update()?; - integrity_checks()?; - - Ok(Pays::No.into()) + ensure!( + Self::inspect_bond_state(&stash) == Ok(LedgerIntegrityState::Ok), + Error::::BadState + ); + Ok(()) } } } diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index f59712d2c54d..069d34820f17 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -7514,7 +7514,7 @@ mod ledger_recovery { assert!(Staking::do_try_state(System::block_number()).is_err()); // recover the ledger bonded by 333 stash. - assert_ok!(Staking::restore_ledger(RuntimeOrigin::root(), 333, None, None)); + assert_ok!(Staking::restore_ledger(RuntimeOrigin::root(), 333, None, None, None)); // try-state checks are ok now. assert_ok!(Staking::do_try_state(System::block_number())); @@ -7558,21 +7558,22 @@ mod ledger_recovery { assert!(Staking::do_try_state(System::block_number()).is_err()); // recover the ledger bonded by 333 stash. - assert_ok!(Staking::restore_ledger(RuntimeOrigin::root(), 333, None, None)); + assert_ok!(Staking::restore_ledger(RuntimeOrigin::root(), 333, None, None, None)); // for the try-state checks to pass, we also need to recover the stash 444 which is // corrupted too by proxy of kill(333). Currently, both the lock and the ledger of 444 // have been cleared so we need to provide the new amount to restore the ledger. assert_noop!( - Staking::restore_ledger(RuntimeOrigin::root(), 444, None, None,), - Error::::CannotResetLedger + Staking::restore_ledger(RuntimeOrigin::root(), 444, None, None, None), + Error::::CannotRestoreLedger ); assert_ok!(Staking::restore_ledger( RuntimeOrigin::root(), 444, None, - Some(total_444_before_corruption) + Some(total_444_before_corruption), + None, )); // try-state checks are ok now. @@ -7613,7 +7614,7 @@ mod ledger_recovery { assert_ok!(StakingLedger::::kill(&444)); // recover the ledger bonded by 333 stash. - assert_ok!(Staking::restore_ledger(RuntimeOrigin::root(), 333, None, None)); + assert_ok!(Staking::restore_ledger(RuntimeOrigin::root(), 333, None, None, None)); // 444 does not need recover in this case since it's been killed successfully. assert_eq!(Staking::inspect_bond_state(&444), Err(Error::::NotStash)); @@ -7670,15 +7671,16 @@ mod ledger_recovery { RuntimeOrigin::root(), 333, None, - Some(lock_333_before + 30) + Some(lock_333_before + 30), + None )); // now recover 444 that although it's not corrupted, its lock and ledger.total are out // of sync. in which case, we need to explicitly set the ledger's lock and amount, // otherwise the ledger recover will fail. assert_noop!( - Staking::restore_ledger(RuntimeOrigin::root(), 444, None, None,), - Error::::CannotResetLedger + Staking::restore_ledger(RuntimeOrigin::root(), 444, None, None, None), + Error::::CannotRestoreLedger ); //and enforcing a new ledger lock/total on this non-corrupted ledger will work. @@ -7686,7 +7688,8 @@ mod ledger_recovery { RuntimeOrigin::root(), 444, None, - Some(lock_444_before + 40) + Some(lock_444_before + 40), + None )); // double-check that ledgers got to expected state and bond_extra done during the From 5f04bb992551b9d90461da0f69e2ebe5cd6896f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Tue, 26 Mar 2024 23:36:50 +0000 Subject: [PATCH 26/31] moves pallet-balances as dev-dependency only again --- substrate/frame/staking/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/staking/Cargo.toml b/substrate/frame/staking/Cargo.toml index eed2a50147f2..15c4bf9e290e 100644 --- a/substrate/frame/staking/Cargo.toml +++ b/substrate/frame/staking/Cargo.toml @@ -30,7 +30,6 @@ frame-system = { path = "../system", default-features = false } pallet-session = { path = "../session", default-features = false, features = [ "historical", ] } -pallet-balances = { path = "../balances" } pallet-authorship = { path = "../authorship", default-features = false } sp-application-crypto = { path = "../../primitives/application-crypto", default-features = false, features = ["serde"] } frame-election-provider-support = { path = "../election-provider-support", default-features = false } @@ -41,6 +40,7 @@ frame-benchmarking = { path = "../benchmarking", default-features = false, optio rand_chacha = { version = "0.2", default-features = false, optional = true } [dev-dependencies] +pallet-balances = { path = "../balances" } sp-tracing = { path = "../../primitives/tracing" } sp-core = { path = "../../primitives/core" } sp-npos-elections = { path = "../../primitives/npos-elections" } From 46360fe13bc32c701271085f75421eb7034bdb8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Wed, 27 Mar 2024 00:08:04 +0000 Subject: [PATCH 27/31] fixes benches; adds prdoc --- substrate/frame/staking/src/benchmarking.rs | 5 ++--- substrate/frame/staking/src/pallet/mod.rs | 5 +++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/substrate/frame/staking/src/benchmarking.rs b/substrate/frame/staking/src/benchmarking.rs index 1fb0a1a29633..0b67cd460395 100644 --- a/substrate/frame/staking/src/benchmarking.rs +++ b/substrate/frame/staking/src/benchmarking.rs @@ -32,7 +32,7 @@ use sp_runtime::{ traits::{Bounded, One, StaticLookup, TrailingZeroInput, Zero}, Perbill, Percent, Saturating, }; -use sp_staking::{currency_to_vote::CurrencyToVote, SessionIndex, StakingInterface}; +use sp_staking::{currency_to_vote::CurrencyToVote, SessionIndex}; use sp_std::prelude::*; pub use frame_benchmarking::v1::{ @@ -957,10 +957,9 @@ benchmarks! { let (stash, controller) = create_stash_controller::(0, 100, RewardDestination::Staked)?; // corrupt ledger. Ledger::::remove(controller); - // TODO: None, None parameter inputs may not be the worst case scenario. }: _(RawOrigin::Root, stash.clone(), None, None, None) verify { - assert_eq!(Staking::::status(&stash).unwrap(), StakerStatus::Nominator(vec![])); + assert_eq!(Staking::::inspect_bond_state(&stash), Ok(LedgerIntegrityState::Ok)); } impl_benchmark_test_suite!( diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 9dbf26465c74..0831e22beb01 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -2007,6 +2007,7 @@ pub mod pallet { T::AdminOrigin::ensure_origin(origin)?; let current_lock = T::Currency::balance_locked(crate::STAKING_ID, &stash); + let stash_balance = T::Currency::free_balance(&stash); let (new_controller, new_total) = match Self::inspect_bond_state(&stash) { Ok(LedgerIntegrityState::Corrupted) => { @@ -2017,7 +2018,7 @@ pub mod pallet { T::Currency::set_lock( crate::STAKING_ID, &stash, - new_total, + new_total.min(stash_balance), WithdrawReasons::all(), ); new_total @@ -2048,7 +2049,7 @@ pub mod pallet { T::Currency::set_lock( crate::STAKING_ID, &stash, - new_total, + new_total.min(stash_balance), WithdrawReasons::all(), ); From 2ed2ed6f78141c0ee8b79f147996e5330ccba746 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Wed, 27 Mar 2024 00:19:36 +0000 Subject: [PATCH 28/31] Adds prdoc --- prdoc/pr_3706.prdoc | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 prdoc/pr_3706.prdoc diff --git a/prdoc/pr_3706.prdoc b/prdoc/pr_3706.prdoc new file mode 100644 index 000000000000..edeb08241bed --- /dev/null +++ b/prdoc/pr_3706.prdoc @@ -0,0 +1,20 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: Extrinsic to restore corrupted staking ledgers + +doc: + - audience: Runtime User + description: | + This PR adds a new extrinsic `Call::restore_ledger ` gated by `StakingAdmin` origin that restores a corrupted staking ledger. This extrinsic will be used to recover ledgers that were affected by the issue discussed in https://github.com/paritytech/polkadot-sdk/issues/3245. + The extrinsic will re-write the storage items associated with a stash account provided as input parameter. The data used to reset the ledger can be either i) fetched on-chain or ii) partially/totally set by the input parameters of the call. + + Changes introduced: + - Adds `Call::restore_ledger ` extrinsic to recover a corrupted ledger; + - Adds trait `frame_support::traits::currency::InspectLockableCurrency` to allow external pallets to read current locks given an account and lock ID; + - Implements the `InspectLockableCurrency` in the pallet-balances. + - Adds staking locks try-runtime checks (https://github.com/paritytech/polkadot-sdk/issues/3751) + +crates: + - name: pallet-staking + - name: pallet-balances From 9426202d84e72e291b5fa9e5bceb37ccb51a32f0 Mon Sep 17 00:00:00 2001 From: command-bot <> Date: Wed, 27 Mar 2024 02:38:03 +0000 Subject: [PATCH 29/31] ".git/.scripts/commands/bench/bench.sh" --subcommand=pallet --runtime=dev --target_dir=substrate --pallet=pallet_staking --- substrate/frame/staking/src/weights.rs | 578 +++++++++++++------------ 1 file changed, 313 insertions(+), 265 deletions(-) diff --git a/substrate/frame/staking/src/weights.rs b/substrate/frame/staking/src/weights.rs index cb82598c40bd..8a04a3dfb3f7 100644 --- a/substrate/frame/staking/src/weights.rs +++ b/substrate/frame/staking/src/weights.rs @@ -17,10 +17,10 @@ //! Autogenerated weights for `pallet_staking` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2024-01-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-03-27, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-q7z7ruxr-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-h2rr8wx7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: @@ -88,21 +88,21 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { /// Storage: `Staking::Bonded` (r:1 w:1) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Ledger` (r:1 w:1) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) /// Storage: `Balances::Locks` (r:1 w:1) /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) /// Storage: `Balances::Freezes` (r:1 w:0) /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) - /// Storage: `Staking::Ledger` (r:0 w:1) - /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) /// Storage: `Staking::Payee` (r:0 w:1) /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn bond() -> Weight { // Proof Size summary in bytes: - // Measured: `927` + // Measured: `1042` // Estimated: `4764` - // Minimum execution time: 42_042_000 picoseconds. - Weight::from_parts(43_292_000, 4764) - .saturating_add(T::DbWeight::get().reads(3_u64)) + // Minimum execution time: 48_753_000 picoseconds. + Weight::from_parts(50_539_000, 4764) + .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } /// Storage: `Staking::Bonded` (r:1 w:0) @@ -121,21 +121,21 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1990` // Estimated: `8877` - // Minimum execution time: 85_050_000 picoseconds. - Weight::from_parts(87_567_000, 8877) + // Minimum execution time: 92_701_000 picoseconds. + Weight::from_parts(95_657_000, 8877) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } /// Storage: `Staking::Ledger` (r:1 w:1) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Nominators` (r:1 w:0) /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) /// Storage: `Staking::MinNominatorBond` (r:1 w:0) /// Proof: `Staking::MinNominatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Staking::CurrentEra` (r:1 w:0) /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Staking::Bonded` (r:1 w:0) - /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Balances::Locks` (r:1 w:1) /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) /// Storage: `Balances::Freezes` (r:1 w:0) @@ -148,41 +148,43 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `2195` // Estimated: `8877` - // Minimum execution time: 89_076_000 picoseconds. - Weight::from_parts(92_715_000, 8877) + // Minimum execution time: 101_049_000 picoseconds. + Weight::from_parts(103_729_000, 8877) .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } /// Storage: `Staking::Ledger` (r:1 w:1) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) - /// Storage: `Staking::CurrentEra` (r:1 w:0) - /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `Staking::Bonded` (r:1 w:0) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::CurrentEra` (r:1 w:0) + /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `Balances::Locks` (r:1 w:1) /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) /// Storage: `Balances::Freezes` (r:1 w:0) /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::ReversePoolIdLookup` (r:1 w:0) + /// Proof: `NominationPools::ReversePoolIdLookup` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_update(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1115` + // Measured: `1297` // Estimated: `4764` - // Minimum execution time: 42_067_000 picoseconds. - Weight::from_parts(43_239_807, 4764) - // Standard Error: 831 - .saturating_add(Weight::from_parts(46_257, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(5_u64)) + // Minimum execution time: 51_672_000 picoseconds. + Weight::from_parts(53_817_441, 4764) + // Standard Error: 1_124 + .saturating_add(Weight::from_parts(49_168, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } /// Storage: `Staking::Ledger` (r:1 w:1) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:1) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::CurrentEra` (r:1 w:0) /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `Staking::SlashingSpans` (r:1 w:1) /// Proof: `Staking::SlashingSpans` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Staking::Bonded` (r:1 w:1) - /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Balances::Locks` (r:1 w:1) /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) /// Storage: `Balances::Freezes` (r:1 w:0) @@ -208,10 +210,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `2196 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 86_490_000 picoseconds. - Weight::from_parts(95_358_751, 6248) - // Standard Error: 3_952 - .saturating_add(Weight::from_parts(1_294_907, 0).saturating_mul(s.into())) + // Minimum execution time: 92_846_000 picoseconds. + Weight::from_parts(102_158_606, 6248) + // Standard Error: 4_187 + .saturating_add(Weight::from_parts(1_436_364, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(13_u64)) .saturating_add(T::DbWeight::get().writes(11_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -219,6 +221,8 @@ impl WeightInfo for SubstrateWeight { } /// Storage: `Staking::Ledger` (r:1 w:0) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::MinValidatorBond` (r:1 w:0) /// Proof: `Staking::MinValidatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Staking::MinCommission` (r:1 w:0) @@ -229,8 +233,6 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Staking::MaxValidatorsCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `Staking::Nominators` (r:1 w:0) /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) - /// Storage: `Staking::Bonded` (r:1 w:0) - /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListNodes` (r:1 w:1) /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListBags` (r:1 w:1) @@ -243,31 +245,35 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1372` // Estimated: `4556` - // Minimum execution time: 50_326_000 picoseconds. - Weight::from_parts(52_253_000, 4556) + // Minimum execution time: 58_162_000 picoseconds. + Weight::from_parts(60_124_000, 4556) .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } /// Storage: `Staking::Ledger` (r:1 w:0) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Nominators` (r:128 w:128) /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) /// The range of component `k` is `[1, 128]`. fn kick(k: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1280 + k * (569 ±0)` + // Measured: `1815 + k * (572 ±0)` // Estimated: `4556 + k * (3033 ±0)` - // Minimum execution time: 29_305_000 picoseconds. - Weight::from_parts(32_199_604, 4556) - // Standard Error: 7_150 - .saturating_add(Weight::from_parts(6_437_124, 0).saturating_mul(k.into())) - .saturating_add(T::DbWeight::get().reads(1_u64)) + // Minimum execution time: 37_950_000 picoseconds. + Weight::from_parts(34_461_075, 4556) + // Standard Error: 8_013 + .saturating_add(Weight::from_parts(6_696_510, 0).saturating_mul(k.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(k.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(k.into()))) .saturating_add(Weight::from_parts(0, 3033).saturating_mul(k.into())) } /// Storage: `Staking::Ledger` (r:1 w:0) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::MinNominatorBond` (r:1 w:0) /// Proof: `Staking::MinNominatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Staking::Nominators` (r:1 w:1) @@ -278,8 +284,6 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) /// Storage: `Staking::CurrentEra` (r:1 w:0) /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Staking::Bonded` (r:1 w:0) - /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListNodes` (r:2 w:2) /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListBags` (r:1 w:1) @@ -293,10 +297,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1866 + n * (102 ±0)` // Estimated: `6248 + n * (2520 ±0)` - // Minimum execution time: 63_267_000 picoseconds. - Weight::from_parts(61_741_404, 6248) - // Standard Error: 12_955 - .saturating_add(Weight::from_parts(3_811_743, 0).saturating_mul(n.into())) + // Minimum execution time: 70_167_000 picoseconds. + Weight::from_parts(68_024_084, 6248) + // Standard Error: 14_256 + .saturating_add(Weight::from_parts(4_195_757, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(6_u64)) @@ -304,6 +308,8 @@ impl WeightInfo for SubstrateWeight { } /// Storage: `Staking::Ledger` (r:1 w:0) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Validators` (r:1 w:0) /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) /// Storage: `Staking::Nominators` (r:1 w:1) @@ -318,11 +324,11 @@ impl WeightInfo for SubstrateWeight { /// Proof: `VoterList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn chill() -> Weight { // Proof Size summary in bytes: - // Measured: `1650` + // Measured: `1816` // Estimated: `6248` - // Minimum execution time: 52_862_000 picoseconds. - Weight::from_parts(54_108_000, 6248) - .saturating_add(T::DbWeight::get().reads(8_u64)) + // Minimum execution time: 61_730_000 picoseconds. + Weight::from_parts(63_430_000, 6248) + .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } /// Storage: `Staking::Ledger` (r:1 w:0) @@ -335,37 +341,37 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `902` // Estimated: `4556` - // Minimum execution time: 16_350_000 picoseconds. - Weight::from_parts(16_802_000, 4556) + // Minimum execution time: 20_857_000 picoseconds. + Weight::from_parts(21_615_000, 4556) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Staking::Ledger` (r:1 w:0) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) - /// Storage: `Staking::Payee` (r:1 w:1) - /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Staking::Bonded` (r:1 w:0) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Payee` (r:1 w:1) + /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn update_payee() -> Weight { // Proof Size summary in bytes: // Measured: `969` // Estimated: `4556` - // Minimum execution time: 19_981_000 picoseconds. - Weight::from_parts(20_539_000, 4556) + // Minimum execution time: 24_739_000 picoseconds. + Weight::from_parts(25_785_000, 4556) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Staking::Bonded` (r:1 w:1) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) - /// Storage: `Staking::Ledger` (r:1 w:2) + /// Storage: `Staking::Ledger` (r:2 w:2) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) fn set_controller() -> Weight { // Proof Size summary in bytes: // Measured: `902` - // Estimated: `4556` - // Minimum execution time: 19_304_000 picoseconds. - Weight::from_parts(20_000_000, 4556) - .saturating_add(T::DbWeight::get().reads(2_u64)) + // Estimated: `8122` + // Minimum execution time: 24_622_000 picoseconds. + Weight::from_parts(25_220_000, 8122) + .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } /// Storage: `Staking::ValidatorCount` (r:0 w:1) @@ -374,8 +380,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_568_000 picoseconds. - Weight::from_parts(2_708_000, 0) + // Minimum execution time: 2_634_000 picoseconds. + Weight::from_parts(2_842_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Staking::ForceEra` (r:0 w:1) @@ -384,8 +390,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_950_000 picoseconds. - Weight::from_parts(8_348_000, 0) + // Minimum execution time: 8_496_000 picoseconds. + Weight::from_parts(9_016_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Staking::ForceEra` (r:0 w:1) @@ -394,8 +400,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_967_000 picoseconds. - Weight::from_parts(8_222_000, 0) + // Minimum execution time: 8_510_000 picoseconds. + Weight::from_parts(8_893_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Staking::ForceEra` (r:0 w:1) @@ -404,8 +410,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_006_000 picoseconds. - Weight::from_parts(8_440_000, 0) + // Minimum execution time: 8_243_000 picoseconds. + Weight::from_parts(8_678_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Staking::Invulnerables` (r:0 w:1) @@ -415,30 +421,30 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_524_000 picoseconds. - Weight::from_parts(3_123_608, 0) - // Standard Error: 59 - .saturating_add(Weight::from_parts(11_596, 0).saturating_mul(v.into())) + // Minimum execution time: 2_781_000 picoseconds. + Weight::from_parts(3_441_708, 0) + // Standard Error: 58 + .saturating_add(Weight::from_parts(11_811, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Staking::Ledger` (r:5900 w:11800) + /// Storage: `Staking::Ledger` (r:11800 w:11800) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:5900 w:5900) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Payee` (r:5900 w:0) /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) - /// Storage: `Staking::Bonded` (r:0 w:5900) - /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// The range of component `i` is `[0, 5900]`. fn deprecate_controller_batch(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1356 + i * (151 ±0)` - // Estimated: `990 + i * (3566 ±0)` - // Minimum execution time: 2_092_000 picoseconds. - Weight::from_parts(2_258_000, 990) - // Standard Error: 32_695 - .saturating_add(Weight::from_parts(16_669_219, 0).saturating_mul(i.into())) - .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(i.into()))) + // Measured: `1746 + i * (229 ±0)` + // Estimated: `990 + i * (7132 ±0)` + // Minimum execution time: 5_331_000 picoseconds. + Weight::from_parts(5_511_000, 990) + // Standard Error: 66_734 + .saturating_add(Weight::from_parts(31_157_413, 0).saturating_mul(i.into())) + .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(i.into()))) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(i.into()))) - .saturating_add(Weight::from_parts(0, 3566).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(0, 7132).saturating_mul(i.into())) } /// Storage: `Staking::SlashingSpans` (r:1 w:1) /// Proof: `Staking::SlashingSpans` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -473,10 +479,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `2196 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 84_275_000 picoseconds. - Weight::from_parts(92_512_416, 6248) - // Standard Error: 3_633 - .saturating_add(Weight::from_parts(1_315_923, 0).saturating_mul(s.into())) + // Minimum execution time: 89_473_000 picoseconds. + Weight::from_parts(98_055_990, 6248) + // Standard Error: 4_159 + .saturating_add(Weight::from_parts(1_398_203, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(13_u64)) .saturating_add(T::DbWeight::get().writes(12_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -489,10 +495,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `66672` // Estimated: `70137` - // Minimum execution time: 101_707_000 picoseconds. - Weight::from_parts(912_819_462, 70137) - // Standard Error: 57_547 - .saturating_add(Weight::from_parts(4_856_799, 0).saturating_mul(s.into())) + // Minimum execution time: 102_480_000 picoseconds. + Weight::from_parts(1_165_789_820, 70137) + // Standard Error: 77_157 + .saturating_add(Weight::from_parts(6_489_253, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -529,10 +535,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `33297 + n * (377 ±0)` // Estimated: `30944 + n * (3774 ±0)` - // Minimum execution time: 138_657_000 picoseconds. - Weight::from_parts(167_173_445, 30944) - // Standard Error: 25_130 - .saturating_add(Weight::from_parts(44_566_012, 0).saturating_mul(n.into())) + // Minimum execution time: 156_890_000 picoseconds. + Weight::from_parts(202_972_688, 30944) + // Standard Error: 29_972 + .saturating_add(Weight::from_parts(48_226_698, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(14_u64)) .saturating_add(T::DbWeight::get().reads((6_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(4_u64)) @@ -556,10 +562,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1991 + l * (7 ±0)` // Estimated: `8877` - // Minimum execution time: 80_061_000 picoseconds. - Weight::from_parts(82_836_434, 8877) - // Standard Error: 4_348 - .saturating_add(Weight::from_parts(75_744, 0).saturating_mul(l.into())) + // Minimum execution time: 88_482_000 picoseconds. + Weight::from_parts(92_616_600, 8877) + // Standard Error: 4_411 + .saturating_add(Weight::from_parts(117_722, 0).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } @@ -594,10 +600,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `2196 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 92_560_000 picoseconds. - Weight::from_parts(97_684_741, 6248) - // Standard Error: 3_361 - .saturating_add(Weight::from_parts(1_292_732, 0).saturating_mul(s.into())) + // Minimum execution time: 98_489_000 picoseconds. + Weight::from_parts(102_968_643, 6248) + // Standard Error: 4_823 + .saturating_add(Weight::from_parts(1_420_838, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().writes(11_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -643,12 +649,12 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0 + n * (720 ±0) + v * (3598 ±0)` // Estimated: `512390 + n * (3566 ±0) + v * (3566 ±0)` - // Minimum execution time: 564_963_000 picoseconds. - Weight::from_parts(569_206_000, 512390) - // Standard Error: 2_033_235 - .saturating_add(Weight::from_parts(68_025_841, 0).saturating_mul(v.into())) - // Standard Error: 202_600 - .saturating_add(Weight::from_parts(17_916_770, 0).saturating_mul(n.into())) + // Minimum execution time: 604_820_000 picoseconds. + Weight::from_parts(608_838_000, 512390) + // Standard Error: 2_300_345 + .saturating_add(Weight::from_parts(72_980_573, 0).saturating_mul(v.into())) + // Standard Error: 229_216 + .saturating_add(Weight::from_parts(20_739_416, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(206_u64)) .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(n.into()))) @@ -679,12 +685,12 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `3175 + n * (911 ±0) + v * (395 ±0)` // Estimated: `512390 + n * (3566 ±0) + v * (3566 ±0)` - // Minimum execution time: 32_196_540_000 picoseconds. - Weight::from_parts(32_341_871_000, 512390) - // Standard Error: 354_657 - .saturating_add(Weight::from_parts(5_143_440, 0).saturating_mul(v.into())) - // Standard Error: 354_657 - .saturating_add(Weight::from_parts(3_328_189, 0).saturating_mul(n.into())) + // Minimum execution time: 37_380_439_000 picoseconds. + Weight::from_parts(38_187_734_000, 512390) + // Standard Error: 425_319 + .saturating_add(Weight::from_parts(6_001_288, 0).saturating_mul(v.into())) + // Standard Error: 425_319 + .saturating_add(Weight::from_parts(4_129_446, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(201_u64)) .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(n.into()))) @@ -701,10 +707,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `979 + v * (50 ±0)` // Estimated: `3510 + v * (2520 ±0)` - // Minimum execution time: 2_381_903_000 picoseconds. - Weight::from_parts(32_693_059, 3510) - // Standard Error: 10_000 - .saturating_add(Weight::from_parts(4_736_173, 0).saturating_mul(v.into())) + // Minimum execution time: 2_572_838_000 picoseconds. + Weight::from_parts(67_632_557, 3510) + // Standard Error: 12_028 + .saturating_add(Weight::from_parts(5_117_459, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(v.into()))) .saturating_add(Weight::from_parts(0, 2520).saturating_mul(v.into())) @@ -715,6 +721,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Staking::MinValidatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Staking::MaxValidatorsCount` (r:0 w:1) /// Proof: `Staking::MaxValidatorsCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Staking::MaxStakedRewards` (r:0 w:1) + /// Proof: `Staking::MaxStakedRewards` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) /// Storage: `Staking::ChillThreshold` (r:0 w:1) /// Proof: `Staking::ChillThreshold` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) /// Storage: `Staking::MaxNominatorsCount` (r:0 w:1) @@ -725,9 +733,9 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_434_000 picoseconds. - Weight::from_parts(5_742_000, 0) - .saturating_add(T::DbWeight::get().writes(6_u64)) + // Minimum execution time: 5_962_000 picoseconds. + Weight::from_parts(6_497_000, 0) + .saturating_add(T::DbWeight::get().writes(7_u64)) } /// Storage: `Staking::MinCommission` (r:0 w:1) /// Proof: `Staking::MinCommission` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -735,6 +743,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Staking::MinValidatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Staking::MaxValidatorsCount` (r:0 w:1) /// Proof: `Staking::MaxValidatorsCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Staking::MaxStakedRewards` (r:0 w:1) + /// Proof: `Staking::MaxStakedRewards` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) /// Storage: `Staking::ChillThreshold` (r:0 w:1) /// Proof: `Staking::ChillThreshold` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) /// Storage: `Staking::MaxNominatorsCount` (r:0 w:1) @@ -745,9 +755,9 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_588_000 picoseconds. - Weight::from_parts(4_854_000, 0) - .saturating_add(T::DbWeight::get().writes(6_u64)) + // Minimum execution time: 5_227_000 picoseconds. + Weight::from_parts(5_496_000, 0) + .saturating_add(T::DbWeight::get().writes(7_u64)) } /// Storage: `Staking::Bonded` (r:1 w:0) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) @@ -775,8 +785,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1939` // Estimated: `6248` - // Minimum execution time: 68_780_000 picoseconds. - Weight::from_parts(71_479_000, 6248) + // Minimum execution time: 75_129_000 picoseconds. + Weight::from_parts(77_498_000, 6248) .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -788,8 +798,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `691` // Estimated: `3510` - // Minimum execution time: 12_268_000 picoseconds. - Weight::from_parts(12_661_000, 3510) + // Minimum execution time: 13_488_000 picoseconds. + Weight::from_parts(14_183_000, 3510) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -799,14 +809,28 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_071_000 picoseconds. - Weight::from_parts(3_334_000, 0) + // Minimum execution time: 3_368_000 picoseconds. + Weight::from_parts(3_582_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } - - /// to be re-written by CI bot. + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:1) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Ledger` (r:1 w:1) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) fn restore_ledger() -> Weight { - Default::default() + // Proof Size summary in bytes: + // Measured: `1047` + // Estimated: `4764` + // Minimum execution time: 44_876_000 picoseconds. + Weight::from_parts(46_353_000, 4764) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) } } @@ -814,21 +838,21 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { /// Storage: `Staking::Bonded` (r:1 w:1) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Ledger` (r:1 w:1) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) /// Storage: `Balances::Locks` (r:1 w:1) /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) /// Storage: `Balances::Freezes` (r:1 w:0) /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) - /// Storage: `Staking::Ledger` (r:0 w:1) - /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) /// Storage: `Staking::Payee` (r:0 w:1) /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn bond() -> Weight { // Proof Size summary in bytes: - // Measured: `927` + // Measured: `1042` // Estimated: `4764` - // Minimum execution time: 42_042_000 picoseconds. - Weight::from_parts(43_292_000, 4764) - .saturating_add(RocksDbWeight::get().reads(3_u64)) + // Minimum execution time: 48_753_000 picoseconds. + Weight::from_parts(50_539_000, 4764) + .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } /// Storage: `Staking::Bonded` (r:1 w:0) @@ -847,21 +871,21 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1990` // Estimated: `8877` - // Minimum execution time: 85_050_000 picoseconds. - Weight::from_parts(87_567_000, 8877) + // Minimum execution time: 92_701_000 picoseconds. + Weight::from_parts(95_657_000, 8877) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } /// Storage: `Staking::Ledger` (r:1 w:1) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Nominators` (r:1 w:0) /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) /// Storage: `Staking::MinNominatorBond` (r:1 w:0) /// Proof: `Staking::MinNominatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Staking::CurrentEra` (r:1 w:0) /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Staking::Bonded` (r:1 w:0) - /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Balances::Locks` (r:1 w:1) /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) /// Storage: `Balances::Freezes` (r:1 w:0) @@ -874,41 +898,43 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `2195` // Estimated: `8877` - // Minimum execution time: 89_076_000 picoseconds. - Weight::from_parts(92_715_000, 8877) + // Minimum execution time: 101_049_000 picoseconds. + Weight::from_parts(103_729_000, 8877) .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } /// Storage: `Staking::Ledger` (r:1 w:1) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) - /// Storage: `Staking::CurrentEra` (r:1 w:0) - /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `Staking::Bonded` (r:1 w:0) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::CurrentEra` (r:1 w:0) + /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `Balances::Locks` (r:1 w:1) /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) /// Storage: `Balances::Freezes` (r:1 w:0) /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::ReversePoolIdLookup` (r:1 w:0) + /// Proof: `NominationPools::ReversePoolIdLookup` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_update(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1115` + // Measured: `1297` // Estimated: `4764` - // Minimum execution time: 42_067_000 picoseconds. - Weight::from_parts(43_239_807, 4764) - // Standard Error: 831 - .saturating_add(Weight::from_parts(46_257, 0).saturating_mul(s.into())) - .saturating_add(RocksDbWeight::get().reads(5_u64)) + // Minimum execution time: 51_672_000 picoseconds. + Weight::from_parts(53_817_441, 4764) + // Standard Error: 1_124 + .saturating_add(Weight::from_parts(49_168, 0).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// Storage: `Staking::Ledger` (r:1 w:1) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:1) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::CurrentEra` (r:1 w:0) /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `Staking::SlashingSpans` (r:1 w:1) /// Proof: `Staking::SlashingSpans` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Staking::Bonded` (r:1 w:1) - /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Balances::Locks` (r:1 w:1) /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) /// Storage: `Balances::Freezes` (r:1 w:0) @@ -934,10 +960,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `2196 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 86_490_000 picoseconds. - Weight::from_parts(95_358_751, 6248) - // Standard Error: 3_952 - .saturating_add(Weight::from_parts(1_294_907, 0).saturating_mul(s.into())) + // Minimum execution time: 92_846_000 picoseconds. + Weight::from_parts(102_158_606, 6248) + // Standard Error: 4_187 + .saturating_add(Weight::from_parts(1_436_364, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(13_u64)) .saturating_add(RocksDbWeight::get().writes(11_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -945,6 +971,8 @@ impl WeightInfo for () { } /// Storage: `Staking::Ledger` (r:1 w:0) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::MinValidatorBond` (r:1 w:0) /// Proof: `Staking::MinValidatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Staking::MinCommission` (r:1 w:0) @@ -955,8 +983,6 @@ impl WeightInfo for () { /// Proof: `Staking::MaxValidatorsCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `Staking::Nominators` (r:1 w:0) /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) - /// Storage: `Staking::Bonded` (r:1 w:0) - /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListNodes` (r:1 w:1) /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListBags` (r:1 w:1) @@ -969,31 +995,35 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1372` // Estimated: `4556` - // Minimum execution time: 50_326_000 picoseconds. - Weight::from_parts(52_253_000, 4556) + // Minimum execution time: 58_162_000 picoseconds. + Weight::from_parts(60_124_000, 4556) .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } /// Storage: `Staking::Ledger` (r:1 w:0) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Nominators` (r:128 w:128) /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) /// The range of component `k` is `[1, 128]`. fn kick(k: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1280 + k * (569 ±0)` + // Measured: `1815 + k * (572 ±0)` // Estimated: `4556 + k * (3033 ±0)` - // Minimum execution time: 29_305_000 picoseconds. - Weight::from_parts(32_199_604, 4556) - // Standard Error: 7_150 - .saturating_add(Weight::from_parts(6_437_124, 0).saturating_mul(k.into())) - .saturating_add(RocksDbWeight::get().reads(1_u64)) + // Minimum execution time: 37_950_000 picoseconds. + Weight::from_parts(34_461_075, 4556) + // Standard Error: 8_013 + .saturating_add(Weight::from_parts(6_696_510, 0).saturating_mul(k.into())) + .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(k.into()))) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(k.into()))) .saturating_add(Weight::from_parts(0, 3033).saturating_mul(k.into())) } /// Storage: `Staking::Ledger` (r:1 w:0) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::MinNominatorBond` (r:1 w:0) /// Proof: `Staking::MinNominatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Staking::Nominators` (r:1 w:1) @@ -1004,8 +1034,6 @@ impl WeightInfo for () { /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) /// Storage: `Staking::CurrentEra` (r:1 w:0) /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Staking::Bonded` (r:1 w:0) - /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListNodes` (r:2 w:2) /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListBags` (r:1 w:1) @@ -1019,10 +1047,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1866 + n * (102 ±0)` // Estimated: `6248 + n * (2520 ±0)` - // Minimum execution time: 63_267_000 picoseconds. - Weight::from_parts(61_741_404, 6248) - // Standard Error: 12_955 - .saturating_add(Weight::from_parts(3_811_743, 0).saturating_mul(n.into())) + // Minimum execution time: 70_167_000 picoseconds. + Weight::from_parts(68_024_084, 6248) + // Standard Error: 14_256 + .saturating_add(Weight::from_parts(4_195_757, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(6_u64)) @@ -1030,6 +1058,8 @@ impl WeightInfo for () { } /// Storage: `Staking::Ledger` (r:1 w:0) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Validators` (r:1 w:0) /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) /// Storage: `Staking::Nominators` (r:1 w:1) @@ -1044,11 +1074,11 @@ impl WeightInfo for () { /// Proof: `VoterList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn chill() -> Weight { // Proof Size summary in bytes: - // Measured: `1650` + // Measured: `1816` // Estimated: `6248` - // Minimum execution time: 52_862_000 picoseconds. - Weight::from_parts(54_108_000, 6248) - .saturating_add(RocksDbWeight::get().reads(8_u64)) + // Minimum execution time: 61_730_000 picoseconds. + Weight::from_parts(63_430_000, 6248) + .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } /// Storage: `Staking::Ledger` (r:1 w:0) @@ -1061,37 +1091,37 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `902` // Estimated: `4556` - // Minimum execution time: 16_350_000 picoseconds. - Weight::from_parts(16_802_000, 4556) + // Minimum execution time: 20_857_000 picoseconds. + Weight::from_parts(21_615_000, 4556) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Staking::Ledger` (r:1 w:0) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) - /// Storage: `Staking::Payee` (r:1 w:1) - /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Staking::Bonded` (r:1 w:0) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Payee` (r:1 w:1) + /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn update_payee() -> Weight { // Proof Size summary in bytes: // Measured: `969` // Estimated: `4556` - // Minimum execution time: 19_981_000 picoseconds. - Weight::from_parts(20_539_000, 4556) + // Minimum execution time: 24_739_000 picoseconds. + Weight::from_parts(25_785_000, 4556) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Staking::Bonded` (r:1 w:1) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) - /// Storage: `Staking::Ledger` (r:1 w:2) + /// Storage: `Staking::Ledger` (r:2 w:2) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) fn set_controller() -> Weight { // Proof Size summary in bytes: // Measured: `902` - // Estimated: `4556` - // Minimum execution time: 19_304_000 picoseconds. - Weight::from_parts(20_000_000, 4556) - .saturating_add(RocksDbWeight::get().reads(2_u64)) + // Estimated: `8122` + // Minimum execution time: 24_622_000 picoseconds. + Weight::from_parts(25_220_000, 8122) + .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } /// Storage: `Staking::ValidatorCount` (r:0 w:1) @@ -1100,8 +1130,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_568_000 picoseconds. - Weight::from_parts(2_708_000, 0) + // Minimum execution time: 2_634_000 picoseconds. + Weight::from_parts(2_842_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Staking::ForceEra` (r:0 w:1) @@ -1110,8 +1140,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_950_000 picoseconds. - Weight::from_parts(8_348_000, 0) + // Minimum execution time: 8_496_000 picoseconds. + Weight::from_parts(9_016_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Staking::ForceEra` (r:0 w:1) @@ -1120,8 +1150,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_967_000 picoseconds. - Weight::from_parts(8_222_000, 0) + // Minimum execution time: 8_510_000 picoseconds. + Weight::from_parts(8_893_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Staking::ForceEra` (r:0 w:1) @@ -1130,8 +1160,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_006_000 picoseconds. - Weight::from_parts(8_440_000, 0) + // Minimum execution time: 8_243_000 picoseconds. + Weight::from_parts(8_678_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Staking::Invulnerables` (r:0 w:1) @@ -1141,30 +1171,30 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_524_000 picoseconds. - Weight::from_parts(3_123_608, 0) - // Standard Error: 59 - .saturating_add(Weight::from_parts(11_596, 0).saturating_mul(v.into())) + // Minimum execution time: 2_781_000 picoseconds. + Weight::from_parts(3_441_708, 0) + // Standard Error: 58 + .saturating_add(Weight::from_parts(11_811, 0).saturating_mul(v.into())) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Staking::Ledger` (r:5900 w:11800) + /// Storage: `Staking::Ledger` (r:11800 w:11800) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:5900 w:5900) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Payee` (r:5900 w:0) /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) - /// Storage: `Staking::Bonded` (r:0 w:5900) - /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// The range of component `i` is `[0, 5900]`. fn deprecate_controller_batch(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1356 + i * (151 ±0)` - // Estimated: `990 + i * (3566 ±0)` - // Minimum execution time: 2_092_000 picoseconds. - Weight::from_parts(2_258_000, 990) - // Standard Error: 32_695 - .saturating_add(Weight::from_parts(16_669_219, 0).saturating_mul(i.into())) - .saturating_add(RocksDbWeight::get().reads((2_u64).saturating_mul(i.into()))) + // Measured: `1746 + i * (229 ±0)` + // Estimated: `990 + i * (7132 ±0)` + // Minimum execution time: 5_331_000 picoseconds. + Weight::from_parts(5_511_000, 990) + // Standard Error: 66_734 + .saturating_add(Weight::from_parts(31_157_413, 0).saturating_mul(i.into())) + .saturating_add(RocksDbWeight::get().reads((4_u64).saturating_mul(i.into()))) .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(i.into()))) - .saturating_add(Weight::from_parts(0, 3566).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(0, 7132).saturating_mul(i.into())) } /// Storage: `Staking::SlashingSpans` (r:1 w:1) /// Proof: `Staking::SlashingSpans` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -1199,10 +1229,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `2196 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 84_275_000 picoseconds. - Weight::from_parts(92_512_416, 6248) - // Standard Error: 3_633 - .saturating_add(Weight::from_parts(1_315_923, 0).saturating_mul(s.into())) + // Minimum execution time: 89_473_000 picoseconds. + Weight::from_parts(98_055_990, 6248) + // Standard Error: 4_159 + .saturating_add(Weight::from_parts(1_398_203, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(13_u64)) .saturating_add(RocksDbWeight::get().writes(12_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -1215,10 +1245,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `66672` // Estimated: `70137` - // Minimum execution time: 101_707_000 picoseconds. - Weight::from_parts(912_819_462, 70137) - // Standard Error: 57_547 - .saturating_add(Weight::from_parts(4_856_799, 0).saturating_mul(s.into())) + // Minimum execution time: 102_480_000 picoseconds. + Weight::from_parts(1_165_789_820, 70137) + // Standard Error: 77_157 + .saturating_add(Weight::from_parts(6_489_253, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1255,10 +1285,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `33297 + n * (377 ±0)` // Estimated: `30944 + n * (3774 ±0)` - // Minimum execution time: 138_657_000 picoseconds. - Weight::from_parts(167_173_445, 30944) - // Standard Error: 25_130 - .saturating_add(Weight::from_parts(44_566_012, 0).saturating_mul(n.into())) + // Minimum execution time: 156_890_000 picoseconds. + Weight::from_parts(202_972_688, 30944) + // Standard Error: 29_972 + .saturating_add(Weight::from_parts(48_226_698, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(14_u64)) .saturating_add(RocksDbWeight::get().reads((6_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(4_u64)) @@ -1282,10 +1312,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1991 + l * (7 ±0)` // Estimated: `8877` - // Minimum execution time: 80_061_000 picoseconds. - Weight::from_parts(82_836_434, 8877) - // Standard Error: 4_348 - .saturating_add(Weight::from_parts(75_744, 0).saturating_mul(l.into())) + // Minimum execution time: 88_482_000 picoseconds. + Weight::from_parts(92_616_600, 8877) + // Standard Error: 4_411 + .saturating_add(Weight::from_parts(117_722, 0).saturating_mul(l.into())) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } @@ -1320,10 +1350,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `2196 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 92_560_000 picoseconds. - Weight::from_parts(97_684_741, 6248) - // Standard Error: 3_361 - .saturating_add(Weight::from_parts(1_292_732, 0).saturating_mul(s.into())) + // Minimum execution time: 98_489_000 picoseconds. + Weight::from_parts(102_968_643, 6248) + // Standard Error: 4_823 + .saturating_add(Weight::from_parts(1_420_838, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().writes(11_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -1369,12 +1399,12 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0 + n * (720 ±0) + v * (3598 ±0)` // Estimated: `512390 + n * (3566 ±0) + v * (3566 ±0)` - // Minimum execution time: 564_963_000 picoseconds. - Weight::from_parts(569_206_000, 512390) - // Standard Error: 2_033_235 - .saturating_add(Weight::from_parts(68_025_841, 0).saturating_mul(v.into())) - // Standard Error: 202_600 - .saturating_add(Weight::from_parts(17_916_770, 0).saturating_mul(n.into())) + // Minimum execution time: 604_820_000 picoseconds. + Weight::from_parts(608_838_000, 512390) + // Standard Error: 2_300_345 + .saturating_add(Weight::from_parts(72_980_573, 0).saturating_mul(v.into())) + // Standard Error: 229_216 + .saturating_add(Weight::from_parts(20_739_416, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(206_u64)) .saturating_add(RocksDbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(RocksDbWeight::get().reads((4_u64).saturating_mul(n.into()))) @@ -1405,12 +1435,12 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `3175 + n * (911 ±0) + v * (395 ±0)` // Estimated: `512390 + n * (3566 ±0) + v * (3566 ±0)` - // Minimum execution time: 32_196_540_000 picoseconds. - Weight::from_parts(32_341_871_000, 512390) - // Standard Error: 354_657 - .saturating_add(Weight::from_parts(5_143_440, 0).saturating_mul(v.into())) - // Standard Error: 354_657 - .saturating_add(Weight::from_parts(3_328_189, 0).saturating_mul(n.into())) + // Minimum execution time: 37_380_439_000 picoseconds. + Weight::from_parts(38_187_734_000, 512390) + // Standard Error: 425_319 + .saturating_add(Weight::from_parts(6_001_288, 0).saturating_mul(v.into())) + // Standard Error: 425_319 + .saturating_add(Weight::from_parts(4_129_446, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(201_u64)) .saturating_add(RocksDbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(RocksDbWeight::get().reads((4_u64).saturating_mul(n.into()))) @@ -1427,10 +1457,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `979 + v * (50 ±0)` // Estimated: `3510 + v * (2520 ±0)` - // Minimum execution time: 2_381_903_000 picoseconds. - Weight::from_parts(32_693_059, 3510) - // Standard Error: 10_000 - .saturating_add(Weight::from_parts(4_736_173, 0).saturating_mul(v.into())) + // Minimum execution time: 2_572_838_000 picoseconds. + Weight::from_parts(67_632_557, 3510) + // Standard Error: 12_028 + .saturating_add(Weight::from_parts(5_117_459, 0).saturating_mul(v.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(v.into()))) .saturating_add(Weight::from_parts(0, 2520).saturating_mul(v.into())) @@ -1441,6 +1471,8 @@ impl WeightInfo for () { /// Proof: `Staking::MinValidatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Staking::MaxValidatorsCount` (r:0 w:1) /// Proof: `Staking::MaxValidatorsCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Staking::MaxStakedRewards` (r:0 w:1) + /// Proof: `Staking::MaxStakedRewards` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) /// Storage: `Staking::ChillThreshold` (r:0 w:1) /// Proof: `Staking::ChillThreshold` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) /// Storage: `Staking::MaxNominatorsCount` (r:0 w:1) @@ -1451,9 +1483,9 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_434_000 picoseconds. - Weight::from_parts(5_742_000, 0) - .saturating_add(RocksDbWeight::get().writes(6_u64)) + // Minimum execution time: 5_962_000 picoseconds. + Weight::from_parts(6_497_000, 0) + .saturating_add(RocksDbWeight::get().writes(7_u64)) } /// Storage: `Staking::MinCommission` (r:0 w:1) /// Proof: `Staking::MinCommission` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -1461,6 +1493,8 @@ impl WeightInfo for () { /// Proof: `Staking::MinValidatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Staking::MaxValidatorsCount` (r:0 w:1) /// Proof: `Staking::MaxValidatorsCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Staking::MaxStakedRewards` (r:0 w:1) + /// Proof: `Staking::MaxStakedRewards` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) /// Storage: `Staking::ChillThreshold` (r:0 w:1) /// Proof: `Staking::ChillThreshold` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) /// Storage: `Staking::MaxNominatorsCount` (r:0 w:1) @@ -1471,9 +1505,9 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_588_000 picoseconds. - Weight::from_parts(4_854_000, 0) - .saturating_add(RocksDbWeight::get().writes(6_u64)) + // Minimum execution time: 5_227_000 picoseconds. + Weight::from_parts(5_496_000, 0) + .saturating_add(RocksDbWeight::get().writes(7_u64)) } /// Storage: `Staking::Bonded` (r:1 w:0) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) @@ -1501,8 +1535,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1939` // Estimated: `6248` - // Minimum execution time: 68_780_000 picoseconds. - Weight::from_parts(71_479_000, 6248) + // Minimum execution time: 75_129_000 picoseconds. + Weight::from_parts(77_498_000, 6248) .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } @@ -1514,8 +1548,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `691` // Estimated: `3510` - // Minimum execution time: 12_268_000 picoseconds. - Weight::from_parts(12_661_000, 3510) + // Minimum execution time: 13_488_000 picoseconds. + Weight::from_parts(14_183_000, 3510) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1525,13 +1559,27 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_071_000 picoseconds. - Weight::from_parts(3_334_000, 0) + // Minimum execution time: 3_368_000 picoseconds. + Weight::from_parts(3_582_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - - /// to be re-written by CI bot. + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:1) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Ledger` (r:1 w:1) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) fn restore_ledger() -> Weight { - Default::default() + // Proof Size summary in bytes: + // Measured: `1047` + // Estimated: `4764` + // Minimum execution time: 44_876_000 picoseconds. + Weight::from_parts(46_353_000, 4764) + .saturating_add(RocksDbWeight::get().reads(5_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) } } From 10fc869a08c792e40c35bcabfe61d3b74f137228 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Wed, 27 Mar 2024 10:45:38 +0000 Subject: [PATCH 30/31] Adds new total checked balance --- substrate/frame/staking/src/pallet/mod.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 0831e22beb01..2e5b3aa7b873 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -2013,12 +2013,13 @@ pub mod pallet { Ok(LedgerIntegrityState::Corrupted) => { let new_controller = maybe_controller.unwrap_or(stash.clone()); - let new_total = if let Some(new_total) = maybe_total { + let new_total = if let Some(total) = maybe_total { + let new_total = total.min(stash_balance); // enforce lock == ledger.amount. T::Currency::set_lock( crate::STAKING_ID, &stash, - new_total.min(stash_balance), + new_total, WithdrawReasons::all(), ); new_total @@ -2045,11 +2046,12 @@ pub mod pallet { Ok(LedgerIntegrityState::LockCorrupted) => { // ledger is not corrupted but its locks are out of sync. In this case, we need // to enforce a new ledger.total and staking lock for this stash. - let new_total = maybe_total.ok_or(Error::::CannotRestoreLedger)?; + let new_total = + maybe_total.ok_or(Error::::CannotRestoreLedger)?.min(stash_balance); T::Currency::set_lock( crate::STAKING_ID, &stash, - new_total.min(stash_balance), + new_total, WithdrawReasons::all(), ); From a3100f88c22fbf0ded74cb7ec8c512744ac80deb Mon Sep 17 00:00:00 2001 From: command-bot <> Date: Wed, 27 Mar 2024 12:11:58 +0000 Subject: [PATCH 31/31] ".git/.scripts/commands/bench/bench.sh" --subcommand=pallet --runtime=westend --target_dir=polkadot --pallet=pallet_staking --- .../westend/src/weights/pallet_staking.rs | 286 ++++++++++-------- 1 file changed, 154 insertions(+), 132 deletions(-) diff --git a/polkadot/runtime/westend/src/weights/pallet_staking.rs b/polkadot/runtime/westend/src/weights/pallet_staking.rs index a27262146306..393fa0b37176 100644 --- a/polkadot/runtime/westend/src/weights/pallet_staking.rs +++ b/polkadot/runtime/westend/src/weights/pallet_staking.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_staking` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-01-28, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-03-27, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-8idpd4bs-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-h2rr8wx7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("westend-dev")`, DB CACHE: 1024 // Executed Command: @@ -50,22 +50,22 @@ pub struct WeightInfo(PhantomData); impl pallet_staking::WeightInfo for WeightInfo { /// Storage: `Staking::Bonded` (r:1 w:1) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Ledger` (r:1 w:1) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) /// Storage: `Balances::Locks` (r:1 w:1) /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) /// Storage: `Balances::Freezes` (r:1 w:0) /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) - /// Storage: `Staking::Ledger` (r:0 w:1) - /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) /// Storage: `Staking::Payee` (r:0 w:1) /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn bond() -> Weight { // Proof Size summary in bytes: - // Measured: `894` + // Measured: `1009` // Estimated: `4764` - // Minimum execution time: 37_340_000 picoseconds. - Weight::from_parts(38_930_000, 0) + // Minimum execution time: 40_585_000 picoseconds. + Weight::from_parts(41_800_000, 0) .saturating_add(Weight::from_parts(0, 4764)) - .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `Staking::Bonded` (r:1 w:0) @@ -84,22 +84,22 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `1921` // Estimated: `8877` - // Minimum execution time: 80_630_000 picoseconds. - Weight::from_parts(82_196_000, 0) + // Minimum execution time: 81_809_000 picoseconds. + Weight::from_parts(84_387_000, 0) .saturating_add(Weight::from_parts(0, 8877)) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(7)) } /// Storage: `Staking::Ledger` (r:1 w:1) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Nominators` (r:1 w:0) /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) /// Storage: `Staking::MinNominatorBond` (r:1 w:0) /// Proof: `Staking::MinNominatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Staking::CurrentEra` (r:1 w:0) /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Staking::Bonded` (r:1 w:0) - /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Balances::Locks` (r:1 w:1) /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) /// Storage: `Balances::Freezes` (r:1 w:0) @@ -112,43 +112,45 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `2128` // Estimated: `8877` - // Minimum execution time: 83_523_000 picoseconds. - Weight::from_parts(86_639_000, 0) + // Minimum execution time: 89_419_000 picoseconds. + Weight::from_parts(91_237_000, 0) .saturating_add(Weight::from_parts(0, 8877)) .saturating_add(T::DbWeight::get().reads(12)) .saturating_add(T::DbWeight::get().writes(7)) } /// Storage: `Staking::Ledger` (r:1 w:1) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) - /// Storage: `Staking::CurrentEra` (r:1 w:0) - /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `Staking::Bonded` (r:1 w:0) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::CurrentEra` (r:1 w:0) + /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `Balances::Locks` (r:1 w:1) /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) /// Storage: `Balances::Freezes` (r:1 w:0) /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `NominationPools::ReversePoolIdLookup` (r:1 w:0) + /// Proof: `NominationPools::ReversePoolIdLookup` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_update(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1075` + // Measured: `1223` // Estimated: `4764` - // Minimum execution time: 38_636_000 picoseconds. - Weight::from_parts(40_399_283, 0) + // Minimum execution time: 45_152_000 picoseconds. + Weight::from_parts(46_460_819, 0) .saturating_add(Weight::from_parts(0, 4764)) - // Standard Error: 869 - .saturating_add(Weight::from_parts(37_752, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(5)) + // Standard Error: 972 + .saturating_add(Weight::from_parts(55_473, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } /// Storage: `Staking::Ledger` (r:1 w:1) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:1) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::CurrentEra` (r:1 w:0) /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `Staking::SlashingSpans` (r:1 w:1) /// Proof: `Staking::SlashingSpans` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Staking::Bonded` (r:1 w:1) - /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Balances::Locks` (r:1 w:1) /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) /// Storage: `Balances::Freezes` (r:1 w:0) @@ -174,11 +176,11 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `2127 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 81_301_000 picoseconds. - Weight::from_parts(88_609_205, 0) + // Minimum execution time: 82_762_000 picoseconds. + Weight::from_parts(91_035_077, 0) .saturating_add(Weight::from_parts(0, 6248)) - // Standard Error: 3_388 - .saturating_add(Weight::from_parts(1_253_692, 0).saturating_mul(s.into())) + // Standard Error: 3_771 + .saturating_add(Weight::from_parts(1_217_871, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(13)) .saturating_add(T::DbWeight::get().writes(11)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -186,6 +188,8 @@ impl pallet_staking::WeightInfo for WeightInfo { } /// Storage: `Staking::Ledger` (r:1 w:0) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::MinValidatorBond` (r:1 w:0) /// Proof: `Staking::MinValidatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Staking::MinCommission` (r:1 w:0) @@ -196,8 +200,6 @@ impl pallet_staking::WeightInfo for WeightInfo { /// Proof: `Staking::MaxValidatorsCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `Staking::Nominators` (r:1 w:0) /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) - /// Storage: `Staking::Bonded` (r:1 w:0) - /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListNodes` (r:1 w:1) /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListBags` (r:1 w:1) @@ -210,33 +212,37 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `1301` // Estimated: `4556` - // Minimum execution time: 47_292_000 picoseconds. - Weight::from_parts(48_566_000, 0) + // Minimum execution time: 50_555_000 picoseconds. + Weight::from_parts(52_052_000, 0) .saturating_add(Weight::from_parts(0, 4556)) .saturating_add(T::DbWeight::get().reads(11)) .saturating_add(T::DbWeight::get().writes(5)) } /// Storage: `Staking::Ledger` (r:1 w:0) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Nominators` (r:128 w:128) /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) /// The range of component `k` is `[1, 128]`. fn kick(k: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1243 + k * (569 ±0)` + // Measured: `1778 + k * (572 ±0)` // Estimated: `4556 + k * (3033 ±0)` - // Minimum execution time: 28_840_000 picoseconds. - Weight::from_parts(27_510_817, 0) + // Minimum execution time: 35_037_000 picoseconds. + Weight::from_parts(35_081_878, 0) .saturating_add(Weight::from_parts(0, 4556)) - // Standard Error: 6_603 - .saturating_add(Weight::from_parts(6_268_853, 0).saturating_mul(k.into())) - .saturating_add(T::DbWeight::get().reads(1)) + // Standard Error: 5_473 + .saturating_add(Weight::from_parts(6_667_924, 0).saturating_mul(k.into())) + .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(k.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(k.into()))) .saturating_add(Weight::from_parts(0, 3033).saturating_mul(k.into())) } /// Storage: `Staking::Ledger` (r:1 w:0) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::MinNominatorBond` (r:1 w:0) /// Proof: `Staking::MinNominatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Staking::Nominators` (r:1 w:1) @@ -247,8 +253,6 @@ impl pallet_staking::WeightInfo for WeightInfo { /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) /// Storage: `Staking::CurrentEra` (r:1 w:0) /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Staking::Bonded` (r:1 w:0) - /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListNodes` (r:2 w:2) /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListBags` (r:1 w:1) @@ -262,11 +266,11 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `1797 + n * (102 ±0)` // Estimated: `6248 + n * (2520 ±0)` - // Minimum execution time: 57_537_000 picoseconds. - Weight::from_parts(55_854_233, 0) + // Minimum execution time: 62_098_000 picoseconds. + Weight::from_parts(60_154_061, 0) .saturating_add(Weight::from_parts(0, 6248)) - // Standard Error: 14_427 - .saturating_add(Weight::from_parts(3_844_957, 0).saturating_mul(n.into())) + // Standard Error: 19_257 + .saturating_add(Weight::from_parts(3_839_855, 0).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)) @@ -274,6 +278,8 @@ impl pallet_staking::WeightInfo for WeightInfo { } /// Storage: `Staking::Ledger` (r:1 w:0) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Validators` (r:1 w:0) /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) /// Storage: `Staking::Nominators` (r:1 w:1) @@ -288,12 +294,12 @@ impl pallet_staking::WeightInfo for WeightInfo { /// Proof: `VoterList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn chill() -> Weight { // Proof Size summary in bytes: - // Measured: `1581` + // Measured: `1747` // Estimated: `6248` - // Minimum execution time: 49_997_000 picoseconds. - Weight::from_parts(51_266_000, 0) + // Minimum execution time: 54_993_000 picoseconds. + Weight::from_parts(56_698_000, 0) .saturating_add(Weight::from_parts(0, 6248)) - .saturating_add(T::DbWeight::get().reads(8)) + .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(6)) } /// Storage: `Staking::Ledger` (r:1 w:0) @@ -306,40 +312,40 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `865` // Estimated: `4556` - // Minimum execution time: 15_342_000 picoseconds. - Weight::from_parts(15_970_000, 0) + // Minimum execution time: 18_100_000 picoseconds. + Weight::from_parts(18_547_000, 0) .saturating_add(Weight::from_parts(0, 4556)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `Staking::Ledger` (r:1 w:0) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) - /// Storage: `Staking::Payee` (r:1 w:1) - /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Staking::Bonded` (r:1 w:0) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Payee` (r:1 w:1) + /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn update_payee() -> Weight { // Proof Size summary in bytes: // Measured: `932` // Estimated: `4556` - // Minimum execution time: 20_719_000 picoseconds. - Weight::from_parts(21_373_000, 0) + // Minimum execution time: 23_428_000 picoseconds. + Weight::from_parts(24_080_000, 0) .saturating_add(Weight::from_parts(0, 4556)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `Staking::Bonded` (r:1 w:1) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) - /// Storage: `Staking::Ledger` (r:1 w:2) + /// Storage: `Staking::Ledger` (r:2 w:2) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) fn set_controller() -> Weight { // Proof Size summary in bytes: // Measured: `865` - // Estimated: `4556` - // Minimum execution time: 18_237_000 picoseconds. - Weight::from_parts(18_896_000, 0) - .saturating_add(Weight::from_parts(0, 4556)) - .saturating_add(T::DbWeight::get().reads(2)) + // Estimated: `8122` + // Minimum execution time: 21_159_000 picoseconds. + Weight::from_parts(21_706_000, 0) + .saturating_add(Weight::from_parts(0, 8122)) + .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `Staking::ValidatorCount` (r:0 w:1) @@ -348,8 +354,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_946_000 picoseconds. - Weight::from_parts(2_131_000, 0) + // Minimum execution time: 1_910_000 picoseconds. + Weight::from_parts(2_003_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -359,8 +365,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_840_000 picoseconds. - Weight::from_parts(7_208_000, 0) + // Minimum execution time: 7_076_000 picoseconds. + Weight::from_parts(7_349_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -370,8 +376,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_812_000 picoseconds. - Weight::from_parts(7_254_000, 0) + // Minimum execution time: 7_067_000 picoseconds. + Weight::from_parts(7_389_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -381,8 +387,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_787_000 picoseconds. - Weight::from_parts(7_206_000, 0) + // Minimum execution time: 7_148_000 picoseconds. + Weight::from_parts(7_446_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -393,32 +399,32 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_045_000 picoseconds. - Weight::from_parts(2_281_841, 0) + // Minimum execution time: 2_025_000 picoseconds. + Weight::from_parts(2_229_953, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 70 - .saturating_add(Weight::from_parts(11_592, 0).saturating_mul(v.into())) + // Standard Error: 67 + .saturating_add(Weight::from_parts(11_785, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `Staking::Ledger` (r:751 w:1502) + /// Storage: `Staking::Ledger` (r:1502 w:1502) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:751 w:751) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Payee` (r:751 w:0) /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) - /// Storage: `Staking::Bonded` (r:0 w:751) - /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// The range of component `i` is `[0, 751]`. fn deprecate_controller_batch(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `668 + i * (148 ±0)` - // Estimated: `990 + i * (3566 ±0)` - // Minimum execution time: 1_657_000 picoseconds. - Weight::from_parts(1_702_000, 0) + // Measured: `680 + i * (227 ±0)` + // Estimated: `990 + i * (7132 ±0)` + // Minimum execution time: 4_321_000 picoseconds. + Weight::from_parts(4_407_000, 0) .saturating_add(Weight::from_parts(0, 990)) - // Standard Error: 20_041 - .saturating_add(Weight::from_parts(13_165_254, 0).saturating_mul(i.into())) - .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(i.into()))) + // Standard Error: 37_239 + .saturating_add(Weight::from_parts(21_300_598, 0).saturating_mul(i.into())) + .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(i.into()))) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(i.into()))) - .saturating_add(Weight::from_parts(0, 3566).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(0, 7132).saturating_mul(i.into())) } /// Storage: `Staking::SlashingSpans` (r:1 w:1) /// Proof: `Staking::SlashingSpans` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -453,11 +459,11 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `2127 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 78_774_000 picoseconds. - Weight::from_parts(85_770_713, 0) + // Minimum execution time: 78_908_000 picoseconds. + Weight::from_parts(84_886_373, 0) .saturating_add(Weight::from_parts(0, 6248)) - // Standard Error: 2_815 - .saturating_add(Weight::from_parts(1_244_494, 0).saturating_mul(s.into())) + // Standard Error: 3_376 + .saturating_add(Weight::from_parts(1_217_850, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(13)) .saturating_add(T::DbWeight::get().writes(12)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -470,11 +476,11 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `66639` // Estimated: `70104` - // Minimum execution time: 129_905_000 picoseconds. - Weight::from_parts(932_195_554, 0) + // Minimum execution time: 136_389_000 picoseconds. + Weight::from_parts(1_207_241_524, 0) .saturating_add(Weight::from_parts(0, 70104)) - // Standard Error: 57_492 - .saturating_add(Weight::from_parts(4_826_754, 0).saturating_mul(s.into())) + // Standard Error: 77_138 + .saturating_add(Weight::from_parts(6_443_948, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -511,11 +517,11 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `8249 + n * (396 ±0)` // Estimated: `10779 + n * (3774 ±0)` - // Minimum execution time: 127_094_000 picoseconds. - Weight::from_parts(160_088_053, 0) + // Minimum execution time: 130_222_000 picoseconds. + Weight::from_parts(167_236_150, 0) .saturating_add(Weight::from_parts(0, 10779)) - // Standard Error: 32_978 - .saturating_add(Weight::from_parts(39_845_710, 0).saturating_mul(n.into())) + // Standard Error: 34_051 + .saturating_add(Weight::from_parts(39_899_917, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(14)) .saturating_add(T::DbWeight::get().reads((6_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(4)) @@ -539,11 +545,11 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `1922 + l * (5 ±0)` // Estimated: `8877` - // Minimum execution time: 75_672_000 picoseconds. - Weight::from_parts(78_708_335, 0) + // Minimum execution time: 79_136_000 picoseconds. + Weight::from_parts(82_129_497, 0) .saturating_add(Weight::from_parts(0, 8877)) - // Standard Error: 3_387 - .saturating_add(Weight::from_parts(37_084, 0).saturating_mul(l.into())) + // Standard Error: 3_867 + .saturating_add(Weight::from_parts(75_156, 0).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(7)) } @@ -578,11 +584,11 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `2127 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 87_991_000 picoseconds. - Weight::from_parts(90_272_005, 0) + // Minimum execution time: 89_375_000 picoseconds. + Weight::from_parts(91_224_907, 0) .saturating_add(Weight::from_parts(0, 6248)) - // Standard Error: 2_815 - .saturating_add(Weight::from_parts(1_232_322, 0).saturating_mul(s.into())) + // Standard Error: 3_424 + .saturating_add(Weight::from_parts(1_219_542, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(12)) .saturating_add(T::DbWeight::get().writes(11)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -627,14 +633,14 @@ impl pallet_staking::WeightInfo for WeightInfo { fn new_era(v: u32, n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + n * (716 ±0) + v * (3594 ±0)` - // Estimated: `456136 + n * (3566 ±0) + v * (3566 ±0)` - // Minimum execution time: 528_862_000 picoseconds. - Weight::from_parts(534_620_000, 0) + // Estimated: `456136 + n * (3566 ±4) + v * (3566 ±0)` + // Minimum execution time: 520_905_000 picoseconds. + Weight::from_parts(523_771_000, 0) .saturating_add(Weight::from_parts(0, 456136)) - // Standard Error: 2_005_553 - .saturating_add(Weight::from_parts(65_586_008, 0).saturating_mul(v.into())) - // Standard Error: 199_842 - .saturating_add(Weight::from_parts(18_155_389, 0).saturating_mul(n.into())) + // Standard Error: 2_142_714 + .saturating_add(Weight::from_parts(68_631_588, 0).saturating_mul(v.into())) + // Standard Error: 213_509 + .saturating_add(Weight::from_parts(19_343_025, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(184)) .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(n.into()))) @@ -665,13 +671,13 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `3108 + n * (907 ±0) + v * (391 ±0)` // Estimated: `456136 + n * (3566 ±0) + v * (3566 ±0)` - // Minimum execution time: 33_532_110_000 picoseconds. - Weight::from_parts(33_926_321_000, 0) + // Minimum execution time: 36_848_619_000 picoseconds. + Weight::from_parts(37_362_442_000, 0) .saturating_add(Weight::from_parts(0, 456136)) - // Standard Error: 374_134 - .saturating_add(Weight::from_parts(4_627_629, 0).saturating_mul(v.into())) - // Standard Error: 374_134 - .saturating_add(Weight::from_parts(4_068_168, 0).saturating_mul(n.into())) + // Standard Error: 415_031 + .saturating_add(Weight::from_parts(5_204_987, 0).saturating_mul(v.into())) + // Standard Error: 415_031 + .saturating_add(Weight::from_parts(4_132_636, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(179)) .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(n.into()))) @@ -688,11 +694,11 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `946 + v * (50 ±0)` // Estimated: `3510 + v * (2520 ±0)` - // Minimum execution time: 2_395_956_000 picoseconds. - Weight::from_parts(88_416_870, 0) + // Minimum execution time: 2_512_817_000 picoseconds. + Weight::from_parts(119_401_374, 0) .saturating_add(Weight::from_parts(0, 3510)) - // Standard Error: 8_731 - .saturating_add(Weight::from_parts(4_750_956, 0).saturating_mul(v.into())) + // Standard Error: 8_463 + .saturating_add(Weight::from_parts(4_860_364, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(v.into()))) .saturating_add(Weight::from_parts(0, 2520).saturating_mul(v.into())) @@ -715,8 +721,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_761_000 picoseconds. - Weight::from_parts(4_013_000, 0) + // Minimum execution time: 3_686_000 picoseconds. + Weight::from_parts(3_881_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(7)) } @@ -738,8 +744,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_325_000 picoseconds. - Weight::from_parts(3_519_000, 0) + // Minimum execution time: 3_143_000 picoseconds. + Weight::from_parts(3_424_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(7)) } @@ -769,8 +775,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `1870` // Estimated: `6248` - // Minimum execution time: 63_583_000 picoseconds. - Weight::from_parts(65_917_000, 0) + // Minimum execution time: 66_946_000 picoseconds. + Weight::from_parts(69_382_000, 0) .saturating_add(Weight::from_parts(0, 6248)) .saturating_add(T::DbWeight::get().reads(12)) .saturating_add(T::DbWeight::get().writes(6)) @@ -783,8 +789,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `658` // Estimated: `3510` - // Minimum execution time: 10_975_000 picoseconds. - Weight::from_parts(11_328_000, 0) + // Minimum execution time: 11_278_000 picoseconds. + Weight::from_parts(11_603_000, 0) .saturating_add(Weight::from_parts(0, 3510)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) @@ -795,13 +801,29 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_954_000 picoseconds. - Weight::from_parts(2_081_000, 0) + // Minimum execution time: 1_963_000 picoseconds. + Weight::from_parts(2_077_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } - /// to be re-written by CI bot. + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:1) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Ledger` (r:1 w:1) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) fn restore_ledger() -> Weight { - Default::default() + // Proof Size summary in bytes: + // Measured: `1014` + // Estimated: `4764` + // Minimum execution time: 40_258_000 picoseconds. + Weight::from_parts(41_210_000, 0) + .saturating_add(Weight::from_parts(0, 4764)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(4)) } }