From 02d3a70b8275079644d77e0905dc5a7025b364dd Mon Sep 17 00:00:00 2001 From: Ankan Date: Sun, 18 Aug 2024 20:02:21 +0200 Subject: [PATCH 001/142] prep for abstracting out all currency calls in a separate mod --- substrate/frame/staking/src/asset.rs | 17 +++++++++ substrate/frame/staking/src/lib.rs | 1 + substrate/frame/staking/src/pallet/impls.rs | 6 ++-- substrate/frame/staking/src/pallet/mod.rs | 12 +++---- substrate/frame/staking/src/tests.rs | 39 ++++++++++----------- 5 files changed, 45 insertions(+), 30 deletions(-) create mode 100644 substrate/frame/staking/src/asset.rs diff --git a/substrate/frame/staking/src/asset.rs b/substrate/frame/staking/src/asset.rs new file mode 100644 index 000000000000..06fba7277bc7 --- /dev/null +++ b/substrate/frame/staking/src/asset.rs @@ -0,0 +1,17 @@ +//! Facade of currency implementation. Useful while migrating from old to new currency system. + +use frame_support::{ + defensive, ensure, + traits::{Defensive, InspectLockableCurrency, LockableCurrency}, +}; +use sp_staking::{StakingAccount, StakingInterface}; + +use crate::{ + BalanceOf, Bonded, Config, Error, Ledger, Pallet, Payee, RewardDestination, StakingLedger, + VirtualStakers, STAKING_ID, +}; + +/// Balance that is staked and at stake. +pub fn staked(who: &T::AccountId) -> BalanceOf { + T::Currency::balance_locked(crate::STAKING_ID, who) +} diff --git a/substrate/frame/staking/src/lib.rs b/substrate/frame/staking/src/lib.rs index 9e59cbd3d0cb..19d999109d8d 100644 --- a/substrate/frame/staking/src/lib.rs +++ b/substrate/frame/staking/src/lib.rs @@ -295,6 +295,7 @@ pub(crate) mod mock; #[cfg(test)] mod tests; +pub mod asset; pub mod election_size_tracker; pub mod inflation; pub mod ledger; diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index 2df3bc084eb0..e28ac763b159 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -50,7 +50,7 @@ use sp_staking::{ }; use crate::{ - election_size_tracker::StaticTracker, log, slashing, weights::WeightInfo, ActiveEraInfo, + asset, election_size_tracker::StaticTracker, log, slashing, weights::WeightInfo, ActiveEraInfo, BalanceOf, EraInfo, EraPayout, Exposure, ExposureOf, Forcing, IndividualExposure, LedgerIntegrityState, MaxNominationsOf, MaxWinnersOf, Nominations, NominationsQuota, PositiveImbalanceOf, RewardDestination, SessionInterface, StakingLedger, ValidatorPrefs, @@ -96,7 +96,7 @@ impl Pallet { pub(crate) fn inspect_bond_state( stash: &T::AccountId, ) -> Result> { - let lock = T::Currency::balance_locked(crate::STAKING_ID, &stash); + let lock = asset::staked::(&stash); let controller = >::get(stash).ok_or_else(|| { if lock == Zero::zero() { @@ -2097,7 +2097,7 @@ impl Pallet { // ensure locks consistency. if VirtualStakers::::contains_key(stash.clone()) { ensure!( - T::Currency::balance_locked(crate::STAKING_ID, &stash) == Zero::zero(), + asset::staked::(&stash) == Zero::zero(), "virtual stakers should not have any locked balance" ); ensure!( diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 79f9d298ada7..5699df162603 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -48,11 +48,11 @@ mod impls; pub use impls::*; use crate::{ - slashing, weights::WeightInfo, AccountIdLookupOf, ActiveEraInfo, BalanceOf, DisablingStrategy, - EraPayout, EraRewardPoints, Exposure, ExposurePage, Forcing, LedgerIntegrityState, - MaxNominationsOf, NegativeImbalanceOf, Nominations, NominationsQuota, PositiveImbalanceOf, - RewardDestination, SessionInterface, StakingLedger, UnappliedSlash, UnlockChunk, - ValidatorPrefs, + asset, slashing, weights::WeightInfo, AccountIdLookupOf, ActiveEraInfo, BalanceOf, + DisablingStrategy, EraPayout, 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 @@ -2073,7 +2073,7 @@ pub mod pallet { // cannot restore ledger for virtual stakers. ensure!(!Self::is_virtual_staker(&stash), Error::::VirtualStakerNotAllowed); - let current_lock = T::Currency::balance_locked(crate::STAKING_ID, &stash); + let current_lock = asset::staked::(&stash); let stash_balance = T::Currency::free_balance(&stash); let (new_controller, new_total) = match Self::inspect_bond_state(&stash) { diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index ab2c00ca9ccc..fe54940c437c 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -18,7 +18,7 @@ //! Tests for the module. use super::{ConfigOp, Event, *}; -use crate::ledger::StakingLedgerInspect; +use crate::{asset, ledger::StakingLedgerInspect}; use frame_election_provider_support::{ bounds::{DataProviderBounds, ElectionBoundsBuilder}, ElectionProvider, SortedListProvider, Support, @@ -7222,7 +7222,7 @@ mod staking_unchecked { // stake assert_ok!(Staking::bond(RuntimeOrigin::signed(200), 1000, RewardDestination::Staked)); - assert_eq!(Balances::balance_locked(crate::STAKING_ID, &200), 1000); + assert_eq!(asset::staked::(&200), 1000); // migrate them to virtual staker ::migrate_to_virtual_staker(&200); @@ -7230,7 +7230,7 @@ mod staking_unchecked { assert_ok!(::set_payee(&200, &201)); // ensure the balance is not locked anymore - assert_eq!(Balances::balance_locked(crate::STAKING_ID, &200), 0); + assert_eq!(asset::staked::(&200), 0); // and they are marked as virtual stakers assert_eq!(Pallet::::is_virtual_staker(&200), true); @@ -7900,7 +7900,7 @@ mod ledger_recovery { ExtBuilder::default().has_stakers(true).try_state(false).build_and_execute(|| { setup_double_bonded_ledgers(); - let lock_333_before = Balances::balance_locked(crate::STAKING_ID, &333); + let lock_333_before = asset::staked::(&333); // get into corrupted and killed ledger state by killing a corrupted ledger: // init state: @@ -7936,14 +7936,14 @@ mod ledger_recovery { // 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_eq!(asset::staked::(&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_eq!(asset::staked::(&444), 0); // NOK assert!(Bonded::::get(&444).is_some()); // OK assert!(Payee::::get(&444).is_some()); // OK assert!(Ledger::::get(&555).is_none()); // NOK @@ -7957,7 +7957,7 @@ mod ledger_recovery { ExtBuilder::default().has_stakers(true).try_state(false).build_and_execute(|| { setup_double_bonded_ledgers(); - let lock_333_before = Balances::balance_locked(crate::STAKING_ID, &333); + let lock_333_before = asset::staked::(&333); // get into corrupted and killed ledger state by killing a corrupted ledger: // init state: @@ -7992,14 +7992,14 @@ mod ledger_recovery { 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!(asset::staked::(&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_eq!(asset::staked::(&444), 0); // OK assert!(Bonded::::get(&444).is_none()); // OK assert!(Payee::::get(&444).is_none()); // OK assert!(Ledger::::get(&555).is_none()); // OK @@ -8080,7 +8080,7 @@ mod ledger_recovery { setup_double_bonded_ledgers(); // ledger.total == lock - let total_444_before_corruption = Balances::balance_locked(crate::STAKING_ID, &444); + let total_444_before_corruption = asset::staked::(&444); // get into corrupted and killed ledger state by killing a corrupted ledger: // init state: @@ -8182,8 +8182,8 @@ mod ledger_recovery { 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); + let lock_333_before = asset::staked::(&333); + let lock_444_before = asset::staked::(&444); // get into corrupted and killed ledger state by killing a corrupted ledger: // init state: @@ -8203,16 +8203,13 @@ mod ledger_recovery { // 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); + assert_eq!(asset::staked::(&333), lock_333_before); + assert_eq!(asset::staked::(&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 + assert_eq!(asset::staked::(&333), lock_444_before + 40 + 30); //not OK + assert_eq!(asset::staked::(&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. @@ -8247,9 +8244,9 @@ mod ledger_recovery { 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!(asset::staked::(&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); + assert_eq!(asset::staked::(&444), ledger_444.total); // try-state checks are ok now. assert_ok!(Staking::do_try_state(System::block_number())); From fa1064f2ad03c7bd0c460db32a22f0c4c1b05ee4 Mon Sep 17 00:00:00 2001 From: Ankan Date: Sun, 18 Aug 2024 20:06:21 +0200 Subject: [PATCH 002/142] replace ED calls --- substrate/frame/staking/src/asset.rs | 7 ++++- substrate/frame/staking/src/benchmarking.rs | 30 ++++++++++---------- substrate/frame/staking/src/pallet/impls.rs | 4 +-- substrate/frame/staking/src/pallet/mod.rs | 10 +++---- substrate/frame/staking/src/slashing.rs | 4 +-- substrate/frame/staking/src/testing_utils.rs | 8 +++--- 6 files changed, 34 insertions(+), 29 deletions(-) diff --git a/substrate/frame/staking/src/asset.rs b/substrate/frame/staking/src/asset.rs index 06fba7277bc7..df072e5b4b2d 100644 --- a/substrate/frame/staking/src/asset.rs +++ b/substrate/frame/staking/src/asset.rs @@ -2,7 +2,7 @@ use frame_support::{ defensive, ensure, - traits::{Defensive, InspectLockableCurrency, LockableCurrency}, + traits::{Defensive, InspectLockableCurrency, LockableCurrency, Currency}, }; use sp_staking::{StakingAccount, StakingInterface}; @@ -15,3 +15,8 @@ use crate::{ pub fn staked(who: &T::AccountId) -> BalanceOf { T::Currency::balance_locked(crate::STAKING_ID, who) } + +/// Existential deposit for the chain. +pub fn existential_deposit() -> BalanceOf { + T::Currency::minimum_balance() +} \ No newline at end of file diff --git a/substrate/frame/staking/src/benchmarking.rs b/substrate/frame/staking/src/benchmarking.rs index 1f8580d7a3e6..6dfbe0c077ec 100644 --- a/substrate/frame/staking/src/benchmarking.rs +++ b/substrate/frame/staking/src/benchmarking.rs @@ -132,7 +132,7 @@ pub fn create_validator_with_nominators( ErasRewardPoints::::insert(current_era, reward); // Create reward pool - let total_payout = T::Currency::minimum_balance() + let total_payout = asset::existential_deposit::() .saturating_mul(upper_bound.into()) .saturating_mul(1000u32.into()); >::insert(current_era, total_payout); @@ -223,7 +223,7 @@ benchmarks! { bond { let stash = create_funded_user::("stash", USER_SEED, 100); let reward_destination = RewardDestination::Staked; - let amount = T::Currency::minimum_balance() * 10u32.into(); + let amount = asset::existential_deposit::() * 10u32.into(); whitelist_account!(stash); }: _(RawOrigin::Signed(stash.clone()), amount, reward_destination) verify { @@ -235,7 +235,7 @@ benchmarks! { // clean up any existing state. clear_validators_and_nominators::(); - let origin_weight = MinNominatorBond::::get().max(T::Currency::minimum_balance()); + let origin_weight = MinNominatorBond::::get().max(asset::existential_deposit::()); // setup the worst case list scenario. @@ -292,7 +292,7 @@ benchmarks! { let s in 0 .. MAX_SPANS; let (stash, controller) = create_stash_controller::(0, 100, RewardDestination::Staked)?; add_slashing_spans::(&stash, s); - let amount = T::Currency::minimum_balance() * 5u32.into(); // Half of total + let amount = asset::existential_deposit::() * 5u32.into(); // Half of total Staking::::unbond(RawOrigin::Signed(controller.clone()).into(), amount)?; CurrentEra::::put(EraIndex::max_value()); let ledger = Ledger::::get(&controller).ok_or("ledger not created before")?; @@ -312,7 +312,7 @@ benchmarks! { // clean up any existing state. clear_validators_and_nominators::(); - let origin_weight = MinNominatorBond::::get().max(T::Currency::minimum_balance()); + let origin_weight = MinNominatorBond::::get().max(asset::existential_deposit::()); // setup a worst case list scenario. Note that we don't care about the setup of the // destination position because we are doing a removal from the list but no insert. @@ -322,7 +322,7 @@ benchmarks! { add_slashing_spans::(&stash, s); assert!(T::VoterList::contains(&stash)); - let ed = T::Currency::minimum_balance(); + let ed = asset::existential_deposit::(); let mut ledger = Ledger::::get(&controller).unwrap(); ledger.active = ed - One::one(); Ledger::::insert(&controller, ledger); @@ -422,7 +422,7 @@ benchmarks! { // clean up any existing state. clear_validators_and_nominators::(); - let origin_weight = MinNominatorBond::::get().max(T::Currency::minimum_balance()); + let origin_weight = MinNominatorBond::::get().max(asset::existential_deposit::()); // setup a worst case list scenario. Note we don't care about the destination position, because // we are just doing an insert into the origin position. @@ -448,7 +448,7 @@ benchmarks! { // clean up any existing state. clear_validators_and_nominators::(); - let origin_weight = MinNominatorBond::::get().max(T::Currency::minimum_balance()); + let origin_weight = MinNominatorBond::::get().max(asset::existential_deposit::()); // setup a worst case list scenario. Note that we don't care about the setup of the // destination position because we are doing a removal from the list but no insert. @@ -564,7 +564,7 @@ benchmarks! { // Clean up any existing state. clear_validators_and_nominators::(); - let origin_weight = MinNominatorBond::::get().max(T::Currency::minimum_balance()); + let origin_weight = MinNominatorBond::::get().max(asset::existential_deposit::()); // setup a worst case list scenario. Note that we don't care about the setup of the // destination position because we are doing a removal from the list but no insert. @@ -640,7 +640,7 @@ benchmarks! { clear_validators_and_nominators::(); let origin_weight = MinNominatorBond::::get() - .max(T::Currency::minimum_balance()) + .max(asset::existential_deposit::()) // we use 100 to play friendly with the list threshold values in the mock .max(100u32.into()); @@ -686,7 +686,7 @@ benchmarks! { // clean up any existing state. clear_validators_and_nominators::(); - let origin_weight = MinNominatorBond::::get().max(T::Currency::minimum_balance()); + let origin_weight = MinNominatorBond::::get().max(asset::existential_deposit::()); // setup a worst case list scenario. Note that we don't care about the setup of the // destination position because we are doing a removal from the list but no insert. @@ -697,7 +697,7 @@ benchmarks! { add_slashing_spans::(&stash, s); let l = StakingLedger::::new( stash.clone(), - T::Currency::minimum_balance() - One::one(), + asset::existential_deposit::() - One::one(), ); Ledger::::insert(&controller, l); @@ -764,7 +764,7 @@ benchmarks! { ErasRewardPoints::::insert(current_era, reward); // Create reward pool - let total_payout = T::Currency::minimum_balance() * 1000u32.into(); + let total_payout = asset::existential_deposit::() * 1000u32.into(); >::insert(current_era, total_payout); let caller: T::AccountId = whitelisted_caller(); @@ -793,7 +793,7 @@ benchmarks! { staking_ledger.unlocking.try_push(unlock_chunk.clone()).unwrap(); } Ledger::::insert(controller, staking_ledger); - let slash_amount = T::Currency::minimum_balance() * 10u32.into(); + let slash_amount = asset::existential_deposit::() * 10u32.into(); let balance_before = T::Currency::free_balance(&stash); }: { crate::slashing::do_slash::( @@ -890,7 +890,7 @@ benchmarks! { // clean up any existing state. clear_validators_and_nominators::(); - let origin_weight = MinNominatorBond::::get().max(T::Currency::minimum_balance()); + let origin_weight = MinNominatorBond::::get().max(asset::existential_deposit::()); // setup a worst case list scenario. Note that we don't care about the setup of the // destination position because we are doing a removal from the list but no insert. diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index e28ac763b159..9ca59616b64d 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -173,7 +173,7 @@ impl Pallet { ledger.total = ledger.total.checked_add(&extra).ok_or(ArithmeticError::Overflow)?; ledger.active = ledger.active.checked_add(&extra).ok_or(ArithmeticError::Overflow)?; // last check: the new active amount of ledger must be more than ED. - ensure!(ledger.active >= T::Currency::minimum_balance(), Error::::InsufficientBond); + ensure!(ledger.active >= asset::existential_deposit::(), Error::::InsufficientBond); // NOTE: ledger must be updated prior to calling `Self::weight_of`. ledger.update()?; @@ -198,7 +198,7 @@ impl Pallet { } let new_total = ledger.total; - let ed = T::Currency::minimum_balance(); + let ed = asset::existential_deposit::(); let used_weight = if ledger.unlocking.is_empty() && (ledger.active < ed || ledger.active.is_zero()) { // This account must have called `unbond()` with some value that caused the active diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 5699df162603..39379c225c48 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -1023,7 +1023,7 @@ pub mod pallet { } // Reject a bond which is considered to be _dust_. - if value < T::Currency::minimum_balance() { + if value < asset::existential_deposit::() { return Err(Error::::InsufficientBond.into()) } @@ -1067,7 +1067,7 @@ pub mod pallet { /// Schedule a portion of the stash to be unlocked ready for transfer out after the bond /// period ends. If this leaves an amount actively bonded less than - /// T::Currency::minimum_balance(), then it is increased to the full amount. + /// asset::existential_deposit::(), then it is increased to the full amount. /// /// The dispatch origin for this call must be _Signed_ by the controller, not the stash. /// @@ -1123,7 +1123,7 @@ pub mod pallet { ledger.active -= value; // Avoid there being a dust balance left in the staking system. - if ledger.active < T::Currency::minimum_balance() { + if ledger.active < asset::existential_deposit::() { value += ledger.active; ledger.active = Zero::zero(); } @@ -1653,7 +1653,7 @@ pub mod pallet { let initial_unlocking = ledger.unlocking.len() as u32; let (ledger, rebonded_value) = ledger.rebond(value); // Last check: the new active amount of ledger must be more than ED. - ensure!(ledger.active >= T::Currency::minimum_balance(), Error::::InsufficientBond); + ensure!(ledger.active >= asset::existential_deposit::(), Error::::InsufficientBond); Self::deposit_event(Event::::Bonded { stash: ledger.stash.clone(), @@ -1705,7 +1705,7 @@ pub mod pallet { // virtual stakers should not be allowed to be reaped. ensure!(!Self::is_virtual_staker(&stash), Error::::VirtualStakerNotAllowed); - let ed = T::Currency::minimum_balance(); + let ed = asset::existential_deposit::(); let origin_balance = T::Currency::total_balance(&stash); let ledger_total = Self::ledger(Stash(stash.clone())).map(|l| l.total).unwrap_or_default(); diff --git a/substrate/frame/staking/src/slashing.rs b/substrate/frame/staking/src/slashing.rs index 9bc8197c50b3..445980494ad1 100644 --- a/substrate/frame/staking/src/slashing.rs +++ b/substrate/frame/staking/src/slashing.rs @@ -50,7 +50,7 @@ //! Based on research at use crate::{ - BalanceOf, Config, DisabledValidators, DisablingStrategy, Error, Exposure, NegativeImbalanceOf, + asset, BalanceOf, Config, DisabledValidators, DisablingStrategy, Error, Exposure, NegativeImbalanceOf, NominatorSlashInEra, Pallet, Perbill, SessionInterface, SpanSlash, UnappliedSlash, ValidatorSlashInEra, }; @@ -578,7 +578,7 @@ pub fn do_slash( Err(_) => return, // nothing to do. }; - let value = ledger.slash(value, T::Currency::minimum_balance(), slash_era); + let value = ledger.slash(value, asset::existential_deposit::(), slash_era); if value.is_zero() { // nothing to do return diff --git a/substrate/frame/staking/src/testing_utils.rs b/substrate/frame/staking/src/testing_utils.rs index 65aaa5f09de4..f50c21bd61a4 100644 --- a/substrate/frame/staking/src/testing_utils.rs +++ b/substrate/frame/staking/src/testing_utils.rs @@ -53,7 +53,7 @@ pub fn create_funded_user( balance_factor: u32, ) -> T::AccountId { let user = account(string, n, SEED); - let balance = T::Currency::minimum_balance() * balance_factor.into(); + let balance = asset::existential_deposit::() * balance_factor.into(); let _ = T::Currency::make_free_balance_be(&user, balance); user } @@ -77,7 +77,7 @@ pub fn create_stash_controller( ) -> Result<(T::AccountId, T::AccountId), &'static str> { let staker = create_funded_user::("stash", n, balance_factor); let amount = - T::Currency::minimum_balance().max(1u64.into()) * (balance_factor / 10).max(1).into(); + asset::existential_deposit::().max(1u64.into()) * (balance_factor / 10).max(1).into(); Staking::::bond(RawOrigin::Signed(staker.clone()).into(), amount, destination)?; Ok((staker.clone(), staker)) } @@ -96,7 +96,7 @@ pub fn create_unique_stash_controller( } else { create_funded_user::("controller", n, balance_factor) }; - let amount = T::Currency::minimum_balance() * (balance_factor / 10).max(1).into(); + let amount = asset::existential_deposit::() * (balance_factor / 10).max(1).into(); Staking::::bond(RawOrigin::Signed(stash.clone()).into(), amount, destination)?; // update ledger to be a *different* controller to stash @@ -129,7 +129,7 @@ pub fn create_stash_and_dead_payee( let staker = create_funded_user::("stash", n, 0); // payee has no funds let payee = create_funded_user::("payee", n, 0); - let amount = T::Currency::minimum_balance() * (balance_factor / 10).max(1).into(); + let amount = asset::existential_deposit::() * (balance_factor / 10).max(1).into(); Staking::::bond( RawOrigin::Signed(staker.clone()).into(), amount, From babc205cf923274100f2e3926178e2c4b20610b2 Mon Sep 17 00:00:00 2001 From: Ankan Date: Sun, 18 Aug 2024 20:12:07 +0200 Subject: [PATCH 003/142] replace ti, burn, and set balance calls --- substrate/frame/staking/src/asset.rs | 12 ++++++++++++ substrate/frame/staking/src/benchmarking.rs | 8 ++++---- substrate/frame/staking/src/pallet/impls.rs | 10 +++++----- substrate/frame/staking/src/testing_utils.rs | 4 ++-- 4 files changed, 23 insertions(+), 11 deletions(-) diff --git a/substrate/frame/staking/src/asset.rs b/substrate/frame/staking/src/asset.rs index df072e5b4b2d..105b6437360e 100644 --- a/substrate/frame/staking/src/asset.rs +++ b/substrate/frame/staking/src/asset.rs @@ -19,4 +19,16 @@ pub fn staked(who: &T::AccountId) -> BalanceOf { /// Existential deposit for the chain. pub fn existential_deposit() -> BalanceOf { T::Currency::minimum_balance() +} + +pub fn burn(amount: BalanceOf) { + T::Currency::burn(amount); +} + +pub fn total_issuance() -> BalanceOf { + T::Currency::total_issuance() +} + +pub fn set_balance(who: &T::AccountId, value: BalanceOf) { + T::Currency::make_free_balance_be(who, value); } \ No newline at end of file diff --git a/substrate/frame/staking/src/benchmarking.rs b/substrate/frame/staking/src/benchmarking.rs index 6dfbe0c077ec..4f70a87c177b 100644 --- a/substrate/frame/staking/src/benchmarking.rs +++ b/substrate/frame/staking/src/benchmarking.rs @@ -18,7 +18,7 @@ //! Staking pallet benchmarking. use super::*; -use crate::{ConfigOp, Pallet as Staking}; +use crate::{asset, ConfigOp, Pallet as Staking}; use testing_utils::*; use codec::Decode; @@ -167,7 +167,7 @@ impl ListScenario { ensure!(!origin_weight.is_zero(), "origin weight must be greater than 0"); // burn the entire issuance. - let i = T::Currency::burn(T::Currency::total_issuance()); + let i = asset::burn::(asset::total_issuance::()); core::mem::forget(i); // create accounts with the origin weight @@ -197,7 +197,7 @@ impl ListScenario { let dest_weight_as_vote = T::VoterList::score_update_worst_case(&origin_stash1, is_increase); - let total_issuance = T::Currency::total_issuance(); + let total_issuance = asset::total_issuance::(); let dest_weight = T::CurrencyToVote::to_currency(dest_weight_as_vote as u128, total_issuance); @@ -264,7 +264,7 @@ benchmarks! { clear_validators_and_nominators::(); // setup the worst case list scenario. - let total_issuance = T::Currency::total_issuance(); + let total_issuance = asset::total_issuance::(); // the weight the nominator will start at. The value used here is expected to be // significantly higher than the first position in a list (e.g. the first bag threshold). let origin_weight = BalanceOf::::try_from(952_994_955_240_703u128) diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index 9ca59616b64d..173ffedd547f 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -142,7 +142,7 @@ impl Pallet { pub fn weight_of_fn() -> Box VoteWeight> { // NOTE: changing this to unboxed `impl Fn(..)` return type and the pallet will still // compile, while some types in mock fail to resolve. - let issuance = T::Currency::total_issuance(); + let issuance = asset::total_issuance::(); Box::new(move |who: &T::AccountId| -> VoteWeight { Self::slashable_balance_of_vote_weight(who, issuance) }) @@ -150,7 +150,7 @@ impl Pallet { /// Same as `weight_of_fn`, but made for one time use. pub fn weight_of(who: &T::AccountId) -> VoteWeight { - let issuance = T::Currency::total_issuance(); + let issuance = asset::total_issuance::(); Self::slashable_balance_of_vote_weight(who, issuance) } @@ -576,7 +576,7 @@ impl Pallet { let era_duration = (now_as_millis_u64.defensive_saturating_sub(active_era_start)) .saturated_into::(); let staked = Self::eras_total_stake(&active_era.index); - let issuance = T::Currency::total_issuance(); + let issuance = asset::total_issuance::(); let (validator_payout, remainder) = T::EraPayout::era_payout(staked, issuance, era_duration); @@ -748,7 +748,7 @@ impl Pallet { fn collect_exposures( supports: BoundedSupportsOf, ) -> BoundedVec<(T::AccountId, Exposure>), MaxWinnersOf> { - let total_issuance = T::Currency::total_issuance(); + let total_issuance = asset::total_issuance::(); let to_currency = |e: frame_election_provider_support::ExtendedBalance| { T::CurrencyToVote::to_currency(e, total_issuance) }; @@ -1581,7 +1581,7 @@ impl ScoreProvider for Pallet { // also, we play a trick to make sure that a issuance based-`CurrencyToVote` behaves well: // This will make sure that total issuance is zero, thus the currency to vote will be a 1-1 // conversion. - let imbalance = T::Currency::burn(T::Currency::total_issuance()); + let imbalance = asset::burn::(asset::total_issuance::()); // kinda ugly, but gets the job done. The fact that this works here is a HUGE exception. // Don't try this pattern in other places. core::mem::forget(imbalance); diff --git a/substrate/frame/staking/src/testing_utils.rs b/substrate/frame/staking/src/testing_utils.rs index f50c21bd61a4..fb6f682c9320 100644 --- a/substrate/frame/staking/src/testing_utils.rs +++ b/substrate/frame/staking/src/testing_utils.rs @@ -54,7 +54,7 @@ pub fn create_funded_user( ) -> T::AccountId { let user = account(string, n, SEED); let balance = asset::existential_deposit::() * balance_factor.into(); - let _ = T::Currency::make_free_balance_be(&user, balance); + let _ = asset::set_balance::(&user, balance); user } @@ -65,7 +65,7 @@ pub fn create_funded_user_with_balance( balance: BalanceOf, ) -> T::AccountId { let user = account(string, n, SEED); - let _ = T::Currency::make_free_balance_be(&user, balance); + let _ = asset::set_balance::(&user, balance); user } From 2f0cd28a24591d7d6c879afb6ef498686b585235 Mon Sep 17 00:00:00 2001 From: Ankan Date: Sun, 18 Aug 2024 20:20:33 +0200 Subject: [PATCH 004/142] add read balance and update lock fn to asset --- substrate/frame/staking/src/asset.rs | 27 ++++++++++++++++++++--- substrate/frame/staking/src/pallet/mod.rs | 5 ++++- substrate/frame/staking/src/slashing.rs | 6 ++--- 3 files changed, 31 insertions(+), 7 deletions(-) diff --git a/substrate/frame/staking/src/asset.rs b/substrate/frame/staking/src/asset.rs index 105b6437360e..37a1696d77bf 100644 --- a/substrate/frame/staking/src/asset.rs +++ b/substrate/frame/staking/src/asset.rs @@ -2,7 +2,7 @@ use frame_support::{ defensive, ensure, - traits::{Defensive, InspectLockableCurrency, LockableCurrency, Currency}, + traits::{Currency, Defensive, InspectLockableCurrency, LockableCurrency}, }; use sp_staking::{StakingAccount, StakingInterface}; @@ -18,7 +18,7 @@ pub fn staked(who: &T::AccountId) -> BalanceOf { /// Existential deposit for the chain. pub fn existential_deposit() -> BalanceOf { - T::Currency::minimum_balance() + T::Currency::minimum_balance() } pub fn burn(amount: BalanceOf) { @@ -31,4 +31,25 @@ pub fn total_issuance() -> BalanceOf { pub fn set_balance(who: &T::AccountId, value: BalanceOf) { T::Currency::make_free_balance_be(who, value); -} \ No newline at end of file +} + +pub fn free_balance(who: &T::AccountId) -> BalanceOf { + T::Currency::free_balance(who) +} + +pub fn total_balance(who: &T::AccountId) -> BalanceOf { + T::Currency::total_balance(who) +} + +pub fn deposit(who: &T::AccountId, value: BalanceOf) { + // FIXME(ank4n) return val? + let _ = T::Currency::deposit_into_existing(who, value); +} + +pub fn update_stake(who: &T::AccountId, amount: BalanceOf) { + T::Currency::set_lock(id, who, amount, frame_support::traits::WithdrawReasons::all()); +} + +pub fn kill_stake(who: &T::AccountId) { + T::Currency::remove_lock(id, who); +} diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 39379c225c48..34154a615d4e 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -1653,7 +1653,10 @@ pub mod pallet { let initial_unlocking = ledger.unlocking.len() as u32; let (ledger, rebonded_value) = ledger.rebond(value); // Last check: the new active amount of ledger must be more than ED. - ensure!(ledger.active >= asset::existential_deposit::(), Error::::InsufficientBond); + ensure!( + ledger.active >= asset::existential_deposit::(), + Error::::InsufficientBond + ); Self::deposit_event(Event::::Bonded { stash: ledger.stash.clone(), diff --git a/substrate/frame/staking/src/slashing.rs b/substrate/frame/staking/src/slashing.rs index 445980494ad1..d9d0695b11d2 100644 --- a/substrate/frame/staking/src/slashing.rs +++ b/substrate/frame/staking/src/slashing.rs @@ -50,9 +50,9 @@ //! Based on research at use crate::{ - asset, BalanceOf, Config, DisabledValidators, DisablingStrategy, Error, Exposure, NegativeImbalanceOf, - NominatorSlashInEra, Pallet, Perbill, SessionInterface, SpanSlash, UnappliedSlash, - ValidatorSlashInEra, + asset, BalanceOf, Config, DisabledValidators, DisablingStrategy, Error, Exposure, + NegativeImbalanceOf, NominatorSlashInEra, Pallet, Perbill, SessionInterface, SpanSlash, + UnappliedSlash, ValidatorSlashInEra, }; use alloc::vec::Vec; use codec::{Decode, Encode, MaxEncodedLen}; From 4af4aee9066263789ec23e10a3ac3fd5bc7a6345 Mon Sep 17 00:00:00 2001 From: Ankan Date: Sun, 18 Aug 2024 20:34:27 +0200 Subject: [PATCH 005/142] replace all currency call with existing asset fn --- substrate/frame/staking/src/asset.rs | 19 ++++++++++------ substrate/frame/staking/src/benchmarking.rs | 14 ++++++------ substrate/frame/staking/src/ledger.rs | 13 ++++------- substrate/frame/staking/src/pallet/impls.rs | 15 +++++-------- substrate/frame/staking/src/pallet/mod.rs | 24 ++++++--------------- 5 files changed, 35 insertions(+), 50 deletions(-) diff --git a/substrate/frame/staking/src/asset.rs b/substrate/frame/staking/src/asset.rs index 37a1696d77bf..ad9fd02ee012 100644 --- a/substrate/frame/staking/src/asset.rs +++ b/substrate/frame/staking/src/asset.rs @@ -7,8 +7,8 @@ use frame_support::{ use sp_staking::{StakingAccount, StakingInterface}; use crate::{ - BalanceOf, Bonded, Config, Error, Ledger, Pallet, Payee, RewardDestination, StakingLedger, - VirtualStakers, STAKING_ID, + BalanceOf, Bonded, Config, Error, Ledger, Pallet, Payee, PositiveImbalanceOf, + RewardDestination, StakingLedger, VirtualStakers, STAKING_ID, }; /// Balance that is staked and at stake. @@ -41,15 +41,20 @@ pub fn total_balance(who: &T::AccountId) -> BalanceOf { T::Currency::total_balance(who) } -pub fn deposit(who: &T::AccountId, value: BalanceOf) { - // FIXME(ank4n) return val? - let _ = T::Currency::deposit_into_existing(who, value); +/// Mint reward. +pub fn mint(who: &T::AccountId, value: BalanceOf) -> Option> { + T::Currency::deposit_into_existing(who, value).ok() } pub fn update_stake(who: &T::AccountId, amount: BalanceOf) { - T::Currency::set_lock(id, who, amount, frame_support::traits::WithdrawReasons::all()); + T::Currency::set_lock( + crate::STAKING_ID, + who, + amount, + frame_support::traits::WithdrawReasons::all(), + ); } pub fn kill_stake(who: &T::AccountId) { - T::Currency::remove_lock(id, who); + T::Currency::remove_lock(crate::STAKING_ID, who); } diff --git a/substrate/frame/staking/src/benchmarking.rs b/substrate/frame/staking/src/benchmarking.rs index 4f70a87c177b..07c9566cc1d6 100644 --- a/substrate/frame/staking/src/benchmarking.rs +++ b/substrate/frame/staking/src/benchmarking.rs @@ -249,7 +249,7 @@ benchmarks! { let original_bonded: BalanceOf = Ledger::::get(&controller).map(|l| l.active).ok_or("ledger not created after")?; - let _ = T::Currency::deposit_into_existing(&stash, max_additional).unwrap(); + let _ = asset::mint::(&stash, max_additional).unwrap(); whitelist_account!(stash); }: _(RawOrigin::Signed(stash), max_additional) @@ -611,21 +611,21 @@ benchmarks! { >::insert(current_era, validator.clone(), >::validators(&validator)); let caller = whitelisted_caller(); - let balance_before = T::Currency::free_balance(&validator); + let balance_before = asset::free_balance::(&validator); let mut nominator_balances_before = Vec::new(); for (stash, _) in &nominators { - let balance = T::Currency::free_balance(stash); + let balance = asset::free_balance::(stash); nominator_balances_before.push(balance); } }: payout_stakers(RawOrigin::Signed(caller), validator.clone(), current_era) verify { - let balance_after = T::Currency::free_balance(&validator); + let balance_after = asset::free_balance::(&validator); ensure!( balance_before < balance_after, "Balance of validator stash should have increased after payout.", ); for ((stash, _), balance_before) in nominators.iter().zip(nominator_balances_before.iter()) { - let balance_after = T::Currency::free_balance(stash); + let balance_after = asset::free_balance::(stash); ensure!( balance_before < &balance_after, "Balance of nominator stash should have increased after payout.", @@ -794,7 +794,7 @@ benchmarks! { } Ledger::::insert(controller, staking_ledger); let slash_amount = asset::existential_deposit::() * 10u32.into(); - let balance_before = T::Currency::free_balance(&stash); + let balance_before = asset::free_balance::(&stash); }: { crate::slashing::do_slash::( &stash, @@ -804,7 +804,7 @@ benchmarks! { EraIndex::zero() ); } verify { - let balance_after = T::Currency::free_balance(&stash); + let balance_after = asset::free_balance::(&stash); assert!(balance_before > balance_after); } diff --git a/substrate/frame/staking/src/ledger.rs b/substrate/frame/staking/src/ledger.rs index dc4b4fc326b8..8a8c41ec0878 100644 --- a/substrate/frame/staking/src/ledger.rs +++ b/substrate/frame/staking/src/ledger.rs @@ -38,8 +38,8 @@ use frame_support::{ use sp_staking::{StakingAccount, StakingInterface}; use crate::{ - BalanceOf, Bonded, Config, Error, Ledger, Pallet, Payee, RewardDestination, StakingLedger, - VirtualStakers, STAKING_ID, + asset, BalanceOf, Bonded, Config, Error, Ledger, Pallet, Payee, RewardDestination, + StakingLedger, VirtualStakers, STAKING_ID, }; #[cfg(any(feature = "runtime-benchmarks", test))] @@ -190,12 +190,7 @@ impl StakingLedger { // We skip locking virtual stakers. if !Pallet::::is_virtual_staker(&self.stash) { // for direct stakers, update lock on stash based on ledger. - T::Currency::set_lock( - STAKING_ID, - &self.stash, - self.total, - frame_support::traits::WithdrawReasons::all(), - ); + asset::update_stake::(&self.stash, self.total); } Ledger::::insert( @@ -269,7 +264,7 @@ impl StakingLedger { // kill virtual staker if it exists. if >::take(&stash).is_none() { // if not virtual staker, clear locks. - T::Currency::remove_lock(STAKING_ID, &ledger.stash); + asset::kill_stake::(&ledger.stash); } Ok(()) diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index 173ffedd547f..71c3db696b05 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -164,7 +164,7 @@ impl Pallet { } else { // additional amount or actual balance of stash whichever is lower. additional.min( - T::Currency::free_balance(stash) + asset::free_balance::(stash) .checked_sub(&ledger.total) .ok_or(ArithmeticError::Overflow)?, ) @@ -414,12 +414,12 @@ impl Pallet { let dest = Self::payee(StakingAccount::Stash(stash.clone()))?; let maybe_imbalance = match dest { - RewardDestination::Stash => T::Currency::deposit_into_existing(stash, amount).ok(), + RewardDestination::Stash => asset::mint::(stash, amount), RewardDestination::Staked => Self::ledger(Stash(stash.clone())) .and_then(|mut ledger| { ledger.active += amount; ledger.total += amount; - let r = T::Currency::deposit_into_existing(stash, amount).ok(); + let r = asset::mint::(stash, amount); let _ = ledger .update() @@ -1919,7 +1919,7 @@ impl StakingInterface for Pallet { impl sp_staking::StakingUnchecked for Pallet { fn migrate_to_virtual_staker(who: &Self::AccountId) { - T::Currency::remove_lock(crate::STAKING_ID, who); + asset::kill_stake::(who); VirtualStakers::::insert(who, ()); } @@ -1956,12 +1956,7 @@ impl sp_staking::StakingUnchecked for Pallet { fn migrate_to_direct_staker(who: &Self::AccountId) { assert!(VirtualStakers::::contains_key(who)); let ledger = StakingLedger::::get(Stash(who.clone())).unwrap(); - T::Currency::set_lock( - crate::STAKING_ID, - who, - ledger.total, - frame_support::traits::WithdrawReasons::all(), - ); + asset::update_stake::(who, ledger.total); VirtualStakers::::remove(who); } } diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 34154a615d4e..ee84bae2047f 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -779,7 +779,7 @@ pub mod pallet { status ); assert!( - T::Currency::free_balance(stash) >= balance, + asset::free_balance::(stash) >= balance, "Stash does not have enough balance to bond." ); frame_support::assert_ok!(>::bond( @@ -1029,7 +1029,7 @@ pub mod pallet { frame_system::Pallet::::inc_consumers(&stash).map_err(|_| Error::::BadState)?; - let stash_balance = T::Currency::free_balance(&stash); + let stash_balance = asset::free_balance::(&stash); let value = value.min(stash_balance); Self::deposit_event(Event::::Bonded { stash: stash.clone(), amount: value }); let ledger = StakingLedger::::new(stash.clone(), value); @@ -1709,7 +1709,7 @@ pub mod pallet { ensure!(!Self::is_virtual_staker(&stash), Error::::VirtualStakerNotAllowed); let ed = asset::existential_deposit::(); - let origin_balance = T::Currency::total_balance(&stash); + let origin_balance = asset::total_balance::(&stash); let ledger_total = Self::ledger(Stash(stash.clone())).map(|l| l.total).unwrap_or_default(); let reapable = origin_balance < ed || @@ -2077,7 +2077,7 @@ pub mod pallet { ensure!(!Self::is_virtual_staker(&stash), Error::::VirtualStakerNotAllowed); let current_lock = asset::staked::(&stash); - let stash_balance = T::Currency::free_balance(&stash); + let stash_balance = asset::free_balance::(&stash); let (new_controller, new_total) = match Self::inspect_bond_state(&stash) { Ok(LedgerIntegrityState::Corrupted) => { @@ -2086,12 +2086,7 @@ pub mod pallet { 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, - WithdrawReasons::all(), - ); + asset::update_stake::(&stash, new_total); new_total } else { current_lock @@ -2118,18 +2113,13 @@ pub mod pallet { // to enforce a new ledger.total and staking lock for this stash. let new_total = maybe_total.ok_or(Error::::CannotRestoreLedger)?.min(stash_balance); - T::Currency::set_lock( - crate::STAKING_ID, - &stash, - new_total, - WithdrawReasons::all(), - ); + asset::update_stake::(&stash, new_total); 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); + asset::kill_stake::(&stash); ensure!( Self::inspect_bond_state(&stash) == Err(Error::::NotStash), Error::::BadState From 1995e060a5fa942017131c125c92e56d9691a397 Mon Sep 17 00:00:00 2001 From: Ankan Date: Sun, 18 Aug 2024 20:52:43 +0200 Subject: [PATCH 006/142] add remaining currency fn --- substrate/frame/staking/src/asset.rs | 50 +++++++++++++++------ substrate/frame/staking/src/benchmarking.rs | 2 +- substrate/frame/staking/src/pallet/impls.rs | 8 ++-- 3 files changed, 41 insertions(+), 19 deletions(-) diff --git a/substrate/frame/staking/src/asset.rs b/substrate/frame/staking/src/asset.rs index ad9fd02ee012..e314e2efe3c2 100644 --- a/substrate/frame/staking/src/asset.rs +++ b/substrate/frame/staking/src/asset.rs @@ -7,24 +7,15 @@ use frame_support::{ use sp_staking::{StakingAccount, StakingInterface}; use crate::{ - BalanceOf, Bonded, Config, Error, Ledger, Pallet, Payee, PositiveImbalanceOf, - RewardDestination, StakingLedger, VirtualStakers, STAKING_ID, + BalanceOf, Bonded, Config, Error, Ledger, NegativeImbalanceOf, Pallet, Payee, + PositiveImbalanceOf, RewardDestination, StakingLedger, VirtualStakers, STAKING_ID, }; -/// Balance that is staked and at stake. -pub fn staked(who: &T::AccountId) -> BalanceOf { - T::Currency::balance_locked(crate::STAKING_ID, who) -} - /// Existential deposit for the chain. pub fn existential_deposit() -> BalanceOf { T::Currency::minimum_balance() } -pub fn burn(amount: BalanceOf) { - T::Currency::burn(amount); -} - pub fn total_issuance() -> BalanceOf { T::Currency::total_issuance() } @@ -33,6 +24,10 @@ pub fn set_balance(who: &T::AccountId, value: BalanceOf) { T::Currency::make_free_balance_be(who, value); } +pub fn burn(amount: BalanceOf) { + T::Currency::burn(amount); +} + pub fn free_balance(who: &T::AccountId) -> BalanceOf { T::Currency::free_balance(who) } @@ -41,9 +36,9 @@ pub fn total_balance(who: &T::AccountId) -> BalanceOf { T::Currency::total_balance(who) } -/// Mint reward. -pub fn mint(who: &T::AccountId, value: BalanceOf) -> Option> { - T::Currency::deposit_into_existing(who, value).ok() +/// Balance that is staked and at stake. +pub fn staked(who: &T::AccountId) -> BalanceOf { + T::Currency::balance_locked(crate::STAKING_ID, who) } pub fn update_stake(who: &T::AccountId, amount: BalanceOf) { @@ -58,3 +53,30 @@ pub fn update_stake(who: &T::AccountId, amount: BalanceOf) { pub fn kill_stake(who: &T::AccountId) { T::Currency::remove_lock(crate::STAKING_ID, who); } + +pub fn slash( + who: &T::AccountId, + value: BalanceOf, +) -> (NegativeImbalanceOf, BalanceOf) { + T::Currency::slash(who, value) +} + +/// Mint reward. +pub fn mint_existing( + who: &T::AccountId, + value: BalanceOf, +) -> Option> { + T::Currency::deposit_into_existing(who, value).ok() +} + +pub fn mint_creating(who: &T::AccountId, value: BalanceOf) -> PositiveImbalanceOf { + T::Currency::deposit_creating(who, value) +} + +pub fn resolve_creating(who: &T::AccountId, value: NegativeImbalanceOf) { + T::Currency::resolve_creating(who, value) +} + +pub fn issue(value: BalanceOf) -> NegativeImbalanceOf { + T::Currency::issue(value) +} diff --git a/substrate/frame/staking/src/benchmarking.rs b/substrate/frame/staking/src/benchmarking.rs index 07c9566cc1d6..ae08f75e91db 100644 --- a/substrate/frame/staking/src/benchmarking.rs +++ b/substrate/frame/staking/src/benchmarking.rs @@ -249,7 +249,7 @@ benchmarks! { let original_bonded: BalanceOf = Ledger::::get(&controller).map(|l| l.active).ok_or("ledger not created after")?; - let _ = asset::mint::(&stash, max_additional).unwrap(); + let _ = asset::mint_existing::(&stash, max_additional).unwrap(); whitelist_account!(stash); }: _(RawOrigin::Signed(stash), max_additional) diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index 71c3db696b05..b460a0cfc8e0 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -414,12 +414,12 @@ impl Pallet { let dest = Self::payee(StakingAccount::Stash(stash.clone()))?; let maybe_imbalance = match dest { - RewardDestination::Stash => asset::mint::(stash, amount), + RewardDestination::Stash => asset::mint_existing::(stash, amount), RewardDestination::Staked => Self::ledger(Stash(stash.clone())) .and_then(|mut ledger| { ledger.active += amount; ledger.total += amount; - let r = asset::mint::(stash, amount); + let r = asset::mint_existing::(stash, amount); let _ = ledger .update() @@ -429,7 +429,7 @@ impl Pallet { }) .unwrap_or_default(), RewardDestination::Account(ref dest_account) => - Some(T::Currency::deposit_creating(&dest_account, amount)), + Some(asset::mint_creating::(&dest_account, amount)), RewardDestination::None => None, #[allow(deprecated)] RewardDestination::Controller => Self::bonded(stash) @@ -437,7 +437,7 @@ impl Pallet { defensive!("Paying out controller as reward destination which is deprecated and should be migrated."); // This should never happen once payees with a `Controller` variant have been migrated. // But if it does, just pay the controller account. - T::Currency::deposit_creating(&controller, amount) + asset::mint_creating::(&controller, amount) }), }; maybe_imbalance.map(|imbalance| (imbalance, dest)) From f3a30810033bd25e41c05e4da245ff57910b654e Mon Sep 17 00:00:00 2001 From: Ankan Date: Sun, 18 Aug 2024 21:04:03 +0200 Subject: [PATCH 007/142] all currency fn replaced --- substrate/frame/staking/src/asset.rs | 7 +++++-- substrate/frame/staking/src/pallet/impls.rs | 2 +- substrate/frame/staking/src/slashing.rs | 4 ++-- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/substrate/frame/staking/src/asset.rs b/substrate/frame/staking/src/asset.rs index e314e2efe3c2..ac28c2bd375a 100644 --- a/substrate/frame/staking/src/asset.rs +++ b/substrate/frame/staking/src/asset.rs @@ -61,7 +61,7 @@ pub fn slash( T::Currency::slash(who, value) } -/// Mint reward. +/// Mint reward into an existing account. Does not increase the total issuance. pub fn mint_existing( who: &T::AccountId, value: BalanceOf, @@ -69,14 +69,17 @@ pub fn mint_existing( T::Currency::deposit_into_existing(who, value).ok() } +/// Mint reward and create if account does not exist. Does not increase the total issuance. pub fn mint_creating(who: &T::AccountId, value: BalanceOf) -> PositiveImbalanceOf { T::Currency::deposit_creating(who, value) } -pub fn resolve_creating(who: &T::AccountId, value: NegativeImbalanceOf) { +/// Deposit to who from slashed value. +pub fn deposit_slashed(who: &T::AccountId, value: NegativeImbalanceOf) { T::Currency::resolve_creating(who, value) } +/// Increases total issuance. pub fn issue(value: BalanceOf) -> NegativeImbalanceOf { T::Currency::issue(value) } diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index b460a0cfc8e0..1c0ebdb742ea 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -597,7 +597,7 @@ impl Pallet { // Set ending era reward. >::insert(&active_era.index, validator_payout); - T::RewardRemainder::on_unbalanced(T::Currency::issue(remainder)); + T::RewardRemainder::on_unbalanced(asset::issue::(remainder)); // Clear disabled validators. >::kill(); diff --git a/substrate/frame/staking/src/slashing.rs b/substrate/frame/staking/src/slashing.rs index d9d0695b11d2..55d3fa340ac1 100644 --- a/substrate/frame/staking/src/slashing.rs +++ b/substrate/frame/staking/src/slashing.rs @@ -586,7 +586,7 @@ pub fn do_slash( // Skip slashing for virtual stakers. The pallets managing them should handle the slashing. if !Pallet::::is_virtual_staker(stash) { - let (imbalance, missing) = T::Currency::slash(stash, value); + let (imbalance, missing) = asset::slash::(stash, value); slashed_imbalance.subsume(imbalance); if !missing.is_zero() { @@ -656,7 +656,7 @@ fn pay_reporters( // this cancels out the reporter reward imbalance internally, leading // to no change in total issuance. - T::Currency::resolve_creating(reporter, reporter_reward); + asset::deposit_slashed::(reporter, reporter_reward); } // the rest goes to the on-slash imbalance handler (e.g. treasury) From 6a03abbec9e2051268adcc63e09c13927ebecd0b Mon Sep 17 00:00:00 2001 From: Ankan Date: Sun, 18 Aug 2024 22:36:40 +0200 Subject: [PATCH 008/142] fix imports --- substrate/frame/staking/src/asset.rs | 16 +++++----------- substrate/frame/staking/src/ledger.rs | 7 ++----- substrate/frame/staking/src/pallet/impls.rs | 4 ++-- substrate/frame/staking/src/pallet/mod.rs | 4 ++-- substrate/frame/staking/src/slashing.rs | 2 +- 5 files changed, 12 insertions(+), 21 deletions(-) diff --git a/substrate/frame/staking/src/asset.rs b/substrate/frame/staking/src/asset.rs index ac28c2bd375a..62e16b29ed28 100644 --- a/substrate/frame/staking/src/asset.rs +++ b/substrate/frame/staking/src/asset.rs @@ -1,15 +1,9 @@ //! Facade of currency implementation. Useful while migrating from old to new currency system. -use frame_support::{ - defensive, ensure, - traits::{Currency, Defensive, InspectLockableCurrency, LockableCurrency}, -}; -use sp_staking::{StakingAccount, StakingInterface}; +use frame_support::traits::{Currency, InspectLockableCurrency, LockableCurrency}; +use sp_staking::StakingInterface; -use crate::{ - BalanceOf, Bonded, Config, Error, Ledger, NegativeImbalanceOf, Pallet, Payee, - PositiveImbalanceOf, RewardDestination, StakingLedger, VirtualStakers, STAKING_ID, -}; +use crate::{BalanceOf, Config, NegativeImbalanceOf, PositiveImbalanceOf}; /// Existential deposit for the chain. pub fn existential_deposit() -> BalanceOf { @@ -24,8 +18,8 @@ pub fn set_balance(who: &T::AccountId, value: BalanceOf) { T::Currency::make_free_balance_be(who, value); } -pub fn burn(amount: BalanceOf) { - T::Currency::burn(amount); +pub fn burn(amount: BalanceOf) -> PositiveImbalanceOf { + T::Currency::burn(amount) } pub fn free_balance(who: &T::AccountId) -> BalanceOf { diff --git a/substrate/frame/staking/src/ledger.rs b/substrate/frame/staking/src/ledger.rs index 8a8c41ec0878..ac3be04cf607 100644 --- a/substrate/frame/staking/src/ledger.rs +++ b/substrate/frame/staking/src/ledger.rs @@ -31,15 +31,12 @@ //! performed through the methods exposed by the [`StakingLedger`] implementation in order to ensure //! state consistency. -use frame_support::{ - defensive, ensure, - traits::{Defensive, LockableCurrency}, -}; +use frame_support::{defensive, ensure, traits::Defensive}; use sp_staking::{StakingAccount, StakingInterface}; use crate::{ asset, BalanceOf, Bonded, Config, Error, Ledger, Pallet, Payee, RewardDestination, - StakingLedger, VirtualStakers, STAKING_ID, + StakingLedger, VirtualStakers, }; #[cfg(any(feature = "runtime-benchmarks", test))] diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index 1c0ebdb742ea..253c49295102 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, - InspectLockableCurrency, Len, LockableCurrency, OnUnbalanced, TryCollect, UnixTime, + Defensive, DefensiveSaturating, EstimateNextNewSession, Get, Imbalance, Len, OnUnbalanced, + TryCollect, UnixTime, }, weights::Weight, }; diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index ee84bae2047f..6908aa4efa84 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -25,8 +25,8 @@ use frame_election_provider_support::{ use frame_support::{ pallet_prelude::*, traits::{ - Currency, Defensive, DefensiveSaturating, EnsureOrigin, EstimateNextNewSession, Get, - InspectLockableCurrency, LockableCurrency, OnUnbalanced, UnixTime, WithdrawReasons, + Defensive, DefensiveSaturating, EnsureOrigin, EstimateNextNewSession, Get, + InspectLockableCurrency, LockableCurrency, OnUnbalanced, UnixTime, }, weights::Weight, BoundedVec, diff --git a/substrate/frame/staking/src/slashing.rs b/substrate/frame/staking/src/slashing.rs index 55d3fa340ac1..9fb782265b8b 100644 --- a/substrate/frame/staking/src/slashing.rs +++ b/substrate/frame/staking/src/slashing.rs @@ -58,7 +58,7 @@ use alloc::vec::Vec; use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{ ensure, - traits::{Currency, Defensive, DefensiveSaturating, Imbalance, OnUnbalanced}, + traits::{Defensive, DefensiveSaturating, Imbalance, OnUnbalanced}, }; use scale_info::TypeInfo; use sp_runtime::{ From 040c630de2fd556770995a5523627fa3c60eab63 Mon Sep 17 00:00:00 2001 From: Ankan Date: Sun, 18 Aug 2024 22:58:13 +0200 Subject: [PATCH 009/142] remove unused import --- substrate/frame/staking/src/asset.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/substrate/frame/staking/src/asset.rs b/substrate/frame/staking/src/asset.rs index 62e16b29ed28..db9fc5a5296a 100644 --- a/substrate/frame/staking/src/asset.rs +++ b/substrate/frame/staking/src/asset.rs @@ -1,7 +1,6 @@ //! Facade of currency implementation. Useful while migrating from old to new currency system. use frame_support::traits::{Currency, InspectLockableCurrency, LockableCurrency}; -use sp_staking::StakingInterface; use crate::{BalanceOf, Config, NegativeImbalanceOf, PositiveImbalanceOf}; From 61eb7b75664bb776b263ce34cd675a64e90b1f69 Mon Sep 17 00:00:00 2001 From: Ankan Date: Sun, 18 Aug 2024 23:15:57 +0200 Subject: [PATCH 010/142] fix clippy --- substrate/frame/staking/src/testing_utils.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/staking/src/testing_utils.rs b/substrate/frame/staking/src/testing_utils.rs index fb6f682c9320..1981792e981e 100644 --- a/substrate/frame/staking/src/testing_utils.rs +++ b/substrate/frame/staking/src/testing_utils.rs @@ -28,7 +28,7 @@ use rand_chacha::{ use sp_io::hashing::blake2_256; use frame_election_provider_support::SortedListProvider; -use frame_support::{pallet_prelude::*, traits::Currency}; +use frame_support::pallet_prelude::*; use sp_runtime::{traits::StaticLookup, Perbill}; const SEED: u32 = 0; From b8a0e4b88bfa89e43021b47dbb3e0c704ebd6e06 Mon Sep 17 00:00:00 2001 From: Ankan Date: Mon, 19 Aug 2024 00:00:06 +0200 Subject: [PATCH 011/142] repalce Balances api calls in test to asset as well --- substrate/frame/staking/src/benchmarking.rs | 2 +- substrate/frame/staking/src/tests.rs | 384 ++++++++++---------- 2 files changed, 197 insertions(+), 189 deletions(-) diff --git a/substrate/frame/staking/src/benchmarking.rs b/substrate/frame/staking/src/benchmarking.rs index ae08f75e91db..acbff6755cce 100644 --- a/substrate/frame/staking/src/benchmarking.rs +++ b/substrate/frame/staking/src/benchmarking.rs @@ -26,7 +26,7 @@ use frame_election_provider_support::{bounds::DataProviderBounds, SortedListProv use frame_support::{ pallet_prelude::*, storage::bounded_vec::BoundedVec, - traits::{Currency, Get, Imbalance, UnfilteredDispatchable}, + traits::{Get, Imbalance, UnfilteredDispatchable}, }; use sp_runtime::{ traits::{Bounded, One, StaticLookup, TrailingZeroInput, Zero}, diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index fe54940c437c..5ed5dfcb9618 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -229,8 +229,8 @@ fn basic_setup_works() { assert_eq!(active_era(), 0); // Account 10 has `balance_factor` free balance - assert_eq!(Balances::free_balance(10), 1); - assert_eq!(Balances::free_balance(10), 1); + assert_eq!(asset::free_balance::(&10), 1); + assert_eq!(asset::free_balance::(&10), 1); // New era is not being forced assert_eq!(Staking::force_era(), Forcing::NotForcing); @@ -311,9 +311,9 @@ fn change_controller_already_paired_once_stash() { #[test] fn rewards_should_work() { ExtBuilder::default().nominate(true).session_per_era(3).build_and_execute(|| { - let init_balance_11 = Balances::total_balance(&11); - let init_balance_21 = Balances::total_balance(&21); - let init_balance_101 = Balances::total_balance(&101); + let init_balance_11 = asset::total_balance::(&11); + let init_balance_21 = asset::total_balance::(&21); + let init_balance_101 = asset::total_balance::(&101); // Set payees Payee::::insert(11, RewardDestination::Account(11)); @@ -332,9 +332,9 @@ fn rewards_should_work() { start_session(1); assert_eq_uvec!(Session::validators(), vec![11, 21]); - assert_eq!(Balances::total_balance(&11), init_balance_11); - assert_eq!(Balances::total_balance(&21), init_balance_21); - assert_eq!(Balances::total_balance(&101), init_balance_101); + assert_eq!(asset::total_balance::(&11), init_balance_11); + assert_eq!(asset::total_balance::(&21), init_balance_21); + assert_eq!(asset::total_balance::(&101), init_balance_101); assert_eq!( Staking::eras_reward_points(active_era()), EraRewardPoints { @@ -363,17 +363,17 @@ fn rewards_should_work() { mock::make_all_reward_payment(0); assert_eq_error_rate!( - Balances::total_balance(&11), + asset::total_balance::(&11), init_balance_11 + part_for_11 * total_payout_0 * 2 / 3, 2, ); assert_eq_error_rate!( - Balances::total_balance(&21), + asset::total_balance::(&21), init_balance_21 + part_for_21 * total_payout_0 * 1 / 3, 2, ); assert_eq_error_rate!( - Balances::total_balance(&101), + asset::total_balance::(&101), init_balance_101 + part_for_101_from_11 * total_payout_0 * 2 / 3 + part_for_101_from_21 * total_payout_0 * 1 / 3, @@ -402,17 +402,17 @@ fn rewards_should_work() { mock::make_all_reward_payment(1); assert_eq_error_rate!( - Balances::total_balance(&11), + asset::total_balance::(&11), init_balance_11 + part_for_11 * (total_payout_0 * 2 / 3 + total_payout_1), 2, ); assert_eq_error_rate!( - Balances::total_balance(&21), + asset::total_balance::(&21), init_balance_21 + part_for_21 * total_payout_0 * 1 / 3, 2, ); assert_eq_error_rate!( - Balances::total_balance(&101), + asset::total_balance::(&101), init_balance_101 + part_for_101_from_11 * (total_payout_0 * 2 / 3 + total_payout_1) + part_for_101_from_21 * total_payout_0 * 1 / 3, @@ -429,7 +429,7 @@ fn staking_should_work() { // put some money in account that we'll use. for i in 1..5 { - let _ = Balances::make_free_balance_be(&i, 2000); + let _ = asset::set_balance::(&i, 2000); } // --- Block 2: @@ -611,7 +611,7 @@ fn nominating_and_rewards_should_work() { // give the man some money let initial_balance = 1000; for i in [1, 3, 5, 11, 21].iter() { - let _ = Balances::make_free_balance_be(i, initial_balance); + let _ = asset::set_balance::(&i, initial_balance); } // bond two account pairs and state interest in nomination. @@ -636,12 +636,12 @@ fn nominating_and_rewards_should_work() { assert_eq_uvec!(validator_controllers(), vec![21, 11]); // old validators must have already received some rewards. - let initial_balance_41 = Balances::total_balance(&41); - let mut initial_balance_21 = Balances::total_balance(&21); + let initial_balance_41 = asset::total_balance::(&41); + let mut initial_balance_21 = asset::total_balance::(&21); mock::make_all_reward_payment(0); - assert_eq!(Balances::total_balance(&41), initial_balance_41 + total_payout_0 / 2); - assert_eq!(Balances::total_balance(&21), initial_balance_21 + total_payout_0 / 2); - initial_balance_21 = Balances::total_balance(&21); + assert_eq!(asset::total_balance::(&41), initial_balance_41 + total_payout_0 / 2); + assert_eq!(asset::total_balance::(&21), initial_balance_21 + total_payout_0 / 2); + initial_balance_21 = asset::total_balance::(&21); assert_eq!(ErasStakersPaged::::iter_prefix_values((active_era(),)).count(), 2); assert_eq!( @@ -683,30 +683,30 @@ fn nominating_and_rewards_should_work() { // Nominator 2: has [400/1800 ~ 2/9 from 10] + [600/2200 ~ 3/11 from 21]'s reward. ==> // 2/9 + 3/11 assert_eq_error_rate!( - Balances::total_balance(&1), + asset::total_balance::(&1), initial_balance + (2 * payout_for_11 / 9 + 3 * payout_for_21 / 11), 2, ); // Nominator 3: has [400/1800 ~ 2/9 from 10] + [600/2200 ~ 3/11 from 21]'s reward. ==> // 2/9 + 3/11 - assert_eq!(Balances::total_balance(&3), initial_balance); + assert_eq!(asset::total_balance::(&3), initial_balance); // 333 is the reward destination for 3. assert_eq_error_rate!( - Balances::total_balance(&333), + asset::total_balance::(&333), 2 * payout_for_11 / 9 + 3 * payout_for_21 / 11, 2 ); // Validator 11: got 800 / 1800 external stake => 8/18 =? 4/9 => Validator's share = 5/9 assert_eq_error_rate!( - Balances::total_balance(&11), + asset::total_balance::(&11), initial_balance + 5 * payout_for_11 / 9, 2, ); // Validator 21: got 1200 / 2200 external stake => 12/22 =? 6/11 => Validator's share = // 5/11 assert_eq_error_rate!( - Balances::total_balance(&21), + asset::total_balance::(&21), initial_balance_21 + 5 * payout_for_21 / 11, 2, ); @@ -993,7 +993,7 @@ fn cannot_transfer_staked_balance() { // Confirm account 11 is stashed assert_eq!(Staking::bonded(&11), Some(11)); // Confirm account 11 has some free balance - assert_eq!(Balances::free_balance(11), 1000); + assert_eq!(asset::free_balance::(&11), 1000); // Confirm account 11 (via controller) is totally staked assert_eq!(Staking::eras_stakers(active_era(), &11).total, 1000); // Confirm account 11 cannot transfer as a result @@ -1003,7 +1003,7 @@ fn cannot_transfer_staked_balance() { ); // Give account 11 extra free balance - let _ = Balances::make_free_balance_be(&11, 10000); + let _ = asset::set_balance::(&11, 10000); // Confirm that account 11 can now transfer some balance assert_ok!(Balances::transfer_allow_death(RuntimeOrigin::signed(11), 21, 1)); }); @@ -1018,7 +1018,7 @@ fn cannot_transfer_staked_balance_2() { // Confirm account 21 is stashed assert_eq!(Staking::bonded(&21), Some(21)); // Confirm account 21 has some free balance - assert_eq!(Balances::free_balance(21), 2000); + assert_eq!(asset::free_balance::(&21), 2000); // Confirm account 21 (via controller) is totally staked assert_eq!(Staking::eras_stakers(active_era(), &21).total, 1000); // Confirm account 21 can transfer at most 1000 @@ -1037,14 +1037,14 @@ fn cannot_reserve_staked_balance() { // Confirm account 11 is stashed assert_eq!(Staking::bonded(&11), Some(11)); // Confirm account 11 has some free balance - assert_eq!(Balances::free_balance(11), 1000); + assert_eq!(asset::free_balance::(&11), 1000); // Confirm account 11 (via controller 10) is totally staked assert_eq!(Staking::eras_stakers(active_era(), &11).own, 1000); // Confirm account 11 cannot reserve as a result assert_noop!(Balances::reserve(&11, 1), BalancesError::::LiquidityRestrictions); // Give account 11 extra free balance - let _ = Balances::make_free_balance_be(&11, 10000); + let _ = asset::set_balance::(&11, 10000); // Confirm account 11 can now reserve balance assert_ok!(Balances::reserve(&11, 1)); }); @@ -1057,9 +1057,9 @@ fn reward_destination_works() { // Check that account 11 is a validator assert!(Session::validators().contains(&11)); // Check the balance of the validator account - assert_eq!(Balances::free_balance(10), 1); + assert_eq!(asset::free_balance::(&10), 1); // Check the balance of the stash account - assert_eq!(Balances::free_balance(11), 1000); + assert_eq!(asset::free_balance::(&11), 1000); // Check how much is at stake assert_eq!( Staking::ledger(11.into()).unwrap(), @@ -1082,7 +1082,7 @@ fn reward_destination_works() { // Check that RewardDestination is Staked assert_eq!(Staking::payee(11.into()), Some(RewardDestination::Staked)); // Check that reward went to the stash account of validator - assert_eq!(Balances::free_balance(11), 1000 + total_payout_0); + assert_eq!(asset::free_balance::(&11), 1000 + total_payout_0); // Check that amount at stake increased accordingly assert_eq!( Staking::ledger(11.into()).unwrap(), @@ -1111,7 +1111,7 @@ fn reward_destination_works() { // Check that RewardDestination is Stash assert_eq!(Staking::payee(11.into()), Some(RewardDestination::Stash)); // Check that reward went to the stash account - assert_eq!(Balances::free_balance(11), 1000 + total_payout_0 + total_payout_1); + assert_eq!(asset::free_balance::(&11), 1000 + total_payout_0 + total_payout_1); // Record this value let recorded_stash_balance = 1000 + total_payout_0 + total_payout_1; // Check that amount at stake is NOT increased @@ -1133,7 +1133,7 @@ fn reward_destination_works() { >::insert(&11, RewardDestination::Account(11)); // Check controller balance - assert_eq!(Balances::free_balance(11), 23150); + assert_eq!(asset::free_balance::(&11), 23150); // Compute total payout now for whole duration as other parameter won't change let total_payout_2 = current_total_payout_for_duration(reward_time_per_era()); @@ -1145,7 +1145,7 @@ fn reward_destination_works() { // Check that RewardDestination is Account(11) assert_eq!(Staking::payee(11.into()), Some(RewardDestination::Account(11))); // Check that reward went to the controller account - assert_eq!(Balances::free_balance(11), recorded_stash_balance + total_payout_2); + assert_eq!(asset::free_balance::(&11), recorded_stash_balance + total_payout_2); // Check that amount at stake is NOT increased assert_eq!( Staking::ledger(11.into()).unwrap(), @@ -1179,8 +1179,8 @@ fn validator_payment_prefs_work() { mock::start_active_era(1); mock::make_all_reward_payment(0); - let balance_era_1_11 = Balances::total_balance(&11); - let balance_era_1_101 = Balances::total_balance(&101); + let balance_era_1_11 = asset::total_balance::(&11); + let balance_era_1_101 = asset::total_balance::(&101); // Compute total payout now for whole duration as other parameter won't change let total_payout_1 = current_total_payout_for_duration(reward_time_per_era()); @@ -1194,8 +1194,16 @@ fn validator_payment_prefs_work() { let shared_cut = total_payout_1 - taken_cut; let reward_of_10 = shared_cut * exposure_1.own / exposure_1.total + taken_cut; let reward_of_100 = shared_cut * exposure_1.others[0].value / exposure_1.total; - assert_eq_error_rate!(Balances::total_balance(&11), balance_era_1_11 + reward_of_10, 2); - assert_eq_error_rate!(Balances::total_balance(&101), balance_era_1_101 + reward_of_100, 2); + assert_eq_error_rate!( + asset::total_balance::(&11), + balance_era_1_11 + reward_of_10, + 2 + ); + assert_eq_error_rate!( + asset::total_balance::(&101), + balance_era_1_101 + reward_of_100, + 2 + ); }); } @@ -1222,7 +1230,7 @@ fn bond_extra_works() { ); // Give account 11 some large free balance greater than total - let _ = Balances::make_free_balance_be(&11, 1000000); + let _ = asset::set_balance::(&11, 1000000); // Call the bond_extra function from controller, add only 100 assert_ok!(Staking::bond_extra(RuntimeOrigin::signed(11), 100)); @@ -1284,13 +1292,13 @@ fn bond_extra_and_withdraw_unbonded_works() { assert_ok!(Staking::set_payee(RuntimeOrigin::signed(11), RewardDestination::Stash)); // Give account 11 some large free balance greater than total - let _ = Balances::make_free_balance_be(&11, 1000000); + let _ = asset::set_balance::(&11, 1000000); // Initial config should be correct assert_eq!(active_era(), 0); // check the balance of a validator accounts. - assert_eq!(Balances::total_balance(&11), 1000000); + assert_eq!(asset::total_balance::(&11), 1000000); // confirm that 10 is a normal validator and gets paid at the end of the era. mock::start_active_era(1); @@ -1495,7 +1503,7 @@ fn rebond_works() { assert_ok!(Staking::set_payee(RuntimeOrigin::signed(11), RewardDestination::Stash)); // Give account 11 some large free balance greater than total - let _ = Balances::make_free_balance_be(&11, 1000000); + let _ = asset::set_balance::(&11, 1000000); // confirm that 10 is a normal validator and gets paid at the end of the era. mock::start_active_era(1); @@ -1621,7 +1629,7 @@ fn rebond_is_fifo() { assert_ok!(Staking::set_payee(RuntimeOrigin::signed(11), RewardDestination::Stash)); // Give account 11 some large free balance greater than total - let _ = Balances::make_free_balance_be(&11, 1000000); + let _ = asset::set_balance::(&11, 1000000); // confirm that 10 is a normal validator and gets paid at the end of the era. mock::start_active_era(1); @@ -1717,7 +1725,7 @@ fn rebond_emits_right_value_in_event() { assert_ok!(Staking::set_payee(RuntimeOrigin::signed(11), RewardDestination::Stash)); // Give account 11 some large free balance greater than total - let _ = Balances::make_free_balance_be(&11, 1000000); + let _ = asset::set_balance::(&11, 1000000); // confirm that 10 is a normal validator and gets paid at the end of the era. mock::start_active_era(1); @@ -1852,8 +1860,8 @@ fn reward_to_stake_works() { assert_eq!(Staking::eras_stakers(active_era(), &21).total, 2000); // Give the man some money. - let _ = Balances::make_free_balance_be(&10, 1000); - let _ = Balances::make_free_balance_be(&20, 1000); + let _ = asset::set_balance::(&10, 1000); + let _ = asset::set_balance::(&20, 1000); // Bypass logic and change current exposure EraInfo::::set_exposure(0, &21, Exposure { total: 69, own: 69, others: vec![] }); @@ -1880,7 +1888,7 @@ fn reward_to_stake_works() { assert_eq!(Staking::eras_stakers(active_era(), &11).total, 1000); assert_eq!(Staking::eras_stakers(active_era(), &21).total, 2000); - let _11_balance = Balances::free_balance(&11); + let _11_balance = asset::free_balance::(&11); assert_eq!(_11_balance, 1000 + total_payout_0 / 2); // Trigger another new era as the info are frozen before the era start. @@ -1899,7 +1907,7 @@ fn reap_stash_works() { .balance_factor(10) .build_and_execute(|| { // given - assert_eq!(Balances::balance_locked(STAKING_ID, &11), 10 * 1000); + assert_eq!(asset::staked::(&11), 10 * 1000); assert_eq!(Staking::bonded(&11), Some(11)); assert!(>::contains_key(&11)); @@ -1926,7 +1934,7 @@ fn reap_stash_works() { assert!(!>::contains_key(&11)); assert!(!>::contains_key(&11)); // lock is removed. - assert_eq!(Balances::balance_locked(STAKING_ID, &11), 0); + assert_eq!(asset::staked::(&11), 0); }); } @@ -1937,7 +1945,7 @@ fn reap_stash_works_with_existential_deposit_zero() { .balance_factor(10) .build_and_execute(|| { // given - assert_eq!(Balances::balance_locked(STAKING_ID, &11), 10 * 1000); + assert_eq!(asset::staked::(&11), 10 * 1000); assert_eq!(Staking::bonded(&11), Some(11)); assert!(>::contains_key(&11)); @@ -1964,7 +1972,7 @@ fn reap_stash_works_with_existential_deposit_zero() { assert!(!>::contains_key(&11)); assert!(!>::contains_key(&11)); // lock is removed. - assert_eq!(Balances::balance_locked(STAKING_ID, &11), 0); + assert_eq!(asset::staked::(&11), 0); }); } @@ -2111,8 +2119,8 @@ fn bond_with_little_staked_value_bounded() { // setup assert_ok!(Staking::chill(RuntimeOrigin::signed(31))); assert_ok!(Staking::set_payee(RuntimeOrigin::signed(11), RewardDestination::Stash)); - let init_balance_1 = Balances::free_balance(&1); - let init_balance_11 = Balances::free_balance(&11); + let init_balance_1 = asset::free_balance::(&1); + let init_balance_11 = asset::free_balance::(&11); // Stingy validator. assert_ok!(Staking::bond(RuntimeOrigin::signed(1), 1, RewardDestination::Account(1))); @@ -2137,12 +2145,12 @@ fn bond_with_little_staked_value_bounded() { // Old ones are rewarded. assert_eq_error_rate!( - Balances::free_balance(11), + asset::free_balance::(&11), init_balance_11 + total_payout_0 / 3, 1 ); // no rewards paid to 2. This was initial election. - assert_eq!(Balances::free_balance(1), init_balance_1); + assert_eq!(asset::free_balance::(&1), init_balance_1); // reward era 2 let total_payout_1 = current_total_payout_for_duration(reward_time_per_era()); @@ -2155,12 +2163,12 @@ fn bond_with_little_staked_value_bounded() { // 2 is now rewarded. assert_eq_error_rate!( - Balances::free_balance(1), + asset::free_balance::(&1), init_balance_1 + total_payout_1 / 3, 1 ); assert_eq_error_rate!( - Balances::free_balance(&11), + asset::free_balance::(&11), init_balance_11 + total_payout_0 / 3 + total_payout_1 / 3, 2, ); @@ -2188,7 +2196,7 @@ fn bond_with_duplicate_vote_should_be_ignored_by_election_provider() { // give the man some money. let initial_balance = 1000; for i in [1, 2, 3, 4].iter() { - let _ = Balances::make_free_balance_be(i, initial_balance); + let _ = asset::set_balance::(&i, initial_balance); } assert_ok!(Staking::bond( @@ -2241,7 +2249,7 @@ fn bond_with_duplicate_vote_should_be_ignored_by_election_provider_elected() { // give the man some money. let initial_balance = 1000; for i in [1, 2, 3, 4].iter() { - let _ = Balances::make_free_balance_be(i, initial_balance); + let _ = asset::set_balance::(&i, initial_balance); } assert_ok!(Staking::bond( @@ -2317,7 +2325,7 @@ fn reward_validator_slashing_validator_does_not_overflow() { assert!(stake.checked_mul(reward_slash).is_none()); // Set staker - let _ = Balances::make_free_balance_be(&11, stake); + let _ = asset::set_balance::(&11, stake); let exposure = Exposure:: { total: stake, own: stake, others: vec![] }; let reward = EraRewardPoints:: { @@ -2330,11 +2338,11 @@ fn reward_validator_slashing_validator_does_not_overflow() { EraInfo::::set_exposure(0, &11, exposure); ErasValidatorReward::::insert(0, stake); assert_ok!(Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, 0, 0)); - assert_eq!(Balances::total_balance(&11), stake * 2); + assert_eq!(asset::total_balance::(&11), stake * 2); // Set staker - let _ = Balances::make_free_balance_be(&11, stake); - let _ = Balances::make_free_balance_be(&2, stake); + let _ = asset::set_balance::(&11, stake); + let _ = asset::set_balance::(&2, stake); // only slashes out of bonded stake are applied. without this line, it is 0. Staking::bond(RuntimeOrigin::signed(2), stake - 1, RewardDestination::Staked).unwrap(); @@ -2358,8 +2366,8 @@ fn reward_validator_slashing_validator_does_not_overflow() { &[Perbill::from_percent(100)], ); - assert_eq!(Balances::total_balance(&11), stake - 1); - assert_eq!(Balances::total_balance(&2), 1); + assert_eq!(asset::total_balance::(&11), stake - 1); + assert_eq!(asset::total_balance::(&2), 1); }) } @@ -2526,7 +2534,7 @@ fn slashing_performed_according_exposure() { ); // The stash account should be slashed for 250 (50% of 500). - assert_eq!(Balances::free_balance(11), 1000 - 250); + assert_eq!(asset::free_balance::(&11), 1000 - 250); }); } @@ -2619,8 +2627,8 @@ fn reporters_receive_their_slice() { // 50% * (10% * initial_balance / 2) let reward = (initial_balance / 20) / 2; let reward_each = reward / 2; // split into two pieces. - assert_eq!(Balances::free_balance(1), 10 + reward_each); - assert_eq!(Balances::free_balance(2), 20 + reward_each); + assert_eq!(asset::free_balance::(&1), 10 + reward_each); + assert_eq!(asset::free_balance::(&2), 20 + reward_each); }); } @@ -2645,7 +2653,7 @@ fn subsequent_reports_in_same_span_pay_out_less() { // F1 * (reward_proportion * slash - 0) // 50% * (10% * initial_balance * 20%) let reward = (initial_balance / 5) / 20; - assert_eq!(Balances::free_balance(1), 10 + reward); + assert_eq!(asset::free_balance::(&1), 10 + reward); on_offence_now( &[OffenceDetails { @@ -2660,7 +2668,7 @@ fn subsequent_reports_in_same_span_pay_out_less() { // F1 * (reward_proportion * slash - prior_payout) // 50% * (10% * (initial_balance / 2) - prior_payout) let reward = ((initial_balance / 20) - prior_payout) / 2; - assert_eq!(Balances::free_balance(1), 10 + prior_payout + reward); + assert_eq!(asset::free_balance::(&1), 10 + prior_payout + reward); }); } @@ -2668,14 +2676,14 @@ fn subsequent_reports_in_same_span_pay_out_less() { fn invulnerables_are_not_slashed() { // For invulnerable validators no slashing is performed. ExtBuilder::default().invulnerables(vec![11]).build_and_execute(|| { - assert_eq!(Balances::free_balance(11), 1000); - assert_eq!(Balances::free_balance(21), 2000); + assert_eq!(asset::free_balance::(&11), 1000); + assert_eq!(asset::free_balance::(&21), 2000); let exposure = Staking::eras_stakers(active_era(), &21); let initial_balance = Staking::slashable_balance_of(&21); let nominator_balances: Vec<_> = - exposure.others.iter().map(|o| Balances::free_balance(&o.who)).collect(); + exposure.others.iter().map(|o| asset::free_balance::(&o.who)).collect(); on_offence_now( &[ @@ -2692,14 +2700,14 @@ fn invulnerables_are_not_slashed() { ); // The validator 11 hasn't been slashed, but 21 has been. - assert_eq!(Balances::free_balance(11), 1000); + assert_eq!(asset::free_balance::(&11), 1000); // 2000 - (0.2 * initial_balance) - assert_eq!(Balances::free_balance(21), 2000 - (2 * initial_balance / 10)); + assert_eq!(asset::free_balance::(&21), 2000 - (2 * initial_balance / 10)); // ensure that nominators were slashed as well. for (initial_balance, other) in nominator_balances.into_iter().zip(exposure.others) { assert_eq!( - Balances::free_balance(&other.who), + asset::free_balance::(&other.who), initial_balance - (2 * other.value / 10), ); } @@ -2710,7 +2718,7 @@ fn invulnerables_are_not_slashed() { fn dont_slash_if_fraction_is_zero() { // Don't slash if the fraction is zero. ExtBuilder::default().build_and_execute(|| { - assert_eq!(Balances::free_balance(11), 1000); + assert_eq!(asset::free_balance::(&11), 1000); on_offence_now( &[OffenceDetails { @@ -2721,7 +2729,7 @@ fn dont_slash_if_fraction_is_zero() { ); // The validator hasn't been slashed. The new era is not forced. - assert_eq!(Balances::free_balance(11), 1000); + assert_eq!(asset::free_balance::(&11), 1000); assert_eq!(Staking::force_era(), Forcing::NotForcing); }); } @@ -2731,7 +2739,7 @@ fn only_slash_for_max_in_era() { // multiple slashes within one era are only applied if it is more than any previous slash in the // same era. ExtBuilder::default().build_and_execute(|| { - assert_eq!(Balances::free_balance(11), 1000); + assert_eq!(asset::free_balance::(&11), 1000); on_offence_now( &[OffenceDetails { @@ -2742,7 +2750,7 @@ fn only_slash_for_max_in_era() { ); // The validator has been slashed and has been force-chilled. - assert_eq!(Balances::free_balance(11), 500); + assert_eq!(asset::free_balance::(&11), 500); assert_eq!(Staking::force_era(), Forcing::NotForcing); on_offence_now( @@ -2754,7 +2762,7 @@ fn only_slash_for_max_in_era() { ); // The validator has not been slashed additionally. - assert_eq!(Balances::free_balance(11), 500); + assert_eq!(asset::free_balance::(&11), 500); on_offence_now( &[OffenceDetails { @@ -2765,7 +2773,7 @@ fn only_slash_for_max_in_era() { ); // The validator got slashed 10% more. - assert_eq!(Balances::free_balance(11), 400); + assert_eq!(asset::free_balance::(&11), 400); }) } @@ -2776,7 +2784,7 @@ fn garbage_collection_after_slashing() { .existential_deposit(2) .balance_factor(2) .build_and_execute(|| { - assert_eq!(Balances::free_balance(11), 2000); + assert_eq!(asset::free_balance::(&11), 2000); on_offence_now( &[OffenceDetails { @@ -2786,7 +2794,7 @@ fn garbage_collection_after_slashing() { &[Perbill::from_percent(10)], ); - assert_eq!(Balances::free_balance(11), 2000 - 200); + assert_eq!(asset::free_balance::(&11), 2000 - 200); assert!(SlashingSpans::::get(&11).is_some()); assert_eq!(SpanSlash::::get(&(11, 0)).amount(), &200); @@ -2801,8 +2809,8 @@ fn garbage_collection_after_slashing() { // validator and nominator slash in era are garbage-collected by era change, // so we don't test those here. - assert_eq!(Balances::free_balance(11), 2); - assert_eq!(Balances::total_balance(&11), 2); + assert_eq!(asset::free_balance::(&11), 2); + assert_eq!(asset::total_balance::(&11), 2); let slashing_spans = SlashingSpans::::get(&11).unwrap(); assert_eq!(slashing_spans.iter().count(), 2); @@ -2826,11 +2834,11 @@ fn garbage_collection_on_window_pruning() { ExtBuilder::default().build_and_execute(|| { mock::start_active_era(1); - assert_eq!(Balances::free_balance(11), 1000); + assert_eq!(asset::free_balance::(&11), 1000); let now = active_era(); let exposure = Staking::eras_stakers(now, &11); - assert_eq!(Balances::free_balance(101), 2000); + assert_eq!(asset::free_balance::(&101), 2000); let nominated_value = exposure.others.iter().find(|o| o.who == 101).unwrap().value; on_offence_now( @@ -2841,8 +2849,8 @@ fn garbage_collection_on_window_pruning() { &[Perbill::from_percent(10)], ); - assert_eq!(Balances::free_balance(11), 900); - assert_eq!(Balances::free_balance(101), 2000 - (nominated_value / 10)); + assert_eq!(asset::free_balance::(&11), 900); + assert_eq!(asset::free_balance::(&101), 2000 - (nominated_value / 10)); assert!(ValidatorSlashInEra::::get(&now, &11).is_some()); assert!(NominatorSlashInEra::::get(&now, &101).is_some()); @@ -2867,9 +2875,9 @@ fn slashing_nominators_by_span_max() { mock::start_active_era(2); mock::start_active_era(3); - assert_eq!(Balances::free_balance(11), 1000); - assert_eq!(Balances::free_balance(21), 2000); - assert_eq!(Balances::free_balance(101), 2000); + assert_eq!(asset::free_balance::(&11), 1000); + assert_eq!(asset::free_balance::(&21), 2000); + assert_eq!(asset::free_balance::(&101), 2000); assert_eq!(Staking::slashable_balance_of(&21), 1000); let exposure_11 = Staking::eras_stakers(active_era(), &11); @@ -2886,10 +2894,10 @@ fn slashing_nominators_by_span_max() { 2, ); - assert_eq!(Balances::free_balance(11), 900); + assert_eq!(asset::free_balance::(&11), 900); let slash_1_amount = Perbill::from_percent(10) * nominated_value_11; - assert_eq!(Balances::free_balance(101), 2000 - slash_1_amount); + assert_eq!(asset::free_balance::(&101), 2000 - slash_1_amount); let expected_spans = vec![ slashing::SlashingSpan { index: 1, start: 4, length: None }, @@ -2913,14 +2921,14 @@ fn slashing_nominators_by_span_max() { ); // 11 was not further slashed, but 21 and 101 were. - assert_eq!(Balances::free_balance(11), 900); - assert_eq!(Balances::free_balance(21), 1700); + assert_eq!(asset::free_balance::(&11), 900); + assert_eq!(asset::free_balance::(&21), 1700); let slash_2_amount = Perbill::from_percent(30) * nominated_value_21; assert!(slash_2_amount > slash_1_amount); // only the maximum slash in a single span is taken. - assert_eq!(Balances::free_balance(101), 2000 - slash_2_amount); + assert_eq!(asset::free_balance::(&101), 2000 - slash_2_amount); // third slash: in same era and on same validator as first, higher // in-era value, but lower slash value than slash 2. @@ -2934,15 +2942,15 @@ fn slashing_nominators_by_span_max() { ); // 11 was further slashed, but 21 and 101 were not. - assert_eq!(Balances::free_balance(11), 800); - assert_eq!(Balances::free_balance(21), 1700); + assert_eq!(asset::free_balance::(&11), 800); + assert_eq!(asset::free_balance::(&21), 1700); let slash_3_amount = Perbill::from_percent(20) * nominated_value_21; assert!(slash_3_amount < slash_2_amount); assert!(slash_3_amount > slash_1_amount); // only the maximum slash in a single span is taken. - assert_eq!(Balances::free_balance(101), 2000 - slash_2_amount); + assert_eq!(asset::free_balance::(&101), 2000 - slash_2_amount); }); } @@ -2953,7 +2961,7 @@ fn slashes_are_summed_across_spans() { mock::start_active_era(2); mock::start_active_era(3); - assert_eq!(Balances::free_balance(21), 2000); + assert_eq!(asset::free_balance::(&21), 2000); assert_eq!(Staking::slashable_balance_of(&21), 1000); let get_span = |account| SlashingSpans::::get(&account).unwrap(); @@ -2972,7 +2980,7 @@ fn slashes_are_summed_across_spans() { ]; assert_eq!(get_span(21).iter().collect::>(), expected_spans); - assert_eq!(Balances::free_balance(21), 1900); + assert_eq!(asset::free_balance::(&21), 1900); // 21 has been force-chilled. re-signal intent to validate. Staking::validate(RuntimeOrigin::signed(21), Default::default()).unwrap(); @@ -2996,7 +3004,7 @@ fn slashes_are_summed_across_spans() { ]; assert_eq!(get_span(21).iter().collect::>(), expected_spans); - assert_eq!(Balances::free_balance(21), 1810); + assert_eq!(asset::free_balance::(&21), 1810); }); } @@ -3005,10 +3013,10 @@ fn deferred_slashes_are_deferred() { ExtBuilder::default().slash_defer_duration(2).build_and_execute(|| { mock::start_active_era(1); - assert_eq!(Balances::free_balance(11), 1000); + assert_eq!(asset::free_balance::(&11), 1000); let exposure = Staking::eras_stakers(active_era(), &11); - assert_eq!(Balances::free_balance(101), 2000); + assert_eq!(asset::free_balance::(&101), 2000); let nominated_value = exposure.others.iter().find(|o| o.who == 101).unwrap().value; System::reset_events(); @@ -3024,25 +3032,25 @@ fn deferred_slashes_are_deferred() { // nominations are not removed regardless of the deferring. assert_eq!(Staking::nominators(101).unwrap().targets, vec![11, 21]); - assert_eq!(Balances::free_balance(11), 1000); - assert_eq!(Balances::free_balance(101), 2000); + assert_eq!(asset::free_balance::(&11), 1000); + assert_eq!(asset::free_balance::(&101), 2000); mock::start_active_era(2); - assert_eq!(Balances::free_balance(11), 1000); - assert_eq!(Balances::free_balance(101), 2000); + assert_eq!(asset::free_balance::(&11), 1000); + assert_eq!(asset::free_balance::(&101), 2000); mock::start_active_era(3); - assert_eq!(Balances::free_balance(11), 1000); - assert_eq!(Balances::free_balance(101), 2000); + assert_eq!(asset::free_balance::(&11), 1000); + assert_eq!(asset::free_balance::(&101), 2000); // at the start of era 4, slashes from era 1 are processed, // after being deferred for at least 2 full eras. mock::start_active_era(4); - assert_eq!(Balances::free_balance(11), 900); - assert_eq!(Balances::free_balance(101), 2000 - (nominated_value / 10)); + assert_eq!(asset::free_balance::(&11), 900); + assert_eq!(asset::free_balance::(&101), 2000 - (nominated_value / 10)); assert!(matches!( staking_events_since_last_call().as_slice(), @@ -3140,8 +3148,8 @@ fn staker_cannot_bail_deferred_slash() { ExtBuilder::default().slash_defer_duration(2).build_and_execute(|| { mock::start_active_era(1); - assert_eq!(Balances::free_balance(11), 1000); - assert_eq!(Balances::free_balance(101), 2000); + assert_eq!(asset::free_balance::(&11), 1000); + assert_eq!(asset::free_balance::(&101), 2000); let exposure = Staking::eras_stakers(active_era(), &11); let nominated_value = exposure.others.iter().find(|o| o.who == 101).unwrap().value; @@ -3173,20 +3181,20 @@ fn staker_cannot_bail_deferred_slash() { ); // no slash yet. - assert_eq!(Balances::free_balance(11), 1000); - assert_eq!(Balances::free_balance(101), 2000); + assert_eq!(asset::free_balance::(&11), 1000); + assert_eq!(asset::free_balance::(&101), 2000); // no slash yet. mock::start_active_era(2); - assert_eq!(Balances::free_balance(11), 1000); - assert_eq!(Balances::free_balance(101), 2000); + assert_eq!(asset::free_balance::(&11), 1000); + assert_eq!(asset::free_balance::(&101), 2000); assert_eq!(Staking::current_era().unwrap(), 2); assert_eq!(active_era(), 2); // no slash yet. mock::start_active_era(3); - assert_eq!(Balances::free_balance(11), 1000); - assert_eq!(Balances::free_balance(101), 2000); + assert_eq!(asset::free_balance::(&11), 1000); + assert_eq!(asset::free_balance::(&101), 2000); assert_eq!(Staking::current_era().unwrap(), 3); assert_eq!(active_era(), 3); @@ -3203,8 +3211,8 @@ fn staker_cannot_bail_deferred_slash() { // after being deferred for at least 2 full eras. mock::start_active_era(4); - assert_eq!(Balances::free_balance(11), 900); - assert_eq!(Balances::free_balance(101), 2000 - (nominated_value / 10)); + assert_eq!(asset::free_balance::(&11), 900); + assert_eq!(asset::free_balance::(&101), 2000 - (nominated_value / 10)); // and the leftover of the funds can now be unbonded. }) @@ -3215,10 +3223,10 @@ fn remove_deferred() { ExtBuilder::default().slash_defer_duration(2).build_and_execute(|| { mock::start_active_era(1); - assert_eq!(Balances::free_balance(11), 1000); + assert_eq!(asset::free_balance::(&11), 1000); let exposure = Staking::eras_stakers(active_era(), &11); - assert_eq!(Balances::free_balance(101), 2000); + assert_eq!(asset::free_balance::(&101), 2000); let nominated_value = exposure.others.iter().find(|o| o.who == 101).unwrap().value; // deferred to start of era 4. @@ -3227,8 +3235,8 @@ fn remove_deferred() { &[Perbill::from_percent(10)], ); - assert_eq!(Balances::free_balance(11), 1000); - assert_eq!(Balances::free_balance(101), 2000); + assert_eq!(asset::free_balance::(&11), 1000); + assert_eq!(asset::free_balance::(&101), 2000); mock::start_active_era(2); @@ -3249,13 +3257,13 @@ fn remove_deferred() { // cancel one of them. assert_ok!(Staking::cancel_deferred_slash(RuntimeOrigin::root(), 4, vec![0])); - assert_eq!(Balances::free_balance(11), 1000); - assert_eq!(Balances::free_balance(101), 2000); + assert_eq!(asset::free_balance::(&11), 1000); + assert_eq!(asset::free_balance::(&101), 2000); mock::start_active_era(3); - assert_eq!(Balances::free_balance(11), 1000); - assert_eq!(Balances::free_balance(101), 2000); + assert_eq!(asset::free_balance::(&11), 1000); + assert_eq!(asset::free_balance::(&101), 2000); // at the start of era 4, slashes from era 1 are processed, // after being deferred for at least 2 full eras. @@ -3280,8 +3288,8 @@ fn remove_deferred() { let actual_slash = total_slash - initial_slash; // 5% slash (15 - 10) processed now. - assert_eq!(Balances::free_balance(11), 950); - assert_eq!(Balances::free_balance(101), 2000 - actual_slash); + assert_eq!(asset::free_balance::(&11), 950); + assert_eq!(asset::free_balance::(&101), 2000 - actual_slash); }) } @@ -3290,10 +3298,10 @@ fn remove_multi_deferred() { ExtBuilder::default().slash_defer_duration(2).build_and_execute(|| { mock::start_active_era(1); - assert_eq!(Balances::free_balance(11), 1000); + assert_eq!(asset::free_balance::(&11), 1000); let exposure = Staking::eras_stakers(active_era(), &11); - assert_eq!(Balances::free_balance(101), 2000); + assert_eq!(asset::free_balance::(&101), 2000); on_offence_now( &[OffenceDetails { offender: (11, exposure.clone()), reporters: vec![] }], @@ -3363,8 +3371,8 @@ fn slash_kicks_validators_not_nominators_and_disables_nominator_for_kicked_valid assert_eq_uvec!(Session::validators(), vec![11, 21, 31, 41, 51, 201, 202]); // pre-slash balance - assert_eq!(Balances::free_balance(11), 1000); - assert_eq!(Balances::free_balance(101), 2000); + assert_eq!(asset::free_balance::(&11), 1000); + assert_eq!(asset::free_balance::(&101), 2000); // 100 has approval for 11 as of now assert!(Staking::nominators(101).unwrap().targets.contains(&11)); @@ -3398,8 +3406,8 @@ fn slash_kicks_validators_not_nominators_and_disables_nominator_for_kicked_valid // post-slash balance let nominator_slash_amount_11 = 125 / 10; - assert_eq!(Balances::free_balance(11), 900); - assert_eq!(Balances::free_balance(101), 2000 - nominator_slash_amount_11); + assert_eq!(asset::free_balance::(&11), 900); + assert_eq!(asset::free_balance::(&101), 2000 - nominator_slash_amount_11); // check that validator was disabled. assert!(is_disabled(11)); @@ -3663,8 +3671,8 @@ fn claim_reward_at_the_last_era_and_no_double_claim_and_invalid_claim() { // Consumed weight for all payout_stakers dispatches that fail let err_weight = ::WeightInfo::payout_stakers_alive_staked(0); - let init_balance_11 = Balances::total_balance(&11); - let init_balance_101 = Balances::total_balance(&101); + let init_balance_11 = asset::total_balance::(&11); + let init_balance_101 = asset::total_balance::(&101); let part_for_11 = Perbill::from_rational::(1000, 1125); let part_for_101 = Perbill::from_rational::(125, 1125); @@ -3728,11 +3736,11 @@ fn claim_reward_at_the_last_era_and_no_double_claim_and_invalid_claim() { // only era 1 and 2 can be rewarded. assert_eq!( - Balances::total_balance(&11), + asset::total_balance::(&11), init_balance_11 + part_for_11 * (total_payout_1 + total_payout_2), ); assert_eq!( - Balances::total_balance(&101), + asset::total_balance::(&101), init_balance_101 + part_for_101 * (total_payout_1 + total_payout_2), ); }); @@ -3749,18 +3757,18 @@ fn zero_slash_keeps_nominators() { .build_and_execute(|| { mock::start_active_era(1); - assert_eq!(Balances::free_balance(11), 1000); + assert_eq!(asset::free_balance::(&11), 1000); let exposure = Staking::eras_stakers(active_era(), &11); - assert_eq!(Balances::free_balance(101), 2000); + assert_eq!(asset::free_balance::(&101), 2000); on_offence_now( &[OffenceDetails { offender: (11, exposure.clone()), reporters: vec![] }], &[Perbill::from_percent(0)], ); - assert_eq!(Balances::free_balance(11), 1000); - assert_eq!(Balances::free_balance(101), 2000); + assert_eq!(asset::free_balance::(&11), 1000); + assert_eq!(asset::free_balance::(&101), 2000); // 11 is not removed but disabled assert!(Validators::::iter().any(|(stash, _)| stash == 11)); @@ -3837,7 +3845,7 @@ fn test_nominators_over_max_exposure_page_size_are_rewarded() { for i in 0..=MaxExposurePageSize::get() { let stash = 10_000 + i as AccountId; let balance = 10_000 + i as Balance; - Balances::make_free_balance_be(&stash, balance); + asset::set_balance::(&stash, balance); assert_ok!(Staking::bond( RuntimeOrigin::signed(stash), balance, @@ -3859,13 +3867,13 @@ fn test_nominators_over_max_exposure_page_size_are_rewarded() { while i < MaxExposurePageSize::get() { let stash = 10_000 + i as AccountId; let balance = 10_000 + i as Balance; - assert!(Balances::free_balance(&stash) > balance); + assert!(asset::free_balance::(&stash) > balance); i += 1; } // Assert overflowing nominators from page 1 are also rewarded let stash = 10_000 + i as AccountId; - assert!(Balances::free_balance(&stash) > (10_000 + i) as Balance); + assert!(asset::free_balance::(&stash) > (10_000 + i) as Balance); }); } @@ -3878,7 +3886,7 @@ fn test_nominators_are_rewarded_for_all_exposure_page() { for i in 0..nominator_count { let stash = 10_000 + i as AccountId; let balance = 10_000 + i as Balance; - Balances::make_free_balance_be(&stash, balance); + asset::set_balance::(&stash, balance); assert_ok!(Staking::bond( RuntimeOrigin::signed(stash), balance, @@ -3900,9 +3908,9 @@ fn test_nominators_are_rewarded_for_all_exposure_page() { // Assert all nominators are rewarded according to their stake for i in 0..nominator_count { // balance of the nominator after the reward payout. - let current_balance = Balances::free_balance(&((10000 + i) as AccountId)); + let current_balance = asset::free_balance::(&((10000 + i) as AccountId)); // balance of the nominator in the previous iteration. - let previous_balance = Balances::free_balance(&((10000 + i - 1) as AccountId)); + let previous_balance = asset::free_balance::(&((10000 + i - 1) as AccountId)); // balance before the reward. let original_balance = 10_000 + i as Balance; @@ -3958,7 +3966,7 @@ fn test_multi_page_payout_stakers_by_page() { RewardOnUnbalanceWasCalled::set(false); System::reset_events(); - let controller_balance_before_p0_payout = Balances::free_balance(&11); + let controller_balance_before_p0_payout = asset::free_balance::(&11); // Payout rewards for first exposure page assert_ok!(Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, 1, 0)); @@ -3972,7 +3980,7 @@ fn test_multi_page_payout_stakers_by_page() { ] )); - let controller_balance_after_p0_payout = Balances::free_balance(&11); + let controller_balance_after_p0_payout = asset::free_balance::(&11); // verify rewards have been paid out but still some left assert!(pallet_balances::TotalIssuance::::get() > pre_payout_total_issuance); @@ -3996,7 +4004,7 @@ fn test_multi_page_payout_stakers_by_page() { ] )); // verify the validator was not rewarded the second time - assert_eq!(Balances::free_balance(&11), controller_balance_after_p0_payout); + assert_eq!(asset::free_balance::(&11), controller_balance_after_p0_payout); // verify all rewards have been paid out assert_eq_error_rate!( @@ -4007,9 +4015,9 @@ fn test_multi_page_payout_stakers_by_page() { assert!(RewardOnUnbalanceWasCalled::get()); // Top 64 nominators of validator 11 automatically paid out, including the validator - assert!(Balances::free_balance(&11) > balance); + assert!(asset::free_balance::(&11) > balance); for i in 0..100 { - assert!(Balances::free_balance(&(1000 + i)) > balance + i as Balance); + assert!(asset::free_balance::(&(1000 + i)) > balance + i as Balance); } // verify we no longer track rewards in `legacy_claimed_rewards` vec @@ -4178,7 +4186,7 @@ fn test_multi_page_payout_stakers_backward_compatible() { let pre_payout_total_issuance = pallet_balances::TotalIssuance::::get(); RewardOnUnbalanceWasCalled::set(false); - let controller_balance_before_p0_payout = Balances::free_balance(&11); + let controller_balance_before_p0_payout = asset::free_balance::(&11); // Payout rewards for first exposure page assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 1)); // page 0 is claimed @@ -4187,7 +4195,7 @@ fn test_multi_page_payout_stakers_backward_compatible() { Error::::AlreadyClaimed.with_weight(err_weight) ); - let controller_balance_after_p0_payout = Balances::free_balance(&11); + let controller_balance_after_p0_payout = asset::free_balance::(&11); // verify rewards have been paid out but still some left assert!(pallet_balances::TotalIssuance::::get() > pre_payout_total_issuance); @@ -4206,7 +4214,7 @@ fn test_multi_page_payout_stakers_backward_compatible() { ); // verify the validator was not rewarded the second time - assert_eq!(Balances::free_balance(&11), controller_balance_after_p0_payout); + assert_eq!(asset::free_balance::(&11), controller_balance_after_p0_payout); // verify all rewards have been paid out assert_eq_error_rate!( @@ -4218,9 +4226,9 @@ fn test_multi_page_payout_stakers_backward_compatible() { // verify all nominators of validator 11 are paid out, including the validator // Validator payout goes to controller. - assert!(Balances::free_balance(&11) > balance); + assert!(asset::free_balance::(&11) > balance); for i in 0..100 { - assert!(Balances::free_balance(&(1000 + i)) > balance + i as Balance); + assert!(asset::free_balance::(&(1000 + i)) > balance + i as Balance); } // verify we no longer track rewards in `legacy_claimed_rewards` vec @@ -4578,25 +4586,25 @@ fn test_commission_paid_across_pages() { let payout = current_total_payout_for_duration(reward_time_per_era()); mock::start_active_era(2); - let initial_balance = Balances::free_balance(&11); + let initial_balance = asset::free_balance::(&11); // Payout rewards for first exposure page assert_ok!(Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, 1, 0)); - let controller_balance_after_p0_payout = Balances::free_balance(&11); + let controller_balance_after_p0_payout = asset::free_balance::(&11); // some commission is paid assert!(initial_balance < controller_balance_after_p0_payout); // payout all pages for i in 1..4 { - let before_balance = Balances::free_balance(&11); + let before_balance = asset::free_balance::(&11); assert_ok!(Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, 1, i)); - let after_balance = Balances::free_balance(&11); + let after_balance = asset::free_balance::(&11); // some commission is paid for every page assert!(before_balance < after_balance); } - assert_eq_error_rate!(Balances::free_balance(&11), initial_balance + payout / 2, 1,); + assert_eq_error_rate!(asset::free_balance::(&11), initial_balance + payout / 2, 1,); }); } @@ -4852,7 +4860,7 @@ fn payout_to_any_account_works() { assert_ok!(Staking::set_payee(RuntimeOrigin::signed(1234), RewardDestination::Account(42))); // Reward Destination account doesn't exist - assert_eq!(Balances::free_balance(42), 0); + assert_eq!(asset::free_balance::(&42), 0); mock::start_active_era(1); Staking::reward_by_ids(vec![(11, 1)]); @@ -4862,7 +4870,7 @@ fn payout_to_any_account_works() { assert_ok!(Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, 1, 0)); // Payment is successful - assert!(Balances::free_balance(42) > 0); + assert!(asset::free_balance::(&42) > 0); }) } @@ -5661,9 +5669,9 @@ fn chill_other_works() { let a = 4 * i; let b = 4 * i + 2; let c = 4 * i + 3; - Balances::make_free_balance_be(&a, 100_000); - Balances::make_free_balance_be(&b, 100_000); - Balances::make_free_balance_be(&c, 100_000); + asset::set_balance::(&a, 100_000); + asset::set_balance::(&b, 100_000); + asset::set_balance::(&c, 100_000); // Nominator assert_ok!(Staking::bond(RuntimeOrigin::signed(a), 1000, RewardDestination::Stash)); @@ -6859,7 +6867,7 @@ fn test_runtime_api_pending_rewards() { // Set staker for v in validator_one..=validator_three { - let _ = Balances::make_free_balance_be(&v, stake); + let _ = asset::set_balance::(&v, stake); assert_ok!(Staking::bond(RuntimeOrigin::signed(v), stake, RewardDestination::Staked)); } @@ -7049,7 +7057,7 @@ mod staking_interface { assert!(!>::contains_key(&11)); assert!(!>::contains_key(&11)); // lock is removed. - assert_eq!(Balances::balance_locked(STAKING_ID, &11), 0); + assert_eq!(asset::staked::(&11), 0); }); } @@ -7086,12 +7094,12 @@ mod staking_unchecked { fn virtual_bond_does_not_lock() { ExtBuilder::default().build_and_execute(|| { mock::start_active_era(1); - assert_eq!(Balances::free_balance(10), 1); + assert_eq!(asset::free_balance::(&10), 1); // 10 can bond more than its balance amount since we do not require lock for virtual // bonding. assert_ok!(::virtual_bond(&10, 100, &15)); // nothing is locked on 10. - assert_eq!(Balances::balance_locked(STAKING_ID, &10), 0); + assert_eq!(asset::staked::(&10), 0); // adding more balance does not lock anything as well. assert_ok!(::bond_extra(&10, 1000)); // but ledger is updated correctly. @@ -7118,7 +7126,7 @@ mod staking_unchecked { Ok(Stake { total: 1100, active: 900 }) ); // still no locks. - assert_eq!(Balances::balance_locked(STAKING_ID, &10), 0); + assert_eq!(asset::staked::(&10), 0); mock::start_active_era(2); // cannot withdraw without waiting for unbonding period. @@ -7218,7 +7226,7 @@ mod staking_unchecked { fn migrate_virtual_staker() { ExtBuilder::default().build_and_execute(|| { // give some balance to 200 - Balances::make_free_balance_be(&200, 2000); + asset::set_balance::(&200, 2000); // stake assert_ok!(Staking::bond(RuntimeOrigin::signed(200), 1000, RewardDestination::Staked)); @@ -7300,7 +7308,7 @@ mod staking_unchecked { assert!(is_disabled(11)); // but virtual nominator's balance is not slashed. - assert_eq!(Balances::free_balance(&101), nominator_balance); + assert_eq!(asset::free_balance::(&101), nominator_balance); // but slash is broadcasted to slash observers. assert_eq!(SlashObserver::get().get(&101).unwrap(), &nominator_share); }) @@ -7332,9 +7340,9 @@ mod staking_unchecked { assert_ok!(::set_payee(&101, &102)); // cache values - let validator_balance = Balances::free_balance(&11); + let validator_balance = asset::free_balance::(&11); let validator_stake = Staking::ledger(11.into()).unwrap().total; - let nominator_balance = Balances::free_balance(&101); + let nominator_balance = asset::free_balance::(&101); let nominator_stake = Staking::ledger(101.into()).unwrap().total; // 11 goes offline @@ -7353,14 +7361,14 @@ mod staking_unchecked { // all validator stake is slashed assert_eq_error_rate!( validator_balance - validator_stake, - Balances::free_balance(&11), + asset::free_balance::(&11), 1 ); // Because slashing happened. assert!(is_disabled(11)); // Virtual nominator's balance is not slashed. - assert_eq!(Balances::free_balance(&101), nominator_balance); + assert_eq!(asset::free_balance::(&101), nominator_balance); // Slash is broadcasted to slash observers. assert_eq!(SlashObserver::get().get(&101).unwrap(), &nominator_stake); From 2926255fc9f602795fca838f36fde54ddd9bfcf0 Mon Sep 17 00:00:00 2001 From: Ankan Date: Mon, 19 Aug 2024 02:13:02 +0200 Subject: [PATCH 012/142] clippy --- substrate/frame/staking/src/tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 5ed5dfcb9618..bbb1ff129a30 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -27,7 +27,7 @@ use frame_support::{ assert_noop, assert_ok, assert_storage_noop, dispatch::{extract_actual_weight, GetDispatchInfo, WithPostDispatchInfo}, pallet_prelude::*, - traits::{Currency, Get, InspectLockableCurrency, ReservableCurrency}, + traits::{Currency, Get, ReservableCurrency}, }; use mock::*; From 34e1d48f3cc57ae2156e1c91fbc9108146dcecf0 Mon Sep 17 00:00:00 2001 From: Ankan Date: Mon, 26 Aug 2024 19:09:10 +0200 Subject: [PATCH 013/142] rustdoc update --- substrate/frame/staking/src/asset.rs | 33 +++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/substrate/frame/staking/src/asset.rs b/substrate/frame/staking/src/asset.rs index db9fc5a5296a..24558af06cc4 100644 --- a/substrate/frame/staking/src/asset.rs +++ b/substrate/frame/staking/src/asset.rs @@ -9,31 +9,42 @@ pub fn existential_deposit() -> BalanceOf { T::Currency::minimum_balance() } +/// Total issuance of the chain. pub fn total_issuance() -> BalanceOf { T::Currency::total_issuance() } +/// Make total balance equal to value. pub fn set_balance(who: &T::AccountId, value: BalanceOf) { T::Currency::make_free_balance_be(who, value); } +/// Burn the amount from the total issuance. pub fn burn(amount: BalanceOf) -> PositiveImbalanceOf { T::Currency::burn(amount) } +/// Stakeable balance. Includes already staked + free to stake. pub fn free_balance(who: &T::AccountId) -> BalanceOf { T::Currency::free_balance(who) } +/// Total balance of an account. Includes both, liquid and reserved. pub fn total_balance(who: &T::AccountId) -> BalanceOf { T::Currency::total_balance(who) } -/// Balance that is staked and at stake. +/// Balance of `who` that is at stake. +/// +/// The staked amount is locked and cannot be transferred out of `who`s account. pub fn staked(who: &T::AccountId) -> BalanceOf { T::Currency::balance_locked(crate::STAKING_ID, who) } +/// Update `amount` at stake for `who`. +/// +/// Overwrites the existing stake amount. If passed amount is lower than the existing stake, the +/// difference is unlocked. pub fn update_stake(who: &T::AccountId, amount: BalanceOf) { T::Currency::set_lock( crate::STAKING_ID, @@ -43,10 +54,16 @@ pub fn update_stake(who: &T::AccountId, amount: BalanceOf) { ); } +/// Kill the stake of `who`. +/// +/// All locked amount is unlocked. pub fn kill_stake(who: &T::AccountId) { T::Currency::remove_lock(crate::STAKING_ID, who); } +/// Slash the value from `who`. +/// +/// A negative imbalance is returned which can be resolved to deposit the slashed value. pub fn slash( who: &T::AccountId, value: BalanceOf, @@ -54,7 +71,9 @@ pub fn slash( T::Currency::slash(who, value) } -/// Mint reward into an existing account. Does not increase the total issuance. +/// Mint reward into an existing account. +/// +/// This does not increase the total issuance. pub fn mint_existing( who: &T::AccountId, value: BalanceOf, @@ -62,17 +81,21 @@ pub fn mint_existing( T::Currency::deposit_into_existing(who, value).ok() } -/// Mint reward and create if account does not exist. Does not increase the total issuance. +/// Mint reward and create account for `who` if it does not exist. +/// +/// This does not increase the total issuance. pub fn mint_creating(who: &T::AccountId, value: BalanceOf) -> PositiveImbalanceOf { T::Currency::deposit_creating(who, value) } -/// Deposit to who from slashed value. +/// Deposit newly issued or slashed `value` into `who`. pub fn deposit_slashed(who: &T::AccountId, value: NegativeImbalanceOf) { T::Currency::resolve_creating(who, value) } -/// Increases total issuance. +/// Issue `value` increasing total issuance. +/// +/// Creates a negative imbalance. pub fn issue(value: BalanceOf) -> NegativeImbalanceOf { T::Currency::issue(value) } From 31c6467925254204e9ef675b28d83a3c297694bf Mon Sep 17 00:00:00 2001 From: Ankan Date: Mon, 26 Aug 2024 19:32:11 +0200 Subject: [PATCH 014/142] refactor --- substrate/frame/staking/src/asset.rs | 15 +- substrate/frame/staking/src/benchmarking.rs | 12 +- substrate/frame/staking/src/pallet/impls.rs | 2 +- substrate/frame/staking/src/pallet/mod.rs | 6 +- substrate/frame/staking/src/testing_utils.rs | 4 +- substrate/frame/staking/src/tests.rs | 302 ++++++++++--------- 6 files changed, 177 insertions(+), 164 deletions(-) diff --git a/substrate/frame/staking/src/asset.rs b/substrate/frame/staking/src/asset.rs index 24558af06cc4..c907931d0a5e 100644 --- a/substrate/frame/staking/src/asset.rs +++ b/substrate/frame/staking/src/asset.rs @@ -14,22 +14,27 @@ pub fn total_issuance() -> BalanceOf { T::Currency::total_issuance() } -/// Make total balance equal to value. -pub fn set_balance(who: &T::AccountId, value: BalanceOf) { +/// Set balance that can be staked for `who`. +/// +/// This includes any balance that is already staked. +pub fn set_stakeable_balance(who: &T::AccountId, value: BalanceOf) { T::Currency::make_free_balance_be(who, value); } /// Burn the amount from the total issuance. +#[cfg(feature = "runtime-benchmarks")] pub fn burn(amount: BalanceOf) -> PositiveImbalanceOf { T::Currency::burn(amount) } -/// Stakeable balance. Includes already staked + free to stake. -pub fn free_balance(who: &T::AccountId) -> BalanceOf { +/// Stakeable balance of `who`. +/// +/// This includes balance free to stake along with any balance that is already staked. +pub fn stakeable_balance(who: &T::AccountId) -> BalanceOf { T::Currency::free_balance(who) } -/// Total balance of an account. Includes both, liquid and reserved. +/// Total balance of an account. Includes both, free and reserved. pub fn total_balance(who: &T::AccountId) -> BalanceOf { T::Currency::total_balance(who) } diff --git a/substrate/frame/staking/src/benchmarking.rs b/substrate/frame/staking/src/benchmarking.rs index acbff6755cce..e4b5cfccd0b4 100644 --- a/substrate/frame/staking/src/benchmarking.rs +++ b/substrate/frame/staking/src/benchmarking.rs @@ -611,21 +611,21 @@ benchmarks! { >::insert(current_era, validator.clone(), >::validators(&validator)); let caller = whitelisted_caller(); - let balance_before = asset::free_balance::(&validator); + let balance_before = asset::stakeable_balance::(&validator); let mut nominator_balances_before = Vec::new(); for (stash, _) in &nominators { - let balance = asset::free_balance::(stash); + let balance = asset::stakeable_balance::(stash); nominator_balances_before.push(balance); } }: payout_stakers(RawOrigin::Signed(caller), validator.clone(), current_era) verify { - let balance_after = asset::free_balance::(&validator); + let balance_after = asset::stakeable_balance::(&validator); ensure!( balance_before < balance_after, "Balance of validator stash should have increased after payout.", ); for ((stash, _), balance_before) in nominators.iter().zip(nominator_balances_before.iter()) { - let balance_after = asset::free_balance::(stash); + let balance_after = asset::stakeable_balance::(stash); ensure!( balance_before < &balance_after, "Balance of nominator stash should have increased after payout.", @@ -794,7 +794,7 @@ benchmarks! { } Ledger::::insert(controller, staking_ledger); let slash_amount = asset::existential_deposit::() * 10u32.into(); - let balance_before = asset::free_balance::(&stash); + let balance_before = asset::stakeable_balance::(&stash); }: { crate::slashing::do_slash::( &stash, @@ -804,7 +804,7 @@ benchmarks! { EraIndex::zero() ); } verify { - let balance_after = asset::free_balance::(&stash); + let balance_after = asset::stakeable_balance::(&stash); assert!(balance_before > balance_after); } diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index 253c49295102..6c4fe8140e8e 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -164,7 +164,7 @@ impl Pallet { } else { // additional amount or actual balance of stash whichever is lower. additional.min( - asset::free_balance::(stash) + asset::stakeable_balance::(stash) .checked_sub(&ledger.total) .ok_or(ArithmeticError::Overflow)?, ) diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 6908aa4efa84..63861d77f368 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -779,7 +779,7 @@ pub mod pallet { status ); assert!( - asset::free_balance::(stash) >= balance, + asset::stakeable_balance::(stash) >= balance, "Stash does not have enough balance to bond." ); frame_support::assert_ok!(>::bond( @@ -1029,7 +1029,7 @@ pub mod pallet { frame_system::Pallet::::inc_consumers(&stash).map_err(|_| Error::::BadState)?; - let stash_balance = asset::free_balance::(&stash); + let stash_balance = asset::stakeable_balance::(&stash); let value = value.min(stash_balance); Self::deposit_event(Event::::Bonded { stash: stash.clone(), amount: value }); let ledger = StakingLedger::::new(stash.clone(), value); @@ -2077,7 +2077,7 @@ pub mod pallet { ensure!(!Self::is_virtual_staker(&stash), Error::::VirtualStakerNotAllowed); let current_lock = asset::staked::(&stash); - let stash_balance = asset::free_balance::(&stash); + let stash_balance = asset::stakeable_balance::(&stash); let (new_controller, new_total) = match Self::inspect_bond_state(&stash) { Ok(LedgerIntegrityState::Corrupted) => { diff --git a/substrate/frame/staking/src/testing_utils.rs b/substrate/frame/staking/src/testing_utils.rs index 1981792e981e..efd4a40f1ab4 100644 --- a/substrate/frame/staking/src/testing_utils.rs +++ b/substrate/frame/staking/src/testing_utils.rs @@ -54,7 +54,7 @@ pub fn create_funded_user( ) -> T::AccountId { let user = account(string, n, SEED); let balance = asset::existential_deposit::() * balance_factor.into(); - let _ = asset::set_balance::(&user, balance); + let _ = asset::set_stakeable_balance::(&user, balance); user } @@ -65,7 +65,7 @@ pub fn create_funded_user_with_balance( balance: BalanceOf, ) -> T::AccountId { let user = account(string, n, SEED); - let _ = asset::set_balance::(&user, balance); + let _ = asset::set_stakeable_balance::(&user, balance); user } diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index bbb1ff129a30..5eb9eff39efa 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -229,8 +229,8 @@ fn basic_setup_works() { assert_eq!(active_era(), 0); // Account 10 has `balance_factor` free balance - assert_eq!(asset::free_balance::(&10), 1); - assert_eq!(asset::free_balance::(&10), 1); + assert_eq!(asset::stakeable_balance::(&10), 1); + assert_eq!(asset::stakeable_balance::(&10), 1); // New era is not being forced assert_eq!(Staking::force_era(), Forcing::NotForcing); @@ -429,7 +429,7 @@ fn staking_should_work() { // put some money in account that we'll use. for i in 1..5 { - let _ = asset::set_balance::(&i, 2000); + let _ = asset::set_stakeable_balance::(&i, 2000); } // --- Block 2: @@ -611,7 +611,7 @@ fn nominating_and_rewards_should_work() { // give the man some money let initial_balance = 1000; for i in [1, 3, 5, 11, 21].iter() { - let _ = asset::set_balance::(&i, initial_balance); + let _ = asset::set_stakeable_balance::(&i, initial_balance); } // bond two account pairs and state interest in nomination. @@ -993,7 +993,7 @@ fn cannot_transfer_staked_balance() { // Confirm account 11 is stashed assert_eq!(Staking::bonded(&11), Some(11)); // Confirm account 11 has some free balance - assert_eq!(asset::free_balance::(&11), 1000); + assert_eq!(asset::stakeable_balance::(&11), 1000); // Confirm account 11 (via controller) is totally staked assert_eq!(Staking::eras_stakers(active_era(), &11).total, 1000); // Confirm account 11 cannot transfer as a result @@ -1003,7 +1003,7 @@ fn cannot_transfer_staked_balance() { ); // Give account 11 extra free balance - let _ = asset::set_balance::(&11, 10000); + let _ = asset::set_stakeable_balance::(&11, 10000); // Confirm that account 11 can now transfer some balance assert_ok!(Balances::transfer_allow_death(RuntimeOrigin::signed(11), 21, 1)); }); @@ -1018,7 +1018,7 @@ fn cannot_transfer_staked_balance_2() { // Confirm account 21 is stashed assert_eq!(Staking::bonded(&21), Some(21)); // Confirm account 21 has some free balance - assert_eq!(asset::free_balance::(&21), 2000); + assert_eq!(asset::stakeable_balance::(&21), 2000); // Confirm account 21 (via controller) is totally staked assert_eq!(Staking::eras_stakers(active_era(), &21).total, 1000); // Confirm account 21 can transfer at most 1000 @@ -1037,14 +1037,14 @@ fn cannot_reserve_staked_balance() { // Confirm account 11 is stashed assert_eq!(Staking::bonded(&11), Some(11)); // Confirm account 11 has some free balance - assert_eq!(asset::free_balance::(&11), 1000); + assert_eq!(asset::stakeable_balance::(&11), 1000); // Confirm account 11 (via controller 10) is totally staked assert_eq!(Staking::eras_stakers(active_era(), &11).own, 1000); // Confirm account 11 cannot reserve as a result assert_noop!(Balances::reserve(&11, 1), BalancesError::::LiquidityRestrictions); // Give account 11 extra free balance - let _ = asset::set_balance::(&11, 10000); + let _ = asset::set_stakeable_balance::(&11, 10000); // Confirm account 11 can now reserve balance assert_ok!(Balances::reserve(&11, 1)); }); @@ -1057,9 +1057,9 @@ fn reward_destination_works() { // Check that account 11 is a validator assert!(Session::validators().contains(&11)); // Check the balance of the validator account - assert_eq!(asset::free_balance::(&10), 1); + assert_eq!(asset::stakeable_balance::(&10), 1); // Check the balance of the stash account - assert_eq!(asset::free_balance::(&11), 1000); + assert_eq!(asset::stakeable_balance::(&11), 1000); // Check how much is at stake assert_eq!( Staking::ledger(11.into()).unwrap(), @@ -1082,7 +1082,7 @@ fn reward_destination_works() { // Check that RewardDestination is Staked assert_eq!(Staking::payee(11.into()), Some(RewardDestination::Staked)); // Check that reward went to the stash account of validator - assert_eq!(asset::free_balance::(&11), 1000 + total_payout_0); + assert_eq!(asset::stakeable_balance::(&11), 1000 + total_payout_0); // Check that amount at stake increased accordingly assert_eq!( Staking::ledger(11.into()).unwrap(), @@ -1111,7 +1111,7 @@ fn reward_destination_works() { // Check that RewardDestination is Stash assert_eq!(Staking::payee(11.into()), Some(RewardDestination::Stash)); // Check that reward went to the stash account - assert_eq!(asset::free_balance::(&11), 1000 + total_payout_0 + total_payout_1); + assert_eq!(asset::stakeable_balance::(&11), 1000 + total_payout_0 + total_payout_1); // Record this value let recorded_stash_balance = 1000 + total_payout_0 + total_payout_1; // Check that amount at stake is NOT increased @@ -1133,7 +1133,7 @@ fn reward_destination_works() { >::insert(&11, RewardDestination::Account(11)); // Check controller balance - assert_eq!(asset::free_balance::(&11), 23150); + assert_eq!(asset::stakeable_balance::(&11), 23150); // Compute total payout now for whole duration as other parameter won't change let total_payout_2 = current_total_payout_for_duration(reward_time_per_era()); @@ -1145,7 +1145,7 @@ fn reward_destination_works() { // Check that RewardDestination is Account(11) assert_eq!(Staking::payee(11.into()), Some(RewardDestination::Account(11))); // Check that reward went to the controller account - assert_eq!(asset::free_balance::(&11), recorded_stash_balance + total_payout_2); + assert_eq!(asset::stakeable_balance::(&11), recorded_stash_balance + total_payout_2); // Check that amount at stake is NOT increased assert_eq!( Staking::ledger(11.into()).unwrap(), @@ -1230,7 +1230,7 @@ fn bond_extra_works() { ); // Give account 11 some large free balance greater than total - let _ = asset::set_balance::(&11, 1000000); + let _ = asset::set_stakeable_balance::(&11, 1000000); // Call the bond_extra function from controller, add only 100 assert_ok!(Staking::bond_extra(RuntimeOrigin::signed(11), 100)); @@ -1292,7 +1292,7 @@ fn bond_extra_and_withdraw_unbonded_works() { assert_ok!(Staking::set_payee(RuntimeOrigin::signed(11), RewardDestination::Stash)); // Give account 11 some large free balance greater than total - let _ = asset::set_balance::(&11, 1000000); + let _ = asset::set_stakeable_balance::(&11, 1000000); // Initial config should be correct assert_eq!(active_era(), 0); @@ -1503,7 +1503,7 @@ fn rebond_works() { assert_ok!(Staking::set_payee(RuntimeOrigin::signed(11), RewardDestination::Stash)); // Give account 11 some large free balance greater than total - let _ = asset::set_balance::(&11, 1000000); + let _ = asset::set_stakeable_balance::(&11, 1000000); // confirm that 10 is a normal validator and gets paid at the end of the era. mock::start_active_era(1); @@ -1629,7 +1629,7 @@ fn rebond_is_fifo() { assert_ok!(Staking::set_payee(RuntimeOrigin::signed(11), RewardDestination::Stash)); // Give account 11 some large free balance greater than total - let _ = asset::set_balance::(&11, 1000000); + let _ = asset::set_stakeable_balance::(&11, 1000000); // confirm that 10 is a normal validator and gets paid at the end of the era. mock::start_active_era(1); @@ -1725,7 +1725,7 @@ fn rebond_emits_right_value_in_event() { assert_ok!(Staking::set_payee(RuntimeOrigin::signed(11), RewardDestination::Stash)); // Give account 11 some large free balance greater than total - let _ = asset::set_balance::(&11, 1000000); + let _ = asset::set_stakeable_balance::(&11, 1000000); // confirm that 10 is a normal validator and gets paid at the end of the era. mock::start_active_era(1); @@ -1860,8 +1860,8 @@ fn reward_to_stake_works() { assert_eq!(Staking::eras_stakers(active_era(), &21).total, 2000); // Give the man some money. - let _ = asset::set_balance::(&10, 1000); - let _ = asset::set_balance::(&20, 1000); + let _ = asset::set_stakeable_balance::(&10, 1000); + let _ = asset::set_stakeable_balance::(&20, 1000); // Bypass logic and change current exposure EraInfo::::set_exposure(0, &21, Exposure { total: 69, own: 69, others: vec![] }); @@ -1888,7 +1888,7 @@ fn reward_to_stake_works() { assert_eq!(Staking::eras_stakers(active_era(), &11).total, 1000); assert_eq!(Staking::eras_stakers(active_era(), &21).total, 2000); - let _11_balance = asset::free_balance::(&11); + let _11_balance = asset::stakeable_balance::(&11); assert_eq!(_11_balance, 1000 + total_payout_0 / 2); // Trigger another new era as the info are frozen before the era start. @@ -2119,8 +2119,8 @@ fn bond_with_little_staked_value_bounded() { // setup assert_ok!(Staking::chill(RuntimeOrigin::signed(31))); assert_ok!(Staking::set_payee(RuntimeOrigin::signed(11), RewardDestination::Stash)); - let init_balance_1 = asset::free_balance::(&1); - let init_balance_11 = asset::free_balance::(&11); + let init_balance_1 = asset::stakeable_balance::(&1); + let init_balance_11 = asset::stakeable_balance::(&11); // Stingy validator. assert_ok!(Staking::bond(RuntimeOrigin::signed(1), 1, RewardDestination::Account(1))); @@ -2145,12 +2145,12 @@ fn bond_with_little_staked_value_bounded() { // Old ones are rewarded. assert_eq_error_rate!( - asset::free_balance::(&11), + asset::stakeable_balance::(&11), init_balance_11 + total_payout_0 / 3, 1 ); // no rewards paid to 2. This was initial election. - assert_eq!(asset::free_balance::(&1), init_balance_1); + assert_eq!(asset::stakeable_balance::(&1), init_balance_1); // reward era 2 let total_payout_1 = current_total_payout_for_duration(reward_time_per_era()); @@ -2163,12 +2163,12 @@ fn bond_with_little_staked_value_bounded() { // 2 is now rewarded. assert_eq_error_rate!( - asset::free_balance::(&1), + asset::stakeable_balance::(&1), init_balance_1 + total_payout_1 / 3, 1 ); assert_eq_error_rate!( - asset::free_balance::(&11), + asset::stakeable_balance::(&11), init_balance_11 + total_payout_0 / 3 + total_payout_1 / 3, 2, ); @@ -2196,7 +2196,7 @@ fn bond_with_duplicate_vote_should_be_ignored_by_election_provider() { // give the man some money. let initial_balance = 1000; for i in [1, 2, 3, 4].iter() { - let _ = asset::set_balance::(&i, initial_balance); + let _ = asset::set_stakeable_balance::(&i, initial_balance); } assert_ok!(Staking::bond( @@ -2249,7 +2249,7 @@ fn bond_with_duplicate_vote_should_be_ignored_by_election_provider_elected() { // give the man some money. let initial_balance = 1000; for i in [1, 2, 3, 4].iter() { - let _ = asset::set_balance::(&i, initial_balance); + let _ = asset::set_stakeable_balance::(&i, initial_balance); } assert_ok!(Staking::bond( @@ -2325,7 +2325,7 @@ fn reward_validator_slashing_validator_does_not_overflow() { assert!(stake.checked_mul(reward_slash).is_none()); // Set staker - let _ = asset::set_balance::(&11, stake); + let _ = asset::set_stakeable_balance::(&11, stake); let exposure = Exposure:: { total: stake, own: stake, others: vec![] }; let reward = EraRewardPoints:: { @@ -2341,8 +2341,8 @@ fn reward_validator_slashing_validator_does_not_overflow() { assert_eq!(asset::total_balance::(&11), stake * 2); // Set staker - let _ = asset::set_balance::(&11, stake); - let _ = asset::set_balance::(&2, stake); + let _ = asset::set_stakeable_balance::(&11, stake); + let _ = asset::set_stakeable_balance::(&2, stake); // only slashes out of bonded stake are applied. without this line, it is 0. Staking::bond(RuntimeOrigin::signed(2), stake - 1, RewardDestination::Staked).unwrap(); @@ -2534,7 +2534,7 @@ fn slashing_performed_according_exposure() { ); // The stash account should be slashed for 250 (50% of 500). - assert_eq!(asset::free_balance::(&11), 1000 - 250); + assert_eq!(asset::stakeable_balance::(&11), 1000 - 250); }); } @@ -2627,8 +2627,8 @@ fn reporters_receive_their_slice() { // 50% * (10% * initial_balance / 2) let reward = (initial_balance / 20) / 2; let reward_each = reward / 2; // split into two pieces. - assert_eq!(asset::free_balance::(&1), 10 + reward_each); - assert_eq!(asset::free_balance::(&2), 20 + reward_each); + assert_eq!(asset::stakeable_balance::(&1), 10 + reward_each); + assert_eq!(asset::stakeable_balance::(&2), 20 + reward_each); }); } @@ -2653,7 +2653,7 @@ fn subsequent_reports_in_same_span_pay_out_less() { // F1 * (reward_proportion * slash - 0) // 50% * (10% * initial_balance * 20%) let reward = (initial_balance / 5) / 20; - assert_eq!(asset::free_balance::(&1), 10 + reward); + assert_eq!(asset::stakeable_balance::(&1), 10 + reward); on_offence_now( &[OffenceDetails { @@ -2668,7 +2668,7 @@ fn subsequent_reports_in_same_span_pay_out_less() { // F1 * (reward_proportion * slash - prior_payout) // 50% * (10% * (initial_balance / 2) - prior_payout) let reward = ((initial_balance / 20) - prior_payout) / 2; - assert_eq!(asset::free_balance::(&1), 10 + prior_payout + reward); + assert_eq!(asset::stakeable_balance::(&1), 10 + prior_payout + reward); }); } @@ -2676,14 +2676,17 @@ fn subsequent_reports_in_same_span_pay_out_less() { fn invulnerables_are_not_slashed() { // For invulnerable validators no slashing is performed. ExtBuilder::default().invulnerables(vec![11]).build_and_execute(|| { - assert_eq!(asset::free_balance::(&11), 1000); - assert_eq!(asset::free_balance::(&21), 2000); + assert_eq!(asset::stakeable_balance::(&11), 1000); + assert_eq!(asset::stakeable_balance::(&21), 2000); let exposure = Staking::eras_stakers(active_era(), &21); let initial_balance = Staking::slashable_balance_of(&21); - let nominator_balances: Vec<_> = - exposure.others.iter().map(|o| asset::free_balance::(&o.who)).collect(); + let nominator_balances: Vec<_> = exposure + .others + .iter() + .map(|o| asset::stakeable_balance::(&o.who)) + .collect(); on_offence_now( &[ @@ -2700,14 +2703,14 @@ fn invulnerables_are_not_slashed() { ); // The validator 11 hasn't been slashed, but 21 has been. - assert_eq!(asset::free_balance::(&11), 1000); + assert_eq!(asset::stakeable_balance::(&11), 1000); // 2000 - (0.2 * initial_balance) - assert_eq!(asset::free_balance::(&21), 2000 - (2 * initial_balance / 10)); + assert_eq!(asset::stakeable_balance::(&21), 2000 - (2 * initial_balance / 10)); // ensure that nominators were slashed as well. for (initial_balance, other) in nominator_balances.into_iter().zip(exposure.others) { assert_eq!( - asset::free_balance::(&other.who), + asset::stakeable_balance::(&other.who), initial_balance - (2 * other.value / 10), ); } @@ -2718,7 +2721,7 @@ fn invulnerables_are_not_slashed() { fn dont_slash_if_fraction_is_zero() { // Don't slash if the fraction is zero. ExtBuilder::default().build_and_execute(|| { - assert_eq!(asset::free_balance::(&11), 1000); + assert_eq!(asset::stakeable_balance::(&11), 1000); on_offence_now( &[OffenceDetails { @@ -2729,7 +2732,7 @@ fn dont_slash_if_fraction_is_zero() { ); // The validator hasn't been slashed. The new era is not forced. - assert_eq!(asset::free_balance::(&11), 1000); + assert_eq!(asset::stakeable_balance::(&11), 1000); assert_eq!(Staking::force_era(), Forcing::NotForcing); }); } @@ -2739,7 +2742,7 @@ fn only_slash_for_max_in_era() { // multiple slashes within one era are only applied if it is more than any previous slash in the // same era. ExtBuilder::default().build_and_execute(|| { - assert_eq!(asset::free_balance::(&11), 1000); + assert_eq!(asset::stakeable_balance::(&11), 1000); on_offence_now( &[OffenceDetails { @@ -2750,7 +2753,7 @@ fn only_slash_for_max_in_era() { ); // The validator has been slashed and has been force-chilled. - assert_eq!(asset::free_balance::(&11), 500); + assert_eq!(asset::stakeable_balance::(&11), 500); assert_eq!(Staking::force_era(), Forcing::NotForcing); on_offence_now( @@ -2762,7 +2765,7 @@ fn only_slash_for_max_in_era() { ); // The validator has not been slashed additionally. - assert_eq!(asset::free_balance::(&11), 500); + assert_eq!(asset::stakeable_balance::(&11), 500); on_offence_now( &[OffenceDetails { @@ -2773,7 +2776,7 @@ fn only_slash_for_max_in_era() { ); // The validator got slashed 10% more. - assert_eq!(asset::free_balance::(&11), 400); + assert_eq!(asset::stakeable_balance::(&11), 400); }) } @@ -2784,7 +2787,7 @@ fn garbage_collection_after_slashing() { .existential_deposit(2) .balance_factor(2) .build_and_execute(|| { - assert_eq!(asset::free_balance::(&11), 2000); + assert_eq!(asset::stakeable_balance::(&11), 2000); on_offence_now( &[OffenceDetails { @@ -2794,7 +2797,7 @@ fn garbage_collection_after_slashing() { &[Perbill::from_percent(10)], ); - assert_eq!(asset::free_balance::(&11), 2000 - 200); + assert_eq!(asset::stakeable_balance::(&11), 2000 - 200); assert!(SlashingSpans::::get(&11).is_some()); assert_eq!(SpanSlash::::get(&(11, 0)).amount(), &200); @@ -2809,7 +2812,7 @@ fn garbage_collection_after_slashing() { // validator and nominator slash in era are garbage-collected by era change, // so we don't test those here. - assert_eq!(asset::free_balance::(&11), 2); + assert_eq!(asset::stakeable_balance::(&11), 2); assert_eq!(asset::total_balance::(&11), 2); let slashing_spans = SlashingSpans::::get(&11).unwrap(); @@ -2834,11 +2837,11 @@ fn garbage_collection_on_window_pruning() { ExtBuilder::default().build_and_execute(|| { mock::start_active_era(1); - assert_eq!(asset::free_balance::(&11), 1000); + assert_eq!(asset::stakeable_balance::(&11), 1000); let now = active_era(); let exposure = Staking::eras_stakers(now, &11); - assert_eq!(asset::free_balance::(&101), 2000); + assert_eq!(asset::stakeable_balance::(&101), 2000); let nominated_value = exposure.others.iter().find(|o| o.who == 101).unwrap().value; on_offence_now( @@ -2849,8 +2852,8 @@ fn garbage_collection_on_window_pruning() { &[Perbill::from_percent(10)], ); - assert_eq!(asset::free_balance::(&11), 900); - assert_eq!(asset::free_balance::(&101), 2000 - (nominated_value / 10)); + assert_eq!(asset::stakeable_balance::(&11), 900); + assert_eq!(asset::stakeable_balance::(&101), 2000 - (nominated_value / 10)); assert!(ValidatorSlashInEra::::get(&now, &11).is_some()); assert!(NominatorSlashInEra::::get(&now, &101).is_some()); @@ -2875,9 +2878,9 @@ fn slashing_nominators_by_span_max() { mock::start_active_era(2); mock::start_active_era(3); - assert_eq!(asset::free_balance::(&11), 1000); - assert_eq!(asset::free_balance::(&21), 2000); - assert_eq!(asset::free_balance::(&101), 2000); + assert_eq!(asset::stakeable_balance::(&11), 1000); + assert_eq!(asset::stakeable_balance::(&21), 2000); + assert_eq!(asset::stakeable_balance::(&101), 2000); assert_eq!(Staking::slashable_balance_of(&21), 1000); let exposure_11 = Staking::eras_stakers(active_era(), &11); @@ -2894,10 +2897,10 @@ fn slashing_nominators_by_span_max() { 2, ); - assert_eq!(asset::free_balance::(&11), 900); + assert_eq!(asset::stakeable_balance::(&11), 900); let slash_1_amount = Perbill::from_percent(10) * nominated_value_11; - assert_eq!(asset::free_balance::(&101), 2000 - slash_1_amount); + assert_eq!(asset::stakeable_balance::(&101), 2000 - slash_1_amount); let expected_spans = vec![ slashing::SlashingSpan { index: 1, start: 4, length: None }, @@ -2921,14 +2924,14 @@ fn slashing_nominators_by_span_max() { ); // 11 was not further slashed, but 21 and 101 were. - assert_eq!(asset::free_balance::(&11), 900); - assert_eq!(asset::free_balance::(&21), 1700); + assert_eq!(asset::stakeable_balance::(&11), 900); + assert_eq!(asset::stakeable_balance::(&21), 1700); let slash_2_amount = Perbill::from_percent(30) * nominated_value_21; assert!(slash_2_amount > slash_1_amount); // only the maximum slash in a single span is taken. - assert_eq!(asset::free_balance::(&101), 2000 - slash_2_amount); + assert_eq!(asset::stakeable_balance::(&101), 2000 - slash_2_amount); // third slash: in same era and on same validator as first, higher // in-era value, but lower slash value than slash 2. @@ -2942,15 +2945,15 @@ fn slashing_nominators_by_span_max() { ); // 11 was further slashed, but 21 and 101 were not. - assert_eq!(asset::free_balance::(&11), 800); - assert_eq!(asset::free_balance::(&21), 1700); + assert_eq!(asset::stakeable_balance::(&11), 800); + assert_eq!(asset::stakeable_balance::(&21), 1700); let slash_3_amount = Perbill::from_percent(20) * nominated_value_21; assert!(slash_3_amount < slash_2_amount); assert!(slash_3_amount > slash_1_amount); // only the maximum slash in a single span is taken. - assert_eq!(asset::free_balance::(&101), 2000 - slash_2_amount); + assert_eq!(asset::stakeable_balance::(&101), 2000 - slash_2_amount); }); } @@ -2961,7 +2964,7 @@ fn slashes_are_summed_across_spans() { mock::start_active_era(2); mock::start_active_era(3); - assert_eq!(asset::free_balance::(&21), 2000); + assert_eq!(asset::stakeable_balance::(&21), 2000); assert_eq!(Staking::slashable_balance_of(&21), 1000); let get_span = |account| SlashingSpans::::get(&account).unwrap(); @@ -2980,7 +2983,7 @@ fn slashes_are_summed_across_spans() { ]; assert_eq!(get_span(21).iter().collect::>(), expected_spans); - assert_eq!(asset::free_balance::(&21), 1900); + assert_eq!(asset::stakeable_balance::(&21), 1900); // 21 has been force-chilled. re-signal intent to validate. Staking::validate(RuntimeOrigin::signed(21), Default::default()).unwrap(); @@ -3004,7 +3007,7 @@ fn slashes_are_summed_across_spans() { ]; assert_eq!(get_span(21).iter().collect::>(), expected_spans); - assert_eq!(asset::free_balance::(&21), 1810); + assert_eq!(asset::stakeable_balance::(&21), 1810); }); } @@ -3013,10 +3016,10 @@ fn deferred_slashes_are_deferred() { ExtBuilder::default().slash_defer_duration(2).build_and_execute(|| { mock::start_active_era(1); - assert_eq!(asset::free_balance::(&11), 1000); + assert_eq!(asset::stakeable_balance::(&11), 1000); let exposure = Staking::eras_stakers(active_era(), &11); - assert_eq!(asset::free_balance::(&101), 2000); + assert_eq!(asset::stakeable_balance::(&101), 2000); let nominated_value = exposure.others.iter().find(|o| o.who == 101).unwrap().value; System::reset_events(); @@ -3032,25 +3035,25 @@ fn deferred_slashes_are_deferred() { // nominations are not removed regardless of the deferring. assert_eq!(Staking::nominators(101).unwrap().targets, vec![11, 21]); - assert_eq!(asset::free_balance::(&11), 1000); - assert_eq!(asset::free_balance::(&101), 2000); + assert_eq!(asset::stakeable_balance::(&11), 1000); + assert_eq!(asset::stakeable_balance::(&101), 2000); mock::start_active_era(2); - assert_eq!(asset::free_balance::(&11), 1000); - assert_eq!(asset::free_balance::(&101), 2000); + assert_eq!(asset::stakeable_balance::(&11), 1000); + assert_eq!(asset::stakeable_balance::(&101), 2000); mock::start_active_era(3); - assert_eq!(asset::free_balance::(&11), 1000); - assert_eq!(asset::free_balance::(&101), 2000); + assert_eq!(asset::stakeable_balance::(&11), 1000); + assert_eq!(asset::stakeable_balance::(&101), 2000); // at the start of era 4, slashes from era 1 are processed, // after being deferred for at least 2 full eras. mock::start_active_era(4); - assert_eq!(asset::free_balance::(&11), 900); - assert_eq!(asset::free_balance::(&101), 2000 - (nominated_value / 10)); + assert_eq!(asset::stakeable_balance::(&11), 900); + assert_eq!(asset::stakeable_balance::(&101), 2000 - (nominated_value / 10)); assert!(matches!( staking_events_since_last_call().as_slice(), @@ -3148,8 +3151,8 @@ fn staker_cannot_bail_deferred_slash() { ExtBuilder::default().slash_defer_duration(2).build_and_execute(|| { mock::start_active_era(1); - assert_eq!(asset::free_balance::(&11), 1000); - assert_eq!(asset::free_balance::(&101), 2000); + assert_eq!(asset::stakeable_balance::(&11), 1000); + assert_eq!(asset::stakeable_balance::(&101), 2000); let exposure = Staking::eras_stakers(active_era(), &11); let nominated_value = exposure.others.iter().find(|o| o.who == 101).unwrap().value; @@ -3181,20 +3184,20 @@ fn staker_cannot_bail_deferred_slash() { ); // no slash yet. - assert_eq!(asset::free_balance::(&11), 1000); - assert_eq!(asset::free_balance::(&101), 2000); + assert_eq!(asset::stakeable_balance::(&11), 1000); + assert_eq!(asset::stakeable_balance::(&101), 2000); // no slash yet. mock::start_active_era(2); - assert_eq!(asset::free_balance::(&11), 1000); - assert_eq!(asset::free_balance::(&101), 2000); + assert_eq!(asset::stakeable_balance::(&11), 1000); + assert_eq!(asset::stakeable_balance::(&101), 2000); assert_eq!(Staking::current_era().unwrap(), 2); assert_eq!(active_era(), 2); // no slash yet. mock::start_active_era(3); - assert_eq!(asset::free_balance::(&11), 1000); - assert_eq!(asset::free_balance::(&101), 2000); + assert_eq!(asset::stakeable_balance::(&11), 1000); + assert_eq!(asset::stakeable_balance::(&101), 2000); assert_eq!(Staking::current_era().unwrap(), 3); assert_eq!(active_era(), 3); @@ -3211,8 +3214,8 @@ fn staker_cannot_bail_deferred_slash() { // after being deferred for at least 2 full eras. mock::start_active_era(4); - assert_eq!(asset::free_balance::(&11), 900); - assert_eq!(asset::free_balance::(&101), 2000 - (nominated_value / 10)); + assert_eq!(asset::stakeable_balance::(&11), 900); + assert_eq!(asset::stakeable_balance::(&101), 2000 - (nominated_value / 10)); // and the leftover of the funds can now be unbonded. }) @@ -3223,10 +3226,10 @@ fn remove_deferred() { ExtBuilder::default().slash_defer_duration(2).build_and_execute(|| { mock::start_active_era(1); - assert_eq!(asset::free_balance::(&11), 1000); + assert_eq!(asset::stakeable_balance::(&11), 1000); let exposure = Staking::eras_stakers(active_era(), &11); - assert_eq!(asset::free_balance::(&101), 2000); + assert_eq!(asset::stakeable_balance::(&101), 2000); let nominated_value = exposure.others.iter().find(|o| o.who == 101).unwrap().value; // deferred to start of era 4. @@ -3235,8 +3238,8 @@ fn remove_deferred() { &[Perbill::from_percent(10)], ); - assert_eq!(asset::free_balance::(&11), 1000); - assert_eq!(asset::free_balance::(&101), 2000); + assert_eq!(asset::stakeable_balance::(&11), 1000); + assert_eq!(asset::stakeable_balance::(&101), 2000); mock::start_active_era(2); @@ -3257,13 +3260,13 @@ fn remove_deferred() { // cancel one of them. assert_ok!(Staking::cancel_deferred_slash(RuntimeOrigin::root(), 4, vec![0])); - assert_eq!(asset::free_balance::(&11), 1000); - assert_eq!(asset::free_balance::(&101), 2000); + assert_eq!(asset::stakeable_balance::(&11), 1000); + assert_eq!(asset::stakeable_balance::(&101), 2000); mock::start_active_era(3); - assert_eq!(asset::free_balance::(&11), 1000); - assert_eq!(asset::free_balance::(&101), 2000); + assert_eq!(asset::stakeable_balance::(&11), 1000); + assert_eq!(asset::stakeable_balance::(&101), 2000); // at the start of era 4, slashes from era 1 are processed, // after being deferred for at least 2 full eras. @@ -3288,8 +3291,8 @@ fn remove_deferred() { let actual_slash = total_slash - initial_slash; // 5% slash (15 - 10) processed now. - assert_eq!(asset::free_balance::(&11), 950); - assert_eq!(asset::free_balance::(&101), 2000 - actual_slash); + assert_eq!(asset::stakeable_balance::(&11), 950); + assert_eq!(asset::stakeable_balance::(&101), 2000 - actual_slash); }) } @@ -3298,10 +3301,10 @@ fn remove_multi_deferred() { ExtBuilder::default().slash_defer_duration(2).build_and_execute(|| { mock::start_active_era(1); - assert_eq!(asset::free_balance::(&11), 1000); + assert_eq!(asset::stakeable_balance::(&11), 1000); let exposure = Staking::eras_stakers(active_era(), &11); - assert_eq!(asset::free_balance::(&101), 2000); + assert_eq!(asset::stakeable_balance::(&101), 2000); on_offence_now( &[OffenceDetails { offender: (11, exposure.clone()), reporters: vec![] }], @@ -3371,8 +3374,8 @@ fn slash_kicks_validators_not_nominators_and_disables_nominator_for_kicked_valid assert_eq_uvec!(Session::validators(), vec![11, 21, 31, 41, 51, 201, 202]); // pre-slash balance - assert_eq!(asset::free_balance::(&11), 1000); - assert_eq!(asset::free_balance::(&101), 2000); + assert_eq!(asset::stakeable_balance::(&11), 1000); + assert_eq!(asset::stakeable_balance::(&101), 2000); // 100 has approval for 11 as of now assert!(Staking::nominators(101).unwrap().targets.contains(&11)); @@ -3406,8 +3409,8 @@ fn slash_kicks_validators_not_nominators_and_disables_nominator_for_kicked_valid // post-slash balance let nominator_slash_amount_11 = 125 / 10; - assert_eq!(asset::free_balance::(&11), 900); - assert_eq!(asset::free_balance::(&101), 2000 - nominator_slash_amount_11); + assert_eq!(asset::stakeable_balance::(&11), 900); + assert_eq!(asset::stakeable_balance::(&101), 2000 - nominator_slash_amount_11); // check that validator was disabled. assert!(is_disabled(11)); @@ -3757,18 +3760,18 @@ fn zero_slash_keeps_nominators() { .build_and_execute(|| { mock::start_active_era(1); - assert_eq!(asset::free_balance::(&11), 1000); + assert_eq!(asset::stakeable_balance::(&11), 1000); let exposure = Staking::eras_stakers(active_era(), &11); - assert_eq!(asset::free_balance::(&101), 2000); + assert_eq!(asset::stakeable_balance::(&101), 2000); on_offence_now( &[OffenceDetails { offender: (11, exposure.clone()), reporters: vec![] }], &[Perbill::from_percent(0)], ); - assert_eq!(asset::free_balance::(&11), 1000); - assert_eq!(asset::free_balance::(&101), 2000); + assert_eq!(asset::stakeable_balance::(&11), 1000); + assert_eq!(asset::stakeable_balance::(&101), 2000); // 11 is not removed but disabled assert!(Validators::::iter().any(|(stash, _)| stash == 11)); @@ -3845,7 +3848,7 @@ fn test_nominators_over_max_exposure_page_size_are_rewarded() { for i in 0..=MaxExposurePageSize::get() { let stash = 10_000 + i as AccountId; let balance = 10_000 + i as Balance; - asset::set_balance::(&stash, balance); + asset::set_stakeable_balance::(&stash, balance); assert_ok!(Staking::bond( RuntimeOrigin::signed(stash), balance, @@ -3867,13 +3870,13 @@ fn test_nominators_over_max_exposure_page_size_are_rewarded() { while i < MaxExposurePageSize::get() { let stash = 10_000 + i as AccountId; let balance = 10_000 + i as Balance; - assert!(asset::free_balance::(&stash) > balance); + assert!(asset::stakeable_balance::(&stash) > balance); i += 1; } // Assert overflowing nominators from page 1 are also rewarded let stash = 10_000 + i as AccountId; - assert!(asset::free_balance::(&stash) > (10_000 + i) as Balance); + assert!(asset::stakeable_balance::(&stash) > (10_000 + i) as Balance); }); } @@ -3886,7 +3889,7 @@ fn test_nominators_are_rewarded_for_all_exposure_page() { for i in 0..nominator_count { let stash = 10_000 + i as AccountId; let balance = 10_000 + i as Balance; - asset::set_balance::(&stash, balance); + asset::set_stakeable_balance::(&stash, balance); assert_ok!(Staking::bond( RuntimeOrigin::signed(stash), balance, @@ -3908,9 +3911,10 @@ fn test_nominators_are_rewarded_for_all_exposure_page() { // Assert all nominators are rewarded according to their stake for i in 0..nominator_count { // balance of the nominator after the reward payout. - let current_balance = asset::free_balance::(&((10000 + i) as AccountId)); + let current_balance = asset::stakeable_balance::(&((10000 + i) as AccountId)); // balance of the nominator in the previous iteration. - let previous_balance = asset::free_balance::(&((10000 + i - 1) as AccountId)); + let previous_balance = + asset::stakeable_balance::(&((10000 + i - 1) as AccountId)); // balance before the reward. let original_balance = 10_000 + i as Balance; @@ -3966,7 +3970,7 @@ fn test_multi_page_payout_stakers_by_page() { RewardOnUnbalanceWasCalled::set(false); System::reset_events(); - let controller_balance_before_p0_payout = asset::free_balance::(&11); + let controller_balance_before_p0_payout = asset::stakeable_balance::(&11); // Payout rewards for first exposure page assert_ok!(Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, 1, 0)); @@ -3980,7 +3984,7 @@ fn test_multi_page_payout_stakers_by_page() { ] )); - let controller_balance_after_p0_payout = asset::free_balance::(&11); + let controller_balance_after_p0_payout = asset::stakeable_balance::(&11); // verify rewards have been paid out but still some left assert!(pallet_balances::TotalIssuance::::get() > pre_payout_total_issuance); @@ -4004,7 +4008,7 @@ fn test_multi_page_payout_stakers_by_page() { ] )); // verify the validator was not rewarded the second time - assert_eq!(asset::free_balance::(&11), controller_balance_after_p0_payout); + assert_eq!(asset::stakeable_balance::(&11), controller_balance_after_p0_payout); // verify all rewards have been paid out assert_eq_error_rate!( @@ -4015,9 +4019,9 @@ fn test_multi_page_payout_stakers_by_page() { assert!(RewardOnUnbalanceWasCalled::get()); // Top 64 nominators of validator 11 automatically paid out, including the validator - assert!(asset::free_balance::(&11) > balance); + assert!(asset::stakeable_balance::(&11) > balance); for i in 0..100 { - assert!(asset::free_balance::(&(1000 + i)) > balance + i as Balance); + assert!(asset::stakeable_balance::(&(1000 + i)) > balance + i as Balance); } // verify we no longer track rewards in `legacy_claimed_rewards` vec @@ -4186,7 +4190,7 @@ fn test_multi_page_payout_stakers_backward_compatible() { let pre_payout_total_issuance = pallet_balances::TotalIssuance::::get(); RewardOnUnbalanceWasCalled::set(false); - let controller_balance_before_p0_payout = asset::free_balance::(&11); + let controller_balance_before_p0_payout = asset::stakeable_balance::(&11); // Payout rewards for first exposure page assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 1)); // page 0 is claimed @@ -4195,7 +4199,7 @@ fn test_multi_page_payout_stakers_backward_compatible() { Error::::AlreadyClaimed.with_weight(err_weight) ); - let controller_balance_after_p0_payout = asset::free_balance::(&11); + let controller_balance_after_p0_payout = asset::stakeable_balance::(&11); // verify rewards have been paid out but still some left assert!(pallet_balances::TotalIssuance::::get() > pre_payout_total_issuance); @@ -4214,7 +4218,7 @@ fn test_multi_page_payout_stakers_backward_compatible() { ); // verify the validator was not rewarded the second time - assert_eq!(asset::free_balance::(&11), controller_balance_after_p0_payout); + assert_eq!(asset::stakeable_balance::(&11), controller_balance_after_p0_payout); // verify all rewards have been paid out assert_eq_error_rate!( @@ -4226,9 +4230,9 @@ fn test_multi_page_payout_stakers_backward_compatible() { // verify all nominators of validator 11 are paid out, including the validator // Validator payout goes to controller. - assert!(asset::free_balance::(&11) > balance); + assert!(asset::stakeable_balance::(&11) > balance); for i in 0..100 { - assert!(asset::free_balance::(&(1000 + i)) > balance + i as Balance); + assert!(asset::stakeable_balance::(&(1000 + i)) > balance + i as Balance); } // verify we no longer track rewards in `legacy_claimed_rewards` vec @@ -4586,25 +4590,29 @@ fn test_commission_paid_across_pages() { let payout = current_total_payout_for_duration(reward_time_per_era()); mock::start_active_era(2); - let initial_balance = asset::free_balance::(&11); + let initial_balance = asset::stakeable_balance::(&11); // Payout rewards for first exposure page assert_ok!(Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, 1, 0)); - let controller_balance_after_p0_payout = asset::free_balance::(&11); + let controller_balance_after_p0_payout = asset::stakeable_balance::(&11); // some commission is paid assert!(initial_balance < controller_balance_after_p0_payout); // payout all pages for i in 1..4 { - let before_balance = asset::free_balance::(&11); + let before_balance = asset::stakeable_balance::(&11); assert_ok!(Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, 1, i)); - let after_balance = asset::free_balance::(&11); + let after_balance = asset::stakeable_balance::(&11); // some commission is paid for every page assert!(before_balance < after_balance); } - assert_eq_error_rate!(asset::free_balance::(&11), initial_balance + payout / 2, 1,); + assert_eq_error_rate!( + asset::stakeable_balance::(&11), + initial_balance + payout / 2, + 1, + ); }); } @@ -4860,7 +4868,7 @@ fn payout_to_any_account_works() { assert_ok!(Staking::set_payee(RuntimeOrigin::signed(1234), RewardDestination::Account(42))); // Reward Destination account doesn't exist - assert_eq!(asset::free_balance::(&42), 0); + assert_eq!(asset::stakeable_balance::(&42), 0); mock::start_active_era(1); Staking::reward_by_ids(vec![(11, 1)]); @@ -4870,7 +4878,7 @@ fn payout_to_any_account_works() { assert_ok!(Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, 1, 0)); // Payment is successful - assert!(asset::free_balance::(&42) > 0); + assert!(asset::stakeable_balance::(&42) > 0); }) } @@ -5669,9 +5677,9 @@ fn chill_other_works() { let a = 4 * i; let b = 4 * i + 2; let c = 4 * i + 3; - asset::set_balance::(&a, 100_000); - asset::set_balance::(&b, 100_000); - asset::set_balance::(&c, 100_000); + asset::set_stakeable_balance::(&a, 100_000); + asset::set_stakeable_balance::(&b, 100_000); + asset::set_stakeable_balance::(&c, 100_000); // Nominator assert_ok!(Staking::bond(RuntimeOrigin::signed(a), 1000, RewardDestination::Stash)); @@ -6867,7 +6875,7 @@ fn test_runtime_api_pending_rewards() { // Set staker for v in validator_one..=validator_three { - let _ = asset::set_balance::(&v, stake); + let _ = asset::set_stakeable_balance::(&v, stake); assert_ok!(Staking::bond(RuntimeOrigin::signed(v), stake, RewardDestination::Staked)); } @@ -7094,7 +7102,7 @@ mod staking_unchecked { fn virtual_bond_does_not_lock() { ExtBuilder::default().build_and_execute(|| { mock::start_active_era(1); - assert_eq!(asset::free_balance::(&10), 1); + assert_eq!(asset::stakeable_balance::(&10), 1); // 10 can bond more than its balance amount since we do not require lock for virtual // bonding. assert_ok!(::virtual_bond(&10, 100, &15)); @@ -7226,7 +7234,7 @@ mod staking_unchecked { fn migrate_virtual_staker() { ExtBuilder::default().build_and_execute(|| { // give some balance to 200 - asset::set_balance::(&200, 2000); + asset::set_stakeable_balance::(&200, 2000); // stake assert_ok!(Staking::bond(RuntimeOrigin::signed(200), 1000, RewardDestination::Staked)); @@ -7308,7 +7316,7 @@ mod staking_unchecked { assert!(is_disabled(11)); // but virtual nominator's balance is not slashed. - assert_eq!(asset::free_balance::(&101), nominator_balance); + assert_eq!(asset::stakeable_balance::(&101), nominator_balance); // but slash is broadcasted to slash observers. assert_eq!(SlashObserver::get().get(&101).unwrap(), &nominator_share); }) @@ -7340,9 +7348,9 @@ mod staking_unchecked { assert_ok!(::set_payee(&101, &102)); // cache values - let validator_balance = asset::free_balance::(&11); + let validator_balance = asset::stakeable_balance::(&11); let validator_stake = Staking::ledger(11.into()).unwrap().total; - let nominator_balance = asset::free_balance::(&101); + let nominator_balance = asset::stakeable_balance::(&101); let nominator_stake = Staking::ledger(101.into()).unwrap().total; // 11 goes offline @@ -7361,14 +7369,14 @@ mod staking_unchecked { // all validator stake is slashed assert_eq_error_rate!( validator_balance - validator_stake, - asset::free_balance::(&11), + asset::stakeable_balance::(&11), 1 ); // Because slashing happened. assert!(is_disabled(11)); // Virtual nominator's balance is not slashed. - assert_eq!(asset::free_balance::(&101), nominator_balance); + assert_eq!(asset::stakeable_balance::(&101), nominator_balance); // Slash is broadcasted to slash observers. assert_eq!(SlashObserver::get().get(&101).unwrap(), &nominator_stake); From 851c5f3e0441ed07cb8d224e3ccd409f31ea209e Mon Sep 17 00:00:00 2001 From: Ankan Date: Tue, 27 Aug 2024 13:20:54 +0200 Subject: [PATCH 015/142] reorder --- substrate/frame/staking/src/asset.rs | 34 ++++++++++++++-------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/substrate/frame/staking/src/asset.rs b/substrate/frame/staking/src/asset.rs index c907931d0a5e..8d125cd0034b 100644 --- a/substrate/frame/staking/src/asset.rs +++ b/substrate/frame/staking/src/asset.rs @@ -14,17 +14,9 @@ pub fn total_issuance() -> BalanceOf { T::Currency::total_issuance() } -/// Set balance that can be staked for `who`. -/// -/// This includes any balance that is already staked. -pub fn set_stakeable_balance(who: &T::AccountId, value: BalanceOf) { - T::Currency::make_free_balance_be(who, value); -} - -/// Burn the amount from the total issuance. -#[cfg(feature = "runtime-benchmarks")] -pub fn burn(amount: BalanceOf) -> PositiveImbalanceOf { - T::Currency::burn(amount) +/// Total balance of `who`. Includes both, free and reserved. +pub fn total_balance(who: &T::AccountId) -> BalanceOf { + T::Currency::total_balance(who) } /// Stakeable balance of `who`. @@ -34,18 +26,20 @@ pub fn stakeable_balance(who: &T::AccountId) -> BalanceOf { T::Currency::free_balance(who) } -/// Total balance of an account. Includes both, free and reserved. -pub fn total_balance(who: &T::AccountId) -> BalanceOf { - T::Currency::total_balance(who) -} - -/// Balance of `who` that is at stake. +/// Balance of `who` that is currently at stake. /// /// The staked amount is locked and cannot be transferred out of `who`s account. pub fn staked(who: &T::AccountId) -> BalanceOf { T::Currency::balance_locked(crate::STAKING_ID, who) } +/// Set balance that can be staked for `who`. +/// +/// This includes any balance that is already staked. +pub fn set_stakeable_balance(who: &T::AccountId, value: BalanceOf) { + T::Currency::make_free_balance_be(who, value); +} + /// Update `amount` at stake for `who`. /// /// Overwrites the existing stake amount. If passed amount is lower than the existing stake, the @@ -104,3 +98,9 @@ pub fn deposit_slashed(who: &T::AccountId, value: NegativeImbalanceOf pub fn issue(value: BalanceOf) -> NegativeImbalanceOf { T::Currency::issue(value) } + +/// Burn the amount from the total issuance. +#[cfg(feature = "runtime-benchmarks")] +pub fn burn(amount: BalanceOf) -> PositiveImbalanceOf { + T::Currency::burn(amount) +} From c92a0bd907afb421a07f7ffd0e11e0bc673a6d29 Mon Sep 17 00:00:00 2001 From: Ankan Date: Sun, 18 Aug 2024 23:07:14 +0200 Subject: [PATCH 016/142] add fungible to config balance hold checks both frozen and reserved wip: around 25 tests failing check Holds instead of locks 20 tests failing fmt 11 fails 4 fails 2 failing 1 fail all tests pass but pending a hygiene check of code fix compile minor refactor remove T::Currency calls from asset mod --- substrate/frame/staking/src/asset.rs | 70 +++++++++++++-------- substrate/frame/staking/src/benchmarking.rs | 4 +- substrate/frame/staking/src/ledger.rs | 5 +- substrate/frame/staking/src/lib.rs | 13 ++-- substrate/frame/staking/src/mock.rs | 16 ++--- substrate/frame/staking/src/pallet/impls.rs | 4 +- substrate/frame/staking/src/pallet/mod.rs | 38 ++++++++++- substrate/frame/staking/src/tests.rs | 33 ++++++---- 8 files changed, 123 insertions(+), 60 deletions(-) diff --git a/substrate/frame/staking/src/asset.rs b/substrate/frame/staking/src/asset.rs index 8d125cd0034b..e4bc82ed6ba9 100644 --- a/substrate/frame/staking/src/asset.rs +++ b/substrate/frame/staking/src/asset.rs @@ -1,63 +1,79 @@ //! Facade of currency implementation. Useful while migrating from old to new currency system. -use frame_support::traits::{Currency, InspectLockableCurrency, LockableCurrency}; - -use crate::{BalanceOf, Config, NegativeImbalanceOf, PositiveImbalanceOf}; +use frame_support::traits::{ + fungible::{ + hold::{Balanced as FunHoldBalanced, Inspect as FunHoldInspect, Mutate as FunHoldMutate}, + Balanced, Inspect as FunInspect, Mutate as FunMutate, + }, + tokens::{Fortitude, Precision}, + Currency, Imbalance, InspectLockableCurrency, LockableCurrency, +}; +use sp_runtime::{traits::Zero, DispatchResult}; + +use crate::{BalanceOf, Config, Error, HoldReason, NegativeImbalanceOf, PositiveImbalanceOf}; /// Existential deposit for the chain. pub fn existential_deposit() -> BalanceOf { - T::Currency::minimum_balance() + T::Fungible::minimum_balance() } /// Total issuance of the chain. pub fn total_issuance() -> BalanceOf { - T::Currency::total_issuance() + T::Fungible::total_issuance() } /// Total balance of `who`. Includes both, free and reserved. pub fn total_balance(who: &T::AccountId) -> BalanceOf { - T::Currency::total_balance(who) + T::Fungible::total_balance(who) } /// Stakeable balance of `who`. /// /// This includes balance free to stake along with any balance that is already staked. pub fn stakeable_balance(who: &T::AccountId) -> BalanceOf { - T::Currency::free_balance(who) + T::Fungible::balance(who) + T::Fungible::balance_on_hold(&HoldReason::Staking.into(), who) } /// Balance of `who` that is currently at stake. /// /// The staked amount is locked and cannot be transferred out of `who`s account. pub fn staked(who: &T::AccountId) -> BalanceOf { - T::Currency::balance_locked(crate::STAKING_ID, who) + T::Fungible::balance_on_hold(&HoldReason::Staking.into(), who) } /// Set balance that can be staked for `who`. /// /// This includes any balance that is already staked. +#[cfg(any(test, feature = "runtime-benchmarks"))] pub fn set_stakeable_balance(who: &T::AccountId, value: BalanceOf) { - T::Currency::make_free_balance_be(who, value); + let reserved_balance = staked::(who); + if reserved_balance < value { + let _ = T::Fungible::set_balance(who, value - reserved_balance); + } else { + update_stake::(who, value).expect("can remove from what is staked"); + // burn all free + let _ = T::Fungible::set_balance(who, Zero::zero()); + } + + assert!(total_balance::(who) == value); } /// Update `amount` at stake for `who`. /// /// Overwrites the existing stake amount. If passed amount is lower than the existing stake, the /// difference is unlocked. -pub fn update_stake(who: &T::AccountId, amount: BalanceOf) { - T::Currency::set_lock( - crate::STAKING_ID, - who, - amount, - frame_support::traits::WithdrawReasons::all(), - ); +pub fn update_stake(who: &T::AccountId, amount: BalanceOf) -> DispatchResult { + // if first stake, inc provider. + if staked::(who) == Zero::zero() && amount > Zero::zero() { + frame_system::Pallet::::inc_providers(who); + } + + T::Fungible::set_on_hold(&HoldReason::Staking.into(), who, amount) } -/// Kill the stake of `who`. -/// -/// All locked amount is unlocked. -pub fn kill_stake(who: &T::AccountId) { - T::Currency::remove_lock(crate::STAKING_ID, who); +pub fn kill_stake(who: &T::AccountId) -> DispatchResult { + let _ = frame_system::Pallet::::dec_providers(who); + T::Fungible::release_all(&HoldReason::Staking.into(), who, Precision::BestEffort).map(|_| ()) } /// Slash the value from `who`. @@ -67,7 +83,7 @@ pub fn slash( who: &T::AccountId, value: BalanceOf, ) -> (NegativeImbalanceOf, BalanceOf) { - T::Currency::slash(who, value) + T::Fungible::slash(&HoldReason::Staking.into(), who, value) } /// Mint reward into an existing account. @@ -77,30 +93,30 @@ pub fn mint_existing( who: &T::AccountId, value: BalanceOf, ) -> Option> { - T::Currency::deposit_into_existing(who, value).ok() + T::Fungible::deposit(who, value, Precision::Exact).ok() } /// Mint reward and create account for `who` if it does not exist. /// /// This does not increase the total issuance. pub fn mint_creating(who: &T::AccountId, value: BalanceOf) -> PositiveImbalanceOf { - T::Currency::deposit_creating(who, value) + T::Fungible::deposit(who, value, Precision::Exact).unwrap_or_default() } /// Deposit newly issued or slashed `value` into `who`. pub fn deposit_slashed(who: &T::AccountId, value: NegativeImbalanceOf) { - T::Currency::resolve_creating(who, value) + let _ = T::Fungible::resolve(who, value); } /// Issue `value` increasing total issuance. /// /// Creates a negative imbalance. pub fn issue(value: BalanceOf) -> NegativeImbalanceOf { - T::Currency::issue(value) + T::Fungible::issue(value) } /// Burn the amount from the total issuance. #[cfg(feature = "runtime-benchmarks")] pub fn burn(amount: BalanceOf) -> PositiveImbalanceOf { - T::Currency::burn(amount) + T::Fungible::rescind(amount) } diff --git a/substrate/frame/staking/src/benchmarking.rs b/substrate/frame/staking/src/benchmarking.rs index e4b5cfccd0b4..e32bd7540cc0 100644 --- a/substrate/frame/staking/src/benchmarking.rs +++ b/substrate/frame/staking/src/benchmarking.rs @@ -1019,14 +1019,14 @@ mod tests { let current_era = CurrentEra::::get().unwrap(); - let original_free_balance = Balances::free_balance(&validator_stash); + let original_free_balance = asset::stakeable_balance::(&validator_stash); assert_ok!(Staking::payout_stakers_by_page( RuntimeOrigin::signed(1337), validator_stash, current_era, 0 )); - let new_free_balance = Balances::free_balance(&validator_stash); + let new_free_balance = asset::stakeable_balance::(&validator_stash); assert!(original_free_balance < new_free_balance); }); diff --git a/substrate/frame/staking/src/ledger.rs b/substrate/frame/staking/src/ledger.rs index ac3be04cf607..0a91c6472d20 100644 --- a/substrate/frame/staking/src/ledger.rs +++ b/substrate/frame/staking/src/ledger.rs @@ -187,7 +187,8 @@ impl StakingLedger { // We skip locking virtual stakers. if !Pallet::::is_virtual_staker(&self.stash) { // for direct stakers, update lock on stash based on ledger. - asset::update_stake::(&self.stash, self.total); + asset::update_stake::(&self.stash, self.total) + .map_err(|_| Error::::NotEnoughFunds)?; } Ledger::::insert( @@ -261,7 +262,7 @@ impl StakingLedger { // kill virtual staker if it exists. if >::take(&stash).is_none() { // if not virtual staker, clear locks. - asset::kill_stake::(&ledger.stash); + let _ = asset::kill_stake::(&ledger.stash).defensive(); } Ok(()) diff --git a/substrate/frame/staking/src/lib.rs b/substrate/frame/staking/src/lib.rs index 19d999109d8d..3bfbc11f3262 100644 --- a/substrate/frame/staking/src/lib.rs +++ b/substrate/frame/staking/src/lib.rs @@ -312,6 +312,10 @@ use codec::{Decode, Encode, HasCompact, MaxEncodedLen}; use frame_support::{ defensive, defensive_assert, traits::{ + tokens::{ + fungible::{Credit, Debt, Inspect, InspectHold}, + Fortitude, Preservation, + }, ConstU32, Currency, Defensive, DefensiveMax, DefensiveSaturating, Get, LockIdentifier, }, weights::Weight, @@ -361,12 +365,9 @@ pub type RewardPoint = u32; /// The balance type of this pallet. pub type BalanceOf = ::CurrencyBalance; -type PositiveImbalanceOf = <::Currency as Currency< - ::AccountId, ->>::PositiveImbalance; -pub type NegativeImbalanceOf = <::Currency as Currency< - ::AccountId, ->>::NegativeImbalance; +type PositiveImbalanceOf = Debt<::AccountId, ::Fungible>; +pub type NegativeImbalanceOf = + Credit<::AccountId, ::Fungible>; type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index 4a0209fc5b08..787b9ec19467 100644 --- a/substrate/frame/staking/src/mock.rs +++ b/substrate/frame/staking/src/mock.rs @@ -25,6 +25,7 @@ use frame_election_provider_support::{ use frame_support::{ assert_ok, derive_impl, ord_parameter_types, parameter_types, traits::{ + fungible::{Inspect, Mutate, MutateHold}, ConstU64, Currency, EitherOfDiverse, FindAuthor, Get, Hooks, Imbalance, LockableCurrency, OnUnbalanced, OneSessionHandler, WithdrawReasons, }, @@ -264,6 +265,7 @@ pub(crate) const DISABLING_LIMIT_FACTOR: usize = 3; #[derive_impl(crate::config_preludes::TestDefaultConfig)] impl crate::pallet::pallet::Config for Test { type Currency = Balances; + type Fungible = Balances; type UnixTime = Timestamp; type RewardRemainder = RewardRemainderMock; type Reward = MockReward; @@ -576,7 +578,7 @@ pub(crate) fn current_era() -> EraIndex { } pub(crate) fn bond(who: AccountId, val: Balance) { - let _ = Balances::make_free_balance_be(&who, val); + let _ = asset::set_stakeable_balance::(&who, val); assert_ok!(Staking::bond(RuntimeOrigin::signed(who), val, RewardDestination::Stash)); } @@ -812,7 +814,7 @@ pub(crate) fn bond_extra_no_checks(stash: &AccountId, amount: Balance) { 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()); + let _ = asset::update_stake::(stash, new_total); ledger.total = new_total; ledger.active = new_total; Ledger::::insert(controller, ledger); @@ -821,10 +823,10 @@ pub(crate) fn bond_extra_no_checks(stash: &AccountId, amount: Balance) { pub(crate) fn setup_double_bonded_ledgers() { 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); + let _ = asset::set_stakeable_balance::(&333, 2000); + let _ = asset::set_stakeable_balance::(&444, 2000); + let _ = asset::set_stakeable_balance::(&555, 2000); + let _ = asset::set_stakeable_balance::(&777, 2000); assert_ok!(Staking::bond(RuntimeOrigin::signed(333), 10, RewardDestination::Staked)); assert_ok!(Staking::bond(RuntimeOrigin::signed(444), 20, RewardDestination::Staked)); @@ -926,5 +928,5 @@ pub(crate) fn staking_events_since_last_call() -> Vec> { } pub(crate) fn balances(who: &AccountId) -> (Balance, Balance) { - (Balances::free_balance(who), Balances::reserved_balance(who)) + (asset::stakeable_balance::(who), Balances::reserved_balance(who)) } diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index 6c4fe8140e8e..797aff003243 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -1919,7 +1919,7 @@ impl StakingInterface for Pallet { impl sp_staking::StakingUnchecked for Pallet { fn migrate_to_virtual_staker(who: &Self::AccountId) { - asset::kill_stake::(who); + let _ = asset::kill_stake::(who).defensive(); VirtualStakers::::insert(who, ()); } @@ -1956,7 +1956,7 @@ impl sp_staking::StakingUnchecked for Pallet { fn migrate_to_direct_staker(who: &Self::AccountId) { assert!(VirtualStakers::::contains_key(who)); let ledger = StakingLedger::::get(Stash(who.clone())).unwrap(); - asset::update_stake::(who, ledger.total); + let _ = asset::update_stake::(who, ledger.total); VirtualStakers::::remove(who); } } diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 63861d77f368..93c042875fc0 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -25,6 +25,13 @@ use frame_election_provider_support::{ use frame_support::{ pallet_prelude::*, traits::{ + fungible::{ + hold::{ + Balanced as FunHoldBalanced, Inspect as FunHoldInspect, Mutate as FunHoldMutate, + }, + Balanced, Inspect as FunInspect, Mutate as FunMutate, + }, + tokens::Precision, Defensive, DefensiveSaturating, EnsureOrigin, EstimateNextNewSession, Get, InspectLockableCurrency, LockableCurrency, OnUnbalanced, UnixTime, }, @@ -95,6 +102,19 @@ pub mod pallet { Moment = BlockNumberFor, Balance = Self::CurrencyBalance, > + InspectLockableCurrency; + + #[pallet::no_default] + type Fungible: FunHoldMutate< + Self::AccountId, + Reason = Self::RuntimeHoldReason, + Balance = Self::CurrencyBalance, + > + FunMutate + + FunHoldBalanced; + + /// Overarching hold reason. + #[pallet::no_default_bounds] + type RuntimeHoldReason: From; + /// Just the `Currency::Balance` type; we have this item to allow us to constrain it to /// `From`. type CurrencyBalance: sp_runtime::traits::AtLeast32BitUnsigned @@ -105,6 +125,8 @@ pub mod pallet { + Default + From + TypeInfo + + Send + + Sync + MaxEncodedLen; /// Time used for computing era duration. /// @@ -308,6 +330,14 @@ pub mod pallet { type WeightInfo: WeightInfo; } + /// A reason for placing a hold on funds. + #[pallet::composite_enum] + pub enum HoldReason { + /// Funds held for stake delegation to another account. + #[codec(index = 0)] + Staking, + } + /// Default implementations of [`DefaultConfig`], which can be used to implement [`Config`]. pub mod config_preludes { use super::*; @@ -326,6 +356,8 @@ pub mod pallet { impl DefaultConfig for TestDefaultConfig { #[inject_runtime_type] type RuntimeEvent = (); + #[inject_runtime_type] + type RuntimeHoldReason = (); type CurrencyBalance = u128; type CurrencyToVote = (); type NominationsQuota = crate::FixedNominationsQuota<16>; @@ -2086,7 +2118,7 @@ pub mod pallet { let new_total = if let Some(total) = maybe_total { let new_total = total.min(stash_balance); // enforce lock == ledger.amount. - asset::update_stake::(&stash, new_total); + asset::update_stake::(&stash, new_total)?; new_total } else { current_lock @@ -2113,13 +2145,13 @@ pub mod pallet { // to enforce a new ledger.total and staking lock for this stash. let new_total = maybe_total.ok_or(Error::::CannotRestoreLedger)?.min(stash_balance); - asset::update_stake::(&stash, new_total); + asset::update_stake::(&stash, new_total)?; Ok((stash.clone(), new_total)) }, Err(Error::::BadState) => { // the stash and ledger do not exist but lock is lingering. - asset::kill_stake::(&stash); + asset::kill_stake::(&stash)?; ensure!( Self::inspect_bond_state(&stash) == Err(Error::::NotStash), Error::::BadState diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 5eb9eff39efa..6a844be32509 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -108,7 +108,7 @@ fn force_unstake_works() { // Cant transfer assert_noop!( Balances::transfer_allow_death(RuntimeOrigin::signed(11), 1, 10), - TokenError::Frozen, + TokenError::FundsUnavailable, ); // Force unstake requires root. assert_noop!(Staking::force_unstake(RuntimeOrigin::signed(11), 11, 2), BadOrigin); @@ -490,7 +490,7 @@ fn staking_should_work() { } ); // e.g. it cannot reserve more than 500 that it has free from the total 2000 - assert_noop!(Balances::reserve(&3, 501), BalancesError::::LiquidityRestrictions); + assert_noop!(Balances::reserve(&3, 501), BalancesError::::InsufficientBalance); assert_ok!(Balances::reserve(&3, 409)); }); } @@ -999,7 +999,7 @@ fn cannot_transfer_staked_balance() { // Confirm account 11 cannot transfer as a result assert_noop!( Balances::transfer_allow_death(RuntimeOrigin::signed(11), 21, 1), - TokenError::Frozen, + TokenError::FundsUnavailable, ); // Give account 11 extra free balance @@ -1024,7 +1024,7 @@ fn cannot_transfer_staked_balance_2() { // Confirm account 21 can transfer at most 1000 assert_noop!( Balances::transfer_allow_death(RuntimeOrigin::signed(21), 21, 1001), - TokenError::Frozen, + TokenError::FundsUnavailable, ); assert_ok!(Balances::transfer_allow_death(RuntimeOrigin::signed(21), 21, 1000)); }); @@ -1041,7 +1041,7 @@ fn cannot_reserve_staked_balance() { // Confirm account 11 (via controller 10) is totally staked assert_eq!(Staking::eras_stakers(active_era(), &11).own, 1000); // Confirm account 11 cannot reserve as a result - assert_noop!(Balances::reserve(&11, 1), BalancesError::::LiquidityRestrictions); + assert_noop!(Balances::reserve(&11, 1), BalancesError::::InsufficientBalance); // Give account 11 extra free balance let _ = asset::set_stakeable_balance::(&11, 10000); @@ -2077,7 +2077,7 @@ fn bond_with_no_staked_value() { ); // bonded with absolute minimum value possible. assert_ok!(Staking::bond(RuntimeOrigin::signed(1), 5, RewardDestination::Account(1))); - assert_eq!(pallet_balances::Locks::::get(&1)[0].amount, 5); + assert_eq!(pallet_balances::Holds::::get(&1)[0].amount, 5); // unbonding even 1 will cause all to be unbonded. assert_ok!(Staking::unbond(RuntimeOrigin::signed(1), 1)); @@ -2098,14 +2098,14 @@ fn bond_with_no_staked_value() { // not yet removed. assert_ok!(Staking::withdraw_unbonded(RuntimeOrigin::signed(1), 0)); assert!(Staking::ledger(1.into()).is_ok()); - assert_eq!(pallet_balances::Locks::::get(&1)[0].amount, 5); + assert_eq!(pallet_balances::Holds::::get(&1)[0].amount, 5); mock::start_active_era(3); // poof. Account 1 is removed from the staking system. assert_ok!(Staking::withdraw_unbonded(RuntimeOrigin::signed(1), 0)); assert!(Staking::ledger(1.into()).is_err()); - assert_eq!(pallet_balances::Locks::::get(&1).len(), 0); + assert_eq!(pallet_balances::Holds::::get(&1).len(), 0); }); } @@ -2340,7 +2340,18 @@ fn reward_validator_slashing_validator_does_not_overflow() { assert_ok!(Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, 0, 0)); assert_eq!(asset::total_balance::(&11), stake * 2); - // Set staker + // ensure ledger has `stake` and no more. + Ledger::::insert( + 11, + StakingLedgerInspect { + stash: 11, + total: stake, + active: stake, + unlocking: Default::default(), + legacy_claimed_rewards: bounded_vec![1], + }, + ); + // Set staker (unsafe, can reduce balance below actual stake) let _ = asset::set_stakeable_balance::(&11, stake); let _ = asset::set_stakeable_balance::(&2, stake); @@ -2812,8 +2823,8 @@ fn garbage_collection_after_slashing() { // validator and nominator slash in era are garbage-collected by era change, // so we don't test those here. - assert_eq!(asset::stakeable_balance::(&11), 2); - assert_eq!(asset::total_balance::(&11), 2); + assert_eq!(asset::stakeable_balance::(&11), 0); + assert_eq!(asset::total_balance::(&11), 0); let slashing_spans = SlashingSpans::::get(&11).unwrap(); assert_eq!(slashing_spans.iter().count(), 2); From ebf60efd978db9a2a73f796a326f3086dc93f800 Mon Sep 17 00:00:00 2001 From: Ankan Date: Tue, 27 Aug 2024 13:37:44 +0200 Subject: [PATCH 017/142] rustdoc fix --- substrate/frame/staking/src/asset.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/substrate/frame/staking/src/asset.rs b/substrate/frame/staking/src/asset.rs index e4bc82ed6ba9..606f04158560 100644 --- a/substrate/frame/staking/src/asset.rs +++ b/substrate/frame/staking/src/asset.rs @@ -43,7 +43,10 @@ pub fn staked(who: &T::AccountId) -> BalanceOf { /// Set balance that can be staked for `who`. /// -/// This includes any balance that is already staked. +/// If `value` is less than already staked, the difference is amount is unlocked. Otherwise, +/// the difference is added to free balance. +/// +/// Should only be used with test. #[cfg(any(test, feature = "runtime-benchmarks"))] pub fn set_stakeable_balance(who: &T::AccountId, value: BalanceOf) { let reserved_balance = staked::(who); From 07e3ca93bd076c1d9d56c3502ec251443b198266 Mon Sep 17 00:00:00 2001 From: Ankan Date: Tue, 27 Aug 2024 14:03:58 +0200 Subject: [PATCH 018/142] rename Fungible to Currency --- substrate/frame/staking/src/asset.rs | 30 +++++++++++------------ substrate/frame/staking/src/lib.rs | 4 +-- substrate/frame/staking/src/mock.rs | 1 - substrate/frame/staking/src/pallet/mod.rs | 9 +------ 4 files changed, 18 insertions(+), 26 deletions(-) diff --git a/substrate/frame/staking/src/asset.rs b/substrate/frame/staking/src/asset.rs index 606f04158560..a1bb9cdd2438 100644 --- a/substrate/frame/staking/src/asset.rs +++ b/substrate/frame/staking/src/asset.rs @@ -14,31 +14,31 @@ use crate::{BalanceOf, Config, Error, HoldReason, NegativeImbalanceOf, PositiveI /// Existential deposit for the chain. pub fn existential_deposit() -> BalanceOf { - T::Fungible::minimum_balance() + T::Currency::minimum_balance() } /// Total issuance of the chain. pub fn total_issuance() -> BalanceOf { - T::Fungible::total_issuance() + T::Currency::total_issuance() } /// Total balance of `who`. Includes both, free and reserved. pub fn total_balance(who: &T::AccountId) -> BalanceOf { - T::Fungible::total_balance(who) + T::Currency::total_balance(who) } /// Stakeable balance of `who`. /// /// This includes balance free to stake along with any balance that is already staked. pub fn stakeable_balance(who: &T::AccountId) -> BalanceOf { - T::Fungible::balance(who) + T::Fungible::balance_on_hold(&HoldReason::Staking.into(), who) + T::Currency::balance(who) + T::Currency::balance_on_hold(&HoldReason::Staking.into(), who) } /// Balance of `who` that is currently at stake. /// /// The staked amount is locked and cannot be transferred out of `who`s account. pub fn staked(who: &T::AccountId) -> BalanceOf { - T::Fungible::balance_on_hold(&HoldReason::Staking.into(), who) + T::Currency::balance_on_hold(&HoldReason::Staking.into(), who) } /// Set balance that can be staked for `who`. @@ -51,11 +51,11 @@ pub fn staked(who: &T::AccountId) -> BalanceOf { pub fn set_stakeable_balance(who: &T::AccountId, value: BalanceOf) { let reserved_balance = staked::(who); if reserved_balance < value { - let _ = T::Fungible::set_balance(who, value - reserved_balance); + let _ = T::Currency::set_balance(who, value - reserved_balance); } else { update_stake::(who, value).expect("can remove from what is staked"); // burn all free - let _ = T::Fungible::set_balance(who, Zero::zero()); + let _ = T::Currency::set_balance(who, Zero::zero()); } assert!(total_balance::(who) == value); @@ -71,12 +71,12 @@ pub fn update_stake(who: &T::AccountId, amount: BalanceOf) -> Disp frame_system::Pallet::::inc_providers(who); } - T::Fungible::set_on_hold(&HoldReason::Staking.into(), who, amount) + T::Currency::set_on_hold(&HoldReason::Staking.into(), who, amount) } pub fn kill_stake(who: &T::AccountId) -> DispatchResult { let _ = frame_system::Pallet::::dec_providers(who); - T::Fungible::release_all(&HoldReason::Staking.into(), who, Precision::BestEffort).map(|_| ()) + T::Currency::release_all(&HoldReason::Staking.into(), who, Precision::BestEffort).map(|_| ()) } /// Slash the value from `who`. @@ -86,7 +86,7 @@ pub fn slash( who: &T::AccountId, value: BalanceOf, ) -> (NegativeImbalanceOf, BalanceOf) { - T::Fungible::slash(&HoldReason::Staking.into(), who, value) + T::Currency::slash(&HoldReason::Staking.into(), who, value) } /// Mint reward into an existing account. @@ -96,30 +96,30 @@ pub fn mint_existing( who: &T::AccountId, value: BalanceOf, ) -> Option> { - T::Fungible::deposit(who, value, Precision::Exact).ok() + T::Currency::deposit(who, value, Precision::Exact).ok() } /// Mint reward and create account for `who` if it does not exist. /// /// This does not increase the total issuance. pub fn mint_creating(who: &T::AccountId, value: BalanceOf) -> PositiveImbalanceOf { - T::Fungible::deposit(who, value, Precision::Exact).unwrap_or_default() + T::Currency::deposit(who, value, Precision::Exact).unwrap_or_default() } /// Deposit newly issued or slashed `value` into `who`. pub fn deposit_slashed(who: &T::AccountId, value: NegativeImbalanceOf) { - let _ = T::Fungible::resolve(who, value); + let _ = T::Currency::resolve(who, value); } /// Issue `value` increasing total issuance. /// /// Creates a negative imbalance. pub fn issue(value: BalanceOf) -> NegativeImbalanceOf { - T::Fungible::issue(value) + T::Currency::issue(value) } /// Burn the amount from the total issuance. #[cfg(feature = "runtime-benchmarks")] pub fn burn(amount: BalanceOf) -> PositiveImbalanceOf { - T::Fungible::rescind(amount) + T::Currency::rescind(amount) } diff --git a/substrate/frame/staking/src/lib.rs b/substrate/frame/staking/src/lib.rs index 3bfbc11f3262..f8a708152866 100644 --- a/substrate/frame/staking/src/lib.rs +++ b/substrate/frame/staking/src/lib.rs @@ -365,9 +365,9 @@ pub type RewardPoint = u32; /// The balance type of this pallet. pub type BalanceOf = ::CurrencyBalance; -type PositiveImbalanceOf = Debt<::AccountId, ::Fungible>; +type PositiveImbalanceOf = Debt<::AccountId, ::Currency>; pub type NegativeImbalanceOf = - Credit<::AccountId, ::Fungible>; + Credit<::AccountId, ::Currency>; type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index 787b9ec19467..e952d91c9c28 100644 --- a/substrate/frame/staking/src/mock.rs +++ b/substrate/frame/staking/src/mock.rs @@ -265,7 +265,6 @@ pub(crate) const DISABLING_LIMIT_FACTOR: usize = 3; #[derive_impl(crate::config_preludes::TestDefaultConfig)] impl crate::pallet::pallet::Config for Test { type Currency = Balances; - type Fungible = Balances; type UnixTime = Timestamp; type RewardRemainder = RewardRemainderMock; type Reward = MockReward; diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 93c042875fc0..19f8a73cfbb7 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -97,14 +97,7 @@ pub mod pallet { pub trait Config: frame_system::Config { /// The staking balance. #[pallet::no_default] - type Currency: LockableCurrency< - Self::AccountId, - Moment = BlockNumberFor, - Balance = Self::CurrencyBalance, - > + InspectLockableCurrency; - - #[pallet::no_default] - type Fungible: FunHoldMutate< + type Currency: FunHoldMutate< Self::AccountId, Reason = Self::RuntimeHoldReason, Balance = Self::CurrencyBalance, From 58e8e83e133e2859080b36f208b21c64a5ebd31f Mon Sep 17 00:00:00 2001 From: Ankan Date: Tue, 27 Aug 2024 14:18:49 +0200 Subject: [PATCH 019/142] add support for fungible imbalance handler in pallet treasury --- polkadot/runtime/test-runtime/src/lib.rs | 1 + polkadot/runtime/westend/src/lib.rs | 1 + substrate/bin/node/runtime/src/lib.rs | 5 +++-- substrate/frame/treasury/src/lib.rs | 21 ++++++++++++++++++--- 4 files changed, 23 insertions(+), 5 deletions(-) diff --git a/polkadot/runtime/test-runtime/src/lib.rs b/polkadot/runtime/test-runtime/src/lib.rs index 8e34320d38f2..450517e7692d 100644 --- a/polkadot/runtime/test-runtime/src/lib.rs +++ b/polkadot/runtime/test-runtime/src/lib.rs @@ -345,6 +345,7 @@ impl pallet_staking::Config for Runtime { type UnixTime = Timestamp; type CurrencyToVote = polkadot_runtime_common::CurrencyToVote; type RewardRemainder = (); + type RuntimeHoldReason = RuntimeHoldReason; type RuntimeEvent = RuntimeEvent; type Slash = (); type Reward = (); diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index 519c7dcde54e..ea43108fe32f 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -728,6 +728,7 @@ parameter_types! { impl pallet_staking::Config for Runtime { type Currency = Balances; type CurrencyBalance = Balance; + type RuntimeHoldReason = RuntimeHoldReason; type UnixTime = Timestamp; type CurrencyToVote = CurrencyToVote; type RewardRemainder = (); diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index ef5c52bf6e6e..7249b79ac0d3 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -671,9 +671,10 @@ impl pallet_staking::Config for Runtime { type CurrencyBalance = Balance; type UnixTime = Timestamp; type CurrencyToVote = sp_staking::currency_to_vote::U128CurrencyToVote; - type RewardRemainder = Treasury; + type RewardRemainder = pallet_treasury::FungibleCompat; type RuntimeEvent = RuntimeEvent; - type Slash = Treasury; // send the slashed funds to the treasury. + type RuntimeHoldReason = RuntimeHoldReason; + type Slash = pallet_treasury::FungibleCompat; // send the slashed funds to the treasury. type Reward = (); // rewards are minted from the void type SessionsPerEra = SessionsPerEra; type BondingDuration = BondingDuration; diff --git a/substrate/frame/treasury/src/lib.rs b/substrate/frame/treasury/src/lib.rs index 3954489a2d15..f74fce028648 100644 --- a/substrate/frame/treasury/src/lib.rs +++ b/substrate/frame/treasury/src/lib.rs @@ -96,8 +96,8 @@ use frame_support::{ dispatch::{DispatchResult, DispatchResultWithPostInfo}, ensure, print, traits::{ - tokens::Pay, Currency, ExistenceRequirement::KeepAlive, Get, Imbalance, OnUnbalanced, - ReservableCurrency, WithdrawReasons, + fungible::Credit, tokens::Pay, Currency, ExistenceRequirement::KeepAlive, Get, Imbalance, + OnUnbalanced, ReservableCurrency, WithdrawReasons, }, weights::Weight, PalletId, @@ -205,7 +205,9 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { /// The staking balance. - type Currency: Currency + ReservableCurrency; + type Currency: Currency + + ReservableCurrency + + frame_support::traits::fungible::Balanced>; /// Origin from which rejections must come. type RejectOrigin: EnsureOrigin; @@ -974,6 +976,19 @@ impl, I: 'static> OnUnbalanced> for Palle } } +/// Implement the `OnUnbalanced` handler for [`frame_support::traits::fungible`] trait currency. +pub struct FungibleCompat(PhantomData); +impl OnUnbalanced> for FungibleCompat { + fn on_nonzero_unbalanced(credit: Credit) { + use frame_support::traits::fungible::Balanced; + let numeric_amount = credit.peek(); + + let _ = T::Currency::resolve(&Pallet::::account_id(), credit); + + Pallet::::deposit_event(Event::Deposit { value: numeric_amount }); + } +} + /// TypedGet implementation to get the AccountId of the Treasury. pub struct TreasuryAccountId(PhantomData); impl sp_runtime::traits::TypedGet for TreasuryAccountId From fe893a8feee4e21045babba03456f656ca30948b Mon Sep 17 00:00:00 2001 From: Ankan Date: Tue, 27 Aug 2024 14:28:05 +0200 Subject: [PATCH 020/142] add license --- substrate/frame/staking/src/asset.rs | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/substrate/frame/staking/src/asset.rs b/substrate/frame/staking/src/asset.rs index 8d125cd0034b..3c31491ce2b5 100644 --- a/substrate/frame/staking/src/asset.rs +++ b/substrate/frame/staking/src/asset.rs @@ -1,4 +1,22 @@ -//! Facade of currency implementation. Useful while migrating from old to new currency system. +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Contains all the interactions with [`Config::Currency`] to manipulate the underlying staking +//! asset. use frame_support::traits::{Currency, InspectLockableCurrency, LockableCurrency}; From a9d0345cdce0f80dcbff3097a02561d83151f304 Mon Sep 17 00:00:00 2001 From: Ankan Date: Tue, 27 Aug 2024 14:42:44 +0200 Subject: [PATCH 021/142] fix unused imports --- substrate/frame/staking/src/asset.rs | 7 +++---- substrate/frame/staking/src/lib.rs | 8 ++------ substrate/frame/staking/src/pallet/mod.rs | 11 ++++------- 3 files changed, 9 insertions(+), 17 deletions(-) diff --git a/substrate/frame/staking/src/asset.rs b/substrate/frame/staking/src/asset.rs index a1bb9cdd2438..53fb499cb7b0 100644 --- a/substrate/frame/staking/src/asset.rs +++ b/substrate/frame/staking/src/asset.rs @@ -3,14 +3,13 @@ use frame_support::traits::{ fungible::{ hold::{Balanced as FunHoldBalanced, Inspect as FunHoldInspect, Mutate as FunHoldMutate}, - Balanced, Inspect as FunInspect, Mutate as FunMutate, + Balanced, Inspect as FunInspect, }, - tokens::{Fortitude, Precision}, - Currency, Imbalance, InspectLockableCurrency, LockableCurrency, + tokens::Precision, }; use sp_runtime::{traits::Zero, DispatchResult}; -use crate::{BalanceOf, Config, Error, HoldReason, NegativeImbalanceOf, PositiveImbalanceOf}; +use crate::{BalanceOf, Config, HoldReason, NegativeImbalanceOf, PositiveImbalanceOf}; /// Existential deposit for the chain. pub fn existential_deposit() -> BalanceOf { diff --git a/substrate/frame/staking/src/lib.rs b/substrate/frame/staking/src/lib.rs index f8a708152866..73f08f9d0be3 100644 --- a/substrate/frame/staking/src/lib.rs +++ b/substrate/frame/staking/src/lib.rs @@ -312,11 +312,8 @@ use codec::{Decode, Encode, HasCompact, MaxEncodedLen}; use frame_support::{ defensive, defensive_assert, traits::{ - tokens::{ - fungible::{Credit, Debt, Inspect, InspectHold}, - Fortitude, Preservation, - }, - ConstU32, Currency, Defensive, DefensiveMax, DefensiveSaturating, Get, LockIdentifier, + tokens::fungible::{Credit, Debt}, + ConstU32, Defensive, DefensiveMax, DefensiveSaturating, Get, }, weights::Weight, BoundedVec, CloneNoBound, EqNoBound, PartialEqNoBound, RuntimeDebugNoBound, @@ -337,7 +334,6 @@ pub use weights::WeightInfo; pub use pallet::{pallet::*, UseNominatorsAndValidatorsMap, UseValidatorsMap}; -pub(crate) const STAKING_ID: LockIdentifier = *b"staking "; pub(crate) const LOG_TARGET: &str = "runtime::staking"; // syntactic sugar for logging. diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 19f8a73cfbb7..715b6b710254 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -26,14 +26,11 @@ use frame_support::{ pallet_prelude::*, traits::{ fungible::{ - hold::{ - Balanced as FunHoldBalanced, Inspect as FunHoldInspect, Mutate as FunHoldMutate, - }, - Balanced, Inspect as FunInspect, Mutate as FunMutate, + hold::{Balanced as FunHoldBalanced, Mutate as FunHoldMutate}, + Mutate as FunMutate, }, - tokens::Precision, - Defensive, DefensiveSaturating, EnsureOrigin, EstimateNextNewSession, Get, - InspectLockableCurrency, LockableCurrency, OnUnbalanced, UnixTime, + Defensive, DefensiveSaturating, EnsureOrigin, EstimateNextNewSession, Get, OnUnbalanced, + UnixTime, }, weights::Weight, BoundedVec, From 67bd3fac9d315715498ba7fe29b0ccefff41c7c1 Mon Sep 17 00:00:00 2001 From: Ankan Date: Tue, 27 Aug 2024 15:05:07 +0200 Subject: [PATCH 022/142] fix rust doc --- 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 63861d77f368..433640eace63 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -1067,7 +1067,7 @@ pub mod pallet { /// Schedule a portion of the stash to be unlocked ready for transfer out after the bond /// period ends. If this leaves an amount actively bonded less than - /// asset::existential_deposit::(), then it is increased to the full amount. + /// [`asset::existential_deposit`], then it is increased to the full amount. /// /// The dispatch origin for this call must be _Signed_ by the controller, not the stash. /// From e6c705e0c24c315ddfb149ee0445f79a3a1c00e8 Mon Sep 17 00:00:00 2001 From: Ankan Date: Tue, 27 Aug 2024 15:13:00 +0200 Subject: [PATCH 023/142] missing import --- substrate/frame/staking/src/asset.rs | 2 +- substrate/frame/staking/src/mock.rs | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/substrate/frame/staking/src/asset.rs b/substrate/frame/staking/src/asset.rs index 2822c05dadea..fb9676af96a0 100644 --- a/substrate/frame/staking/src/asset.rs +++ b/substrate/frame/staking/src/asset.rs @@ -21,7 +21,7 @@ use frame_support::traits::{ fungible::{ hold::{Balanced as FunHoldBalanced, Inspect as FunHoldInspect, Mutate as FunHoldMutate}, - Balanced, Inspect as FunInspect, + Balanced, Inspect as FunInspect, Mutate as FunMutate, }, tokens::Precision, }; diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index e952d91c9c28..64f3011ea3c4 100644 --- a/substrate/frame/staking/src/mock.rs +++ b/substrate/frame/staking/src/mock.rs @@ -25,9 +25,8 @@ use frame_election_provider_support::{ use frame_support::{ assert_ok, derive_impl, ord_parameter_types, parameter_types, traits::{ - fungible::{Inspect, Mutate, MutateHold}, - ConstU64, Currency, EitherOfDiverse, FindAuthor, Get, Hooks, Imbalance, LockableCurrency, - OnUnbalanced, OneSessionHandler, WithdrawReasons, + ConstU64, EitherOfDiverse, FindAuthor, Get, Hooks, Imbalance, + OnUnbalanced, OneSessionHandler, }, weights::constants::RocksDbWeight, }; From c4a9c9d95b1e27330da7d277c86a89f877310926 Mon Sep 17 00:00:00 2001 From: Ankan Date: Tue, 27 Aug 2024 15:23:37 +0200 Subject: [PATCH 024/142] conditional import of fun mutate --- substrate/frame/staking/src/asset.rs | 4 +++- substrate/frame/staking/src/mock.rs | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/substrate/frame/staking/src/asset.rs b/substrate/frame/staking/src/asset.rs index fb9676af96a0..eaefd6893cb7 100644 --- a/substrate/frame/staking/src/asset.rs +++ b/substrate/frame/staking/src/asset.rs @@ -21,7 +21,7 @@ use frame_support::traits::{ fungible::{ hold::{Balanced as FunHoldBalanced, Inspect as FunHoldInspect, Mutate as FunHoldMutate}, - Balanced, Inspect as FunInspect, Mutate as FunMutate, + Balanced, Inspect as FunInspect, }, tokens::Precision, }; @@ -66,6 +66,8 @@ pub fn staked(who: &T::AccountId) -> BalanceOf { /// Should only be used with test. #[cfg(any(test, feature = "runtime-benchmarks"))] pub fn set_stakeable_balance(who: &T::AccountId, value: BalanceOf) { + use frame_support::traits::fungible::Mutate; + let reserved_balance = staked::(who); if reserved_balance < value { let _ = T::Currency::set_balance(who, value - reserved_balance); diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index 64f3011ea3c4..61602253d3a1 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, EitherOfDiverse, FindAuthor, Get, Hooks, Imbalance, - OnUnbalanced, OneSessionHandler, + ConstU64, EitherOfDiverse, FindAuthor, Get, Hooks, Imbalance, OnUnbalanced, + OneSessionHandler, }, weights::constants::RocksDbWeight, }; From 994c6c570816cf3a280cd64cf60624aa87c3e777 Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 28 Aug 2024 14:40:32 +0200 Subject: [PATCH 025/142] refactor bench test since moving from currency to fungible change events --- .../frame/offences/benchmarking/src/inner.rs | 44 ++++++++++--------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/substrate/frame/offences/benchmarking/src/inner.rs b/substrate/frame/offences/benchmarking/src/inner.rs index b16e5be653d1..3cffa8134ef1 100644 --- a/substrate/frame/offences/benchmarking/src/inner.rs +++ b/substrate/frame/offences/benchmarking/src/inner.rs @@ -172,6 +172,14 @@ fn make_offenders( } benchmarks! { + where_clause { + where + ::RuntimeEvent: TryInto>, + ::RuntimeEvent: TryInto>, + ::RuntimeEvent: TryInto, + ::RuntimeEvent: TryInto>, + } + report_offence_grandpa { let n in 0 .. MAX_NOMINATORS.min(MaxNominationsOf::::get()); @@ -197,16 +205,14 @@ benchmarks! { } verify { // make sure that all slashes have been applied - #[cfg(test)] - assert_eq!( - System::::event_count(), 0 - + 1 // offence - + 3 // reporter (reward + endowment) - + 1 // offenders reported - + 3 // offenders slashed - + 1 // offenders chilled - + 3 * n // nominators slashed - ); + // (n+1) * (slash + unlocked) + deposit + endowment + rescinded + assert_eq!(System::::read_events_for_pallet::>().len(), 2 * (n + 1) as usize + 3); + // (n+1) * slashed + Slash Reported + assert_eq!(System::::read_events_for_pallet::>().len(), 1 * (n + 1) as usize + 1); + // offence + assert_eq!(System::::read_events_for_pallet::().len(), 1); + // new account + assert_eq!(System::::read_events_for_pallet::>().len(), 1); } report_offence_babe { @@ -234,16 +240,14 @@ benchmarks! { } verify { // make sure that all slashes have been applied - #[cfg(test)] - assert_eq!( - System::::event_count(), 0 - + 1 // offence - + 3 // reporter (reward + endowment) - + 1 // offenders reported - + 3 // offenders slashed - + 1 // offenders chilled - + 3 * n // nominators slashed - ); + // (n+1) * (slash + unlocked) + deposit + endowment + rescinded + assert_eq!(System::::read_events_for_pallet::>().len(), 2 * (n + 1) as usize + 3); + // (n+1) * slashed + Slash Reported + assert_eq!(System::::read_events_for_pallet::>().len(), 1 * (n + 1) as usize + 1); + // offence + assert_eq!(System::::read_events_for_pallet::().len(), 1); + // new account + assert_eq!(System::::read_events_for_pallet::>().len(), 1); } impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::Test); From 940e5e04f7c9f8fdcd7b6043168d177788ef8d05 Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 28 Aug 2024 14:49:41 +0200 Subject: [PATCH 026/142] improve test comments --- substrate/frame/offences/benchmarking/src/inner.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/substrate/frame/offences/benchmarking/src/inner.rs b/substrate/frame/offences/benchmarking/src/inner.rs index 3cffa8134ef1..647bcbd0a4df 100644 --- a/substrate/frame/offences/benchmarking/src/inner.rs +++ b/substrate/frame/offences/benchmarking/src/inner.rs @@ -205,13 +205,14 @@ benchmarks! { } verify { // make sure that all slashes have been applied - // (n+1) * (slash + unlocked) + deposit + endowment + rescinded + // (n nominators + one validator) * (slashed + unlocked) + deposit to reporter + reporter + // account endowed + some funds rescinded from issuance. assert_eq!(System::::read_events_for_pallet::>().len(), 2 * (n + 1) as usize + 3); - // (n+1) * slashed + Slash Reported + // (n nominators + one validator) * slashed + Slash Reported assert_eq!(System::::read_events_for_pallet::>().len(), 1 * (n + 1) as usize + 1); // offence assert_eq!(System::::read_events_for_pallet::().len(), 1); - // new account + // reporter new account assert_eq!(System::::read_events_for_pallet::>().len(), 1); } @@ -240,13 +241,14 @@ benchmarks! { } verify { // make sure that all slashes have been applied - // (n+1) * (slash + unlocked) + deposit + endowment + rescinded + // (n nominators + one validator) * (slashed + unlocked) + deposit to reporter + reporter + // account endowed + some funds rescinded from issuance. assert_eq!(System::::read_events_for_pallet::>().len(), 2 * (n + 1) as usize + 3); - // (n+1) * slashed + Slash Reported + // (n nominators + one validator) * slashed + Slash Reported assert_eq!(System::::read_events_for_pallet::>().len(), 1 * (n + 1) as usize + 1); // offence assert_eq!(System::::read_events_for_pallet::().len(), 1); - // new account + // reporter new account assert_eq!(System::::read_events_for_pallet::>().len(), 1); } From 0c296ab485e2f7d6cb5499ed320ac62d807609eb Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 28 Aug 2024 15:04:43 +0200 Subject: [PATCH 027/142] refactor offence benchmark --- substrate/frame/offences/benchmarking/src/inner.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/substrate/frame/offences/benchmarking/src/inner.rs b/substrate/frame/offences/benchmarking/src/inner.rs index 647bcbd0a4df..7db9cdbff986 100644 --- a/substrate/frame/offences/benchmarking/src/inner.rs +++ b/substrate/frame/offences/benchmarking/src/inner.rs @@ -20,7 +20,7 @@ use alloc::{vec, vec::Vec}; use frame_benchmarking::v1::{account, benchmarks}; -use frame_support::traits::{Currency, Get}; +use frame_support::traits::Get; use frame_system::{Config as SystemConfig, Pallet as System, RawOrigin}; use sp_runtime::{ @@ -89,7 +89,7 @@ struct Offender { } fn bond_amount() -> BalanceOf { - T::Currency::minimum_balance().saturating_mul(10_000u32.into()) + pallet_staking::asset::existential_deposit::().saturating_mul(10_000u32.into()) } fn create_offender(n: u32, nominators: u32) -> Result, &'static str> { @@ -99,7 +99,7 @@ fn create_offender(n: u32, nominators: u32) -> Result, &' let amount = bond_amount::(); // add twice as much balance to prevent the account from being killed. let free_amount = amount.saturating_mul(2u32.into()); - T::Currency::make_free_balance_be(&stash, free_amount); + pallet_staking::asset::set_stakeable_balance::(&stash, free_amount); Staking::::bond( RawOrigin::Signed(stash.clone()).into(), amount, @@ -116,7 +116,7 @@ fn create_offender(n: u32, nominators: u32) -> Result, &' for i in 0..nominators { let nominator_stash: T::AccountId = account("nominator stash", n * MAX_NOMINATORS + i, SEED); - T::Currency::make_free_balance_be(&nominator_stash, free_amount); + pallet_staking::asset::set_stakeable_balance::(&nominator_stash, free_amount); Staking::::bond( RawOrigin::Signed(nominator_stash.clone()).into(), From 61bac3544040dc3dce82896b040a236f60733453 Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 28 Aug 2024 15:06:38 +0200 Subject: [PATCH 028/142] fix balance of --- substrate/frame/offences/benchmarking/src/inner.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/substrate/frame/offences/benchmarking/src/inner.rs b/substrate/frame/offences/benchmarking/src/inner.rs index 7db9cdbff986..ed61b59bb46a 100644 --- a/substrate/frame/offences/benchmarking/src/inner.rs +++ b/substrate/frame/offences/benchmarking/src/inner.rs @@ -77,8 +77,7 @@ where } type LookupSourceOf = <::Lookup as StaticLookup>::Source; -type BalanceOf = - <::Currency as Currency<::AccountId>>::Balance; +type BalanceOf = ::CurrencyBalance; struct Offender { pub controller: T::AccountId, From e5b80ce4c0aa5acdf9edb980a6a0569aebe8689c Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 28 Aug 2024 15:09:16 +0200 Subject: [PATCH 029/142] fix event count with fungibles --- substrate/frame/offences/benchmarking/src/inner.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/substrate/frame/offences/benchmarking/src/inner.rs b/substrate/frame/offences/benchmarking/src/inner.rs index ed61b59bb46a..73b300a4c441 100644 --- a/substrate/frame/offences/benchmarking/src/inner.rs +++ b/substrate/frame/offences/benchmarking/src/inner.rs @@ -204,9 +204,8 @@ benchmarks! { } verify { // make sure that all slashes have been applied - // (n nominators + one validator) * (slashed + unlocked) + deposit to reporter + reporter - // account endowed + some funds rescinded from issuance. - assert_eq!(System::::read_events_for_pallet::>().len(), 2 * (n + 1) as usize + 3); + // deposit to reporter + reporter account endowed. + assert_eq!(System::::read_events_for_pallet::>().len(), 2); // (n nominators + one validator) * slashed + Slash Reported assert_eq!(System::::read_events_for_pallet::>().len(), 1 * (n + 1) as usize + 1); // offence @@ -240,9 +239,8 @@ benchmarks! { } verify { // make sure that all slashes have been applied - // (n nominators + one validator) * (slashed + unlocked) + deposit to reporter + reporter - // account endowed + some funds rescinded from issuance. - assert_eq!(System::::read_events_for_pallet::>().len(), 2 * (n + 1) as usize + 3); + // deposit to reporter + reporter account endowed. + assert_eq!(System::::read_events_for_pallet::>().len(), 2); // (n nominators + one validator) * slashed + Slash Reported assert_eq!(System::::read_events_for_pallet::>().len(), 1 * (n + 1) as usize + 1); // offence From 9660a4166f598d4db78a6bf6e13127b1b8e59ff8 Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 28 Aug 2024 15:58:59 +0200 Subject: [PATCH 030/142] refactor root offences test to use staking asset --- substrate/frame/root-offences/src/tests.rs | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/substrate/frame/root-offences/src/tests.rs b/substrate/frame/root-offences/src/tests.rs index f96884d750da..289bb708efbb 100644 --- a/substrate/frame/root-offences/src/tests.rs +++ b/substrate/frame/root-offences/src/tests.rs @@ -17,7 +17,8 @@ use super::*; use frame_support::{assert_err, assert_ok}; -use mock::{active_era, start_session, Balances, ExtBuilder, RootOffences, RuntimeOrigin, System}; +use mock::{active_era, start_session, ExtBuilder, RootOffences, RuntimeOrigin, System, Test as T}; +use pallet_staking::asset; #[test] fn create_offence_fails_given_signed_origin() { @@ -35,18 +36,18 @@ fn create_offence_works_given_root_origin() { assert_eq!(active_era(), 0); - assert_eq!(Balances::free_balance(11), 1000); + assert_eq!(asset::staked::(&11), 1000); let offenders = [(11, Perbill::from_percent(50))].to_vec(); assert_ok!(RootOffences::create_offence(RuntimeOrigin::root(), offenders.clone())); System::assert_last_event(Event::OffenceCreated { offenders }.into()); // the slash should be applied right away. - assert_eq!(Balances::free_balance(11), 500); + assert_eq!(asset::staked::(&11), 500); // the other validator should keep their balance, because we only created // an offences for the first validator. - assert_eq!(Balances::free_balance(21), 1000); + assert_eq!(asset::staked::(&21), 1000); }) } @@ -58,7 +59,7 @@ fn create_offence_wont_slash_non_active_validators() { assert_eq!(active_era(), 0); // 31 is not an active validator. - assert_eq!(Balances::free_balance(31), 500); + assert_eq!(asset::staked::(&31), 500); let offenders = [(31, Perbill::from_percent(20)), (11, Perbill::from_percent(20))].to_vec(); assert_ok!(RootOffences::create_offence(RuntimeOrigin::root(), offenders.clone())); @@ -66,10 +67,10 @@ fn create_offence_wont_slash_non_active_validators() { System::assert_last_event(Event::OffenceCreated { offenders }.into()); // so 31 didn't get slashed. - assert_eq!(Balances::free_balance(31), 500); + assert_eq!(asset::staked::(&31), 500); // but 11 is an active validator so they got slashed. - assert_eq!(Balances::free_balance(11), 800); + assert_eq!(asset::staked::(&11), 800); }) } @@ -81,7 +82,7 @@ fn create_offence_wont_slash_idle() { assert_eq!(active_era(), 0); // 41 is idle. - assert_eq!(Balances::free_balance(41), 1000); + assert_eq!(asset::staked::(&41), 1000); let offenders = [(41, Perbill::from_percent(50))].to_vec(); assert_ok!(RootOffences::create_offence(RuntimeOrigin::root(), offenders.clone())); @@ -89,6 +90,6 @@ fn create_offence_wont_slash_idle() { System::assert_last_event(Event::OffenceCreated { offenders }.into()); // 41 didn't get slashed. - assert_eq!(Balances::free_balance(41), 1000); + assert_eq!(asset::staked::(&41), 1000); }) } From 0cfd8e4f6a7e454a6ff0b67932399bf02b94934a Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 28 Aug 2024 16:08:31 +0200 Subject: [PATCH 031/142] unused import --- substrate/frame/staking/src/benchmarking.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/staking/src/benchmarking.rs b/substrate/frame/staking/src/benchmarking.rs index e4b5cfccd0b4..1c86d0ddb113 100644 --- a/substrate/frame/staking/src/benchmarking.rs +++ b/substrate/frame/staking/src/benchmarking.rs @@ -972,7 +972,7 @@ benchmarks! { #[cfg(test)] mod tests { use super::*; - use crate::mock::{Balances, ExtBuilder, RuntimeOrigin, Staking, Test}; + use crate::mock::{ExtBuilder, RuntimeOrigin, Staking, Test}; use frame_support::assert_ok; #[test] From 0ec6a3baf2017b3a1db383de17881c1c3cb9f536 Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 28 Aug 2024 16:34:48 +0200 Subject: [PATCH 032/142] fix failing tests --- .../frame/delegated-staking/src/tests.rs | 2 +- substrate/frame/fast-unstake/src/tests.rs | 21 ++++++++++++------- .../frame/nomination-pools/src/adapter.rs | 3 ++- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs index 2c965e18b1b3..b7b82a43771e 100644 --- a/substrate/frame/delegated-staking/src/tests.rs +++ b/substrate/frame/delegated-staking/src/tests.rs @@ -676,7 +676,7 @@ mod staking_integration { // in equal parts. lets try to migrate this nominator into delegate based stake. // all balance currently is in 200 - assert_eq!(Balances::free_balance(agent), agent_amount); + assert_eq!(pallet_staking::asset::stakeable_balance::(&agent), agent_amount); // to migrate, nominator needs to set an account as a proxy delegator where staked funds // will be moved and delegated back to this old nominator account. This should be funded diff --git a/substrate/frame/fast-unstake/src/tests.rs b/substrate/frame/fast-unstake/src/tests.rs index 77128872f285..3e4eb7915769 100644 --- a/substrate/frame/fast-unstake/src/tests.rs +++ b/substrate/frame/fast-unstake/src/tests.rs @@ -137,15 +137,16 @@ fn deregister_works() { ExtBuilder::default().build_and_execute(|| { ErasToCheckPerBlock::::put(1); - assert_eq!(::Currency::reserved_balance(&1), 0); + // reserved balance prior to registering for fast unstake. + let pre_reserved = ::Currency::reserved_balance(&1); // Controller account registers for fast unstake. assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(1))); - assert_eq!(::Currency::reserved_balance(&1), Deposit::get()); + assert_eq!(::Currency::reserved_balance(&1) - pre_reserved, Deposit::get()); // Controller then changes mind and deregisters. assert_ok!(FastUnstake::deregister(RuntimeOrigin::signed(1))); - assert_eq!(::Currency::reserved_balance(&1), 0); + assert_eq!(::Currency::reserved_balance(&1) - pre_reserved, 0); // Ensure stash no longer exists in the queue. assert_eq!(Queue::::get(1), None); @@ -243,15 +244,18 @@ mod on_idle { CurrentEra::::put(BondingDuration::get()); // given - assert_eq!(::Currency::reserved_balance(&1), 0); - + // reserved balance prior to registering for fast unstake. + let pre_reserved = ::Currency::reserved_balance(&1); assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(1))); assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(3))); assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(5))); assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(7))); assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(9))); - assert_eq!(::Currency::reserved_balance(&1), Deposit::get()); + assert_eq!( + ::Currency::reserved_balance(&1) - pre_reserved, + Deposit::get() + ); assert_eq!(Queue::::count(), 5); assert_eq!(Head::::get(), None); @@ -279,6 +283,9 @@ mod on_idle { // when next_block(true); + // pre_reserve may change due to unstaked amount. + let pre_reserved = ::Currency::reserved_balance(&1); + // then assert_eq!( Head::::get(), @@ -289,7 +296,7 @@ mod on_idle { ); assert_eq!(Queue::::count(), 3); - assert_eq!(::Currency::reserved_balance(&1), 0); + assert_eq!(::Currency::reserved_balance(&1) - pre_reserved, 0); assert_eq!( fast_unstake_events_since_last_call(), diff --git a/substrate/frame/nomination-pools/src/adapter.rs b/substrate/frame/nomination-pools/src/adapter.rs index 272b3b60612b..bdd24ffc26e5 100644 --- a/substrate/frame/nomination-pools/src/adapter.rs +++ b/substrate/frame/nomination-pools/src/adapter.rs @@ -262,7 +262,8 @@ impl, AccountId = T: pool_account: Pool, _: Member, ) -> BalanceOf { - T::Currency::balance(&pool_account.0).saturating_sub(Self::active_stake(pool_account)) + // free/liquid balance of the pool account. + T::Currency::balance(&pool_account.0) } fn total_balance(pool_account: Pool) -> Option> { From 165261f40de318bad5de83537e8962414f461bec Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 28 Aug 2024 16:47:27 +0200 Subject: [PATCH 033/142] fix compile --- substrate/frame/staking/src/benchmarking.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/substrate/frame/staking/src/benchmarking.rs b/substrate/frame/staking/src/benchmarking.rs index 1c86d0ddb113..a25085a18036 100644 --- a/substrate/frame/staking/src/benchmarking.rs +++ b/substrate/frame/staking/src/benchmarking.rs @@ -1019,16 +1019,17 @@ mod tests { let current_era = CurrentEra::::get().unwrap(); - let original_free_balance = Balances::free_balance(&validator_stash); + let original_stakeable_balance = asset::stakeable_balance::(&validator_stash); assert_ok!(Staking::payout_stakers_by_page( RuntimeOrigin::signed(1337), validator_stash, current_era, 0 )); - let new_free_balance = Balances::free_balance(&validator_stash); + let new_stakeable_balance = asset::stakeable_balance::(&validator_stash); - assert!(original_free_balance < new_free_balance); + // reward increases stakeable balance + assert!(original_stakeable_balance < new_stakeable_balance); }); } From f62354bce781577d9711c1b2fcd749d9242edd8e Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 28 Aug 2024 17:28:43 +0200 Subject: [PATCH 034/142] refactor epm e2e tests --- .../test-staking-e2e/src/lib.rs | 41 +++++++++++-------- .../test-staking-e2e/src/mock.rs | 5 +-- 2 files changed, 26 insertions(+), 20 deletions(-) diff --git a/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/lib.rs b/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/lib.rs index 0dc202ff2115..135149694387 100644 --- a/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/lib.rs +++ b/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/lib.rs @@ -322,24 +322,24 @@ fn automatic_unbonding_pools() { assert_eq!(::MaxUnbonding::get(), 1); // init state of pool members. - let init_free_balance_2 = Balances::free_balance(2); - let init_free_balance_3 = Balances::free_balance(3); + let init_stakeable_balance_2 = pallet_staking::asset::stakeable_balance::(&2); + let init_stakeable_balance_3 = pallet_staking::asset::stakeable_balance::(&3); let pool_bonded_account = Pools::generate_bonded_account(1); // creates a pool with 5 bonded, owned by 1. assert_ok!(Pools::create(RuntimeOrigin::signed(1), 5, 1, 1, 1)); - assert_eq!(locked_amount_for(pool_bonded_account), 5); + assert_eq!(staked_amount_for(pool_bonded_account), 5); let init_tvl = TotalValueLocked::::get(); // 2 joins the pool. assert_ok!(Pools::join(RuntimeOrigin::signed(2), 10, 1)); - assert_eq!(locked_amount_for(pool_bonded_account), 15); + assert_eq!(staked_amount_for(pool_bonded_account), 15); // 3 joins the pool. assert_ok!(Pools::join(RuntimeOrigin::signed(3), 10, 1)); - assert_eq!(locked_amount_for(pool_bonded_account), 25); + assert_eq!(staked_amount_for(pool_bonded_account), 25); assert_eq!(TotalValueLocked::::get(), 25); @@ -350,7 +350,7 @@ fn automatic_unbonding_pools() { assert_ok!(Pools::unbond(RuntimeOrigin::signed(2), 2, 10)); // amount is still locked in the pool, needs to wait for unbonding period. - assert_eq!(locked_amount_for(pool_bonded_account), 25); + assert_eq!(staked_amount_for(pool_bonded_account), 25); // max chunks in the ledger are now filled up (`MaxUnlockingChunks == 1`). assert_eq!(unlocking_chunks_of(pool_bonded_account), 1); @@ -372,8 +372,8 @@ fn automatic_unbonding_pools() { assert_eq!(current_era(), 3); System::reset_events(); - let locked_before_withdraw_pool = locked_amount_for(pool_bonded_account); - assert_eq!(Balances::free_balance(pool_bonded_account), 26); + let staked_before_withdraw_pool = staked_amount_for(pool_bonded_account); + assert_eq!(pallet_staking::asset::stakeable_balance::(&pool_bonded_account), 26); // now unbonding 3 will work, although the pool's ledger still has the unlocking chunks // filled up. @@ -391,20 +391,21 @@ fn automatic_unbonding_pools() { ); // balance of the pool remains the same, it hasn't withdraw explicitly from the pool yet. - assert_eq!(Balances::free_balance(pool_bonded_account), 26); + assert_eq!(pallet_staking::asset::stakeable_balance::(&pool_bonded_account), 26); // but the locked amount in the pool's account decreases due to the auto-withdraw: - assert_eq!(locked_before_withdraw_pool - 10, locked_amount_for(pool_bonded_account)); + assert_eq!(staked_before_withdraw_pool - 10, staked_amount_for(pool_bonded_account)); // TVL correctly updated. assert_eq!(TotalValueLocked::::get(), 25 - 10); // however, note that the withdrawing from the pool still works for 2, the funds are taken - // from the pool's free balance. - assert_eq!(Balances::free_balance(pool_bonded_account), 26); + // from the pool's non staked balance. + assert_eq!(pallet_staking::asset::stakeable_balance::(&pool_bonded_account), 26); + assert_eq!(pallet_staking::asset::staked::(&pool_bonded_account), 15); assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(2), 2, 10)); - assert_eq!(Balances::free_balance(pool_bonded_account), 16); + assert_eq!(pallet_staking::asset::stakeable_balance::(&pool_bonded_account), 16); - assert_eq!(Balances::free_balance(2), 20); + assert_eq!(pallet_staking::asset::stakeable_balance::(&2), 20); assert_eq!(TotalValueLocked::::get(), 15); // 3 cannot withdraw yet. @@ -423,9 +424,15 @@ fn automatic_unbonding_pools() { assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(3), 3, 10)); // final conditions are the expected. - assert_eq!(Balances::free_balance(pool_bonded_account), 6); // 5 init bonded + ED - assert_eq!(Balances::free_balance(2), init_free_balance_2); - assert_eq!(Balances::free_balance(3), init_free_balance_3); + assert_eq!(pallet_staking::asset::stakeable_balance::(&pool_bonded_account), 6); // 5 init bonded + ED + assert_eq!( + pallet_staking::asset::stakeable_balance::(&2), + init_stakeable_balance_2 + ); + assert_eq!( + pallet_staking::asset::stakeable_balance::(&3), + init_stakeable_balance_3 + ); assert_eq!(TotalValueLocked::::get(), init_tvl); }); diff --git a/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs b/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs index e45452c1ddf9..f20e3983b09d 100644 --- a/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs +++ b/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs @@ -915,9 +915,8 @@ pub(crate) fn set_minimum_election_score( .map_err(|_| ()) } -pub(crate) fn locked_amount_for(account_id: AccountId) -> Balance { - let lock = pallet_balances::Locks::::get(account_id); - lock[0].amount +pub(crate) fn staked_amount_for(account_id: AccountId) -> Balance { + pallet_staking::asset::staked::(&account_id) } pub(crate) fn staking_events() -> Vec> { From 0188158d470386f4d80f4b22b6432e1906c84eba Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 28 Aug 2024 18:16:44 +0200 Subject: [PATCH 035/142] best effort while minting money --- substrate/frame/staking/src/asset.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/substrate/frame/staking/src/asset.rs b/substrate/frame/staking/src/asset.rs index eaefd6893cb7..e64a0a77e55e 100644 --- a/substrate/frame/staking/src/asset.rs +++ b/substrate/frame/staking/src/asset.rs @@ -115,14 +115,14 @@ pub fn mint_existing( who: &T::AccountId, value: BalanceOf, ) -> Option> { - T::Currency::deposit(who, value, Precision::Exact).ok() + T::Currency::deposit(who, value, Precision::BestEffort).ok() } /// Mint reward and create account for `who` if it does not exist. /// /// This does not increase the total issuance. pub fn mint_creating(who: &T::AccountId, value: BalanceOf) -> PositiveImbalanceOf { - T::Currency::deposit(who, value, Precision::Exact).unwrap_or_default() + T::Currency::deposit(who, value, Precision::BestEffort).unwrap_or_default() } /// Deposit newly issued or slashed `value` into `who`. From 0dc0ca412e9ce95a20038c23a769f3edfda5a27c Mon Sep 17 00:00:00 2001 From: Ankan Date: Mon, 2 Sep 2024 01:06:01 +0200 Subject: [PATCH 036/142] fix ed bug while minting --- substrate/frame/staking/src/asset.rs | 9 ++++++--- .../frame/support/src/traits/tokens/fungible/regular.rs | 5 ++++- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/substrate/frame/staking/src/asset.rs b/substrate/frame/staking/src/asset.rs index e64a0a77e55e..59cef415905d 100644 --- a/substrate/frame/staking/src/asset.rs +++ b/substrate/frame/staking/src/asset.rs @@ -108,17 +108,20 @@ pub fn slash( T::Currency::slash(&HoldReason::Staking.into(), who, value) } -/// Mint reward into an existing account. +/// Mint `value` into an existing account. /// /// This does not increase the total issuance. pub fn mint_existing( who: &T::AccountId, value: BalanceOf, ) -> Option> { - T::Currency::deposit(who, value, Precision::BestEffort).ok() + // since the account already exists, we mint exact value even if value is below ED. + T::Currency::deposit(who, value, Precision::Exact).ok() } -/// Mint reward and create account for `who` if it does not exist. +/// Mint `value` and create account for `who` if it does not exist. +/// +/// If value is below existential deposit, the account is not created. /// /// This does not increase the total issuance. pub fn mint_creating(who: &T::AccountId, value: BalanceOf) -> PositiveImbalanceOf { diff --git a/substrate/frame/support/src/traits/tokens/fungible/regular.rs b/substrate/frame/support/src/traits/tokens/fungible/regular.rs index 54a04444649d..c54b5e4c8c68 100644 --- a/substrate/frame/support/src/traits/tokens/fungible/regular.rs +++ b/substrate/frame/support/src/traits/tokens/fungible/regular.rs @@ -213,7 +213,10 @@ pub trait Unbalanced: Inspect { } else { old_balance.checked_add(&amount).ok_or(ArithmeticError::Overflow)? }; - if new_balance < Self::minimum_balance() { + // FIXME(ank4n): add test for this case + // look at total balance to ensure ED is respected + let new_total_balance = amount.saturating_add(Self::total_balance(who)); + if new_total_balance < Self::minimum_balance() { // Attempt to increase from 0 to below minimum -> stays at zero. if let BestEffort = precision { Ok(Default::default()) From f0ef9d171ff04b4767b1d6250cdaa6130b4c0019 Mon Sep 17 00:00:00 2001 From: Ankan Date: Mon, 2 Sep 2024 22:05:05 +0200 Subject: [PATCH 037/142] release/dec consumer before dec providers --- substrate/frame/staking/src/asset.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/substrate/frame/staking/src/asset.rs b/substrate/frame/staking/src/asset.rs index 59cef415905d..3c333934f4f5 100644 --- a/substrate/frame/staking/src/asset.rs +++ b/substrate/frame/staking/src/asset.rs @@ -94,8 +94,9 @@ pub fn update_stake(who: &T::AccountId, amount: BalanceOf) -> Disp } pub fn kill_stake(who: &T::AccountId) -> DispatchResult { + T::Currency::release_all(&HoldReason::Staking.into(), who, Precision::BestEffort).map(|_| ())?; let _ = frame_system::Pallet::::dec_providers(who); - T::Currency::release_all(&HoldReason::Staking.into(), who, Precision::BestEffort).map(|_| ()) + Ok(()) } /// Slash the value from `who`. From ca81fea267010114d7c4256d1934b5a3b212813d Mon Sep 17 00:00:00 2001 From: Ankan Date: Mon, 2 Sep 2024 23:38:20 +0200 Subject: [PATCH 038/142] works, but hacky --- substrate/frame/staking/src/asset.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/substrate/frame/staking/src/asset.rs b/substrate/frame/staking/src/asset.rs index 3c333934f4f5..533675964e3e 100644 --- a/substrate/frame/staking/src/asset.rs +++ b/substrate/frame/staking/src/asset.rs @@ -77,7 +77,7 @@ pub fn set_stakeable_balance(who: &T::AccountId, value: BalanceOf) let _ = T::Currency::set_balance(who, Zero::zero()); } - assert!(total_balance::(who) == value); + assert_eq!(total_balance::(who), value); } /// Update `amount` at stake for `who`. @@ -85,17 +85,22 @@ pub fn set_stakeable_balance(who: &T::AccountId, value: BalanceOf) /// Overwrites the existing stake amount. If passed amount is lower than the existing stake, the /// difference is unlocked. pub fn update_stake(who: &T::AccountId, amount: BalanceOf) -> DispatchResult { - // if first stake, inc provider. + // if first stake, inc provider. This allows us to stake all free balance. if staked::(who) == Zero::zero() && amount > Zero::zero() { frame_system::Pallet::::inc_providers(who); } + // FIXME(ank4n) hacky, find a better way. + // if all amount is getting staked, inc an extra provider that would get decremented on hold. + if stakeable_balance::(who) == amount { + frame_system::Pallet::::inc_providers(who); + } + T::Currency::set_on_hold(&HoldReason::Staking.into(), who, amount) } pub fn kill_stake(who: &T::AccountId) -> DispatchResult { T::Currency::release_all(&HoldReason::Staking.into(), who, Precision::BestEffort).map(|_| ())?; - let _ = frame_system::Pallet::::dec_providers(who); Ok(()) } From b15efb616344266c8d69728114258f88366cc939 Mon Sep 17 00:00:00 2001 From: Ankan Date: Tue, 3 Sep 2024 00:24:36 +0200 Subject: [PATCH 039/142] fix provider --- substrate/frame/staking/src/asset.rs | 22 ++++++++++++------- substrate/frame/staking/src/tests.rs | 3 ++- .../src/traits/tokens/fungible/regular.rs | 2 +- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/substrate/frame/staking/src/asset.rs b/substrate/frame/staking/src/asset.rs index 533675964e3e..422d5d1243b6 100644 --- a/substrate/frame/staking/src/asset.rs +++ b/substrate/frame/staking/src/asset.rs @@ -24,6 +24,7 @@ use frame_support::traits::{ Balanced, Inspect as FunInspect, }, tokens::Precision, + Defensive, }; use sp_runtime::{traits::Zero, DispatchResult}; @@ -60,18 +61,19 @@ pub fn staked(who: &T::AccountId) -> BalanceOf { /// Set balance that can be staked for `who`. /// -/// If `value` is less than already staked, the difference is amount is unlocked. Otherwise, -/// the difference is added to free balance. +/// `Value` must be greater than already staked plus existential deposit for free balance. /// /// Should only be used with test. #[cfg(any(test, feature = "runtime-benchmarks"))] pub fn set_stakeable_balance(who: &T::AccountId, value: BalanceOf) { use frame_support::traits::fungible::Mutate; - let reserved_balance = staked::(who); - if reserved_balance < value { - let _ = T::Currency::set_balance(who, value - reserved_balance); + let staked_balance = staked::(who); + // if value is greater than staked balance, we need to increase the free balance. + if value > staked_balance { + let _ = T::Currency::set_balance(who, value - staked_balance); } else { + // else reduce the staked balance. update_stake::(who, value).expect("can remove from what is staked"); // burn all free let _ = T::Currency::set_balance(who, Zero::zero()); @@ -90,8 +92,9 @@ pub fn update_stake(who: &T::AccountId, amount: BalanceOf) -> Disp frame_system::Pallet::::inc_providers(who); } - // FIXME(ank4n) hacky, find a better way. - // if all amount is getting staked, inc an extra provider that would get decremented on hold. + // Hacky but this allows us to replicate the old currency behaviour of allowing free balance to + // go below ED if an account transfers funds. + // FIXME(ank4n): probably not needed to replicate old behaviour and can be refactored. if stakeable_balance::(who) == amount { frame_system::Pallet::::inc_providers(who); } @@ -100,7 +103,10 @@ pub fn update_stake(who: &T::AccountId, amount: BalanceOf) -> Disp } pub fn kill_stake(who: &T::AccountId) -> DispatchResult { - T::Currency::release_all(&HoldReason::Staking.into(), who, Precision::BestEffort).map(|_| ())?; + T::Currency::release_all(&HoldReason::Staking.into(), who, Precision::BestEffort) + .map(|_| ())?; + // dec provider that we incremented for a new stake. + let _ = frame_system::Pallet::::dec_providers(who).defensive(); Ok(()) } diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 6a844be32509..bfc674ec704e 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -1021,11 +1021,12 @@ fn cannot_transfer_staked_balance_2() { assert_eq!(asset::stakeable_balance::(&21), 2000); // Confirm account 21 (via controller) is totally staked assert_eq!(Staking::eras_stakers(active_era(), &21).total, 1000); - // Confirm account 21 can transfer at most 1000 + // Confirm account 21 cannot transfer more than 1000 assert_noop!( Balances::transfer_allow_death(RuntimeOrigin::signed(21), 21, 1001), TokenError::FundsUnavailable, ); + // Confirm account 21 needs to leave at least ED in free balance to be able to transfer assert_ok!(Balances::transfer_allow_death(RuntimeOrigin::signed(21), 21, 1000)); }); } diff --git a/substrate/frame/support/src/traits/tokens/fungible/regular.rs b/substrate/frame/support/src/traits/tokens/fungible/regular.rs index c54b5e4c8c68..29f907ce2654 100644 --- a/substrate/frame/support/src/traits/tokens/fungible/regular.rs +++ b/substrate/frame/support/src/traits/tokens/fungible/regular.rs @@ -216,7 +216,7 @@ pub trait Unbalanced: Inspect { // FIXME(ank4n): add test for this case // look at total balance to ensure ED is respected let new_total_balance = amount.saturating_add(Self::total_balance(who)); - if new_total_balance < Self::minimum_balance() { + if new_total_balance < Self::minimum_balance() { // Attempt to increase from 0 to below minimum -> stays at zero. if let BestEffort = precision { Ok(Default::default()) From b1f313bffe1ef6b26390c6f5cdfbf44c7be93470 Mon Sep 17 00:00:00 2001 From: Ankan Date: Tue, 3 Sep 2024 02:07:08 +0200 Subject: [PATCH 040/142] remove the hack provider logic --- substrate/frame/staking/src/asset.rs | 7 ------- substrate/frame/staking/src/benchmarking.rs | 2 +- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/substrate/frame/staking/src/asset.rs b/substrate/frame/staking/src/asset.rs index 422d5d1243b6..7a4c3a39d5a6 100644 --- a/substrate/frame/staking/src/asset.rs +++ b/substrate/frame/staking/src/asset.rs @@ -92,13 +92,6 @@ pub fn update_stake(who: &T::AccountId, amount: BalanceOf) -> Disp frame_system::Pallet::::inc_providers(who); } - // Hacky but this allows us to replicate the old currency behaviour of allowing free balance to - // go below ED if an account transfers funds. - // FIXME(ank4n): probably not needed to replicate old behaviour and can be refactored. - if stakeable_balance::(who) == amount { - frame_system::Pallet::::inc_providers(who); - } - T::Currency::set_on_hold(&HoldReason::Staking.into(), who, amount) } diff --git a/substrate/frame/staking/src/benchmarking.rs b/substrate/frame/staking/src/benchmarking.rs index a25085a18036..97a76932f1ba 100644 --- a/substrate/frame/staking/src/benchmarking.rs +++ b/substrate/frame/staking/src/benchmarking.rs @@ -249,7 +249,7 @@ benchmarks! { let original_bonded: BalanceOf = Ledger::::get(&controller).map(|l| l.active).ok_or("ledger not created after")?; - let _ = asset::mint_existing::(&stash, max_additional).unwrap(); + let _ = asset::mint_existing::(&stash, max_additional + asset::existential_deposit::()).unwrap(); whitelist_account!(stash); }: _(RawOrigin::Signed(stash), max_additional) From 32be80c03f3b0a22a7519208674054b5339d5b54 Mon Sep 17 00:00:00 2001 From: Ankan Date: Tue, 3 Sep 2024 23:57:06 +0200 Subject: [PATCH 041/142] verify only for tests --- substrate/frame/offences/benchmarking/src/inner.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/substrate/frame/offences/benchmarking/src/inner.rs b/substrate/frame/offences/benchmarking/src/inner.rs index 73b300a4c441..4adc49c39c7f 100644 --- a/substrate/frame/offences/benchmarking/src/inner.rs +++ b/substrate/frame/offences/benchmarking/src/inner.rs @@ -203,6 +203,8 @@ benchmarks! { let _ = Offences::::report_offence(reporters, offence); } verify { + #[cfg(test)] + { // make sure that all slashes have been applied // deposit to reporter + reporter account endowed. assert_eq!(System::::read_events_for_pallet::>().len(), 2); @@ -212,6 +214,7 @@ benchmarks! { assert_eq!(System::::read_events_for_pallet::().len(), 1); // reporter new account assert_eq!(System::::read_events_for_pallet::>().len(), 1); + } } report_offence_babe { @@ -238,6 +241,8 @@ benchmarks! { let _ = Offences::::report_offence(reporters, offence); } verify { + #[cfg(test)] + { // make sure that all slashes have been applied // deposit to reporter + reporter account endowed. assert_eq!(System::::read_events_for_pallet::>().len(), 2); @@ -247,6 +252,7 @@ benchmarks! { assert_eq!(System::::read_events_for_pallet::().len(), 1); // reporter new account assert_eq!(System::::read_events_for_pallet::>().len(), 1); + } } impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::Test); From e0fac32ed7b9a71be0e8ae2bf1d13768c9780793 Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 4 Sep 2024 16:22:14 +0200 Subject: [PATCH 042/142] hacky to pass tests for now --- substrate/frame/staking/src/asset.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/substrate/frame/staking/src/asset.rs b/substrate/frame/staking/src/asset.rs index 7a4c3a39d5a6..265fcd66eebd 100644 --- a/substrate/frame/staking/src/asset.rs +++ b/substrate/frame/staking/src/asset.rs @@ -99,7 +99,8 @@ pub fn kill_stake(who: &T::AccountId) -> DispatchResult { T::Currency::release_all(&HoldReason::Staking.into(), who, Precision::BestEffort) .map(|_| ())?; // dec provider that we incremented for a new stake. - let _ = frame_system::Pallet::::dec_providers(who).defensive(); + // fixme(ank4n): fails while slashing? Need to carefully examine consumer and provider changes. + let _ = frame_system::Pallet::::dec_providers(who); Ok(()) } From d74ebd6e27bcf7c6720af7e0a50e3904aa4fdec2 Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 4 Sep 2024 16:55:33 +0200 Subject: [PATCH 043/142] unused import --- substrate/frame/staking/src/asset.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/substrate/frame/staking/src/asset.rs b/substrate/frame/staking/src/asset.rs index 265fcd66eebd..679adc113587 100644 --- a/substrate/frame/staking/src/asset.rs +++ b/substrate/frame/staking/src/asset.rs @@ -24,7 +24,6 @@ use frame_support::traits::{ Balanced, Inspect as FunInspect, }, tokens::Precision, - Defensive, }; use sp_runtime::{traits::Zero, DispatchResult}; From c5a7730fe1f7a06b22910a483ae1711590232701 Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 4 Sep 2024 17:49:35 +0200 Subject: [PATCH 044/142] staking does not need to inc consumer anymore --- substrate/frame/staking/src/pallet/impls.rs | 5 ----- substrate/frame/staking/src/pallet/mod.rs | 2 -- 2 files changed, 7 deletions(-) diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index 797aff003243..d2703801de0a 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -797,8 +797,6 @@ impl Pallet { Self::do_remove_validator(&stash); Self::do_remove_nominator(&stash); - frame_system::Pallet::::dec_consumers(&stash); - Ok(()) } @@ -1938,9 +1936,6 @@ impl sp_staking::StakingUnchecked for Pallet { // check if payee not same as who. ensure!(keyless_who != payee, Error::::RewardDestinationRestricted); - // mark this pallet as consumer of `who`. - frame_system::Pallet::::inc_consumers(&keyless_who).map_err(|_| Error::::BadState)?; - // mark who as a virtual staker. VirtualStakers::::insert(keyless_who, ()); diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index d36714206507..169cd5123b2f 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -1049,8 +1049,6 @@ pub mod pallet { return Err(Error::::InsufficientBond.into()) } - frame_system::Pallet::::inc_consumers(&stash).map_err(|_| Error::::BadState)?; - let stash_balance = asset::stakeable_balance::(&stash); let value = value.min(stash_balance); Self::deposit_event(Event::::Bonded { stash: stash.clone(), amount: value }); From dedecbcebbbf7d2475b0a96d853b3ed6d99c8b0e Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 4 Sep 2024 21:46:52 +0200 Subject: [PATCH 045/142] purge session key when trying to kill stash --- substrate/frame/staking/src/asset.rs | 15 ++++++++++++--- substrate/frame/staking/src/lib.rs | 12 +++++++++++- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/substrate/frame/staking/src/asset.rs b/substrate/frame/staking/src/asset.rs index 679adc113587..8a1f0bbb1f49 100644 --- a/substrate/frame/staking/src/asset.rs +++ b/substrate/frame/staking/src/asset.rs @@ -27,7 +27,9 @@ use frame_support::traits::{ }; use sp_runtime::{traits::Zero, DispatchResult}; -use crate::{BalanceOf, Config, HoldReason, NegativeImbalanceOf, PositiveImbalanceOf}; +use crate::{ + BalanceOf, Config, HoldReason, NegativeImbalanceOf, PositiveImbalanceOf, SessionInterface, +}; /// Existential deposit for the chain. pub fn existential_deposit() -> BalanceOf { @@ -97,9 +99,16 @@ pub fn update_stake(who: &T::AccountId, amount: BalanceOf) -> Disp pub fn kill_stake(who: &T::AccountId) -> DispatchResult { T::Currency::release_all(&HoldReason::Staking.into(), who, Precision::BestEffort) .map(|_| ())?; + + // if can't dec provider, try cleaning up session keys first. + // FIXME(ank4n): may have to update bench. Also add failing test if non session consumers on + // stash. + if !frame_system::Pallet::::can_dec_provider(who) { + T::SessionInterface::purge_keys(who.clone())?; + } + // dec provider that we incremented for a new stake. - // fixme(ank4n): fails while slashing? Need to carefully examine consumer and provider changes. - let _ = frame_system::Pallet::::dec_providers(who); + let _ = frame_system::Pallet::::dec_providers(who)?; Ok(()) } diff --git a/substrate/frame/staking/src/lib.rs b/substrate/frame/staking/src/lib.rs index 73f08f9d0be3..aeaa334b66b3 100644 --- a/substrate/frame/staking/src/lib.rs +++ b/substrate/frame/staking/src/lib.rs @@ -318,11 +318,12 @@ use frame_support::{ weights::Weight, BoundedVec, CloneNoBound, EqNoBound, PartialEqNoBound, RuntimeDebugNoBound, }; +use frame_system::RawOrigin; use scale_info::TypeInfo; use sp_runtime::{ curve::PiecewiseLinear, traits::{AtLeast32BitUnsigned, Convert, StaticLookup, Zero}, - Perbill, Perquintill, Rounding, RuntimeDebug, Saturating, + DispatchResult, Perbill, Perquintill, Rounding, RuntimeDebug, Saturating, }; use sp_staking::{ offence::{Offence, OffenceError, ReportOffence}, @@ -850,6 +851,8 @@ pub trait SessionInterface { fn validators() -> Vec; /// Prune historical session tries up to but not including the given index. fn prune_historical_up_to(up_to: SessionIndex); + /// Purge session key of the validator. + fn purge_keys(stash: AccountId) -> DispatchResult; } impl SessionInterface<::AccountId> for T @@ -877,6 +880,10 @@ where fn prune_historical_up_to(up_to: SessionIndex) { >::prune_up_to(up_to); } + + fn purge_keys(stash: ::AccountId) -> DispatchResult { + >::purge_keys(RawOrigin::Signed(stash.clone()).into()) + } } impl SessionInterface for () { @@ -889,6 +896,9 @@ impl SessionInterface for () { fn prune_historical_up_to(_: SessionIndex) { () } + fn purge_keys(stash: AccountId) -> DispatchResult { + Ok(()) + } } /// Handler for determining how much of a balance should be paid out on the current era. From bcdb7497c040aad352427f44dfa88852006b3041 Mon Sep 17 00:00:00 2001 From: Ankan Date: Thu, 5 Sep 2024 10:45:44 +0200 Subject: [PATCH 046/142] small updates --- substrate/frame/staking/src/asset.rs | 4 +++- substrate/frame/staking/src/lib.rs | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/substrate/frame/staking/src/asset.rs b/substrate/frame/staking/src/asset.rs index 8a1f0bbb1f49..80a495e1a42b 100644 --- a/substrate/frame/staking/src/asset.rs +++ b/substrate/frame/staking/src/asset.rs @@ -100,10 +100,12 @@ pub fn kill_stake(who: &T::AccountId) -> DispatchResult { T::Currency::release_all(&HoldReason::Staking.into(), who, Precision::BestEffort) .map(|_| ())?; - // if can't dec provider, try cleaning up session keys first. // FIXME(ank4n): may have to update bench. Also add failing test if non session consumers on // stash. if !frame_system::Pallet::::can_dec_provider(who) { + // The session pallet keeps a consumer reference to validator stash which may block this + // pallet from clearing its provider reference. If the account cannot provide for itself + // (via enough free balance) to keep the session key, we should clean up the session keys. T::SessionInterface::purge_keys(who.clone())?; } diff --git a/substrate/frame/staking/src/lib.rs b/substrate/frame/staking/src/lib.rs index aeaa334b66b3..e6c01948a897 100644 --- a/substrate/frame/staking/src/lib.rs +++ b/substrate/frame/staking/src/lib.rs @@ -896,7 +896,7 @@ impl SessionInterface for () { fn prune_historical_up_to(_: SessionIndex) { () } - fn purge_keys(stash: AccountId) -> DispatchResult { + fn purge_keys(_stash: AccountId) -> DispatchResult { Ok(()) } } From 18928a422b6383bef9d3ccdf1184b7d4332967fe Mon Sep 17 00:00:00 2001 From: Ankan Date: Thu, 5 Sep 2024 11:36:30 +0200 Subject: [PATCH 047/142] kill stake is fallible --- substrate/frame/delegated-staking/src/lib.rs | 2 +- .../test-transfer-stake/src/lib.rs | 6 +++--- substrate/frame/staking/src/pallet/impls.rs | 16 +++++++--------- substrate/frame/staking/src/pallet/mod.rs | 2 ++ substrate/frame/staking/src/tests.rs | 8 ++++---- substrate/primitives/staking/src/lib.rs | 2 +- 6 files changed, 18 insertions(+), 18 deletions(-) diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs index 7b8d14b0a611..dbb5247436f8 100644 --- a/substrate/frame/delegated-staking/src/lib.rs +++ b/substrate/frame/delegated-staking/src/lib.rs @@ -520,7 +520,7 @@ impl Pallet { let stake = T::CoreStaking::stake(who)?; // release funds from core staking. - T::CoreStaking::migrate_to_virtual_staker(who); + T::CoreStaking::migrate_to_virtual_staker(who)?; // transfer just released staked amount plus any free amount. let amount_to_transfer = diff --git a/substrate/frame/nomination-pools/test-transfer-stake/src/lib.rs b/substrate/frame/nomination-pools/test-transfer-stake/src/lib.rs index 28e978bba0e5..8cd4f20d3459 100644 --- a/substrate/frame/nomination-pools/test-transfer-stake/src/lib.rs +++ b/substrate/frame/nomination-pools/test-transfer-stake/src/lib.rs @@ -200,13 +200,13 @@ fn destroy_pool_with_erroneous_consumer() { assert_ok!(Pools::create(RuntimeOrigin::signed(10), 50, 10, 10, 10)); assert_eq!(LastPoolId::::get(), 1); - // expect consumers on pool account to be 2 (staking lock and an explicit inc by staking). - assert_eq!(frame_system::Pallet::::consumers(&POOL1_BONDED), 2); + // expect consumers on pool account to be 1 (staking hold). + assert_eq!(frame_system::Pallet::::consumers(&POOL1_BONDED), 1); // increment consumer by 1 reproducing the erroneous consumer bug. // refer https://github.com/paritytech/polkadot-sdk/issues/4440. assert_ok!(frame_system::Pallet::::inc_consumers(&POOL1_BONDED)); - assert_eq!(frame_system::Pallet::::consumers(&POOL1_BONDED), 3); + assert_eq!(frame_system::Pallet::::consumers(&POOL1_BONDED), 2); // have the pool nominate. assert_ok!(Pools::nominate(RuntimeOrigin::signed(10), 1, vec![1, 2, 3])); diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index d2703801de0a..cd627831f78b 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -34,13 +34,10 @@ use frame_support::{ }; use frame_system::{pallet_prelude::BlockNumberFor, RawOrigin}; use pallet_session::historical; -use sp_runtime::{ - traits::{ - Bounded, CheckedAdd, CheckedSub, Convert, One, SaturatedConversion, Saturating, - StaticLookup, Zero, - }, - ArithmeticError, Perbill, Percent, -}; +use sp_runtime::{traits::{ + Bounded, CheckedAdd, CheckedSub, Convert, One, SaturatedConversion, Saturating, + StaticLookup, Zero, +}, ArithmeticError, Perbill, Percent, DispatchResult}; use sp_staking::{ currency_to_vote::CurrencyToVote, offence::{OffenceDetails, OnOffenceHandler}, @@ -1916,9 +1913,10 @@ impl StakingInterface for Pallet { } impl sp_staking::StakingUnchecked for Pallet { - fn migrate_to_virtual_staker(who: &Self::AccountId) { - let _ = asset::kill_stake::(who).defensive(); + fn migrate_to_virtual_staker(who: &Self::AccountId) -> DispatchResult { + asset::kill_stake::(who)?; VirtualStakers::::insert(who, ()); + Ok(()) } /// Virtually bonds `keyless_who` to `payee` with `value`. diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 169cd5123b2f..584992db6d4a 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -956,6 +956,8 @@ pub mod pallet { NotEnoughFunds, /// Operation not allowed for virtual stakers. VirtualStakerNotAllowed, + /// Stash could not be reaped as other pallet might depend on it. + CannotReapStash, } #[pallet::hooks] diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index bfc674ec704e..e66a04fe7aae 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -7253,7 +7253,7 @@ mod staking_unchecked { assert_eq!(asset::staked::(&200), 1000); // migrate them to virtual staker - ::migrate_to_virtual_staker(&200); + assert_ok!(::migrate_to_virtual_staker(&200)); // payee needs to be updated to a non-stash account. assert_ok!(::set_payee(&200, &201)); @@ -7280,7 +7280,7 @@ mod staking_unchecked { // 101 is a nominator for 11 assert_eq!(initial_exposure.others.first().unwrap().who, 101); // make 101 a virtual nominator - ::migrate_to_virtual_staker(&101); + assert_ok!(::migrate_to_virtual_staker(&101)); // set payee different to self. assert_ok!(::set_payee(&101, &102)); @@ -7355,7 +7355,7 @@ mod staking_unchecked { // 101 is a nominator for 11 assert_eq!(initial_exposure.others.first().unwrap().who, 101); // make 101 a virtual nominator - ::migrate_to_virtual_staker(&101); + assert_ok!(::migrate_to_virtual_staker(&101)); // set payee different to self. assert_ok!(::set_payee(&101, &102)); @@ -7411,7 +7411,7 @@ mod staking_unchecked { // 333 is corrupted assert_eq!(Staking::inspect_bond_state(&333).unwrap(), LedgerIntegrityState::Corrupted); // migrate to virtual staker. - ::migrate_to_virtual_staker(&333); + assert_ok!(::migrate_to_virtual_staker(&333)); // recover the ledger won't work for virtual staker assert_noop!( diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs index 5e94524816a0..22969479d30c 100644 --- a/substrate/primitives/staking/src/lib.rs +++ b/substrate/primitives/staking/src/lib.rs @@ -325,7 +325,7 @@ pub trait StakingUnchecked: StakingInterface { /// Migrate an existing staker to a virtual staker. /// /// It would release all funds held by the implementation pallet. - fn migrate_to_virtual_staker(who: &Self::AccountId); + fn migrate_to_virtual_staker(who: &Self::AccountId) -> DispatchResult; /// Book-keep a new bond for `keyless_who` without applying any locks (hence virtual). /// From 6a7001e143c046c4f144c1d35e0ef0be87f36084 Mon Sep 17 00:00:00 2001 From: Ankan Date: Thu, 5 Sep 2024 11:42:10 +0200 Subject: [PATCH 048/142] fail ledger kill if stake cannot be killed --- substrate/frame/staking/src/ledger.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/substrate/frame/staking/src/ledger.rs b/substrate/frame/staking/src/ledger.rs index 0a91c6472d20..b2163fbef516 100644 --- a/substrate/frame/staking/src/ledger.rs +++ b/substrate/frame/staking/src/ledger.rs @@ -260,9 +260,9 @@ impl StakingLedger { >::remove(&stash); // kill virtual staker if it exists. - if >::take(&stash).is_none() { + if >::take(&ledger.stash).is_none() { // if not virtual staker, clear locks. - let _ = asset::kill_stake::(&ledger.stash).defensive(); + asset::kill_stake::(&ledger.stash).map_err(|_| Error::::CannotReapStash)?; } Ok(()) From ef54e9ab508d6515b9f67a4674df84002d5d8c69 Mon Sep 17 00:00:00 2001 From: Ankan Date: Thu, 5 Sep 2024 11:47:21 +0200 Subject: [PATCH 049/142] doc fixes --- substrate/frame/staking/src/pallet/impls.rs | 3 ++- substrate/frame/staking/src/pallet/mod.rs | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index cd627831f78b..5a064664b1b5 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -1945,11 +1945,12 @@ impl sp_staking::StakingUnchecked for Pallet { Ok(()) } + /// Only meant to be used in tests. #[cfg(feature = "runtime-benchmarks")] fn migrate_to_direct_staker(who: &Self::AccountId) { assert!(VirtualStakers::::contains_key(who)); let ledger = StakingLedger::::get(Stash(who.clone())).unwrap(); - let _ = asset::update_stake::(who, ledger.total); + let _ = asset::update_stake::(who, ledger.total).expect("funds must be transferred to stash"); VirtualStakers::::remove(who); } } diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 584992db6d4a..7738188d0ec2 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -323,7 +323,7 @@ pub mod pallet { /// A reason for placing a hold on funds. #[pallet::composite_enum] pub enum HoldReason { - /// Funds held for stake delegation to another account. + /// Funds on stake by a nominator or a validator. #[codec(index = 0)] Staking, } From 45552096f62cc5965f222ff3c3adc48a425a21c0 Mon Sep 17 00:00:00 2001 From: Ankan Date: Thu, 5 Sep 2024 12:55:52 +0200 Subject: [PATCH 050/142] fmt --- substrate/frame/staking/src/pallet/impls.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index 5a064664b1b5..73a457ea8bdd 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -34,10 +34,13 @@ use frame_support::{ }; use frame_system::{pallet_prelude::BlockNumberFor, RawOrigin}; use pallet_session::historical; -use sp_runtime::{traits::{ - Bounded, CheckedAdd, CheckedSub, Convert, One, SaturatedConversion, Saturating, - StaticLookup, Zero, -}, ArithmeticError, Perbill, Percent, DispatchResult}; +use sp_runtime::{ + traits::{ + Bounded, CheckedAdd, CheckedSub, Convert, One, SaturatedConversion, Saturating, + StaticLookup, Zero, + }, + ArithmeticError, DispatchResult, Perbill, Percent, +}; use sp_staking::{ currency_to_vote::CurrencyToVote, offence::{OffenceDetails, OnOffenceHandler}, @@ -1950,7 +1953,8 @@ impl sp_staking::StakingUnchecked for Pallet { fn migrate_to_direct_staker(who: &Self::AccountId) { assert!(VirtualStakers::::contains_key(who)); let ledger = StakingLedger::::get(Stash(who.clone())).unwrap(); - let _ = asset::update_stake::(who, ledger.total).expect("funds must be transferred to stash"); + let _ = asset::update_stake::(who, ledger.total) + .expect("funds must be transferred to stash"); VirtualStakers::::remove(who); } } From 684828abd6cdf889b2a12345bc6afed33ed30d7e Mon Sep 17 00:00:00 2001 From: Ankan Date: Thu, 5 Sep 2024 21:03:53 +0200 Subject: [PATCH 051/142] fix migrate test --- substrate/frame/delegated-staking/src/impls.rs | 2 -- substrate/frame/nomination-pools/benchmarking/src/inner.rs | 4 +++- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/substrate/frame/delegated-staking/src/impls.rs b/substrate/frame/delegated-staking/src/impls.rs index 4e6812dee249..a25efabca339 100644 --- a/substrate/frame/delegated-staking/src/impls.rs +++ b/substrate/frame/delegated-staking/src/impls.rs @@ -136,8 +136,6 @@ impl DelegationMigrator for Pallet { ); >::remove(&delegator); }); - - T::CoreStaking::migrate_to_direct_staker(&agent.get()); } } diff --git a/substrate/frame/nomination-pools/benchmarking/src/inner.rs b/substrate/frame/nomination-pools/benchmarking/src/inner.rs index 2a4559425111..b0c8f3655a50 100644 --- a/substrate/frame/nomination-pools/benchmarking/src/inner.rs +++ b/substrate/frame/nomination-pools/benchmarking/src/inner.rs @@ -41,7 +41,7 @@ use sp_runtime::{ traits::{Bounded, StaticLookup, Zero}, Perbill, }; -use sp_staking::EraIndex; +use sp_staking::{EraIndex, StakingUnchecked}; // `frame_benchmarking::benchmarks!` macro needs this use pallet_nomination_pools::Call; @@ -131,6 +131,8 @@ fn migrate_to_transfer_stake(pool_id: PoolId) { ) .expect("member should have enough balance to transfer"); }); + + pallet_staking::Pallet::::migrate_to_direct_staker(&pool_acc); } fn vote_to_balance( From 6d94601ddab5d5d571f8f09dac9f188aacf0ff13 Mon Sep 17 00:00:00 2001 From: Ankan Date: Fri, 6 Sep 2024 13:43:09 +0200 Subject: [PATCH 052/142] rename agent kill function --- substrate/frame/delegated-staking/src/impls.rs | 2 +- substrate/frame/nomination-pools/src/adapter.rs | 2 +- substrate/primitives/staking/src/lib.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/substrate/frame/delegated-staking/src/impls.rs b/substrate/frame/delegated-staking/src/impls.rs index a25efabca339..a443df7b20f5 100644 --- a/substrate/frame/delegated-staking/src/impls.rs +++ b/substrate/frame/delegated-staking/src/impls.rs @@ -124,7 +124,7 @@ impl DelegationMigrator for Pallet { /// Only used for testing. #[cfg(feature = "runtime-benchmarks")] - fn migrate_to_direct_staker(agent: Agent) { + fn force_kill_agent(agent: Agent) { >::remove(agent.clone().get()); >::iter() .filter(|(_, delegation)| delegation.agent == agent.clone().get()) diff --git a/substrate/frame/nomination-pools/src/adapter.rs b/substrate/frame/nomination-pools/src/adapter.rs index bdd24ffc26e5..95694943271a 100644 --- a/substrate/frame/nomination-pools/src/adapter.rs +++ b/substrate/frame/nomination-pools/src/adapter.rs @@ -461,6 +461,6 @@ impl< #[cfg(feature = "runtime-benchmarks")] fn remove_as_agent(pool: Pool) { - Delegation::migrate_to_direct_staker(pool.into()) + Delegation::force_kill_agent(pool.into()) } } diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs index 22969479d30c..8e23c6800a9d 100644 --- a/substrate/primitives/staking/src/lib.rs +++ b/substrate/primitives/staking/src/lib.rs @@ -619,7 +619,7 @@ pub trait DelegationMigrator { /// /// Also removed from [`StakingUnchecked`] as a Virtual Staker. Useful for testing. #[cfg(feature = "runtime-benchmarks")] - fn migrate_to_direct_staker(agent: Agent); + fn force_kill_agent(agent: Agent); } sp_core::generate_feature_enabled_macro!(runtime_benchmarks_enabled, feature = "runtime-benchmarks", $); From a3267afe2ff87dea85311209512d86dde331ab85 Mon Sep 17 00:00:00 2001 From: Ankan Date: Fri, 6 Sep 2024 13:51:46 +0200 Subject: [PATCH 053/142] small edits --- substrate/frame/staking/src/asset.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/substrate/frame/staking/src/asset.rs b/substrate/frame/staking/src/asset.rs index 80a495e1a42b..9d8c48c2d7d6 100644 --- a/substrate/frame/staking/src/asset.rs +++ b/substrate/frame/staking/src/asset.rs @@ -96,6 +96,9 @@ pub fn update_stake(who: &T::AccountId, amount: BalanceOf) -> Disp T::Currency::set_on_hold(&HoldReason::Staking.into(), who, amount) } +/// Release all staked amount to `who`. +/// +/// Fails if there are consumers left on `who` that restricts it from being reaped. pub fn kill_stake(who: &T::AccountId) -> DispatchResult { T::Currency::release_all(&HoldReason::Staking.into(), who, Precision::BestEffort) .map(|_| ())?; @@ -139,7 +142,7 @@ pub fn mint_existing( /// /// If value is below existential deposit, the account is not created. /// -/// This does not increase the total issuance. +/// Note: This does not increase the total issuance. pub fn mint_creating(who: &T::AccountId, value: BalanceOf) -> PositiveImbalanceOf { T::Currency::deposit(who, value, Precision::BestEffort).unwrap_or_default() } From c1fc3dc2a5a086715e6c6a3d097e9797e6f1fadc Mon Sep 17 00:00:00 2001 From: Ankan Date: Fri, 6 Sep 2024 13:53:36 +0200 Subject: [PATCH 054/142] port some changes from migration pr back to base --- .../frame/delegated-staking/src/impls.rs | 4 +--- .../frame/delegated-staking/src/tests.rs | 2 +- substrate/frame/fast-unstake/src/tests.rs | 20 +++++++++++++------ .../benchmarking/src/inner.rs | 4 +++- .../frame/nomination-pools/src/adapter.rs | 2 +- .../frame/offences/benchmarking/src/inner.rs | 6 ++++++ substrate/frame/staking/src/asset.rs | 3 ++- substrate/primitives/staking/src/lib.rs | 2 +- 8 files changed, 29 insertions(+), 14 deletions(-) diff --git a/substrate/frame/delegated-staking/src/impls.rs b/substrate/frame/delegated-staking/src/impls.rs index 4e6812dee249..a443df7b20f5 100644 --- a/substrate/frame/delegated-staking/src/impls.rs +++ b/substrate/frame/delegated-staking/src/impls.rs @@ -124,7 +124,7 @@ impl DelegationMigrator for Pallet { /// Only used for testing. #[cfg(feature = "runtime-benchmarks")] - fn migrate_to_direct_staker(agent: Agent) { + fn force_kill_agent(agent: Agent) { >::remove(agent.clone().get()); >::iter() .filter(|(_, delegation)| delegation.agent == agent.clone().get()) @@ -136,8 +136,6 @@ impl DelegationMigrator for Pallet { ); >::remove(&delegator); }); - - T::CoreStaking::migrate_to_direct_staker(&agent.get()); } } diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs index 2c965e18b1b3..b7b82a43771e 100644 --- a/substrate/frame/delegated-staking/src/tests.rs +++ b/substrate/frame/delegated-staking/src/tests.rs @@ -676,7 +676,7 @@ mod staking_integration { // in equal parts. lets try to migrate this nominator into delegate based stake. // all balance currently is in 200 - assert_eq!(Balances::free_balance(agent), agent_amount); + assert_eq!(pallet_staking::asset::stakeable_balance::(&agent), agent_amount); // to migrate, nominator needs to set an account as a proxy delegator where staked funds // will be moved and delegated back to this old nominator account. This should be funded diff --git a/substrate/frame/fast-unstake/src/tests.rs b/substrate/frame/fast-unstake/src/tests.rs index 77128872f285..7c11f381ca10 100644 --- a/substrate/frame/fast-unstake/src/tests.rs +++ b/substrate/frame/fast-unstake/src/tests.rs @@ -137,15 +137,16 @@ fn deregister_works() { ExtBuilder::default().build_and_execute(|| { ErasToCheckPerBlock::::put(1); - assert_eq!(::Currency::reserved_balance(&1), 0); + // reserved balance prior to registering for fast unstake. + let pre_reserved = ::Currency::reserved_balance(&1); // Controller account registers for fast unstake. assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(1))); - assert_eq!(::Currency::reserved_balance(&1), Deposit::get()); + assert_eq!(::Currency::reserved_balance(&1) - pre_reserved, Deposit::get()); // Controller then changes mind and deregisters. assert_ok!(FastUnstake::deregister(RuntimeOrigin::signed(1))); - assert_eq!(::Currency::reserved_balance(&1), 0); + assert_eq!(::Currency::reserved_balance(&1) - pre_reserved, 0); // Ensure stash no longer exists in the queue. assert_eq!(Queue::::get(1), None); @@ -243,7 +244,8 @@ mod on_idle { CurrentEra::::put(BondingDuration::get()); // given - assert_eq!(::Currency::reserved_balance(&1), 0); + // reserved balance prior to registering for fast unstake. + let pre_reserved = ::Currency::reserved_balance(&1); assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(1))); assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(3))); @@ -251,7 +253,10 @@ mod on_idle { assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(7))); assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(9))); - assert_eq!(::Currency::reserved_balance(&1), Deposit::get()); + assert_eq!( + ::Currency::reserved_balance(&1) - pre_reserved, + Deposit::get() + ); assert_eq!(Queue::::count(), 5); assert_eq!(Head::::get(), None); @@ -279,6 +284,9 @@ mod on_idle { // when next_block(true); + // pre_reserve may change due to unstaked amount. + let pre_reserved = ::Currency::reserved_balance(&1); + // then assert_eq!( Head::::get(), @@ -289,7 +297,7 @@ mod on_idle { ); assert_eq!(Queue::::count(), 3); - assert_eq!(::Currency::reserved_balance(&1), 0); + assert_eq!(::Currency::reserved_balance(&1) - pre_reserved, 0); assert_eq!( fast_unstake_events_since_last_call(), diff --git a/substrate/frame/nomination-pools/benchmarking/src/inner.rs b/substrate/frame/nomination-pools/benchmarking/src/inner.rs index 2a4559425111..b0c8f3655a50 100644 --- a/substrate/frame/nomination-pools/benchmarking/src/inner.rs +++ b/substrate/frame/nomination-pools/benchmarking/src/inner.rs @@ -41,7 +41,7 @@ use sp_runtime::{ traits::{Bounded, StaticLookup, Zero}, Perbill, }; -use sp_staking::EraIndex; +use sp_staking::{EraIndex, StakingUnchecked}; // `frame_benchmarking::benchmarks!` macro needs this use pallet_nomination_pools::Call; @@ -131,6 +131,8 @@ fn migrate_to_transfer_stake(pool_id: PoolId) { ) .expect("member should have enough balance to transfer"); }); + + pallet_staking::Pallet::::migrate_to_direct_staker(&pool_acc); } fn vote_to_balance( diff --git a/substrate/frame/nomination-pools/src/adapter.rs b/substrate/frame/nomination-pools/src/adapter.rs index 272b3b60612b..f125919dabfa 100644 --- a/substrate/frame/nomination-pools/src/adapter.rs +++ b/substrate/frame/nomination-pools/src/adapter.rs @@ -460,6 +460,6 @@ impl< #[cfg(feature = "runtime-benchmarks")] fn remove_as_agent(pool: Pool) { - Delegation::migrate_to_direct_staker(pool.into()) + Delegation::force_kill_agent(pool.into()) } } diff --git a/substrate/frame/offences/benchmarking/src/inner.rs b/substrate/frame/offences/benchmarking/src/inner.rs index ed61b59bb46a..a45b1d1045fe 100644 --- a/substrate/frame/offences/benchmarking/src/inner.rs +++ b/substrate/frame/offences/benchmarking/src/inner.rs @@ -203,6 +203,8 @@ benchmarks! { let _ = Offences::::report_offence(reporters, offence); } verify { + #[cfg(test)] + { // make sure that all slashes have been applied // (n nominators + one validator) * (slashed + unlocked) + deposit to reporter + reporter // account endowed + some funds rescinded from issuance. @@ -213,6 +215,7 @@ benchmarks! { assert_eq!(System::::read_events_for_pallet::().len(), 1); // reporter new account assert_eq!(System::::read_events_for_pallet::>().len(), 1); + } } report_offence_babe { @@ -239,6 +242,8 @@ benchmarks! { let _ = Offences::::report_offence(reporters, offence); } verify { + #[cfg(test)] + { // make sure that all slashes have been applied // (n nominators + one validator) * (slashed + unlocked) + deposit to reporter + reporter // account endowed + some funds rescinded from issuance. @@ -249,6 +254,7 @@ benchmarks! { assert_eq!(System::::read_events_for_pallet::().len(), 1); // reporter new account assert_eq!(System::::read_events_for_pallet::>().len(), 1); + } } impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::Test); diff --git a/substrate/frame/staking/src/asset.rs b/substrate/frame/staking/src/asset.rs index 3c31491ce2b5..23368b1f8fca 100644 --- a/substrate/frame/staking/src/asset.rs +++ b/substrate/frame/staking/src/asset.rs @@ -54,6 +54,7 @@ pub fn staked(who: &T::AccountId) -> BalanceOf { /// Set balance that can be staked for `who`. /// /// This includes any balance that is already staked. +#[cfg(any(test, feature = "runtime-benchmarks"))] pub fn set_stakeable_balance(who: &T::AccountId, value: BalanceOf) { T::Currency::make_free_balance_be(who, value); } @@ -88,7 +89,7 @@ pub fn slash( T::Currency::slash(who, value) } -/// Mint reward into an existing account. +/// Mint `value` into an existing account `who`. /// /// This does not increase the total issuance. pub fn mint_existing( diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs index 5e94524816a0..17010a8907fc 100644 --- a/substrate/primitives/staking/src/lib.rs +++ b/substrate/primitives/staking/src/lib.rs @@ -619,7 +619,7 @@ pub trait DelegationMigrator { /// /// Also removed from [`StakingUnchecked`] as a Virtual Staker. Useful for testing. #[cfg(feature = "runtime-benchmarks")] - fn migrate_to_direct_staker(agent: Agent); + fn force_kill_agent(agent: Agent); } sp_core::generate_feature_enabled_macro!(runtime_benchmarks_enabled, feature = "runtime-benchmarks", $); From 679f29075bc4754e9bf012f3d19ea7b94777be7a Mon Sep 17 00:00:00 2001 From: Ankan Date: Fri, 6 Sep 2024 13:55:02 +0200 Subject: [PATCH 055/142] fmt --- .../frame/offences/benchmarking/src/inner.rs | 44 +++++++++---------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/substrate/frame/offences/benchmarking/src/inner.rs b/substrate/frame/offences/benchmarking/src/inner.rs index a45b1d1045fe..573114de0742 100644 --- a/substrate/frame/offences/benchmarking/src/inner.rs +++ b/substrate/frame/offences/benchmarking/src/inner.rs @@ -205,17 +205,17 @@ benchmarks! { verify { #[cfg(test)] { - // make sure that all slashes have been applied - // (n nominators + one validator) * (slashed + unlocked) + deposit to reporter + reporter - // account endowed + some funds rescinded from issuance. - assert_eq!(System::::read_events_for_pallet::>().len(), 2 * (n + 1) as usize + 3); - // (n nominators + one validator) * slashed + Slash Reported - assert_eq!(System::::read_events_for_pallet::>().len(), 1 * (n + 1) as usize + 1); - // offence - assert_eq!(System::::read_events_for_pallet::().len(), 1); - // reporter new account - assert_eq!(System::::read_events_for_pallet::>().len(), 1); - } + // make sure that all slashes have been applied + // (n nominators + one validator) * (slashed + unlocked) + deposit to reporter + reporter + // account endowed + some funds rescinded from issuance. + assert_eq!(System::::read_events_for_pallet::>().len(), 2 * (n + 1) as usize + 3); + // (n nominators + one validator) * slashed + Slash Reported + assert_eq!(System::::read_events_for_pallet::>().len(), 1 * (n + 1) as usize + 1); + // offence + assert_eq!(System::::read_events_for_pallet::().len(), 1); + // reporter new account + assert_eq!(System::::read_events_for_pallet::>().len(), 1); + } } report_offence_babe { @@ -244,17 +244,17 @@ benchmarks! { verify { #[cfg(test)] { - // make sure that all slashes have been applied - // (n nominators + one validator) * (slashed + unlocked) + deposit to reporter + reporter - // account endowed + some funds rescinded from issuance. - assert_eq!(System::::read_events_for_pallet::>().len(), 2 * (n + 1) as usize + 3); - // (n nominators + one validator) * slashed + Slash Reported - assert_eq!(System::::read_events_for_pallet::>().len(), 1 * (n + 1) as usize + 1); - // offence - assert_eq!(System::::read_events_for_pallet::().len(), 1); - // reporter new account - assert_eq!(System::::read_events_for_pallet::>().len(), 1); - } + // make sure that all slashes have been applied + // (n nominators + one validator) * (slashed + unlocked) + deposit to reporter + reporter + // account endowed + some funds rescinded from issuance. + assert_eq!(System::::read_events_for_pallet::>().len(), 2 * (n + 1) as usize + 3); + // (n nominators + one validator) * slashed + Slash Reported + assert_eq!(System::::read_events_for_pallet::>().len(), 1 * (n + 1) as usize + 1); + // offence + assert_eq!(System::::read_events_for_pallet::().len(), 1); + // reporter new account + assert_eq!(System::::read_events_for_pallet::>().len(), 1); + } } impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::Test); From dc4a9a4e1f14b1165cdd26b71553e370a8669871 Mon Sep 17 00:00:00 2001 From: Ankan Date: Fri, 6 Sep 2024 13:55:59 +0200 Subject: [PATCH 056/142] fmt --- .../frame/offences/benchmarking/src/inner.rs | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/substrate/frame/offences/benchmarking/src/inner.rs b/substrate/frame/offences/benchmarking/src/inner.rs index 4adc49c39c7f..9836a6104374 100644 --- a/substrate/frame/offences/benchmarking/src/inner.rs +++ b/substrate/frame/offences/benchmarking/src/inner.rs @@ -205,15 +205,15 @@ benchmarks! { verify { #[cfg(test)] { - // make sure that all slashes have been applied - // deposit to reporter + reporter account endowed. - assert_eq!(System::::read_events_for_pallet::>().len(), 2); - // (n nominators + one validator) * slashed + Slash Reported - assert_eq!(System::::read_events_for_pallet::>().len(), 1 * (n + 1) as usize + 1); - // offence - assert_eq!(System::::read_events_for_pallet::().len(), 1); - // reporter new account - assert_eq!(System::::read_events_for_pallet::>().len(), 1); + // make sure that all slashes have been applied + // deposit to reporter + reporter account endowed. + assert_eq!(System::::read_events_for_pallet::>().len(), 2); + // (n nominators + one validator) * slashed + Slash Reported + assert_eq!(System::::read_events_for_pallet::>().len(), 1 * (n + 1) as usize + 1); + // offence + assert_eq!(System::::read_events_for_pallet::().len(), 1); + // reporter new account + assert_eq!(System::::read_events_for_pallet::>().len(), 1); } } @@ -243,15 +243,15 @@ benchmarks! { verify { #[cfg(test)] { - // make sure that all slashes have been applied - // deposit to reporter + reporter account endowed. - assert_eq!(System::::read_events_for_pallet::>().len(), 2); - // (n nominators + one validator) * slashed + Slash Reported - assert_eq!(System::::read_events_for_pallet::>().len(), 1 * (n + 1) as usize + 1); - // offence - assert_eq!(System::::read_events_for_pallet::().len(), 1); - // reporter new account - assert_eq!(System::::read_events_for_pallet::>().len(), 1); + // make sure that all slashes have been applied + // deposit to reporter + reporter account endowed. + assert_eq!(System::::read_events_for_pallet::>().len(), 2); + // (n nominators + one validator) * slashed + Slash Reported + assert_eq!(System::::read_events_for_pallet::>().len(), 1 * (n + 1) as usize + 1); + // offence + assert_eq!(System::::read_events_for_pallet::().len(), 1); + // reporter new account + assert_eq!(System::::read_events_for_pallet::>().len(), 1); } } From 9570a61841f9a388c916c917d2afa5ba97d1cd40 Mon Sep 17 00:00:00 2001 From: Ankan Date: Tue, 10 Sep 2024 11:21:34 +0200 Subject: [PATCH 057/142] remove provider inc in pallet-delegated-staking --- substrate/frame/delegated-staking/src/tests.rs | 9 +++++---- substrate/frame/delegated-staking/src/types.rs | 6 ------ 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs index b7b82a43771e..ccec495efd1e 100644 --- a/substrate/frame/delegated-staking/src/tests.rs +++ b/substrate/frame/delegated-staking/src/tests.rs @@ -671,6 +671,8 @@ mod staking_integration { )); assert_ok!(Staking::nominate(RuntimeOrigin::signed(agent), vec![GENESIS_VALIDATOR],)); let init_stake = Staking::stake(&agent).unwrap(); + // agent has an extra provider now added by CoreStaking. + assert_eq!(System::providers(&agent), 2); // scenario: 200 is a pool account, and the stake comes from its 4 delegators (300..304) // in equal parts. lets try to migrate this nominator into delegate based stake. @@ -685,8 +687,9 @@ mod staking_integration { DelegatedStaking::generate_proxy_delegator(Agent::from(agent)).get(); assert_ok!(DelegatedStaking::migrate_to_agent(RawOrigin::Signed(agent).into(), 201)); - // after migration, funds are moved to proxy delegator, still a provider exists. - assert_eq!(System::providers(&agent), 1); + // after migration, no provider left since free balance is 0 and staking pallet released + // all funds. + assert_eq!(System::providers(&agent), 0); assert_eq!(Balances::free_balance(agent), 0); // proxy delegator has one provider as well with no free balance. assert_eq!(System::providers(&proxy_delegator), 1); @@ -798,8 +801,6 @@ mod staking_integration { RawOrigin::Signed(agent).into(), reward_acc )); - // becoming an agent adds another provider. - assert_eq!(System::providers(&agent), 2); // delegate to this account fund(&delegator, 1000); diff --git a/substrate/frame/delegated-staking/src/types.rs b/substrate/frame/delegated-staking/src/types.rs index a78aa3f55906..14f49466f0e2 100644 --- a/substrate/frame/delegated-staking/src/types.rs +++ b/substrate/frame/delegated-staking/src/types.rs @@ -131,10 +131,6 @@ impl AgentLedger { /// /// Increments provider count if this is a new agent. pub(crate) fn update(self, key: &T::AccountId) { - if !>::contains_key(key) { - // This is a new agent. Provide for this account. - frame_system::Pallet::::inc_providers(key); - } >::insert(key, self) } @@ -142,8 +138,6 @@ impl AgentLedger { pub(crate) fn remove(key: &T::AccountId) { debug_assert!(>::contains_key(key), "Agent should exist in storage"); >::remove(key); - // Remove provider reference. - let _ = frame_system::Pallet::::dec_providers(key).defensive(); } /// Effective total balance of the `Agent`. From 0e7e8d54970e90a4348fd537b2647161095f311a Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 11 Sep 2024 21:09:31 +0200 Subject: [PATCH 058/142] add migrate function to staking --- polkadot/runtime/westend/src/tests.rs | 28 +++++++++-------- substrate/frame/staking/src/pallet/impls.rs | 33 +++++++++++++++++++++ 2 files changed, 48 insertions(+), 13 deletions(-) diff --git a/polkadot/runtime/westend/src/tests.rs b/polkadot/runtime/westend/src/tests.rs index dc8103ab52c4..8f61943182d3 100644 --- a/polkadot/runtime/westend/src/tests.rs +++ b/polkadot/runtime/westend/src/tests.rs @@ -149,25 +149,27 @@ mod remote_tests { let transport: Transport = var("WS").unwrap_or("ws://127.0.0.1:9900".to_string()).into(); let maybe_state_snapshot: Option = var("SNAP").map(|s| s.into()).ok(); + let online_config = OnlineConfig { + transport, + state_snapshot: maybe_state_snapshot.clone(), + child_trie: false, + pallets: vec![ + "Staking".into(), + "System".into(), + "Balances".into(), + "NominationPools".into(), + "DelegatedStaking".into(), + ], + ..Default::default() + }; let mut ext = Builder::::default() .mode(if let Some(state_snapshot) = maybe_state_snapshot { Mode::OfflineOrElseOnline( OfflineConfig { state_snapshot: state_snapshot.clone() }, - OnlineConfig { - transport, - state_snapshot: Some(state_snapshot), - pallets: vec![ - "staking".into(), - "system".into(), - "balances".into(), - "nomination-pools".into(), - "delegated-staking".into(), - ], - ..Default::default() - }, + online_config, ) } else { - Mode::Online(OnlineConfig { transport, ..Default::default() }) + Mode::Online(online_config) }) .build() .await diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index 73a457ea8bdd..c25f16663900 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -1159,6 +1159,39 @@ impl Pallet { ) -> Exposure> { EraInfo::::get_full_exposure(era, account) } + + pub fn migrate_lock_to_hold(stash: &T::AccountId) -> DispatchResult + where + OldCurrency: frame_support::traits::InspectLockableCurrency, + BalanceOf: From, + { + // use frame_support::traits::InspectLockableCurrency; + let ledger = Self::ledger(Stash(stash.clone()))?; + + const LOCK_ID: frame_support::traits::LockIdentifier = *b"staking "; + let locked: BalanceOf = OldCurrency::balance_locked(LOCK_ID, stash).into(); + let max_hold = asset::stakeable_balance::(&stash); + if max_hold >= locked { + // this is great. easy job for us. + // just hold asset. + asset::update_stake::(&stash, locked)?; + } else { + let unsafe_withdraw = locked.saturating_sub(max_hold); + log::info!(target: "remote_test", "unsafe_withdraw: {:?} {:?}", stash, unsafe_withdraw); + + // we ignore if active is 0. This amount will get unlocked anyways in the future. + StakingLedger { + total: max_hold, + active: ledger.active.saturating_sub(unsafe_withdraw), + // we are not changing the stash, so we can keep the stash. + ..ledger + } + .update()?; + } + + frame_system::Pallet::::dec_consumers(&stash); + Ok(()) + } } impl Pallet { From 7fad8173b3d6c824133381c4f7a42a5f29104eec Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 11 Sep 2024 22:14:20 +0200 Subject: [PATCH 059/142] remote test --- polkadot/runtime/westend/src/tests.rs | 60 +++++++++++++++++++++ substrate/frame/staking/src/pallet/impls.rs | 11 ++-- 2 files changed, 68 insertions(+), 3 deletions(-) diff --git a/polkadot/runtime/westend/src/tests.rs b/polkadot/runtime/westend/src/tests.rs index 8f61943182d3..e6f8eb55ac88 100644 --- a/polkadot/runtime/westend/src/tests.rs +++ b/polkadot/runtime/westend/src/tests.rs @@ -237,4 +237,64 @@ mod remote_tests { ); }); } + + #[tokio::test] + async fn staking_curr_fun_migrate() { + // Intended to be run only manually. + if var("RUN_MIGRATION_TESTS").is_err() { + return; + } + use frame_support::assert_ok; + sp_tracing::try_init_simple(); + + let transport: Transport = var("WS").unwrap_or("ws://127.0.0.1:9900".to_string()).into(); + let maybe_state_snapshot: Option = var("SNAP").map(|s| s.into()).ok(); + let online_config = OnlineConfig { + transport, + state_snapshot: maybe_state_snapshot.clone(), + child_trie: false, + pallets: vec!["Staking".into(), "System".into(), "Balances".into()], + ..Default::default() + }; + let mut ext = Builder::::default() + .mode(if let Some(state_snapshot) = maybe_state_snapshot { + Mode::OfflineOrElseOnline( + OfflineConfig { state_snapshot: state_snapshot.clone() }, + online_config, + ) + } else { + Mode::Online(online_config) + }) + .build() + .await + .unwrap(); + ext.execute_with(|| { + // create an account with some balance + let alice = AccountId::from([1u8; 32]); + use frame_support::traits::Currency; + let _ = Balances::deposit_creating(&alice, 100_000 * UNITS); + + let mut success = 0; + let mut err = 0; + // iterate over all pools + pallet_staking::Ledger::::iter_values().for_each(|ledger| { + match pallet_staking::Pallet::::migrate_lock_to_hold::(&ledger.stash) { + Ok(_) => { + success += 1; + } + Err(e) => { + log::error!(target: "remote_test", "Error migrating {:?}: {:?}", ledger.stash, e); + err += 1; + } + } + }); + + log::info!( + target: "remote_test", + "Migration stats: success: {}, err: {}", + success, + err, + ); + }); + } } diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index c25f16663900..574fb565063f 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -1165,9 +1165,13 @@ impl Pallet { OldCurrency: frame_support::traits::InspectLockableCurrency, BalanceOf: From, { - // use frame_support::traits::InspectLockableCurrency; - let ledger = Self::ledger(Stash(stash.clone()))?; + if Self::is_virtual_staker(stash) { + // we don't need to do anything for virtual stakers since their funds are not locked by + // this pallet. + return Ok(()) + } + let ledger = Self::ledger(Stash(stash.clone()))?; const LOCK_ID: frame_support::traits::LockIdentifier = *b"staking "; let locked: BalanceOf = OldCurrency::balance_locked(LOCK_ID, stash).into(); let max_hold = asset::stakeable_balance::(&stash); @@ -1176,8 +1180,9 @@ impl Pallet { // just hold asset. asset::update_stake::(&stash, locked)?; } else { + let ed = asset::existential_deposit::(); let unsafe_withdraw = locked.saturating_sub(max_hold); - log::info!(target: "remote_test", "unsafe_withdraw: {:?} {:?}", stash, unsafe_withdraw); + log::info!(target: "remote_test", "unsafe_withdraw from stash: {:?}, value {:?}, active {:?}", stash, unsafe_withdraw/ed, ledger.active/ed); // we ignore if active is 0. This amount will get unlocked anyways in the future. StakingLedger { From bb7b8a089f5c4b0e5d7ecf5450a25d8c3f0f82b2 Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 11 Sep 2024 22:14:44 +0200 Subject: [PATCH 060/142] fmt --- polkadot/runtime/westend/src/tests.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/polkadot/runtime/westend/src/tests.rs b/polkadot/runtime/westend/src/tests.rs index e6f8eb55ac88..c7a08f02bc8a 100644 --- a/polkadot/runtime/westend/src/tests.rs +++ b/polkadot/runtime/westend/src/tests.rs @@ -278,14 +278,16 @@ mod remote_tests { let mut err = 0; // iterate over all pools pallet_staking::Ledger::::iter_values().for_each(|ledger| { - match pallet_staking::Pallet::::migrate_lock_to_hold::(&ledger.stash) { + match pallet_staking::Pallet::::migrate_lock_to_hold::( + &ledger.stash, + ) { Ok(_) => { success += 1; - } + }, Err(e) => { log::error!(target: "remote_test", "Error migrating {:?}: {:?}", ledger.stash, e); err += 1; - } + }, } }); From 7bc708630c7606b341bb5a1f11814a5a98bafe67 Mon Sep 17 00:00:00 2001 From: Ankan Date: Fri, 13 Sep 2024 15:38:37 +0200 Subject: [PATCH 061/142] add OldCurrency to runtime configs --- polkadot/runtime/test-runtime/src/lib.rs | 1 + polkadot/runtime/westend/src/lib.rs | 1 + substrate/bin/node/runtime/src/lib.rs | 1 + substrate/frame/babe/src/mock.rs | 1 + substrate/frame/beefy/src/mock.rs | 1 + substrate/frame/delegated-staking/src/mock.rs | 1 + .../test-staking-e2e/src/mock.rs | 1 + substrate/frame/fast-unstake/src/mock.rs | 1 + substrate/frame/grandpa/src/mock.rs | 1 + .../frame/nomination-pools/benchmarking/src/mock.rs | 1 + .../nomination-pools/test-delegate-stake/src/mock.rs | 1 + .../nomination-pools/test-transfer-stake/src/mock.rs | 1 + substrate/frame/offences/benchmarking/src/mock.rs | 1 + substrate/frame/root-offences/src/mock.rs | 1 + substrate/frame/session/benchmarking/src/mock.rs | 1 + substrate/frame/staking/src/mock.rs | 1 + substrate/frame/staking/src/pallet/mod.rs | 12 ++++++++++-- 17 files changed, 26 insertions(+), 2 deletions(-) diff --git a/polkadot/runtime/test-runtime/src/lib.rs b/polkadot/runtime/test-runtime/src/lib.rs index 46e592ca77ca..d61a4929ffe0 100644 --- a/polkadot/runtime/test-runtime/src/lib.rs +++ b/polkadot/runtime/test-runtime/src/lib.rs @@ -344,6 +344,7 @@ impl onchain::Config for OnChainSeqPhragmen { const MAX_QUOTA_NOMINATIONS: u32 = 16; impl pallet_staking::Config for Runtime { + type OldCurrency = Balances; type Currency = Balances; type CurrencyBalance = Balance; type UnixTime = Timestamp; diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index 46d5f15be34a..df3d088bc0c6 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -730,6 +730,7 @@ parameter_types! { } impl pallet_staking::Config for Runtime { + type OldCurrency = Balances; type Currency = Balances; type CurrencyBalance = Balance; type RuntimeHoldReason = RuntimeHoldReason; diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index 5f8122822d8d..720d8bd475e8 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -666,6 +666,7 @@ impl pallet_staking::BenchmarkingConfig for StakingBenchmarkingConfig { } impl pallet_staking::Config for Runtime { + type OldCurrency = Balances; type Currency = Balances; type CurrencyBalance = Balance; type UnixTime = Timestamp; diff --git a/substrate/frame/babe/src/mock.rs b/substrate/frame/babe/src/mock.rs index 4e4052b2b566..4a173ecdc27f 100644 --- a/substrate/frame/babe/src/mock.rs +++ b/substrate/frame/babe/src/mock.rs @@ -148,6 +148,7 @@ impl onchain::Config for OnChainSeqPhragmen { #[derive_impl(pallet_staking::config_preludes::TestDefaultConfig)] impl pallet_staking::Config for Test { + type OldCurrency = Balances; type Currency = Balances; type SessionsPerEra = SessionsPerEra; type BondingDuration = BondingDuration; diff --git a/substrate/frame/beefy/src/mock.rs b/substrate/frame/beefy/src/mock.rs index 5c79d8f7d7d7..f3a3446691cd 100644 --- a/substrate/frame/beefy/src/mock.rs +++ b/substrate/frame/beefy/src/mock.rs @@ -226,6 +226,7 @@ impl onchain::Config for OnChainSeqPhragmen { #[derive_impl(pallet_staking::config_preludes::TestDefaultConfig)] impl pallet_staking::Config for Test { type RuntimeEvent = RuntimeEvent; + type OldCurrency = Balances; type Currency = Balances; type AdminOrigin = frame_system::EnsureRoot; type SessionInterface = Self; diff --git a/substrate/frame/delegated-staking/src/mock.rs b/substrate/frame/delegated-staking/src/mock.rs index 811d5739f4e9..875279864f7a 100644 --- a/substrate/frame/delegated-staking/src/mock.rs +++ b/substrate/frame/delegated-staking/src/mock.rs @@ -102,6 +102,7 @@ impl onchain::Config for OnChainSeqPhragmen { #[derive_impl(pallet_staking::config_preludes::TestDefaultConfig)] impl pallet_staking::Config for Runtime { + type OldCurrency = Balances; type Currency = Balances; type UnixTime = pallet_timestamp::Pallet; type AdminOrigin = frame_system::EnsureRoot; diff --git a/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs b/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs index f20e3983b09d..9e0b02a9275f 100644 --- a/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs +++ b/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs @@ -285,6 +285,7 @@ pub(crate) const SLASHING_DISABLING_FACTOR: usize = 3; #[derive_impl(pallet_staking::config_preludes::TestDefaultConfig)] impl pallet_staking::Config for Runtime { + type OldCurrency = Balances; type Currency = Balances; type CurrencyBalance = Balance; type UnixTime = Timestamp; diff --git a/substrate/frame/fast-unstake/src/mock.rs b/substrate/frame/fast-unstake/src/mock.rs index 757052e230a1..19f01ebcd13b 100644 --- a/substrate/frame/fast-unstake/src/mock.rs +++ b/substrate/frame/fast-unstake/src/mock.rs @@ -105,6 +105,7 @@ impl frame_election_provider_support::ElectionProvider for MockElection { #[derive_impl(pallet_staking::config_preludes::TestDefaultConfig)] impl pallet_staking::Config for Runtime { + type OldCurrency = Balances; type Currency = Balances; type UnixTime = pallet_timestamp::Pallet; type AdminOrigin = frame_system::EnsureRoot; diff --git a/substrate/frame/grandpa/src/mock.rs b/substrate/frame/grandpa/src/mock.rs index caac4107cfb7..e9374ada472a 100644 --- a/substrate/frame/grandpa/src/mock.rs +++ b/substrate/frame/grandpa/src/mock.rs @@ -152,6 +152,7 @@ impl onchain::Config for OnChainSeqPhragmen { #[derive_impl(pallet_staking::config_preludes::TestDefaultConfig)] impl pallet_staking::Config for Test { + type OldCurrency = Balances; type Currency = Balances; type CurrencyBalance = ::Balance; type SessionsPerEra = SessionsPerEra; diff --git a/substrate/frame/nomination-pools/benchmarking/src/mock.rs b/substrate/frame/nomination-pools/benchmarking/src/mock.rs index 15d9e2c56031..7c09cf22ad51 100644 --- a/substrate/frame/nomination-pools/benchmarking/src/mock.rs +++ b/substrate/frame/nomination-pools/benchmarking/src/mock.rs @@ -78,6 +78,7 @@ parameter_types! { } #[derive_impl(pallet_staking::config_preludes::TestDefaultConfig)] impl pallet_staking::Config for Runtime { + type OldCurrency = Balances; type Currency = Balances; type CurrencyBalance = Balance; type UnixTime = pallet_timestamp::Pallet; diff --git a/substrate/frame/nomination-pools/test-delegate-stake/src/mock.rs b/substrate/frame/nomination-pools/test-delegate-stake/src/mock.rs index d1bc4ef8ff28..8befa7838544 100644 --- a/substrate/frame/nomination-pools/test-delegate-stake/src/mock.rs +++ b/substrate/frame/nomination-pools/test-delegate-stake/src/mock.rs @@ -92,6 +92,7 @@ parameter_types! { #[derive_impl(pallet_staking::config_preludes::TestDefaultConfig)] impl pallet_staking::Config for Runtime { + type OldCurrency = Balances; type Currency = Balances; type UnixTime = pallet_timestamp::Pallet; type AdminOrigin = frame_system::EnsureRoot; diff --git a/substrate/frame/nomination-pools/test-transfer-stake/src/mock.rs b/substrate/frame/nomination-pools/test-transfer-stake/src/mock.rs index d913c5fe6948..d1dcaec7c4d8 100644 --- a/substrate/frame/nomination-pools/test-transfer-stake/src/mock.rs +++ b/substrate/frame/nomination-pools/test-transfer-stake/src/mock.rs @@ -84,6 +84,7 @@ parameter_types! { #[derive_impl(pallet_staking::config_preludes::TestDefaultConfig)] impl pallet_staking::Config for Runtime { + type OldCurrency = Balances; type Currency = Balances; type UnixTime = pallet_timestamp::Pallet; type AdminOrigin = frame_system::EnsureRoot; diff --git a/substrate/frame/offences/benchmarking/src/mock.rs b/substrate/frame/offences/benchmarking/src/mock.rs index e243ad0e718e..144f5086dbd3 100644 --- a/substrate/frame/offences/benchmarking/src/mock.rs +++ b/substrate/frame/offences/benchmarking/src/mock.rs @@ -126,6 +126,7 @@ impl onchain::Config for OnChainSeqPhragmen { #[derive_impl(pallet_staking::config_preludes::TestDefaultConfig)] impl pallet_staking::Config for Test { + type OldCurrency = Balances; type Currency = Balances; type CurrencyBalance = ::Balance; type UnixTime = pallet_timestamp::Pallet; diff --git a/substrate/frame/root-offences/src/mock.rs b/substrate/frame/root-offences/src/mock.rs index af073d7672cf..d7f41fe25467 100644 --- a/substrate/frame/root-offences/src/mock.rs +++ b/substrate/frame/root-offences/src/mock.rs @@ -126,6 +126,7 @@ parameter_types! { #[derive_impl(pallet_staking::config_preludes::TestDefaultConfig)] impl pallet_staking::Config for Test { + type OldCurrency = Balances; type Currency = Balances; type CurrencyBalance = ::Balance; type UnixTime = Timestamp; diff --git a/substrate/frame/session/benchmarking/src/mock.rs b/substrate/frame/session/benchmarking/src/mock.rs index 2aec58cceded..5611cbc786dd 100644 --- a/substrate/frame/session/benchmarking/src/mock.rs +++ b/substrate/frame/session/benchmarking/src/mock.rs @@ -131,6 +131,7 @@ impl onchain::Config for OnChainSeqPhragmen { #[derive_impl(pallet_staking::config_preludes::TestDefaultConfig)] impl pallet_staking::Config for Test { + type OldCurrency = Balances; type Currency = Balances; type CurrencyBalance = ::Balance; type UnixTime = pallet_timestamp::Pallet; diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index 61602253d3a1..894a9b9747b9 100644 --- a/substrate/frame/staking/src/mock.rs +++ b/substrate/frame/staking/src/mock.rs @@ -263,6 +263,7 @@ pub(crate) const DISABLING_LIMIT_FACTOR: usize = 3; #[derive_impl(crate::config_preludes::TestDefaultConfig)] impl crate::pallet::pallet::Config for Test { + type OldCurrency = Balances; type Currency = Balances; type UnixTime = Timestamp; type RewardRemainder = RewardRemainderMock; diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 7738188d0ec2..083f2116aa95 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -29,8 +29,8 @@ use frame_support::{ hold::{Balanced as FunHoldBalanced, Mutate as FunHoldMutate}, Mutate as FunMutate, }, - Defensive, DefensiveSaturating, EnsureOrigin, EstimateNextNewSession, Get, OnUnbalanced, - UnixTime, + Defensive, DefensiveSaturating, EnsureOrigin, EstimateNextNewSession, Get, + InspectLockableCurrency, OnUnbalanced, UnixTime, }, weights::Weight, BoundedVec, @@ -92,6 +92,14 @@ pub mod pallet { #[pallet::config(with_default)] pub trait Config: frame_system::Config { + /// The old trait for staking balance. Deprecated and only used for migrating old ledgers. + #[pallet::no_default] + type OldCurrency: InspectLockableCurrency< + Self::AccountId, + Moment = BlockNumberFor, + Balance = Self::CurrencyBalance, + >; + /// The staking balance. #[pallet::no_default] type Currency: FunHoldMutate< From 9ed47166ef59a450e1a7a58aae0a4b6745e206ee Mon Sep 17 00:00:00 2001 From: Ankan Date: Fri, 13 Sep 2024 16:50:00 +0200 Subject: [PATCH 062/142] add old currency to config --- polkadot/runtime/westend/src/tests.rs | 4 +- substrate/frame/staking/src/pallet/impls.rs | 48 ++++++++++++--------- substrate/frame/staking/src/pallet/mod.rs | 5 +++ 3 files changed, 33 insertions(+), 24 deletions(-) diff --git a/polkadot/runtime/westend/src/tests.rs b/polkadot/runtime/westend/src/tests.rs index c7a08f02bc8a..d68b0258692a 100644 --- a/polkadot/runtime/westend/src/tests.rs +++ b/polkadot/runtime/westend/src/tests.rs @@ -278,9 +278,7 @@ mod remote_tests { let mut err = 0; // iterate over all pools pallet_staking::Ledger::::iter_values().for_each(|ledger| { - match pallet_staking::Pallet::::migrate_lock_to_hold::( - &ledger.stash, - ) { + match pallet_staking::Pallet::::migrate_currency(&ledger.stash) { Ok(_) => { success += 1; }, diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index 574fb565063f..24cacf3919b8 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -61,6 +61,7 @@ use super::pallet::*; #[cfg(feature = "try-runtime")] use frame_support::ensure; +use frame_support::traits::LockIdentifier; #[cfg(any(test, feature = "try-runtime"))] use sp_runtime::TryRuntimeError; @@ -1160,41 +1161,46 @@ impl Pallet { EraInfo::::get_full_exposure(era, account) } - pub fn migrate_lock_to_hold(stash: &T::AccountId) -> DispatchResult - where - OldCurrency: frame_support::traits::InspectLockableCurrency, - BalanceOf: From, - { - if Self::is_virtual_staker(stash) { - // we don't need to do anything for virtual stakers since their funds are not locked by - // this pallet. - return Ok(()) - } + pub fn migrate_currency(stash: &T::AccountId) -> DispatchResult { + use frame_support::traits::{InspectLockableCurrency, LockIdentifier, LockableCurrency}; + // we can't do anything for virtual stakers since their funds are not managed/held by + // this pallet. + ensure!(!Self::is_virtual_staker(stash), Error::::VirtualStakerNotAllowed); let ledger = Self::ledger(Stash(stash.clone()))?; - const LOCK_ID: frame_support::traits::LockIdentifier = *b"staking "; - let locked: BalanceOf = OldCurrency::balance_locked(LOCK_ID, stash).into(); + const LOCK_ID: LockIdentifier = *b"staking "; + let locked: BalanceOf = T::OldCurrency::balance_locked(LOCK_ID, stash).into(); + ensure!(!locked.is_zero(), Error::::AlreadyMigrated); + ensure!(ledger.total == locked, Error::::BadState); + let max_hold = asset::stakeable_balance::(&stash); - if max_hold >= locked { - // this is great. easy job for us. - // just hold asset. + let force_withdraw = if max_hold >= locked { + // this means we can replace all locked with stake. yay! asset::update_stake::(&stash, locked)?; + Zero::zero() } else { - let ed = asset::existential_deposit::(); - let unsafe_withdraw = locked.saturating_sub(max_hold); - log::info!(target: "remote_test", "unsafe_withdraw from stash: {:?}, value {:?}, active {:?}", stash, unsafe_withdraw/ed, ledger.active/ed); + // if we are here, it means we cannot hold all funds. We will do a force withdraw from + // ledger which will mean the stake of the user will abruptly reduce. + let force_withdraw = locked.saturating_sub(max_hold); + log::info!(target: "remote_test", "force_withdraw from stash: {:?}, value {:?}, active {:?}", stash, force_withdraw, ledger.active); - // we ignore if active is 0. This amount will get unlocked anyways in the future. + // we ignore if active is 0. It implies the locked amount is not actively staked. The + // account can still get away from potential slash but we can't do much better here. StakingLedger { total: max_hold, - active: ledger.active.saturating_sub(unsafe_withdraw), + active: ledger.active.saturating_sub(force_withdraw), // we are not changing the stash, so we can keep the stash. ..ledger } .update()?; - } + force_withdraw + }; + // We used to have an extra consumer before. Get rid of it. frame_system::Pallet::::dec_consumers(&stash); + + Self::deposit_event(Event::::CurrencyMigrated { stash: stash.clone(), force_withdraw }); + Ok(()) } } diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 083f2116aa95..2421f3fcae8a 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -893,6 +893,9 @@ pub mod pallet { ForceEra { mode: Forcing }, /// Report of a controller batch deprecation. ControllerBatchDeprecated { failures: u32 }, + /// Staking balance migrated from locks to holds, with any balance that could not be held + /// is force withdrawn. + CurrencyMigrated { stash: T::AccountId, force_withdraw: BalanceOf }, } #[pallet::error] @@ -966,6 +969,8 @@ pub mod pallet { VirtualStakerNotAllowed, /// Stash could not be reaped as other pallet might depend on it. CannotReapStash, + /// The stake of this account is already migrated to `Fungible` holds. + AlreadyMigrated, } #[pallet::hooks] From c009a62fecd36bbcd23278af1367d1f68a8852e6 Mon Sep 17 00:00:00 2001 From: Ankan Date: Sun, 15 Sep 2024 20:05:10 +0200 Subject: [PATCH 063/142] ensure ledger update also updates holds --- substrate/frame/staking/Cargo.toml | 1 + substrate/frame/staking/src/lib.rs | 3 +- substrate/frame/staking/src/mock.rs | 13 +++- substrate/frame/staking/src/pallet/impls.rs | 11 +-- substrate/frame/staking/src/tests.rs | 85 ++++++++++++++++++++- 5 files changed, 105 insertions(+), 8 deletions(-) diff --git a/substrate/frame/staking/Cargo.toml b/substrate/frame/staking/Cargo.toml index a6a0ccd3b0a7..e0b6bab7b69b 100644 --- a/substrate/frame/staking/Cargo.toml +++ b/substrate/frame/staking/Cargo.toml @@ -50,6 +50,7 @@ substrate-test-utils = { workspace = true } frame-benchmarking = { workspace = true, default-features = true } frame-election-provider-support = { workspace = true, default-features = true } rand_chacha = { workspace = true, default-features = true } +frame-support = { features = ["experimental"], workspace = true, default-features = true } [features] default = ["std"] diff --git a/substrate/frame/staking/src/lib.rs b/substrate/frame/staking/src/lib.rs index e6c01948a897..179309cabd7a 100644 --- a/substrate/frame/staking/src/lib.rs +++ b/substrate/frame/staking/src/lib.rs @@ -313,7 +313,7 @@ use frame_support::{ defensive, defensive_assert, traits::{ tokens::fungible::{Credit, Debt}, - ConstU32, Defensive, DefensiveMax, DefensiveSaturating, Get, + ConstU32, Defensive, DefensiveMax, DefensiveSaturating, Get, LockIdentifier, }, weights::Weight, BoundedVec, CloneNoBound, EqNoBound, PartialEqNoBound, RuntimeDebugNoBound, @@ -335,6 +335,7 @@ pub use weights::WeightInfo; pub use pallet::{pallet::*, UseNominatorsAndValidatorsMap, UseValidatorsMap}; +pub(crate) const STAKING_ID: LockIdentifier = *b"staking "; pub(crate) const LOG_TARGET: &str = "runtime::staking"; // syntactic sugar for logging. diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index 894a9b9747b9..a30792b938c3 100644 --- a/substrate/frame/staking/src/mock.rs +++ b/substrate/frame/staking/src/mock.rs @@ -25,7 +25,7 @@ use frame_election_provider_support::{ use frame_support::{ assert_ok, derive_impl, ord_parameter_types, parameter_types, traits::{ - ConstU64, EitherOfDiverse, FindAuthor, Get, Hooks, Imbalance, OnUnbalanced, + ConstU64, EitherOfDiverse, FindAuthor, Get, Hooks, Imbalance, LockIdentifier, OnUnbalanced, OneSessionHandler, }, weights::constants::RocksDbWeight, @@ -929,3 +929,14 @@ pub(crate) fn staking_events_since_last_call() -> Vec> { pub(crate) fn balances(who: &AccountId) -> (Balance, Balance) { (asset::stakeable_balance::(who), Balances::reserved_balance(who)) } + +pub(crate) fn migrate_to_old_currency(who: &AccountId) { + use frame_support::traits::LockableCurrency; + let staked = asset::staked::(who); + + // apply locks. + Balances::set_lock(STAKING_ID, who, staked, frame_support::traits::WithdrawReasons::all()); + + // remove holds. + asset::kill_stake::(who).expect("remove hold failed"); +} diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index 24cacf3919b8..86358c13dcd4 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -54,6 +54,7 @@ use crate::{ BalanceOf, EraInfo, EraPayout, Exposure, ExposureOf, Forcing, IndividualExposure, LedgerIntegrityState, MaxNominationsOf, MaxWinnersOf, Nominations, NominationsQuota, PositiveImbalanceOf, RewardDestination, SessionInterface, StakingLedger, ValidatorPrefs, + STAKING_ID, }; use alloc::{boxed::Box, vec, vec::Vec}; @@ -1162,14 +1163,13 @@ impl Pallet { } pub fn migrate_currency(stash: &T::AccountId) -> DispatchResult { - use frame_support::traits::{InspectLockableCurrency, LockIdentifier, LockableCurrency}; + use frame_support::traits::{InspectLockableCurrency, LockableCurrency}; // we can't do anything for virtual stakers since their funds are not managed/held by // this pallet. ensure!(!Self::is_virtual_staker(stash), Error::::VirtualStakerNotAllowed); let ledger = Self::ledger(Stash(stash.clone()))?; - const LOCK_ID: LockIdentifier = *b"staking "; - let locked: BalanceOf = T::OldCurrency::balance_locked(LOCK_ID, stash).into(); + let locked: BalanceOf = T::OldCurrency::balance_locked(STAKING_ID, stash).into(); ensure!(!locked.is_zero(), Error::::AlreadyMigrated); ensure!(ledger.total == locked, Error::::BadState); @@ -1196,11 +1196,12 @@ impl Pallet { force_withdraw }; - // We used to have an extra consumer before. Get rid of it. + // remove lock + T::OldCurrency::remove_lock(STAKING_ID, &stash); + // Get rid of the extra consumer we used to have with OldCurrency. frame_system::Pallet::::dec_consumers(&stash); Self::deposit_event(Event::::CurrencyMigrated { stash: stash.clone(), force_withdraw }); - Ok(()) } } diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index e66a04fe7aae..105f70dd1622 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -26,8 +26,9 @@ use frame_election_provider_support::{ use frame_support::{ assert_noop, assert_ok, assert_storage_noop, dispatch::{extract_actual_weight, GetDispatchInfo, WithPostDispatchInfo}, + hypothetically, pallet_prelude::*, - traits::{Currency, Get, ReservableCurrency}, + traits::{Currency, Get, InspectLockableCurrency, ReservableCurrency}, }; use mock::*; @@ -8347,3 +8348,85 @@ mod byzantine_threshold_disabling_strategy { }); } } + +mod hold_migration { + use super::*; + use sp_staking::{Stake, StakingInterface}; + + #[test] + fn ledger_update_creates_hold() { + ExtBuilder::default().has_stakers(true).build_and_execute(|| { + // GIVEN alice who is a nominator with old currency + let alice = 300; + bond_nominator(alice, 1000, vec![11]); + assert_eq!(asset::staked::(&alice), 1000); + assert_eq!(Balances::balance_locked(STAKING_ID, &alice), 0); + // migrate alice currency to legacy locks + migrate_to_old_currency(&alice); + // no more holds + assert_eq!(asset::staked::(&alice), 0); + assert_eq!(Balances::balance_locked(STAKING_ID, &alice), 1000); + assert_eq!( + ::stake(&alice), + Ok(Stake { total: 1000, active: 1000 }) + ); + + // any ledger mutation should create a hold + hypothetically!({ + // give some extra balance to alice. + let _ = asset::mint_existing::(&alice, 100); + + // WHEN new fund is bonded to ledger. + assert_ok!(Staking::bond_extra(RuntimeOrigin::signed(alice), 100)); + + // THEN new hold is created + assert_eq!(asset::staked::(&alice), 1000 + 100); + assert_eq!( + ::stake(&alice), + Ok(Stake { total: 1100, active: 1100 }) + ); + + // old locked balance is untouched + assert_eq!(Balances::balance_locked(STAKING_ID, &alice), 1000); + }); + + hypothetically!({ + // WHEN new fund is unbonded from ledger. + assert_ok!(Staking::unbond(RuntimeOrigin::signed(alice), 100)); + + // THEN hold is updated. + assert_eq!(asset::staked::(&alice), 1000); + assert_eq!( + ::stake(&alice), + Ok(Stake { total: 1000, active: 900 }) + ); + + // old locked balance is untouched + assert_eq!(Balances::balance_locked(STAKING_ID, &alice), 1000); + }); + + // WHEN alice currency is migrated. + assert_ok!(Staking::migrate_currency(&alice)); + + // THEN hold is updated. + assert_eq!(asset::staked::(&alice), 1000); + assert_eq!( + ::stake(&alice), + Ok(Stake { total: 1000, active: 1000 }) + ); + + // locked balance is removed + assert_eq!(Balances::balance_locked(STAKING_ID, &alice), 0); + }); + } + + #[test] + fn migrate_removes_old_lock() {} + #[test] + fn cannot_hold_all_stake() {} + + #[test] + fn hold_includes_ed() { + // edge case bond extra with all free does not work + } +} From 17c4aa3f86016cc825cfe1267e7cba3d8908632d Mon Sep 17 00:00:00 2001 From: Ankan Date: Sun, 15 Sep 2024 21:42:26 +0200 Subject: [PATCH 064/142] new call to migrate currency --- polkadot/runtime/westend/src/tests.rs | 5 ++- substrate/frame/staking/src/mock.rs | 8 ++-- substrate/frame/staking/src/pallet/impls.rs | 4 +- substrate/frame/staking/src/pallet/mod.rs | 7 ++++ substrate/frame/staking/src/tests.rs | 45 +++++++++++++++++++-- 5 files changed, 59 insertions(+), 10 deletions(-) diff --git a/polkadot/runtime/westend/src/tests.rs b/polkadot/runtime/westend/src/tests.rs index d68b0258692a..ae212e583586 100644 --- a/polkadot/runtime/westend/src/tests.rs +++ b/polkadot/runtime/westend/src/tests.rs @@ -278,7 +278,10 @@ mod remote_tests { let mut err = 0; // iterate over all pools pallet_staking::Ledger::::iter_values().for_each(|ledger| { - match pallet_staking::Pallet::::migrate_currency(&ledger.stash) { + match pallet_staking::Pallet::::migrate_currency( + RuntimeOrigin::signed(alice.clone()).into(), + &ledger.stash, + ) { Ok(_) => { success += 1; }, diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index a30792b938c3..f9ec75edf43f 100644 --- a/substrate/frame/staking/src/mock.rs +++ b/substrate/frame/staking/src/mock.rs @@ -25,7 +25,7 @@ use frame_election_provider_support::{ use frame_support::{ assert_ok, derive_impl, ord_parameter_types, parameter_types, traits::{ - ConstU64, EitherOfDiverse, FindAuthor, Get, Hooks, Imbalance, LockIdentifier, OnUnbalanced, + ConstU64, EitherOfDiverse, FindAuthor, Get, Hooks, Imbalance, OnUnbalanced, OneSessionHandler, }, weights::constants::RocksDbWeight, @@ -934,9 +934,11 @@ pub(crate) fn migrate_to_old_currency(who: &AccountId) { use frame_support::traits::LockableCurrency; let staked = asset::staked::(who); - // apply locks. + // apply locks (this also adds a consumer). Balances::set_lock(STAKING_ID, who, staked, frame_support::traits::WithdrawReasons::all()); - // remove holds. asset::kill_stake::(who).expect("remove hold failed"); + + // replicate old behaviour of explicitly increment consumer. + System::inc_consumers(who).expect("increment consumer failed"); } diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index 86358c13dcd4..4a4e5430aad7 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -62,7 +62,6 @@ use super::pallet::*; #[cfg(feature = "try-runtime")] use frame_support::ensure; -use frame_support::traits::LockIdentifier; #[cfg(any(test, feature = "try-runtime"))] use sp_runtime::TryRuntimeError; @@ -1162,7 +1161,7 @@ impl Pallet { EraInfo::::get_full_exposure(era, account) } - pub fn migrate_currency(stash: &T::AccountId) -> DispatchResult { + pub(super) fn do_migrate_currency(stash: &T::AccountId) -> DispatchResult { use frame_support::traits::{InspectLockableCurrency, LockableCurrency}; // we can't do anything for virtual stakers since their funds are not managed/held by @@ -1198,6 +1197,7 @@ impl Pallet { // remove lock T::OldCurrency::remove_lock(STAKING_ID, &stash); + // Get rid of the extra consumer we used to have with OldCurrency. frame_system::Pallet::::dec_consumers(&stash); diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 2421f3fcae8a..3186d163a6f5 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -2180,6 +2180,13 @@ pub mod pallet { ); Ok(()) } + + #[pallet::call_index(30)] + #[pallet::weight(Weight::zero())] + pub fn migrate_currency(origin: OriginFor, stash: T::AccountId) -> DispatchResult { + let _ = ensure_signed(origin)?; + Self::do_migrate_currency(&stash) + } } } diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 105f70dd1622..1d09f20142f0 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -8406,7 +8406,7 @@ mod hold_migration { }); // WHEN alice currency is migrated. - assert_ok!(Staking::migrate_currency(&alice)); + assert_ok!(Staking::migrate_currency(RuntimeOrigin::signed(1), alice)); // THEN hold is updated. assert_eq!(asset::staked::(&alice), 1000); @@ -8421,12 +8421,49 @@ mod hold_migration { } #[test] - fn migrate_removes_old_lock() {} + fn migrate_removes_old_lock() { + ExtBuilder::default().has_stakers(true).build_and_execute(|| { + // GIVEN alice who is a nominator with old currency + let alice = 300; + bond_nominator(alice, 1000, vec![11]); + migrate_to_old_currency(&alice); + assert_eq!(asset::staked::(&alice), 0); + assert_eq!(Balances::balance_locked(STAKING_ID, &alice), 1000); + let pre_migrate_consumer = System::consumers(&alice); + System::reset_events(); + + // WHEN alice currency is migrated. + assert_ok!(Staking::migrate_currency(RuntimeOrigin::signed(1), alice)); + + // THEN + // ensure consumer count stays same. + assert_eq!(System::consumers(&alice), pre_migrate_consumer); + // ensure no lock + assert_eq!(Balances::balance_locked(STAKING_ID, &alice), 0); + // ensure stake and hold are same. + assert_eq!( + ::stake(&alice), + Ok(Stake { total: 1000, active: 1000 }) + ); + assert_eq!(asset::staked::(&alice), 1000); + // ensure events are emitted. + assert_eq!( + staking_events_since_last_call(), + vec![Event::CurrencyMigrated { stash: alice, force_withdraw: 0 }] + ); + }); + } #[test] - fn cannot_hold_all_stake() {} + fn cannot_hold_all_stake() { + ExtBuilder::default().has_stakers(true).build_and_execute(|| { + // check force withdraw + }); + } #[test] fn hold_includes_ed() { - // edge case bond extra with all free does not work + ExtBuilder::default().has_stakers(true).build_and_execute(|| { + // edge case bond extra with all free does not work + }); } } From c4af869432d4cf57ffa0f9afba1961626ed67bd6 Mon Sep 17 00:00:00 2001 From: Ankan Date: Sun, 15 Sep 2024 21:58:56 +0200 Subject: [PATCH 065/142] force withdraw test --- substrate/frame/staking/src/tests.rs | 46 +++++++++++++++++++++++----- 1 file changed, 39 insertions(+), 7 deletions(-) diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 1d09f20142f0..87bd8b371287 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -8455,15 +8455,47 @@ mod hold_migration { } #[test] fn cannot_hold_all_stake() { + // When there is not enough funds to hold all stake, part of the stake if force withdrawn. + // At end of the migration, the stake and hold should be same. ExtBuilder::default().has_stakers(true).build_and_execute(|| { - // check force withdraw - }); - } + // GIVEN alice who is a nominator with old currency. + let alice = 300; + let stake = 1000; + bond_nominator(alice, stake, vec![11]); + migrate_to_old_currency(&alice); + assert_eq!(asset::staked::(&alice), 0); + assert_eq!(Balances::balance_locked(STAKING_ID, &alice), stake); + // ledger has 1000 staked. + assert_eq!( + ::stake(&alice), + Ok(Stake { total: stake, active: stake }) + ); - #[test] - fn hold_includes_ed() { - ExtBuilder::default().has_stakers(true).build_and_execute(|| { - // edge case bond extra with all free does not work + // She has extra reserved amount which would prevent us from holding all stake. + let expected_force_withdraw = 200; + assert_ok!(Balances::reserve(&alice, expected_force_withdraw)); + + // clear events + System::reset_events(); + + // WHEN alice currency is migrated. + assert_ok!(Staking::migrate_currency(RuntimeOrigin::signed(1), alice)); + + // THEN + let expected_hold = stake - expected_force_withdraw; + // ensure no lock + assert_eq!(Balances::balance_locked(STAKING_ID, &alice), 0); + // ensure stake and hold are same. + assert_eq!( + ::stake(&alice), + Ok(Stake { total: expected_hold, active: expected_hold }) + ); + assert_eq!(asset::staked::(&alice), expected_hold); + // ensure events are emitted. + assert_eq!( + staking_events_since_last_call(), + vec![Event::CurrencyMigrated { stash: alice, force_withdraw: expected_force_withdraw }] + ); }); } } From e1f1d42669a9b11b946fb3d42943674b388c1986 Mon Sep 17 00:00:00 2001 From: Ankan Date: Sun, 15 Sep 2024 21:59:16 +0200 Subject: [PATCH 066/142] fmt --- substrate/frame/staking/src/tests.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 87bd8b371287..0cbaacbedb9c 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -8494,7 +8494,10 @@ mod hold_migration { // ensure events are emitted. assert_eq!( staking_events_since_last_call(), - vec![Event::CurrencyMigrated { stash: alice, force_withdraw: expected_force_withdraw }] + vec![Event::CurrencyMigrated { + stash: alice, + force_withdraw: expected_force_withdraw + }] ); }); } From b57660d75c3112f391e0f40390d1625716620079 Mon Sep 17 00:00:00 2001 From: Ankan Date: Sun, 15 Sep 2024 23:53:27 +0200 Subject: [PATCH 067/142] add reap stash fail test --- substrate/frame/staking/src/asset.rs | 3 +- substrate/frame/staking/src/ledger.rs | 5 +-- substrate/frame/staking/src/pallet/mod.rs | 11 +++++-- substrate/frame/staking/src/tests.rs | 38 ++++++++++++++++++++++- 4 files changed, 51 insertions(+), 6 deletions(-) diff --git a/substrate/frame/staking/src/asset.rs b/substrate/frame/staking/src/asset.rs index 71da4f5f4c1d..5034ea15ea43 100644 --- a/substrate/frame/staking/src/asset.rs +++ b/substrate/frame/staking/src/asset.rs @@ -80,7 +80,8 @@ pub fn set_stakeable_balance(who: &T::AccountId, value: BalanceOf) let _ = T::Currency::set_balance(who, Zero::zero()); } - assert_eq!(total_balance::(who), value); + // ensure new stakeable balance same as desired `value`. + assert_eq!(stakeable_balance::(who), value); } /// Update `amount` at stake for `who`. diff --git a/substrate/frame/staking/src/ledger.rs b/substrate/frame/staking/src/ledger.rs index b2163fbef516..947050f10183 100644 --- a/substrate/frame/staking/src/ledger.rs +++ b/substrate/frame/staking/src/ledger.rs @@ -251,7 +251,7 @@ impl StakingLedger { /// Clears all data related to a staking ledger and its bond in both [`Ledger`] and [`Bonded`] /// storage items and updates the stash staking lock. - pub(crate) fn kill(stash: &T::AccountId) -> Result<(), Error> { + pub(crate) fn kill(stash: &T::AccountId) -> DispatchResult { let controller = >::get(stash).ok_or(Error::::NotStash)?; >::get(&controller).ok_or(Error::::NotController).map(|ledger| { @@ -262,7 +262,7 @@ impl StakingLedger { // kill virtual staker if it exists. if >::take(&ledger.stash).is_none() { // if not virtual staker, clear locks. - asset::kill_stake::(&ledger.stash).map_err(|_| Error::::CannotReapStash)?; + asset::kill_stake::(&ledger.stash)?; } Ok(()) @@ -270,6 +270,7 @@ impl StakingLedger { } } +use sp_runtime::DispatchResult; #[cfg(test)] use { crate::UnlockChunk, diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 3186d163a6f5..afacce6bb53e 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -2182,10 +2182,17 @@ pub mod pallet { } #[pallet::call_index(30)] + // FIXME(ank4n): Bench #[pallet::weight(Weight::zero())] - pub fn migrate_currency(origin: OriginFor, stash: T::AccountId) -> DispatchResult { + pub fn migrate_currency( + origin: OriginFor, + stash: T::AccountId, + ) -> DispatchResultWithPostInfo { let _ = ensure_signed(origin)?; - Self::do_migrate_currency(&stash) + Self::do_migrate_currency(&stash)?; + + // Refund the transaction fee. + Ok(Pays::No.into()) } } } diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 0cbaacbedb9c..785be1097486 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -26,7 +26,7 @@ use frame_election_provider_support::{ use frame_support::{ assert_noop, assert_ok, assert_storage_noop, dispatch::{extract_actual_weight, GetDispatchInfo, WithPostDispatchInfo}, - hypothetically, + hypothetically, hypothetically_ok, pallet_prelude::*, traits::{Currency, Get, InspectLockableCurrency, ReservableCurrency}, }; @@ -1940,6 +1940,42 @@ fn reap_stash_works() { }); } +#[test] +fn reap_stash_fails_if_extra_consumer() { + ExtBuilder::default() + .existential_deposit(10) + .balance_factor(10) + .build_and_execute(|| { + // given + assert_eq!(asset::staked::(&11), 10 * 1000); + assert_eq!(Staking::bonded(&11), Some(11)); + + // When ledger goes below ED + let mut ledger = Staking::ledger(11.into()).unwrap(); + ledger.slash(ledger.total, 10, 1); + assert_ok!(ledger.update()); + // make stake balance as zero. + asset::set_stakeable_balance::(&11, 0); + assert_eq!(asset::staked::(&11), 0); + + // reap stash would work without the extra consumer. + hypothetically_ok!(Staking::reap_stash(RuntimeOrigin::signed(20), 11, 0)); + + // mock stash has an extra consumer from another pallet in the runtime. + System::inc_consumers(&11).expect("stash has a provider so this should not fail"); + + // This would prevent the pallet to decrement provider from reaping the stash. + assert_noop!( + Staking::reap_stash(RuntimeOrigin::signed(20), 11, 0), + DispatchError::ConsumerRemaining + ); + + // Once the extra consumer is removed, the pallet can reap the stash. + System::dec_consumers(&11); + assert_ok!(Staking::reap_stash(RuntimeOrigin::signed(20), 11, 0)); + }); +} + #[test] fn reap_stash_works_with_existential_deposit_zero() { ExtBuilder::default() From dc55b979e1182db09bb730dbb15beb6338ea0fc4 Mon Sep 17 00:00:00 2001 From: Ankan Date: Mon, 16 Sep 2024 00:00:36 +0200 Subject: [PATCH 068/142] split stakeable into staked and free to stake --- substrate/frame/staking/src/asset.rs | 13 ++++++++++--- substrate/frame/staking/src/pallet/impls.rs | 9 ++------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/substrate/frame/staking/src/asset.rs b/substrate/frame/staking/src/asset.rs index 5034ea15ea43..0bf70dab6407 100644 --- a/substrate/frame/staking/src/asset.rs +++ b/substrate/frame/staking/src/asset.rs @@ -25,7 +25,7 @@ use frame_support::traits::{ }, tokens::Precision, }; -use sp_runtime::{traits::Zero, DispatchResult}; +use sp_runtime::{traits::Zero, DispatchResult, Saturating}; use crate::{ BalanceOf, Config, HoldReason, NegativeImbalanceOf, PositiveImbalanceOf, SessionInterface, @@ -50,16 +50,23 @@ pub fn total_balance(who: &T::AccountId) -> BalanceOf { /// /// This includes balance free to stake along with any balance that is already staked. pub fn stakeable_balance(who: &T::AccountId) -> BalanceOf { - T::Currency::balance(who) + T::Currency::balance_on_hold(&HoldReason::Staking.into(), who) + free_to_stake::(who).saturating_add(staked::(who)) } /// Balance of `who` that is currently at stake. /// -/// The staked amount is locked and cannot be transferred out of `who`s account. +/// The staked amount is on hold and cannot be transferred out of `who`s account. pub fn staked(who: &T::AccountId) -> BalanceOf { T::Currency::balance_on_hold(&HoldReason::Staking.into(), who) } +/// Balance of who that can be staked additionally. +/// +/// Does not include the current stake. +pub fn free_to_stake(who: &T::AccountId) -> BalanceOf { + T::Currency::balance(who) +} + /// Set balance that can be staked for `who`. /// /// `Value` must be greater than already staked plus existential deposit for free balance. diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index 4a4e5430aad7..9cc7576ae7fa 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -36,8 +36,7 @@ use frame_system::{pallet_prelude::BlockNumberFor, RawOrigin}; use pallet_session::historical; use sp_runtime::{ traits::{ - Bounded, CheckedAdd, CheckedSub, Convert, One, SaturatedConversion, Saturating, - StaticLookup, Zero, + Bounded, CheckedAdd, Convert, One, SaturatedConversion, Saturating, StaticLookup, Zero, }, ArithmeticError, DispatchResult, Perbill, Percent, }; @@ -164,11 +163,7 @@ impl Pallet { additional } else { // additional amount or actual balance of stash whichever is lower. - additional.min( - asset::stakeable_balance::(stash) - .checked_sub(&ledger.total) - .ok_or(ArithmeticError::Overflow)?, - ) + additional.min(asset::free_to_stake::(stash)) }; ledger.total = ledger.total.checked_add(&extra).ok_or(ArithmeticError::Overflow)?; From 591945df7cfdc34b92838ccc7cc02bd08d565ce6 Mon Sep 17 00:00:00 2001 From: Ankan Date: Mon, 16 Sep 2024 01:07:21 +0200 Subject: [PATCH 069/142] refactor remote test migration --- polkadot/runtime/westend/src/tests.rs | 15 ++++++++++++--- substrate/frame/staking/src/pallet/impls.rs | 1 - 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/polkadot/runtime/westend/src/tests.rs b/polkadot/runtime/westend/src/tests.rs index ae212e583586..53e85cebe620 100644 --- a/polkadot/runtime/westend/src/tests.rs +++ b/polkadot/runtime/westend/src/tests.rs @@ -276,13 +276,21 @@ mod remote_tests { let mut success = 0; let mut err = 0; + let mut force_withdraw_acc = 0; // iterate over all pools - pallet_staking::Ledger::::iter_values().for_each(|ledger| { + pallet_staking::Ledger::::iter().for_each(|(ctrl, ledger)| { match pallet_staking::Pallet::::migrate_currency( RuntimeOrigin::signed(alice.clone()).into(), - &ledger.stash, + ledger.stash.clone(), ) { Ok(_) => { + let updated_ledger = + pallet_staking::Ledger::::get(&ctrl).expect("ledger exists"); + let force_withdraw = ledger.total - updated_ledger.total; + if force_withdraw > 0 { + force_withdraw_acc += force_withdraw; + log::info!(target: "remote_test", "Force withdraw from stash {:?}: value {:?}", ledger.stash, force_withdraw); + } success += 1; }, Err(e) => { @@ -294,9 +302,10 @@ mod remote_tests { log::info!( target: "remote_test", - "Migration stats: success: {}, err: {}", + "Migration stats: success: {}, err: {}, total force withdrawn stake: {}", success, err, + force_withdraw_acc ); }); } diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index 9cc7576ae7fa..a399c8ac0015 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -1176,7 +1176,6 @@ impl Pallet { // if we are here, it means we cannot hold all funds. We will do a force withdraw from // ledger which will mean the stake of the user will abruptly reduce. let force_withdraw = locked.saturating_sub(max_hold); - log::info!(target: "remote_test", "force_withdraw from stash: {:?}, value {:?}, active {:?}", stash, force_withdraw, ledger.active); // we ignore if active is 0. It implies the locked amount is not actively staked. The // account can still get away from potential slash but we can't do much better here. From a1ccab713d9c7ea03b91418b7f45b306622df34b Mon Sep 17 00:00:00 2001 From: Ankan Date: Mon, 16 Sep 2024 22:32:44 +0200 Subject: [PATCH 070/142] add bench for migrate currency --- .../westend/src/weights/pallet_staking.rs | 4 ++++ substrate/frame/staking/src/asset.rs | 5 ++--- substrate/frame/staking/src/benchmarking.rs | 12 ++++++++++++ substrate/frame/staking/src/mock.rs | 13 ------------- substrate/frame/staking/src/pallet/mod.rs | 5 ++--- substrate/frame/staking/src/testing_utils.rs | 18 ++++++++++++++++++ substrate/frame/staking/src/tests.rs | 6 +++--- substrate/frame/staking/src/weights.rs | 9 +++++++++ 8 files changed, 50 insertions(+), 22 deletions(-) diff --git a/polkadot/runtime/westend/src/weights/pallet_staking.rs b/polkadot/runtime/westend/src/weights/pallet_staking.rs index 393fa0b37176..b3443f7c6cd2 100644 --- a/polkadot/runtime/westend/src/weights/pallet_staking.rs +++ b/polkadot/runtime/westend/src/weights/pallet_staking.rs @@ -826,4 +826,8 @@ impl pallet_staking::WeightInfo for WeightInfo { .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(4)) } + fn migrate_currency() -> Weight { + // will be auto-generated + Default::default() + } } diff --git a/substrate/frame/staking/src/asset.rs b/substrate/frame/staking/src/asset.rs index 0bf70dab6407..847bfbc2db6c 100644 --- a/substrate/frame/staking/src/asset.rs +++ b/substrate/frame/staking/src/asset.rs @@ -111,12 +111,11 @@ pub fn kill_stake(who: &T::AccountId) -> DispatchResult { T::Currency::release_all(&HoldReason::Staking.into(), who, Precision::BestEffort) .map(|_| ())?; - // FIXME(ank4n): may have to update bench. Also add failing test if non session consumers on - // stash. if !frame_system::Pallet::::can_dec_provider(who) { // The session pallet keeps a consumer reference to validator stash which may block this // pallet from clearing its provider reference. If the account cannot provide for itself - // (via enough free balance) to keep the session key, we should clean up the session keys. + // (via enough free balance) to keep the session key, we try to clean up the session keys. + // If the extra consumer comes from somewhere else, reap stash would fail. T::SessionInterface::purge_keys(who.clone())?; } diff --git a/substrate/frame/staking/src/benchmarking.rs b/substrate/frame/staking/src/benchmarking.rs index 97a76932f1ba..33f282bdeeec 100644 --- a/substrate/frame/staking/src/benchmarking.rs +++ b/substrate/frame/staking/src/benchmarking.rs @@ -961,6 +961,18 @@ benchmarks! { assert_eq!(Staking::::inspect_bond_state(&stash), Ok(LedgerIntegrityState::Ok)); } + migrate_currency { + let (stash, _ctrl) = create_stash_controller::(USER_SEED, 100, RewardDestination::Staked)?; + let stake = asset::staked::(&stash); + migrate_to_old_currency::(stash.clone()); + // no holds + assert!(asset::staked::(&stash).is_zero()); + whitelist_account!(stash); + }: _(RawOrigin::Signed(stash.clone()), stash.clone()) + verify { + assert_eq!(asset::staked::(&stash), stake); + } + impl_benchmark_test_suite!( Staking, crate::mock::ExtBuilder::default().has_stakers(true), diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index f9ec75edf43f..894a9b9747b9 100644 --- a/substrate/frame/staking/src/mock.rs +++ b/substrate/frame/staking/src/mock.rs @@ -929,16 +929,3 @@ pub(crate) fn staking_events_since_last_call() -> Vec> { pub(crate) fn balances(who: &AccountId) -> (Balance, Balance) { (asset::stakeable_balance::(who), Balances::reserved_balance(who)) } - -pub(crate) fn migrate_to_old_currency(who: &AccountId) { - use frame_support::traits::LockableCurrency; - let staked = asset::staked::(who); - - // apply locks (this also adds a consumer). - Balances::set_lock(STAKING_ID, who, staked, frame_support::traits::WithdrawReasons::all()); - // remove holds. - asset::kill_stake::(who).expect("remove hold failed"); - - // replicate old behaviour of explicitly increment consumer. - System::inc_consumers(who).expect("increment consumer failed"); -} diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index afacce6bb53e..b091eee595ca 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -2182,8 +2182,7 @@ pub mod pallet { } #[pallet::call_index(30)] - // FIXME(ank4n): Bench - #[pallet::weight(Weight::zero())] + #[pallet::weight(T::WeightInfo::migrate_currency())] pub fn migrate_currency( origin: OriginFor, stash: T::AccountId, @@ -2191,7 +2190,7 @@ pub mod pallet { let _ = ensure_signed(origin)?; Self::do_migrate_currency(&stash)?; - // Refund the transaction fee. + // Refund the transaction fee if successful. Ok(Pays::No.into()) } } diff --git a/substrate/frame/staking/src/testing_utils.rs b/substrate/frame/staking/src/testing_utils.rs index efd4a40f1ab4..ee28849f8c33 100644 --- a/substrate/frame/staking/src/testing_utils.rs +++ b/substrate/frame/staking/src/testing_utils.rs @@ -238,3 +238,21 @@ pub fn create_validators_with_nominators_for_era( pub fn current_era() -> EraIndex { >::current_era().unwrap_or(0) } + +pub fn migrate_to_old_currency(who: T::AccountId) { + use frame_support::traits::LockableCurrency; + let staked = asset::staked::(&who); + + // apply locks (this also adds a consumer). + T::OldCurrency::set_lock( + STAKING_ID, + &who, + staked, + frame_support::traits::WithdrawReasons::all(), + ); + // remove holds. + asset::kill_stake::(&who).expect("remove hold failed"); + + // replicate old behaviour of explicitly increment consumer. + frame_system::Pallet::::inc_consumers(&who).expect("increment consumer failed"); +} diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 785be1097486..3a1693eacf90 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -8398,7 +8398,7 @@ mod hold_migration { assert_eq!(asset::staked::(&alice), 1000); assert_eq!(Balances::balance_locked(STAKING_ID, &alice), 0); // migrate alice currency to legacy locks - migrate_to_old_currency(&alice); + testing_utils::migrate_to_old_currency::(alice); // no more holds assert_eq!(asset::staked::(&alice), 0); assert_eq!(Balances::balance_locked(STAKING_ID, &alice), 1000); @@ -8462,7 +8462,7 @@ mod hold_migration { // GIVEN alice who is a nominator with old currency let alice = 300; bond_nominator(alice, 1000, vec![11]); - migrate_to_old_currency(&alice); + testing_utils::migrate_to_old_currency::(alice); assert_eq!(asset::staked::(&alice), 0); assert_eq!(Balances::balance_locked(STAKING_ID, &alice), 1000); let pre_migrate_consumer = System::consumers(&alice); @@ -8498,7 +8498,7 @@ mod hold_migration { let alice = 300; let stake = 1000; bond_nominator(alice, stake, vec![11]); - migrate_to_old_currency(&alice); + testing_utils::migrate_to_old_currency::(alice); assert_eq!(asset::staked::(&alice), 0); assert_eq!(Balances::balance_locked(STAKING_ID, &alice), stake); // ledger has 1000 staked. diff --git a/substrate/frame/staking/src/weights.rs b/substrate/frame/staking/src/weights.rs index cd4e7f973ce3..04a7f3ab167c 100644 --- a/substrate/frame/staking/src/weights.rs +++ b/substrate/frame/staking/src/weights.rs @@ -83,6 +83,7 @@ pub trait WeightInfo { fn force_apply_min_commission() -> Weight; fn set_min_commission() -> Weight; fn restore_ledger() -> Weight; + fn migrate_currency() -> Weight; } /// Weights for `pallet_staking` using the Substrate node and recommended hardware. @@ -834,6 +835,10 @@ impl WeightInfo for SubstrateWeight { .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } + fn migrate_currency() -> Weight { + // will be auto-generated + Default::default() + } } // For backwards compatibility and tests. @@ -1584,4 +1589,8 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } + fn migrate_currency() -> Weight { + // will be auto-generated + Default::default() + } } From 8c59b582ee103b6262b413e2bc2ab068e0696304 Mon Sep 17 00:00:00 2001 From: Ankan Date: Tue, 17 Sep 2024 12:56:33 +0200 Subject: [PATCH 071/142] fix try states --- substrate/frame/staking/src/pallet/impls.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index a399c8ac0015..cd223c319ff3 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::{ - Defensive, DefensiveSaturating, EstimateNextNewSession, Get, Imbalance, Len, OnUnbalanced, - TryCollect, UnixTime, + Defensive, DefensiveSaturating, EstimateNextNewSession, Get, Imbalance, + InspectLockableCurrency, Len, LockableCurrency, OnUnbalanced, TryCollect, UnixTime, }, weights::Weight, }; @@ -96,10 +96,12 @@ impl Pallet { pub(crate) fn inspect_bond_state( stash: &T::AccountId, ) -> Result> { - let lock = asset::staked::(&stash); + // look at any old unmigrated lock as well. + let hold_or_lock = asset::staked::(&stash) + .max(T::OldCurrency::balance_locked(STAKING_ID, &stash).into()); let controller = >::get(stash).ok_or_else(|| { - if lock == Zero::zero() { + if hold_or_lock == Zero::zero() { Error::::NotStash } else { Error::::BadState @@ -111,7 +113,7 @@ impl Pallet { if ledger.stash != *stash { Ok(LedgerIntegrityState::Corrupted) } else { - if lock != ledger.total { + if hold_or_lock != ledger.total { Ok(LedgerIntegrityState::LockCorrupted) } else { Ok(LedgerIntegrityState::Ok) @@ -1157,8 +1159,6 @@ impl Pallet { } pub(super) fn do_migrate_currency(stash: &T::AccountId) -> DispatchResult { - use frame_support::traits::{InspectLockableCurrency, LockableCurrency}; - // we can't do anything for virtual stakers since their funds are not managed/held by // this pallet. ensure!(!Self::is_virtual_staker(stash), Error::::VirtualStakerNotAllowed); @@ -2130,7 +2130,7 @@ impl Pallet { if VirtualStakers::::contains_key(stash.clone()) { ensure!( asset::staked::(&stash) == Zero::zero(), - "virtual stakers should not have any locked balance" + "virtual stakers should not have any staked balance" ); ensure!( >::get(stash.clone()).unwrap() == stash.clone(), @@ -2154,7 +2154,7 @@ impl Pallet { } else { ensure!( Self::inspect_bond_state(&stash) == Ok(LedgerIntegrityState::Ok), - "bond, ledger and/or staking lock inconsistent for a bonded stash." + "bond, ledger and/or staking hold inconsistent for a bonded stash." ); } From 36bb12e3fb92c3b4e7687f329d30196cd54193ac Mon Sep 17 00:00:00 2001 From: Ankan Date: Tue, 17 Sep 2024 13:22:24 +0200 Subject: [PATCH 072/142] prdoc --- prdoc/pr_5501.prdoc | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 prdoc/pr_5501.prdoc diff --git a/prdoc/pr_5501.prdoc b/prdoc/pr_5501.prdoc new file mode 100644 index 000000000000..82ac554bbbf8 --- /dev/null +++ b/prdoc/pr_5501.prdoc @@ -0,0 +1,27 @@ +# 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: Currency to Fungible migration for pallet-staking + +doc: + - audience: Runtime User + description: | + Lazy migration of staking balance from `Currency::locks` to `Fungible::holds`. New extrinsic + `staking::migrate_currency` removes the old lock along with other housekeeping. Additionally, any ledger mutation + creates hold if it does not exist. + +crates: + - name: westend-runtime + bump: minor + - name: kitchensink-runtime + bump: minor + - name: pallet-delegated-staking + bump: patch + - name: pallet-nomination-pools + bump: patch + - name: frame-support + bump: patch + - name: pallet-treasury + bump: minor + - name: sp-staking + bump: minor From c06e60bfa69bee13c8f9c32619574b0cc7b42c74 Mon Sep 17 00:00:00 2001 From: Ankan Date: Tue, 17 Sep 2024 13:23:53 +0200 Subject: [PATCH 073/142] clippy fix --- polkadot/runtime/westend/src/tests.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/polkadot/runtime/westend/src/tests.rs b/polkadot/runtime/westend/src/tests.rs index 53e85cebe620..6f2e36c68e3b 100644 --- a/polkadot/runtime/westend/src/tests.rs +++ b/polkadot/runtime/westend/src/tests.rs @@ -244,7 +244,6 @@ mod remote_tests { if var("RUN_MIGRATION_TESTS").is_err() { return; } - use frame_support::assert_ok; sp_tracing::try_init_simple(); let transport: Transport = var("WS").unwrap_or("ws://127.0.0.1:9900".to_string()).into(); From 5c29547f260ef8a8fb9907e4877cf52e70dd4a94 Mon Sep 17 00:00:00 2001 From: Ankan Date: Tue, 17 Sep 2024 13:28:50 +0200 Subject: [PATCH 074/142] improve tests --- substrate/frame/staking/src/tests.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 3a1693eacf90..6d5cca4f3984 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -8511,6 +8511,12 @@ mod hold_migration { let expected_force_withdraw = 200; assert_ok!(Balances::reserve(&alice, expected_force_withdraw)); + // ledger mutation would fail in this case before migration because of failing hold. + assert_noop!( + Staking::unbond(RuntimeOrigin::signed(alice), 100), + Error::::NotEnoughFunds + ); + // clear events System::reset_events(); @@ -8535,6 +8541,9 @@ mod hold_migration { force_withdraw: expected_force_withdraw }] ); + + // unbond works after migration. + assert_ok!(Staking::unbond(RuntimeOrigin::signed(alice), 100)); }); } } From f07061bdd5643dce485c7c0db52f42e863a47c2d Mon Sep 17 00:00:00 2001 From: command-bot <> Date: Tue, 17 Sep 2024 13:44:40 +0000 Subject: [PATCH 075/142] ".git/.scripts/commands/bench/bench.sh" --subcommand=pallet --runtime=dev --target_dir=substrate --pallet=pallet_staking --- substrate/frame/staking/src/weights.rs | 758 +++++++++++++------------ 1 file changed, 397 insertions(+), 361 deletions(-) diff --git a/substrate/frame/staking/src/weights.rs b/substrate/frame/staking/src/weights.rs index 04a7f3ab167c..b03fa4ce594f 100644 --- a/substrate/frame/staking/src/weights.rs +++ b/substrate/frame/staking/src/weights.rs @@ -18,27 +18,25 @@ //! Autogenerated weights for `pallet_staking` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-04-09, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-09-17, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-anb7yjbi-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-obbyq9g6-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: -// ./target/production/substrate-node +// target/production/substrate-node // benchmark // pallet -// --chain=dev // --steps=50 // --repeat=20 -// --pallet=pallet_staking -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --extrinsic=* // --wasm-execution=compiled // --heap-pages=4096 -// --output=./substrate/frame/staking/src/weights.rs +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=pallet_staking +// --chain=dev // --header=./substrate/HEADER-APACHE2 +// --output=./substrate/frame/staking/src/weights.rs // --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -93,18 +91,18 @@ impl WeightInfo for SubstrateWeight { /// 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: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) + /// Storage: `Staking::VirtualStakers` (r:1 w:0) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, 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: `1042` - // Estimated: `4764` - // Minimum execution time: 46_504_000 picoseconds. - Weight::from_parts(48_459_000, 4764) + // Measured: `1068` + // Estimated: `4556` + // Minimum execution time: 71_854_000 picoseconds. + Weight::from_parts(73_408_000, 4556) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -112,20 +110,20 @@ impl WeightInfo for SubstrateWeight { /// 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::VirtualStakers` (r:1 w:0) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListNodes` (r:3 w:3) /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListBags` (r:2 w:2) /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) fn bond_extra() -> Weight { // Proof Size summary in bytes: - // Measured: `1990` + // Measured: `2049` // Estimated: `8877` - // Minimum execution time: 90_475_000 picoseconds. - Weight::from_parts(93_619_000, 8877) + // Minimum execution time: 127_442_000 picoseconds. + Weight::from_parts(130_845_000, 8877) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } @@ -139,22 +137,22 @@ impl WeightInfo for SubstrateWeight { /// 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: `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::VirtualStakers` (r:1 w:0) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:0) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListNodes` (r:3 w:3) /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListBags` (r:2 w:2) /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) fn unbond() -> Weight { // Proof Size summary in bytes: - // Measured: `2195` + // Measured: `2151` // Estimated: `8877` - // Minimum execution time: 99_335_000 picoseconds. - Weight::from_parts(101_440_000, 8877) + // Minimum execution time: 105_259_000 picoseconds. + Weight::from_parts(107_112_000, 8877) .saturating_add(T::DbWeight::get().reads(12_u64)) - .saturating_add(T::DbWeight::get().writes(7_u64)) + .saturating_add(T::DbWeight::get().writes(6_u64)) } /// Storage: `Staking::Ledger` (r:1 w:1) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) @@ -162,21 +160,21 @@ impl WeightInfo for SubstrateWeight { /// 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: `Staking::VirtualStakers` (r:1 w:0) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, 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: `1297` - // Estimated: `4764` - // Minimum execution time: 50_067_000 picoseconds. - Weight::from_parts(52_396_327, 4764) - // Standard Error: 1_419 - .saturating_add(Weight::from_parts(51_406, 0).saturating_mul(s.into())) + // Measured: `1393` + // Estimated: `4556` + // Minimum execution time: 77_158_000 picoseconds. + Weight::from_parts(79_140_122, 4556) + // Standard Error: 1_688 + .saturating_add(Weight::from_parts(62_663, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -188,10 +186,10 @@ impl WeightInfo for SubstrateWeight { /// 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: `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::VirtualStakers` (r:1 w:1) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, 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) @@ -211,14 +209,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_kill(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2196 + s * (4 ±0)` + // Measured: `2255 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 92_931_000 picoseconds. - Weight::from_parts(101_398_156, 6248) - // Standard Error: 4_180 - .saturating_add(Weight::from_parts(1_377_850, 0).saturating_mul(s.into())) + // Minimum execution time: 125_396_000 picoseconds. + Weight::from_parts(134_915_543, 6248) + // Standard Error: 3_660 + .saturating_add(Weight::from_parts(1_324_736, 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(12_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) .saturating_add(Weight::from_parts(0, 4).saturating_mul(s.into())) } @@ -246,10 +244,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Staking::CounterForValidators` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn validate() -> Weight { // Proof Size summary in bytes: - // Measured: `1372` + // Measured: `1438` // Estimated: `4556` - // Minimum execution time: 56_291_000 picoseconds. - Weight::from_parts(58_372_000, 4556) + // Minimum execution time: 68_826_000 picoseconds. + Weight::from_parts(71_261_000, 4556) .saturating_add(T::DbWeight::get().reads(11_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -262,12 +260,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `k` is `[1, 128]`. fn kick(k: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1815 + k * (572 ±0)` + // Measured: `1848 + k * (572 ±0)` // Estimated: `4556 + k * (3033 ±0)` - // Minimum execution time: 36_218_000 picoseconds. - Weight::from_parts(38_811_308, 4556) - // Standard Error: 8_352 - .saturating_add(Weight::from_parts(6_527_398, 0).saturating_mul(k.into())) + // Minimum execution time: 46_082_000 picoseconds. + Weight::from_parts(49_541_374, 4556) + // Standard Error: 7_218 + .saturating_add(Weight::from_parts(7_281_079, 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()))) @@ -298,12 +296,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[1, 16]`. fn nominate(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1866 + n * (102 ±0)` + // Measured: `1932 + n * (102 ±0)` // Estimated: `6248 + n * (2520 ±0)` - // Minimum execution time: 68_607_000 picoseconds. - Weight::from_parts(66_831_185, 6248) - // Standard Error: 14_014 - .saturating_add(Weight::from_parts(4_031_635, 0).saturating_mul(n.into())) + // Minimum execution time: 83_854_000 picoseconds. + Weight::from_parts(81_387_241, 6248) + // Standard Error: 16_811 + .saturating_add(Weight::from_parts(4_900_554, 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)) @@ -327,10 +325,10 @@ 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: `1816` + // Measured: `1882` // Estimated: `6248` - // Minimum execution time: 60_088_000 picoseconds. - Weight::from_parts(62_471_000, 6248) + // Minimum execution time: 73_939_000 picoseconds. + Weight::from_parts(75_639_000, 6248) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -342,10 +340,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn set_payee() -> Weight { // Proof Size summary in bytes: - // Measured: `902` + // Measured: `935` // Estimated: `4556` - // Minimum execution time: 19_777_000 picoseconds. - Weight::from_parts(20_690_000, 4556) + // Minimum execution time: 24_592_000 picoseconds. + Weight::from_parts(25_092_000, 4556) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -357,10 +355,10 @@ impl WeightInfo for SubstrateWeight { /// 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` + // Measured: `1002` // Estimated: `4556` - // Minimum execution time: 23_705_000 picoseconds. - Weight::from_parts(24_409_000, 4556) + // Minimum execution time: 29_735_000 picoseconds. + Weight::from_parts(30_546_000, 4556) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -370,10 +368,10 @@ impl WeightInfo for SubstrateWeight { /// 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` + // Measured: `935` // Estimated: `8122` - // Minimum execution time: 23_479_000 picoseconds. - Weight::from_parts(24_502_000, 8122) + // Minimum execution time: 28_728_000 picoseconds. + Weight::from_parts(29_709_000, 8122) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -383,8 +381,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_675_000 picoseconds. - Weight::from_parts(2_802_000, 0) + // Minimum execution time: 2_519_000 picoseconds. + Weight::from_parts(2_673_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Staking::ForceEra` (r:0 w:1) @@ -393,8 +391,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_067_000 picoseconds. - Weight::from_parts(7_413_000, 0) + // Minimum execution time: 8_050_000 picoseconds. + Weight::from_parts(8_268_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Staking::ForceEra` (r:0 w:1) @@ -403,8 +401,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_977_000 picoseconds. - Weight::from_parts(7_353_000, 0) + // Minimum execution time: 8_131_000 picoseconds. + Weight::from_parts(8_349_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Staking::ForceEra` (r:0 w:1) @@ -413,8 +411,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_071_000 picoseconds. - Weight::from_parts(7_463_000, 0) + // Minimum execution time: 8_104_000 picoseconds. + Weight::from_parts(8_317_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Staking::Invulnerables` (r:0 w:1) @@ -424,10 +422,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_833_000 picoseconds. - Weight::from_parts(3_328_130, 0) - // Standard Error: 30 - .saturating_add(Weight::from_parts(10_058, 0).saturating_mul(v.into())) + // Minimum execution time: 2_669_000 picoseconds. + Weight::from_parts(3_013_436, 0) + // Standard Error: 31 + .saturating_add(Weight::from_parts(10_704, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Staking::Ledger` (r:11800 w:11800) @@ -439,12 +437,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `i` is `[0, 5900]`. fn deprecate_controller_batch(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1746 + i * (229 ±0)` + // Measured: `1779 + i * (229 ±0)` // Estimated: `990 + i * (7132 ±0)` - // Minimum execution time: 5_300_000 picoseconds. - Weight::from_parts(5_437_000, 990) - // Standard Error: 66_261 - .saturating_add(Weight::from_parts(30_172_457, 0).saturating_mul(i.into())) + // Minimum execution time: 5_101_000 picoseconds. + Weight::from_parts(5_368_000, 990) + // Standard Error: 75_180 + .saturating_add(Weight::from_parts(33_781_643, 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, 7132).saturating_mul(i.into())) @@ -455,10 +453,10 @@ impl WeightInfo for SubstrateWeight { /// 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::VirtualStakers` (r:1 w:1) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, 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::Validators` (r:1 w:0) @@ -480,14 +478,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `s` is `[0, 100]`. fn force_unstake(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2196 + s * (4 ±0)` + // Measured: `2255 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 87_677_000 picoseconds. - Weight::from_parts(96_386_462, 6248) - // Standard Error: 3_717 - .saturating_add(Weight::from_parts(1_370_585, 0).saturating_mul(s.into())) + // Minimum execution time: 119_955_000 picoseconds. + Weight::from_parts(128_392_032, 6248) + // Standard Error: 3_773 + .saturating_add(Weight::from_parts(1_302_488, 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(13_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) .saturating_add(Weight::from_parts(0, 4).saturating_mul(s.into())) } @@ -496,12 +494,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `s` is `[1, 1000]`. fn cancel_deferred_slash(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `66672` - // Estimated: `70137` - // Minimum execution time: 105_086_000 picoseconds. - Weight::from_parts(1_167_895_222, 70137) - // Standard Error: 77_022 - .saturating_add(Weight::from_parts(6_487_305, 0).saturating_mul(s.into())) + // Measured: `66705` + // Estimated: `70170` + // Minimum execution time: 139_290_000 picoseconds. + Weight::from_parts(959_667_494, 70170) + // Standard Error: 56_271 + .saturating_add(Weight::from_parts(4_798_293, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -519,12 +517,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `Staking::ErasValidatorReward` (r:1 w:0) /// Proof: `Staking::ErasValidatorReward` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) - /// Storage: `Balances::Locks` (r:257 w:257) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:257 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:257 w:257) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Staking::VirtualStakers` (r:257 w:0) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:257 w:257) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) /// Storage: `Staking::ErasStakersPaged` (r:1 w:0) /// Proof: `Staking::ErasStakersPaged` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Staking::ErasRewardPoints` (r:1 w:0) @@ -533,29 +529,31 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Staking::ErasValidatorPrefs` (`max_values`: None, `max_size`: Some(57), added: 2532, mode: `MaxEncodedLen`) /// Storage: `Staking::Payee` (r:257 w:0) /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:257 w:257) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// The range of component `n` is `[0, 256]`. fn payout_stakers_alive_staked(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `33297 + n * (377 ±0)` - // Estimated: `30944 + n * (3774 ±3)` - // Minimum execution time: 154_210_000 picoseconds. - Weight::from_parts(192_836_012, 30944) - // Standard Error: 40_441 - .saturating_add(Weight::from_parts(47_646_642, 0).saturating_mul(n.into())) + // Measured: `33283 + n * (370 ±0)` + // Estimated: `30958 + n * (3566 ±0)` + // Minimum execution time: 193_068_000 picoseconds. + Weight::from_parts(252_762_568, 30958) + // Standard Error: 22_743 + .saturating_add(Weight::from_parts(81_185_306, 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)) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_parts(0, 3774).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 3566).saturating_mul(n.into())) } /// 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: `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::VirtualStakers` (r:1 w:0) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:0) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListNodes` (r:3 w:3) /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListBags` (r:2 w:2) @@ -563,25 +561,25 @@ impl WeightInfo for SubstrateWeight { /// The range of component `l` is `[1, 32]`. fn rebond(l: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1991 + l * (7 ±0)` + // Measured: `1947 + l * (7 ±0)` // Estimated: `8877` - // Minimum execution time: 88_337_000 picoseconds. - Weight::from_parts(91_391_254, 8877) - // Standard Error: 4_485 - .saturating_add(Weight::from_parts(103_443, 0).saturating_mul(l.into())) + // Minimum execution time: 91_151_000 picoseconds. + Weight::from_parts(93_596_096, 8877) + // Standard Error: 5_313 + .saturating_add(Weight::from_parts(124_684, 0).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(9_u64)) - .saturating_add(T::DbWeight::get().writes(7_u64)) + .saturating_add(T::DbWeight::get().writes(6_u64)) } + /// Storage: `Staking::VirtualStakers` (r:1 w:1) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, 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: `Staking::SlashingSpans` (r:1 w:1) /// Proof: `Staking::SlashingSpans` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// 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: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, 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) @@ -601,14 +599,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `s` is `[1, 100]`. fn reap_stash(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2196 + s * (4 ±0)` + // Measured: `2255 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 98_014_000 picoseconds. - Weight::from_parts(102_537_670, 6248) - // Standard Error: 3_324 - .saturating_add(Weight::from_parts(1_353_142, 0).saturating_mul(s.into())) + // Minimum execution time: 133_214_000 picoseconds. + Weight::from_parts(137_290_527, 6248) + // Standard Error: 4_153 + .saturating_add(Weight::from_parts(1_291_007, 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(12_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) .saturating_add(Weight::from_parts(0, 4).saturating_mul(s.into())) } @@ -652,12 +650,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: 608_575_000 picoseconds. - Weight::from_parts(613_663_000, 512390) - // Standard Error: 2_286_521 - .saturating_add(Weight::from_parts(72_108_001, 0).saturating_mul(v.into())) - // Standard Error: 227_839 - .saturating_add(Weight::from_parts(20_314_085, 0).saturating_mul(n.into())) + // Minimum execution time: 692_301_000 picoseconds. + Weight::from_parts(708_732_000, 512390) + // Standard Error: 2_117_299 + .saturating_add(Weight::from_parts(70_087_600, 0).saturating_mul(v.into())) + // Standard Error: 210_977 + .saturating_add(Weight::from_parts(22_953_405, 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()))) @@ -686,14 +684,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[500, 1000]`. fn get_npos_voters(v: u32, n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `3175 + n * (911 ±0) + v * (395 ±0)` + // Measured: `3241 + n * (911 ±0) + v * (395 ±0)` // Estimated: `512390 + n * (3566 ±0) + v * (3566 ±0)` - // Minimum execution time: 37_173_756_000 picoseconds. - Weight::from_parts(37_488_937_000, 512390) - // Standard Error: 467_413 - .saturating_add(Weight::from_parts(8_086_367, 0).saturating_mul(v.into())) - // Standard Error: 467_413 - .saturating_add(Weight::from_parts(3_108_193, 0).saturating_mul(n.into())) + // Minimum execution time: 43_708_472_000 picoseconds. + Weight::from_parts(44_048_436_000, 512390) + // Standard Error: 493_244 + .saturating_add(Weight::from_parts(6_697_278, 0).saturating_mul(v.into())) + // Standard Error: 493_244 + .saturating_add(Weight::from_parts(4_559_779, 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()))) @@ -708,12 +706,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `v` is `[500, 1000]`. fn get_npos_targets(v: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `979 + v * (50 ±0)` + // Measured: `1012 + v * (50 ±0)` // Estimated: `3510 + v * (2520 ±0)` - // Minimum execution time: 2_641_258_000 picoseconds. - Weight::from_parts(382_882_595, 3510) - // Standard Error: 11_991 - .saturating_add(Weight::from_parts(4_695_820, 0).saturating_mul(v.into())) + // Minimum execution time: 2_917_165_000 picoseconds. + Weight::from_parts(2_948_999_000, 3510) + // Standard Error: 33_372 + .saturating_add(Weight::from_parts(2_126_909, 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())) @@ -736,8 +734,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_753_000 picoseconds. - Weight::from_parts(6_529_000, 0) + // Minimum execution time: 4_748_000 picoseconds. + Weight::from_parts(5_052_000, 0) .saturating_add(T::DbWeight::get().writes(7_u64)) } /// Storage: `Staking::MinCommission` (r:0 w:1) @@ -758,8 +756,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_212_000 picoseconds. - Weight::from_parts(5_451_000, 0) + // Minimum execution time: 4_316_000 picoseconds. + Weight::from_parts(4_526_000, 0) .saturating_add(T::DbWeight::get().writes(7_u64)) } /// Storage: `Staking::Bonded` (r:1 w:0) @@ -786,10 +784,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `VoterList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn chill_other() -> Weight { // Proof Size summary in bytes: - // Measured: `1939` + // Measured: `2005` // Estimated: `6248` - // Minimum execution time: 73_000_000 picoseconds. - Weight::from_parts(75_184_000, 6248) + // Minimum execution time: 87_374_000 picoseconds. + Weight::from_parts(89_848_000, 6248) .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -799,10 +797,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) fn force_apply_min_commission() -> Weight { // Proof Size summary in bytes: - // Measured: `691` + // Measured: `724` // Estimated: `3510` - // Minimum execution time: 13_056_000 picoseconds. - Weight::from_parts(13_517_000, 3510) + // Minimum execution time: 15_529_000 picoseconds. + Weight::from_parts(16_094_000, 3510) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -812,32 +810,51 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_201_000 picoseconds. - Weight::from_parts(3_442_000, 0) + // Minimum execution time: 2_533_000 picoseconds. + Weight::from_parts(2_817_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// 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) + /// Storage: `Staking::VirtualStakers` (r:1 w:0) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:0) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:1 w:0) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, 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 { // Proof Size summary in bytes: - // Measured: `1047` + // Measured: `1110` // Estimated: `4764` - // Minimum execution time: 44_671_000 picoseconds. - Weight::from_parts(45_611_000, 4764) - .saturating_add(T::DbWeight::get().reads(5_u64)) - .saturating_add(T::DbWeight::get().writes(4_u64)) + // Minimum execution time: 50_105_000 picoseconds. + Weight::from_parts(50_966_000, 4764) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) } + /// Storage: `Staking::VirtualStakers` (r:1 w:0) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, 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::Ledger` (r:1 w:0) + /// 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::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) fn migrate_currency() -> Weight { - // will be auto-generated - Default::default() + // Proof Size summary in bytes: + // Measured: `1246` + // Estimated: `4764` + // Minimum execution time: 94_054_000 picoseconds. + Weight::from_parts(96_272_000, 4764) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) } } @@ -847,18 +864,18 @@ impl WeightInfo for () { /// 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: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) + /// Storage: `Staking::VirtualStakers` (r:1 w:0) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, 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: `1042` - // Estimated: `4764` - // Minimum execution time: 46_504_000 picoseconds. - Weight::from_parts(48_459_000, 4764) + // Measured: `1068` + // Estimated: `4556` + // Minimum execution time: 71_854_000 picoseconds. + Weight::from_parts(73_408_000, 4556) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -866,20 +883,20 @@ impl WeightInfo for () { /// 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::VirtualStakers` (r:1 w:0) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListNodes` (r:3 w:3) /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListBags` (r:2 w:2) /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) fn bond_extra() -> Weight { // Proof Size summary in bytes: - // Measured: `1990` + // Measured: `2049` // Estimated: `8877` - // Minimum execution time: 90_475_000 picoseconds. - Weight::from_parts(93_619_000, 8877) + // Minimum execution time: 127_442_000 picoseconds. + Weight::from_parts(130_845_000, 8877) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } @@ -893,22 +910,22 @@ impl WeightInfo for () { /// 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: `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::VirtualStakers` (r:1 w:0) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:0) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListNodes` (r:3 w:3) /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListBags` (r:2 w:2) /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) fn unbond() -> Weight { // Proof Size summary in bytes: - // Measured: `2195` + // Measured: `2151` // Estimated: `8877` - // Minimum execution time: 99_335_000 picoseconds. - Weight::from_parts(101_440_000, 8877) + // Minimum execution time: 105_259_000 picoseconds. + Weight::from_parts(107_112_000, 8877) .saturating_add(RocksDbWeight::get().reads(12_u64)) - .saturating_add(RocksDbWeight::get().writes(7_u64)) + .saturating_add(RocksDbWeight::get().writes(6_u64)) } /// Storage: `Staking::Ledger` (r:1 w:1) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) @@ -916,21 +933,21 @@ impl WeightInfo for () { /// 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: `Staking::VirtualStakers` (r:1 w:0) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, 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: `1297` - // Estimated: `4764` - // Minimum execution time: 50_067_000 picoseconds. - Weight::from_parts(52_396_327, 4764) - // Standard Error: 1_419 - .saturating_add(Weight::from_parts(51_406, 0).saturating_mul(s.into())) + // Measured: `1393` + // Estimated: `4556` + // Minimum execution time: 77_158_000 picoseconds. + Weight::from_parts(79_140_122, 4556) + // Standard Error: 1_688 + .saturating_add(Weight::from_parts(62_663, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -942,10 +959,10 @@ impl WeightInfo for () { /// 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: `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::VirtualStakers` (r:1 w:1) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, 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) @@ -965,14 +982,14 @@ impl WeightInfo for () { /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_kill(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2196 + s * (4 ±0)` + // Measured: `2255 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 92_931_000 picoseconds. - Weight::from_parts(101_398_156, 6248) - // Standard Error: 4_180 - .saturating_add(Weight::from_parts(1_377_850, 0).saturating_mul(s.into())) + // Minimum execution time: 125_396_000 picoseconds. + Weight::from_parts(134_915_543, 6248) + // Standard Error: 3_660 + .saturating_add(Weight::from_parts(1_324_736, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(13_u64)) - .saturating_add(RocksDbWeight::get().writes(11_u64)) + .saturating_add(RocksDbWeight::get().writes(12_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) .saturating_add(Weight::from_parts(0, 4).saturating_mul(s.into())) } @@ -1000,10 +1017,10 @@ impl WeightInfo for () { /// Proof: `Staking::CounterForValidators` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn validate() -> Weight { // Proof Size summary in bytes: - // Measured: `1372` + // Measured: `1438` // Estimated: `4556` - // Minimum execution time: 56_291_000 picoseconds. - Weight::from_parts(58_372_000, 4556) + // Minimum execution time: 68_826_000 picoseconds. + Weight::from_parts(71_261_000, 4556) .saturating_add(RocksDbWeight::get().reads(11_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -1016,12 +1033,12 @@ impl WeightInfo for () { /// The range of component `k` is `[1, 128]`. fn kick(k: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1815 + k * (572 ±0)` + // Measured: `1848 + k * (572 ±0)` // Estimated: `4556 + k * (3033 ±0)` - // Minimum execution time: 36_218_000 picoseconds. - Weight::from_parts(38_811_308, 4556) - // Standard Error: 8_352 - .saturating_add(Weight::from_parts(6_527_398, 0).saturating_mul(k.into())) + // Minimum execution time: 46_082_000 picoseconds. + Weight::from_parts(49_541_374, 4556) + // Standard Error: 7_218 + .saturating_add(Weight::from_parts(7_281_079, 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()))) @@ -1052,12 +1069,12 @@ impl WeightInfo for () { /// The range of component `n` is `[1, 16]`. fn nominate(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1866 + n * (102 ±0)` + // Measured: `1932 + n * (102 ±0)` // Estimated: `6248 + n * (2520 ±0)` - // Minimum execution time: 68_607_000 picoseconds. - Weight::from_parts(66_831_185, 6248) - // Standard Error: 14_014 - .saturating_add(Weight::from_parts(4_031_635, 0).saturating_mul(n.into())) + // Minimum execution time: 83_854_000 picoseconds. + Weight::from_parts(81_387_241, 6248) + // Standard Error: 16_811 + .saturating_add(Weight::from_parts(4_900_554, 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)) @@ -1081,10 +1098,10 @@ 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: `1816` + // Measured: `1882` // Estimated: `6248` - // Minimum execution time: 60_088_000 picoseconds. - Weight::from_parts(62_471_000, 6248) + // Minimum execution time: 73_939_000 picoseconds. + Weight::from_parts(75_639_000, 6248) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } @@ -1096,10 +1113,10 @@ impl WeightInfo for () { /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn set_payee() -> Weight { // Proof Size summary in bytes: - // Measured: `902` + // Measured: `935` // Estimated: `4556` - // Minimum execution time: 19_777_000 picoseconds. - Weight::from_parts(20_690_000, 4556) + // Minimum execution time: 24_592_000 picoseconds. + Weight::from_parts(25_092_000, 4556) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1111,10 +1128,10 @@ impl WeightInfo for () { /// 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` + // Measured: `1002` // Estimated: `4556` - // Minimum execution time: 23_705_000 picoseconds. - Weight::from_parts(24_409_000, 4556) + // Minimum execution time: 29_735_000 picoseconds. + Weight::from_parts(30_546_000, 4556) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1124,10 +1141,10 @@ impl WeightInfo for () { /// 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` + // Measured: `935` // Estimated: `8122` - // Minimum execution time: 23_479_000 picoseconds. - Weight::from_parts(24_502_000, 8122) + // Minimum execution time: 28_728_000 picoseconds. + Weight::from_parts(29_709_000, 8122) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -1137,8 +1154,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_675_000 picoseconds. - Weight::from_parts(2_802_000, 0) + // Minimum execution time: 2_519_000 picoseconds. + Weight::from_parts(2_673_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Staking::ForceEra` (r:0 w:1) @@ -1147,8 +1164,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_067_000 picoseconds. - Weight::from_parts(7_413_000, 0) + // Minimum execution time: 8_050_000 picoseconds. + Weight::from_parts(8_268_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Staking::ForceEra` (r:0 w:1) @@ -1157,8 +1174,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_977_000 picoseconds. - Weight::from_parts(7_353_000, 0) + // Minimum execution time: 8_131_000 picoseconds. + Weight::from_parts(8_349_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Staking::ForceEra` (r:0 w:1) @@ -1167,8 +1184,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_071_000 picoseconds. - Weight::from_parts(7_463_000, 0) + // Minimum execution time: 8_104_000 picoseconds. + Weight::from_parts(8_317_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Staking::Invulnerables` (r:0 w:1) @@ -1178,10 +1195,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_833_000 picoseconds. - Weight::from_parts(3_328_130, 0) - // Standard Error: 30 - .saturating_add(Weight::from_parts(10_058, 0).saturating_mul(v.into())) + // Minimum execution time: 2_669_000 picoseconds. + Weight::from_parts(3_013_436, 0) + // Standard Error: 31 + .saturating_add(Weight::from_parts(10_704, 0).saturating_mul(v.into())) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Staking::Ledger` (r:11800 w:11800) @@ -1193,12 +1210,12 @@ impl WeightInfo for () { /// The range of component `i` is `[0, 5900]`. fn deprecate_controller_batch(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1746 + i * (229 ±0)` + // Measured: `1779 + i * (229 ±0)` // Estimated: `990 + i * (7132 ±0)` - // Minimum execution time: 5_300_000 picoseconds. - Weight::from_parts(5_437_000, 990) - // Standard Error: 66_261 - .saturating_add(Weight::from_parts(30_172_457, 0).saturating_mul(i.into())) + // Minimum execution time: 5_101_000 picoseconds. + Weight::from_parts(5_368_000, 990) + // Standard Error: 75_180 + .saturating_add(Weight::from_parts(33_781_643, 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, 7132).saturating_mul(i.into())) @@ -1209,10 +1226,10 @@ impl WeightInfo for () { /// 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::VirtualStakers` (r:1 w:1) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, 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::Validators` (r:1 w:0) @@ -1234,14 +1251,14 @@ impl WeightInfo for () { /// The range of component `s` is `[0, 100]`. fn force_unstake(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2196 + s * (4 ±0)` + // Measured: `2255 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 87_677_000 picoseconds. - Weight::from_parts(96_386_462, 6248) - // Standard Error: 3_717 - .saturating_add(Weight::from_parts(1_370_585, 0).saturating_mul(s.into())) + // Minimum execution time: 119_955_000 picoseconds. + Weight::from_parts(128_392_032, 6248) + // Standard Error: 3_773 + .saturating_add(Weight::from_parts(1_302_488, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(13_u64)) - .saturating_add(RocksDbWeight::get().writes(12_u64)) + .saturating_add(RocksDbWeight::get().writes(13_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) .saturating_add(Weight::from_parts(0, 4).saturating_mul(s.into())) } @@ -1250,12 +1267,12 @@ impl WeightInfo for () { /// The range of component `s` is `[1, 1000]`. fn cancel_deferred_slash(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `66672` - // Estimated: `70137` - // Minimum execution time: 105_086_000 picoseconds. - Weight::from_parts(1_167_895_222, 70137) - // Standard Error: 77_022 - .saturating_add(Weight::from_parts(6_487_305, 0).saturating_mul(s.into())) + // Measured: `66705` + // Estimated: `70170` + // Minimum execution time: 139_290_000 picoseconds. + Weight::from_parts(959_667_494, 70170) + // Standard Error: 56_271 + .saturating_add(Weight::from_parts(4_798_293, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1273,12 +1290,10 @@ impl WeightInfo for () { /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `Staking::ErasValidatorReward` (r:1 w:0) /// Proof: `Staking::ErasValidatorReward` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) - /// Storage: `Balances::Locks` (r:257 w:257) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:257 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:257 w:257) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Staking::VirtualStakers` (r:257 w:0) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:257 w:257) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) /// Storage: `Staking::ErasStakersPaged` (r:1 w:0) /// Proof: `Staking::ErasStakersPaged` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Staking::ErasRewardPoints` (r:1 w:0) @@ -1287,29 +1302,31 @@ impl WeightInfo for () { /// Proof: `Staking::ErasValidatorPrefs` (`max_values`: None, `max_size`: Some(57), added: 2532, mode: `MaxEncodedLen`) /// Storage: `Staking::Payee` (r:257 w:0) /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:257 w:257) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// The range of component `n` is `[0, 256]`. fn payout_stakers_alive_staked(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `33297 + n * (377 ±0)` - // Estimated: `30944 + n * (3774 ±3)` - // Minimum execution time: 154_210_000 picoseconds. - Weight::from_parts(192_836_012, 30944) - // Standard Error: 40_441 - .saturating_add(Weight::from_parts(47_646_642, 0).saturating_mul(n.into())) + // Measured: `33283 + n * (370 ±0)` + // Estimated: `30958 + n * (3566 ±0)` + // Minimum execution time: 193_068_000 picoseconds. + Weight::from_parts(252_762_568, 30958) + // Standard Error: 22_743 + .saturating_add(Weight::from_parts(81_185_306, 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)) .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_parts(0, 3774).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 3566).saturating_mul(n.into())) } /// 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: `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::VirtualStakers` (r:1 w:0) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:0) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListNodes` (r:3 w:3) /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListBags` (r:2 w:2) @@ -1317,25 +1334,25 @@ impl WeightInfo for () { /// The range of component `l` is `[1, 32]`. fn rebond(l: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1991 + l * (7 ±0)` + // Measured: `1947 + l * (7 ±0)` // Estimated: `8877` - // Minimum execution time: 88_337_000 picoseconds. - Weight::from_parts(91_391_254, 8877) - // Standard Error: 4_485 - .saturating_add(Weight::from_parts(103_443, 0).saturating_mul(l.into())) + // Minimum execution time: 91_151_000 picoseconds. + Weight::from_parts(93_596_096, 8877) + // Standard Error: 5_313 + .saturating_add(Weight::from_parts(124_684, 0).saturating_mul(l.into())) .saturating_add(RocksDbWeight::get().reads(9_u64)) - .saturating_add(RocksDbWeight::get().writes(7_u64)) + .saturating_add(RocksDbWeight::get().writes(6_u64)) } + /// Storage: `Staking::VirtualStakers` (r:1 w:1) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, 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: `Staking::SlashingSpans` (r:1 w:1) /// Proof: `Staking::SlashingSpans` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// 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: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, 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) @@ -1355,14 +1372,14 @@ impl WeightInfo for () { /// The range of component `s` is `[1, 100]`. fn reap_stash(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2196 + s * (4 ±0)` + // Measured: `2255 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 98_014_000 picoseconds. - Weight::from_parts(102_537_670, 6248) - // Standard Error: 3_324 - .saturating_add(Weight::from_parts(1_353_142, 0).saturating_mul(s.into())) + // Minimum execution time: 133_214_000 picoseconds. + Weight::from_parts(137_290_527, 6248) + // Standard Error: 4_153 + .saturating_add(Weight::from_parts(1_291_007, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(12_u64)) - .saturating_add(RocksDbWeight::get().writes(11_u64)) + .saturating_add(RocksDbWeight::get().writes(12_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) .saturating_add(Weight::from_parts(0, 4).saturating_mul(s.into())) } @@ -1406,12 +1423,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: 608_575_000 picoseconds. - Weight::from_parts(613_663_000, 512390) - // Standard Error: 2_286_521 - .saturating_add(Weight::from_parts(72_108_001, 0).saturating_mul(v.into())) - // Standard Error: 227_839 - .saturating_add(Weight::from_parts(20_314_085, 0).saturating_mul(n.into())) + // Minimum execution time: 692_301_000 picoseconds. + Weight::from_parts(708_732_000, 512390) + // Standard Error: 2_117_299 + .saturating_add(Weight::from_parts(70_087_600, 0).saturating_mul(v.into())) + // Standard Error: 210_977 + .saturating_add(Weight::from_parts(22_953_405, 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()))) @@ -1440,14 +1457,14 @@ impl WeightInfo for () { /// The range of component `n` is `[500, 1000]`. fn get_npos_voters(v: u32, n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `3175 + n * (911 ±0) + v * (395 ±0)` + // Measured: `3241 + n * (911 ±0) + v * (395 ±0)` // Estimated: `512390 + n * (3566 ±0) + v * (3566 ±0)` - // Minimum execution time: 37_173_756_000 picoseconds. - Weight::from_parts(37_488_937_000, 512390) - // Standard Error: 467_413 - .saturating_add(Weight::from_parts(8_086_367, 0).saturating_mul(v.into())) - // Standard Error: 467_413 - .saturating_add(Weight::from_parts(3_108_193, 0).saturating_mul(n.into())) + // Minimum execution time: 43_708_472_000 picoseconds. + Weight::from_parts(44_048_436_000, 512390) + // Standard Error: 493_244 + .saturating_add(Weight::from_parts(6_697_278, 0).saturating_mul(v.into())) + // Standard Error: 493_244 + .saturating_add(Weight::from_parts(4_559_779, 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()))) @@ -1462,12 +1479,12 @@ impl WeightInfo for () { /// The range of component `v` is `[500, 1000]`. fn get_npos_targets(v: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `979 + v * (50 ±0)` + // Measured: `1012 + v * (50 ±0)` // Estimated: `3510 + v * (2520 ±0)` - // Minimum execution time: 2_641_258_000 picoseconds. - Weight::from_parts(382_882_595, 3510) - // Standard Error: 11_991 - .saturating_add(Weight::from_parts(4_695_820, 0).saturating_mul(v.into())) + // Minimum execution time: 2_917_165_000 picoseconds. + Weight::from_parts(2_948_999_000, 3510) + // Standard Error: 33_372 + .saturating_add(Weight::from_parts(2_126_909, 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())) @@ -1490,8 +1507,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_753_000 picoseconds. - Weight::from_parts(6_529_000, 0) + // Minimum execution time: 4_748_000 picoseconds. + Weight::from_parts(5_052_000, 0) .saturating_add(RocksDbWeight::get().writes(7_u64)) } /// Storage: `Staking::MinCommission` (r:0 w:1) @@ -1512,8 +1529,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_212_000 picoseconds. - Weight::from_parts(5_451_000, 0) + // Minimum execution time: 4_316_000 picoseconds. + Weight::from_parts(4_526_000, 0) .saturating_add(RocksDbWeight::get().writes(7_u64)) } /// Storage: `Staking::Bonded` (r:1 w:0) @@ -1540,10 +1557,10 @@ impl WeightInfo for () { /// Proof: `VoterList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn chill_other() -> Weight { // Proof Size summary in bytes: - // Measured: `1939` + // Measured: `2005` // Estimated: `6248` - // Minimum execution time: 73_000_000 picoseconds. - Weight::from_parts(75_184_000, 6248) + // Minimum execution time: 87_374_000 picoseconds. + Weight::from_parts(89_848_000, 6248) .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } @@ -1553,10 +1570,10 @@ impl WeightInfo for () { /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) fn force_apply_min_commission() -> Weight { // Proof Size summary in bytes: - // Measured: `691` + // Measured: `724` // Estimated: `3510` - // Minimum execution time: 13_056_000 picoseconds. - Weight::from_parts(13_517_000, 3510) + // Minimum execution time: 15_529_000 picoseconds. + Weight::from_parts(16_094_000, 3510) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1566,31 +1583,50 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_201_000 picoseconds. - Weight::from_parts(3_442_000, 0) + // Minimum execution time: 2_533_000 picoseconds. + Weight::from_parts(2_817_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// 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) + /// Storage: `Staking::VirtualStakers` (r:1 w:0) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:0) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:1 w:0) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, 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 { // Proof Size summary in bytes: - // Measured: `1047` + // Measured: `1110` // Estimated: `4764` - // Minimum execution time: 44_671_000 picoseconds. - Weight::from_parts(45_611_000, 4764) - .saturating_add(RocksDbWeight::get().reads(5_u64)) - .saturating_add(RocksDbWeight::get().writes(4_u64)) + // Minimum execution time: 50_105_000 picoseconds. + Weight::from_parts(50_966_000, 4764) + .saturating_add(RocksDbWeight::get().reads(6_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) } + /// Storage: `Staking::VirtualStakers` (r:1 w:0) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, 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::Ledger` (r:1 w:0) + /// 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::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(355), added: 2830, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) fn migrate_currency() -> Weight { - // will be auto-generated - Default::default() + // Proof Size summary in bytes: + // Measured: `1246` + // Estimated: `4764` + // Minimum execution time: 94_054_000 picoseconds. + Weight::from_parts(96_272_000, 4764) + .saturating_add(RocksDbWeight::get().reads(6_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) } } From da0a7c31f8c15f54601f81b061911aa2ce789a99 Mon Sep 17 00:00:00 2001 From: command-bot <> Date: Tue, 17 Sep 2024 15:10:17 +0000 Subject: [PATCH 076/142] ".git/.scripts/commands/bench/bench.sh" --subcommand=pallet --runtime=westend --target_dir=polkadot --pallet=pallet_staking --- .../westend/src/weights/pallet_staking.rs | 388 +++++++++--------- 1 file changed, 205 insertions(+), 183 deletions(-) diff --git a/polkadot/runtime/westend/src/weights/pallet_staking.rs b/polkadot/runtime/westend/src/weights/pallet_staking.rs index b3443f7c6cd2..f1e7f5ba1576 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-03-27, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-09-17, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-h2rr8wx7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-obbyq9g6-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("westend-dev")`, DB CACHE: 1024 // Executed Command: @@ -52,19 +52,19 @@ impl pallet_staking::WeightInfo for WeightInfo { /// 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: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(103), added: 2578, mode: `MaxEncodedLen`) + /// Storage: `Staking::VirtualStakers` (r:1 w:0) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, 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: `1009` - // Estimated: `4764` - // Minimum execution time: 40_585_000 picoseconds. - Weight::from_parts(41_800_000, 0) - .saturating_add(Weight::from_parts(0, 4764)) + // Measured: `1035` + // Estimated: `4556` + // Minimum execution time: 70_147_000 picoseconds. + Weight::from_parts(71_795_000, 0) + .saturating_add(Weight::from_parts(0, 4556)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -72,20 +72,20 @@ impl pallet_staking::WeightInfo for WeightInfo { /// 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::VirtualStakers` (r:1 w:0) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(103), added: 2578, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListNodes` (r:3 w:3) /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListBags` (r:2 w:2) /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) fn bond_extra() -> Weight { // Proof Size summary in bytes: - // Measured: `1921` + // Measured: `1947` // Estimated: `8877` - // Minimum execution time: 81_809_000 picoseconds. - Weight::from_parts(84_387_000, 0) + // Minimum execution time: 125_203_000 picoseconds. + Weight::from_parts(128_088_000, 0) .saturating_add(Weight::from_parts(0, 8877)) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(7)) @@ -100,23 +100,23 @@ impl pallet_staking::WeightInfo for WeightInfo { /// 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: `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::VirtualStakers` (r:1 w:0) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:0) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(103), added: 2578, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListNodes` (r:3 w:3) /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListBags` (r:2 w:2) /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) fn unbond() -> Weight { // Proof Size summary in bytes: - // Measured: `2128` + // Measured: `2051` // Estimated: `8877` - // Minimum execution time: 89_419_000 picoseconds. - Weight::from_parts(91_237_000, 0) + // Minimum execution time: 101_991_000 picoseconds. + Weight::from_parts(104_567_000, 0) .saturating_add(Weight::from_parts(0, 8877)) .saturating_add(T::DbWeight::get().reads(12)) - .saturating_add(T::DbWeight::get().writes(7)) + .saturating_add(T::DbWeight::get().writes(6)) } /// Storage: `Staking::Ledger` (r:1 w:1) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) @@ -124,23 +124,25 @@ impl pallet_staking::WeightInfo for WeightInfo { /// 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: `Staking::VirtualStakers` (r:1 w:0) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(103), added: 2578, mode: `MaxEncodedLen`) /// Storage: `NominationPools::ReversePoolIdLookup` (r:1 w:0) /// Proof: `NominationPools::ReversePoolIdLookup` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) + /// Storage: `DelegatedStaking::Agents` (r:1 w:0) + /// Proof: `DelegatedStaking::Agents` (`max_values`: None, `max_size`: Some(120), added: 2595, mode: `MaxEncodedLen`) /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_update(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1223` - // Estimated: `4764` - // Minimum execution time: 45_152_000 picoseconds. - Weight::from_parts(46_460_819, 0) - .saturating_add(Weight::from_parts(0, 4764)) - // Standard Error: 972 - .saturating_add(Weight::from_parts(55_473, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(6)) + // Measured: `1253` + // Estimated: `4556` + // Minimum execution time: 76_450_000 picoseconds. + Weight::from_parts(78_836_594, 0) + .saturating_add(Weight::from_parts(0, 4556)) + // Standard Error: 1_529 + .saturating_add(Weight::from_parts(66_662, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(2)) } /// Storage: `Staking::Ledger` (r:1 w:1) @@ -151,10 +153,10 @@ impl pallet_staking::WeightInfo for WeightInfo { /// 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: `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::VirtualStakers` (r:1 w:1) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(103), added: 2578, 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) @@ -174,15 +176,15 @@ impl pallet_staking::WeightInfo for WeightInfo { /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_kill(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2127 + s * (4 ±0)` + // Measured: `2153 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 82_762_000 picoseconds. - Weight::from_parts(91_035_077, 0) + // Minimum execution time: 121_962_000 picoseconds. + Weight::from_parts(131_000_151, 0) .saturating_add(Weight::from_parts(0, 6248)) - // Standard Error: 3_771 - .saturating_add(Weight::from_parts(1_217_871, 0).saturating_mul(s.into())) + // Standard Error: 3_846 + .saturating_add(Weight::from_parts(1_277_843, 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(12)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) .saturating_add(Weight::from_parts(0, 4).saturating_mul(s.into())) } @@ -210,10 +212,10 @@ impl pallet_staking::WeightInfo for WeightInfo { /// Proof: `Staking::CounterForValidators` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn validate() -> Weight { // Proof Size summary in bytes: - // Measured: `1301` + // Measured: `1334` // Estimated: `4556` - // Minimum execution time: 50_555_000 picoseconds. - Weight::from_parts(52_052_000, 0) + // Minimum execution time: 66_450_000 picoseconds. + Weight::from_parts(68_302_000, 0) .saturating_add(Weight::from_parts(0, 4556)) .saturating_add(T::DbWeight::get().reads(11)) .saturating_add(T::DbWeight::get().writes(5)) @@ -227,13 +229,13 @@ impl pallet_staking::WeightInfo for WeightInfo { /// The range of component `k` is `[1, 128]`. fn kick(k: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1778 + k * (572 ±0)` + // Measured: `1811 + k * (572 ±0)` // Estimated: `4556 + k * (3033 ±0)` - // Minimum execution time: 35_037_000 picoseconds. - Weight::from_parts(35_081_878, 0) + // Minimum execution time: 43_875_000 picoseconds. + Weight::from_parts(47_332_240, 0) .saturating_add(Weight::from_parts(0, 4556)) - // Standard Error: 5_473 - .saturating_add(Weight::from_parts(6_667_924, 0).saturating_mul(k.into())) + // Standard Error: 6_530 + .saturating_add(Weight::from_parts(7_398_001, 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()))) @@ -264,13 +266,13 @@ impl pallet_staking::WeightInfo for WeightInfo { /// The range of component `n` is `[1, 16]`. fn nominate(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1797 + n * (102 ±0)` + // Measured: `1830 + n * (102 ±0)` // Estimated: `6248 + n * (2520 ±0)` - // Minimum execution time: 62_098_000 picoseconds. - Weight::from_parts(60_154_061, 0) + // Minimum execution time: 80_640_000 picoseconds. + Weight::from_parts(78_801_092, 0) .saturating_add(Weight::from_parts(0, 6248)) - // Standard Error: 19_257 - .saturating_add(Weight::from_parts(3_839_855, 0).saturating_mul(n.into())) + // Standard Error: 22_249 + .saturating_add(Weight::from_parts(4_996_344, 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)) @@ -294,10 +296,10 @@ 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: `1747` + // Measured: `1780` // Estimated: `6248` - // Minimum execution time: 54_993_000 picoseconds. - Weight::from_parts(56_698_000, 0) + // Minimum execution time: 71_494_000 picoseconds. + Weight::from_parts(73_487_000, 0) .saturating_add(Weight::from_parts(0, 6248)) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(6)) @@ -310,10 +312,10 @@ impl pallet_staking::WeightInfo for WeightInfo { /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn set_payee() -> Weight { // Proof Size summary in bytes: - // Measured: `865` + // Measured: `898` // Estimated: `4556` - // Minimum execution time: 18_100_000 picoseconds. - Weight::from_parts(18_547_000, 0) + // Minimum execution time: 24_310_000 picoseconds. + Weight::from_parts(24_676_000, 0) .saturating_add(Weight::from_parts(0, 4556)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) @@ -326,10 +328,10 @@ impl pallet_staking::WeightInfo for WeightInfo { /// 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` + // Measured: `965` // Estimated: `4556` - // Minimum execution time: 23_428_000 picoseconds. - Weight::from_parts(24_080_000, 0) + // Minimum execution time: 31_348_000 picoseconds. + Weight::from_parts(32_384_000, 0) .saturating_add(Weight::from_parts(0, 4556)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) @@ -340,10 +342,10 @@ impl pallet_staking::WeightInfo for WeightInfo { /// 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` + // Measured: `898` // Estimated: `8122` - // Minimum execution time: 21_159_000 picoseconds. - Weight::from_parts(21_706_000, 0) + // Minimum execution time: 27_537_000 picoseconds. + Weight::from_parts(28_714_000, 0) .saturating_add(Weight::from_parts(0, 8122)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) @@ -354,8 +356,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_910_000 picoseconds. - Weight::from_parts(2_003_000, 0) + // Minimum execution time: 2_362_000 picoseconds. + Weight::from_parts(2_518_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -365,8 +367,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_076_000 picoseconds. - Weight::from_parts(7_349_000, 0) + // Minimum execution time: 7_752_000 picoseconds. + Weight::from_parts(8_105_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -376,8 +378,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_067_000 picoseconds. - Weight::from_parts(7_389_000, 0) + // Minimum execution time: 7_868_000 picoseconds. + Weight::from_parts(8_175_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -387,8 +389,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_148_000 picoseconds. - Weight::from_parts(7_446_000, 0) + // Minimum execution time: 7_945_000 picoseconds. + Weight::from_parts(8_203_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -399,11 +401,11 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_025_000 picoseconds. - Weight::from_parts(2_229_953, 0) + // Minimum execution time: 2_458_000 picoseconds. + Weight::from_parts(2_815_664, 0) .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 67 - .saturating_add(Weight::from_parts(11_785, 0).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(12_287, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `Staking::Ledger` (r:1502 w:1502) @@ -415,13 +417,13 @@ impl pallet_staking::WeightInfo for WeightInfo { /// The range of component `i` is `[0, 751]`. fn deprecate_controller_batch(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `680 + i * (227 ±0)` + // Measured: `713 + i * (227 ±0)` // Estimated: `990 + i * (7132 ±0)` - // Minimum execution time: 4_321_000 picoseconds. - Weight::from_parts(4_407_000, 0) + // Minimum execution time: 4_976_000 picoseconds. + Weight::from_parts(5_102_000, 0) .saturating_add(Weight::from_parts(0, 990)) - // Standard Error: 37_239 - .saturating_add(Weight::from_parts(21_300_598, 0).saturating_mul(i.into())) + // Standard Error: 36_458 + .saturating_add(Weight::from_parts(25_359_275, 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, 7132).saturating_mul(i.into())) @@ -432,10 +434,10 @@ impl pallet_staking::WeightInfo for WeightInfo { /// 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::VirtualStakers` (r:1 w:1) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(103), added: 2578, 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::Validators` (r:1 w:0) @@ -457,15 +459,15 @@ impl pallet_staking::WeightInfo for WeightInfo { /// The range of component `s` is `[0, 100]`. fn force_unstake(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2127 + s * (4 ±0)` + // Measured: `2153 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 78_908_000 picoseconds. - Weight::from_parts(84_886_373, 0) + // Minimum execution time: 116_776_000 picoseconds. + Weight::from_parts(125_460_389, 0) .saturating_add(Weight::from_parts(0, 6248)) - // Standard Error: 3_376 - .saturating_add(Weight::from_parts(1_217_850, 0).saturating_mul(s.into())) + // Standard Error: 3_095 + .saturating_add(Weight::from_parts(1_300_502, 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(13)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) .saturating_add(Weight::from_parts(0, 4).saturating_mul(s.into())) } @@ -474,13 +476,13 @@ impl pallet_staking::WeightInfo for WeightInfo { /// The range of component `s` is `[1, 1000]`. fn cancel_deferred_slash(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `66639` - // Estimated: `70104` - // Minimum execution time: 136_389_000 picoseconds. - Weight::from_parts(1_207_241_524, 0) - .saturating_add(Weight::from_parts(0, 70104)) - // Standard Error: 77_138 - .saturating_add(Weight::from_parts(6_443_948, 0).saturating_mul(s.into())) + // Measured: `66672` + // Estimated: `70137` + // Minimum execution time: 135_135_000 picoseconds. + Weight::from_parts(937_565_332, 0) + .saturating_add(Weight::from_parts(0, 70137)) + // Standard Error: 57_675 + .saturating_add(Weight::from_parts(4_828_080, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -498,12 +500,10 @@ impl pallet_staking::WeightInfo for WeightInfo { /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `Staking::ErasValidatorReward` (r:1 w:0) /// Proof: `Staking::ErasValidatorReward` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) - /// Storage: `Balances::Locks` (r:65 w:65) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:65 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:65 w:65) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Staking::VirtualStakers` (r:65 w:0) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:65 w:65) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(103), added: 2578, mode: `MaxEncodedLen`) /// Storage: `Staking::ErasStakersPaged` (r:1 w:0) /// Proof: `Staking::ErasStakersPaged` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Staking::ErasRewardPoints` (r:1 w:0) @@ -512,30 +512,32 @@ impl pallet_staking::WeightInfo for WeightInfo { /// Proof: `Staking::ErasValidatorPrefs` (`max_values`: None, `max_size`: Some(57), added: 2532, mode: `MaxEncodedLen`) /// Storage: `Staking::Payee` (r:65 w:0) /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:65 w:65) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// The range of component `n` is `[0, 64]`. fn payout_stakers_alive_staked(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `8249 + n * (396 ±0)` - // Estimated: `10779 + n * (3774 ±0)` - // Minimum execution time: 130_222_000 picoseconds. - Weight::from_parts(167_236_150, 0) - .saturating_add(Weight::from_parts(0, 10779)) - // Standard Error: 34_051 - .saturating_add(Weight::from_parts(39_899_917, 0).saturating_mul(n.into())) + // Measured: `8275 + n * (389 ±0)` + // Estimated: `10805 + n * (3566 ±0)` + // Minimum execution time: 180_144_000 picoseconds. + Weight::from_parts(237_134_733, 0) + .saturating_add(Weight::from_parts(0, 10805)) + // Standard Error: 52_498 + .saturating_add(Weight::from_parts(73_633_326, 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)) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_parts(0, 3774).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 3566).saturating_mul(n.into())) } /// 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: `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::VirtualStakers` (r:1 w:0) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:0) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(103), added: 2578, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListNodes` (r:3 w:3) /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListBags` (r:2 w:2) @@ -543,26 +545,26 @@ impl pallet_staking::WeightInfo for WeightInfo { /// The range of component `l` is `[1, 32]`. fn rebond(l: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1922 + l * (5 ±0)` + // Measured: `1845 + l * (5 ±0)` // Estimated: `8877` - // Minimum execution time: 79_136_000 picoseconds. - Weight::from_parts(82_129_497, 0) + // Minimum execution time: 89_307_000 picoseconds. + Weight::from_parts(92_902_634, 0) .saturating_add(Weight::from_parts(0, 8877)) - // Standard Error: 3_867 - .saturating_add(Weight::from_parts(75_156, 0).saturating_mul(l.into())) + // Standard Error: 4_446 + .saturating_add(Weight::from_parts(73_546, 0).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(9)) - .saturating_add(T::DbWeight::get().writes(7)) + .saturating_add(T::DbWeight::get().writes(6)) } + /// Storage: `Staking::VirtualStakers` (r:1 w:1) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, 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: `Staking::SlashingSpans` (r:1 w:1) /// Proof: `Staking::SlashingSpans` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// 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: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(103), added: 2578, 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) @@ -582,15 +584,15 @@ impl pallet_staking::WeightInfo for WeightInfo { /// The range of component `s` is `[1, 100]`. fn reap_stash(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2127 + s * (4 ±0)` + // Measured: `2153 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 89_375_000 picoseconds. - Weight::from_parts(91_224_907, 0) + // Minimum execution time: 130_544_000 picoseconds. + Weight::from_parts(133_260_598, 0) .saturating_add(Weight::from_parts(0, 6248)) - // Standard Error: 3_424 - .saturating_add(Weight::from_parts(1_219_542, 0).saturating_mul(s.into())) + // Standard Error: 3_545 + .saturating_add(Weight::from_parts(1_313_348, 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(12)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) .saturating_add(Weight::from_parts(0, 4).saturating_mul(s.into())) } @@ -633,14 +635,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 ±4) + v * (3566 ±0)` - // Minimum execution time: 520_905_000 picoseconds. - Weight::from_parts(523_771_000, 0) + // Estimated: `456136 + n * (3566 ±4) + v * (3566 ±40)` + // Minimum execution time: 654_756_000 picoseconds. + Weight::from_parts(658_861_000, 0) .saturating_add(Weight::from_parts(0, 456136)) - // 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())) + // Standard Error: 2_078_102 + .saturating_add(Weight::from_parts(67_775_668, 0).saturating_mul(v.into())) + // Standard Error: 207_071 + .saturating_add(Weight::from_parts(22_624_711, 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()))) @@ -669,15 +671,15 @@ impl pallet_staking::WeightInfo for WeightInfo { /// The range of component `n` is `[500, 1000]`. fn get_npos_voters(v: u32, n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `3108 + n * (907 ±0) + v * (391 ±0)` + // Measured: `3141 + n * (907 ±0) + v * (391 ±0)` // Estimated: `456136 + n * (3566 ±0) + v * (3566 ±0)` - // Minimum execution time: 36_848_619_000 picoseconds. - Weight::from_parts(37_362_442_000, 0) + // Minimum execution time: 42_790_195_000 picoseconds. + Weight::from_parts(42_954_437_000, 0) .saturating_add(Weight::from_parts(0, 456136)) - // 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())) + // Standard Error: 478_107 + .saturating_add(Weight::from_parts(6_744_044, 0).saturating_mul(v.into())) + // Standard Error: 478_107 + .saturating_add(Weight::from_parts(4_837_739, 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()))) @@ -692,13 +694,13 @@ impl pallet_staking::WeightInfo for WeightInfo { /// The range of component `v` is `[500, 1000]`. fn get_npos_targets(v: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `946 + v * (50 ±0)` + // Measured: `979 + v * (50 ±0)` // Estimated: `3510 + v * (2520 ±0)` - // Minimum execution time: 2_512_817_000 picoseconds. - Weight::from_parts(119_401_374, 0) + // Minimum execution time: 2_851_801_000 picoseconds. + Weight::from_parts(4_477_533, 0) .saturating_add(Weight::from_parts(0, 3510)) - // Standard Error: 8_463 - .saturating_add(Weight::from_parts(4_860_364, 0).saturating_mul(v.into())) + // Standard Error: 8_644 + .saturating_add(Weight::from_parts(5_811_682, 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())) @@ -721,8 +723,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_686_000 picoseconds. - Weight::from_parts(3_881_000, 0) + // Minimum execution time: 4_250_000 picoseconds. + Weight::from_parts(4_472_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(7)) } @@ -744,8 +746,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_143_000 picoseconds. - Weight::from_parts(3_424_000, 0) + // Minimum execution time: 3_986_000 picoseconds. + Weight::from_parts(4_144_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(7)) } @@ -773,10 +775,10 @@ impl pallet_staking::WeightInfo for WeightInfo { /// Proof: `VoterList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn chill_other() -> Weight { // Proof Size summary in bytes: - // Measured: `1870` + // Measured: `1903` // Estimated: `6248` - // Minimum execution time: 66_946_000 picoseconds. - Weight::from_parts(69_382_000, 0) + // Minimum execution time: 87_291_000 picoseconds. + Weight::from_parts(89_344_000, 0) .saturating_add(Weight::from_parts(0, 6248)) .saturating_add(T::DbWeight::get().reads(12)) .saturating_add(T::DbWeight::get().writes(6)) @@ -787,10 +789,10 @@ impl pallet_staking::WeightInfo for WeightInfo { /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) fn force_apply_min_commission() -> Weight { // Proof Size summary in bytes: - // Measured: `658` + // Measured: `691` // Estimated: `3510` - // Minimum execution time: 11_278_000 picoseconds. - Weight::from_parts(11_603_000, 0) + // Minimum execution time: 16_113_000 picoseconds. + Weight::from_parts(16_593_000, 0) .saturating_add(Weight::from_parts(0, 3510)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) @@ -801,33 +803,53 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_963_000 picoseconds. - Weight::from_parts(2_077_000, 0) + // Minimum execution time: 2_433_000 picoseconds. + Weight::from_parts(2_561_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } - /// 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) + /// Storage: `Staking::VirtualStakers` (r:1 w:0) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:0) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(103), added: 2578, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:0) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:1 w:0) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, 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 { // Proof Size summary in bytes: - // Measured: `1014` + // Measured: `1040` // Estimated: `4764` - // Minimum execution time: 40_258_000 picoseconds. - Weight::from_parts(41_210_000, 0) + // Minimum execution time: 50_167_000 picoseconds. + Weight::from_parts(51_108_000, 0) .saturating_add(Weight::from_parts(0, 4764)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(4)) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(2)) } + /// Storage: `Staking::VirtualStakers` (r:1 w:0) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, 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::Ledger` (r:1 w:0) + /// 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::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(103), added: 2578, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) fn migrate_currency() -> Weight { - // will be auto-generated - Default::default() + // Proof Size summary in bytes: + // Measured: `1209` + // Estimated: `4764` + // Minimum execution time: 91_790_000 picoseconds. + Weight::from_parts(92_991_000, 0) + .saturating_add(Weight::from_parts(0, 4764)) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(2)) } } From b3352dd41dddbc7e349d8b56df1e9a4ee8c62c2b Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 18 Sep 2024 14:30:16 +0200 Subject: [PATCH 077/142] comment about ignoring resolve err --- substrate/frame/treasury/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/substrate/frame/treasury/src/lib.rs b/substrate/frame/treasury/src/lib.rs index fd948d82e0ba..6617e796c8cb 100644 --- a/substrate/frame/treasury/src/lib.rs +++ b/substrate/frame/treasury/src/lib.rs @@ -995,6 +995,7 @@ impl OnUnbalanced> for FungibleComp use frame_support::traits::fungible::Balanced; let numeric_amount = credit.peek(); + // can't do much if following errors since the calling function is infallible. let _ = T::Currency::resolve(&Pallet::::account_id(), credit); Pallet::::deposit_event(Event::Deposit { value: numeric_amount }); From f0d2d148c641596d2b51fb59ee400f75a51ca15a Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 18 Sep 2024 14:34:48 +0200 Subject: [PATCH 078/142] total balance for ED --- substrate/frame/support/src/traits/tokens/fungible/regular.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/substrate/frame/support/src/traits/tokens/fungible/regular.rs b/substrate/frame/support/src/traits/tokens/fungible/regular.rs index 29f907ce2654..836602219fff 100644 --- a/substrate/frame/support/src/traits/tokens/fungible/regular.rs +++ b/substrate/frame/support/src/traits/tokens/fungible/regular.rs @@ -213,8 +213,8 @@ pub trait Unbalanced: Inspect { } else { old_balance.checked_add(&amount).ok_or(ArithmeticError::Overflow)? }; - // FIXME(ank4n): add test for this case - // look at total balance to ensure ED is respected + + // look at total balance to ensure ED is respected. let new_total_balance = amount.saturating_add(Self::total_balance(who)); if new_total_balance < Self::minimum_balance() { // Attempt to increase from 0 to below minimum -> stays at zero. From 3ca1081bb56f1c15c8dbea61925e9e0f633466b4 Mon Sep 17 00:00:00 2001 From: Ankan Date: Thu, 19 Sep 2024 12:22:38 +0200 Subject: [PATCH 079/142] ensure ti is updated at reward --- substrate/frame/staking/src/tests.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 6d5cca4f3984..3c2233cea736 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -361,8 +361,16 @@ fn rewards_should_work() { remainder: maximum_payout - total_payout_0 } ); + + // make note of total issuance before rewards. + let total_issuance_0 = asset::total_issuance::(); + mock::make_all_reward_payment(0); + // total issuance should have increased + let total_issuance_1 = asset::total_issuance::(); + assert_eq!(total_issuance_1, total_issuance_0 + total_payout_0); + assert_eq_error_rate!( asset::total_balance::(&11), init_balance_11 + part_for_11 * total_payout_0 * 2 / 3, @@ -402,6 +410,7 @@ fn rewards_should_work() { ); mock::make_all_reward_payment(1); + assert_eq!(asset::total_issuance::(), total_issuance_1 + total_payout_1); assert_eq_error_rate!( asset::total_balance::(&11), init_balance_11 + part_for_11 * (total_payout_0 * 2 / 3 + total_payout_1), From 7a16988e726a9a29d51b70a2e5e44185fb94e0d2 Mon Sep 17 00:00:00 2001 From: Ankan Date: Thu, 19 Sep 2024 12:31:07 +0200 Subject: [PATCH 080/142] make slash resolve to treasury defensive --- substrate/frame/treasury/src/lib.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/substrate/frame/treasury/src/lib.rs b/substrate/frame/treasury/src/lib.rs index 6617e796c8cb..b4c1a02a1970 100644 --- a/substrate/frame/treasury/src/lib.rs +++ b/substrate/frame/treasury/src/lib.rs @@ -96,8 +96,8 @@ use frame_support::{ dispatch::{DispatchResult, DispatchResultWithPostInfo}, ensure, print, traits::{ - fungible::Credit, tokens::Pay, Currency, ExistenceRequirement::KeepAlive, Get, Imbalance, - OnUnbalanced, ReservableCurrency, WithdrawReasons, + fungible::Credit, tokens::Pay, Currency, Defensive, ExistenceRequirement::KeepAlive, Get, + Imbalance, OnUnbalanced, ReservableCurrency, WithdrawReasons, }, weights::Weight, BoundedVec, PalletId, @@ -995,8 +995,7 @@ impl OnUnbalanced> for FungibleComp use frame_support::traits::fungible::Balanced; let numeric_amount = credit.peek(); - // can't do much if following errors since the calling function is infallible. - let _ = T::Currency::resolve(&Pallet::::account_id(), credit); + let _ = T::Currency::resolve(&Pallet::::account_id(), credit).defensive(); Pallet::::deposit_event(Event::Deposit { value: numeric_amount }); } From d67069a5f11f17fe2fc248c31010b06a8c6eb171 Mon Sep 17 00:00:00 2001 From: Ankan Date: Fri, 20 Sep 2024 18:37:53 +0200 Subject: [PATCH 081/142] migrate virtual stakers code --- substrate/frame/staking/src/pallet/impls.rs | 34 +++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index cd223c319ff3..fc7a7aa66c17 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -1159,8 +1159,38 @@ impl Pallet { } pub(super) fn do_migrate_currency(stash: &T::AccountId) -> DispatchResult { - // we can't do anything for virtual stakers since their funds are not managed/held by - // this pallet. + if Self::is_virtual_staker(stash) { + // Funds for virtual stakers not managed/held by this pallet. We only need to clear + // the extra consumer we used to have with OldCurrency. + frame_system::Pallet::::dec_consumers(&stash); + + // The delegation system that manages the virtual staker needed to increment provider + // previously because of the consumer needed by this pallet. In reality, this stash + // is just a key for managing the ledger and the account does not need to hold any + // balance or exist. We decrement this provider. + let actual_providers = frame_system::Pallet::::providers(stash); + + let expected_providers = + // provider is expected to be 1 but someone can always transfer some free funds to + // these accounts, increasing the provider. + if asset::free_to_stake::(&stash) >= asset::existential_deposit::() { + 2 + } else { + 1 + }; + + // We should never have more than expected providers. + ensure!(actual_providers <= expected_providers, Error::::BadState); + + // if actual provider is less than expected, it is already migrated. + ensure!(actual_providers == expected_providers, Error::::AlreadyMigrated); + + // dec provider + let _ = frame_system::Pallet::::dec_providers(&stash)?; + + return Ok(()) + } + ensure!(!Self::is_virtual_staker(stash), Error::::VirtualStakerNotAllowed); let ledger = Self::ledger(Stash(stash.clone()))?; let locked: BalanceOf = T::OldCurrency::balance_locked(STAKING_ID, stash).into(); From 39f520ba320c94b6ac1d773ec92631f515e5b9b3 Mon Sep 17 00:00:00 2001 From: Ankan Date: Fri, 20 Sep 2024 19:14:44 +0200 Subject: [PATCH 082/142] add test for migration of virtual stakers --- substrate/frame/staking/src/mock.rs | 4 ---- substrate/frame/staking/src/tests.rs | 22 ++++++++++++++++++++++ 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index 894a9b9747b9..048735030e02 100644 --- a/substrate/frame/staking/src/mock.rs +++ b/substrate/frame/staking/src/mock.rs @@ -602,10 +602,6 @@ pub(crate) fn bond_virtual_nominator( val: Balance, target: Vec, ) { - // In a real scenario, `who` is a keyless account managed by another pallet which provides for - // it. - System::inc_providers(&who); - // Bond who virtually. assert_ok!(::virtual_bond(&who, val, &payee)); assert_ok!(Staking::nominate(RuntimeOrigin::signed(who), target)); diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 3c2233cea736..bc5664b2a14e 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -8554,5 +8554,27 @@ mod hold_migration { // unbond works after migration. assert_ok!(Staking::unbond(RuntimeOrigin::signed(alice), 100)); }); + + #[test] + fn virtual_staker_consumer_provider_dec() { + // Ensure virtual stakers consumer and provider count is decremented. + ExtBuilder::default().has_stakers(true).build_and_execute(|| { + // 200 virtual bonds + bond_virtual_nominator(200, 201, 500, vec![11, 21]); + + // previously the virtual nominator had a provider inc by the delegation system as + // well as a consumer by this pallet. + System::inc_providers(&200); + System::inc_consumers(&200).expect("has provider, can consume"); + + // migrate 200 + assert_ok!(Staking::migrate_currency(RuntimeOrigin::signed(1), 200)); + + // ensure account does not exist in system anymore. + assert_eq!(System::consumers(&200), 0); + assert_eq!(System::providers(&200), 0); + assert!(!System::account_exists(&200)); + }); + } } } From 0f01445db1973097cc6cb4ebf5a3973d91f62d6f Mon Sep 17 00:00:00 2001 From: Ankan Date: Fri, 20 Sep 2024 19:26:47 +0200 Subject: [PATCH 083/142] add more cases to virtual staker migration --- substrate/frame/staking/src/tests.rs | 48 +++++++++++++++++++++------- 1 file changed, 37 insertions(+), 11 deletions(-) diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index bc5664b2a14e..5be4ba6d0c94 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -8554,19 +8554,21 @@ mod hold_migration { // unbond works after migration. assert_ok!(Staking::unbond(RuntimeOrigin::signed(alice), 100)); }); + } - #[test] - fn virtual_staker_consumer_provider_dec() { - // Ensure virtual stakers consumer and provider count is decremented. - ExtBuilder::default().has_stakers(true).build_and_execute(|| { - // 200 virtual bonds - bond_virtual_nominator(200, 201, 500, vec![11, 21]); + #[test] + fn virtual_staker_consumer_provider_dec() { + // Ensure virtual stakers consumer and provider count is decremented. + ExtBuilder::default().has_stakers(true).build_and_execute(|| { + // 200 virtual bonds + bond_virtual_nominator(200, 201, 500, vec![11, 21]); - // previously the virtual nominator had a provider inc by the delegation system as - // well as a consumer by this pallet. - System::inc_providers(&200); - System::inc_consumers(&200).expect("has provider, can consume"); + // previously the virtual nominator had a provider inc by the delegation system as + // well as a consumer by this pallet. + System::inc_providers(&200); + System::inc_consumers(&200).expect("has provider, can consume"); + hypothetically!({ // migrate 200 assert_ok!(Staking::migrate_currency(RuntimeOrigin::signed(1), 200)); @@ -8575,6 +8577,30 @@ mod hold_migration { assert_eq!(System::providers(&200), 0); assert!(!System::account_exists(&200)); }); - } + + hypothetically!({ + // 200 has an erroneously extra provider + System::inc_providers(&200); + + // causes migration to fail. + assert_noop!( + Staking::migrate_currency(RuntimeOrigin::signed(1), 200), + Error::::BadState + ); + }); + + // 200 is funded for more than ED by a random account. + assert_ok!(Balances::transfer_allow_death(RuntimeOrigin::signed(999), 200, 10)); + + // it has an extra provider now. + assert_eq!(System::providers(&200), 2); + + // migrate 200 + assert_ok!(Staking::migrate_currency(RuntimeOrigin::signed(1), 200)); + + // 1 provider is left, consumers is 0. + assert_eq!(System::providers(&200), 1); + assert_eq!(System::consumers(&200), 0); + }); } } From 423b950bf858c2d4eaa52b72635668f4cc139d09 Mon Sep 17 00:00:00 2001 From: Ankan Date: Tue, 8 Oct 2024 15:01:03 +0200 Subject: [PATCH 084/142] apply donal suggestions --- .../test-staking-e2e/src/lib.rs | 21 ++++++++++--------- substrate/frame/fast-unstake/src/tests.rs | 4 ++-- substrate/frame/staking/src/asset.rs | 4 ++-- substrate/frame/staking/src/benchmarking.rs | 2 +- substrate/frame/staking/src/pallet/impls.rs | 4 ++-- substrate/frame/staking/src/tests.rs | 2 +- 6 files changed, 19 insertions(+), 18 deletions(-) diff --git a/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/lib.rs b/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/lib.rs index 135149694387..34cd149e32b5 100644 --- a/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/lib.rs +++ b/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/lib.rs @@ -25,6 +25,7 @@ use mock::*; use pallet_timestamp::Now; use sp_core::Get; use sp_runtime::Perbill; +use pallet_staking::asset::stakeable_balance; use crate::mock::RuntimeOrigin; @@ -322,8 +323,8 @@ fn automatic_unbonding_pools() { assert_eq!(::MaxUnbonding::get(), 1); // init state of pool members. - let init_stakeable_balance_2 = pallet_staking::asset::stakeable_balance::(&2); - let init_stakeable_balance_3 = pallet_staking::asset::stakeable_balance::(&3); + let init_stakeable_balance_2 = stakeable_balance::(&2); + let init_stakeable_balance_3 = stakeable_balance::(&3); let pool_bonded_account = Pools::generate_bonded_account(1); @@ -373,7 +374,7 @@ fn automatic_unbonding_pools() { System::reset_events(); let staked_before_withdraw_pool = staked_amount_for(pool_bonded_account); - assert_eq!(pallet_staking::asset::stakeable_balance::(&pool_bonded_account), 26); + assert_eq!(stakeable_balance::(&pool_bonded_account), 26); // now unbonding 3 will work, although the pool's ledger still has the unlocking chunks // filled up. @@ -391,7 +392,7 @@ fn automatic_unbonding_pools() { ); // balance of the pool remains the same, it hasn't withdraw explicitly from the pool yet. - assert_eq!(pallet_staking::asset::stakeable_balance::(&pool_bonded_account), 26); + assert_eq!(stakeable_balance::(&pool_bonded_account), 26); // but the locked amount in the pool's account decreases due to the auto-withdraw: assert_eq!(staked_before_withdraw_pool - 10, staked_amount_for(pool_bonded_account)); @@ -400,12 +401,12 @@ fn automatic_unbonding_pools() { // however, note that the withdrawing from the pool still works for 2, the funds are taken // from the pool's non staked balance. - assert_eq!(pallet_staking::asset::stakeable_balance::(&pool_bonded_account), 26); + assert_eq!(stakeable_balance::(&pool_bonded_account), 26); assert_eq!(pallet_staking::asset::staked::(&pool_bonded_account), 15); assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(2), 2, 10)); - assert_eq!(pallet_staking::asset::stakeable_balance::(&pool_bonded_account), 16); + assert_eq!(stakeable_balance::(&pool_bonded_account), 16); - assert_eq!(pallet_staking::asset::stakeable_balance::(&2), 20); + assert_eq!(stakeable_balance::(&2), 20); assert_eq!(TotalValueLocked::::get(), 15); // 3 cannot withdraw yet. @@ -424,13 +425,13 @@ fn automatic_unbonding_pools() { assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(3), 3, 10)); // final conditions are the expected. - assert_eq!(pallet_staking::asset::stakeable_balance::(&pool_bonded_account), 6); // 5 init bonded + ED + assert_eq!(stakeable_balance::(&pool_bonded_account), 6); // 5 init bonded + ED assert_eq!( - pallet_staking::asset::stakeable_balance::(&2), + stakeable_balance::(&2), init_stakeable_balance_2 ); assert_eq!( - pallet_staking::asset::stakeable_balance::(&3), + stakeable_balance::(&3), init_stakeable_balance_3 ); diff --git a/substrate/frame/fast-unstake/src/tests.rs b/substrate/frame/fast-unstake/src/tests.rs index 7c11f381ca10..6bd9163cb4fb 100644 --- a/substrate/frame/fast-unstake/src/tests.rs +++ b/substrate/frame/fast-unstake/src/tests.rs @@ -146,7 +146,7 @@ fn deregister_works() { // Controller then changes mind and deregisters. assert_ok!(FastUnstake::deregister(RuntimeOrigin::signed(1))); - assert_eq!(::Currency::reserved_balance(&1) - pre_reserved, 0); + assert_eq!(::Currency::reserved_balance(&1), pre_reserved); // Ensure stash no longer exists in the queue. assert_eq!(Queue::::get(1), None); @@ -297,7 +297,7 @@ mod on_idle { ); assert_eq!(Queue::::count(), 3); - assert_eq!(::Currency::reserved_balance(&1) - pre_reserved, 0); + assert_eq!(::Currency::reserved_balance(&1), pre_reserved); assert_eq!( fast_unstake_events_since_last_call(), diff --git a/substrate/frame/staking/src/asset.rs b/substrate/frame/staking/src/asset.rs index 847bfbc2db6c..d17a3233ef77 100644 --- a/substrate/frame/staking/src/asset.rs +++ b/substrate/frame/staking/src/asset.rs @@ -41,7 +41,7 @@ pub fn total_issuance() -> BalanceOf { T::Currency::total_issuance() } -/// Total balance of `who`. Includes both, free and reserved. +/// Total balance of `who`. Includes both free and reserved. pub fn total_balance(who: &T::AccountId) -> BalanceOf { T::Currency::total_balance(who) } @@ -137,7 +137,7 @@ pub fn slash( /// Mint `value` into an existing account `who`. /// /// This does not increase the total issuance. -pub fn mint_existing( +pub fn mint_into_existing( who: &T::AccountId, value: BalanceOf, ) -> Option> { diff --git a/substrate/frame/staking/src/benchmarking.rs b/substrate/frame/staking/src/benchmarking.rs index 3b06831c9c8a..36a0e186c1a8 100644 --- a/substrate/frame/staking/src/benchmarking.rs +++ b/substrate/frame/staking/src/benchmarking.rs @@ -249,7 +249,7 @@ benchmarks! { let original_bonded: BalanceOf = Ledger::::get(&controller).map(|l| l.active).ok_or("ledger not created after")?; - let _ = asset::mint_existing::(&stash, max_additional).unwrap(); + let _ = asset::mint_into_existing::(&stash, max_additional).unwrap(); whitelist_account!(stash); }: _(RawOrigin::Signed(stash), max_additional) diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index fc7a7aa66c17..7790994bea9a 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -412,12 +412,12 @@ impl Pallet { let dest = Self::payee(StakingAccount::Stash(stash.clone()))?; let maybe_imbalance = match dest { - RewardDestination::Stash => asset::mint_existing::(stash, amount), + RewardDestination::Stash => asset::mint_into_existing::(stash, amount), RewardDestination::Staked => Self::ledger(Stash(stash.clone())) .and_then(|mut ledger| { ledger.active += amount; ledger.total += amount; - let r = asset::mint_existing::(stash, amount); + let r = asset::mint_into_existing::(stash, amount); let _ = ledger .update() diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index d811cccfb30d..e6e5c61c5f91 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -8419,7 +8419,7 @@ mod hold_migration { // any ledger mutation should create a hold hypothetically!({ // give some extra balance to alice. - let _ = asset::mint_existing::(&alice, 100); + let _ = asset::mint_into_existing::(&alice, 100); // WHEN new fund is bonded to ledger. assert_ok!(Staking::bond_extra(RuntimeOrigin::signed(alice), 100)); From c03df7f39cbb61de589e831afc8aaaa753bd530e Mon Sep 17 00:00:00 2001 From: Ankan Date: Tue, 8 Oct 2024 15:01:52 +0200 Subject: [PATCH 085/142] fmt --- .../test-staking-e2e/src/lib.rs | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/lib.rs b/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/lib.rs index 34cd149e32b5..0bf8fee1bf2b 100644 --- a/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/lib.rs +++ b/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/lib.rs @@ -22,10 +22,10 @@ pub(crate) const LOG_TARGET: &str = "tests::e2e-epm"; use frame_support::{assert_err, assert_noop, assert_ok}; use mock::*; +use pallet_staking::asset::stakeable_balance; use pallet_timestamp::Now; use sp_core::Get; use sp_runtime::Perbill; -use pallet_staking::asset::stakeable_balance; use crate::mock::RuntimeOrigin; @@ -426,14 +426,8 @@ fn automatic_unbonding_pools() { // final conditions are the expected. assert_eq!(stakeable_balance::(&pool_bonded_account), 6); // 5 init bonded + ED - assert_eq!( - stakeable_balance::(&2), - init_stakeable_balance_2 - ); - assert_eq!( - stakeable_balance::(&3), - init_stakeable_balance_3 - ); + assert_eq!(stakeable_balance::(&2), init_stakeable_balance_2); + assert_eq!(stakeable_balance::(&3), init_stakeable_balance_3); assert_eq!(TotalValueLocked::::get(), init_tvl); }); From e688c9321bff95d514a04c26df3382c2b23cfa42 Mon Sep 17 00:00:00 2001 From: Ankan Date: Tue, 8 Oct 2024 19:26:57 +0200 Subject: [PATCH 086/142] stash needs ed to stay alive --- substrate/frame/staking/src/benchmarking.rs | 2 +- substrate/frame/staking/src/tests.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/substrate/frame/staking/src/benchmarking.rs b/substrate/frame/staking/src/benchmarking.rs index 36a0e186c1a8..674e30faa022 100644 --- a/substrate/frame/staking/src/benchmarking.rs +++ b/substrate/frame/staking/src/benchmarking.rs @@ -249,7 +249,7 @@ benchmarks! { let original_bonded: BalanceOf = Ledger::::get(&controller).map(|l| l.active).ok_or("ledger not created after")?; - let _ = asset::mint_into_existing::(&stash, max_additional).unwrap(); + let _ = asset::mint_into_existing::(&stash, max_additional + asset::existential_deposit::()).unwrap(); whitelist_account!(stash); }: _(RawOrigin::Signed(stash), max_additional) diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index e6e5c61c5f91..c024c12d36ab 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -8069,7 +8069,7 @@ mod ledger_recovery { assert_eq!(asset::staked::(&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. + // 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. From d9e0f86e31bf14a00d78f693edf19bac9eed437a Mon Sep 17 00:00:00 2001 From: Ankan Date: Tue, 8 Oct 2024 19:39:02 +0200 Subject: [PATCH 087/142] update prdoc --- prdoc/pr_5501.prdoc | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/prdoc/pr_5501.prdoc b/prdoc/pr_5501.prdoc index 82ac554bbbf8..6c775c1c3311 100644 --- a/prdoc/pr_5501.prdoc +++ b/prdoc/pr_5501.prdoc @@ -12,7 +12,7 @@ doc: crates: - name: westend-runtime - bump: minor + bump: major - name: kitchensink-runtime bump: minor - name: pallet-delegated-staking @@ -22,6 +22,22 @@ crates: - name: frame-support bump: patch - name: pallet-treasury - bump: minor + bump: patch - name: sp-staking - bump: minor + bump: patch + - name: pallet-beefy + bump: patch + - name: pallet-fast_unstake + bump: patch + - name: pallet-staking + bump: major + - name: pallet-grandpa + bump: patch + - name: pallet-babe + bump: patch + - name: pallet-nomination-pools-benchmarking + bump: patch + - name: pallet-session-benchmarking + bump: patch + - name: pallet-root-offences + bump: patch \ No newline at end of file From 8db37b6ed115152f114a01a258ad0202c64e1e66 Mon Sep 17 00:00:00 2001 From: Ankan Date: Tue, 8 Oct 2024 22:15:12 +0200 Subject: [PATCH 088/142] fix prdoc --- prdoc/pr_5501.prdoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prdoc/pr_5501.prdoc b/prdoc/pr_5501.prdoc index 6c775c1c3311..1f0ff07d473e 100644 --- a/prdoc/pr_5501.prdoc +++ b/prdoc/pr_5501.prdoc @@ -27,7 +27,7 @@ crates: bump: patch - name: pallet-beefy bump: patch - - name: pallet-fast_unstake + - name: pallet-fast-unstake bump: patch - name: pallet-staking bump: major From e87b5e48375182f9c3d28242c625aef4a27d3c72 Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 9 Oct 2024 00:18:12 +0200 Subject: [PATCH 089/142] fix prdoc --- prdoc/pr_5501.prdoc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/prdoc/pr_5501.prdoc b/prdoc/pr_5501.prdoc index 1f0ff07d473e..88d86db22b63 100644 --- a/prdoc/pr_5501.prdoc +++ b/prdoc/pr_5501.prdoc @@ -40,4 +40,6 @@ crates: - name: pallet-session-benchmarking bump: patch - name: pallet-root-offences + bump: patch + - name: pallet-offences-benchmarking bump: patch \ No newline at end of file From b5e473b643a9952ca621896ae9cc0c927faabf50 Mon Sep 17 00:00:00 2001 From: command-bot <> Date: Tue, 8 Oct 2024 22:19:04 +0000 Subject: [PATCH 090/142] ".git/.scripts/commands/fmt/fmt.sh" --- substrate/frame/staking/src/tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index c024c12d36ab..e6e5c61c5f91 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -8069,7 +8069,7 @@ mod ledger_recovery { assert_eq!(asset::staked::(&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. + // 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. From ff1878dedce6f8ee3741e2fc7af4babe9afa38c2 Mon Sep 17 00:00:00 2001 From: Ankan Date: Fri, 25 Oct 2024 12:46:42 +0200 Subject: [PATCH 091/142] update comment --- substrate/frame/staking/src/asset.rs | 7 +++---- substrate/frame/staking/src/ledger.rs | 2 +- substrate/frame/staking/src/pallet/mod.rs | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/substrate/frame/staking/src/asset.rs b/substrate/frame/staking/src/asset.rs index d17a3233ef77..216ec22a4987 100644 --- a/substrate/frame/staking/src/asset.rs +++ b/substrate/frame/staking/src/asset.rs @@ -18,6 +18,9 @@ //! Contains all the interactions with [`Config::Currency`] to manipulate the underlying staking //! asset. +use crate::{ + BalanceOf, Config, HoldReason, NegativeImbalanceOf, PositiveImbalanceOf, SessionInterface, +}; use frame_support::traits::{ fungible::{ hold::{Balanced as FunHoldBalanced, Inspect as FunHoldInspect, Mutate as FunHoldMutate}, @@ -27,10 +30,6 @@ use frame_support::traits::{ }; use sp_runtime::{traits::Zero, DispatchResult, Saturating}; -use crate::{ - BalanceOf, Config, HoldReason, NegativeImbalanceOf, PositiveImbalanceOf, SessionInterface, -}; - /// Existential deposit for the chain. pub fn existential_deposit() -> BalanceOf { T::Currency::minimum_balance() diff --git a/substrate/frame/staking/src/ledger.rs b/substrate/frame/staking/src/ledger.rs index 947050f10183..1d66ebd27e9f 100644 --- a/substrate/frame/staking/src/ledger.rs +++ b/substrate/frame/staking/src/ledger.rs @@ -32,6 +32,7 @@ //! state consistency. use frame_support::{defensive, ensure, traits::Defensive}; +use sp_runtime::DispatchResult; use sp_staking::{StakingAccount, StakingInterface}; use crate::{ @@ -270,7 +271,6 @@ impl StakingLedger { } } -use sp_runtime::DispatchResult; #[cfg(test)] use { crate::UnlockChunk, diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index b091eee595ca..750286fcb715 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -2120,7 +2120,7 @@ pub mod pallet { let new_total = if let Some(total) = maybe_total { let new_total = total.min(stash_balance); - // enforce lock == ledger.amount. + // enforce hold == ledger.amount. asset::update_stake::(&stash, new_total)?; new_total } else { From e6de610d5a8ffdd46f9ae60d77afb42153877883 Mon Sep 17 00:00:00 2001 From: Ankan Date: Sat, 26 Oct 2024 16:47:52 +0200 Subject: [PATCH 092/142] test validator purge keys --- substrate/frame/staking/src/tests.rs | 96 +++++++++++++++++++++------- 1 file changed, 73 insertions(+), 23 deletions(-) diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index e6e5c61c5f91..2b09c08c9741 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -26,7 +26,7 @@ use frame_election_provider_support::{ use frame_support::{ assert_noop, assert_ok, assert_storage_noop, dispatch::{extract_actual_weight, GetDispatchInfo, WithPostDispatchInfo}, - hypothetically, hypothetically_ok, + hypothetically, pallet_prelude::*, traits::{Currency, Get, InspectLockableCurrency, ReservableCurrency}, }; @@ -1955,33 +1955,83 @@ fn reap_stash_fails_if_extra_consumer() { .existential_deposit(10) .balance_factor(10) .build_and_execute(|| { - // given - assert_eq!(asset::staked::(&11), 10 * 1000); - assert_eq!(Staking::bonded(&11), Some(11)); + // given a validator + let validator: AccountId = 300; + asset::set_stakeable_balance::(&validator, 1000); + assert_ok!(Staking::bond( + RuntimeOrigin::signed(validator), + 1000, + RewardDestination::Account(validator) + )); + assert_ok!(Staking::validate( + RuntimeOrigin::signed(validator), + ValidatorPrefs::default() + )); + assert_ok!(Session::set_keys( + RuntimeOrigin::signed(validator), + SessionKeys { other: validator.into() }, + vec![] + )); - // When ledger goes below ED - let mut ledger = Staking::ledger(11.into()).unwrap(); - ledger.slash(ledger.total, 10, 1); - assert_ok!(ledger.update()); - // make stake balance as zero. - asset::set_stakeable_balance::(&11, 0); - assert_eq!(asset::staked::(&11), 0); + // and a nominator + let nominator: AccountId = 301; + asset::set_stakeable_balance::(&nominator, 500); + assert_ok!(Staking::bond( + RuntimeOrigin::signed(nominator), + 500, + RewardDestination::Account(nominator) + )); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(nominator), vec![validator])); + + // assert setup + assert_eq!(asset::staked::(&validator), 1000); + assert_eq!(Staking::bonded(&validator), Some(validator)); + assert_eq!(asset::staked::(&nominator), 500); + assert_eq!(Staking::bonded(&nominator), Some(nominator)); + + // the validator has an extra consumer from another pallet (session) in the runtime. + assert_eq!(System::consumers(&validator), 2); + assert_eq!(System::consumers(&nominator), 1); + + // Slash their bonds to make their stake go below ED + let mut vledger = Staking::ledger(validator.into()).unwrap(); + vledger.slash(vledger.total, 10, 1); + assert_ok!(vledger.update()); + let mut nledger = Staking::ledger(nominator.into()).unwrap(); + nledger.slash(nledger.total, 10, 1); + assert_ok!(nledger.update()); + + // ensure they don't have any extra balance to stake. + asset::set_stakeable_balance::(&validator, 0); + assert_eq!(asset::staked::(&validator), 0); + asset::set_stakeable_balance::(&nominator, 0); + assert_eq!(asset::staked::(&nominator), 0); - // reap stash would work without the extra consumer. - hypothetically_ok!(Staking::reap_stash(RuntimeOrigin::signed(20), 11, 0)); + hypothetically!({ + // Validator has an extra consumer coming from another pallet other than session. + System::inc_consumers(&validator) + .expect("stash has a provider so this should not fail"); + + // This would prevent the pallet to decrement provider from reaping the stash. + assert_noop!( + Staking::reap_stash(RuntimeOrigin::signed(20), validator, 0), + DispatchError::ConsumerRemaining + ); - // mock stash has an extra consumer from another pallet in the runtime. - System::inc_consumers(&11).expect("stash has a provider so this should not fail"); + // Once the extra consumer is removed, the pallet can reap the stash as usual. + System::dec_consumers(&validator); + assert_ok!(Staking::reap_stash(RuntimeOrigin::signed(20), validator, 0)); + }); - // This would prevent the pallet to decrement provider from reaping the stash. - assert_noop!( - Staking::reap_stash(RuntimeOrigin::signed(20), 11, 0), - DispatchError::ConsumerRemaining - ); + // reap stash removes the extra consumer by purging keys. + assert!(pallet_session::NextKeys::::contains_key(&validator)); + assert_ok!(Staking::reap_stash(RuntimeOrigin::signed(20), validator, 0)); + assert!(!pallet_session::NextKeys::::contains_key(&validator)); + assert_eq!(Staking::bonded(&validator), None); - // Once the extra consumer is removed, the pallet can reap the stash. - System::dec_consumers(&11); - assert_ok!(Staking::reap_stash(RuntimeOrigin::signed(20), 11, 0)); + // reap stash works for nominator + assert_ok!(Staking::reap_stash(RuntimeOrigin::signed(20), nominator, 0)); + assert_eq!(Staking::bonded(&nominator), None); }); } From 8e957ff6872653a81f2162b42b0a0c59e5643a34 Mon Sep 17 00:00:00 2001 From: Ankan Date: Sat, 26 Oct 2024 16:52:43 +0200 Subject: [PATCH 093/142] test session purge for reaping validators --- substrate/frame/staking/src/benchmarking.rs | 19 ++++++++++++++----- substrate/frame/staking/src/tests.rs | 2 +- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/substrate/frame/staking/src/benchmarking.rs b/substrate/frame/staking/src/benchmarking.rs index 49e00741bf01..b48ae60a3e61 100644 --- a/substrate/frame/staking/src/benchmarking.rs +++ b/substrate/frame/staking/src/benchmarking.rs @@ -257,7 +257,11 @@ mod benchmarks { .map(|l| l.active) .ok_or("ledger not created after")?; - let _ = asset::mint_into_existing::(&stash, max_additional + asset::existential_deposit::()).unwrap(); + let _ = asset::mint_into_existing::( + &stash, + max_additional + asset::existential_deposit::(), + ) + .unwrap(); whitelist_account!(stash); @@ -1131,16 +1135,21 @@ mod benchmarks { Ok(()) } - migrate_currency { - let (stash, _ctrl) = create_stash_controller::(USER_SEED, 100, RewardDestination::Staked)?; + #[benchmark] + fn migrate_currency() -> Result<(), BenchmarkError> { + let (stash, _ctrl) = + create_stash_controller::(USER_SEED, 100, RewardDestination::Staked)?; let stake = asset::staked::(&stash); migrate_to_old_currency::(stash.clone()); // no holds assert!(asset::staked::(&stash).is_zero()); whitelist_account!(stash); - }: _(RawOrigin::Signed(stash.clone()), stash.clone()) - verify { + + #[extrinsic_call] + _(RawOrigin::Signed(stash.clone()), stash.clone()); + assert_eq!(asset::staked::(&stash), stake); + Ok(()) } impl_benchmark_test_suite!( diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 2b09c08c9741..e156fb7d5992 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -8119,7 +8119,7 @@ mod ledger_recovery { assert_eq!(asset::staked::(&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. + // 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. From d2b1084f4e2473159899d67f9d384457973f9793 Mon Sep 17 00:00:00 2001 From: Ankan Date: Sat, 26 Oct 2024 17:03:56 +0200 Subject: [PATCH 094/142] refactor migration code --- substrate/frame/staking/src/pallet/impls.rs | 63 +++++++++++---------- substrate/frame/staking/src/tests.rs | 32 ++++++++++- 2 files changed, 64 insertions(+), 31 deletions(-) diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index 7790994bea9a..0cb96ccc2764 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -1160,38 +1160,9 @@ impl Pallet { pub(super) fn do_migrate_currency(stash: &T::AccountId) -> DispatchResult { if Self::is_virtual_staker(stash) { - // Funds for virtual stakers not managed/held by this pallet. We only need to clear - // the extra consumer we used to have with OldCurrency. - frame_system::Pallet::::dec_consumers(&stash); - - // The delegation system that manages the virtual staker needed to increment provider - // previously because of the consumer needed by this pallet. In reality, this stash - // is just a key for managing the ledger and the account does not need to hold any - // balance or exist. We decrement this provider. - let actual_providers = frame_system::Pallet::::providers(stash); - - let expected_providers = - // provider is expected to be 1 but someone can always transfer some free funds to - // these accounts, increasing the provider. - if asset::free_to_stake::(&stash) >= asset::existential_deposit::() { - 2 - } else { - 1 - }; - - // We should never have more than expected providers. - ensure!(actual_providers <= expected_providers, Error::::BadState); - - // if actual provider is less than expected, it is already migrated. - ensure!(actual_providers == expected_providers, Error::::AlreadyMigrated); - - // dec provider - let _ = frame_system::Pallet::::dec_providers(&stash)?; - - return Ok(()) + return Self::do_migrate_virtual_staker(stash); } - ensure!(!Self::is_virtual_staker(stash), Error::::VirtualStakerNotAllowed); let ledger = Self::ledger(Stash(stash.clone()))?; let locked: BalanceOf = T::OldCurrency::balance_locked(STAKING_ID, stash).into(); ensure!(!locked.is_zero(), Error::::AlreadyMigrated); @@ -1228,6 +1199,38 @@ impl Pallet { Self::deposit_event(Event::::CurrencyMigrated { stash: stash.clone(), force_withdraw }); Ok(()) } + + fn do_migrate_virtual_staker(stash: &T::AccountId) -> DispatchResult { + // Funds for virtual stakers not managed/held by this pallet. We only need to clear + // the extra consumer we used to have with OldCurrency. + frame_system::Pallet::::dec_consumers(&stash); + + // The delegation system that manages the virtual staker needed to increment provider + // previously because of the consumer needed by this pallet. In reality, this stash + // is just a key for managing the ledger and the account does not need to hold any + // balance or exist. We decrement this provider. + let actual_providers = frame_system::Pallet::::providers(stash); + + let expected_providers = + // provider is expected to be 1 but someone can always transfer some free funds to + // these accounts, increasing the provider. + if asset::free_to_stake::(&stash) >= asset::existential_deposit::() { + 2 + } else { + 1 + }; + + // We should never have more than expected providers. + ensure!(actual_providers <= expected_providers, Error::::BadState); + + // if actual provider is less than expected, it is already migrated. + ensure!(actual_providers == expected_providers, Error::::AlreadyMigrated); + + // dec provider + let _ = frame_system::Pallet::::dec_providers(&stash)?; + + return Ok(()) + } } impl Pallet { diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index e156fb7d5992..b0163ab29ae8 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -8118,7 +8118,7 @@ mod ledger_recovery { // side effects on 333 - ledger, bonded, payee, lock should be intact. assert_eq!(asset::staked::(&333), lock_333_before); // OK assert_eq!(Bonded::::get(&333), Some(444)); // OK - assert!(Payee::::get(&333).is_some()); // OK + assert!(Payee::::get(&333).is_some()); // however, ledger associated with its controller was killed. assert!(Ledger::::get(&444).is_none()); // NOK @@ -8510,6 +8510,12 @@ mod hold_migration { Ok(Stake { total: 1000, active: 1000 }) ); + // ensure cannot migrate again. + assert_noop!( + Staking::migrate_currency(RuntimeOrigin::signed(1), alice), + Error::::AlreadyMigrated + ); + // locked balance is removed assert_eq!(Balances::balance_locked(STAKING_ID, &alice), 0); }); @@ -8546,6 +8552,12 @@ mod hold_migration { staking_events_since_last_call(), vec![Event::CurrencyMigrated { stash: alice, force_withdraw: 0 }] ); + + // ensure cannot migrate again. + assert_noop!( + Staking::migrate_currency(RuntimeOrigin::signed(1), alice), + Error::::AlreadyMigrated + ); }); } #[test] @@ -8601,6 +8613,12 @@ mod hold_migration { }] ); + // ensure cannot migrate again. + assert_noop!( + Staking::migrate_currency(RuntimeOrigin::signed(1), alice), + Error::::AlreadyMigrated + ); + // unbond works after migration. assert_ok!(Staking::unbond(RuntimeOrigin::signed(alice), 100)); }); @@ -8626,6 +8644,12 @@ mod hold_migration { assert_eq!(System::consumers(&200), 0); assert_eq!(System::providers(&200), 0); assert!(!System::account_exists(&200)); + + // ensure cannot migrate again. + assert_noop!( + Staking::migrate_currency(RuntimeOrigin::signed(1), 200), + Error::::AlreadyMigrated + ); }); hypothetically!({ @@ -8651,6 +8675,12 @@ mod hold_migration { // 1 provider is left, consumers is 0. assert_eq!(System::providers(&200), 1); assert_eq!(System::consumers(&200), 0); + + // ensure cannot migrate again. + assert_noop!( + Staking::migrate_currency(RuntimeOrigin::signed(1), 200), + Error::::AlreadyMigrated + ); }); } } From 3e48265301c807b6fdd5d72f8ba809e55dd6b979 Mon Sep 17 00:00:00 2001 From: Ankan Date: Sat, 26 Oct 2024 17:09:47 +0200 Subject: [PATCH 095/142] add rustdoc for migrate --- substrate/frame/staking/src/pallet/mod.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 750286fcb715..20be42b63b2d 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -2181,6 +2181,13 @@ pub mod pallet { Ok(()) } + /// Migrates permissionlessly a stash from locks to holds. + /// + /// This removes the old lock on the stake and creates a hold on it atomically. If all + /// stake cannot be held, the best effort is made to hold as much as possible. The remaining + /// stake is removed from the ledger. + /// + /// The fee is waived if the migration is successful. #[pallet::call_index(30)] #[pallet::weight(T::WeightInfo::migrate_currency())] pub fn migrate_currency( From 7adfb85241c8195fd3fdfc26d7e948f14e717a2d Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 6 Nov 2024 22:16:07 +0100 Subject: [PATCH 096/142] staking should not add provider for accounts --- substrate/frame/staking/src/asset.rs | 19 +------------------ .../src/traits/tokens/fungible/regular.rs | 5 +---- 2 files changed, 2 insertions(+), 22 deletions(-) diff --git a/substrate/frame/staking/src/asset.rs b/substrate/frame/staking/src/asset.rs index 216ec22a4987..3dafd1ce5ec6 100644 --- a/substrate/frame/staking/src/asset.rs +++ b/substrate/frame/staking/src/asset.rs @@ -95,11 +95,6 @@ pub fn set_stakeable_balance(who: &T::AccountId, value: BalanceOf) /// Overwrites the existing stake amount. If passed amount is lower than the existing stake, the /// difference is unlocked. pub fn update_stake(who: &T::AccountId, amount: BalanceOf) -> DispatchResult { - // if first stake, inc provider. This allows us to stake all free balance. - if staked::(who) == Zero::zero() && amount > Zero::zero() { - frame_system::Pallet::::inc_providers(who); - } - T::Currency::set_on_hold(&HoldReason::Staking.into(), who, amount) } @@ -108,19 +103,7 @@ pub fn update_stake(who: &T::AccountId, amount: BalanceOf) -> Disp /// Fails if there are consumers left on `who` that restricts it from being reaped. pub fn kill_stake(who: &T::AccountId) -> DispatchResult { T::Currency::release_all(&HoldReason::Staking.into(), who, Precision::BestEffort) - .map(|_| ())?; - - if !frame_system::Pallet::::can_dec_provider(who) { - // The session pallet keeps a consumer reference to validator stash which may block this - // pallet from clearing its provider reference. If the account cannot provide for itself - // (via enough free balance) to keep the session key, we try to clean up the session keys. - // If the extra consumer comes from somewhere else, reap stash would fail. - T::SessionInterface::purge_keys(who.clone())?; - } - - // dec provider that we incremented for a new stake. - let _ = frame_system::Pallet::::dec_providers(who)?; - Ok(()) + .map(|_| ()) } /// Slash the value from `who`. diff --git a/substrate/frame/support/src/traits/tokens/fungible/regular.rs b/substrate/frame/support/src/traits/tokens/fungible/regular.rs index 836602219fff..54a04444649d 100644 --- a/substrate/frame/support/src/traits/tokens/fungible/regular.rs +++ b/substrate/frame/support/src/traits/tokens/fungible/regular.rs @@ -213,10 +213,7 @@ pub trait Unbalanced: Inspect { } else { old_balance.checked_add(&amount).ok_or(ArithmeticError::Overflow)? }; - - // look at total balance to ensure ED is respected. - let new_total_balance = amount.saturating_add(Self::total_balance(who)); - if new_total_balance < Self::minimum_balance() { + if new_balance < Self::minimum_balance() { // Attempt to increase from 0 to below minimum -> stays at zero. if let BestEffort = precision { Ok(Default::default()) From 60972caaa76d213fa26f659e44417cc4b7c0e374 Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 6 Nov 2024 22:30:57 +0100 Subject: [PATCH 097/142] 49 fails --- substrate/frame/staking/src/mock.rs | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index 048735030e02..a5e816ee47d8 100644 --- a/substrate/frame/staking/src/mock.rs +++ b/substrate/frame/staking/src/mock.rs @@ -431,6 +431,7 @@ impl ExtBuilder { fn build(self) -> sp_io::TestExternalities { sp_tracing::try_init_simple(); let mut storage = frame_system::GenesisConfig::::default().build_storage().unwrap(); + let ed = ExistentialDeposit::get(); let _ = pallet_balances::GenesisConfig:: { balances: vec![ @@ -445,16 +446,19 @@ impl ExtBuilder { (40, self.balance_factor), (50, self.balance_factor), // stashes - (11, self.balance_factor * 1000), - (21, self.balance_factor * 2000), - (31, self.balance_factor * 2000), - (41, self.balance_factor * 2000), - (51, self.balance_factor * 2000), - (201, self.balance_factor * 2000), - (202, self.balance_factor * 2000), + // Note: Previously this pallet used locks and stakers could stake all their balance + // including ED. Now with holds, stakers are required to maintain (non-staked) ED in their + // accounts. Therefore, we drop an additional existential deposit to genesis stakers. + (11, self.balance_factor * 1000 + ed), + (21, self.balance_factor * 2000 + ed), + (31, self.balance_factor * 2000 + ed), + (41, self.balance_factor * 2000 + ed), + (51, self.balance_factor * 2000 + ed), + (201, self.balance_factor * 2000 + ed), + (202, self.balance_factor * 2000 + ed), // optional nominator - (100, self.balance_factor * 2000), - (101, self.balance_factor * 2000), + (100, self.balance_factor * 2000 + ed), + (101, self.balance_factor * 2000 + ed), // aux accounts (60, self.balance_factor), (61, self.balance_factor * 2000), From 7e7980d36a9b65d828658a5a68c92f146a509587 Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 6 Nov 2024 22:40:25 +0100 Subject: [PATCH 098/142] 20 fails --- substrate/frame/staking/src/asset.rs | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/substrate/frame/staking/src/asset.rs b/substrate/frame/staking/src/asset.rs index 3dafd1ce5ec6..ef13146e9c3f 100644 --- a/substrate/frame/staking/src/asset.rs +++ b/substrate/frame/staking/src/asset.rs @@ -19,7 +19,7 @@ //! asset. use crate::{ - BalanceOf, Config, HoldReason, NegativeImbalanceOf, PositiveImbalanceOf, SessionInterface, + BalanceOf, Config, HoldReason, NegativeImbalanceOf, PositiveImbalanceOf, }; use frame_support::traits::{ fungible::{ @@ -28,7 +28,8 @@ use frame_support::traits::{ }, tokens::Precision, }; -use sp_runtime::{traits::Zero, DispatchResult, Saturating}; +use frame_support::traits::tokens::{Fortitude, Preservation}; +use sp_runtime::{DispatchResult, Saturating}; /// Existential deposit for the chain. pub fn existential_deposit() -> BalanceOf { @@ -63,7 +64,7 @@ pub fn staked(who: &T::AccountId) -> BalanceOf { /// /// Does not include the current stake. pub fn free_to_stake(who: &T::AccountId) -> BalanceOf { - T::Currency::balance(who) + T::Currency::reducible_balance(who, Preservation::Preserve, Fortitude::Polite) } /// Set balance that can be staked for `who`. @@ -75,15 +76,19 @@ pub fn free_to_stake(who: &T::AccountId) -> BalanceOf { pub fn set_stakeable_balance(who: &T::AccountId, value: BalanceOf) { use frame_support::traits::fungible::Mutate; + // minimum free balance (non-staked) required to keep the account alive. + let ed = existential_deposit::(); + // currently on stake let staked_balance = staked::(who); - // if value is greater than staked balance, we need to increase the free balance. + + // if new value is greater than staked balance, mint some free balance. if value > staked_balance { - let _ = T::Currency::set_balance(who, value - staked_balance); + let _ = T::Currency::set_balance(who, value - staked_balance + ed); } else { // else reduce the staked balance. update_stake::(who, value).expect("can remove from what is staked"); - // burn all free - let _ = T::Currency::set_balance(who, Zero::zero()); + // burn all free, only leaving ED. + let _ = T::Currency::set_balance(who, ed); } // ensure new stakeable balance same as desired `value`. From 69e7bcb6cd1ad939dab1371aded97183094cf388 Mon Sep 17 00:00:00 2001 From: Ankan Date: Thu, 7 Nov 2024 00:00:59 +0100 Subject: [PATCH 099/142] 12 fails --- substrate/frame/staking/src/asset.rs | 2 +- substrate/frame/staking/src/mock.rs | 2 +- substrate/frame/staking/src/testing_utils.rs | 2 +- substrate/frame/staking/src/tests.rs | 28 +++++++++++--------- 4 files changed, 18 insertions(+), 16 deletions(-) diff --git a/substrate/frame/staking/src/asset.rs b/substrate/frame/staking/src/asset.rs index ef13146e9c3f..5290c531f738 100644 --- a/substrate/frame/staking/src/asset.rs +++ b/substrate/frame/staking/src/asset.rs @@ -41,7 +41,7 @@ pub fn total_issuance() -> BalanceOf { T::Currency::total_issuance() } -/// Total balance of `who`. Includes both free and reserved. +/// Total balance of `who`. Includes both free and staked. pub fn total_balance(who: &T::AccountId) -> BalanceOf { T::Currency::total_balance(who) } diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index a5e816ee47d8..4b8aaa23f6b7 100644 --- a/substrate/frame/staking/src/mock.rs +++ b/substrate/frame/staking/src/mock.rs @@ -461,7 +461,7 @@ impl ExtBuilder { (101, self.balance_factor * 2000 + ed), // aux accounts (60, self.balance_factor), - (61, self.balance_factor * 2000), + (61, self.balance_factor * 2000 + ed), (70, self.balance_factor), (71, self.balance_factor * 2000), (80, self.balance_factor), diff --git a/substrate/frame/staking/src/testing_utils.rs b/substrate/frame/staking/src/testing_utils.rs index ee28849f8c33..56c2a73b43b9 100644 --- a/substrate/frame/staking/src/testing_utils.rs +++ b/substrate/frame/staking/src/testing_utils.rs @@ -253,6 +253,6 @@ pub fn migrate_to_old_currency(who: T::AccountId) { // remove holds. asset::kill_stake::(&who).expect("remove hold failed"); - // replicate old behaviour of explicitly increment consumer. + // replicate old behaviour of explicit increment of consumer. frame_system::Pallet::::inc_consumers(&who).expect("increment consumer failed"); } diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index b0163ab29ae8..cbc774948ede 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -28,7 +28,7 @@ use frame_support::{ dispatch::{extract_actual_weight, GetDispatchInfo, WithPostDispatchInfo}, hypothetically, pallet_prelude::*, - traits::{Currency, Get, InspectLockableCurrency, ReservableCurrency}, + traits::{Currency, Get, InspectLockableCurrency, ReservableCurrency, fungible::Inspect}, }; use mock::*; @@ -230,8 +230,7 @@ fn basic_setup_works() { assert_eq!(active_era(), 0); // Account 10 has `balance_factor` free balance - assert_eq!(asset::stakeable_balance::(&10), 1); - assert_eq!(asset::stakeable_balance::(&10), 1); + assert_eq!(Balances::balance(&10), 1); // New era is not being forced assert_eq!(Staking::force_era(), Forcing::NotForcing); @@ -1002,14 +1001,14 @@ fn cannot_transfer_staked_balance() { ExtBuilder::default().nominate(false).build_and_execute(|| { // Confirm account 11 is stashed assert_eq!(Staking::bonded(&11), Some(11)); - // Confirm account 11 has some free balance + // Confirm account 11 has some stakeable balance assert_eq!(asset::stakeable_balance::(&11), 1000); - // Confirm account 11 (via controller) is totally staked + // Confirm account 11 is totally staked assert_eq!(Staking::eras_stakers(active_era(), &11).total, 1000); // Confirm account 11 cannot transfer as a result assert_noop!( Balances::transfer_allow_death(RuntimeOrigin::signed(11), 21, 1), - TokenError::FundsUnavailable, + TokenError::Frozen, ); // Give account 11 extra free balance @@ -1034,7 +1033,7 @@ fn cannot_transfer_staked_balance_2() { // Confirm account 21 cannot transfer more than 1000 assert_noop!( Balances::transfer_allow_death(RuntimeOrigin::signed(21), 21, 1001), - TokenError::FundsUnavailable, + TokenError::Frozen, ); // Confirm account 21 needs to leave at least ED in free balance to be able to transfer assert_ok!(Balances::transfer_allow_death(RuntimeOrigin::signed(21), 21, 1000)); @@ -1047,12 +1046,13 @@ fn cannot_reserve_staked_balance() { ExtBuilder::default().build_and_execute(|| { // Confirm account 11 is stashed assert_eq!(Staking::bonded(&11), Some(11)); - // Confirm account 11 has some free balance + // Confirm account 11 has some stakeable balance. assert_eq!(asset::stakeable_balance::(&11), 1000); - // Confirm account 11 (via controller 10) is totally staked + // Confirm account 11 is totally staked assert_eq!(Staking::eras_stakers(active_era(), &11).own, 1000); // Confirm account 11 cannot reserve as a result - assert_noop!(Balances::reserve(&11, 1), BalancesError::::InsufficientBalance); + assert_noop!(Balances::reserve(&11, 2), BalancesError::::InsufficientBalance); + assert_noop!(Balances::reserve(&11, 1), DispatchError::ConsumerRemaining); // Give account 11 extra free balance let _ = asset::set_stakeable_balance::(&11, 10000); @@ -1305,11 +1305,12 @@ fn bond_extra_and_withdraw_unbonded_works() { // Give account 11 some large free balance greater than total let _ = asset::set_stakeable_balance::(&11, 1000000); + // ensure it has the correct balance. + assert_eq!(asset::stakeable_balance::(&11), 1000000); + // Initial config should be correct assert_eq!(active_era(), 0); - // check the balance of a validator accounts. - assert_eq!(asset::total_balance::(&11), 1000000); // confirm that 10 is a normal validator and gets paid at the end of the era. mock::start_active_era(1); @@ -2921,7 +2922,8 @@ fn garbage_collection_after_slashing() { // so we don't test those here. assert_eq!(asset::stakeable_balance::(&11), 0); - assert_eq!(asset::total_balance::(&11), 0); + // Non staked balance is not touched. + assert_eq!(asset::total_balance::(&11), ExistentialDeposit::get()); let slashing_spans = SlashingSpans::::get(&11).unwrap(); assert_eq!(slashing_spans.iter().count(), 2); From bec40b138fbfdc476051a3d76c11aaefa1329f59 Mon Sep 17 00:00:00 2001 From: Ankan Date: Thu, 7 Nov 2024 00:35:33 +0100 Subject: [PATCH 100/142] fix migration --- substrate/frame/staking/src/pallet/impls.rs | 25 +++++++++++---------- substrate/frame/staking/src/tests.rs | 7 +++--- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index f1cd855b4121..7fc3cd8915d0 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -1164,19 +1164,23 @@ impl Pallet { } let ledger = Self::ledger(Stash(stash.clone()))?; - let locked: BalanceOf = T::OldCurrency::balance_locked(STAKING_ID, stash).into(); - ensure!(!locked.is_zero(), Error::::AlreadyMigrated); - ensure!(ledger.total == locked, Error::::BadState); + let staked: BalanceOf = T::OldCurrency::balance_locked(STAKING_ID, stash).into(); + ensure!(!staked.is_zero(), Error::::AlreadyMigrated); + ensure!(ledger.total == staked, Error::::BadState); + // remove old staking lock + T::OldCurrency::remove_lock(STAKING_ID, &stash); + + // check if we can hold all stake. let max_hold = asset::stakeable_balance::(&stash); - let force_withdraw = if max_hold >= locked { - // this means we can replace all locked with stake. yay! - asset::update_stake::(&stash, locked)?; + let force_withdraw = if max_hold >= staked { + // this means we can hold all stake. yay! + asset::update_stake::(&stash, staked)?; Zero::zero() } else { - // if we are here, it means we cannot hold all funds. We will do a force withdraw from - // ledger which will mean the stake of the user will abruptly reduce. - let force_withdraw = locked.saturating_sub(max_hold); + // if we are here, it means we cannot hold all user stake. We will do a force withdraw + // from ledger, but that's okay since anyways user do not have funds for it. + let force_withdraw = staked.saturating_sub(max_hold); // we ignore if active is 0. It implies the locked amount is not actively staked. The // account can still get away from potential slash but we can't do much better here. @@ -1190,9 +1194,6 @@ impl Pallet { force_withdraw }; - // remove lock - T::OldCurrency::remove_lock(STAKING_ID, &stash); - // Get rid of the extra consumer we used to have with OldCurrency. frame_system::Pallet::::dec_consumers(&stash); diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index cbc774948ede..11eacab20883 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -8580,9 +8580,10 @@ mod hold_migration { Ok(Stake { total: stake, active: stake }) ); - // She has extra reserved amount which would prevent us from holding all stake. - let expected_force_withdraw = 200; - assert_ok!(Balances::reserve(&alice, expected_force_withdraw)); + // Get rid of the extra ED to emulate all their balance including ED is staked. + assert_ok!(Balances::transfer_allow_death(RuntimeOrigin::signed(alice), 10, ExistentialDeposit::get())); + + let expected_force_withdraw = ExistentialDeposit::get(); // ledger mutation would fail in this case before migration because of failing hold. assert_noop!( From 2451f93c50de0c5486b334b295c579394f4d9cbc Mon Sep 17 00:00:00 2001 From: Ankan Date: Thu, 7 Nov 2024 01:02:57 +0100 Subject: [PATCH 101/142] staking all test pass --- substrate/frame/staking/src/tests.rs | 116 ++++----------------------- 1 file changed, 15 insertions(+), 101 deletions(-) diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 11eacab20883..184256029322 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -499,7 +499,7 @@ fn staking_should_work() { } ); // e.g. it cannot reserve more than 500 that it has free from the total 2000 - assert_noop!(Balances::reserve(&3, 501), BalancesError::::InsufficientBalance); + assert_noop!(Balances::reserve(&3, 501), DispatchError::ConsumerRemaining); assert_ok!(Balances::reserve(&3, 409)); }); } @@ -698,7 +698,7 @@ fn nominating_and_rewards_should_work() { ); // Nominator 3: has [400/1800 ~ 2/9 from 10] + [600/2200 ~ 3/11 from 21]'s reward. ==> // 2/9 + 3/11 - assert_eq!(asset::total_balance::(&3), initial_balance); + assert_eq!(asset::stakeable_balance::(&3), initial_balance); // 333 is the reward destination for 3. assert_eq_error_rate!( asset::total_balance::(&333), @@ -1068,9 +1068,9 @@ fn reward_destination_works() { // Check that account 11 is a validator assert!(Session::validators().contains(&11)); // Check the balance of the validator account - assert_eq!(asset::stakeable_balance::(&10), 1); + assert_eq!(asset::total_balance::(&10), 1); // Check the balance of the stash account - assert_eq!(asset::stakeable_balance::(&11), 1000); + assert_eq!(asset::total_balance::(&11), 1001); // Check how much is at stake assert_eq!( Staking::ledger(11.into()).unwrap(), @@ -1950,92 +1950,6 @@ fn reap_stash_works() { }); } -#[test] -fn reap_stash_fails_if_extra_consumer() { - ExtBuilder::default() - .existential_deposit(10) - .balance_factor(10) - .build_and_execute(|| { - // given a validator - let validator: AccountId = 300; - asset::set_stakeable_balance::(&validator, 1000); - assert_ok!(Staking::bond( - RuntimeOrigin::signed(validator), - 1000, - RewardDestination::Account(validator) - )); - assert_ok!(Staking::validate( - RuntimeOrigin::signed(validator), - ValidatorPrefs::default() - )); - assert_ok!(Session::set_keys( - RuntimeOrigin::signed(validator), - SessionKeys { other: validator.into() }, - vec![] - )); - - // and a nominator - let nominator: AccountId = 301; - asset::set_stakeable_balance::(&nominator, 500); - assert_ok!(Staking::bond( - RuntimeOrigin::signed(nominator), - 500, - RewardDestination::Account(nominator) - )); - assert_ok!(Staking::nominate(RuntimeOrigin::signed(nominator), vec![validator])); - - // assert setup - assert_eq!(asset::staked::(&validator), 1000); - assert_eq!(Staking::bonded(&validator), Some(validator)); - assert_eq!(asset::staked::(&nominator), 500); - assert_eq!(Staking::bonded(&nominator), Some(nominator)); - - // the validator has an extra consumer from another pallet (session) in the runtime. - assert_eq!(System::consumers(&validator), 2); - assert_eq!(System::consumers(&nominator), 1); - - // Slash their bonds to make their stake go below ED - let mut vledger = Staking::ledger(validator.into()).unwrap(); - vledger.slash(vledger.total, 10, 1); - assert_ok!(vledger.update()); - let mut nledger = Staking::ledger(nominator.into()).unwrap(); - nledger.slash(nledger.total, 10, 1); - assert_ok!(nledger.update()); - - // ensure they don't have any extra balance to stake. - asset::set_stakeable_balance::(&validator, 0); - assert_eq!(asset::staked::(&validator), 0); - asset::set_stakeable_balance::(&nominator, 0); - assert_eq!(asset::staked::(&nominator), 0); - - hypothetically!({ - // Validator has an extra consumer coming from another pallet other than session. - System::inc_consumers(&validator) - .expect("stash has a provider so this should not fail"); - - // This would prevent the pallet to decrement provider from reaping the stash. - assert_noop!( - Staking::reap_stash(RuntimeOrigin::signed(20), validator, 0), - DispatchError::ConsumerRemaining - ); - - // Once the extra consumer is removed, the pallet can reap the stash as usual. - System::dec_consumers(&validator); - assert_ok!(Staking::reap_stash(RuntimeOrigin::signed(20), validator, 0)); - }); - - // reap stash removes the extra consumer by purging keys. - assert!(pallet_session::NextKeys::::contains_key(&validator)); - assert_ok!(Staking::reap_stash(RuntimeOrigin::signed(20), validator, 0)); - assert!(!pallet_session::NextKeys::::contains_key(&validator)); - assert_eq!(Staking::bonded(&validator), None); - - // reap stash works for nominator - assert_ok!(Staking::reap_stash(RuntimeOrigin::signed(20), nominator, 0)); - assert_eq!(Staking::bonded(&nominator), None); - }); -} - #[test] fn reap_stash_works_with_existential_deposit_zero() { ExtBuilder::default() @@ -2436,7 +2350,7 @@ fn reward_validator_slashing_validator_does_not_overflow() { EraInfo::::set_exposure(0, &11, exposure); ErasValidatorReward::::insert(0, stake); assert_ok!(Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, 0, 0)); - assert_eq!(asset::total_balance::(&11), stake * 2); + assert_eq!(asset::stakeable_balance::(&11), stake * 2); // ensure ledger has `stake` and no more. Ledger::::insert( @@ -2475,8 +2389,8 @@ fn reward_validator_slashing_validator_does_not_overflow() { &[Perbill::from_percent(100)], ); - assert_eq!(asset::total_balance::(&11), stake - 1); - assert_eq!(asset::total_balance::(&2), 1); + assert_eq!(asset::stakeable_balance::(&11), stake - 1); + assert_eq!(asset::stakeable_balance::(&2), 1); }) } @@ -2736,8 +2650,8 @@ fn reporters_receive_their_slice() { // 50% * (10% * initial_balance / 2) let reward = (initial_balance / 20) / 2; let reward_each = reward / 2; // split into two pieces. - assert_eq!(asset::stakeable_balance::(&1), 10 + reward_each); - assert_eq!(asset::stakeable_balance::(&2), 20 + reward_each); + assert_eq!(asset::total_balance::(&1), 10 + reward_each); + assert_eq!(asset::total_balance::(&2), 20 + reward_each); }); } @@ -2762,7 +2676,7 @@ fn subsequent_reports_in_same_span_pay_out_less() { // F1 * (reward_proportion * slash - 0) // 50% * (10% * initial_balance * 20%) let reward = (initial_balance / 5) / 20; - assert_eq!(asset::stakeable_balance::(&1), 10 + reward); + assert_eq!(asset::total_balance::(&1), 10 + reward); on_offence_now( &[OffenceDetails { @@ -2777,7 +2691,7 @@ fn subsequent_reports_in_same_span_pay_out_less() { // F1 * (reward_proportion * slash - prior_payout) // 50% * (10% * (initial_balance / 2) - prior_payout) let reward = ((initial_balance / 20) - prior_payout) / 2; - assert_eq!(asset::stakeable_balance::(&1), 10 + prior_payout + reward); + assert_eq!(asset::total_balance::(&1), 10 + prior_payout + reward); }); } @@ -6179,7 +6093,7 @@ fn nomination_quota_max_changes_decoding() { .add_staker(70, 71, 10, StakerStatus::Nominator(vec![1, 2, 3])) .add_staker(30, 330, 10, StakerStatus::Nominator(vec![1, 2, 3, 4])) .add_staker(50, 550, 10, StakerStatus::Nominator(vec![1, 2, 3, 4])) - .balance_factor(10) + .balance_factor(11) .build_and_execute(|| { // pre-condition. assert_eq!(MaxNominationsOf::::get(), 16); @@ -7212,7 +7126,7 @@ mod staking_unchecked { fn virtual_bond_does_not_lock() { ExtBuilder::default().build_and_execute(|| { mock::start_active_era(1); - assert_eq!(asset::stakeable_balance::(&10), 1); + assert_eq!(asset::total_balance::(&10), 1); // 10 can bond more than its balance amount since we do not require lock for virtual // bonding. assert_ok!(::virtual_bond(&10, 100, &15)); @@ -8539,8 +8453,8 @@ mod hold_migration { assert_ok!(Staking::migrate_currency(RuntimeOrigin::signed(1), alice)); // THEN - // ensure consumer count stays same. - assert_eq!(System::consumers(&alice), pre_migrate_consumer); + // the extra consumer from old code is removed. + assert_eq!(System::consumers(&alice), pre_migrate_consumer - 1); // ensure no lock assert_eq!(Balances::balance_locked(STAKING_ID, &alice), 0); // ensure stake and hold are same. From 5f8ec96443cee8522ec5fd959fe5f5e47be3fbf1 Mon Sep 17 00:00:00 2001 From: Ankan Date: Thu, 7 Nov 2024 01:03:21 +0100 Subject: [PATCH 102/142] fmt --- substrate/frame/staking/src/asset.rs | 10 +++------- substrate/frame/staking/src/mock.rs | 7 ++++--- substrate/frame/staking/src/tests.rs | 9 ++++++--- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/substrate/frame/staking/src/asset.rs b/substrate/frame/staking/src/asset.rs index 5290c531f738..9c3d483f9427 100644 --- a/substrate/frame/staking/src/asset.rs +++ b/substrate/frame/staking/src/asset.rs @@ -18,17 +18,14 @@ //! Contains all the interactions with [`Config::Currency`] to manipulate the underlying staking //! asset. -use crate::{ - BalanceOf, Config, HoldReason, NegativeImbalanceOf, PositiveImbalanceOf, -}; +use crate::{BalanceOf, Config, HoldReason, NegativeImbalanceOf, PositiveImbalanceOf}; use frame_support::traits::{ fungible::{ hold::{Balanced as FunHoldBalanced, Inspect as FunHoldInspect, Mutate as FunHoldMutate}, Balanced, Inspect as FunInspect, }, - tokens::Precision, + tokens::{Fortitude, Precision, Preservation}, }; -use frame_support::traits::tokens::{Fortitude, Preservation}; use sp_runtime::{DispatchResult, Saturating}; /// Existential deposit for the chain. @@ -107,8 +104,7 @@ pub fn update_stake(who: &T::AccountId, amount: BalanceOf) -> Disp /// /// Fails if there are consumers left on `who` that restricts it from being reaped. pub fn kill_stake(who: &T::AccountId) -> DispatchResult { - T::Currency::release_all(&HoldReason::Staking.into(), who, Precision::BestEffort) - .map(|_| ()) + T::Currency::release_all(&HoldReason::Staking.into(), who, Precision::BestEffort).map(|_| ()) } /// Slash the value from `who`. diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index 4b8aaa23f6b7..2f258d2faba1 100644 --- a/substrate/frame/staking/src/mock.rs +++ b/substrate/frame/staking/src/mock.rs @@ -446,9 +446,10 @@ impl ExtBuilder { (40, self.balance_factor), (50, self.balance_factor), // stashes - // Note: Previously this pallet used locks and stakers could stake all their balance - // including ED. Now with holds, stakers are required to maintain (non-staked) ED in their - // accounts. Therefore, we drop an additional existential deposit to genesis stakers. + // Note: Previously this pallet used locks and stakers could stake all their + // balance including ED. Now with holds, stakers are required to maintain + // (non-staked) ED in their accounts. Therefore, we drop an additional existential + // deposit to genesis stakers. (11, self.balance_factor * 1000 + ed), (21, self.balance_factor * 2000 + ed), (31, self.balance_factor * 2000 + ed), diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 184256029322..971667109fd3 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -28,7 +28,7 @@ use frame_support::{ dispatch::{extract_actual_weight, GetDispatchInfo, WithPostDispatchInfo}, hypothetically, pallet_prelude::*, - traits::{Currency, Get, InspectLockableCurrency, ReservableCurrency, fungible::Inspect}, + traits::{fungible::Inspect, Currency, Get, InspectLockableCurrency, ReservableCurrency}, }; use mock::*; @@ -1311,7 +1311,6 @@ fn bond_extra_and_withdraw_unbonded_works() { // Initial config should be correct assert_eq!(active_era(), 0); - // confirm that 10 is a normal validator and gets paid at the end of the era. mock::start_active_era(1); @@ -8495,7 +8494,11 @@ mod hold_migration { ); // Get rid of the extra ED to emulate all their balance including ED is staked. - assert_ok!(Balances::transfer_allow_death(RuntimeOrigin::signed(alice), 10, ExistentialDeposit::get())); + assert_ok!(Balances::transfer_allow_death( + RuntimeOrigin::signed(alice), + 10, + ExistentialDeposit::get() + )); let expected_force_withdraw = ExistentialDeposit::get(); From bb532f2ef51d1f29d67e79d83ddca6ebe410ef8a Mon Sep 17 00:00:00 2001 From: Ankan Date: Sat, 9 Nov 2024 13:16:27 +0100 Subject: [PATCH 103/142] fix fast unstake tests --- substrate/frame/delegated-staking/src/tests.rs | 6 +++--- substrate/frame/fast-unstake/src/mock.rs | 5 +++-- substrate/frame/fast-unstake/src/tests.rs | 12 +++++++++++- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs index ccec495efd1e..c764e2741a2a 100644 --- a/substrate/frame/delegated-staking/src/tests.rs +++ b/substrate/frame/delegated-staking/src/tests.rs @@ -671,14 +671,14 @@ mod staking_integration { )); assert_ok!(Staking::nominate(RuntimeOrigin::signed(agent), vec![GENESIS_VALIDATOR],)); let init_stake = Staking::stake(&agent).unwrap(); - // agent has an extra provider now added by CoreStaking. - assert_eq!(System::providers(&agent), 2); + // no extra provider added. + assert_eq!(System::providers(&agent), 1); // scenario: 200 is a pool account, and the stake comes from its 4 delegators (300..304) // in equal parts. lets try to migrate this nominator into delegate based stake. // all balance currently is in 200 - assert_eq!(pallet_staking::asset::stakeable_balance::(&agent), agent_amount); + assert_eq!(pallet_staking::asset::total_balance::(&agent), agent_amount); // to migrate, nominator needs to set an account as a proxy delegator where staked funds // will be moved and delegated back to this old nominator account. This should be funded diff --git a/substrate/frame/fast-unstake/src/mock.rs b/substrate/frame/fast-unstake/src/mock.rs index 19f01ebcd13b..a8eba05b26bf 100644 --- a/substrate/frame/fast-unstake/src/mock.rs +++ b/substrate/frame/fast-unstake/src/mock.rs @@ -224,8 +224,9 @@ impl ExtBuilder { .clone() .into_iter() .map(|(stash, _, balance)| (stash, balance * 2)) - .chain(validators_range.clone().map(|x| (x, 7 + 100))) - .chain(nominators_range.clone().map(|x| (x, 7 + 100))) + // give stakers enough balance for stake, ed and fast unstake deposit. + .chain(validators_range.clone().map(|x| (x, 7 + 1 + 100))) + .chain(nominators_range.clone().map(|x| (x, 7 + 1 + 100))) .collect::>(), } .assimilate_storage(&mut storage); diff --git a/substrate/frame/fast-unstake/src/tests.rs b/substrate/frame/fast-unstake/src/tests.rs index 6bd9163cb4fb..0fddb88e02b7 100644 --- a/substrate/frame/fast-unstake/src/tests.rs +++ b/substrate/frame/fast-unstake/src/tests.rs @@ -19,7 +19,15 @@ use super::*; use crate::{mock::*, types::*, Event}; -use frame_support::{pallet_prelude::*, testing_prelude::*, traits::Currency}; +use frame_support::{ + pallet_prelude::*, + testing_prelude::*, + traits::{ + fungible::Inspect, + tokens::{Fortitude::Polite, Preservation::Expendable}, + Currency, + }, +}; use pallet_staking::{CurrentEra, RewardDestination}; use sp_runtime::traits::BadOrigin; @@ -793,6 +801,8 @@ mod on_idle { RuntimeOrigin::signed(VALIDATOR_PREFIX), vec![VALIDATOR_PREFIX] )); + + assert_eq!(Balances::reducible_balance(&VALIDATOR_PREFIX, Expendable, Polite), 7); assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(VALIDATOR_PREFIX))); // but they indeed are exposed! From 56d8c91c53f5c8ed37dce79537748f2efa79441b Mon Sep 17 00:00:00 2001 From: Ankan Date: Sat, 9 Nov 2024 14:50:26 +0100 Subject: [PATCH 104/142] remove tests for transfer stake --- Cargo.toml | 1 - .../test-transfer-stake/Cargo.toml | 40 --- .../test-transfer-stake/src/mock.rs | 231 ------------------ 3 files changed, 272 deletions(-) delete mode 100644 substrate/frame/nomination-pools/test-transfer-stake/Cargo.toml delete mode 100644 substrate/frame/nomination-pools/test-transfer-stake/src/mock.rs diff --git a/Cargo.toml b/Cargo.toml index 533ea4c9e878..8d30f4ff8a85 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -386,7 +386,6 @@ members = [ "substrate/frame/nomination-pools/fuzzer", "substrate/frame/nomination-pools/runtime-api", "substrate/frame/nomination-pools/test-delegate-stake", - "substrate/frame/nomination-pools/test-transfer-stake", "substrate/frame/offences", "substrate/frame/offences/benchmarking", "substrate/frame/paged-list", diff --git a/substrate/frame/nomination-pools/test-transfer-stake/Cargo.toml b/substrate/frame/nomination-pools/test-transfer-stake/Cargo.toml deleted file mode 100644 index 7398404c2351..000000000000 --- a/substrate/frame/nomination-pools/test-transfer-stake/Cargo.toml +++ /dev/null @@ -1,40 +0,0 @@ -[package] -name = "pallet-nomination-pools-test-transfer-stake" -version = "1.0.0" -authors.workspace = true -edition.workspace = true -license = "Apache-2.0" -homepage.workspace = true -repository.workspace = true -description = "FRAME nomination pools pallet tests with the staking pallet" -publish = false - -[lints] -workspace = true - -[package.metadata.docs.rs] -targets = ["x86_64-unknown-linux-gnu"] - -[dev-dependencies] -codec = { features = ["derive"], workspace = true, default-features = true } -scale-info = { features = ["derive"], workspace = true, default-features = true } - -sp-runtime = { workspace = true, default-features = true } -sp-io = { workspace = true, default-features = true } -sp-std = { workspace = true, default-features = true } -sp-staking = { workspace = true, default-features = true } -sp-core = { workspace = true, default-features = true } - -frame-system = { workspace = true, default-features = true } -frame-support = { workspace = true, default-features = true } -frame-election-provider-support = { workspace = true, default-features = true } - -pallet-timestamp = { workspace = true, default-features = true } -pallet-balances = { workspace = true, default-features = true } -pallet-staking = { workspace = true, default-features = true } -pallet-bags-list = { workspace = true, default-features = true } -pallet-staking-reward-curve = { workspace = true, default-features = true } -pallet-nomination-pools = { workspace = true, default-features = true } - -sp-tracing = { workspace = true, default-features = true } -log = { workspace = true, default-features = true } diff --git a/substrate/frame/nomination-pools/test-transfer-stake/src/mock.rs b/substrate/frame/nomination-pools/test-transfer-stake/src/mock.rs deleted file mode 100644 index d913c5fe6948..000000000000 --- a/substrate/frame/nomination-pools/test-transfer-stake/src/mock.rs +++ /dev/null @@ -1,231 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use frame_election_provider_support::VoteWeight; -use frame_support::{ - assert_ok, derive_impl, - pallet_prelude::*, - parameter_types, - traits::{ConstU64, ConstU8, VariantCountOf}, - PalletId, -}; -use sp_runtime::{ - traits::{Convert, IdentityLookup}, - BuildStorage, FixedU128, Perbill, -}; - -type AccountId = u128; -type BlockNumber = u64; -type Balance = u128; - -pub(crate) type T = Runtime; - -pub(crate) const POOL1_BONDED: AccountId = 20318131474730217858575332831085u128; -pub(crate) const POOL1_REWARD: AccountId = 20397359637244482196168876781421u128; - -#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] -impl frame_system::Config for Runtime { - type AccountId = AccountId; - type Lookup = IdentityLookup; - type Block = Block; - type AccountData = pallet_balances::AccountData; -} - -impl pallet_timestamp::Config for Runtime { - type Moment = u64; - type OnTimestampSet = (); - type MinimumPeriod = ConstU64<5>; - type WeightInfo = (); -} - -parameter_types! { - pub static ExistentialDeposit: Balance = 5; -} - -#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig)] -impl pallet_balances::Config for Runtime { - type Balance = Balance; - type ExistentialDeposit = ExistentialDeposit; - type AccountStore = System; - type FreezeIdentifier = RuntimeFreezeReason; - type MaxFreezes = VariantCountOf; - type RuntimeFreezeReason = RuntimeFreezeReason; -} - -pallet_staking_reward_curve::build! { - const I_NPOS: sp_runtime::curve::PiecewiseLinear<'static> = curve!( - min_inflation: 0_025_000, - max_inflation: 0_100_000, - ideal_stake: 0_500_000, - falloff: 0_050_000, - max_piece_count: 40, - test_precision: 0_005_000, - ); -} - -parameter_types! { - pub const RewardCurve: &'static sp_runtime::curve::PiecewiseLinear<'static> = &I_NPOS; - pub static BondingDuration: u32 = 3; -} - -#[derive_impl(pallet_staking::config_preludes::TestDefaultConfig)] -impl pallet_staking::Config for Runtime { - type Currency = Balances; - type UnixTime = pallet_timestamp::Pallet; - type AdminOrigin = frame_system::EnsureRoot; - type BondingDuration = BondingDuration; - type EraPayout = pallet_staking::ConvertCurve; - type ElectionProvider = - frame_election_provider_support::NoElection<(AccountId, BlockNumber, Staking, ())>; - type GenesisElectionProvider = Self::ElectionProvider; - type VoterList = VoterList; - type TargetList = pallet_staking::UseValidatorsMap; - type EventListeners = Pools; - type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; -} - -parameter_types! { - pub static BagThresholds: &'static [VoteWeight] = &[10, 20, 30, 40, 50, 60, 1_000, 2_000, 10_000]; -} - -type VoterBagsListInstance = pallet_bags_list::Instance1; -impl pallet_bags_list::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type WeightInfo = (); - type BagThresholds = BagThresholds; - type ScoreProvider = Staking; - type Score = VoteWeight; -} - -pub struct BalanceToU256; -impl Convert for BalanceToU256 { - fn convert(n: Balance) -> sp_core::U256 { - n.into() - } -} - -pub struct U256ToBalance; -impl Convert for U256ToBalance { - fn convert(n: sp_core::U256) -> Balance { - n.try_into().unwrap() - } -} - -parameter_types! { - pub const PostUnbondingPoolsWindow: u32 = 10; - pub const PoolsPalletId: PalletId = PalletId(*b"py/nopls"); -} - -impl pallet_nomination_pools::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type WeightInfo = (); - type Currency = Balances; - type RuntimeFreezeReason = RuntimeFreezeReason; - type RewardCounter = FixedU128; - type BalanceToU256 = BalanceToU256; - type U256ToBalance = U256ToBalance; - type StakeAdapter = pallet_nomination_pools::adapter::TransferStake; - type PostUnbondingPoolsWindow = PostUnbondingPoolsWindow; - type MaxMetadataLen = ConstU32<256>; - type MaxUnbonding = ConstU32<8>; - type MaxPointsToBalance = ConstU8<10>; - type PalletId = PoolsPalletId; - type AdminOrigin = frame_system::EnsureRoot; -} - -type Block = frame_system::mocking::MockBlock; - -frame_support::construct_runtime!( - pub enum Runtime { - System: frame_system, - Timestamp: pallet_timestamp, - Balances: pallet_balances, - Staking: pallet_staking, - VoterList: pallet_bags_list::, - Pools: pallet_nomination_pools, - } -); - -pub fn new_test_ext() -> sp_io::TestExternalities { - sp_tracing::try_init_simple(); - let mut storage = frame_system::GenesisConfig::::default().build_storage().unwrap(); - let _ = pallet_nomination_pools::GenesisConfig:: { - min_join_bond: 2, - min_create_bond: 2, - max_pools: Some(3), - max_members_per_pool: Some(5), - max_members: Some(3 * 5), - global_max_commission: Some(Perbill::from_percent(90)), - } - .assimilate_storage(&mut storage) - .unwrap(); - - let _ = pallet_balances::GenesisConfig:: { - balances: vec![(10, 100), (20, 100), (21, 100), (22, 100)], - } - .assimilate_storage(&mut storage) - .unwrap(); - - let mut ext = sp_io::TestExternalities::from(storage); - - ext.execute_with(|| { - // for events to be deposited. - frame_system::Pallet::::set_block_number(1); - - // set some limit for nominations. - assert_ok!(Staking::set_staking_configs( - RuntimeOrigin::root(), - pallet_staking::ConfigOp::Set(10), // minimum nominator bond - pallet_staking::ConfigOp::Noop, - pallet_staking::ConfigOp::Noop, - pallet_staking::ConfigOp::Noop, - pallet_staking::ConfigOp::Noop, - pallet_staking::ConfigOp::Noop, - pallet_staking::ConfigOp::Noop, - )); - }); - - ext -} - -parameter_types! { - static ObservedEventsPools: usize = 0; - static ObservedEventsStaking: usize = 0; - static ObservedEventsBalances: usize = 0; -} - -pub(crate) fn pool_events_since_last_call() -> Vec> { - let events = System::events() - .into_iter() - .map(|r| r.event) - .filter_map(|e| if let RuntimeEvent::Pools(inner) = e { Some(inner) } else { None }) - .collect::>(); - let already_seen = ObservedEventsPools::get(); - ObservedEventsPools::set(events.len()); - events.into_iter().skip(already_seen).collect() -} - -pub(crate) fn staking_events_since_last_call() -> Vec> { - let events = System::events() - .into_iter() - .map(|r| r.event) - .filter_map(|e| if let RuntimeEvent::Staking(inner) = e { Some(inner) } else { None }) - .collect::>(); - let already_seen = ObservedEventsStaking::get(); - ObservedEventsStaking::set(events.len()); - events.into_iter().skip(already_seen).collect() -} From 699085e3be6cf6ffd93ce087d2b4dbf229a80424 Mon Sep 17 00:00:00 2001 From: Ankan Date: Sat, 9 Nov 2024 14:55:11 +0100 Subject: [PATCH 105/142] (failing) remove TransferStake strategy --- .../frame/nomination-pools/src/adapter.rs | 113 ------------------ substrate/frame/nomination-pools/src/mock.rs | 59 ++++++++- 2 files changed, 56 insertions(+), 116 deletions(-) diff --git a/substrate/frame/nomination-pools/src/adapter.rs b/substrate/frame/nomination-pools/src/adapter.rs index f125919dabfa..bc3a48bc6df6 100644 --- a/substrate/frame/nomination-pools/src/adapter.rs +++ b/substrate/frame/nomination-pools/src/adapter.rs @@ -236,119 +236,6 @@ pub trait StakeStrategy { } } -/// A staking strategy implementation that supports transfer based staking. -/// -/// In order to stake, this adapter transfers the funds from the member/delegator account to the -/// pool account and stakes through the pool account on `Staking`. -/// -/// This is the older Staking strategy used by pools. To switch to the newer [`DelegateStake`] -/// strategy in an existing runtime, storage migration is required. See -/// [`migration::unversioned::DelegationStakeMigration`]. For new runtimes, it is highly recommended -/// to use the [`DelegateStake`] strategy. -pub struct TransferStake(PhantomData<(T, Staking)>); - -impl, AccountId = T::AccountId>> - StakeStrategy for TransferStake -{ - type Balance = BalanceOf; - type AccountId = T::AccountId; - type CoreStaking = Staking; - - fn strategy_type() -> StakeStrategyType { - StakeStrategyType::Transfer - } - - fn transferable_balance( - pool_account: Pool, - _: Member, - ) -> BalanceOf { - T::Currency::balance(&pool_account.0).saturating_sub(Self::active_stake(pool_account)) - } - - fn total_balance(pool_account: Pool) -> Option> { - Some(T::Currency::total_balance(&pool_account.get())) - } - - fn member_delegation_balance( - _member_account: Member, - ) -> Option { - // for transfer stake, no delegation exists. - None - } - - fn pledge_bond( - who: Member, - pool_account: Pool, - reward_account: &Self::AccountId, - amount: BalanceOf, - bond_type: BondType, - ) -> DispatchResult { - match bond_type { - BondType::Create => { - // first bond - T::Currency::transfer(&who.0, &pool_account.0, amount, Preservation::Expendable)?; - Staking::bond(&pool_account.0, amount, &reward_account) - }, - BondType::Extra => { - // additional bond - T::Currency::transfer(&who.0, &pool_account.0, amount, Preservation::Preserve)?; - Staking::bond_extra(&pool_account.0, amount) - }, - } - } - - fn member_withdraw( - who: Member, - pool_account: Pool, - amount: BalanceOf, - _num_slashing_spans: u32, - ) -> DispatchResult { - T::Currency::transfer(&pool_account.0, &who.0, amount, Preservation::Expendable)?; - - Ok(()) - } - - fn dissolve(pool_account: Pool) -> DispatchResult { - defensive_assert!( - T::Currency::total_balance(&pool_account.clone().get()).is_zero(), - "dissolving pool should not have any balance" - ); - - // Defensively force set balance to zero. - T::Currency::set_balance(&pool_account.get(), Zero::zero()); - Ok(()) - } - - fn pending_slash(_: Pool) -> Self::Balance { - // for transfer stake strategy, slashing is greedy and never deferred. - Zero::zero() - } - - fn member_slash( - _who: Member, - _pool: Pool, - _amount: Staking::Balance, - _maybe_reporter: Option, - ) -> DispatchResult { - Err(Error::::Defensive(DefensiveError::DelegationUnsupported).into()) - } - - fn migrate_nominator_to_agent( - _pool: Pool, - _reward_account: &Self::AccountId, - ) -> DispatchResult { - Err(Error::::Defensive(DefensiveError::DelegationUnsupported).into()) - } - - fn migrate_delegation( - _pool: Pool, - _delegator: Member, - _value: Self::Balance, - ) -> DispatchResult { - Err(Error::::Defensive(DefensiveError::DelegationUnsupported).into()) - } -} - /// A staking strategy implementation that supports delegation based staking. /// /// In this approach, first the funds are delegated from delegator to the pool account and later diff --git a/substrate/frame/nomination-pools/src/mock.rs b/substrate/frame/nomination-pools/src/mock.rs index cc942039760c..082e66d13ecd 100644 --- a/substrate/frame/nomination-pools/src/mock.rs +++ b/substrate/frame/nomination-pools/src/mock.rs @@ -23,8 +23,8 @@ use frame_support::{ PalletId, }; use frame_system::{EnsureSignedBy, RawOrigin}; -use sp_runtime::{BuildStorage, FixedU128}; -use sp_staking::{OnStakingUpdate, Stake}; +use sp_runtime::{BuildStorage, DispatchResult, FixedU128}; +use sp_staking::{Agent, DelegationInterface, DelegationMigrator, Delegator, OnStakingUpdate, Stake}; pub type BlockNumber = u64; pub type AccountId = u128; @@ -239,6 +239,59 @@ impl sp_staking::StakingInterface for StakingMock { } } +pub struct DelegateMock; +impl DelegationInterface for DelegateMock { + type Balance = Balance; + type AccountId = AccountId; + fn agent_balance(agent: Agent) -> Option { + todo!() + } + + fn agent_transferable_balance(agent: Agent) -> Option { + todo!() + } + + fn delegator_balance(delegator: Delegator) -> Option { + todo!() + } + + fn register_agent(agent: Agent, reward_account: &Self::AccountId) -> DispatchResult { + todo!() + } + + fn remove_agent(agent: Agent) -> DispatchResult { + todo!() + } + + fn delegate(delegator: Delegator, agent: Agent, amount: Self::Balance) -> DispatchResult { + todo!() + } + + fn withdraw_delegation(delegator: Delegator, agent: Agent, amount: Self::Balance, num_slashing_spans: u32) -> DispatchResult { + todo!() + } + + fn pending_slash(agent: Agent) -> Option { + todo!() + } + + fn delegator_slash(agent: Agent, delegator: Delegator, value: Self::Balance, maybe_reporter: Option) -> DispatchResult { + todo!() + } +} + +impl DelegationMigrator for DelegateMock { + type Balance = Balance; + type AccountId = AccountId; + fn migrate_nominator_to_agent(agent: Agent, reward_account: &Self::AccountId) -> DispatchResult { + todo!() + } + + fn migrate_delegation(agent: Agent, delegator: Delegator, value: Self::Balance) -> DispatchResult { + todo!() + } +} + #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Runtime { type Nonce = u64; @@ -295,7 +348,7 @@ impl pools::Config for Runtime { type RewardCounter = RewardCounter; type BalanceToU256 = BalanceToU256; type U256ToBalance = U256ToBalance; - type StakeAdapter = adapter::TransferStake; + type StakeAdapter = adapter::DelegateStake; type PostUnbondingPoolsWindow = PostUnbondingPoolsWindow; type PalletId = PoolsPalletId; type MaxMetadataLen = MaxMetadataLen; From 49e7822580d7fe33aa4c343058d2d41e18619206 Mon Sep 17 00:00:00 2001 From: Ankan Date: Thu, 21 Nov 2024 11:16:13 +0100 Subject: [PATCH 106/142] basic impl of delegator interface --- Cargo.lock | 24 ---- substrate/frame/nomination-pools/src/mock.rs | 109 +++++++++++++++---- 2 files changed, 90 insertions(+), 43 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 330c2563d976..06ceba9704be 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14199,30 +14199,6 @@ dependencies = [ "sp-tracing 16.0.0", ] -[[package]] -name = "pallet-nomination-pools-test-transfer-stake" -version = "1.0.0" -dependencies = [ - "frame-election-provider-support 28.0.0", - "frame-support 28.0.0", - "frame-system 28.0.0", - "log", - "pallet-bags-list 27.0.0", - "pallet-balances 28.0.0", - "pallet-nomination-pools 25.0.0", - "pallet-staking 28.0.0", - "pallet-staking-reward-curve", - "pallet-timestamp 27.0.0", - "parity-scale-codec", - "scale-info", - "sp-core 28.0.0", - "sp-io 30.0.0", - "sp-runtime 31.0.1", - "sp-staking 26.0.0", - "sp-std 14.0.0", - "sp-tracing 16.0.0", -] - [[package]] name = "pallet-offences" version = "27.0.0" diff --git a/substrate/frame/nomination-pools/src/mock.rs b/substrate/frame/nomination-pools/src/mock.rs index 082e66d13ecd..ba1c28df8a83 100644 --- a/substrate/frame/nomination-pools/src/mock.rs +++ b/substrate/frame/nomination-pools/src/mock.rs @@ -24,7 +24,9 @@ use frame_support::{ }; use frame_system::{EnsureSignedBy, RawOrigin}; use sp_runtime::{BuildStorage, DispatchResult, FixedU128}; -use sp_staking::{Agent, DelegationInterface, DelegationMigrator, Delegator, OnStakingUpdate, Stake}; +use sp_staking::{ + Agent, DelegationInterface, DelegationMigrator, Delegator, OnStakingUpdate, Stake, +}; pub type BlockNumber = u64; pub type AccountId = u128; @@ -112,8 +114,8 @@ impl sp_staking::StakingInterface for StakingMock { .ok_or(DispatchError::Other("NotStash")) } - fn is_virtual_staker(_who: &Self::AccountId) -> bool { - false + fn is_virtual_staker(who: &Self::AccountId) -> bool { + BondedBalanceMap::get().contains_key(who) } fn bond_extra(who: &Self::AccountId, extra: Self::Balance) -> DispatchResult { @@ -239,55 +241,124 @@ impl sp_staking::StakingInterface for StakingMock { } } +parameter_types! { + // Map of agent to their (delegated balance, unclaimed withdrawal, pending slash). + pub storage AgentBalanceMap: BTreeMap = Default::default(); + pub storage DelegatorBalanceMap: BTreeMap = Default::default(); +} pub struct DelegateMock; impl DelegationInterface for DelegateMock { type Balance = Balance; type AccountId = AccountId; fn agent_balance(agent: Agent) -> Option { - todo!() + AgentBalanceMap::get() + .get(&agent.get()) + .copied() + .map(|(delegated, _, pending)| delegated - pending) } fn agent_transferable_balance(agent: Agent) -> Option { - todo!() + AgentBalanceMap::get() + .get(&agent.get()) + .copied() + .map(|(_, unclaimed_withdrawals, _)| unclaimed_withdrawals) } fn delegator_balance(delegator: Delegator) -> Option { - todo!() + DelegatorBalanceMap::get().get(&delegator.get()).copied() } - fn register_agent(agent: Agent, reward_account: &Self::AccountId) -> DispatchResult { - todo!() + fn register_agent( + agent: Agent, + reward_account: &Self::AccountId, + ) -> DispatchResult { + AgentBalanceMap::get().insert(agent.get(), (0, 0, 0)); + Ok(()) } fn remove_agent(agent: Agent) -> DispatchResult { - todo!() + AgentBalanceMap::get().remove(&agent.get()); + Ok(()) } - fn delegate(delegator: Delegator, agent: Agent, amount: Self::Balance) -> DispatchResult { - todo!() + fn delegate( + delegator: Delegator, + agent: Agent, + amount: Self::Balance, + ) -> DispatchResult { + let mut delegators = DelegatorBalanceMap::get(); + delegators.get_mut(&delegator.get()).map(|b| *b += amount); + DelegatorBalanceMap::set(&delegators); + + let mut agents = AgentBalanceMap::get(); + agents.get_mut(&agent.get()).map(|(d, _, _)| *d += amount); + AgentBalanceMap::set(&agents); + + Ok(()) } - fn withdraw_delegation(delegator: Delegator, agent: Agent, amount: Self::Balance, num_slashing_spans: u32) -> DispatchResult { - todo!() + fn withdraw_delegation( + delegator: Delegator, + agent: Agent, + amount: Self::Balance, + num_slashing_spans: u32, + ) -> DispatchResult { + let mut delegators = DelegatorBalanceMap::get(); + delegators.get_mut(&delegator.get()).map(|b| *b -= amount); + DelegatorBalanceMap::set(&delegators); + + let mut agents = AgentBalanceMap::get(); + agents.get_mut(&agent.get()).map(|(d, u, _)| { + *d -= amount; + *u -= amount; + }); + AgentBalanceMap::set(&agents); + + Ok(()) } fn pending_slash(agent: Agent) -> Option { - todo!() - } + AgentBalanceMap::get() + .get(&agent.get()) + .copied() + .map(|(_, _, pending_slash)| pending_slash) + } + + fn delegator_slash( + agent: Agent, + delegator: Delegator, + value: Self::Balance, + _maybe_reporter: Option, + ) -> DispatchResult { + let mut delegators = DelegatorBalanceMap::get(); + delegators.get_mut(&delegator.get()).map(|b| *b -= value); + DelegatorBalanceMap::set(&delegators); + + let mut agents = AgentBalanceMap::get(); + agents.get_mut(&agent.get()).map(|(_, _, p)| { + *p -= value; + }); + AgentBalanceMap::set(&agents); - fn delegator_slash(agent: Agent, delegator: Delegator, value: Self::Balance, maybe_reporter: Option) -> DispatchResult { - todo!() + Ok(()) } } impl DelegationMigrator for DelegateMock { type Balance = Balance; type AccountId = AccountId; - fn migrate_nominator_to_agent(agent: Agent, reward_account: &Self::AccountId) -> DispatchResult { + fn migrate_nominator_to_agent( + agent: Agent, + reward_account: &Self::AccountId, + ) -> DispatchResult { todo!() } - fn migrate_delegation(agent: Agent, delegator: Delegator, value: Self::Balance) -> DispatchResult { + fn migrate_delegation( + agent: Agent, + delegator: Delegator, + value: Self::Balance, + ) -> DispatchResult { todo!() } } From 21d82313becfdf9fd58c0cfc9e035de0944e7fc9 Mon Sep 17 00:00:00 2001 From: Ankan Date: Thu, 21 Nov 2024 12:54:33 +0100 Subject: [PATCH 107/142] 107/120 failing --- substrate/frame/nomination-pools/src/lib.rs | 1 + substrate/frame/nomination-pools/src/mock.rs | 24 ++++++++++++++++---- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/substrate/frame/nomination-pools/src/lib.rs b/substrate/frame/nomination-pools/src/lib.rs index 201b0af1d608..4401f816b31e 100644 --- a/substrate/frame/nomination-pools/src/lib.rs +++ b/substrate/frame/nomination-pools/src/lib.rs @@ -2018,6 +2018,7 @@ pub mod pallet { ensure!(!PoolMembers::::contains_key(&who), Error::::AccountBelongsToOtherPool); let mut bonded_pool = BondedPool::::get(pool_id).ok_or(Error::::PoolNotFound)?; + ensure!(bonded_pool.state == PoolState::Open, Error::::NotOpen); bonded_pool.ok_to_join()?; let mut reward_pool = RewardPools::::get(pool_id) diff --git a/substrate/frame/nomination-pools/src/mock.rs b/substrate/frame/nomination-pools/src/mock.rs index ba1c28df8a83..3265013f8c84 100644 --- a/substrate/frame/nomination-pools/src/mock.rs +++ b/substrate/frame/nomination-pools/src/mock.rs @@ -78,6 +78,7 @@ impl StakingMock { let bonded = BondedBalanceMap::get(); let pre_total = bonded.get(&acc).unwrap(); Self::set_bonded_balance(acc, pre_total - amount); + DelegateMock::on_slash(acc, amount); Pools::on_slash(&acc, pre_total - amount, &Default::default(), amount); } } @@ -115,7 +116,7 @@ impl sp_staking::StakingInterface for StakingMock { } fn is_virtual_staker(who: &Self::AccountId) -> bool { - BondedBalanceMap::get().contains_key(who) + true } fn bond_extra(who: &Self::AccountId, extra: Self::Balance) -> DispatchResult { @@ -286,15 +287,22 @@ impl DelegationInterface for DelegateMock { agent: Agent, amount: Self::Balance, ) -> DispatchResult { + let delegator = delegator.get(); let mut delegators = DelegatorBalanceMap::get(); - delegators.get_mut(&delegator.get()).map(|b| *b += amount); + delegators.entry(delegator).and_modify(|b| *b += amount).or_insert(amount); DelegatorBalanceMap::set(&delegators); + let agent = agent.get(); let mut agents = AgentBalanceMap::get(); - agents.get_mut(&agent.get()).map(|(d, _, _)| *d += amount); + agents.get_mut(&agent).map(|(d, _, _)| *d += amount); AgentBalanceMap::set(&agents); - Ok(()) + if BondedBalanceMap::get().contains_key(&agent) { + StakingMock::bond_extra(&agent, amount) + } else { + // reward account does not matter in this context. + StakingMock::bond(&agent, amount, &999) + } } fn withdraw_delegation( @@ -344,6 +352,14 @@ impl DelegationInterface for DelegateMock { } } +impl DelegateMock { + fn on_slash(agent: AccountId, amount: Balance) { + let mut agents = AgentBalanceMap::get(); + agents.get_mut(&agent).map(|(_, _, p)| *p += amount); + AgentBalanceMap::set(&agents); + } +} + impl DelegationMigrator for DelegateMock { type Balance = Balance; type AccountId = AccountId; From 9f734aabebc40b125c35751cffaf1a1fb8a74c0d Mon Sep 17 00:00:00 2001 From: Ankan Date: Sun, 24 Nov 2024 20:34:16 +0100 Subject: [PATCH 108/142] 20 failing --- substrate/frame/nomination-pools/src/mock.rs | 30 +++++++++-- substrate/frame/nomination-pools/src/tests.rs | 50 +++++++++---------- 2 files changed, 52 insertions(+), 28 deletions(-) diff --git a/substrate/frame/nomination-pools/src/mock.rs b/substrate/frame/nomination-pools/src/mock.rs index 3265013f8c84..4647c1f0b488 100644 --- a/substrate/frame/nomination-pools/src/mock.rs +++ b/substrate/frame/nomination-pools/src/mock.rs @@ -165,7 +165,9 @@ impl sp_staking::StakingInterface for StakingMock { staker_map.retain(|(unlocking_at, _amount)| *unlocking_at > current_era); // if there was a withdrawal, notify the pallet. - Pools::on_withdraw(&who, unlocking_before.saturating_sub(unlocking(&staker_map))); + let withdraw_amount = unlocking_before.saturating_sub(unlocking(&staker_map)); + Pools::on_withdraw(&who, withdraw_amount); + DelegateMock::on_withdraw(who, withdraw_amount); UnbondingBalanceMap::set(&unbonding_map); Ok(UnbondingBalanceMap::get().get(&who).unwrap().is_empty() && @@ -273,12 +275,16 @@ impl DelegationInterface for DelegateMock { agent: Agent, reward_account: &Self::AccountId, ) -> DispatchResult { - AgentBalanceMap::get().insert(agent.get(), (0, 0, 0)); + let mut agents = AgentBalanceMap::get(); + agents.insert(agent.get(), (0, 0, 0)); + AgentBalanceMap::set(&agents); Ok(()) } fn remove_agent(agent: Agent) -> DispatchResult { - AgentBalanceMap::get().remove(&agent.get()); + let mut agents = AgentBalanceMap::get(); + agents.remove(&agent.get()); + AgentBalanceMap::set(&agents); Ok(()) } @@ -353,11 +359,24 @@ impl DelegationInterface for DelegateMock { } impl DelegateMock { + pub(crate) fn set_agent_balance(who: AccountId, delegated: Balance) { + let mut agents = AgentBalanceMap::get(); + agents.insert(who, (delegated, 0, 0)); + AgentBalanceMap::set(&agents); + } + fn on_slash(agent: AccountId, amount: Balance) { let mut agents = AgentBalanceMap::get(); agents.get_mut(&agent).map(|(_, _, p)| *p += amount); AgentBalanceMap::set(&agents); } + + fn on_withdraw(agent: AccountId, amount: Balance) { + let mut agents = AgentBalanceMap::get(); + // if agent exists, add the amount to unclaimed withdrawals. + agents.get_mut(&agent).map(|(_, u, _)| *u += amount); + AgentBalanceMap::set(&agents); + } } impl DelegationMigrator for DelegateMock { @@ -673,6 +692,11 @@ pub fn reward_imbalance(pool: PoolId) -> RewardImbalance { } } +pub(crate) fn set_pool_balance(who: AccountId, amount: Balance) { + StakingMock::set_bonded_balance(who, amount); + DelegateMock::set_agent_balance(who, amount); +} + #[cfg(test)] mod test { use super::*; diff --git a/substrate/frame/nomination-pools/src/tests.rs b/substrate/frame/nomination-pools/src/tests.rs index 06261699a5b2..2b7fbff63b7d 100644 --- a/substrate/frame/nomination-pools/src/tests.rs +++ b/substrate/frame/nomination-pools/src/tests.rs @@ -127,41 +127,41 @@ mod bonded_pool { }; // 1 points : 1 balance ratio - StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 100); + set_pool_balance(bonded_pool.bonded_account(), 100); assert_eq!(bonded_pool.balance_to_point(10), 10); assert_eq!(bonded_pool.balance_to_point(0), 0); // 2 points : 1 balance ratio - StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 50); + set_pool_balance(bonded_pool.bonded_account(), 50); assert_eq!(bonded_pool.balance_to_point(10), 20); // 1 points : 2 balance ratio - StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 100); + set_pool_balance(bonded_pool.bonded_account(), 100); bonded_pool.points = 50; assert_eq!(bonded_pool.balance_to_point(10), 5); // 100 points : 0 balance ratio - StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 0); + set_pool_balance(bonded_pool.bonded_account(), 0); bonded_pool.points = 100; assert_eq!(bonded_pool.balance_to_point(10), 100 * 10); // 0 points : 100 balance - StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 100); + set_pool_balance(bonded_pool.bonded_account(), 100); bonded_pool.points = 0; assert_eq!(bonded_pool.balance_to_point(10), 10); // 10 points : 3 balance ratio - StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 30); + set_pool_balance(bonded_pool.bonded_account(), 30); bonded_pool.points = 100; assert_eq!(bonded_pool.balance_to_point(10), 33); // 2 points : 3 balance ratio - StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 300); + set_pool_balance(bonded_pool.bonded_account(), 300); bonded_pool.points = 200; assert_eq!(bonded_pool.balance_to_point(10), 6); // 4 points : 9 balance ratio - StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 900); + set_pool_balance(bonded_pool.bonded_account(), 900); bonded_pool.points = 400; assert_eq!(bonded_pool.balance_to_point(90), 40); }) @@ -182,7 +182,7 @@ mod bonded_pool { }, }; - StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 100); + set_pool_balance(bonded_pool.bonded_account(), 100); assert_eq!(bonded_pool.points_to_balance(10), 10); assert_eq!(bonded_pool.points_to_balance(0), 0); @@ -191,27 +191,27 @@ mod bonded_pool { assert_eq!(bonded_pool.points_to_balance(10), 20); // 100 balance : 0 points ratio - StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 100); + set_pool_balance(bonded_pool.bonded_account(), 100); bonded_pool.points = 0; assert_eq!(bonded_pool.points_to_balance(10), 0); // 0 balance : 100 points ratio - StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 0); + set_pool_balance(bonded_pool.bonded_account(), 0); bonded_pool.points = 100; assert_eq!(bonded_pool.points_to_balance(10), 0); // 10 balance : 3 points ratio - StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 100); + set_pool_balance(bonded_pool.bonded_account(), 100); bonded_pool.points = 30; assert_eq!(bonded_pool.points_to_balance(10), 33); // 2 balance : 3 points ratio - StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 200); + set_pool_balance(bonded_pool.bonded_account(), 200); bonded_pool.points = 300; assert_eq!(bonded_pool.points_to_balance(10), 6); // 4 balance : 9 points ratio - StakingMock::set_bonded_balance(bonded_pool.bonded_account(), 400); + set_pool_balance(bonded_pool.bonded_account(), 400); bonded_pool.points = 900; assert_eq!(bonded_pool.points_to_balance(90), 40); }) @@ -269,27 +269,27 @@ mod bonded_pool { <::MaxPointsToBalance as Get>::get().into(); // Simulate a 100% slashed pool - StakingMock::set_bonded_balance(pool.bonded_account(), 0); + set_pool_balance(pool.bonded_account(), 0); assert_noop!(pool.ok_to_join(), Error::::OverflowRisk); // Simulate a slashed pool at `MaxPointsToBalance` + 1 slashed pool - StakingMock::set_bonded_balance( + set_pool_balance( pool.bonded_account(), max_points_to_balance.saturating_add(1), ); assert_ok!(pool.ok_to_join()); // Simulate a slashed pool at `MaxPointsToBalance` - StakingMock::set_bonded_balance(pool.bonded_account(), max_points_to_balance); + set_pool_balance(pool.bonded_account(), max_points_to_balance); assert_noop!(pool.ok_to_join(), Error::::OverflowRisk); - StakingMock::set_bonded_balance( + set_pool_balance( pool.bonded_account(), Balance::MAX / max_points_to_balance, ); // and a sanity check - StakingMock::set_bonded_balance( + set_pool_balance( pool.bonded_account(), Balance::MAX / max_points_to_balance - 1, ); @@ -310,7 +310,7 @@ mod bonded_pool { state: PoolState::Open, }, }; - StakingMock::set_bonded_balance(bonded_pool.bonded_account(), u128::MAX); + set_pool_balance(bonded_pool.bonded_account(), u128::MAX); // Max out the points and balance of the pool and make sure the conversion works as // expected and does not overflow. @@ -728,7 +728,7 @@ mod join { ); // Force the pools bonded balance to 0, simulating a 100% slash - StakingMock::set_bonded_balance(Pools::generate_bonded_account(1), 0); + set_pool_balance(Pools::generate_bonded_account(1), 0); assert_noop!( Pools::join(RuntimeOrigin::signed(11), 420, 1), Error::::OverflowRisk @@ -754,7 +754,7 @@ mod join { let max_points_to_balance: u128 = <::MaxPointsToBalance as Get>::get().into(); - StakingMock::set_bonded_balance( + set_pool_balance( Pools::generate_bonded_account(123), max_points_to_balance, ); @@ -763,7 +763,7 @@ mod join { Error::::OverflowRisk ); - StakingMock::set_bonded_balance( + set_pool_balance( Pools::generate_bonded_account(123), Balance::MAX / max_points_to_balance, ); @@ -773,7 +773,7 @@ mod join { TokenError::FundsUnavailable, ); - StakingMock::set_bonded_balance( + set_pool_balance( Pools::generate_bonded_account(1), max_points_to_balance, ); @@ -807,7 +807,7 @@ mod join { #[cfg_attr(not(debug_assertions), should_panic)] fn join_panics_when_reward_pool_not_found() { ExtBuilder::default().build_and_execute(|| { - StakingMock::set_bonded_balance(Pools::generate_bonded_account(123), 100); + set_pool_balance(Pools::generate_bonded_account(123), 100); BondedPool:: { id: 123, inner: BondedPoolInner { From 00d772adae956ce7fbde24214e2560e60622cabc Mon Sep 17 00:00:00 2001 From: Ankan Date: Sun, 24 Nov 2024 22:44:26 +0100 Subject: [PATCH 109/142] 18 fail --- substrate/frame/nomination-pools/src/mock.rs | 5 +++ substrate/frame/nomination-pools/src/tests.rs | 40 +++++++------------ 2 files changed, 19 insertions(+), 26 deletions(-) diff --git a/substrate/frame/nomination-pools/src/mock.rs b/substrate/frame/nomination-pools/src/mock.rs index 4647c1f0b488..443e77ea4402 100644 --- a/substrate/frame/nomination-pools/src/mock.rs +++ b/substrate/frame/nomination-pools/src/mock.rs @@ -697,6 +697,11 @@ pub(crate) fn set_pool_balance(who: AccountId, amount: Balance) { DelegateMock::set_agent_balance(who, amount); } +pub fn member_balance(who: AccountId) -> Balance { + ::StakeAdapter::member_delegation_balance(Member::from(who)) + .expect("who must be a pool member") +} + #[cfg(test)] mod test { use super::*; diff --git a/substrate/frame/nomination-pools/src/tests.rs b/substrate/frame/nomination-pools/src/tests.rs index 2b7fbff63b7d..b3bca712afb4 100644 --- a/substrate/frame/nomination-pools/src/tests.rs +++ b/substrate/frame/nomination-pools/src/tests.rs @@ -24,6 +24,7 @@ use sp_runtime::{ traits::{BadOrigin, Dispatchable}, FixedU128, }; +use sp_staking::{DelegationInterface, Delegator}; macro_rules! unbonding_pools_with_era { ($($k:expr => $v:expr),* $(,)?) => {{ @@ -273,26 +274,17 @@ mod bonded_pool { assert_noop!(pool.ok_to_join(), Error::::OverflowRisk); // Simulate a slashed pool at `MaxPointsToBalance` + 1 slashed pool - set_pool_balance( - pool.bonded_account(), - max_points_to_balance.saturating_add(1), - ); + set_pool_balance(pool.bonded_account(), max_points_to_balance.saturating_add(1)); assert_ok!(pool.ok_to_join()); // Simulate a slashed pool at `MaxPointsToBalance` set_pool_balance(pool.bonded_account(), max_points_to_balance); assert_noop!(pool.ok_to_join(), Error::::OverflowRisk); - set_pool_balance( - pool.bonded_account(), - Balance::MAX / max_points_to_balance, - ); + set_pool_balance(pool.bonded_account(), Balance::MAX / max_points_to_balance); // and a sanity check - set_pool_balance( - pool.bonded_account(), - Balance::MAX / max_points_to_balance - 1, - ); + set_pool_balance(pool.bonded_account(), Balance::MAX / max_points_to_balance - 1); assert_ok!(pool.ok_to_join()); }); } @@ -754,10 +746,7 @@ mod join { let max_points_to_balance: u128 = <::MaxPointsToBalance as Get>::get().into(); - set_pool_balance( - Pools::generate_bonded_account(123), - max_points_to_balance, - ); + set_pool_balance(Pools::generate_bonded_account(123), max_points_to_balance); assert_noop!( Pools::join(RuntimeOrigin::signed(11), 420, 123), Error::::OverflowRisk @@ -773,10 +762,7 @@ mod join { TokenError::FundsUnavailable, ); - set_pool_balance( - Pools::generate_bonded_account(1), - max_points_to_balance, - ); + set_pool_balance(Pools::generate_bonded_account(1), max_points_to_balance); // Cannot join a pool that isn't open unsafe_set_state(123, PoolState::Blocked); @@ -5221,13 +5207,15 @@ mod bond_extra { // given assert_eq!(PoolMembers::::get(10).unwrap().points, 10); assert_eq!(BondedPools::::get(1).unwrap().points, 10); - assert_eq!(Currency::free_balance(&10), 35); + // 10 has delegated 10 tokens to the pool. + assert_eq!(member_balance(10), 10); // when assert_ok!(Pools::bond_extra(RuntimeOrigin::signed(10), BondExtra::Rewards)); // then - assert_eq!(Currency::free_balance(&10), 35); + // delegator balance is increased by the claimable reward. + assert_eq!(member_balance(10), 10 + claimable_reward); assert_eq!(PoolMembers::::get(10).unwrap().points, 10 + claimable_reward); assert_eq!(BondedPools::::get(1).unwrap().points, 10 + claimable_reward); @@ -5320,8 +5308,8 @@ mod bond_extra { assert_eq!(PoolMembers::::get(10).unwrap().points, 10); assert_eq!(PoolMembers::::get(20).unwrap().points, 20); assert_eq!(BondedPools::::get(1).unwrap().points, 30); - assert_eq!(Currency::free_balance(&10), 35); - assert_eq!(Currency::free_balance(&20), 20); + assert_eq!(member_balance(10), 10); + assert_eq!(member_balance(20), 20); // Permissioned by default assert_noop!( @@ -5337,7 +5325,7 @@ mod bond_extra { assert_eq!(Currency::free_balance(&default_reward_account()), 7); // then - assert_eq!(Currency::free_balance(&10), 35); + assert_eq!(member_balance(10), 10 + 1); assert_eq!(PoolMembers::::get(10).unwrap().points, 10 + 1); assert_eq!(BondedPools::::get(1).unwrap().points, 30 + 1); @@ -5355,7 +5343,7 @@ mod bond_extra { )); // then - assert_eq!(Currency::free_balance(&20), 12); + assert_eq!(member_balance(20), 20 + 10); assert_eq!(Currency::free_balance(&default_reward_account()), 5); assert_eq!(PoolMembers::::get(20).unwrap().points, 30); assert_eq!(BondedPools::::get(1).unwrap().points, 41); From fb9efa7accd23cd37d81b041e9e4e6a9de3f428d Mon Sep 17 00:00:00 2001 From: Ankan Date: Mon, 25 Nov 2024 01:42:45 +0100 Subject: [PATCH 110/142] all pass --- substrate/frame/nomination-pools/src/mock.rs | 39 ++- substrate/frame/nomination-pools/src/tests.rs | 259 +++++------------- 2 files changed, 95 insertions(+), 203 deletions(-) diff --git a/substrate/frame/nomination-pools/src/mock.rs b/substrate/frame/nomination-pools/src/mock.rs index 443e77ea4402..91100018d7f2 100644 --- a/substrate/frame/nomination-pools/src/mock.rs +++ b/substrate/frame/nomination-pools/src/mock.rs @@ -116,7 +116,7 @@ impl sp_staking::StakingInterface for StakingMock { } fn is_virtual_staker(who: &Self::AccountId) -> bool { - true + AgentBalanceMap::get().contains_key(who) } fn bond_extra(who: &Self::AccountId, extra: Self::Balance) -> DispatchResult { @@ -273,7 +273,7 @@ impl DelegationInterface for DelegateMock { fn register_agent( agent: Agent, - reward_account: &Self::AccountId, + _reward_account: &Self::AccountId, ) -> DispatchResult { let mut agents = AgentBalanceMap::get(); agents.insert(agent.get(), (0, 0, 0)); @@ -315,7 +315,7 @@ impl DelegationInterface for DelegateMock { delegator: Delegator, agent: Agent, amount: Self::Balance, - num_slashing_spans: u32, + _num_slashing_spans: u32, ) -> DispatchResult { let mut delegators = DelegatorBalanceMap::get(); delegators.get_mut(&delegator.get()).map(|b| *b -= amount); @@ -350,7 +350,7 @@ impl DelegationInterface for DelegateMock { let mut agents = AgentBalanceMap::get(); agents.get_mut(&agent.get()).map(|(_, _, p)| { - *p -= value; + p.saturating_reduce(value); }); AgentBalanceMap::set(&agents); @@ -359,13 +359,19 @@ impl DelegationInterface for DelegateMock { } impl DelegateMock { - pub(crate) fn set_agent_balance(who: AccountId, delegated: Balance) { + pub fn set_agent_balance(who: AccountId, delegated: Balance) { let mut agents = AgentBalanceMap::get(); agents.insert(who, (delegated, 0, 0)); AgentBalanceMap::set(&agents); } - fn on_slash(agent: AccountId, amount: Balance) { + pub fn set_delegator_balance(who: AccountId, amount: Balance) { + let mut delegators = DelegatorBalanceMap::get(); + delegators.insert(who, amount); + DelegatorBalanceMap::set(&delegators); + } + + pub fn on_slash(agent: AccountId, amount: Balance) { let mut agents = AgentBalanceMap::get(); agents.get_mut(&agent).map(|(_, _, p)| *p += amount); AgentBalanceMap::set(&agents); @@ -383,18 +389,18 @@ impl DelegationMigrator for DelegateMock { type Balance = Balance; type AccountId = AccountId; fn migrate_nominator_to_agent( - agent: Agent, - reward_account: &Self::AccountId, + _agent: Agent, + _reward_account: &Self::AccountId, ) -> DispatchResult { - todo!() + unimplemented!("not used in current unit tests") } fn migrate_delegation( - agent: Agent, - delegator: Delegator, - value: Self::Balance, + _agent: Agent, + _delegator: Delegator, + _value: Self::Balance, ) -> DispatchResult { - todo!() + unimplemented!("not used in current unit tests") } } @@ -697,11 +703,16 @@ pub(crate) fn set_pool_balance(who: AccountId, amount: Balance) { DelegateMock::set_agent_balance(who, amount); } -pub fn member_balance(who: AccountId) -> Balance { +pub fn member_delegation(who: AccountId) -> Balance { ::StakeAdapter::member_delegation_balance(Member::from(who)) .expect("who must be a pool member") } +pub fn pool_balance(id: PoolId) -> Balance { + ::StakeAdapter::total_balance(Pool::from(Pools::generate_bonded_account(id))) + .expect("who must be a bonded pool account") +} + #[cfg(test)] mod test { use super::*; diff --git a/substrate/frame/nomination-pools/src/tests.rs b/substrate/frame/nomination-pools/src/tests.rs index b3bca712afb4..b8d8b3ed1e0f 100644 --- a/substrate/frame/nomination-pools/src/tests.rs +++ b/substrate/frame/nomination-pools/src/tests.rs @@ -24,7 +24,7 @@ use sp_runtime::{ traits::{BadOrigin, Dispatchable}, FixedU128, }; -use sp_staking::{DelegationInterface, Delegator}; +use sp_staking::{Agent, DelegationInterface}; macro_rules! unbonding_pools_with_era { ($($k:expr => $v:expr),* $(,)?) => {{ @@ -632,8 +632,6 @@ mod sub_pools { } mod join { - use sp_runtime::TokenError; - use super::*; #[test] @@ -752,16 +750,6 @@ mod join { Error::::OverflowRisk ); - set_pool_balance( - Pools::generate_bonded_account(123), - Balance::MAX / max_points_to_balance, - ); - // Balance needs to be gt Balance::MAX / `MaxPointsToBalance` - assert_noop!( - Pools::join(RuntimeOrigin::signed(11), 5, 123), - TokenError::FundsUnavailable, - ); - set_pool_balance(Pools::generate_bonded_account(1), max_points_to_balance); // Cannot join a pool that isn't open @@ -2307,8 +2295,8 @@ mod claim_payout { fn rewards_are_rounded_down_depositor_collects_them() { ExtBuilder::default().add_members(vec![(20, 20)]).build_and_execute(|| { // initial balance of 10. - - assert_eq!(Currency::free_balance(&10), 35); + let init_balance_10 = Currency::free_balance(&10); + assert_eq!(member_delegation(10), 10); assert_eq!( Currency::free_balance(&default_reward_account()), Currency::minimum_balance() @@ -2359,8 +2347,10 @@ mod claim_payout { ); assert!(!Metadata::::contains_key(1)); - // original ed + ed put into reward account + reward + bond + dust. - assert_eq!(Currency::free_balance(&10), 35 + 5 + 13 + 10 + 1); + // original ed + ed put into reward account + reward + dust. + assert_eq!(Currency::free_balance(&10), init_balance_10 + 5 + 13 + 1); + // delegation reduced from 10 to 0. + assert_eq!(member_delegation(10), 0); }) } @@ -2430,9 +2420,10 @@ mod claim_payout { let claimable_reward = 8 - ExistentialDeposit::get(); // NOTE: easier to read if we use 3, so let's use the number instead of variable. assert_eq!(claimable_reward, 3, "test is correct if rewards are divisible by 3"); + let init_balance = Currency::free_balance(&10); // given - assert_eq!(Currency::free_balance(&10), 35); + assert_eq!(member_delegation(10), 10); // when @@ -2441,7 +2432,10 @@ mod claim_payout { assert_ok!(Pools::claim_payout_other(RuntimeOrigin::signed(80), 10)); // then - assert_eq!(Currency::free_balance(&10), 36); + // delegated balance does not change. + assert_eq!(member_delegation(10), 10); + // reward of 1 is paid out to 10. + assert_eq!(Currency::free_balance(&10), init_balance + 1); assert_eq!(Currency::free_balance(&default_reward_account()), 7); }) } @@ -2804,6 +2798,8 @@ mod unbond { ExtBuilder::default() .add_members(vec![(40, 40), (550, 550)]) .build_and_execute(|| { + let init_balance_40 = Currency::free_balance(&40); + let init_balance_550 = Currency::free_balance(&550); let ed = Currency::minimum_balance(); // Given a slash from 600 -> 500 StakingMock::slash_by(1, 500); @@ -2850,7 +2846,9 @@ mod unbond { PoolMembers::::get(40).unwrap().unbonding_eras, member_unbonding_eras!(3 => 6) ); - assert_eq!(Currency::free_balance(&40), 40 + 40); // We claim rewards when unbonding + assert_eq!(member_delegation(40), 40); + // We claim rewards when unbonding + assert_eq!(Currency::free_balance(&40), init_balance_40 + 40); // When unsafe_set_state(1, PoolState::Destroying); @@ -2879,7 +2877,8 @@ mod unbond { PoolMembers::::get(550).unwrap().unbonding_eras, member_unbonding_eras!(3 => 92) ); - assert_eq!(Currency::free_balance(&550), 550 + 550); + assert_eq!(member_delegation(550), 550); + assert_eq!(Currency::free_balance(&550), init_balance_550 + 550); assert_eq!( pool_events_since_last_call(), vec![ @@ -2920,7 +2919,8 @@ mod unbond { ); assert_eq!(StakingMock::active_stake(&default_bonded_account()).unwrap(), 0); - assert_eq!(Currency::free_balance(&550), 550 + 550 + 92); + // 550 is removed from pool. + assert_eq!(member_delegation(550), 0); assert_eq!( pool_events_since_last_call(), vec![ @@ -3518,7 +3518,7 @@ mod pool_withdraw_unbonded { assert_eq!(StakingMock::active_stake(&default_bonded_account()), Ok(15)); assert_eq!(StakingMock::total_stake(&default_bonded_account()), Ok(20)); - assert_eq!(Balances::free_balance(&default_bonded_account()), 20); + assert_eq!(pool_balance(1), 20); // When CurrentEra::set(StakingMock::current_era() + StakingMock::bonding_duration() + 1); @@ -3527,7 +3527,7 @@ mod pool_withdraw_unbonded { // Then their unbonding balance is no longer locked assert_eq!(StakingMock::active_stake(&default_bonded_account()), Ok(15)); assert_eq!(StakingMock::total_stake(&default_bonded_account()), Ok(15)); - assert_eq!(Balances::free_balance(&default_bonded_account()), 20); + assert_eq!(pool_balance(1), 20); }); } #[test] @@ -3538,7 +3538,7 @@ mod pool_withdraw_unbonded { assert_eq!(StakingMock::active_stake(&default_bonded_account()), Ok(15)); assert_eq!(StakingMock::total_stake(&default_bonded_account()), Ok(20)); - assert_eq!(Balances::free_balance(&default_bonded_account()), 20); + assert_eq!(pool_balance(1), 20); assert_eq!(TotalValueLocked::::get(), 20); // When @@ -3554,14 +3554,14 @@ mod pool_withdraw_unbonded { // Then their unbonding balance is no longer locked assert_eq!(StakingMock::active_stake(&default_bonded_account()), Ok(15)); assert_eq!(StakingMock::total_stake(&default_bonded_account()), Ok(15)); - assert_eq!(Currency::free_balance(&default_bonded_account()), 20); + assert_eq!(pool_balance(1), 20); // The difference between TVL and member_balance is exactly the difference between - // `total_stake` and the `free_balance`. - // This relation is not guaranteed in the wild as arbitrary transfers towards - // `free_balance` can be made to the pool that are not accounted for. - let non_locked_balance = Balances::free_balance(&default_bonded_account()) - - StakingMock::total_stake(&default_bonded_account()).unwrap(); + // `pool balance` (sum of all balance delegated to pool) and the `staked balance`. + // This is the withdrawn funds from the pool stake that has not yet been claimed by the + // respective members. + let non_locked_balance = + pool_balance(1) - StakingMock::total_stake(&default_bonded_account()).unwrap(); assert_eq!(member_balance, TotalValueLocked::::get() + non_locked_balance); }); } @@ -3583,7 +3583,7 @@ mod withdraw_unbonded { assert_eq!(StakingMock::bonding_duration(), 3); assert_ok!(Pools::fully_unbond(RuntimeOrigin::signed(550), 550)); assert_ok!(Pools::fully_unbond(RuntimeOrigin::signed(40), 40)); - assert_eq!(Currency::free_balance(&default_bonded_account()), 600); + assert_eq!(pool_balance(1), 600); let mut current_era = 1; CurrentEra::set(current_era); @@ -3612,10 +3612,7 @@ mod withdraw_unbonded { .1 /= 2; UnbondingBalanceMap::set(&x); - Currency::set_balance( - &default_bonded_account(), - Currency::free_balance(&default_bonded_account()) / 2, // 300 - ); + set_pool_balance(1, pool_balance(1) / 2); assert_eq!(StakingMock::active_stake(&default_bonded_account()).unwrap(), 10); StakingMock::slash_by(1, 5); assert_eq!(StakingMock::active_stake(&default_bonded_account()).unwrap(), 5); @@ -3657,11 +3654,6 @@ mod withdraw_unbonded { Event::PoolSlashed { pool_id: 1, balance: 5 } ] ); - assert_eq!( - balances_events_since_last_call(), - vec![BEvent::Burned { who: default_bonded_account(), amount: 300 }] - ); - // When assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(550), 550, 0)); @@ -3677,10 +3669,9 @@ mod withdraw_unbonded { Event::MemberRemoved { pool_id: 1, member: 550, released_balance: 0 } ] ); - assert_eq!( - balances_events_since_last_call(), - vec![BEvent::Transfer { from: default_bonded_account(), to: 550, amount: 275 }] - ); + + // member has 40 tokens in delegation, but only 20 can be withdrawan. + assert_eq!(member_delegation(40), 40); // When assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(40), 40, 0)); @@ -3694,18 +3685,18 @@ mod withdraw_unbonded { assert_eq!( pool_events_since_last_call(), vec![ + // out of 40, 20 is withdrawn. Event::Withdrawn { member: 40, pool_id: 1, balance: 20, points: 40 }, - Event::MemberRemoved { pool_id: 1, member: 40, released_balance: 0 } + // member is removed and the dangling delegation of 20 tokens left in their + // account is released. + Event::MemberRemoved { pool_id: 1, member: 40, released_balance: 20 } ] ); - assert_eq!( - balances_events_since_last_call(), - vec![BEvent::Transfer { from: default_bonded_account(), to: 40, amount: 20 }] - ); // now, finally, the depositor can take out its share. unsafe_set_state(1, PoolState::Destroying); assert_ok!(fully_unbond_permissioned(10)); + assert_eq!(member_delegation(10), 10); current_era += 3; CurrentEra::set(current_era); @@ -3717,7 +3708,9 @@ mod withdraw_unbonded { vec![ Event::Unbonded { member: 10, pool_id: 1, balance: 5, points: 5, era: 9 }, Event::Withdrawn { member: 10, pool_id: 1, balance: 5, points: 5 }, - Event::MemberRemoved { pool_id: 1, member: 10, released_balance: 0 }, + // when member is removed, any leftover delegation is released. + Event::MemberRemoved { pool_id: 1, member: 10, released_balance: 5 }, + // when the last member leaves, the pool is destroyed. Event::Destroyed { pool_id: 1 } ] ); @@ -3725,7 +3718,6 @@ mod withdraw_unbonded { assert_eq!( balances_events_since_last_call(), vec![ - BEvent::Transfer { from: default_bonded_account(), to: 10, amount: 5 }, BEvent::Thawed { who: default_reward_account(), amount: 5 }, BEvent::Transfer { from: default_reward_account(), to: 10, amount: 5 } ] @@ -3739,11 +3731,9 @@ mod withdraw_unbonded { .add_members(vec![(40, 40), (550, 550)]) .build_and_execute(|| { let _ = balances_events_since_last_call(); - // Given // current bond is 600, we slash it all to 300. StakingMock::slash_by(1, 300); - Currency::set_balance(&default_bonded_account(), 300); assert_eq!(StakingMock::total_stake(&default_bonded_account()), Ok(300)); assert_ok!(fully_unbond_permissioned(40)); @@ -3773,10 +3763,6 @@ mod withdraw_unbonded { } ] ); - assert_eq!( - balances_events_since_last_call(), - vec![BEvent::Burned { who: default_bonded_account(), amount: 300 },] - ); CurrentEra::set(StakingMock::bonding_duration()); @@ -3784,10 +3770,6 @@ mod withdraw_unbonded { assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(40), 40, 0)); // Then - assert_eq!( - balances_events_since_last_call(), - vec![BEvent::Transfer { from: default_bonded_account(), to: 40, amount: 20 },] - ); assert_eq!( pool_events_since_last_call(), vec![ @@ -3805,10 +3787,6 @@ mod withdraw_unbonded { assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(550), 550, 0)); // Then - assert_eq!( - balances_events_since_last_call(), - vec![BEvent::Transfer { from: default_bonded_account(), to: 550, amount: 275 },] - ); assert_eq!( pool_events_since_last_call(), vec![ @@ -3838,9 +3816,8 @@ mod withdraw_unbonded { assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(10), 10, 0)); // then - assert_eq!(Currency::free_balance(&10), 10 + 35); - assert_eq!(Currency::free_balance(&default_bonded_account()), 0); - + assert_eq!(DelegateMock::agent_balance(Agent::from(default_bonded_account())), None); + assert_eq!(StakingMock::stake(&default_bonded_account()).unwrap().total, 0); // in this test 10 also gets a fair share of the slash, because the slash was // applied to the bonded account. assert_eq!( @@ -3856,7 +3833,6 @@ mod withdraw_unbonded { assert_eq!( balances_events_since_last_call(), vec![ - BEvent::Transfer { from: default_bonded_account(), to: 10, amount: 5 }, BEvent::Thawed { who: default_reward_account(), amount: 5 }, BEvent::Transfer { from: default_reward_account(), to: 10, amount: 5 } ] @@ -3864,35 +3840,6 @@ mod withdraw_unbonded { }); } - #[test] - fn withdraw_unbonded_handles_faulty_sub_pool_accounting() { - ExtBuilder::default().build_and_execute(|| { - // Given - assert_eq!(Currency::minimum_balance(), 5); - assert_eq!(Currency::free_balance(&10), 35); - assert_eq!(Currency::free_balance(&default_bonded_account()), 10); - unsafe_set_state(1, PoolState::Destroying); - assert_ok!(Pools::fully_unbond(RuntimeOrigin::signed(10), 10)); - - // Simulate a slash that is not accounted for in the sub pools. - Currency::set_balance(&default_bonded_account(), 5); - assert_eq!( - SubPoolsStorage::::get(1).unwrap().with_era, - //------------------------------balance decrease is not account for - unbonding_pools_with_era! { 3 => UnbondPool { points: 10, balance: 10 } } - ); - - CurrentEra::set(3); - - // When - assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(10), 10, 0)); - - // Then - assert_eq!(Currency::free_balance(&10), 10 + 35); - assert_eq!(Currency::free_balance(&default_bonded_account()), 0); - }); - } - #[test] fn withdraw_unbonded_errors_correctly() { ExtBuilder::default().with_check(0).build_and_execute(|| { @@ -3911,6 +3858,10 @@ mod withdraw_unbonded { let mut member = PoolMember { pool_id: 1, points: 10, ..Default::default() }; PoolMembers::::insert(11, member.clone()); + // set agent and delegator balance + DelegateMock::set_agent_balance(Pools::generate_bonded_account(1), 10); + DelegateMock::set_delegator_balance(11, 10); + // Simulate calling `unbond` member.unbonding_eras = member_unbonding_eras!(3 => 10); PoolMembers::::insert(11, member.clone()); @@ -4031,7 +3982,7 @@ mod withdraw_unbonded { } ); CurrentEra::set(StakingMock::bonding_duration()); - assert_eq!(Currency::free_balance(&100), 100); + assert_eq!(member_delegation(100), 100); // Cannot permissionlessly withdraw assert_noop!( @@ -4047,6 +3998,7 @@ mod withdraw_unbonded { assert_eq!(SubPoolsStorage::::get(1).unwrap(), Default::default(),); assert_eq!(Currency::free_balance(&100), 100 + 100); + assert_eq!(member_delegation(100), 0); assert!(!PoolMembers::::contains_key(100)); assert_eq!( pool_events_since_last_call(), @@ -4648,10 +4600,6 @@ mod withdraw_unbonded { // move to era when unbonded funds can be withdrawn. CurrentEra::set(4); - - // increment consumer by 1 reproducing the erroneous consumer bug. - // refer https://github.com/paritytech/polkadot-sdk/issues/4440. - assert_ok!(frame_system::Pallet::::inc_consumers(&pool_one)); assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(10), 10, 0)); assert_eq!( @@ -4698,7 +4646,7 @@ mod create { )); assert_eq!(TotalValueLocked::::get(), 10 + StakingMock::minimum_nominator_bond()); - assert_eq!(Currency::free_balance(&11), 0); + assert_eq!(member_delegation(11), StakingMock::minimum_nominator_bond()); assert_eq!( PoolMembers::::get(11).unwrap(), PoolMember { @@ -4837,7 +4785,7 @@ mod create { 789 )); - assert_eq!(Currency::free_balance(&11), 0); + assert_eq!(member_delegation(11), StakingMock::minimum_nominator_bond()); // delete the initial pool created, then pool_Id `1` will be free assert_noop!( @@ -5000,16 +4948,9 @@ mod set_state { // surpassed. Making this pool destroyable by anyone. StakingMock::slash_by(1, 10); - // in mock we are using transfer stake which implies slash is greedy. Extrinsic to - // apply pending slash should fail. - assert_noop!( - Pools::apply_slash(RuntimeOrigin::signed(11), 10), - Error::::NotSupported - ); - - // pending slash api should return zero as well. - assert_eq!(Pools::api_pool_pending_slash(1), 0); - assert_eq!(Pools::api_member_pending_slash(10), 0); + // pending slash is correct. + assert_eq!(Pools::api_pool_pending_slash(1), 10); + assert_eq!(Pools::api_member_pending_slash(10), 10); // When assert_ok!(Pools::set_state(RuntimeOrigin::signed(11), 1, PoolState::Destroying)); @@ -5161,13 +5102,13 @@ mod bond_extra { // given assert_eq!(PoolMembers::::get(10).unwrap().points, 10); assert_eq!(BondedPools::::get(1).unwrap().points, 10); - assert_eq!(Currency::free_balance(&10), 100); + assert_eq!(member_delegation(10), 10); // when assert_ok!(Pools::bond_extra(RuntimeOrigin::signed(10), BondExtra::FreeBalance(10))); // then - assert_eq!(Currency::free_balance(&10), 90); + assert_eq!(member_delegation(10), 10 + 10); assert_eq!(PoolMembers::::get(10).unwrap().points, 20); assert_eq!(BondedPools::::get(1).unwrap().points, 20); @@ -5184,7 +5125,7 @@ mod bond_extra { assert_ok!(Pools::bond_extra(RuntimeOrigin::signed(10), BondExtra::FreeBalance(20))); // then - assert_eq!(Currency::free_balance(&10), 70); + assert_eq!(member_delegation(10), 20 + 20); assert_eq!(PoolMembers::::get(10).unwrap().points, 40); assert_eq!(BondedPools::::get(1).unwrap().points, 40); @@ -5208,14 +5149,14 @@ mod bond_extra { assert_eq!(PoolMembers::::get(10).unwrap().points, 10); assert_eq!(BondedPools::::get(1).unwrap().points, 10); // 10 has delegated 10 tokens to the pool. - assert_eq!(member_balance(10), 10); + assert_eq!(member_delegation(10), 10); // when assert_ok!(Pools::bond_extra(RuntimeOrigin::signed(10), BondExtra::Rewards)); // then // delegator balance is increased by the claimable reward. - assert_eq!(member_balance(10), 10 + claimable_reward); + assert_eq!(member_delegation(10), 10 + claimable_reward); assert_eq!(PoolMembers::::get(10).unwrap().points, 10 + claimable_reward); assert_eq!(BondedPools::::get(1).unwrap().points, 10 + claimable_reward); @@ -5252,8 +5193,8 @@ mod bond_extra { assert_eq!(PoolMembers::::get(20).unwrap().points, 20); assert_eq!(BondedPools::::get(1).unwrap().points, 30); - assert_eq!(Currency::free_balance(&10), 35); - assert_eq!(Currency::free_balance(&20), 20); + assert_eq!(member_delegation(10), 10); + assert_eq!(member_delegation(20), 20); assert_eq!(TotalValueLocked::::get(), 30); // when @@ -5261,7 +5202,7 @@ mod bond_extra { assert_eq!(Currency::free_balance(&default_reward_account()), 7); // then - assert_eq!(Currency::free_balance(&10), 35); + assert_eq!(member_delegation(10), 10 + 1); assert_eq!(TotalValueLocked::::get(), 31); // 10's share of the reward is 1/3, since they gave 10/30 of the total shares. @@ -5272,11 +5213,11 @@ mod bond_extra { assert_ok!(Pools::bond_extra(RuntimeOrigin::signed(20), BondExtra::Rewards)); // then - assert_eq!(Currency::free_balance(&20), 20); assert_eq!(TotalValueLocked::::get(), 33); // 20's share of the rewards is the other 2/3 of the rewards, since they have 20/30 of // the shares + assert_eq!(member_delegation(20), 20 + 2); assert_eq!(PoolMembers::::get(20).unwrap().points, 20 + 2); assert_eq!(BondedPools::::get(1).unwrap().points, 30 + 3); @@ -5308,8 +5249,8 @@ mod bond_extra { assert_eq!(PoolMembers::::get(10).unwrap().points, 10); assert_eq!(PoolMembers::::get(20).unwrap().points, 20); assert_eq!(BondedPools::::get(1).unwrap().points, 30); - assert_eq!(member_balance(10), 10); - assert_eq!(member_balance(20), 20); + assert_eq!(member_delegation(10), 10); + assert_eq!(member_delegation(20), 20); // Permissioned by default assert_noop!( @@ -5325,7 +5266,7 @@ mod bond_extra { assert_eq!(Currency::free_balance(&default_reward_account()), 7); // then - assert_eq!(member_balance(10), 10 + 1); + assert_eq!(member_delegation(10), 10 + 1); assert_eq!(PoolMembers::::get(10).unwrap().points, 10 + 1); assert_eq!(BondedPools::::get(1).unwrap().points, 30 + 1); @@ -5343,7 +5284,7 @@ mod bond_extra { )); // then - assert_eq!(member_balance(20), 20 + 10); + assert_eq!(member_delegation(20), 20 + 10); assert_eq!(Currency::free_balance(&default_reward_account()), 5); assert_eq!(PoolMembers::::get(20).unwrap().points, 30); assert_eq!(BondedPools::::get(1).unwrap().points, 41); @@ -7475,63 +7416,3 @@ mod chill { }) } } - -// the test mock is using `TransferStake` and so `DelegateStake` is not tested here. Extrinsics -// meant for `DelegateStake` should be gated. -// -// `DelegateStake` tests are in `pallet-nomination-pools-test-delegate-stake`. Since we support both -// strategies currently, we keep these tests as it is but in future we may remove `TransferStake` -// completely. -mod delegate_stake { - use super::*; - #[test] - fn delegation_specific_calls_are_gated() { - ExtBuilder::default().with_check(0).build_and_execute(|| { - // Given - Currency::set_balance(&11, ExistentialDeposit::get() + 2); - assert!(!PoolMembers::::contains_key(11)); - - // When - assert_ok!(Pools::join(RuntimeOrigin::signed(11), 2, 1)); - - // Then - assert_eq!( - pool_events_since_last_call(), - vec![ - Event::Created { depositor: 10, pool_id: 1 }, - Event::Bonded { member: 10, pool_id: 1, bonded: 10, joined: true }, - Event::Bonded { member: 11, pool_id: 1, bonded: 2, joined: true }, - ] - ); - - assert_eq!( - PoolMembers::::get(11).unwrap(), - PoolMember:: { pool_id: 1, points: 2, ..Default::default() } - ); - - // ensure pool 1 cannot be migrated. - assert!(!Pools::api_pool_needs_delegate_migration(1)); - assert_noop!( - Pools::migrate_pool_to_delegate_stake(RuntimeOrigin::signed(10), 1), - Error::::NotSupported - ); - - // members cannot be migrated either. - assert!(!Pools::api_member_needs_delegate_migration(10)); - assert_noop!( - Pools::migrate_delegation(RuntimeOrigin::signed(10), 11), - Error::::NotSupported - ); - - // Given - // The bonded balance is slashed in half - StakingMock::slash_by(1, 6); - - // since slash is greedy with `TransferStake`, `apply_slash` should not work either. - assert_noop!( - Pools::apply_slash(RuntimeOrigin::signed(10), 11), - Error::::NotSupported - ); - }); - } -} From 4498648487ed7189fd692e3ef362a089b3388169 Mon Sep 17 00:00:00 2001 From: Ankan Date: Mon, 25 Nov 2024 01:42:59 +0100 Subject: [PATCH 111/142] fmt --- substrate/frame/nomination-pools/src/tests.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/substrate/frame/nomination-pools/src/tests.rs b/substrate/frame/nomination-pools/src/tests.rs index b8d8b3ed1e0f..c46638d2f8f7 100644 --- a/substrate/frame/nomination-pools/src/tests.rs +++ b/substrate/frame/nomination-pools/src/tests.rs @@ -3816,7 +3816,10 @@ mod withdraw_unbonded { assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(10), 10, 0)); // then - assert_eq!(DelegateMock::agent_balance(Agent::from(default_bonded_account())), None); + assert_eq!( + DelegateMock::agent_balance(Agent::from(default_bonded_account())), + None + ); assert_eq!(StakingMock::stake(&default_bonded_account()).unwrap().total, 0); // in this test 10 also gets a fair share of the slash, because the slash was // applied to the bonded account. From 7bdb6279a428c23a50f1aab9850a7fee87bb560e Mon Sep 17 00:00:00 2001 From: Ankan Date: Mon, 25 Nov 2024 02:11:01 +0100 Subject: [PATCH 112/142] fix compile --- substrate/frame/nomination-pools/src/mock.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/nomination-pools/src/mock.rs b/substrate/frame/nomination-pools/src/mock.rs index 91100018d7f2..75e4fe19a953 100644 --- a/substrate/frame/nomination-pools/src/mock.rs +++ b/substrate/frame/nomination-pools/src/mock.rs @@ -698,7 +698,7 @@ pub fn reward_imbalance(pool: PoolId) -> RewardImbalance { } } -pub(crate) fn set_pool_balance(who: AccountId, amount: Balance) { +pub fn set_pool_balance(who: AccountId, amount: Balance) { StakingMock::set_bonded_balance(who, amount); DelegateMock::set_agent_balance(who, amount); } From 9ba8f25ffb5180c1f769c24aa5246bcaaa5a85eb Mon Sep 17 00:00:00 2001 From: Ankan Date: Mon, 25 Nov 2024 03:50:57 +0100 Subject: [PATCH 113/142] fails e2e test --- Cargo.lock | 1 + substrate/bin/node/runtime/src/lib.rs | 22 +- .../test-staking-e2e/Cargo.toml | 2 + .../test-staking-e2e/src/mock.rs | 26 +- .../nomination-pools/runtime-api/src/lib.rs | 3 +- .../frame/nomination-pools/src/adapter.rs | 3 +- .../test-transfer-stake/src/lib.rs | 912 ------------------ 7 files changed, 46 insertions(+), 923 deletions(-) delete mode 100644 substrate/frame/nomination-pools/test-transfer-stake/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 95f8ab259f1d..2fde8a614fd5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13098,6 +13098,7 @@ dependencies = [ "log", "pallet-bags-list 27.0.0", "pallet-balances 28.0.0", + "pallet-delegated-staking 1.0.0", "pallet-election-provider-multi-phase 27.0.0", "pallet-nomination-pools 25.0.0", "pallet-session 28.0.0", diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index bff263548087..274b61a0c58b 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -741,7 +741,7 @@ impl pallet_staking::Config for Runtime { type MaxUnlockingChunks = ConstU32<32>; type MaxControllersInDeprecationBatch = MaxControllersInDeprecationBatch; type HistoryDepth = HistoryDepth; - type EventListeners = NominationPools; + type EventListeners = (NominationPools, DelegatedStaking); type WeightInfo = pallet_staking::weights::SubstrateWeight; type BenchmarkingConfig = StakingBenchmarkingConfig; type DisablingStrategy = pallet_staking::UpToLimitWithReEnablingDisablingStrategy; @@ -925,6 +925,21 @@ impl pallet_bags_list::Config for Runtime { type WeightInfo = pallet_bags_list::weights::SubstrateWeight; } +parameter_types! { + pub const DelegatedStakingPalletId: PalletId = PalletId(*b"py/dlstk"); + pub const SlashRewardFraction: Perbill = Perbill::from_percent(1); +} + +impl pallet_delegated_staking::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type PalletId = DelegatedStakingPalletId; + type Currency = Balances; + type OnSlash = (); + type SlashRewardFraction = SlashRewardFraction; + type RuntimeHoldReason = RuntimeHoldReason; + type CoreStaking = Staking; +} + parameter_types! { pub const PostUnbondPoolsWindow: u32 = 4; pub const NominationPoolsPalletId: PalletId = PalletId(*b"py/nopls"); @@ -953,7 +968,7 @@ impl pallet_nomination_pools::Config for Runtime { type RewardCounter = FixedU128; type BalanceToU256 = BalanceToU256; type U256ToBalance = U256ToBalance; - type StakeAdapter = pallet_nomination_pools::adapter::TransferStake; + type StakeAdapter = pallet_nomination_pools::adapter::DelegateStake; type PostUnbondingPoolsWindow = PostUnbondPoolsWindow; type MaxMetadataLen = ConstU32<256>; type MaxUnbonding = ConstU32<8>; @@ -2633,6 +2648,9 @@ mod runtime { #[runtime::pallet_index(81)] pub type VerifySignature = pallet_verify_signature::Pallet; + + #[runtime::pallet_index(82)] + pub type DelegatedStaking = pallet_delegated_staking::Pallet; } impl TryFrom for pallet_revive::Call { diff --git a/substrate/frame/election-provider-multi-phase/test-staking-e2e/Cargo.toml b/substrate/frame/election-provider-multi-phase/test-staking-e2e/Cargo.toml index 771376e06656..1cea41c39473 100644 --- a/substrate/frame/election-provider-multi-phase/test-staking-e2e/Cargo.toml +++ b/substrate/frame/election-provider-multi-phase/test-staking-e2e/Cargo.toml @@ -33,6 +33,7 @@ frame-system = { workspace = true, default-features = true } frame-support = { workspace = true, default-features = true } frame-election-provider-support = { workspace = true, default-features = true } +pallet-delegated-staking = { workspace = true, default-features = true } pallet-election-provider-multi-phase = { workspace = true, default-features = true } pallet-staking = { workspace = true, default-features = true } pallet-nomination-pools = { workspace = true, default-features = true } @@ -48,6 +49,7 @@ try-runtime = [ "frame-system/try-runtime", "pallet-bags-list/try-runtime", "pallet-balances/try-runtime", + "pallet-delegated-staking/try-runtime", "pallet-election-provider-multi-phase/try-runtime", "pallet-nomination-pools/try-runtime", "pallet-session/try-runtime", diff --git a/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs b/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs index eaab848c1694..96f71f7b78db 100644 --- a/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs +++ b/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs @@ -20,7 +20,7 @@ use frame_support::{ assert_ok, parameter_types, traits, traits::{Hooks, UnfilteredDispatchable, VariantCountOf}, - weights::constants, + weights::constants, PalletId }; use frame_system::EnsureRoot; use sp_core::{ConstU32, Get}; @@ -68,6 +68,7 @@ frame_support::construct_runtime!( System: frame_system, ElectionProviderMultiPhase: pallet_election_provider_multi_phase, Staking: pallet_staking, + DelegatedStaking: pallet_delegated_staking, Pools: pallet_nomination_pools, Balances: pallet_balances, BagsList: pallet_bags_list, @@ -77,7 +78,7 @@ frame_support::construct_runtime!( } ); -pub(crate) type AccountId = u64; +pub(crate) type AccountId = u128; pub(crate) type AccountIndex = u32; pub(crate) type BlockNumber = u32; pub(crate) type Balance = u64; @@ -265,7 +266,7 @@ impl pallet_nomination_pools::Config for Runtime { type RewardCounter = sp_runtime::FixedU128; type BalanceToU256 = BalanceToU256; type U256ToBalance = U256ToBalance; - type StakeAdapter = pallet_nomination_pools::adapter::TransferStake; + type StakeAdapter = pallet_nomination_pools::adapter::DelegateStake; type PostUnbondingPoolsWindow = ConstU32<2>; type PalletId = PoolsPalletId; type MaxMetadataLen = ConstU32<256>; @@ -274,6 +275,21 @@ impl pallet_nomination_pools::Config for Runtime { type AdminOrigin = frame_system::EnsureRoot; } +parameter_types! { + pub const DelegatedStakingPalletId: PalletId = PalletId(*b"py/dlstk"); + pub const SlashRewardFraction: Perbill = Perbill::from_percent(1); +} + +impl pallet_delegated_staking::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type PalletId = DelegatedStakingPalletId; + type Currency = Balances; + type OnSlash = (); + type SlashRewardFraction = SlashRewardFraction; + type RuntimeHoldReason = RuntimeHoldReason; + type CoreStaking = Staking; +} + parameter_types! { pub static MaxUnlockingChunks: u32 = 32; } @@ -302,7 +318,7 @@ impl pallet_staking::Config for Runtime { type NominationsQuota = pallet_staking::FixedNominationsQuota; type TargetList = pallet_staking::UseValidatorsMap; type MaxUnlockingChunks = MaxUnlockingChunks; - type EventListeners = Pools; + type EventListeners = (Pools, DelegatedStaking); type WeightInfo = pallet_staking::weights::SubstrateWeight; type DisablingStrategy = pallet_staking::UpToLimitWithReEnablingDisablingStrategy; @@ -581,7 +597,7 @@ impl ExtBuilder { // set the keys for the first session. keys: stakers .into_iter() - .map(|(id, ..)| (id, id, SessionKeys { other: (id as u64).into() })) + .map(|(id, ..)| (id, id, SessionKeys { other: (id as AccountId).into() })) .collect(), ..Default::default() } diff --git a/substrate/frame/nomination-pools/runtime-api/src/lib.rs b/substrate/frame/nomination-pools/runtime-api/src/lib.rs index 644ee07fd634..798fe1187f3f 100644 --- a/substrate/frame/nomination-pools/runtime-api/src/lib.rs +++ b/substrate/frame/nomination-pools/runtime-api/src/lib.rs @@ -52,8 +52,7 @@ sp_api::decl_runtime_apis! { /// /// This can happen when the `pallet-nomination-pools` has switched to using strategy /// [`DelegateStake`](pallet_nomination_pools::adapter::DelegateStake) but the pool - /// still has funds that were staked using the older strategy - /// [TransferStake](pallet_nomination_pools::adapter::TransferStake). Use + /// still has funds that were staked using the older `TransferStake` strategy. Use /// [`migrate_pool_to_delegate_stake`](pallet_nomination_pools::Call::migrate_pool_to_delegate_stake) /// to migrate the pool. fn pool_needs_delegate_migration(pool_id: PoolId) -> bool; diff --git a/substrate/frame/nomination-pools/src/adapter.rs b/substrate/frame/nomination-pools/src/adapter.rs index bc3a48bc6df6..95365590ed4c 100644 --- a/substrate/frame/nomination-pools/src/adapter.rs +++ b/substrate/frame/nomination-pools/src/adapter.rs @@ -79,8 +79,7 @@ impl Member { /// An adapter trait that can support multiple staking strategies. /// /// Depending on which staking strategy we want to use, the staking logic can be slightly -/// different. Refer the two possible strategies currently: [`TransferStake`] and -/// [`DelegateStake`] for more detail. +/// different. See [`DelegateStake`] for more detail. pub trait StakeStrategy { type Balance: frame_support::traits::tokens::Balance; type AccountId: Clone + core::fmt::Debug; diff --git a/substrate/frame/nomination-pools/test-transfer-stake/src/lib.rs b/substrate/frame/nomination-pools/test-transfer-stake/src/lib.rs deleted file mode 100644 index cc39cfee91c8..000000000000 --- a/substrate/frame/nomination-pools/test-transfer-stake/src/lib.rs +++ /dev/null @@ -1,912 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#![cfg(test)] - -mod mock; - -use frame_support::{assert_noop, assert_ok, traits::Currency}; -use mock::*; -use pallet_nomination_pools::{ - BondExtra, BondedPools, Error as PoolsError, Event as PoolsEvent, LastPoolId, PoolMember, - PoolMembers, PoolState, -}; -use pallet_staking::{ - CurrentEra, Error as StakingError, Event as StakingEvent, Payee, RewardDestination, -}; -use sp_runtime::{bounded_btree_map, traits::Zero}; - -#[test] -fn pool_lifecycle_e2e() { - new_test_ext().execute_with(|| { - assert_eq!(Balances::minimum_balance(), 5); - assert_eq!(CurrentEra::::get(), None); - - // create the pool, we know this has id 1. - assert_ok!(Pools::create(RuntimeOrigin::signed(10), 50, 10, 10, 10)); - assert_eq!(LastPoolId::::get(), 1); - - // have the pool nominate. - assert_ok!(Pools::nominate(RuntimeOrigin::signed(10), 1, vec![1, 2, 3])); - - assert_eq!( - staking_events_since_last_call(), - vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: 50 }] - ); - assert_eq!( - pool_events_since_last_call(), - vec![ - PoolsEvent::Created { depositor: 10, pool_id: 1 }, - PoolsEvent::Bonded { member: 10, pool_id: 1, bonded: 50, joined: true }, - ] - ); - - // have two members join - assert_ok!(Pools::join(RuntimeOrigin::signed(20), 10, 1)); - assert_ok!(Pools::join(RuntimeOrigin::signed(21), 10, 1)); - - assert_eq!( - staking_events_since_last_call(), - vec![ - StakingEvent::Bonded { stash: POOL1_BONDED, amount: 10 }, - StakingEvent::Bonded { stash: POOL1_BONDED, amount: 10 }, - ] - ); - assert_eq!( - pool_events_since_last_call(), - vec![ - PoolsEvent::Bonded { member: 20, pool_id: 1, bonded: 10, joined: true }, - PoolsEvent::Bonded { member: 21, pool_id: 1, bonded: 10, joined: true }, - ] - ); - - // pool goes into destroying - assert_ok!(Pools::set_state(RuntimeOrigin::signed(10), 1, PoolState::Destroying)); - - // depositor cannot unbond yet. - assert_noop!( - Pools::unbond(RuntimeOrigin::signed(10), 10, 50), - PoolsError::::MinimumBondNotMet, - ); - - // now the members want to unbond. - assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 10)); - assert_ok!(Pools::unbond(RuntimeOrigin::signed(21), 21, 10)); - - assert_eq!(PoolMembers::::get(20).unwrap().unbonding_eras.len(), 1); - assert_eq!(PoolMembers::::get(20).unwrap().points, 0); - assert_eq!(PoolMembers::::get(21).unwrap().unbonding_eras.len(), 1); - assert_eq!(PoolMembers::::get(21).unwrap().points, 0); - - assert_eq!( - staking_events_since_last_call(), - vec![ - StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 }, - StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 }, - ] - ); - assert_eq!( - pool_events_since_last_call(), - vec![ - PoolsEvent::StateChanged { pool_id: 1, new_state: PoolState::Destroying }, - PoolsEvent::Unbonded { member: 20, pool_id: 1, points: 10, balance: 10, era: 3 }, - PoolsEvent::Unbonded { member: 21, pool_id: 1, points: 10, balance: 10, era: 3 }, - ] - ); - - // depositor cannot still unbond - assert_noop!( - Pools::unbond(RuntimeOrigin::signed(10), 10, 50), - PoolsError::::MinimumBondNotMet, - ); - - for e in 1..BondingDuration::get() { - CurrentEra::::set(Some(e)); - assert_noop!( - Pools::withdraw_unbonded(RuntimeOrigin::signed(20), 20, 0), - PoolsError::::CannotWithdrawAny - ); - } - - // members are now unlocked. - CurrentEra::::set(Some(BondingDuration::get())); - - // depositor cannot still unbond - assert_noop!( - Pools::unbond(RuntimeOrigin::signed(10), 10, 50), - PoolsError::::MinimumBondNotMet, - ); - - // but members can now withdraw. - assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(20), 20, 0)); - assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(21), 21, 0)); - assert!(PoolMembers::::get(20).is_none()); - assert!(PoolMembers::::get(21).is_none()); - - assert_eq!( - staking_events_since_last_call(), - vec![StakingEvent::Withdrawn { stash: POOL1_BONDED, amount: 20 },] - ); - assert_eq!( - pool_events_since_last_call(), - vec![ - PoolsEvent::Withdrawn { member: 20, pool_id: 1, points: 10, balance: 10 }, - PoolsEvent::MemberRemoved { pool_id: 1, member: 20, released_balance: 0 }, - PoolsEvent::Withdrawn { member: 21, pool_id: 1, points: 10, balance: 10 }, - PoolsEvent::MemberRemoved { pool_id: 1, member: 21, released_balance: 0 }, - ] - ); - - // as soon as all members have left, the depositor can try to unbond, but since the - // min-nominator intention is set, they must chill first. - assert_noop!( - Pools::unbond(RuntimeOrigin::signed(10), 10, 50), - pallet_staking::Error::::InsufficientBond - ); - - assert_ok!(Pools::chill(RuntimeOrigin::signed(10), 1)); - assert_ok!(Pools::unbond(RuntimeOrigin::signed(10), 10, 50)); - - assert_eq!( - staking_events_since_last_call(), - vec![ - StakingEvent::Chilled { stash: POOL1_BONDED }, - StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 50 }, - ] - ); - assert_eq!( - pool_events_since_last_call(), - vec![PoolsEvent::Unbonded { member: 10, pool_id: 1, points: 50, balance: 50, era: 6 }] - ); - - // waiting another bonding duration: - CurrentEra::::set(Some(BondingDuration::get() * 2)); - assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(10), 10, 1)); - - // pools is fully destroyed now. - assert_eq!( - staking_events_since_last_call(), - vec![StakingEvent::Withdrawn { stash: POOL1_BONDED, amount: 50 },] - ); - assert_eq!( - pool_events_since_last_call(), - vec![ - PoolsEvent::Withdrawn { member: 10, pool_id: 1, points: 50, balance: 50 }, - PoolsEvent::MemberRemoved { pool_id: 1, member: 10, released_balance: 0 }, - PoolsEvent::Destroyed { pool_id: 1 } - ] - ); - }) -} - -#[test] -fn destroy_pool_with_erroneous_consumer() { - new_test_ext().execute_with(|| { - // create the pool, we know this has id 1. - assert_ok!(Pools::create(RuntimeOrigin::signed(10), 50, 10, 10, 10)); - assert_eq!(LastPoolId::::get(), 1); - - // expect consumers on pool account to be 2 (staking lock and an explicit inc by staking). - assert_eq!(frame_system::Pallet::::consumers(&POOL1_BONDED), 2); - - // increment consumer by 1 reproducing the erroneous consumer bug. - // refer https://github.com/paritytech/polkadot-sdk/issues/4440. - assert_ok!(frame_system::Pallet::::inc_consumers(&POOL1_BONDED)); - assert_eq!(frame_system::Pallet::::consumers(&POOL1_BONDED), 3); - - // have the pool nominate. - assert_ok!(Pools::nominate(RuntimeOrigin::signed(10), 1, vec![1, 2, 3])); - - assert_eq!( - staking_events_since_last_call(), - vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: 50 }] - ); - assert_eq!( - pool_events_since_last_call(), - vec![ - PoolsEvent::Created { depositor: 10, pool_id: 1 }, - PoolsEvent::Bonded { member: 10, pool_id: 1, bonded: 50, joined: true }, - ] - ); - - // pool goes into destroying - assert_ok!(Pools::set_state(RuntimeOrigin::signed(10), 1, PoolState::Destroying)); - - assert_eq!( - pool_events_since_last_call(), - vec![PoolsEvent::StateChanged { pool_id: 1, new_state: PoolState::Destroying },] - ); - - // move to era 1 - CurrentEra::::set(Some(1)); - - // depositor need to chill before unbonding - assert_noop!( - Pools::unbond(RuntimeOrigin::signed(10), 10, 50), - pallet_staking::Error::::InsufficientBond - ); - - assert_ok!(Pools::chill(RuntimeOrigin::signed(10), 1)); - assert_ok!(Pools::unbond(RuntimeOrigin::signed(10), 10, 50)); - - assert_eq!( - staking_events_since_last_call(), - vec![ - StakingEvent::Chilled { stash: POOL1_BONDED }, - StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 50 }, - ] - ); - assert_eq!( - pool_events_since_last_call(), - vec![PoolsEvent::Unbonded { - member: 10, - pool_id: 1, - points: 50, - balance: 50, - era: 1 + 3 - }] - ); - - // waiting bonding duration: - CurrentEra::::set(Some(1 + 3)); - // this should work even with an extra consumer count on pool account. - assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(10), 10, 1)); - - // pools is fully destroyed now. - assert_eq!( - staking_events_since_last_call(), - vec![StakingEvent::Withdrawn { stash: POOL1_BONDED, amount: 50 },] - ); - assert_eq!( - pool_events_since_last_call(), - vec![ - PoolsEvent::Withdrawn { member: 10, pool_id: 1, points: 50, balance: 50 }, - PoolsEvent::MemberRemoved { pool_id: 1, member: 10, released_balance: 0 }, - PoolsEvent::Destroyed { pool_id: 1 } - ] - ); - }) -} - -#[test] -fn pool_chill_e2e() { - new_test_ext().execute_with(|| { - assert_eq!(Balances::minimum_balance(), 5); - assert_eq!(CurrentEra::::get(), None); - - // create the pool, we know this has id 1. - assert_ok!(Pools::create(RuntimeOrigin::signed(10), 50, 10, 10, 10)); - assert_eq!(LastPoolId::::get(), 1); - - // have the pool nominate. - assert_ok!(Pools::nominate(RuntimeOrigin::signed(10), 1, vec![1, 2, 3])); - - assert_eq!( - staking_events_since_last_call(), - vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: 50 }] - ); - assert_eq!( - pool_events_since_last_call(), - vec![ - PoolsEvent::Created { depositor: 10, pool_id: 1 }, - PoolsEvent::Bonded { member: 10, pool_id: 1, bonded: 50, joined: true }, - ] - ); - - // have two members join - assert_ok!(Pools::join(RuntimeOrigin::signed(20), 10, 1)); - assert_ok!(Pools::join(RuntimeOrigin::signed(21), 10, 1)); - - assert_eq!( - staking_events_since_last_call(), - vec![ - StakingEvent::Bonded { stash: POOL1_BONDED, amount: 10 }, - StakingEvent::Bonded { stash: POOL1_BONDED, amount: 10 }, - ] - ); - assert_eq!( - pool_events_since_last_call(), - vec![ - PoolsEvent::Bonded { member: 20, pool_id: 1, bonded: 10, joined: true }, - PoolsEvent::Bonded { member: 21, pool_id: 1, bonded: 10, joined: true }, - ] - ); - - // in case depositor does not have more than `MinNominatorBond` staked, we can end up in - // situation where a member unbonding would cause pool balance to drop below - // `MinNominatorBond` and hence not allowed. This can happen if the `MinNominatorBond` is - // increased after the pool is created. - assert_ok!(Staking::set_staking_configs( - RuntimeOrigin::root(), - pallet_staking::ConfigOp::Set(55), // minimum nominator bond - pallet_staking::ConfigOp::Noop, - pallet_staking::ConfigOp::Noop, - pallet_staking::ConfigOp::Noop, - pallet_staking::ConfigOp::Noop, - pallet_staking::ConfigOp::Noop, - pallet_staking::ConfigOp::Noop, - )); - - // members can unbond as long as total stake of the pool is above min nominator bond - assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 10),); - assert_eq!(PoolMembers::::get(20).unwrap().unbonding_eras.len(), 1); - assert_eq!(PoolMembers::::get(20).unwrap().points, 0); - - // this member cannot unbond since it will cause `pool stake < MinNominatorBond` - assert_noop!( - Pools::unbond(RuntimeOrigin::signed(21), 21, 10), - StakingError::::InsufficientBond, - ); - - // members can call `chill` permissionlessly now - assert_ok!(Pools::chill(RuntimeOrigin::signed(20), 1)); - - // now another member can unbond. - assert_ok!(Pools::unbond(RuntimeOrigin::signed(21), 21, 10)); - assert_eq!(PoolMembers::::get(21).unwrap().unbonding_eras.len(), 1); - assert_eq!(PoolMembers::::get(21).unwrap().points, 0); - - // nominator can not resume nomination until depositor have enough stake - assert_noop!( - Pools::nominate(RuntimeOrigin::signed(10), 1, vec![1, 2, 3]), - PoolsError::::MinimumBondNotMet, - ); - - // other members joining pool does not affect the depositor's ability to resume nomination - assert_ok!(Pools::join(RuntimeOrigin::signed(22), 10, 1)); - - assert_noop!( - Pools::nominate(RuntimeOrigin::signed(10), 1, vec![1, 2, 3]), - PoolsError::::MinimumBondNotMet, - ); - - // depositor can bond extra stake - assert_ok!(Pools::bond_extra(RuntimeOrigin::signed(10), BondExtra::FreeBalance(10))); - - // `chill` can not be called permissionlessly anymore - assert_noop!( - Pools::chill(RuntimeOrigin::signed(20), 1), - PoolsError::::NotNominator, - ); - - // now nominator can resume nomination - assert_ok!(Pools::nominate(RuntimeOrigin::signed(10), 1, vec![1, 2, 3])); - - // skip to make the unbonding period end. - CurrentEra::::set(Some(BondingDuration::get())); - - // members can now withdraw. - assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(20), 20, 0)); - assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(21), 21, 0)); - - assert_eq!( - staking_events_since_last_call(), - vec![ - StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 }, - StakingEvent::Chilled { stash: POOL1_BONDED }, - StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 }, - StakingEvent::Bonded { stash: POOL1_BONDED, amount: 10 }, // other member bonding - StakingEvent::Bonded { stash: POOL1_BONDED, amount: 10 }, // depositor bond extra - StakingEvent::Withdrawn { stash: POOL1_BONDED, amount: 20 }, - ] - ); - }) -} - -#[test] -fn pool_slash_e2e() { - new_test_ext().execute_with(|| { - ExistentialDeposit::set(1); - assert_eq!(Balances::minimum_balance(), 1); - assert_eq!(CurrentEra::::get(), None); - - // create the pool, we know this has id 1. - assert_ok!(Pools::create(RuntimeOrigin::signed(10), 40, 10, 10, 10)); - assert_eq!(LastPoolId::::get(), 1); - - assert_eq!( - staking_events_since_last_call(), - vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: 40 }] - ); - assert_eq!( - pool_events_since_last_call(), - vec![ - PoolsEvent::Created { depositor: 10, pool_id: 1 }, - PoolsEvent::Bonded { member: 10, pool_id: 1, bonded: 40, joined: true }, - ] - ); - - assert_eq!( - Payee::::get(POOL1_BONDED), - Some(RewardDestination::Account(POOL1_REWARD)) - ); - - // have two members join - assert_ok!(Pools::join(RuntimeOrigin::signed(20), 20, 1)); - assert_ok!(Pools::join(RuntimeOrigin::signed(21), 20, 1)); - - assert_eq!( - staking_events_since_last_call(), - vec![ - StakingEvent::Bonded { stash: POOL1_BONDED, amount: 20 }, - StakingEvent::Bonded { stash: POOL1_BONDED, amount: 20 } - ] - ); - assert_eq!( - pool_events_since_last_call(), - vec![ - PoolsEvent::Bonded { member: 20, pool_id: 1, bonded: 20, joined: true }, - PoolsEvent::Bonded { member: 21, pool_id: 1, bonded: 20, joined: true }, - ] - ); - - // now let's progress a bit. - CurrentEra::::set(Some(1)); - - // 20 / 80 of the total funds are unlocked, and safe from any further slash. - assert_ok!(Pools::unbond(RuntimeOrigin::signed(10), 10, 10)); - assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 10)); - - assert_eq!( - staking_events_since_last_call(), - vec![ - StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 }, - StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 } - ] - ); - assert_eq!( - pool_events_since_last_call(), - vec![ - PoolsEvent::Unbonded { member: 10, pool_id: 1, balance: 10, points: 10, era: 4 }, - PoolsEvent::Unbonded { member: 20, pool_id: 1, balance: 10, points: 10, era: 4 } - ] - ); - - CurrentEra::::set(Some(2)); - - // note: depositor cannot fully unbond at this point. - // these funds will still get slashed. - assert_ok!(Pools::unbond(RuntimeOrigin::signed(10), 10, 10)); - assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 10)); - assert_ok!(Pools::unbond(RuntimeOrigin::signed(21), 21, 10)); - - assert_eq!( - staking_events_since_last_call(), - vec![ - StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 }, - StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 }, - StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 }, - ] - ); - - assert_eq!( - pool_events_since_last_call(), - vec![ - PoolsEvent::Unbonded { member: 10, pool_id: 1, balance: 10, points: 10, era: 5 }, - PoolsEvent::Unbonded { member: 20, pool_id: 1, balance: 10, points: 10, era: 5 }, - PoolsEvent::Unbonded { member: 21, pool_id: 1, balance: 10, points: 10, era: 5 }, - ] - ); - - // At this point, 20 are safe from slash, 30 are unlocking but vulnerable to slash, and - // another 30 are active and vulnerable to slash. Let's slash half of them. - pallet_staking::slashing::do_slash::( - &POOL1_BONDED, - 30, - &mut Default::default(), - &mut Default::default(), - 2, // slash era 2, affects chunks at era 5 onwards. - ); - - assert_eq!( - staking_events_since_last_call(), - vec![StakingEvent::Slashed { staker: POOL1_BONDED, amount: 30 }] - ); - assert_eq!( - pool_events_since_last_call(), - vec![ - // 30 has been slashed to 15 (15 slash) - PoolsEvent::UnbondingPoolSlashed { pool_id: 1, era: 5, balance: 15 }, - // 30 has been slashed to 15 (15 slash) - PoolsEvent::PoolSlashed { pool_id: 1, balance: 15 } - ] - ); - - CurrentEra::::set(Some(3)); - assert_ok!(Pools::unbond(RuntimeOrigin::signed(21), 21, 10)); - - assert_eq!( - PoolMembers::::get(21).unwrap(), - PoolMember { - pool_id: 1, - points: 0, - last_recorded_reward_counter: Zero::zero(), - // the 10 points unlocked just now correspond to 5 points in the unbond pool. - unbonding_eras: bounded_btree_map!(5 => 10, 6 => 5) - } - ); - assert_eq!( - staking_events_since_last_call(), - vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 5 }] - ); - assert_eq!( - pool_events_since_last_call(), - vec![PoolsEvent::Unbonded { member: 21, pool_id: 1, balance: 5, points: 5, era: 6 }] - ); - - // now we start withdrawing. we do it all at once, at era 6 where 20 and 21 are fully free. - CurrentEra::::set(Some(6)); - assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(20), 20, 0)); - assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(21), 21, 0)); - - assert_eq!( - pool_events_since_last_call(), - vec![ - // 20 had unbonded 10 safely, and 10 got slashed by half. - PoolsEvent::Withdrawn { member: 20, pool_id: 1, balance: 10 + 5, points: 20 }, - PoolsEvent::MemberRemoved { pool_id: 1, member: 20, released_balance: 0 }, - // 21 unbonded all of it after the slash - PoolsEvent::Withdrawn { member: 21, pool_id: 1, balance: 5 + 5, points: 15 }, - PoolsEvent::MemberRemoved { pool_id: 1, member: 21, released_balance: 0 } - ] - ); - assert_eq!( - staking_events_since_last_call(), - // a 10 (un-slashed) + 10/2 (slashed) balance from 10 has also been unlocked - vec![StakingEvent::Withdrawn { stash: POOL1_BONDED, amount: 15 + 10 + 15 }] - ); - - // now, finally, we can unbond the depositor further than their current limit. - assert_ok!(Pools::set_state(RuntimeOrigin::signed(10), 1, PoolState::Destroying)); - assert_ok!(Pools::unbond(RuntimeOrigin::signed(10), 10, 20)); - - assert_eq!( - staking_events_since_last_call(), - vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 }] - ); - assert_eq!( - pool_events_since_last_call(), - vec![ - PoolsEvent::StateChanged { pool_id: 1, new_state: PoolState::Destroying }, - PoolsEvent::Unbonded { member: 10, pool_id: 1, points: 10, balance: 10, era: 9 } - ] - ); - - CurrentEra::::set(Some(9)); - assert_eq!( - PoolMembers::::get(10).unwrap(), - PoolMember { - pool_id: 1, - points: 0, - last_recorded_reward_counter: Zero::zero(), - unbonding_eras: bounded_btree_map!(4 => 10, 5 => 10, 9 => 10) - } - ); - // withdraw the depositor, they should lose 12 balance in total due to slash. - assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(10), 10, 0)); - - assert_eq!( - staking_events_since_last_call(), - vec![StakingEvent::Withdrawn { stash: POOL1_BONDED, amount: 10 }] - ); - assert_eq!( - pool_events_since_last_call(), - vec![ - PoolsEvent::Withdrawn { member: 10, pool_id: 1, balance: 10 + 15, points: 30 }, - PoolsEvent::MemberRemoved { pool_id: 1, member: 10, released_balance: 0 }, - PoolsEvent::Destroyed { pool_id: 1 } - ] - ); - }); -} - -#[test] -fn pool_slash_proportional() { - // a typical example where 3 pool members unbond in era 99, 100, and 101, and a slash that - // happened in era 100 should only affect the latter two. - new_test_ext().execute_with(|| { - ExistentialDeposit::set(1); - BondingDuration::set(28); - assert_eq!(Balances::minimum_balance(), 1); - assert_eq!(CurrentEra::::get(), None); - - // create the pool, we know this has id 1. - assert_ok!(Pools::create(RuntimeOrigin::signed(10), 40, 10, 10, 10)); - assert_eq!(LastPoolId::::get(), 1); - - assert_eq!( - staking_events_since_last_call(), - vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: 40 }] - ); - assert_eq!( - pool_events_since_last_call(), - vec![ - PoolsEvent::Created { depositor: 10, pool_id: 1 }, - PoolsEvent::Bonded { member: 10, pool_id: 1, bonded: 40, joined: true }, - ] - ); - - // have two members join - let bond = 20; - assert_ok!(Pools::join(RuntimeOrigin::signed(20), bond, 1)); - assert_ok!(Pools::join(RuntimeOrigin::signed(21), bond, 1)); - assert_ok!(Pools::join(RuntimeOrigin::signed(22), bond, 1)); - - assert_eq!( - staking_events_since_last_call(), - vec![ - StakingEvent::Bonded { stash: POOL1_BONDED, amount: bond }, - StakingEvent::Bonded { stash: POOL1_BONDED, amount: bond }, - StakingEvent::Bonded { stash: POOL1_BONDED, amount: bond }, - ] - ); - assert_eq!( - pool_events_since_last_call(), - vec![ - PoolsEvent::Bonded { member: 20, pool_id: 1, bonded: bond, joined: true }, - PoolsEvent::Bonded { member: 21, pool_id: 1, bonded: bond, joined: true }, - PoolsEvent::Bonded { member: 22, pool_id: 1, bonded: bond, joined: true }, - ] - ); - - // now let's progress a lot. - CurrentEra::::set(Some(99)); - - // and unbond - assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, bond)); - - assert_eq!( - staking_events_since_last_call(), - vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: bond },] - ); - assert_eq!( - pool_events_since_last_call(), - vec![PoolsEvent::Unbonded { - member: 20, - pool_id: 1, - balance: bond, - points: bond, - era: 127 - }] - ); - - CurrentEra::::set(Some(100)); - assert_ok!(Pools::unbond(RuntimeOrigin::signed(21), 21, bond)); - assert_eq!( - staking_events_since_last_call(), - vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: bond },] - ); - assert_eq!( - pool_events_since_last_call(), - vec![PoolsEvent::Unbonded { - member: 21, - pool_id: 1, - balance: bond, - points: bond, - era: 128 - }] - ); - - CurrentEra::::set(Some(101)); - assert_ok!(Pools::unbond(RuntimeOrigin::signed(22), 22, bond)); - assert_eq!( - staking_events_since_last_call(), - vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: bond },] - ); - assert_eq!( - pool_events_since_last_call(), - vec![PoolsEvent::Unbonded { - member: 22, - pool_id: 1, - balance: bond, - points: bond, - era: 129 - }] - ); - - // Apply a slash that happened in era 100. This is typically applied with a delay. - // Of the total 100, 50 is slashed. - assert_eq!(BondedPools::::get(1).unwrap().points, 40); - pallet_staking::slashing::do_slash::( - &POOL1_BONDED, - 50, - &mut Default::default(), - &mut Default::default(), - 100, - ); - - assert_eq!( - staking_events_since_last_call(), - vec![StakingEvent::Slashed { staker: POOL1_BONDED, amount: 50 }] - ); - assert_eq!( - pool_events_since_last_call(), - vec![ - // This era got slashed 12.5, which rounded up to 13. - PoolsEvent::UnbondingPoolSlashed { pool_id: 1, era: 128, balance: 7 }, - // This era got slashed 12 instead of 12.5 because an earlier chunk got 0.5 more - // slashed, and 12 is all the remaining slash - PoolsEvent::UnbondingPoolSlashed { pool_id: 1, era: 129, balance: 8 }, - // Bonded pool got slashed for 25, remaining 15 in it. - PoolsEvent::PoolSlashed { pool_id: 1, balance: 15 } - ] - ); - }); -} - -#[test] -fn pool_slash_non_proportional_only_bonded_pool() { - // A typical example where a pool member unbonds in era 99, and they can get away with a slash - // that happened in era 100, as long as the pool has enough active bond to cover the slash. If - // everything else in the slashing/staking system works, this should always be the case. - // Nonetheless, `ledger.slash` has been written such that it will slash greedily from any chunk - // if it runs out of chunks that it thinks should be affected by the slash. - new_test_ext().execute_with(|| { - ExistentialDeposit::set(1); - BondingDuration::set(28); - assert_eq!(Balances::minimum_balance(), 1); - assert_eq!(CurrentEra::::get(), None); - - // create the pool, we know this has id 1. - assert_ok!(Pools::create(RuntimeOrigin::signed(10), 40, 10, 10, 10)); - assert_eq!( - staking_events_since_last_call(), - vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: 40 }] - ); - assert_eq!( - pool_events_since_last_call(), - vec![ - PoolsEvent::Created { depositor: 10, pool_id: 1 }, - PoolsEvent::Bonded { member: 10, pool_id: 1, bonded: 40, joined: true }, - ] - ); - - // have two members join - let bond = 20; - assert_ok!(Pools::join(RuntimeOrigin::signed(20), bond, 1)); - assert_eq!( - staking_events_since_last_call(), - vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: bond }] - ); - assert_eq!( - pool_events_since_last_call(), - vec![PoolsEvent::Bonded { member: 20, pool_id: 1, bonded: bond, joined: true }] - ); - - // progress and unbond. - CurrentEra::::set(Some(99)); - assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, bond)); - assert_eq!( - staking_events_since_last_call(), - vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: bond }] - ); - assert_eq!( - pool_events_since_last_call(), - vec![PoolsEvent::Unbonded { - member: 20, - pool_id: 1, - balance: bond, - points: bond, - era: 127 - }] - ); - - // slash for 30. This will be deducted only from the bonded pool. - CurrentEra::::set(Some(100)); - assert_eq!(BondedPools::::get(1).unwrap().points, 40); - pallet_staking::slashing::do_slash::( - &POOL1_BONDED, - 30, - &mut Default::default(), - &mut Default::default(), - 100, - ); - - assert_eq!( - staking_events_since_last_call(), - vec![StakingEvent::Slashed { staker: POOL1_BONDED, amount: 30 }] - ); - assert_eq!( - pool_events_since_last_call(), - vec![PoolsEvent::PoolSlashed { pool_id: 1, balance: 10 }] - ); - }); -} - -#[test] -fn pool_slash_non_proportional_bonded_pool_and_chunks() { - // An uncommon example where even though some funds are unlocked such that they should not be - // affected by a slash, we still slash out of them. This should not happen at all. If a - // nomination has unbonded, from the next era onwards, their exposure will drop, so if an era - // happens in that era, then their share of that slash should naturally be less, such that only - // their active ledger stake is enough to compensate it. - new_test_ext().execute_with(|| { - ExistentialDeposit::set(1); - BondingDuration::set(28); - assert_eq!(Balances::minimum_balance(), 1); - assert_eq!(CurrentEra::::get(), None); - - // create the pool, we know this has id 1. - assert_ok!(Pools::create(RuntimeOrigin::signed(10), 40, 10, 10, 10)); - assert_eq!( - staking_events_since_last_call(), - vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: 40 }] - ); - assert_eq!( - pool_events_since_last_call(), - vec![ - PoolsEvent::Created { depositor: 10, pool_id: 1 }, - PoolsEvent::Bonded { member: 10, pool_id: 1, bonded: 40, joined: true }, - ] - ); - - // have two members join - let bond = 20; - assert_ok!(Pools::join(RuntimeOrigin::signed(20), bond, 1)); - assert_eq!( - staking_events_since_last_call(), - vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: bond }] - ); - assert_eq!( - pool_events_since_last_call(), - vec![PoolsEvent::Bonded { member: 20, pool_id: 1, bonded: bond, joined: true }] - ); - - // progress and unbond. - CurrentEra::::set(Some(99)); - assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, bond)); - assert_eq!( - staking_events_since_last_call(), - vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: bond }] - ); - assert_eq!( - pool_events_since_last_call(), - vec![PoolsEvent::Unbonded { - member: 20, - pool_id: 1, - balance: bond, - points: bond, - era: 127 - }] - ); - - // slash 50. This will be deducted only from the bonded pool and one of the unbonding pools. - CurrentEra::::set(Some(100)); - assert_eq!(BondedPools::::get(1).unwrap().points, 40); - pallet_staking::slashing::do_slash::( - &POOL1_BONDED, - 50, - &mut Default::default(), - &mut Default::default(), - 100, - ); - - assert_eq!( - staking_events_since_last_call(), - vec![StakingEvent::Slashed { staker: POOL1_BONDED, amount: 50 }] - ); - assert_eq!( - pool_events_since_last_call(), - vec![ - // out of 20, 10 was taken. - PoolsEvent::UnbondingPoolSlashed { pool_id: 1, era: 127, balance: 10 }, - // out of 40, all was taken. - PoolsEvent::PoolSlashed { pool_id: 1, balance: 0 } - ] - ); - }); -} From bbd17af55fe5fff93630dc5bcd9abeb479e40ce5 Mon Sep 17 00:00:00 2001 From: Ankan Date: Mon, 25 Nov 2024 14:18:41 +0100 Subject: [PATCH 114/142] keep transfer stake struct --- .../frame/nomination-pools/src/adapter.rs | 116 +++++++++++++++++- 1 file changed, 115 insertions(+), 1 deletion(-) diff --git a/substrate/frame/nomination-pools/src/adapter.rs b/substrate/frame/nomination-pools/src/adapter.rs index 95365590ed4c..f125919dabfa 100644 --- a/substrate/frame/nomination-pools/src/adapter.rs +++ b/substrate/frame/nomination-pools/src/adapter.rs @@ -79,7 +79,8 @@ impl Member { /// An adapter trait that can support multiple staking strategies. /// /// Depending on which staking strategy we want to use, the staking logic can be slightly -/// different. See [`DelegateStake`] for more detail. +/// different. Refer the two possible strategies currently: [`TransferStake`] and +/// [`DelegateStake`] for more detail. pub trait StakeStrategy { type Balance: frame_support::traits::tokens::Balance; type AccountId: Clone + core::fmt::Debug; @@ -235,6 +236,119 @@ pub trait StakeStrategy { } } +/// A staking strategy implementation that supports transfer based staking. +/// +/// In order to stake, this adapter transfers the funds from the member/delegator account to the +/// pool account and stakes through the pool account on `Staking`. +/// +/// This is the older Staking strategy used by pools. To switch to the newer [`DelegateStake`] +/// strategy in an existing runtime, storage migration is required. See +/// [`migration::unversioned::DelegationStakeMigration`]. For new runtimes, it is highly recommended +/// to use the [`DelegateStake`] strategy. +pub struct TransferStake(PhantomData<(T, Staking)>); + +impl, AccountId = T::AccountId>> + StakeStrategy for TransferStake +{ + type Balance = BalanceOf; + type AccountId = T::AccountId; + type CoreStaking = Staking; + + fn strategy_type() -> StakeStrategyType { + StakeStrategyType::Transfer + } + + fn transferable_balance( + pool_account: Pool, + _: Member, + ) -> BalanceOf { + T::Currency::balance(&pool_account.0).saturating_sub(Self::active_stake(pool_account)) + } + + fn total_balance(pool_account: Pool) -> Option> { + Some(T::Currency::total_balance(&pool_account.get())) + } + + fn member_delegation_balance( + _member_account: Member, + ) -> Option { + // for transfer stake, no delegation exists. + None + } + + fn pledge_bond( + who: Member, + pool_account: Pool, + reward_account: &Self::AccountId, + amount: BalanceOf, + bond_type: BondType, + ) -> DispatchResult { + match bond_type { + BondType::Create => { + // first bond + T::Currency::transfer(&who.0, &pool_account.0, amount, Preservation::Expendable)?; + Staking::bond(&pool_account.0, amount, &reward_account) + }, + BondType::Extra => { + // additional bond + T::Currency::transfer(&who.0, &pool_account.0, amount, Preservation::Preserve)?; + Staking::bond_extra(&pool_account.0, amount) + }, + } + } + + fn member_withdraw( + who: Member, + pool_account: Pool, + amount: BalanceOf, + _num_slashing_spans: u32, + ) -> DispatchResult { + T::Currency::transfer(&pool_account.0, &who.0, amount, Preservation::Expendable)?; + + Ok(()) + } + + fn dissolve(pool_account: Pool) -> DispatchResult { + defensive_assert!( + T::Currency::total_balance(&pool_account.clone().get()).is_zero(), + "dissolving pool should not have any balance" + ); + + // Defensively force set balance to zero. + T::Currency::set_balance(&pool_account.get(), Zero::zero()); + Ok(()) + } + + fn pending_slash(_: Pool) -> Self::Balance { + // for transfer stake strategy, slashing is greedy and never deferred. + Zero::zero() + } + + fn member_slash( + _who: Member, + _pool: Pool, + _amount: Staking::Balance, + _maybe_reporter: Option, + ) -> DispatchResult { + Err(Error::::Defensive(DefensiveError::DelegationUnsupported).into()) + } + + fn migrate_nominator_to_agent( + _pool: Pool, + _reward_account: &Self::AccountId, + ) -> DispatchResult { + Err(Error::::Defensive(DefensiveError::DelegationUnsupported).into()) + } + + fn migrate_delegation( + _pool: Pool, + _delegator: Member, + _value: Self::Balance, + ) -> DispatchResult { + Err(Error::::Defensive(DefensiveError::DelegationUnsupported).into()) + } +} + /// A staking strategy implementation that supports delegation based staking. /// /// In this approach, first the funds are delegated from delegator to the pool account and later From 48544726d10e86c94781f80c327614c6d2532d90 Mon Sep 17 00:00:00 2001 From: command-bot <> Date: Tue, 26 Nov 2024 11:56:41 +0000 Subject: [PATCH 115/142] ".git/.scripts/commands/fmt/fmt.sh" --- substrate/bin/node/runtime/src/lib.rs | 3 ++- .../test-staking-e2e/src/mock.rs | 6 ++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index 274b61a0c58b..113fc06ba4c8 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -968,7 +968,8 @@ impl pallet_nomination_pools::Config for Runtime { type RewardCounter = FixedU128; type BalanceToU256 = BalanceToU256; type U256ToBalance = U256ToBalance; - type StakeAdapter = pallet_nomination_pools::adapter::DelegateStake; + type StakeAdapter = + pallet_nomination_pools::adapter::DelegateStake; type PostUnbondingPoolsWindow = PostUnbondPoolsWindow; type MaxMetadataLen = ConstU32<256>; type MaxUnbonding = ConstU32<8>; diff --git a/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs b/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs index 96f71f7b78db..ff7dd0e03417 100644 --- a/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs +++ b/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs @@ -20,7 +20,8 @@ use frame_support::{ assert_ok, parameter_types, traits, traits::{Hooks, UnfilteredDispatchable, VariantCountOf}, - weights::constants, PalletId + weights::constants, + PalletId, }; use frame_system::EnsureRoot; use sp_core::{ConstU32, Get}; @@ -266,7 +267,8 @@ impl pallet_nomination_pools::Config for Runtime { type RewardCounter = sp_runtime::FixedU128; type BalanceToU256 = BalanceToU256; type U256ToBalance = U256ToBalance; - type StakeAdapter = pallet_nomination_pools::adapter::DelegateStake; + type StakeAdapter = + pallet_nomination_pools::adapter::DelegateStake; type PostUnbondingPoolsWindow = ConstU32<2>; type PalletId = PoolsPalletId; type MaxMetadataLen = ConstU32<256>; From 1cb756e06f2f64c7b938a7c8eb357fcba9415fed Mon Sep 17 00:00:00 2001 From: Ankan Date: Tue, 26 Nov 2024 12:02:55 +0100 Subject: [PATCH 116/142] fix e2e tests --- .../test-staking-e2e/src/lib.rs | 26 +++++++++---------- .../test-staking-e2e/src/mock.rs | 17 +++++++++--- 2 files changed, 27 insertions(+), 16 deletions(-) diff --git a/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/lib.rs b/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/lib.rs index 26a6345e145f..96e4d112fe1b 100644 --- a/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/lib.rs +++ b/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/lib.rs @@ -327,8 +327,8 @@ fn automatic_unbonding_pools() { assert_eq!(::MaxUnbonding::get(), 1); // init state of pool members. - let init_stakeable_balance_2 = pallet_staking::asset::stakeable_balance::(&2); - let init_stakeable_balance_3 = pallet_staking::asset::stakeable_balance::(&3); + let init_stakeable_balance_2 = stakeable_balance_for(2); + let init_stakeable_balance_3 = stakeable_balance_for(3); let pool_bonded_account = Pools::generate_bonded_account(1); @@ -378,7 +378,7 @@ fn automatic_unbonding_pools() { System::reset_events(); let staked_before_withdraw_pool = staked_amount_for(pool_bonded_account); - assert_eq!(pallet_staking::asset::stakeable_balance::(&pool_bonded_account), 26); + assert_eq!(delegated_balance_for(pool_bonded_account), 5 + 10 + 10); // now unbonding 3 will work, although the pool's ledger still has the unlocking chunks // filled up. @@ -390,13 +390,13 @@ fn automatic_unbonding_pools() { [ // auto-withdraw happened as expected to release 2's unbonding funds, but the funds // were not transferred to 2 and stay in the pool's transferrable balance instead. - pallet_staking::Event::Withdrawn { stash: 7939698191839293293, amount: 10 }, - pallet_staking::Event::Unbonded { stash: 7939698191839293293, amount: 10 } + pallet_staking::Event::Withdrawn { stash: pool_bonded_account, amount: 10 }, + pallet_staking::Event::Unbonded { stash: pool_bonded_account, amount: 10 } ] ); // balance of the pool remains the same, it hasn't withdraw explicitly from the pool yet. - assert_eq!(pallet_staking::asset::stakeable_balance::(&pool_bonded_account), 26); + assert_eq!(delegated_balance_for(pool_bonded_account), 25); // but the locked amount in the pool's account decreases due to the auto-withdraw: assert_eq!(staked_before_withdraw_pool - 10, staked_amount_for(pool_bonded_account)); @@ -405,12 +405,12 @@ fn automatic_unbonding_pools() { // however, note that the withdrawing from the pool still works for 2, the funds are taken // from the pool's non staked balance. - assert_eq!(pallet_staking::asset::stakeable_balance::(&pool_bonded_account), 26); - assert_eq!(pallet_staking::asset::staked::(&pool_bonded_account), 15); + assert_eq!(delegated_balance_for(pool_bonded_account), 25); + assert_eq!(staked_amount_for(pool_bonded_account), 15); assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(2), 2, 10)); - assert_eq!(pallet_staking::asset::stakeable_balance::(&pool_bonded_account), 16); + assert_eq!(delegated_balance_for(pool_bonded_account), 15); - assert_eq!(pallet_staking::asset::stakeable_balance::(&2), 20); + assert_eq!(stakeable_balance_for(2), 20); assert_eq!(TotalValueLocked::::get(), 15); // 3 cannot withdraw yet. @@ -429,13 +429,13 @@ fn automatic_unbonding_pools() { assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(3), 3, 10)); // final conditions are the expected. - assert_eq!(pallet_staking::asset::stakeable_balance::(&pool_bonded_account), 6); // 5 init bonded + ED + assert_eq!(delegated_balance_for(pool_bonded_account), 5); // 5 init bonded assert_eq!( - pallet_staking::asset::stakeable_balance::(&2), + stakeable_balance_for(2), init_stakeable_balance_2 ); assert_eq!( - pallet_staking::asset::stakeable_balance::(&3), + stakeable_balance_for(3), init_stakeable_balance_3 ); diff --git a/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs b/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs index ff7dd0e03417..ffa8dd09aed2 100644 --- a/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs +++ b/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs @@ -37,7 +37,7 @@ use sp_runtime::{ }; use sp_staking::{ offence::{OffenceDetails, OnOffenceHandler}, - EraIndex, SessionIndex, + EraIndex, SessionIndex, StakingInterface, DelegationInterface, Agent, }; use std::collections::BTreeMap; @@ -89,8 +89,10 @@ pub(crate) type Moment = u32; #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Runtime { + type AccountId = AccountId; type Block = Block; type AccountData = pallet_balances::AccountData; + type Lookup = sp_runtime::traits::IdentityLookup; } const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); @@ -599,7 +601,7 @@ impl ExtBuilder { // set the keys for the first session. keys: stakers .into_iter() - .map(|(id, ..)| (id, id, SessionKeys { other: (id as AccountId).into() })) + .map(|(id, ..)| (id, id, SessionKeys { other: (id as AccountId as u64).into() })) .collect(), ..Default::default() } @@ -944,7 +946,16 @@ pub(crate) fn set_minimum_election_score( } pub(crate) fn staked_amount_for(account_id: AccountId) -> Balance { - pallet_staking::asset::staked::(&account_id) + Staking::total_stake(&account_id).expect("account must be staker") +} + +pub(crate) fn delegated_balance_for(account_id: AccountId) -> Balance { + DelegatedStaking::agent_balance(Agent::from(account_id)).unwrap_or_default() +} + +/// Balance available to be staked for an account. +pub(crate) fn stakeable_balance_for(account_id: AccountId) -> Balance { + pallet_staking::asset::stakeable_balance::(&account_id) } pub(crate) fn staking_events() -> Vec> { From 25779f0caa85bc1e3fee83aa5499e1956b69152f Mon Sep 17 00:00:00 2001 From: Ankan Date: Tue, 26 Nov 2024 12:06:27 +0100 Subject: [PATCH 117/142] minor --- substrate/frame/nomination-pools/benchmarking/src/inner.rs | 2 +- substrate/frame/nomination-pools/runtime-api/src/lib.rs | 2 +- substrate/frame/nomination-pools/src/adapter.rs | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/substrate/frame/nomination-pools/benchmarking/src/inner.rs b/substrate/frame/nomination-pools/benchmarking/src/inner.rs index 7ddb78cca3f9..2837578a0659 100644 --- a/substrate/frame/nomination-pools/benchmarking/src/inner.rs +++ b/substrate/frame/nomination-pools/benchmarking/src/inner.rs @@ -981,7 +981,7 @@ mod benchmarks { #[benchmark] fn apply_slash() { - // Note: With older `TransferStake` strategy, slashing is greedy and apply_slash should + // Note: With `TransferStake` strategy, slashing is greedy and apply_slash should // always fail. // We want to fill member's unbonding pools. So let's bond with big enough amount. diff --git a/substrate/frame/nomination-pools/runtime-api/src/lib.rs b/substrate/frame/nomination-pools/runtime-api/src/lib.rs index 798fe1187f3f..4229d901bbdc 100644 --- a/substrate/frame/nomination-pools/runtime-api/src/lib.rs +++ b/substrate/frame/nomination-pools/runtime-api/src/lib.rs @@ -52,7 +52,7 @@ sp_api::decl_runtime_apis! { /// /// This can happen when the `pallet-nomination-pools` has switched to using strategy /// [`DelegateStake`](pallet_nomination_pools::adapter::DelegateStake) but the pool - /// still has funds that were staked using the older `TransferStake` strategy. Use + /// still has funds that were staked using the deprecated `TransferStake` strategy. Use /// [`migrate_pool_to_delegate_stake`](pallet_nomination_pools::Call::migrate_pool_to_delegate_stake) /// to migrate the pool. fn pool_needs_delegate_migration(pool_id: PoolId) -> bool; diff --git a/substrate/frame/nomination-pools/src/adapter.rs b/substrate/frame/nomination-pools/src/adapter.rs index f125919dabfa..9bb060cd5a1f 100644 --- a/substrate/frame/nomination-pools/src/adapter.rs +++ b/substrate/frame/nomination-pools/src/adapter.rs @@ -245,6 +245,7 @@ pub trait StakeStrategy { /// strategy in an existing runtime, storage migration is required. See /// [`migration::unversioned::DelegationStakeMigration`]. For new runtimes, it is highly recommended /// to use the [`DelegateStake`] strategy. +#[deprecated = "use DelegateStake instead"] pub struct TransferStake(PhantomData<(T, Staking)>); impl, AccountId = T::AccountId>> From 95890b546457ff54d0e304b1418883fcaec3ca13 Mon Sep 17 00:00:00 2001 From: Ankan Date: Tue, 26 Nov 2024 13:19:53 +0100 Subject: [PATCH 118/142] add missing fn --- substrate/frame/nomination-pools/src/mock.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/substrate/frame/nomination-pools/src/mock.rs b/substrate/frame/nomination-pools/src/mock.rs index 75e4fe19a953..5d4b00306d31 100644 --- a/substrate/frame/nomination-pools/src/mock.rs +++ b/substrate/frame/nomination-pools/src/mock.rs @@ -402,6 +402,11 @@ impl DelegationMigrator for DelegateMock { ) -> DispatchResult { unimplemented!("not used in current unit tests") } + + #[cfg(feature = "runtime-benchmarks")] + fn force_kill_agent(_agent: Agent) { + unimplemented!("not used in current unit tests") + } } #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] From bafe3a678074e5d73279699c9e5a007c5c8e9427 Mon Sep 17 00:00:00 2001 From: Ankan Date: Tue, 26 Nov 2024 14:32:10 +0100 Subject: [PATCH 119/142] fmt --- .../test-staking-e2e/src/lib.rs | 10 ++-------- .../test-staking-e2e/src/mock.rs | 2 +- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/lib.rs b/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/lib.rs index 96e4d112fe1b..af9f4d844ab9 100644 --- a/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/lib.rs +++ b/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/lib.rs @@ -430,14 +430,8 @@ fn automatic_unbonding_pools() { // final conditions are the expected. assert_eq!(delegated_balance_for(pool_bonded_account), 5); // 5 init bonded - assert_eq!( - stakeable_balance_for(2), - init_stakeable_balance_2 - ); - assert_eq!( - stakeable_balance_for(3), - init_stakeable_balance_3 - ); + assert_eq!(stakeable_balance_for(2), init_stakeable_balance_2); + assert_eq!(stakeable_balance_for(3), init_stakeable_balance_3); assert_eq!(TotalValueLocked::::get(), init_tvl); }); diff --git a/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs b/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs index ffa8dd09aed2..7dbca2e750cf 100644 --- a/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs +++ b/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs @@ -37,7 +37,7 @@ use sp_runtime::{ }; use sp_staking::{ offence::{OffenceDetails, OnOffenceHandler}, - EraIndex, SessionIndex, StakingInterface, DelegationInterface, Agent, + Agent, DelegationInterface, EraIndex, SessionIndex, StakingInterface, }; use std::collections::BTreeMap; From 99fb083b1cf12b9a20fe59ca80279d6717a6933b Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 27 Nov 2024 14:14:08 +0100 Subject: [PATCH 120/142] use of deprecated --- substrate/frame/nomination-pools/src/adapter.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/substrate/frame/nomination-pools/src/adapter.rs b/substrate/frame/nomination-pools/src/adapter.rs index 9bb060cd5a1f..f3e19124360c 100644 --- a/substrate/frame/nomination-pools/src/adapter.rs +++ b/substrate/frame/nomination-pools/src/adapter.rs @@ -245,9 +245,10 @@ pub trait StakeStrategy { /// strategy in an existing runtime, storage migration is required. See /// [`migration::unversioned::DelegationStakeMigration`]. For new runtimes, it is highly recommended /// to use the [`DelegateStake`] strategy. -#[deprecated = "use DelegateStake instead"] +#[deprecated = "consider migrating to DelegateStake"] pub struct TransferStake(PhantomData<(T, Staking)>); +#[allow(deprecated)] impl, AccountId = T::AccountId>> StakeStrategy for TransferStake { From 104622dbb07e7e62ddf768375d45d91fa2a858e2 Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 27 Nov 2024 16:35:43 +0100 Subject: [PATCH 121/142] allow deprecated in test-delegate-stake --- .../frame/nomination-pools/test-delegate-stake/src/mock.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/substrate/frame/nomination-pools/test-delegate-stake/src/mock.rs b/substrate/frame/nomination-pools/test-delegate-stake/src/mock.rs index d1bc4ef8ff28..2e8480e7c6c3 100644 --- a/substrate/frame/nomination-pools/test-delegate-stake/src/mock.rs +++ b/substrate/frame/nomination-pools/test-delegate-stake/src/mock.rs @@ -15,6 +15,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +#![allow(deprecated)] + use frame_election_provider_support::VoteWeight; use frame_support::{ assert_ok, derive_impl, From 1e7704d42c8591b0a9ff24753f259d769e38a779 Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 27 Nov 2024 22:24:45 +0100 Subject: [PATCH 122/142] keep the transfer stake tests --- Cargo.toml | 1 + .../test-transfer-stake/Cargo.toml | 40 + .../test-transfer-stake/src/lib.rs | 912 ++++++++++++++++++ .../test-transfer-stake/src/mock.rs | 233 +++++ 4 files changed, 1186 insertions(+) create mode 100644 substrate/frame/nomination-pools/test-transfer-stake/Cargo.toml create mode 100644 substrate/frame/nomination-pools/test-transfer-stake/src/lib.rs create mode 100644 substrate/frame/nomination-pools/test-transfer-stake/src/mock.rs diff --git a/Cargo.toml b/Cargo.toml index 93abf8e98024..53f95406e79a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -386,6 +386,7 @@ members = [ "substrate/frame/nomination-pools/fuzzer", "substrate/frame/nomination-pools/runtime-api", "substrate/frame/nomination-pools/test-delegate-stake", + "substrate/frame/nomination-pools/test-transfer-stake", "substrate/frame/offences", "substrate/frame/offences/benchmarking", "substrate/frame/paged-list", diff --git a/substrate/frame/nomination-pools/test-transfer-stake/Cargo.toml b/substrate/frame/nomination-pools/test-transfer-stake/Cargo.toml new file mode 100644 index 000000000000..7398404c2351 --- /dev/null +++ b/substrate/frame/nomination-pools/test-transfer-stake/Cargo.toml @@ -0,0 +1,40 @@ +[package] +name = "pallet-nomination-pools-test-transfer-stake" +version = "1.0.0" +authors.workspace = true +edition.workspace = true +license = "Apache-2.0" +homepage.workspace = true +repository.workspace = true +description = "FRAME nomination pools pallet tests with the staking pallet" +publish = false + +[lints] +workspace = true + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dev-dependencies] +codec = { features = ["derive"], workspace = true, default-features = true } +scale-info = { features = ["derive"], workspace = true, default-features = true } + +sp-runtime = { workspace = true, default-features = true } +sp-io = { workspace = true, default-features = true } +sp-std = { workspace = true, default-features = true } +sp-staking = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } + +frame-system = { workspace = true, default-features = true } +frame-support = { workspace = true, default-features = true } +frame-election-provider-support = { workspace = true, default-features = true } + +pallet-timestamp = { workspace = true, default-features = true } +pallet-balances = { workspace = true, default-features = true } +pallet-staking = { workspace = true, default-features = true } +pallet-bags-list = { workspace = true, default-features = true } +pallet-staking-reward-curve = { workspace = true, default-features = true } +pallet-nomination-pools = { workspace = true, default-features = true } + +sp-tracing = { workspace = true, default-features = true } +log = { workspace = true, default-features = true } diff --git a/substrate/frame/nomination-pools/test-transfer-stake/src/lib.rs b/substrate/frame/nomination-pools/test-transfer-stake/src/lib.rs new file mode 100644 index 000000000000..cc39cfee91c8 --- /dev/null +++ b/substrate/frame/nomination-pools/test-transfer-stake/src/lib.rs @@ -0,0 +1,912 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#![cfg(test)] + +mod mock; + +use frame_support::{assert_noop, assert_ok, traits::Currency}; +use mock::*; +use pallet_nomination_pools::{ + BondExtra, BondedPools, Error as PoolsError, Event as PoolsEvent, LastPoolId, PoolMember, + PoolMembers, PoolState, +}; +use pallet_staking::{ + CurrentEra, Error as StakingError, Event as StakingEvent, Payee, RewardDestination, +}; +use sp_runtime::{bounded_btree_map, traits::Zero}; + +#[test] +fn pool_lifecycle_e2e() { + new_test_ext().execute_with(|| { + assert_eq!(Balances::minimum_balance(), 5); + assert_eq!(CurrentEra::::get(), None); + + // create the pool, we know this has id 1. + assert_ok!(Pools::create(RuntimeOrigin::signed(10), 50, 10, 10, 10)); + assert_eq!(LastPoolId::::get(), 1); + + // have the pool nominate. + assert_ok!(Pools::nominate(RuntimeOrigin::signed(10), 1, vec![1, 2, 3])); + + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: 50 }] + ); + assert_eq!( + pool_events_since_last_call(), + vec![ + PoolsEvent::Created { depositor: 10, pool_id: 1 }, + PoolsEvent::Bonded { member: 10, pool_id: 1, bonded: 50, joined: true }, + ] + ); + + // have two members join + assert_ok!(Pools::join(RuntimeOrigin::signed(20), 10, 1)); + assert_ok!(Pools::join(RuntimeOrigin::signed(21), 10, 1)); + + assert_eq!( + staking_events_since_last_call(), + vec![ + StakingEvent::Bonded { stash: POOL1_BONDED, amount: 10 }, + StakingEvent::Bonded { stash: POOL1_BONDED, amount: 10 }, + ] + ); + assert_eq!( + pool_events_since_last_call(), + vec![ + PoolsEvent::Bonded { member: 20, pool_id: 1, bonded: 10, joined: true }, + PoolsEvent::Bonded { member: 21, pool_id: 1, bonded: 10, joined: true }, + ] + ); + + // pool goes into destroying + assert_ok!(Pools::set_state(RuntimeOrigin::signed(10), 1, PoolState::Destroying)); + + // depositor cannot unbond yet. + assert_noop!( + Pools::unbond(RuntimeOrigin::signed(10), 10, 50), + PoolsError::::MinimumBondNotMet, + ); + + // now the members want to unbond. + assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 10)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(21), 21, 10)); + + assert_eq!(PoolMembers::::get(20).unwrap().unbonding_eras.len(), 1); + assert_eq!(PoolMembers::::get(20).unwrap().points, 0); + assert_eq!(PoolMembers::::get(21).unwrap().unbonding_eras.len(), 1); + assert_eq!(PoolMembers::::get(21).unwrap().points, 0); + + assert_eq!( + staking_events_since_last_call(), + vec![ + StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 }, + StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 }, + ] + ); + assert_eq!( + pool_events_since_last_call(), + vec![ + PoolsEvent::StateChanged { pool_id: 1, new_state: PoolState::Destroying }, + PoolsEvent::Unbonded { member: 20, pool_id: 1, points: 10, balance: 10, era: 3 }, + PoolsEvent::Unbonded { member: 21, pool_id: 1, points: 10, balance: 10, era: 3 }, + ] + ); + + // depositor cannot still unbond + assert_noop!( + Pools::unbond(RuntimeOrigin::signed(10), 10, 50), + PoolsError::::MinimumBondNotMet, + ); + + for e in 1..BondingDuration::get() { + CurrentEra::::set(Some(e)); + assert_noop!( + Pools::withdraw_unbonded(RuntimeOrigin::signed(20), 20, 0), + PoolsError::::CannotWithdrawAny + ); + } + + // members are now unlocked. + CurrentEra::::set(Some(BondingDuration::get())); + + // depositor cannot still unbond + assert_noop!( + Pools::unbond(RuntimeOrigin::signed(10), 10, 50), + PoolsError::::MinimumBondNotMet, + ); + + // but members can now withdraw. + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(20), 20, 0)); + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(21), 21, 0)); + assert!(PoolMembers::::get(20).is_none()); + assert!(PoolMembers::::get(21).is_none()); + + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Withdrawn { stash: POOL1_BONDED, amount: 20 },] + ); + assert_eq!( + pool_events_since_last_call(), + vec![ + PoolsEvent::Withdrawn { member: 20, pool_id: 1, points: 10, balance: 10 }, + PoolsEvent::MemberRemoved { pool_id: 1, member: 20, released_balance: 0 }, + PoolsEvent::Withdrawn { member: 21, pool_id: 1, points: 10, balance: 10 }, + PoolsEvent::MemberRemoved { pool_id: 1, member: 21, released_balance: 0 }, + ] + ); + + // as soon as all members have left, the depositor can try to unbond, but since the + // min-nominator intention is set, they must chill first. + assert_noop!( + Pools::unbond(RuntimeOrigin::signed(10), 10, 50), + pallet_staking::Error::::InsufficientBond + ); + + assert_ok!(Pools::chill(RuntimeOrigin::signed(10), 1)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(10), 10, 50)); + + assert_eq!( + staking_events_since_last_call(), + vec![ + StakingEvent::Chilled { stash: POOL1_BONDED }, + StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 50 }, + ] + ); + assert_eq!( + pool_events_since_last_call(), + vec![PoolsEvent::Unbonded { member: 10, pool_id: 1, points: 50, balance: 50, era: 6 }] + ); + + // waiting another bonding duration: + CurrentEra::::set(Some(BondingDuration::get() * 2)); + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(10), 10, 1)); + + // pools is fully destroyed now. + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Withdrawn { stash: POOL1_BONDED, amount: 50 },] + ); + assert_eq!( + pool_events_since_last_call(), + vec![ + PoolsEvent::Withdrawn { member: 10, pool_id: 1, points: 50, balance: 50 }, + PoolsEvent::MemberRemoved { pool_id: 1, member: 10, released_balance: 0 }, + PoolsEvent::Destroyed { pool_id: 1 } + ] + ); + }) +} + +#[test] +fn destroy_pool_with_erroneous_consumer() { + new_test_ext().execute_with(|| { + // create the pool, we know this has id 1. + assert_ok!(Pools::create(RuntimeOrigin::signed(10), 50, 10, 10, 10)); + assert_eq!(LastPoolId::::get(), 1); + + // expect consumers on pool account to be 2 (staking lock and an explicit inc by staking). + assert_eq!(frame_system::Pallet::::consumers(&POOL1_BONDED), 2); + + // increment consumer by 1 reproducing the erroneous consumer bug. + // refer https://github.com/paritytech/polkadot-sdk/issues/4440. + assert_ok!(frame_system::Pallet::::inc_consumers(&POOL1_BONDED)); + assert_eq!(frame_system::Pallet::::consumers(&POOL1_BONDED), 3); + + // have the pool nominate. + assert_ok!(Pools::nominate(RuntimeOrigin::signed(10), 1, vec![1, 2, 3])); + + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: 50 }] + ); + assert_eq!( + pool_events_since_last_call(), + vec![ + PoolsEvent::Created { depositor: 10, pool_id: 1 }, + PoolsEvent::Bonded { member: 10, pool_id: 1, bonded: 50, joined: true }, + ] + ); + + // pool goes into destroying + assert_ok!(Pools::set_state(RuntimeOrigin::signed(10), 1, PoolState::Destroying)); + + assert_eq!( + pool_events_since_last_call(), + vec![PoolsEvent::StateChanged { pool_id: 1, new_state: PoolState::Destroying },] + ); + + // move to era 1 + CurrentEra::::set(Some(1)); + + // depositor need to chill before unbonding + assert_noop!( + Pools::unbond(RuntimeOrigin::signed(10), 10, 50), + pallet_staking::Error::::InsufficientBond + ); + + assert_ok!(Pools::chill(RuntimeOrigin::signed(10), 1)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(10), 10, 50)); + + assert_eq!( + staking_events_since_last_call(), + vec![ + StakingEvent::Chilled { stash: POOL1_BONDED }, + StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 50 }, + ] + ); + assert_eq!( + pool_events_since_last_call(), + vec![PoolsEvent::Unbonded { + member: 10, + pool_id: 1, + points: 50, + balance: 50, + era: 1 + 3 + }] + ); + + // waiting bonding duration: + CurrentEra::::set(Some(1 + 3)); + // this should work even with an extra consumer count on pool account. + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(10), 10, 1)); + + // pools is fully destroyed now. + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Withdrawn { stash: POOL1_BONDED, amount: 50 },] + ); + assert_eq!( + pool_events_since_last_call(), + vec![ + PoolsEvent::Withdrawn { member: 10, pool_id: 1, points: 50, balance: 50 }, + PoolsEvent::MemberRemoved { pool_id: 1, member: 10, released_balance: 0 }, + PoolsEvent::Destroyed { pool_id: 1 } + ] + ); + }) +} + +#[test] +fn pool_chill_e2e() { + new_test_ext().execute_with(|| { + assert_eq!(Balances::minimum_balance(), 5); + assert_eq!(CurrentEra::::get(), None); + + // create the pool, we know this has id 1. + assert_ok!(Pools::create(RuntimeOrigin::signed(10), 50, 10, 10, 10)); + assert_eq!(LastPoolId::::get(), 1); + + // have the pool nominate. + assert_ok!(Pools::nominate(RuntimeOrigin::signed(10), 1, vec![1, 2, 3])); + + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: 50 }] + ); + assert_eq!( + pool_events_since_last_call(), + vec![ + PoolsEvent::Created { depositor: 10, pool_id: 1 }, + PoolsEvent::Bonded { member: 10, pool_id: 1, bonded: 50, joined: true }, + ] + ); + + // have two members join + assert_ok!(Pools::join(RuntimeOrigin::signed(20), 10, 1)); + assert_ok!(Pools::join(RuntimeOrigin::signed(21), 10, 1)); + + assert_eq!( + staking_events_since_last_call(), + vec![ + StakingEvent::Bonded { stash: POOL1_BONDED, amount: 10 }, + StakingEvent::Bonded { stash: POOL1_BONDED, amount: 10 }, + ] + ); + assert_eq!( + pool_events_since_last_call(), + vec![ + PoolsEvent::Bonded { member: 20, pool_id: 1, bonded: 10, joined: true }, + PoolsEvent::Bonded { member: 21, pool_id: 1, bonded: 10, joined: true }, + ] + ); + + // in case depositor does not have more than `MinNominatorBond` staked, we can end up in + // situation where a member unbonding would cause pool balance to drop below + // `MinNominatorBond` and hence not allowed. This can happen if the `MinNominatorBond` is + // increased after the pool is created. + assert_ok!(Staking::set_staking_configs( + RuntimeOrigin::root(), + pallet_staking::ConfigOp::Set(55), // minimum nominator bond + pallet_staking::ConfigOp::Noop, + pallet_staking::ConfigOp::Noop, + pallet_staking::ConfigOp::Noop, + pallet_staking::ConfigOp::Noop, + pallet_staking::ConfigOp::Noop, + pallet_staking::ConfigOp::Noop, + )); + + // members can unbond as long as total stake of the pool is above min nominator bond + assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 10),); + assert_eq!(PoolMembers::::get(20).unwrap().unbonding_eras.len(), 1); + assert_eq!(PoolMembers::::get(20).unwrap().points, 0); + + // this member cannot unbond since it will cause `pool stake < MinNominatorBond` + assert_noop!( + Pools::unbond(RuntimeOrigin::signed(21), 21, 10), + StakingError::::InsufficientBond, + ); + + // members can call `chill` permissionlessly now + assert_ok!(Pools::chill(RuntimeOrigin::signed(20), 1)); + + // now another member can unbond. + assert_ok!(Pools::unbond(RuntimeOrigin::signed(21), 21, 10)); + assert_eq!(PoolMembers::::get(21).unwrap().unbonding_eras.len(), 1); + assert_eq!(PoolMembers::::get(21).unwrap().points, 0); + + // nominator can not resume nomination until depositor have enough stake + assert_noop!( + Pools::nominate(RuntimeOrigin::signed(10), 1, vec![1, 2, 3]), + PoolsError::::MinimumBondNotMet, + ); + + // other members joining pool does not affect the depositor's ability to resume nomination + assert_ok!(Pools::join(RuntimeOrigin::signed(22), 10, 1)); + + assert_noop!( + Pools::nominate(RuntimeOrigin::signed(10), 1, vec![1, 2, 3]), + PoolsError::::MinimumBondNotMet, + ); + + // depositor can bond extra stake + assert_ok!(Pools::bond_extra(RuntimeOrigin::signed(10), BondExtra::FreeBalance(10))); + + // `chill` can not be called permissionlessly anymore + assert_noop!( + Pools::chill(RuntimeOrigin::signed(20), 1), + PoolsError::::NotNominator, + ); + + // now nominator can resume nomination + assert_ok!(Pools::nominate(RuntimeOrigin::signed(10), 1, vec![1, 2, 3])); + + // skip to make the unbonding period end. + CurrentEra::::set(Some(BondingDuration::get())); + + // members can now withdraw. + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(20), 20, 0)); + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(21), 21, 0)); + + assert_eq!( + staking_events_since_last_call(), + vec![ + StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 }, + StakingEvent::Chilled { stash: POOL1_BONDED }, + StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 }, + StakingEvent::Bonded { stash: POOL1_BONDED, amount: 10 }, // other member bonding + StakingEvent::Bonded { stash: POOL1_BONDED, amount: 10 }, // depositor bond extra + StakingEvent::Withdrawn { stash: POOL1_BONDED, amount: 20 }, + ] + ); + }) +} + +#[test] +fn pool_slash_e2e() { + new_test_ext().execute_with(|| { + ExistentialDeposit::set(1); + assert_eq!(Balances::minimum_balance(), 1); + assert_eq!(CurrentEra::::get(), None); + + // create the pool, we know this has id 1. + assert_ok!(Pools::create(RuntimeOrigin::signed(10), 40, 10, 10, 10)); + assert_eq!(LastPoolId::::get(), 1); + + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: 40 }] + ); + assert_eq!( + pool_events_since_last_call(), + vec![ + PoolsEvent::Created { depositor: 10, pool_id: 1 }, + PoolsEvent::Bonded { member: 10, pool_id: 1, bonded: 40, joined: true }, + ] + ); + + assert_eq!( + Payee::::get(POOL1_BONDED), + Some(RewardDestination::Account(POOL1_REWARD)) + ); + + // have two members join + assert_ok!(Pools::join(RuntimeOrigin::signed(20), 20, 1)); + assert_ok!(Pools::join(RuntimeOrigin::signed(21), 20, 1)); + + assert_eq!( + staking_events_since_last_call(), + vec![ + StakingEvent::Bonded { stash: POOL1_BONDED, amount: 20 }, + StakingEvent::Bonded { stash: POOL1_BONDED, amount: 20 } + ] + ); + assert_eq!( + pool_events_since_last_call(), + vec![ + PoolsEvent::Bonded { member: 20, pool_id: 1, bonded: 20, joined: true }, + PoolsEvent::Bonded { member: 21, pool_id: 1, bonded: 20, joined: true }, + ] + ); + + // now let's progress a bit. + CurrentEra::::set(Some(1)); + + // 20 / 80 of the total funds are unlocked, and safe from any further slash. + assert_ok!(Pools::unbond(RuntimeOrigin::signed(10), 10, 10)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 10)); + + assert_eq!( + staking_events_since_last_call(), + vec![ + StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 }, + StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 } + ] + ); + assert_eq!( + pool_events_since_last_call(), + vec![ + PoolsEvent::Unbonded { member: 10, pool_id: 1, balance: 10, points: 10, era: 4 }, + PoolsEvent::Unbonded { member: 20, pool_id: 1, balance: 10, points: 10, era: 4 } + ] + ); + + CurrentEra::::set(Some(2)); + + // note: depositor cannot fully unbond at this point. + // these funds will still get slashed. + assert_ok!(Pools::unbond(RuntimeOrigin::signed(10), 10, 10)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 10)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(21), 21, 10)); + + assert_eq!( + staking_events_since_last_call(), + vec![ + StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 }, + StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 }, + StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 }, + ] + ); + + assert_eq!( + pool_events_since_last_call(), + vec![ + PoolsEvent::Unbonded { member: 10, pool_id: 1, balance: 10, points: 10, era: 5 }, + PoolsEvent::Unbonded { member: 20, pool_id: 1, balance: 10, points: 10, era: 5 }, + PoolsEvent::Unbonded { member: 21, pool_id: 1, balance: 10, points: 10, era: 5 }, + ] + ); + + // At this point, 20 are safe from slash, 30 are unlocking but vulnerable to slash, and + // another 30 are active and vulnerable to slash. Let's slash half of them. + pallet_staking::slashing::do_slash::( + &POOL1_BONDED, + 30, + &mut Default::default(), + &mut Default::default(), + 2, // slash era 2, affects chunks at era 5 onwards. + ); + + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Slashed { staker: POOL1_BONDED, amount: 30 }] + ); + assert_eq!( + pool_events_since_last_call(), + vec![ + // 30 has been slashed to 15 (15 slash) + PoolsEvent::UnbondingPoolSlashed { pool_id: 1, era: 5, balance: 15 }, + // 30 has been slashed to 15 (15 slash) + PoolsEvent::PoolSlashed { pool_id: 1, balance: 15 } + ] + ); + + CurrentEra::::set(Some(3)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(21), 21, 10)); + + assert_eq!( + PoolMembers::::get(21).unwrap(), + PoolMember { + pool_id: 1, + points: 0, + last_recorded_reward_counter: Zero::zero(), + // the 10 points unlocked just now correspond to 5 points in the unbond pool. + unbonding_eras: bounded_btree_map!(5 => 10, 6 => 5) + } + ); + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 5 }] + ); + assert_eq!( + pool_events_since_last_call(), + vec![PoolsEvent::Unbonded { member: 21, pool_id: 1, balance: 5, points: 5, era: 6 }] + ); + + // now we start withdrawing. we do it all at once, at era 6 where 20 and 21 are fully free. + CurrentEra::::set(Some(6)); + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(20), 20, 0)); + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(21), 21, 0)); + + assert_eq!( + pool_events_since_last_call(), + vec![ + // 20 had unbonded 10 safely, and 10 got slashed by half. + PoolsEvent::Withdrawn { member: 20, pool_id: 1, balance: 10 + 5, points: 20 }, + PoolsEvent::MemberRemoved { pool_id: 1, member: 20, released_balance: 0 }, + // 21 unbonded all of it after the slash + PoolsEvent::Withdrawn { member: 21, pool_id: 1, balance: 5 + 5, points: 15 }, + PoolsEvent::MemberRemoved { pool_id: 1, member: 21, released_balance: 0 } + ] + ); + assert_eq!( + staking_events_since_last_call(), + // a 10 (un-slashed) + 10/2 (slashed) balance from 10 has also been unlocked + vec![StakingEvent::Withdrawn { stash: POOL1_BONDED, amount: 15 + 10 + 15 }] + ); + + // now, finally, we can unbond the depositor further than their current limit. + assert_ok!(Pools::set_state(RuntimeOrigin::signed(10), 1, PoolState::Destroying)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(10), 10, 20)); + + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 }] + ); + assert_eq!( + pool_events_since_last_call(), + vec![ + PoolsEvent::StateChanged { pool_id: 1, new_state: PoolState::Destroying }, + PoolsEvent::Unbonded { member: 10, pool_id: 1, points: 10, balance: 10, era: 9 } + ] + ); + + CurrentEra::::set(Some(9)); + assert_eq!( + PoolMembers::::get(10).unwrap(), + PoolMember { + pool_id: 1, + points: 0, + last_recorded_reward_counter: Zero::zero(), + unbonding_eras: bounded_btree_map!(4 => 10, 5 => 10, 9 => 10) + } + ); + // withdraw the depositor, they should lose 12 balance in total due to slash. + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(10), 10, 0)); + + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Withdrawn { stash: POOL1_BONDED, amount: 10 }] + ); + assert_eq!( + pool_events_since_last_call(), + vec![ + PoolsEvent::Withdrawn { member: 10, pool_id: 1, balance: 10 + 15, points: 30 }, + PoolsEvent::MemberRemoved { pool_id: 1, member: 10, released_balance: 0 }, + PoolsEvent::Destroyed { pool_id: 1 } + ] + ); + }); +} + +#[test] +fn pool_slash_proportional() { + // a typical example where 3 pool members unbond in era 99, 100, and 101, and a slash that + // happened in era 100 should only affect the latter two. + new_test_ext().execute_with(|| { + ExistentialDeposit::set(1); + BondingDuration::set(28); + assert_eq!(Balances::minimum_balance(), 1); + assert_eq!(CurrentEra::::get(), None); + + // create the pool, we know this has id 1. + assert_ok!(Pools::create(RuntimeOrigin::signed(10), 40, 10, 10, 10)); + assert_eq!(LastPoolId::::get(), 1); + + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: 40 }] + ); + assert_eq!( + pool_events_since_last_call(), + vec![ + PoolsEvent::Created { depositor: 10, pool_id: 1 }, + PoolsEvent::Bonded { member: 10, pool_id: 1, bonded: 40, joined: true }, + ] + ); + + // have two members join + let bond = 20; + assert_ok!(Pools::join(RuntimeOrigin::signed(20), bond, 1)); + assert_ok!(Pools::join(RuntimeOrigin::signed(21), bond, 1)); + assert_ok!(Pools::join(RuntimeOrigin::signed(22), bond, 1)); + + assert_eq!( + staking_events_since_last_call(), + vec![ + StakingEvent::Bonded { stash: POOL1_BONDED, amount: bond }, + StakingEvent::Bonded { stash: POOL1_BONDED, amount: bond }, + StakingEvent::Bonded { stash: POOL1_BONDED, amount: bond }, + ] + ); + assert_eq!( + pool_events_since_last_call(), + vec![ + PoolsEvent::Bonded { member: 20, pool_id: 1, bonded: bond, joined: true }, + PoolsEvent::Bonded { member: 21, pool_id: 1, bonded: bond, joined: true }, + PoolsEvent::Bonded { member: 22, pool_id: 1, bonded: bond, joined: true }, + ] + ); + + // now let's progress a lot. + CurrentEra::::set(Some(99)); + + // and unbond + assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, bond)); + + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: bond },] + ); + assert_eq!( + pool_events_since_last_call(), + vec![PoolsEvent::Unbonded { + member: 20, + pool_id: 1, + balance: bond, + points: bond, + era: 127 + }] + ); + + CurrentEra::::set(Some(100)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(21), 21, bond)); + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: bond },] + ); + assert_eq!( + pool_events_since_last_call(), + vec![PoolsEvent::Unbonded { + member: 21, + pool_id: 1, + balance: bond, + points: bond, + era: 128 + }] + ); + + CurrentEra::::set(Some(101)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(22), 22, bond)); + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: bond },] + ); + assert_eq!( + pool_events_since_last_call(), + vec![PoolsEvent::Unbonded { + member: 22, + pool_id: 1, + balance: bond, + points: bond, + era: 129 + }] + ); + + // Apply a slash that happened in era 100. This is typically applied with a delay. + // Of the total 100, 50 is slashed. + assert_eq!(BondedPools::::get(1).unwrap().points, 40); + pallet_staking::slashing::do_slash::( + &POOL1_BONDED, + 50, + &mut Default::default(), + &mut Default::default(), + 100, + ); + + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Slashed { staker: POOL1_BONDED, amount: 50 }] + ); + assert_eq!( + pool_events_since_last_call(), + vec![ + // This era got slashed 12.5, which rounded up to 13. + PoolsEvent::UnbondingPoolSlashed { pool_id: 1, era: 128, balance: 7 }, + // This era got slashed 12 instead of 12.5 because an earlier chunk got 0.5 more + // slashed, and 12 is all the remaining slash + PoolsEvent::UnbondingPoolSlashed { pool_id: 1, era: 129, balance: 8 }, + // Bonded pool got slashed for 25, remaining 15 in it. + PoolsEvent::PoolSlashed { pool_id: 1, balance: 15 } + ] + ); + }); +} + +#[test] +fn pool_slash_non_proportional_only_bonded_pool() { + // A typical example where a pool member unbonds in era 99, and they can get away with a slash + // that happened in era 100, as long as the pool has enough active bond to cover the slash. If + // everything else in the slashing/staking system works, this should always be the case. + // Nonetheless, `ledger.slash` has been written such that it will slash greedily from any chunk + // if it runs out of chunks that it thinks should be affected by the slash. + new_test_ext().execute_with(|| { + ExistentialDeposit::set(1); + BondingDuration::set(28); + assert_eq!(Balances::minimum_balance(), 1); + assert_eq!(CurrentEra::::get(), None); + + // create the pool, we know this has id 1. + assert_ok!(Pools::create(RuntimeOrigin::signed(10), 40, 10, 10, 10)); + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: 40 }] + ); + assert_eq!( + pool_events_since_last_call(), + vec![ + PoolsEvent::Created { depositor: 10, pool_id: 1 }, + PoolsEvent::Bonded { member: 10, pool_id: 1, bonded: 40, joined: true }, + ] + ); + + // have two members join + let bond = 20; + assert_ok!(Pools::join(RuntimeOrigin::signed(20), bond, 1)); + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: bond }] + ); + assert_eq!( + pool_events_since_last_call(), + vec![PoolsEvent::Bonded { member: 20, pool_id: 1, bonded: bond, joined: true }] + ); + + // progress and unbond. + CurrentEra::::set(Some(99)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, bond)); + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: bond }] + ); + assert_eq!( + pool_events_since_last_call(), + vec![PoolsEvent::Unbonded { + member: 20, + pool_id: 1, + balance: bond, + points: bond, + era: 127 + }] + ); + + // slash for 30. This will be deducted only from the bonded pool. + CurrentEra::::set(Some(100)); + assert_eq!(BondedPools::::get(1).unwrap().points, 40); + pallet_staking::slashing::do_slash::( + &POOL1_BONDED, + 30, + &mut Default::default(), + &mut Default::default(), + 100, + ); + + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Slashed { staker: POOL1_BONDED, amount: 30 }] + ); + assert_eq!( + pool_events_since_last_call(), + vec![PoolsEvent::PoolSlashed { pool_id: 1, balance: 10 }] + ); + }); +} + +#[test] +fn pool_slash_non_proportional_bonded_pool_and_chunks() { + // An uncommon example where even though some funds are unlocked such that they should not be + // affected by a slash, we still slash out of them. This should not happen at all. If a + // nomination has unbonded, from the next era onwards, their exposure will drop, so if an era + // happens in that era, then their share of that slash should naturally be less, such that only + // their active ledger stake is enough to compensate it. + new_test_ext().execute_with(|| { + ExistentialDeposit::set(1); + BondingDuration::set(28); + assert_eq!(Balances::minimum_balance(), 1); + assert_eq!(CurrentEra::::get(), None); + + // create the pool, we know this has id 1. + assert_ok!(Pools::create(RuntimeOrigin::signed(10), 40, 10, 10, 10)); + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: 40 }] + ); + assert_eq!( + pool_events_since_last_call(), + vec![ + PoolsEvent::Created { depositor: 10, pool_id: 1 }, + PoolsEvent::Bonded { member: 10, pool_id: 1, bonded: 40, joined: true }, + ] + ); + + // have two members join + let bond = 20; + assert_ok!(Pools::join(RuntimeOrigin::signed(20), bond, 1)); + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: bond }] + ); + assert_eq!( + pool_events_since_last_call(), + vec![PoolsEvent::Bonded { member: 20, pool_id: 1, bonded: bond, joined: true }] + ); + + // progress and unbond. + CurrentEra::::set(Some(99)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, bond)); + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: bond }] + ); + assert_eq!( + pool_events_since_last_call(), + vec![PoolsEvent::Unbonded { + member: 20, + pool_id: 1, + balance: bond, + points: bond, + era: 127 + }] + ); + + // slash 50. This will be deducted only from the bonded pool and one of the unbonding pools. + CurrentEra::::set(Some(100)); + assert_eq!(BondedPools::::get(1).unwrap().points, 40); + pallet_staking::slashing::do_slash::( + &POOL1_BONDED, + 50, + &mut Default::default(), + &mut Default::default(), + 100, + ); + + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Slashed { staker: POOL1_BONDED, amount: 50 }] + ); + assert_eq!( + pool_events_since_last_call(), + vec![ + // out of 20, 10 was taken. + PoolsEvent::UnbondingPoolSlashed { pool_id: 1, era: 127, balance: 10 }, + // out of 40, all was taken. + PoolsEvent::PoolSlashed { pool_id: 1, balance: 0 } + ] + ); + }); +} diff --git a/substrate/frame/nomination-pools/test-transfer-stake/src/mock.rs b/substrate/frame/nomination-pools/test-transfer-stake/src/mock.rs new file mode 100644 index 000000000000..fdab925b06e6 --- /dev/null +++ b/substrate/frame/nomination-pools/test-transfer-stake/src/mock.rs @@ -0,0 +1,233 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#![allow(deprecated)] + +use frame_election_provider_support::VoteWeight; +use frame_support::{ + assert_ok, derive_impl, + pallet_prelude::*, + parameter_types, + traits::{ConstU64, ConstU8, VariantCountOf}, + PalletId, +}; +use sp_runtime::{ + traits::{Convert, IdentityLookup}, + BuildStorage, FixedU128, Perbill, +}; + +type AccountId = u128; +type BlockNumber = u64; +type Balance = u128; + +pub(crate) type T = Runtime; + +pub(crate) const POOL1_BONDED: AccountId = 20318131474730217858575332831085u128; +pub(crate) const POOL1_REWARD: AccountId = 20397359637244482196168876781421u128; + +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] +impl frame_system::Config for Runtime { + type AccountId = AccountId; + type Lookup = IdentityLookup; + type Block = Block; + type AccountData = pallet_balances::AccountData; +} + +impl pallet_timestamp::Config for Runtime { + type Moment = u64; + type OnTimestampSet = (); + type MinimumPeriod = ConstU64<5>; + type WeightInfo = (); +} + +parameter_types! { + pub static ExistentialDeposit: Balance = 5; +} + +#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig)] +impl pallet_balances::Config for Runtime { + type Balance = Balance; + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type FreezeIdentifier = RuntimeFreezeReason; + type MaxFreezes = VariantCountOf; + type RuntimeFreezeReason = RuntimeFreezeReason; +} + +pallet_staking_reward_curve::build! { + const I_NPOS: sp_runtime::curve::PiecewiseLinear<'static> = curve!( + min_inflation: 0_025_000, + max_inflation: 0_100_000, + ideal_stake: 0_500_000, + falloff: 0_050_000, + max_piece_count: 40, + test_precision: 0_005_000, + ); +} + +parameter_types! { + pub const RewardCurve: &'static sp_runtime::curve::PiecewiseLinear<'static> = &I_NPOS; + pub static BondingDuration: u32 = 3; +} + +#[derive_impl(pallet_staking::config_preludes::TestDefaultConfig)] +impl pallet_staking::Config for Runtime { + type Currency = Balances; + type UnixTime = pallet_timestamp::Pallet; + type AdminOrigin = frame_system::EnsureRoot; + type BondingDuration = BondingDuration; + type EraPayout = pallet_staking::ConvertCurve; + type ElectionProvider = + frame_election_provider_support::NoElection<(AccountId, BlockNumber, Staking, ())>; + type GenesisElectionProvider = Self::ElectionProvider; + type VoterList = VoterList; + type TargetList = pallet_staking::UseValidatorsMap; + type EventListeners = Pools; + type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; +} + +parameter_types! { + pub static BagThresholds: &'static [VoteWeight] = &[10, 20, 30, 40, 50, 60, 1_000, 2_000, 10_000]; +} + +type VoterBagsListInstance = pallet_bags_list::Instance1; +impl pallet_bags_list::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type WeightInfo = (); + type BagThresholds = BagThresholds; + type ScoreProvider = Staking; + type Score = VoteWeight; +} + +pub struct BalanceToU256; +impl Convert for BalanceToU256 { + fn convert(n: Balance) -> sp_core::U256 { + n.into() + } +} + +pub struct U256ToBalance; +impl Convert for U256ToBalance { + fn convert(n: sp_core::U256) -> Balance { + n.try_into().unwrap() + } +} + +parameter_types! { + pub const PostUnbondingPoolsWindow: u32 = 10; + pub const PoolsPalletId: PalletId = PalletId(*b"py/nopls"); +} + +impl pallet_nomination_pools::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type WeightInfo = (); + type Currency = Balances; + type RuntimeFreezeReason = RuntimeFreezeReason; + type RewardCounter = FixedU128; + type BalanceToU256 = BalanceToU256; + type U256ToBalance = U256ToBalance; + type StakeAdapter = pallet_nomination_pools::adapter::TransferStake; + type PostUnbondingPoolsWindow = PostUnbondingPoolsWindow; + type MaxMetadataLen = ConstU32<256>; + type MaxUnbonding = ConstU32<8>; + type MaxPointsToBalance = ConstU8<10>; + type PalletId = PoolsPalletId; + type AdminOrigin = frame_system::EnsureRoot; +} + +type Block = frame_system::mocking::MockBlock; + +frame_support::construct_runtime!( + pub enum Runtime { + System: frame_system, + Timestamp: pallet_timestamp, + Balances: pallet_balances, + Staking: pallet_staking, + VoterList: pallet_bags_list::, + Pools: pallet_nomination_pools, + } +); + +pub fn new_test_ext() -> sp_io::TestExternalities { + sp_tracing::try_init_simple(); + let mut storage = frame_system::GenesisConfig::::default().build_storage().unwrap(); + let _ = pallet_nomination_pools::GenesisConfig:: { + min_join_bond: 2, + min_create_bond: 2, + max_pools: Some(3), + max_members_per_pool: Some(5), + max_members: Some(3 * 5), + global_max_commission: Some(Perbill::from_percent(90)), + } + .assimilate_storage(&mut storage) + .unwrap(); + + let _ = pallet_balances::GenesisConfig:: { + balances: vec![(10, 100), (20, 100), (21, 100), (22, 100)], + } + .assimilate_storage(&mut storage) + .unwrap(); + + let mut ext = sp_io::TestExternalities::from(storage); + + ext.execute_with(|| { + // for events to be deposited. + frame_system::Pallet::::set_block_number(1); + + // set some limit for nominations. + assert_ok!(Staking::set_staking_configs( + RuntimeOrigin::root(), + pallet_staking::ConfigOp::Set(10), // minimum nominator bond + pallet_staking::ConfigOp::Noop, + pallet_staking::ConfigOp::Noop, + pallet_staking::ConfigOp::Noop, + pallet_staking::ConfigOp::Noop, + pallet_staking::ConfigOp::Noop, + pallet_staking::ConfigOp::Noop, + )); + }); + + ext +} + +parameter_types! { + static ObservedEventsPools: usize = 0; + static ObservedEventsStaking: usize = 0; + static ObservedEventsBalances: usize = 0; +} + +pub(crate) fn pool_events_since_last_call() -> Vec> { + let events = System::events() + .into_iter() + .map(|r| r.event) + .filter_map(|e| if let RuntimeEvent::Pools(inner) = e { Some(inner) } else { None }) + .collect::>(); + let already_seen = ObservedEventsPools::get(); + ObservedEventsPools::set(events.len()); + events.into_iter().skip(already_seen).collect() +} + +pub(crate) fn staking_events_since_last_call() -> Vec> { + let events = System::events() + .into_iter() + .map(|r| r.event) + .filter_map(|e| if let RuntimeEvent::Staking(inner) = e { Some(inner) } else { None }) + .collect::>(); + let already_seen = ObservedEventsStaking::get(); + ObservedEventsStaking::set(events.len()); + events.into_iter().skip(already_seen).collect() +} From 072be367896906b31d2b5fc5dda70bbe4c90a733 Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 27 Nov 2024 22:38:35 +0100 Subject: [PATCH 123/142] get rid of test transfer stake tests --- Cargo.toml | 1 - .../test-delegate-stake/src/lib.rs | 2 + .../test-transfer-stake/Cargo.toml | 40 - .../test-transfer-stake/src/lib.rs | 912 ------------------ .../test-transfer-stake/src/mock.rs | 234 ----- 5 files changed, 2 insertions(+), 1187 deletions(-) delete mode 100644 substrate/frame/nomination-pools/test-transfer-stake/Cargo.toml delete mode 100644 substrate/frame/nomination-pools/test-transfer-stake/src/lib.rs delete mode 100644 substrate/frame/nomination-pools/test-transfer-stake/src/mock.rs diff --git a/Cargo.toml b/Cargo.toml index b1a52712e736..8720b76d3098 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -386,7 +386,6 @@ members = [ "substrate/frame/nomination-pools/fuzzer", "substrate/frame/nomination-pools/runtime-api", "substrate/frame/nomination-pools/test-delegate-stake", - "substrate/frame/nomination-pools/test-transfer-stake", "substrate/frame/offences", "substrate/frame/offences/benchmarking", "substrate/frame/paged-list", diff --git a/substrate/frame/nomination-pools/test-delegate-stake/src/lib.rs b/substrate/frame/nomination-pools/test-delegate-stake/src/lib.rs index cc6335959ab7..745f4dd96b52 100644 --- a/substrate/frame/nomination-pools/test-delegate-stake/src/lib.rs +++ b/substrate/frame/nomination-pools/test-delegate-stake/src/lib.rs @@ -939,6 +939,7 @@ fn pool_slash_non_proportional_bonded_pool_and_chunks() { } #[test] +#[ignore = "TransferStake is incompatible with core staking using fungibles"] fn pool_migration_e2e() { new_test_ext().execute_with(|| { LegacyAdapter::set(true); @@ -1217,6 +1218,7 @@ fn pool_migration_e2e() { } #[test] +#[ignore = "TransferStake is incompatible with core staking using fungibles"] fn disable_pool_operations_on_non_migrated() { new_test_ext().execute_with(|| { LegacyAdapter::set(true); diff --git a/substrate/frame/nomination-pools/test-transfer-stake/Cargo.toml b/substrate/frame/nomination-pools/test-transfer-stake/Cargo.toml deleted file mode 100644 index 7398404c2351..000000000000 --- a/substrate/frame/nomination-pools/test-transfer-stake/Cargo.toml +++ /dev/null @@ -1,40 +0,0 @@ -[package] -name = "pallet-nomination-pools-test-transfer-stake" -version = "1.0.0" -authors.workspace = true -edition.workspace = true -license = "Apache-2.0" -homepage.workspace = true -repository.workspace = true -description = "FRAME nomination pools pallet tests with the staking pallet" -publish = false - -[lints] -workspace = true - -[package.metadata.docs.rs] -targets = ["x86_64-unknown-linux-gnu"] - -[dev-dependencies] -codec = { features = ["derive"], workspace = true, default-features = true } -scale-info = { features = ["derive"], workspace = true, default-features = true } - -sp-runtime = { workspace = true, default-features = true } -sp-io = { workspace = true, default-features = true } -sp-std = { workspace = true, default-features = true } -sp-staking = { workspace = true, default-features = true } -sp-core = { workspace = true, default-features = true } - -frame-system = { workspace = true, default-features = true } -frame-support = { workspace = true, default-features = true } -frame-election-provider-support = { workspace = true, default-features = true } - -pallet-timestamp = { workspace = true, default-features = true } -pallet-balances = { workspace = true, default-features = true } -pallet-staking = { workspace = true, default-features = true } -pallet-bags-list = { workspace = true, default-features = true } -pallet-staking-reward-curve = { workspace = true, default-features = true } -pallet-nomination-pools = { workspace = true, default-features = true } - -sp-tracing = { workspace = true, default-features = true } -log = { workspace = true, default-features = true } diff --git a/substrate/frame/nomination-pools/test-transfer-stake/src/lib.rs b/substrate/frame/nomination-pools/test-transfer-stake/src/lib.rs deleted file mode 100644 index 71d70203b1e6..000000000000 --- a/substrate/frame/nomination-pools/test-transfer-stake/src/lib.rs +++ /dev/null @@ -1,912 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#![cfg(test)] - -mod mock; - -use frame_support::{assert_noop, assert_ok, traits::Currency}; -use mock::*; -use pallet_nomination_pools::{ - BondExtra, BondedPools, Error as PoolsError, Event as PoolsEvent, LastPoolId, PoolMember, - PoolMembers, PoolState, -}; -use pallet_staking::{ - CurrentEra, Error as StakingError, Event as StakingEvent, Payee, RewardDestination, -}; -use sp_runtime::{bounded_btree_map, traits::Zero}; - -#[test] -fn pool_lifecycle_e2e() { - new_test_ext().execute_with(|| { - assert_eq!(Balances::minimum_balance(), 5); - assert_eq!(CurrentEra::::get(), None); - - // create the pool, we know this has id 1. - assert_ok!(Pools::create(RuntimeOrigin::signed(10), 50, 10, 10, 10)); - assert_eq!(LastPoolId::::get(), 1); - - // have the pool nominate. - assert_ok!(Pools::nominate(RuntimeOrigin::signed(10), 1, vec![1, 2, 3])); - - assert_eq!( - staking_events_since_last_call(), - vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: 50 }] - ); - assert_eq!( - pool_events_since_last_call(), - vec![ - PoolsEvent::Created { depositor: 10, pool_id: 1 }, - PoolsEvent::Bonded { member: 10, pool_id: 1, bonded: 50, joined: true }, - ] - ); - - // have two members join - assert_ok!(Pools::join(RuntimeOrigin::signed(20), 10, 1)); - assert_ok!(Pools::join(RuntimeOrigin::signed(21), 10, 1)); - - assert_eq!( - staking_events_since_last_call(), - vec![ - StakingEvent::Bonded { stash: POOL1_BONDED, amount: 10 }, - StakingEvent::Bonded { stash: POOL1_BONDED, amount: 10 }, - ] - ); - assert_eq!( - pool_events_since_last_call(), - vec![ - PoolsEvent::Bonded { member: 20, pool_id: 1, bonded: 10, joined: true }, - PoolsEvent::Bonded { member: 21, pool_id: 1, bonded: 10, joined: true }, - ] - ); - - // pool goes into destroying - assert_ok!(Pools::set_state(RuntimeOrigin::signed(10), 1, PoolState::Destroying)); - - // depositor cannot unbond yet. - assert_noop!( - Pools::unbond(RuntimeOrigin::signed(10), 10, 50), - PoolsError::::MinimumBondNotMet, - ); - - // now the members want to unbond. - assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 10)); - assert_ok!(Pools::unbond(RuntimeOrigin::signed(21), 21, 10)); - - assert_eq!(PoolMembers::::get(20).unwrap().unbonding_eras.len(), 1); - assert_eq!(PoolMembers::::get(20).unwrap().points, 0); - assert_eq!(PoolMembers::::get(21).unwrap().unbonding_eras.len(), 1); - assert_eq!(PoolMembers::::get(21).unwrap().points, 0); - - assert_eq!( - staking_events_since_last_call(), - vec![ - StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 }, - StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 }, - ] - ); - assert_eq!( - pool_events_since_last_call(), - vec![ - PoolsEvent::StateChanged { pool_id: 1, new_state: PoolState::Destroying }, - PoolsEvent::Unbonded { member: 20, pool_id: 1, points: 10, balance: 10, era: 3 }, - PoolsEvent::Unbonded { member: 21, pool_id: 1, points: 10, balance: 10, era: 3 }, - ] - ); - - // depositor cannot still unbond - assert_noop!( - Pools::unbond(RuntimeOrigin::signed(10), 10, 50), - PoolsError::::MinimumBondNotMet, - ); - - for e in 1..BondingDuration::get() { - CurrentEra::::set(Some(e)); - assert_noop!( - Pools::withdraw_unbonded(RuntimeOrigin::signed(20), 20, 0), - PoolsError::::CannotWithdrawAny - ); - } - - // members are now unlocked. - CurrentEra::::set(Some(BondingDuration::get())); - - // depositor cannot still unbond - assert_noop!( - Pools::unbond(RuntimeOrigin::signed(10), 10, 50), - PoolsError::::MinimumBondNotMet, - ); - - // but members can now withdraw. - assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(20), 20, 0)); - assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(21), 21, 0)); - assert!(PoolMembers::::get(20).is_none()); - assert!(PoolMembers::::get(21).is_none()); - - assert_eq!( - staking_events_since_last_call(), - vec![StakingEvent::Withdrawn { stash: POOL1_BONDED, amount: 20 },] - ); - assert_eq!( - pool_events_since_last_call(), - vec![ - PoolsEvent::Withdrawn { member: 20, pool_id: 1, points: 10, balance: 10 }, - PoolsEvent::MemberRemoved { pool_id: 1, member: 20, released_balance: 0 }, - PoolsEvent::Withdrawn { member: 21, pool_id: 1, points: 10, balance: 10 }, - PoolsEvent::MemberRemoved { pool_id: 1, member: 21, released_balance: 0 }, - ] - ); - - // as soon as all members have left, the depositor can try to unbond, but since the - // min-nominator intention is set, they must chill first. - assert_noop!( - Pools::unbond(RuntimeOrigin::signed(10), 10, 50), - pallet_staking::Error::::InsufficientBond - ); - - assert_ok!(Pools::chill(RuntimeOrigin::signed(10), 1)); - assert_ok!(Pools::unbond(RuntimeOrigin::signed(10), 10, 50)); - - assert_eq!( - staking_events_since_last_call(), - vec![ - StakingEvent::Chilled { stash: POOL1_BONDED }, - StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 50 }, - ] - ); - assert_eq!( - pool_events_since_last_call(), - vec![PoolsEvent::Unbonded { member: 10, pool_id: 1, points: 50, balance: 50, era: 6 }] - ); - - // waiting another bonding duration: - CurrentEra::::set(Some(BondingDuration::get() * 2)); - assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(10), 10, 1)); - - // pools is fully destroyed now. - assert_eq!( - staking_events_since_last_call(), - vec![StakingEvent::Withdrawn { stash: POOL1_BONDED, amount: 50 },] - ); - assert_eq!( - pool_events_since_last_call(), - vec![ - PoolsEvent::Withdrawn { member: 10, pool_id: 1, points: 50, balance: 50 }, - PoolsEvent::MemberRemoved { pool_id: 1, member: 10, released_balance: 0 }, - PoolsEvent::Destroyed { pool_id: 1 } - ] - ); - }) -} - -#[test] -fn destroy_pool_with_erroneous_consumer() { - new_test_ext().execute_with(|| { - // create the pool, we know this has id 1. - assert_ok!(Pools::create(RuntimeOrigin::signed(10), 50, 10, 10, 10)); - assert_eq!(LastPoolId::::get(), 1); - - // expect consumers on pool account to be 1 (staking hold). - assert_eq!(frame_system::Pallet::::consumers(&POOL1_BONDED), 1); - - // increment consumer by 1 reproducing the erroneous consumer bug. - // refer https://github.com/paritytech/polkadot-sdk/issues/4440. - assert_ok!(frame_system::Pallet::::inc_consumers(&POOL1_BONDED)); - assert_eq!(frame_system::Pallet::::consumers(&POOL1_BONDED), 2); - - // have the pool nominate. - assert_ok!(Pools::nominate(RuntimeOrigin::signed(10), 1, vec![1, 2, 3])); - - assert_eq!( - staking_events_since_last_call(), - vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: 50 }] - ); - assert_eq!( - pool_events_since_last_call(), - vec![ - PoolsEvent::Created { depositor: 10, pool_id: 1 }, - PoolsEvent::Bonded { member: 10, pool_id: 1, bonded: 50, joined: true }, - ] - ); - - // pool goes into destroying - assert_ok!(Pools::set_state(RuntimeOrigin::signed(10), 1, PoolState::Destroying)); - - assert_eq!( - pool_events_since_last_call(), - vec![PoolsEvent::StateChanged { pool_id: 1, new_state: PoolState::Destroying },] - ); - - // move to era 1 - CurrentEra::::set(Some(1)); - - // depositor need to chill before unbonding - assert_noop!( - Pools::unbond(RuntimeOrigin::signed(10), 10, 50), - pallet_staking::Error::::InsufficientBond - ); - - assert_ok!(Pools::chill(RuntimeOrigin::signed(10), 1)); - assert_ok!(Pools::unbond(RuntimeOrigin::signed(10), 10, 50)); - - assert_eq!( - staking_events_since_last_call(), - vec![ - StakingEvent::Chilled { stash: POOL1_BONDED }, - StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 50 }, - ] - ); - assert_eq!( - pool_events_since_last_call(), - vec![PoolsEvent::Unbonded { - member: 10, - pool_id: 1, - points: 50, - balance: 50, - era: 1 + 3 - }] - ); - - // waiting bonding duration: - CurrentEra::::set(Some(1 + 3)); - // this should work even with an extra consumer count on pool account. - assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(10), 10, 1)); - - // pools is fully destroyed now. - assert_eq!( - staking_events_since_last_call(), - vec![StakingEvent::Withdrawn { stash: POOL1_BONDED, amount: 50 },] - ); - assert_eq!( - pool_events_since_last_call(), - vec![ - PoolsEvent::Withdrawn { member: 10, pool_id: 1, points: 50, balance: 50 }, - PoolsEvent::MemberRemoved { pool_id: 1, member: 10, released_balance: 0 }, - PoolsEvent::Destroyed { pool_id: 1 } - ] - ); - }) -} - -#[test] -fn pool_chill_e2e() { - new_test_ext().execute_with(|| { - assert_eq!(Balances::minimum_balance(), 5); - assert_eq!(CurrentEra::::get(), None); - - // create the pool, we know this has id 1. - assert_ok!(Pools::create(RuntimeOrigin::signed(10), 50, 10, 10, 10)); - assert_eq!(LastPoolId::::get(), 1); - - // have the pool nominate. - assert_ok!(Pools::nominate(RuntimeOrigin::signed(10), 1, vec![1, 2, 3])); - - assert_eq!( - staking_events_since_last_call(), - vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: 50 }] - ); - assert_eq!( - pool_events_since_last_call(), - vec![ - PoolsEvent::Created { depositor: 10, pool_id: 1 }, - PoolsEvent::Bonded { member: 10, pool_id: 1, bonded: 50, joined: true }, - ] - ); - - // have two members join - assert_ok!(Pools::join(RuntimeOrigin::signed(20), 10, 1)); - assert_ok!(Pools::join(RuntimeOrigin::signed(21), 10, 1)); - - assert_eq!( - staking_events_since_last_call(), - vec![ - StakingEvent::Bonded { stash: POOL1_BONDED, amount: 10 }, - StakingEvent::Bonded { stash: POOL1_BONDED, amount: 10 }, - ] - ); - assert_eq!( - pool_events_since_last_call(), - vec![ - PoolsEvent::Bonded { member: 20, pool_id: 1, bonded: 10, joined: true }, - PoolsEvent::Bonded { member: 21, pool_id: 1, bonded: 10, joined: true }, - ] - ); - - // in case depositor does not have more than `MinNominatorBond` staked, we can end up in - // situation where a member unbonding would cause pool balance to drop below - // `MinNominatorBond` and hence not allowed. This can happen if the `MinNominatorBond` is - // increased after the pool is created. - assert_ok!(Staking::set_staking_configs( - RuntimeOrigin::root(), - pallet_staking::ConfigOp::Set(55), // minimum nominator bond - pallet_staking::ConfigOp::Noop, - pallet_staking::ConfigOp::Noop, - pallet_staking::ConfigOp::Noop, - pallet_staking::ConfigOp::Noop, - pallet_staking::ConfigOp::Noop, - pallet_staking::ConfigOp::Noop, - )); - - // members can unbond as long as total stake of the pool is above min nominator bond - assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 10),); - assert_eq!(PoolMembers::::get(20).unwrap().unbonding_eras.len(), 1); - assert_eq!(PoolMembers::::get(20).unwrap().points, 0); - - // this member cannot unbond since it will cause `pool stake < MinNominatorBond` - assert_noop!( - Pools::unbond(RuntimeOrigin::signed(21), 21, 10), - StakingError::::InsufficientBond, - ); - - // members can call `chill` permissionlessly now - assert_ok!(Pools::chill(RuntimeOrigin::signed(20), 1)); - - // now another member can unbond. - assert_ok!(Pools::unbond(RuntimeOrigin::signed(21), 21, 10)); - assert_eq!(PoolMembers::::get(21).unwrap().unbonding_eras.len(), 1); - assert_eq!(PoolMembers::::get(21).unwrap().points, 0); - - // nominator can not resume nomination until depositor have enough stake - assert_noop!( - Pools::nominate(RuntimeOrigin::signed(10), 1, vec![1, 2, 3]), - PoolsError::::MinimumBondNotMet, - ); - - // other members joining pool does not affect the depositor's ability to resume nomination - assert_ok!(Pools::join(RuntimeOrigin::signed(22), 10, 1)); - - assert_noop!( - Pools::nominate(RuntimeOrigin::signed(10), 1, vec![1, 2, 3]), - PoolsError::::MinimumBondNotMet, - ); - - // depositor can bond extra stake - assert_ok!(Pools::bond_extra(RuntimeOrigin::signed(10), BondExtra::FreeBalance(10))); - - // `chill` can not be called permissionlessly anymore - assert_noop!( - Pools::chill(RuntimeOrigin::signed(20), 1), - PoolsError::::NotNominator, - ); - - // now nominator can resume nomination - assert_ok!(Pools::nominate(RuntimeOrigin::signed(10), 1, vec![1, 2, 3])); - - // skip to make the unbonding period end. - CurrentEra::::set(Some(BondingDuration::get())); - - // members can now withdraw. - assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(20), 20, 0)); - assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(21), 21, 0)); - - assert_eq!( - staking_events_since_last_call(), - vec![ - StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 }, - StakingEvent::Chilled { stash: POOL1_BONDED }, - StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 }, - StakingEvent::Bonded { stash: POOL1_BONDED, amount: 10 }, // other member bonding - StakingEvent::Bonded { stash: POOL1_BONDED, amount: 10 }, // depositor bond extra - StakingEvent::Withdrawn { stash: POOL1_BONDED, amount: 20 }, - ] - ); - }) -} - -#[test] -fn pool_slash_e2e() { - new_test_ext().execute_with(|| { - ExistentialDeposit::set(1); - assert_eq!(Balances::minimum_balance(), 1); - assert_eq!(CurrentEra::::get(), None); - - // create the pool, we know this has id 1. - assert_ok!(Pools::create(RuntimeOrigin::signed(10), 40, 10, 10, 10)); - assert_eq!(LastPoolId::::get(), 1); - - assert_eq!( - staking_events_since_last_call(), - vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: 40 }] - ); - assert_eq!( - pool_events_since_last_call(), - vec![ - PoolsEvent::Created { depositor: 10, pool_id: 1 }, - PoolsEvent::Bonded { member: 10, pool_id: 1, bonded: 40, joined: true }, - ] - ); - - assert_eq!( - Payee::::get(POOL1_BONDED), - Some(RewardDestination::Account(POOL1_REWARD)) - ); - - // have two members join - assert_ok!(Pools::join(RuntimeOrigin::signed(20), 20, 1)); - assert_ok!(Pools::join(RuntimeOrigin::signed(21), 20, 1)); - - assert_eq!( - staking_events_since_last_call(), - vec![ - StakingEvent::Bonded { stash: POOL1_BONDED, amount: 20 }, - StakingEvent::Bonded { stash: POOL1_BONDED, amount: 20 } - ] - ); - assert_eq!( - pool_events_since_last_call(), - vec![ - PoolsEvent::Bonded { member: 20, pool_id: 1, bonded: 20, joined: true }, - PoolsEvent::Bonded { member: 21, pool_id: 1, bonded: 20, joined: true }, - ] - ); - - // now let's progress a bit. - CurrentEra::::set(Some(1)); - - // 20 / 80 of the total funds are unlocked, and safe from any further slash. - assert_ok!(Pools::unbond(RuntimeOrigin::signed(10), 10, 10)); - assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 10)); - - assert_eq!( - staking_events_since_last_call(), - vec![ - StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 }, - StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 } - ] - ); - assert_eq!( - pool_events_since_last_call(), - vec![ - PoolsEvent::Unbonded { member: 10, pool_id: 1, balance: 10, points: 10, era: 4 }, - PoolsEvent::Unbonded { member: 20, pool_id: 1, balance: 10, points: 10, era: 4 } - ] - ); - - CurrentEra::::set(Some(2)); - - // note: depositor cannot fully unbond at this point. - // these funds will still get slashed. - assert_ok!(Pools::unbond(RuntimeOrigin::signed(10), 10, 10)); - assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 10)); - assert_ok!(Pools::unbond(RuntimeOrigin::signed(21), 21, 10)); - - assert_eq!( - staking_events_since_last_call(), - vec![ - StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 }, - StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 }, - StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 }, - ] - ); - - assert_eq!( - pool_events_since_last_call(), - vec![ - PoolsEvent::Unbonded { member: 10, pool_id: 1, balance: 10, points: 10, era: 5 }, - PoolsEvent::Unbonded { member: 20, pool_id: 1, balance: 10, points: 10, era: 5 }, - PoolsEvent::Unbonded { member: 21, pool_id: 1, balance: 10, points: 10, era: 5 }, - ] - ); - - // At this point, 20 are safe from slash, 30 are unlocking but vulnerable to slash, and - // another 30 are active and vulnerable to slash. Let's slash half of them. - pallet_staking::slashing::do_slash::( - &POOL1_BONDED, - 30, - &mut Default::default(), - &mut Default::default(), - 2, // slash era 2, affects chunks at era 5 onwards. - ); - - assert_eq!( - staking_events_since_last_call(), - vec![StakingEvent::Slashed { staker: POOL1_BONDED, amount: 30 }] - ); - assert_eq!( - pool_events_since_last_call(), - vec![ - // 30 has been slashed to 15 (15 slash) - PoolsEvent::UnbondingPoolSlashed { pool_id: 1, era: 5, balance: 15 }, - // 30 has been slashed to 15 (15 slash) - PoolsEvent::PoolSlashed { pool_id: 1, balance: 15 } - ] - ); - - CurrentEra::::set(Some(3)); - assert_ok!(Pools::unbond(RuntimeOrigin::signed(21), 21, 10)); - - assert_eq!( - PoolMembers::::get(21).unwrap(), - PoolMember { - pool_id: 1, - points: 0, - last_recorded_reward_counter: Zero::zero(), - // the 10 points unlocked just now correspond to 5 points in the unbond pool. - unbonding_eras: bounded_btree_map!(5 => 10, 6 => 5) - } - ); - assert_eq!( - staking_events_since_last_call(), - vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 5 }] - ); - assert_eq!( - pool_events_since_last_call(), - vec![PoolsEvent::Unbonded { member: 21, pool_id: 1, balance: 5, points: 5, era: 6 }] - ); - - // now we start withdrawing. we do it all at once, at era 6 where 20 and 21 are fully free. - CurrentEra::::set(Some(6)); - assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(20), 20, 0)); - assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(21), 21, 0)); - - assert_eq!( - pool_events_since_last_call(), - vec![ - // 20 had unbonded 10 safely, and 10 got slashed by half. - PoolsEvent::Withdrawn { member: 20, pool_id: 1, balance: 10 + 5, points: 20 }, - PoolsEvent::MemberRemoved { pool_id: 1, member: 20, released_balance: 0 }, - // 21 unbonded all of it after the slash - PoolsEvent::Withdrawn { member: 21, pool_id: 1, balance: 5 + 5, points: 15 }, - PoolsEvent::MemberRemoved { pool_id: 1, member: 21, released_balance: 0 } - ] - ); - assert_eq!( - staking_events_since_last_call(), - // a 10 (un-slashed) + 10/2 (slashed) balance from 10 has also been unlocked - vec![StakingEvent::Withdrawn { stash: POOL1_BONDED, amount: 15 + 10 + 15 }] - ); - - // now, finally, we can unbond the depositor further than their current limit. - assert_ok!(Pools::set_state(RuntimeOrigin::signed(10), 1, PoolState::Destroying)); - assert_ok!(Pools::unbond(RuntimeOrigin::signed(10), 10, 20)); - - assert_eq!( - staking_events_since_last_call(), - vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 }] - ); - assert_eq!( - pool_events_since_last_call(), - vec![ - PoolsEvent::StateChanged { pool_id: 1, new_state: PoolState::Destroying }, - PoolsEvent::Unbonded { member: 10, pool_id: 1, points: 10, balance: 10, era: 9 } - ] - ); - - CurrentEra::::set(Some(9)); - assert_eq!( - PoolMembers::::get(10).unwrap(), - PoolMember { - pool_id: 1, - points: 0, - last_recorded_reward_counter: Zero::zero(), - unbonding_eras: bounded_btree_map!(4 => 10, 5 => 10, 9 => 10) - } - ); - // withdraw the depositor, they should lose 12 balance in total due to slash. - assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(10), 10, 0)); - - assert_eq!( - staking_events_since_last_call(), - vec![StakingEvent::Withdrawn { stash: POOL1_BONDED, amount: 10 }] - ); - assert_eq!( - pool_events_since_last_call(), - vec![ - PoolsEvent::Withdrawn { member: 10, pool_id: 1, balance: 10 + 15, points: 30 }, - PoolsEvent::MemberRemoved { pool_id: 1, member: 10, released_balance: 0 }, - PoolsEvent::Destroyed { pool_id: 1 } - ] - ); - }); -} - -#[test] -fn pool_slash_proportional() { - // a typical example where 3 pool members unbond in era 99, 100, and 101, and a slash that - // happened in era 100 should only affect the latter two. - new_test_ext().execute_with(|| { - ExistentialDeposit::set(1); - BondingDuration::set(28); - assert_eq!(Balances::minimum_balance(), 1); - assert_eq!(CurrentEra::::get(), None); - - // create the pool, we know this has id 1. - assert_ok!(Pools::create(RuntimeOrigin::signed(10), 40, 10, 10, 10)); - assert_eq!(LastPoolId::::get(), 1); - - assert_eq!( - staking_events_since_last_call(), - vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: 40 }] - ); - assert_eq!( - pool_events_since_last_call(), - vec![ - PoolsEvent::Created { depositor: 10, pool_id: 1 }, - PoolsEvent::Bonded { member: 10, pool_id: 1, bonded: 40, joined: true }, - ] - ); - - // have two members join - let bond = 20; - assert_ok!(Pools::join(RuntimeOrigin::signed(20), bond, 1)); - assert_ok!(Pools::join(RuntimeOrigin::signed(21), bond, 1)); - assert_ok!(Pools::join(RuntimeOrigin::signed(22), bond, 1)); - - assert_eq!( - staking_events_since_last_call(), - vec![ - StakingEvent::Bonded { stash: POOL1_BONDED, amount: bond }, - StakingEvent::Bonded { stash: POOL1_BONDED, amount: bond }, - StakingEvent::Bonded { stash: POOL1_BONDED, amount: bond }, - ] - ); - assert_eq!( - pool_events_since_last_call(), - vec![ - PoolsEvent::Bonded { member: 20, pool_id: 1, bonded: bond, joined: true }, - PoolsEvent::Bonded { member: 21, pool_id: 1, bonded: bond, joined: true }, - PoolsEvent::Bonded { member: 22, pool_id: 1, bonded: bond, joined: true }, - ] - ); - - // now let's progress a lot. - CurrentEra::::set(Some(99)); - - // and unbond - assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, bond)); - - assert_eq!( - staking_events_since_last_call(), - vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: bond },] - ); - assert_eq!( - pool_events_since_last_call(), - vec![PoolsEvent::Unbonded { - member: 20, - pool_id: 1, - balance: bond, - points: bond, - era: 127 - }] - ); - - CurrentEra::::set(Some(100)); - assert_ok!(Pools::unbond(RuntimeOrigin::signed(21), 21, bond)); - assert_eq!( - staking_events_since_last_call(), - vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: bond },] - ); - assert_eq!( - pool_events_since_last_call(), - vec![PoolsEvent::Unbonded { - member: 21, - pool_id: 1, - balance: bond, - points: bond, - era: 128 - }] - ); - - CurrentEra::::set(Some(101)); - assert_ok!(Pools::unbond(RuntimeOrigin::signed(22), 22, bond)); - assert_eq!( - staking_events_since_last_call(), - vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: bond },] - ); - assert_eq!( - pool_events_since_last_call(), - vec![PoolsEvent::Unbonded { - member: 22, - pool_id: 1, - balance: bond, - points: bond, - era: 129 - }] - ); - - // Apply a slash that happened in era 100. This is typically applied with a delay. - // Of the total 100, 50 is slashed. - assert_eq!(BondedPools::::get(1).unwrap().points, 40); - pallet_staking::slashing::do_slash::( - &POOL1_BONDED, - 50, - &mut Default::default(), - &mut Default::default(), - 100, - ); - - assert_eq!( - staking_events_since_last_call(), - vec![StakingEvent::Slashed { staker: POOL1_BONDED, amount: 50 }] - ); - assert_eq!( - pool_events_since_last_call(), - vec![ - // This era got slashed 12.5, which rounded up to 13. - PoolsEvent::UnbondingPoolSlashed { pool_id: 1, era: 128, balance: 7 }, - // This era got slashed 12 instead of 12.5 because an earlier chunk got 0.5 more - // slashed, and 12 is all the remaining slash - PoolsEvent::UnbondingPoolSlashed { pool_id: 1, era: 129, balance: 8 }, - // Bonded pool got slashed for 25, remaining 15 in it. - PoolsEvent::PoolSlashed { pool_id: 1, balance: 15 } - ] - ); - }); -} - -#[test] -fn pool_slash_non_proportional_only_bonded_pool() { - // A typical example where a pool member unbonds in era 99, and they can get away with a slash - // that happened in era 100, as long as the pool has enough active bond to cover the slash. If - // everything else in the slashing/staking system works, this should always be the case. - // Nonetheless, `ledger.slash` has been written such that it will slash greedily from any chunk - // if it runs out of chunks that it thinks should be affected by the slash. - new_test_ext().execute_with(|| { - ExistentialDeposit::set(1); - BondingDuration::set(28); - assert_eq!(Balances::minimum_balance(), 1); - assert_eq!(CurrentEra::::get(), None); - - // create the pool, we know this has id 1. - assert_ok!(Pools::create(RuntimeOrigin::signed(10), 40, 10, 10, 10)); - assert_eq!( - staking_events_since_last_call(), - vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: 40 }] - ); - assert_eq!( - pool_events_since_last_call(), - vec![ - PoolsEvent::Created { depositor: 10, pool_id: 1 }, - PoolsEvent::Bonded { member: 10, pool_id: 1, bonded: 40, joined: true }, - ] - ); - - // have two members join - let bond = 20; - assert_ok!(Pools::join(RuntimeOrigin::signed(20), bond, 1)); - assert_eq!( - staking_events_since_last_call(), - vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: bond }] - ); - assert_eq!( - pool_events_since_last_call(), - vec![PoolsEvent::Bonded { member: 20, pool_id: 1, bonded: bond, joined: true }] - ); - - // progress and unbond. - CurrentEra::::set(Some(99)); - assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, bond)); - assert_eq!( - staking_events_since_last_call(), - vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: bond }] - ); - assert_eq!( - pool_events_since_last_call(), - vec![PoolsEvent::Unbonded { - member: 20, - pool_id: 1, - balance: bond, - points: bond, - era: 127 - }] - ); - - // slash for 30. This will be deducted only from the bonded pool. - CurrentEra::::set(Some(100)); - assert_eq!(BondedPools::::get(1).unwrap().points, 40); - pallet_staking::slashing::do_slash::( - &POOL1_BONDED, - 30, - &mut Default::default(), - &mut Default::default(), - 100, - ); - - assert_eq!( - staking_events_since_last_call(), - vec![StakingEvent::Slashed { staker: POOL1_BONDED, amount: 30 }] - ); - assert_eq!( - pool_events_since_last_call(), - vec![PoolsEvent::PoolSlashed { pool_id: 1, balance: 10 }] - ); - }); -} - -#[test] -fn pool_slash_non_proportional_bonded_pool_and_chunks() { - // An uncommon example where even though some funds are unlocked such that they should not be - // affected by a slash, we still slash out of them. This should not happen at all. If a - // nomination has unbonded, from the next era onwards, their exposure will drop, so if an era - // happens in that era, then their share of that slash should naturally be less, such that only - // their active ledger stake is enough to compensate it. - new_test_ext().execute_with(|| { - ExistentialDeposit::set(1); - BondingDuration::set(28); - assert_eq!(Balances::minimum_balance(), 1); - assert_eq!(CurrentEra::::get(), None); - - // create the pool, we know this has id 1. - assert_ok!(Pools::create(RuntimeOrigin::signed(10), 40, 10, 10, 10)); - assert_eq!( - staking_events_since_last_call(), - vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: 40 }] - ); - assert_eq!( - pool_events_since_last_call(), - vec![ - PoolsEvent::Created { depositor: 10, pool_id: 1 }, - PoolsEvent::Bonded { member: 10, pool_id: 1, bonded: 40, joined: true }, - ] - ); - - // have two members join - let bond = 20; - assert_ok!(Pools::join(RuntimeOrigin::signed(20), bond, 1)); - assert_eq!( - staking_events_since_last_call(), - vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: bond }] - ); - assert_eq!( - pool_events_since_last_call(), - vec![PoolsEvent::Bonded { member: 20, pool_id: 1, bonded: bond, joined: true }] - ); - - // progress and unbond. - CurrentEra::::set(Some(99)); - assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, bond)); - assert_eq!( - staking_events_since_last_call(), - vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: bond }] - ); - assert_eq!( - pool_events_since_last_call(), - vec![PoolsEvent::Unbonded { - member: 20, - pool_id: 1, - balance: bond, - points: bond, - era: 127 - }] - ); - - // slash 50. This will be deducted only from the bonded pool and one of the unbonding pools. - CurrentEra::::set(Some(100)); - assert_eq!(BondedPools::::get(1).unwrap().points, 40); - pallet_staking::slashing::do_slash::( - &POOL1_BONDED, - 50, - &mut Default::default(), - &mut Default::default(), - 100, - ); - - assert_eq!( - staking_events_since_last_call(), - vec![StakingEvent::Slashed { staker: POOL1_BONDED, amount: 50 }] - ); - assert_eq!( - pool_events_since_last_call(), - vec![ - // out of 20, 10 was taken. - PoolsEvent::UnbondingPoolSlashed { pool_id: 1, era: 127, balance: 10 }, - // out of 40, all was taken. - PoolsEvent::PoolSlashed { pool_id: 1, balance: 0 } - ] - ); - }); -} diff --git a/substrate/frame/nomination-pools/test-transfer-stake/src/mock.rs b/substrate/frame/nomination-pools/test-transfer-stake/src/mock.rs deleted file mode 100644 index 17ada3a0ee3d..000000000000 --- a/substrate/frame/nomination-pools/test-transfer-stake/src/mock.rs +++ /dev/null @@ -1,234 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#![allow(deprecated)] - -use frame_election_provider_support::VoteWeight; -use frame_support::{ - assert_ok, derive_impl, - pallet_prelude::*, - parameter_types, - traits::{ConstU64, ConstU8, VariantCountOf}, - PalletId, -}; -use sp_runtime::{ - traits::{Convert, IdentityLookup}, - BuildStorage, FixedU128, Perbill, -}; - -type AccountId = u128; -type BlockNumber = u64; -type Balance = u128; - -pub(crate) type T = Runtime; - -pub(crate) const POOL1_BONDED: AccountId = 20318131474730217858575332831085u128; -pub(crate) const POOL1_REWARD: AccountId = 20397359637244482196168876781421u128; - -#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] -impl frame_system::Config for Runtime { - type AccountId = AccountId; - type Lookup = IdentityLookup; - type Block = Block; - type AccountData = pallet_balances::AccountData; -} - -impl pallet_timestamp::Config for Runtime { - type Moment = u64; - type OnTimestampSet = (); - type MinimumPeriod = ConstU64<5>; - type WeightInfo = (); -} - -parameter_types! { - pub static ExistentialDeposit: Balance = 5; -} - -#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig)] -impl pallet_balances::Config for Runtime { - type Balance = Balance; - type ExistentialDeposit = ExistentialDeposit; - type AccountStore = System; - type FreezeIdentifier = RuntimeFreezeReason; - type MaxFreezes = VariantCountOf; - type RuntimeFreezeReason = RuntimeFreezeReason; -} - -pallet_staking_reward_curve::build! { - const I_NPOS: sp_runtime::curve::PiecewiseLinear<'static> = curve!( - min_inflation: 0_025_000, - max_inflation: 0_100_000, - ideal_stake: 0_500_000, - falloff: 0_050_000, - max_piece_count: 40, - test_precision: 0_005_000, - ); -} - -parameter_types! { - pub const RewardCurve: &'static sp_runtime::curve::PiecewiseLinear<'static> = &I_NPOS; - pub static BondingDuration: u32 = 3; -} - -#[derive_impl(pallet_staking::config_preludes::TestDefaultConfig)] -impl pallet_staking::Config for Runtime { - type OldCurrency = Balances; - type Currency = Balances; - type UnixTime = pallet_timestamp::Pallet; - type AdminOrigin = frame_system::EnsureRoot; - type BondingDuration = BondingDuration; - type EraPayout = pallet_staking::ConvertCurve; - type ElectionProvider = - frame_election_provider_support::NoElection<(AccountId, BlockNumber, Staking, ())>; - type GenesisElectionProvider = Self::ElectionProvider; - type VoterList = VoterList; - type TargetList = pallet_staking::UseValidatorsMap; - type EventListeners = Pools; - type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; -} - -parameter_types! { - pub static BagThresholds: &'static [VoteWeight] = &[10, 20, 30, 40, 50, 60, 1_000, 2_000, 10_000]; -} - -type VoterBagsListInstance = pallet_bags_list::Instance1; -impl pallet_bags_list::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type WeightInfo = (); - type BagThresholds = BagThresholds; - type ScoreProvider = Staking; - type Score = VoteWeight; -} - -pub struct BalanceToU256; -impl Convert for BalanceToU256 { - fn convert(n: Balance) -> sp_core::U256 { - n.into() - } -} - -pub struct U256ToBalance; -impl Convert for U256ToBalance { - fn convert(n: sp_core::U256) -> Balance { - n.try_into().unwrap() - } -} - -parameter_types! { - pub const PostUnbondingPoolsWindow: u32 = 10; - pub const PoolsPalletId: PalletId = PalletId(*b"py/nopls"); -} - -impl pallet_nomination_pools::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type WeightInfo = (); - type Currency = Balances; - type RuntimeFreezeReason = RuntimeFreezeReason; - type RewardCounter = FixedU128; - type BalanceToU256 = BalanceToU256; - type U256ToBalance = U256ToBalance; - type StakeAdapter = pallet_nomination_pools::adapter::TransferStake; - type PostUnbondingPoolsWindow = PostUnbondingPoolsWindow; - type MaxMetadataLen = ConstU32<256>; - type MaxUnbonding = ConstU32<8>; - type MaxPointsToBalance = ConstU8<10>; - type PalletId = PoolsPalletId; - type AdminOrigin = frame_system::EnsureRoot; -} - -type Block = frame_system::mocking::MockBlock; - -frame_support::construct_runtime!( - pub enum Runtime { - System: frame_system, - Timestamp: pallet_timestamp, - Balances: pallet_balances, - Staking: pallet_staking, - VoterList: pallet_bags_list::, - Pools: pallet_nomination_pools, - } -); - -pub fn new_test_ext() -> sp_io::TestExternalities { - sp_tracing::try_init_simple(); - let mut storage = frame_system::GenesisConfig::::default().build_storage().unwrap(); - let _ = pallet_nomination_pools::GenesisConfig:: { - min_join_bond: 2, - min_create_bond: 2, - max_pools: Some(3), - max_members_per_pool: Some(5), - max_members: Some(3 * 5), - global_max_commission: Some(Perbill::from_percent(90)), - } - .assimilate_storage(&mut storage) - .unwrap(); - - let _ = pallet_balances::GenesisConfig:: { - balances: vec![(10, 100), (20, 100), (21, 100), (22, 100)], - } - .assimilate_storage(&mut storage) - .unwrap(); - - let mut ext = sp_io::TestExternalities::from(storage); - - ext.execute_with(|| { - // for events to be deposited. - frame_system::Pallet::::set_block_number(1); - - // set some limit for nominations. - assert_ok!(Staking::set_staking_configs( - RuntimeOrigin::root(), - pallet_staking::ConfigOp::Set(10), // minimum nominator bond - pallet_staking::ConfigOp::Noop, - pallet_staking::ConfigOp::Noop, - pallet_staking::ConfigOp::Noop, - pallet_staking::ConfigOp::Noop, - pallet_staking::ConfigOp::Noop, - pallet_staking::ConfigOp::Noop, - )); - }); - - ext -} - -parameter_types! { - static ObservedEventsPools: usize = 0; - static ObservedEventsStaking: usize = 0; - static ObservedEventsBalances: usize = 0; -} - -pub(crate) fn pool_events_since_last_call() -> Vec> { - let events = System::events() - .into_iter() - .map(|r| r.event) - .filter_map(|e| if let RuntimeEvent::Pools(inner) = e { Some(inner) } else { None }) - .collect::>(); - let already_seen = ObservedEventsPools::get(); - ObservedEventsPools::set(events.len()); - events.into_iter().skip(already_seen).collect() -} - -pub(crate) fn staking_events_since_last_call() -> Vec> { - let events = System::events() - .into_iter() - .map(|r| r.event) - .filter_map(|e| if let RuntimeEvent::Staking(inner) = e { Some(inner) } else { None }) - .collect::>(); - let already_seen = ObservedEventsStaking::get(); - ObservedEventsStaking::set(events.len()); - events.into_iter().skip(already_seen).collect() -} From 5d4325369b432a64f061204c57b2d64fd25e4bac Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 27 Nov 2024 22:42:03 +0100 Subject: [PATCH 124/142] get rid of TransferSTake usage in delegate stake tests --- .../test-delegate-stake/src/lib.rs | 463 +----------------- .../test-delegate-stake/src/mock.rs | 116 +---- 2 files changed, 3 insertions(+), 576 deletions(-) diff --git a/substrate/frame/nomination-pools/test-delegate-stake/src/lib.rs b/substrate/frame/nomination-pools/test-delegate-stake/src/lib.rs index 745f4dd96b52..127f84285240 100644 --- a/substrate/frame/nomination-pools/test-delegate-stake/src/lib.rs +++ b/substrate/frame/nomination-pools/test-delegate-stake/src/lib.rs @@ -25,7 +25,7 @@ use frame_support::{ }; use mock::*; use pallet_nomination_pools::{ - BondExtra, BondedPools, CommissionChangeRate, ConfigOp, Error as PoolsError, + BondExtra, BondedPools, Error as PoolsError, Event as PoolsEvent, LastPoolId, PoolMember, PoolMembers, PoolState, }; use pallet_staking::{ @@ -34,8 +34,7 @@ use pallet_staking::{ use pallet_delegated_staking::Event as DelegatedStakingEvent; -use sp_runtime::{bounded_btree_map, traits::Zero, Perbill}; -use sp_staking::Agent; +use sp_runtime::{bounded_btree_map, traits::Zero}; #[test] fn pool_lifecycle_e2e() { @@ -937,464 +936,6 @@ fn pool_slash_non_proportional_bonded_pool_and_chunks() { ); }); } - -#[test] -#[ignore = "TransferStake is incompatible with core staking using fungibles"] -fn pool_migration_e2e() { - new_test_ext().execute_with(|| { - LegacyAdapter::set(true); - assert_eq!(Balances::minimum_balance(), 5); - assert_eq!(CurrentEra::::get(), None); - - // create the pool with TransferStake strategy. - assert_ok!(Pools::create(RuntimeOrigin::signed(10), 50, 10, 10, 10)); - assert_eq!(LastPoolId::::get(), 1); - - // have the pool nominate. - assert_ok!(Pools::nominate(RuntimeOrigin::signed(10), 1, vec![1, 2, 3])); - - assert_eq!( - staking_events_since_last_call(), - vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: 50 }] - ); - assert_eq!( - pool_events_since_last_call(), - vec![ - PoolsEvent::Created { depositor: 10, pool_id: 1 }, - PoolsEvent::Bonded { member: 10, pool_id: 1, bonded: 50, joined: true }, - ] - ); - - // have three members join - let pre_20 = Balances::free_balance(20); - assert_ok!(Pools::join(RuntimeOrigin::signed(20), 10, 1)); - let pre_21 = Balances::free_balance(21); - assert_ok!(Pools::join(RuntimeOrigin::signed(21), 10, 1)); - let pre_22 = Balances::free_balance(22); - assert_ok!(Pools::join(RuntimeOrigin::signed(22), 10, 1)); - - // verify members balance is moved to pool. - assert_eq!(Balances::free_balance(20), pre_20 - 10); - assert_eq!(Balances::free_balance(21), pre_21 - 10); - assert_eq!(Balances::free_balance(22), pre_22 - 10); - - assert_eq!( - staking_events_since_last_call(), - vec![ - StakingEvent::Bonded { stash: POOL1_BONDED, amount: 10 }, - StakingEvent::Bonded { stash: POOL1_BONDED, amount: 10 }, - StakingEvent::Bonded { stash: POOL1_BONDED, amount: 10 }, - ] - ); - assert_eq!( - pool_events_since_last_call(), - vec![ - PoolsEvent::Bonded { member: 20, pool_id: 1, bonded: 10, joined: true }, - PoolsEvent::Bonded { member: 21, pool_id: 1, bonded: 10, joined: true }, - PoolsEvent::Bonded { member: 22, pool_id: 1, bonded: 10, joined: true }, - ] - ); - - CurrentEra::::set(Some(2)); - // 20 is partially unbonding - assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 5)); - - CurrentEra::::set(Some(3)); - // 21 is fully unbonding - assert_ok!(Pools::unbond(RuntimeOrigin::signed(21), 21, 10)); - - assert_eq!( - staking_events_since_last_call(), - vec![ - StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 5 }, - StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 }, - ] - ); - assert_eq!( - pool_events_since_last_call(), - vec![ - PoolsEvent::Unbonded { member: 20, pool_id: 1, balance: 5, points: 5, era: 5 }, - PoolsEvent::Unbonded { member: 21, pool_id: 1, balance: 10, points: 10, era: 6 }, - ] - ); - - // with `TransferStake`, we can't migrate. - assert!(!Pools::api_pool_needs_delegate_migration(1)); - assert_noop!( - Pools::migrate_pool_to_delegate_stake(RuntimeOrigin::signed(10), 1), - PoolsError::::NotSupported - ); - - // we reset the adapter to `DelegateStake`. - LegacyAdapter::set(false); - - // cannot migrate the member delegation unless pool is migrated first. - assert_noop!( - Pools::migrate_delegation(RuntimeOrigin::signed(10), 20), - PoolsError::::NotMigrated - ); - - // migrate the pool. - assert!(Pools::api_pool_needs_delegate_migration(1)); - assert_ok!(Pools::migrate_pool_to_delegate_stake(RuntimeOrigin::signed(10), 1)); - - // migrate again does not work. - assert!(!Pools::api_pool_needs_delegate_migration(1)); - assert_noop!( - Pools::migrate_pool_to_delegate_stake(RuntimeOrigin::signed(10), 1), - PoolsError::::AlreadyMigrated - ); - - // unclaimed delegations to the pool are stored in this account. - let proxy_delegator_1 = - DelegatedStaking::generate_proxy_delegator(Agent::from(POOL1_BONDED)).get(); - - assert_eq!( - delegated_staking_events_since_last_call(), - vec![DelegatedStakingEvent::Delegated { - agent: POOL1_BONDED, - delegator: proxy_delegator_1, - amount: 50 + 10 * 3 - }] - ); - - // move to era 5 when 20 can withdraw unbonded funds. - CurrentEra::::set(Some(5)); - - // Cannot unbond without claiming delegation. Lets unbond 22. - assert_noop!( - Pools::unbond(RuntimeOrigin::signed(22), 22, 5), - PoolsError::::NotMigrated - ); - - // withdraw fails for 20 before claiming delegation - assert_noop!( - Pools::withdraw_unbonded(RuntimeOrigin::signed(20), 20, 10), - PoolsError::::NotMigrated - ); - - let pre_claim_balance_20 = Balances::total_balance(&20); - assert_eq!(Balances::total_balance_on_hold(&20), 0); - - // migrate delegation for 20. This is permissionless and can be called by anyone. - assert!(Pools::api_member_needs_delegate_migration(20)); - assert_ok!(Pools::migrate_delegation(RuntimeOrigin::signed(10), 20)); - - // tokens moved to 20's account and held there. - assert_eq!(Balances::total_balance(&20), pre_claim_balance_20 + 10); - assert_eq!(Balances::total_balance_on_hold(&20), 10); - - // withdraw works now - assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(20), 20, 5)); - - // balance unlocked in 20's account - assert_eq!(Balances::total_balance_on_hold(&20), 5); - assert_eq!(Balances::total_balance(&20), pre_claim_balance_20 + 10); - - assert_eq!( - staking_events_since_last_call(), - vec![StakingEvent::Withdrawn { stash: POOL1_BONDED, amount: 5 }] - ); - assert_eq!( - pool_events_since_last_call(), - vec![PoolsEvent::Withdrawn { member: 20, pool_id: 1, balance: 5, points: 5 },] - ); - assert_eq!( - delegated_staking_events_since_last_call(), - vec![ - DelegatedStakingEvent::MigratedDelegation { - agent: POOL1_BONDED, - delegator: 20, - amount: 10 - }, - DelegatedStakingEvent::Released { agent: POOL1_BONDED, delegator: 20, amount: 5 } - ] - ); - - // MIGRATE 21 - let pre_migrate_balance_21 = Balances::total_balance(&21); - assert_eq!(Balances::total_balance_on_hold(&21), 0); - - // migrate delegation for 21. - assert!(Pools::api_member_needs_delegate_migration(21)); - assert_ok!(Pools::migrate_delegation(RuntimeOrigin::signed(10), 21)); - - // tokens moved to 21's account and held there. - assert_eq!(Balances::total_balance(&21), pre_migrate_balance_21 + 10); - assert_eq!(Balances::total_balance_on_hold(&21), 10); - - // withdraw fails since 21 only unbonds at era 6. - assert_noop!( - Pools::withdraw_unbonded(RuntimeOrigin::signed(21), 21, 10), - PoolsError::::CannotWithdrawAny - ); - - // go to era when 21 can unbond - CurrentEra::::set(Some(6)); - - // withdraw works now - assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(21), 21, 10)); - - // all balance unlocked in 21's account - assert_eq!(Balances::total_balance_on_hold(&21), 0); - assert_eq!(Balances::total_balance(&21), pre_migrate_balance_21 + 10); - - // MIGRATE 22 - assert_eq!(Balances::total_balance_on_hold(&22), 0); - // make balance of 22 as 0. - let _ = Balances::make_free_balance_be(&22, 0); - - // migrate delegation for 22. - assert!(Pools::api_member_needs_delegate_migration(22)); - assert_ok!(Pools::migrate_delegation(RuntimeOrigin::signed(10), 22)); - - // cannot migrate a pool member again. - assert!(!Pools::api_member_needs_delegate_migration(22)); - assert_noop!( - Pools::migrate_delegation(RuntimeOrigin::signed(10), 22), - PoolsError::::AlreadyMigrated - ); - - // tokens moved to 22's account and held there. - assert_eq!(Balances::total_balance(&22), 10); - assert_eq!(Balances::total_balance_on_hold(&22), 10); - - // unbond 22 should work now - assert_ok!(Pools::unbond(RuntimeOrigin::signed(22), 22, 5)); - - // withdraw fails since 22 only unbonds after era 9. - assert_noop!( - Pools::withdraw_unbonded(RuntimeOrigin::signed(22), 22, 5), - PoolsError::::CannotWithdrawAny - ); - - // go to era when 22 can unbond - CurrentEra::::set(Some(9)); - - // withdraw works now - assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(22), 22, 10)); - - // balance of 5 unlocked in 22's account - assert_eq!(Balances::total_balance_on_hold(&22), 10 - 5); - - // assert events for 21 and 22. - assert_eq!( - staking_events_since_last_call(), - vec![ - StakingEvent::Withdrawn { stash: POOL1_BONDED, amount: 10 }, - StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 5 }, - StakingEvent::Withdrawn { stash: POOL1_BONDED, amount: 5 } - ] - ); - - assert_eq!( - pool_events_since_last_call(), - vec![ - PoolsEvent::Withdrawn { member: 21, pool_id: 1, balance: 10, points: 10 }, - // 21 was fully unbonding and removed from pool. - PoolsEvent::MemberRemoved { member: 21, pool_id: 1, released_balance: 0 }, - PoolsEvent::Unbonded { member: 22, pool_id: 1, balance: 5, points: 5, era: 9 }, - PoolsEvent::Withdrawn { member: 22, pool_id: 1, balance: 5, points: 5 }, - ] - ); - assert_eq!( - delegated_staking_events_since_last_call(), - vec![ - DelegatedStakingEvent::MigratedDelegation { - agent: POOL1_BONDED, - delegator: 21, - amount: 10 - }, - DelegatedStakingEvent::Released { agent: POOL1_BONDED, delegator: 21, amount: 10 }, - DelegatedStakingEvent::MigratedDelegation { - agent: POOL1_BONDED, - delegator: 22, - amount: 10 - }, - DelegatedStakingEvent::Released { agent: POOL1_BONDED, delegator: 22, amount: 5 } - ] - ); - }) -} - -#[test] -#[ignore = "TransferStake is incompatible with core staking using fungibles"] -fn disable_pool_operations_on_non_migrated() { - new_test_ext().execute_with(|| { - LegacyAdapter::set(true); - assert_eq!(Balances::minimum_balance(), 5); - assert_eq!(CurrentEra::::get(), None); - - // create the pool with TransferStake strategy. - assert_ok!(Pools::create(RuntimeOrigin::signed(10), 50, 10, 10, 10)); - assert_eq!(LastPoolId::::get(), 1); - - // have the pool nominate. - assert_ok!(Pools::nominate(RuntimeOrigin::signed(10), 1, vec![1, 2, 3])); - - assert_eq!( - staking_events_since_last_call(), - vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: 50 }] - ); - assert_eq!( - pool_events_since_last_call(), - vec![ - PoolsEvent::Created { depositor: 10, pool_id: 1 }, - PoolsEvent::Bonded { member: 10, pool_id: 1, bonded: 50, joined: true }, - ] - ); - - let pre_20 = Balances::free_balance(20); - assert_ok!(Pools::join(RuntimeOrigin::signed(20), 10, 1)); - - // verify members balance is moved to pool. - assert_eq!(Balances::free_balance(20), pre_20 - 10); - - assert_eq!( - staking_events_since_last_call(), - vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: 10 },] - ); - assert_eq!( - pool_events_since_last_call(), - vec![PoolsEvent::Bonded { member: 20, pool_id: 1, bonded: 10, joined: true },] - ); - - // we reset the adapter to `DelegateStake`. - LegacyAdapter::set(false); - - // pool is pending migration. - assert!(Pools::api_pool_needs_delegate_migration(1)); - - // ensure pool mutation is not allowed until pool is migrated. - assert_noop!( - Pools::join(RuntimeOrigin::signed(21), 10, 1), - PoolsError::::NotMigrated - ); - assert_noop!( - Pools::pool_withdraw_unbonded(RuntimeOrigin::signed(10), 1, 0), - PoolsError::::NotMigrated - ); - assert_noop!( - Pools::nominate(RuntimeOrigin::signed(10), 1, vec![1, 2, 3]), - PoolsError::::NotMigrated - ); - assert_noop!( - Pools::set_state(RuntimeOrigin::signed(10), 1, PoolState::Blocked), - PoolsError::::NotMigrated - ); - assert_noop!( - Pools::set_metadata(RuntimeOrigin::signed(10), 1, vec![1, 1]), - PoolsError::::NotMigrated - ); - assert_noop!( - Pools::update_roles( - RuntimeOrigin::signed(10), - 1, - ConfigOp::Set(5), - ConfigOp::Set(6), - ConfigOp::Set(7) - ), - PoolsError::::NotMigrated - ); - assert_noop!( - Pools::chill(RuntimeOrigin::signed(10), 1), - PoolsError::::NotMigrated - ); - assert_noop!( - Pools::set_commission(RuntimeOrigin::signed(10), 1, None), - PoolsError::::NotMigrated - ); - assert_noop!( - Pools::set_commission_max(RuntimeOrigin::signed(10), 1, Zero::zero()), - PoolsError::::NotMigrated - ); - assert_noop!( - Pools::set_commission_change_rate( - RuntimeOrigin::signed(10), - 1, - CommissionChangeRate { max_increase: Perbill::from_percent(1), min_delay: 2_u64 } - ), - PoolsError::::NotMigrated - ); - assert_noop!( - Pools::claim_commission(RuntimeOrigin::signed(10), 1), - PoolsError::::NotMigrated - ); - assert_noop!( - Pools::adjust_pool_deposit(RuntimeOrigin::signed(10), 1), - PoolsError::::NotMigrated - ); - assert_noop!( - Pools::set_commission_claim_permission(RuntimeOrigin::signed(10), 1, None), - PoolsError::::NotMigrated - ); - - // migrate the pool. - assert_ok!(Pools::migrate_pool_to_delegate_stake(RuntimeOrigin::signed(10), 1)); - assert_eq!( - delegated_staking_events_since_last_call(), - vec![DelegatedStakingEvent::Delegated { - agent: POOL1_BONDED, - delegator: DelegatedStaking::generate_proxy_delegator(Agent::from(POOL1_BONDED)) - .get(), - amount: 50 + 10 - },] - ); - - // member is pending migration. - assert!(Pools::api_member_needs_delegate_migration(20)); - - // ensure member mutation is not allowed until member's delegation is migrated. - assert_noop!( - Pools::bond_extra(RuntimeOrigin::signed(20), BondExtra::FreeBalance(5)), - PoolsError::::NotMigrated - ); - assert_noop!( - Pools::bond_extra_other(RuntimeOrigin::signed(10), 20, BondExtra::Rewards), - PoolsError::::NotMigrated - ); - assert_noop!( - Pools::claim_payout(RuntimeOrigin::signed(20)), - PoolsError::::NotMigrated - ); - assert_noop!( - Pools::unbond(RuntimeOrigin::signed(20), 20, 5), - PoolsError::::NotMigrated - ); - assert_noop!( - Pools::withdraw_unbonded(RuntimeOrigin::signed(20), 20, 0), - PoolsError::::NotMigrated - ); - - // migrate 20 - assert_ok!(Pools::migrate_delegation(RuntimeOrigin::signed(10), 20)); - // now `bond_extra` for 20 works. - assert_ok!(Pools::bond_extra(RuntimeOrigin::signed(20), BondExtra::FreeBalance(5))); - - assert_eq!( - staking_events_since_last_call(), - vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: 5 },] - ); - - assert_eq!( - pool_events_since_last_call(), - vec![PoolsEvent::Bonded { member: 20, pool_id: 1, bonded: 5, joined: false },] - ); - - assert_eq!( - delegated_staking_events_since_last_call(), - vec![ - DelegatedStakingEvent::MigratedDelegation { - agent: POOL1_BONDED, - delegator: 20, - amount: 10 - }, - DelegatedStakingEvent::Delegated { agent: POOL1_BONDED, delegator: 20, amount: 5 }, - ] - ); - }) -} - #[test] fn pool_no_dangling_delegation() { new_test_ext().execute_with(|| { diff --git a/substrate/frame/nomination-pools/test-delegate-stake/src/mock.rs b/substrate/frame/nomination-pools/test-delegate-stake/src/mock.rs index 5f51ce4a9c2d..cc871b9e56bd 100644 --- a/substrate/frame/nomination-pools/test-delegate-stake/src/mock.rs +++ b/substrate/frame/nomination-pools/test-delegate-stake/src/mock.rs @@ -26,10 +26,6 @@ use frame_support::{ PalletId, }; use frame_system::EnsureRoot; -use pallet_nomination_pools::{ - adapter::{Member, Pool, StakeStrategyType}, - BondType, -}; use sp_runtime::{ traits::{Convert, IdentityLookup}, BuildStorage, FixedU128, Perbill, @@ -139,120 +135,10 @@ impl Convert for U256ToBalance { parameter_types! { pub const PostUnbondingPoolsWindow: u32 = 10; pub const PoolsPalletId: PalletId = PalletId(*b"py/nopls"); - pub static LegacyAdapter: bool = false; } -pub struct MockAdapter; type DelegateStake = pallet_nomination_pools::adapter::DelegateStake; -type TransferStake = pallet_nomination_pools::adapter::TransferStake; -impl pallet_nomination_pools::adapter::StakeStrategy for MockAdapter { - type Balance = Balance; - type AccountId = AccountId; - type CoreStaking = Staking; - - fn strategy_type() -> StakeStrategyType { - if LegacyAdapter::get() { - return TransferStake::strategy_type() - } - DelegateStake::strategy_type() - } - fn transferable_balance( - pool_account: Pool, - member_account: Member, - ) -> Self::Balance { - if LegacyAdapter::get() { - return TransferStake::transferable_balance(pool_account, member_account) - } - DelegateStake::transferable_balance(pool_account, member_account) - } - - fn total_balance(pool_account: Pool) -> Option { - if LegacyAdapter::get() { - return TransferStake::total_balance(pool_account) - } - DelegateStake::total_balance(pool_account) - } - - fn member_delegation_balance(member_account: Member) -> Option { - if LegacyAdapter::get() { - return TransferStake::member_delegation_balance(member_account) - } - DelegateStake::member_delegation_balance(member_account) - } - - fn pledge_bond( - who: Member, - pool_account: Pool, - reward_account: &Self::AccountId, - amount: Self::Balance, - bond_type: BondType, - ) -> DispatchResult { - if LegacyAdapter::get() { - return TransferStake::pledge_bond(who, pool_account, reward_account, amount, bond_type) - } - DelegateStake::pledge_bond(who, pool_account, reward_account, amount, bond_type) - } - - fn member_withdraw( - who: Member, - pool_account: Pool, - amount: Self::Balance, - num_slashing_spans: u32, - ) -> DispatchResult { - if LegacyAdapter::get() { - return TransferStake::member_withdraw(who, pool_account, amount, num_slashing_spans) - } - DelegateStake::member_withdraw(who, pool_account, amount, num_slashing_spans) - } - - fn dissolve(pool_account: Pool) -> DispatchResult { - if LegacyAdapter::get() { - return TransferStake::dissolve(pool_account) - } - DelegateStake::dissolve(pool_account) - } - - fn pending_slash(pool_account: Pool) -> Self::Balance { - if LegacyAdapter::get() { - return TransferStake::pending_slash(pool_account) - } - DelegateStake::pending_slash(pool_account) - } - - fn member_slash( - who: Member, - pool_account: Pool, - amount: Self::Balance, - maybe_reporter: Option, - ) -> DispatchResult { - if LegacyAdapter::get() { - return TransferStake::member_slash(who, pool_account, amount, maybe_reporter) - } - DelegateStake::member_slash(who, pool_account, amount, maybe_reporter) - } - - fn migrate_nominator_to_agent( - agent: Pool, - reward_account: &Self::AccountId, - ) -> DispatchResult { - if LegacyAdapter::get() { - return TransferStake::migrate_nominator_to_agent(agent, reward_account) - } - DelegateStake::migrate_nominator_to_agent(agent, reward_account) - } - - fn migrate_delegation( - agent: Pool, - delegator: Member, - value: Self::Balance, - ) -> DispatchResult { - if LegacyAdapter::get() { - return TransferStake::migrate_delegation(agent, delegator, value) - } - DelegateStake::migrate_delegation(agent, delegator, value) - } -} impl pallet_nomination_pools::Config for Runtime { type RuntimeEvent = RuntimeEvent; type WeightInfo = (); @@ -261,7 +147,7 @@ impl pallet_nomination_pools::Config for Runtime { type RewardCounter = FixedU128; type BalanceToU256 = BalanceToU256; type U256ToBalance = U256ToBalance; - type StakeAdapter = MockAdapter; + type StakeAdapter = DelegateStake; type PostUnbondingPoolsWindow = PostUnbondingPoolsWindow; type MaxMetadataLen = ConstU32<256>; type MaxUnbonding = ConstU32<8>; From 7b032e1bcd46e86ead165695a6725fbc1f856f99 Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 27 Nov 2024 22:48:47 +0100 Subject: [PATCH 125/142] fmt --- .../frame/nomination-pools/test-delegate-stake/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/substrate/frame/nomination-pools/test-delegate-stake/src/lib.rs b/substrate/frame/nomination-pools/test-delegate-stake/src/lib.rs index 127f84285240..27b1524c6e98 100644 --- a/substrate/frame/nomination-pools/test-delegate-stake/src/lib.rs +++ b/substrate/frame/nomination-pools/test-delegate-stake/src/lib.rs @@ -25,8 +25,8 @@ use frame_support::{ }; use mock::*; use pallet_nomination_pools::{ - BondExtra, BondedPools, Error as PoolsError, - Event as PoolsEvent, LastPoolId, PoolMember, PoolMembers, PoolState, + BondExtra, BondedPools, Error as PoolsError, Event as PoolsEvent, LastPoolId, PoolMember, + PoolMembers, PoolState, }; use pallet_staking::{ CurrentEra, Error as StakingError, Event as StakingEvent, Payee, RewardDestination, From 923902ee52b0cf2b2024b15d298fd0b85f638975 Mon Sep 17 00:00:00 2001 From: Ankan Date: Thu, 28 Nov 2024 00:05:18 +0100 Subject: [PATCH 126/142] fix bench --- .../benchmarking/src/inner.rs | 75 ++++++++----------- 1 file changed, 30 insertions(+), 45 deletions(-) diff --git a/substrate/frame/nomination-pools/benchmarking/src/inner.rs b/substrate/frame/nomination-pools/benchmarking/src/inner.rs index 2837578a0659..20c5eafbcfc5 100644 --- a/substrate/frame/nomination-pools/benchmarking/src/inner.rs +++ b/substrate/frame/nomination-pools/benchmarking/src/inner.rs @@ -132,6 +132,10 @@ fn migrate_to_transfer_stake(pool_id: PoolId) { .expect("member should have enough balance to transfer"); }); + // Pool needs to have ED balance free to stake so give it some. + // Note: we didn't require ED until pallet-staking migrated from locks to holds. + let _ = CurrencyOf::::mint_into(&pool_acc, CurrencyOf::::minimum_balance()); + pallet_staking::Pallet::::migrate_to_direct_staker(&pool_acc); } @@ -141,14 +145,6 @@ fn vote_to_balance( vote.try_into().map_err(|_| "could not convert u64 to Balance") } -/// `assertion` should strictly be true if the adapter is using `Delegate` strategy and strictly -/// false if the adapter is not using `Delegate` strategy. -fn assert_if_delegate(assertion: bool) { - let legacy_adapter_used = T::StakeAdapter::strategy_type() != StakeStrategyType::Delegate; - // one and only one of the two should be true. - assert!(assertion ^ legacy_adapter_used); -} - #[allow(unused)] struct ListScenario { /// Stash/Controller that is expected to be moved. @@ -981,9 +977,6 @@ mod benchmarks { #[benchmark] fn apply_slash() { - // Note: With `TransferStake` strategy, slashing is greedy and apply_slash should - // always fail. - // We want to fill member's unbonding pools. So let's bond with big enough amount. let deposit_amount = Pools::::depositor_min_bond() * T::MaxUnbonding::get().into() * 4u32.into(); @@ -993,7 +986,7 @@ mod benchmarks { // verify user balance in the pool. assert_eq!(PoolMembers::::get(&depositor).unwrap().total_balance(), deposit_amount); // verify delegated balance. - assert_if_delegate::( + assert!( T::StakeAdapter::member_delegation_balance(Member::from(depositor.clone())) == Some(deposit_amount), ); @@ -1017,7 +1010,7 @@ mod benchmarks { deposit_amount / 2u32.into() ); // verify delegated balance are not yet slashed. - assert_if_delegate::( + assert!( T::StakeAdapter::member_delegation_balance(Member::from(depositor.clone())) == Some(deposit_amount), ); @@ -1041,13 +1034,11 @@ mod benchmarks { #[block] { - assert_if_delegate::( - Pools::::apply_slash( - RuntimeOrigin::Signed(slash_reporter.clone()).into(), - depositor_lookup.clone(), - ) - .is_ok(), - ); + assert!(Pools::::apply_slash( + RuntimeOrigin::Signed(slash_reporter.clone()).into(), + depositor_lookup.clone(), + ) + .is_ok(),); } // verify balances are correct and slash applied. @@ -1055,7 +1046,7 @@ mod benchmarks { PoolMembers::::get(&depositor).unwrap().total_balance(), deposit_amount / 2u32.into() ); - assert_if_delegate::( + assert!( T::StakeAdapter::member_delegation_balance(Member::from(depositor.clone())) == Some(deposit_amount / 2u32.into()), ); @@ -1126,18 +1117,16 @@ mod benchmarks { let _ = migrate_to_transfer_stake::(1); #[block] { - assert_if_delegate::( - Pools::::migrate_pool_to_delegate_stake( - RuntimeOrigin::Signed(depositor.clone()).into(), - 1u32.into(), - ) - .is_ok(), - ); + assert!(Pools::::migrate_pool_to_delegate_stake( + RuntimeOrigin::Signed(depositor.clone()).into(), + 1u32.into(), + ) + .is_ok(),); } - // this queries agent balance if `DelegateStake` strategy. + // this queries agent balance. assert_eq!( T::StakeAdapter::total_balance(Pool::from(pool_account.clone())), - Some(deposit_amount) + Some(deposit_amount + CurrencyOf::::minimum_balance()) ); } @@ -1152,13 +1141,11 @@ mod benchmarks { let _ = migrate_to_transfer_stake::(1); // Now migrate pool to delegate stake keeping delegators unmigrated. - assert_if_delegate::( - Pools::::migrate_pool_to_delegate_stake( - RuntimeOrigin::Signed(depositor.clone()).into(), - 1u32.into(), - ) - .is_ok(), - ); + assert!(Pools::::migrate_pool_to_delegate_stake( + RuntimeOrigin::Signed(depositor.clone()).into(), + 1u32.into(), + ) + .is_ok(),); // delegation does not exist. assert!( @@ -1171,16 +1158,14 @@ mod benchmarks { #[block] { - assert_if_delegate::( - Pools::::migrate_delegation( - RuntimeOrigin::Signed(depositor.clone()).into(), - depositor_lookup.clone(), - ) - .is_ok(), - ); + assert!(Pools::::migrate_delegation( + RuntimeOrigin::Signed(depositor.clone()).into(), + depositor_lookup.clone(), + ) + .is_ok(),); } // verify balances once more. - assert_if_delegate::( + assert!( T::StakeAdapter::member_delegation_balance(Member::from(depositor.clone())) == Some(deposit_amount), ); From 3c6015981c0a823858b43063deb83b8c42e31982 Mon Sep 17 00:00:00 2001 From: Ankan Date: Thu, 28 Nov 2024 00:51:29 +0100 Subject: [PATCH 127/142] fix clippy --- .../election-provider-multi-phase/test-staking-e2e/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/lib.rs b/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/lib.rs index e9ca4fe3ded3..af9f4d844ab9 100644 --- a/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/lib.rs +++ b/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/lib.rs @@ -22,7 +22,6 @@ pub(crate) const LOG_TARGET: &str = "tests::e2e-epm"; use frame_support::{assert_err, assert_noop, assert_ok}; use mock::*; -use pallet_staking::asset::stakeable_balance; use pallet_timestamp::Now; use sp_core::Get; use sp_runtime::Perbill; From 7b04630a92bcc734433930a6b015f68c3cb80e11 Mon Sep 17 00:00:00 2001 From: Ankan Date: Thu, 28 Nov 2024 02:11:01 +0100 Subject: [PATCH 128/142] fix e2e tests --- .../test-staking-e2e/src/lib.rs | 10 +++++----- .../test-staking-e2e/src/mock.rs | 7 +------ 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/lib.rs b/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/lib.rs index af9f4d844ab9..b1029e89fe85 100644 --- a/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/lib.rs +++ b/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/lib.rs @@ -327,8 +327,8 @@ fn automatic_unbonding_pools() { assert_eq!(::MaxUnbonding::get(), 1); // init state of pool members. - let init_stakeable_balance_2 = stakeable_balance_for(2); - let init_stakeable_balance_3 = stakeable_balance_for(3); + let init_free_balance_2 = Balances::free_balance(2); + let init_free_balance_3 = Balances::free_balance(3); let pool_bonded_account = Pools::generate_bonded_account(1); @@ -410,7 +410,7 @@ fn automatic_unbonding_pools() { assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(2), 2, 10)); assert_eq!(delegated_balance_for(pool_bonded_account), 15); - assert_eq!(stakeable_balance_for(2), 20); + assert_eq!(Balances::free_balance(2), 20); assert_eq!(TotalValueLocked::::get(), 15); // 3 cannot withdraw yet. @@ -430,8 +430,8 @@ fn automatic_unbonding_pools() { // final conditions are the expected. assert_eq!(delegated_balance_for(pool_bonded_account), 5); // 5 init bonded - assert_eq!(stakeable_balance_for(2), init_stakeable_balance_2); - assert_eq!(stakeable_balance_for(3), init_stakeable_balance_3); + assert_eq!(Balances::free_balance(2), init_free_balance_2); + assert_eq!(Balances::free_balance(3), init_free_balance_3); assert_eq!(TotalValueLocked::::get(), init_tvl); }); diff --git a/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs b/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs index 59b8fadfecb7..bcb25f8287b3 100644 --- a/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs +++ b/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs @@ -523,7 +523,7 @@ impl Default for BalancesExtBuilder { (100, 100), (200, 100), // stashes - (11, 1000), + (11, 1100), (21, 2000), (31, 3000), (41, 4000), @@ -954,11 +954,6 @@ pub(crate) fn delegated_balance_for(account_id: AccountId) -> Balance { DelegatedStaking::agent_balance(Agent::from(account_id)).unwrap_or_default() } -/// Balance available to be staked for an account. -pub(crate) fn stakeable_balance_for(account_id: AccountId) -> Balance { - pallet_staking::asset::stakeable_balance::(&account_id) -} - pub(crate) fn staking_events() -> Vec> { System::events() .into_iter() From 4b1736b04aa7efa5f614b16eabf5bddc755fb2f5 Mon Sep 17 00:00:00 2001 From: Ankan Date: Thu, 28 Nov 2024 02:33:45 +0100 Subject: [PATCH 129/142] fix ed requirement --- substrate/bin/node/testing/src/genesis.rs | 4 ++-- substrate/frame/root-offences/src/mock.rs | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/substrate/bin/node/testing/src/genesis.rs b/substrate/bin/node/testing/src/genesis.rs index 7f5364744c66..0394f6cd7394 100644 --- a/substrate/bin/node/testing/src/genesis.rs +++ b/substrate/bin/node/testing/src/genesis.rs @@ -38,9 +38,9 @@ pub fn config_endowed(extra_endowed: Vec) -> RuntimeGenesisConfig { (alice(), 111 * DOLLARS), (bob(), 100 * DOLLARS), (charlie(), 100_000_000 * DOLLARS), - (dave(), 111 * DOLLARS), + (dave(), 112 * DOLLARS), (eve(), 101 * DOLLARS), - (ferdie(), 100 * DOLLARS), + (ferdie(), 101 * DOLLARS), ]; endowed.extend(extra_endowed.into_iter().map(|endowed| (endowed, 100 * DOLLARS))); diff --git a/substrate/frame/root-offences/src/mock.rs b/substrate/frame/root-offences/src/mock.rs index 6267ef4f9038..689a20f80774 100644 --- a/substrate/frame/root-offences/src/mock.rs +++ b/substrate/frame/root-offences/src/mock.rs @@ -207,10 +207,10 @@ impl ExtBuilder { (30, self.balance_factor * 50), (40, self.balance_factor * 50), // stashes - (11, self.balance_factor * 1000), - (21, self.balance_factor * 1000), - (31, self.balance_factor * 500), - (41, self.balance_factor * 1000), + (11, self.balance_factor * 1500), + (21, self.balance_factor * 1500), + (31, self.balance_factor * 1000), + (41, self.balance_factor * 2000), ], } .assimilate_storage(&mut storage) From 637321ef9fdbbb08c61af6fa4b43eac6b8f301cb Mon Sep 17 00:00:00 2001 From: Ankan Date: Thu, 28 Nov 2024 12:15:01 +0100 Subject: [PATCH 130/142] remove fungible compat --- prdoc/pr_5501.prdoc | 6 ++---- substrate/bin/node/runtime/src/lib.rs | 6 +++--- .../frame/nomination-pools/runtime-api/src/lib.rs | 3 ++- substrate/frame/treasury/src/lib.rs | 13 ------------- 4 files changed, 7 insertions(+), 21 deletions(-) diff --git a/prdoc/pr_5501.prdoc b/prdoc/pr_5501.prdoc index 88d86db22b63..ed63bdbb93b1 100644 --- a/prdoc/pr_5501.prdoc +++ b/prdoc/pr_5501.prdoc @@ -18,10 +18,8 @@ crates: - name: pallet-delegated-staking bump: patch - name: pallet-nomination-pools - bump: patch - - name: frame-support - bump: patch - - name: pallet-treasury + bump: minor + - name: pallet-nomination-pools-runtime-api bump: patch - name: sp-staking bump: patch diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index 0db163c75a47..292f050b20a7 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -53,7 +53,7 @@ use frame_support::{ Balanced, Credit, HoldConsideration, ItemOf, NativeFromLeft, NativeOrWithId, UnionOf, }, tokens::{ - imbalance::ResolveAssetTo, nonfungibles_v2::Inspect, pay::PayAssetFromAccount, + imbalance::{ResolveTo, ResolveAssetTo}, nonfungibles_v2::Inspect, pay::PayAssetFromAccount, GetSalary, PayFromAccount, }, AsEnsureOriginWithArg, ConstBool, ConstU128, ConstU16, ConstU32, ConstU64, Contains, @@ -717,10 +717,10 @@ impl pallet_staking::Config for Runtime { type CurrencyBalance = Balance; type UnixTime = Timestamp; type CurrencyToVote = sp_staking::currency_to_vote::U128CurrencyToVote; - type RewardRemainder = pallet_treasury::FungibleCompat; + type RewardRemainder = ResolveTo; type RuntimeEvent = RuntimeEvent; type RuntimeHoldReason = RuntimeHoldReason; - type Slash = pallet_treasury::FungibleCompat; // send the slashed funds to the treasury. + type Slash = ResolveTo; // send the slashed funds to the treasury. type Reward = (); // rewards are minted from the void type SessionsPerEra = SessionsPerEra; type BondingDuration = BondingDuration; diff --git a/substrate/frame/nomination-pools/runtime-api/src/lib.rs b/substrate/frame/nomination-pools/runtime-api/src/lib.rs index 4229d901bbdc..644ee07fd634 100644 --- a/substrate/frame/nomination-pools/runtime-api/src/lib.rs +++ b/substrate/frame/nomination-pools/runtime-api/src/lib.rs @@ -52,7 +52,8 @@ sp_api::decl_runtime_apis! { /// /// This can happen when the `pallet-nomination-pools` has switched to using strategy /// [`DelegateStake`](pallet_nomination_pools::adapter::DelegateStake) but the pool - /// still has funds that were staked using the deprecated `TransferStake` strategy. Use + /// still has funds that were staked using the older strategy + /// [TransferStake](pallet_nomination_pools::adapter::TransferStake). Use /// [`migrate_pool_to_delegate_stake`](pallet_nomination_pools::Call::migrate_pool_to_delegate_stake) /// to migrate the pool. fn pool_needs_delegate_migration(pool_id: PoolId) -> bool; diff --git a/substrate/frame/treasury/src/lib.rs b/substrate/frame/treasury/src/lib.rs index 1d088d12d2dd..4460ec0a5ee0 100644 --- a/substrate/frame/treasury/src/lib.rs +++ b/substrate/frame/treasury/src/lib.rs @@ -1081,19 +1081,6 @@ impl, I: 'static> OnUnbalanced> for Palle } } -/// Implement the `OnUnbalanced` handler for [`frame_support::traits::fungible`] trait currency. -pub struct FungibleCompat(PhantomData); -impl OnUnbalanced> for FungibleCompat { - fn on_nonzero_unbalanced(credit: Credit) { - use frame_support::traits::fungible::Balanced; - let numeric_amount = credit.peek(); - - let _ = T::Currency::resolve(&Pallet::::account_id(), credit).defensive(); - - Pallet::::deposit_event(Event::Deposit { value: numeric_amount }); - } -} - /// TypedGet implementation to get the AccountId of the Treasury. pub struct TreasuryAccountId(PhantomData); impl sp_runtime::traits::TypedGet for TreasuryAccountId From 0a97a04bba1072d95098f65c6a41591be38487ee Mon Sep 17 00:00:00 2001 From: Ankan Date: Thu, 28 Nov 2024 12:42:46 +0100 Subject: [PATCH 131/142] keep migration tests in test-delegate-stake --- prdoc/pr_5501.prdoc | 2 +- substrate/bin/node/runtime/src/lib.rs | 4 +- .../test-delegate-stake/src/lib.rs | 476 +++++++++++++++++- .../test-delegate-stake/src/mock.rs | 117 ++++- 4 files changed, 592 insertions(+), 7 deletions(-) diff --git a/prdoc/pr_5501.prdoc b/prdoc/pr_5501.prdoc index ed63bdbb93b1..33bd21ccd947 100644 --- a/prdoc/pr_5501.prdoc +++ b/prdoc/pr_5501.prdoc @@ -40,4 +40,4 @@ crates: - name: pallet-root-offences bump: patch - name: pallet-offences-benchmarking - bump: patch \ No newline at end of file + bump: patch diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index 292f050b20a7..22ad9401e142 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -53,7 +53,9 @@ use frame_support::{ Balanced, Credit, HoldConsideration, ItemOf, NativeFromLeft, NativeOrWithId, UnionOf, }, tokens::{ - imbalance::{ResolveTo, ResolveAssetTo}, nonfungibles_v2::Inspect, pay::PayAssetFromAccount, + imbalance::{ResolveAssetTo, ResolveTo}, + nonfungibles_v2::Inspect, + pay::PayAssetFromAccount, GetSalary, PayFromAccount, }, AsEnsureOriginWithArg, ConstBool, ConstU128, ConstU16, ConstU32, ConstU64, Contains, diff --git a/substrate/frame/nomination-pools/test-delegate-stake/src/lib.rs b/substrate/frame/nomination-pools/test-delegate-stake/src/lib.rs index 27b1524c6e98..50048c36982f 100644 --- a/substrate/frame/nomination-pools/test-delegate-stake/src/lib.rs +++ b/substrate/frame/nomination-pools/test-delegate-stake/src/lib.rs @@ -21,12 +21,12 @@ mod mock; use frame_support::{ assert_noop, assert_ok, hypothetically, - traits::{fungible::InspectHold, Currency}, + traits::{fungible::{InspectHold, Mutate}, Currency}, }; use mock::*; use pallet_nomination_pools::{ - BondExtra, BondedPools, Error as PoolsError, Event as PoolsEvent, LastPoolId, PoolMember, - PoolMembers, PoolState, + BondExtra, BondedPools, CommissionChangeRate, ConfigOp, Error as PoolsError, + Event as PoolsEvent, LastPoolId, PoolMember, PoolMembers, PoolState, }; use pallet_staking::{ CurrentEra, Error as StakingError, Event as StakingEvent, Payee, RewardDestination, @@ -34,7 +34,8 @@ use pallet_staking::{ use pallet_delegated_staking::Event as DelegatedStakingEvent; -use sp_runtime::{bounded_btree_map, traits::Zero}; +use sp_runtime::{bounded_btree_map, traits::Zero, Perbill}; +use sp_staking::Agent; #[test] fn pool_lifecycle_e2e() { @@ -936,6 +937,473 @@ fn pool_slash_non_proportional_bonded_pool_and_chunks() { ); }); } + +#[test] +fn pool_migration_e2e() { + new_test_ext().execute_with(|| { + LegacyAdapter::set(true); + assert_eq!(CurrentEra::::get(), None); + + // hack: mint ED to pool so that the deprecated `TransferStake` works correctly with + // staking. + assert_eq!(Balances::minimum_balance(), 5); + assert_ok!(Balances::mint_into(&POOL1_BONDED, 5)); + + // create the pool with TransferStake strategy. + assert_ok!(Pools::create(RuntimeOrigin::signed(10), 50, 10, 10, 10)); + assert_eq!(LastPoolId::::get(), 1); + + // have the pool nominate. + assert_ok!(Pools::nominate(RuntimeOrigin::signed(10), 1, vec![1, 2, 3])); + + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: 50 }] + ); + assert_eq!( + pool_events_since_last_call(), + vec![ + PoolsEvent::Created { depositor: 10, pool_id: 1 }, + PoolsEvent::Bonded { member: 10, pool_id: 1, bonded: 50, joined: true }, + ] + ); + + // have three members join + let pre_20 = Balances::free_balance(20); + assert_ok!(Pools::join(RuntimeOrigin::signed(20), 10, 1)); + let pre_21 = Balances::free_balance(21); + assert_ok!(Pools::join(RuntimeOrigin::signed(21), 10, 1)); + let pre_22 = Balances::free_balance(22); + assert_ok!(Pools::join(RuntimeOrigin::signed(22), 10, 1)); + + // verify members balance is moved to pool. + assert_eq!(Balances::free_balance(20), pre_20 - 10); + assert_eq!(Balances::free_balance(21), pre_21 - 10); + assert_eq!(Balances::free_balance(22), pre_22 - 10); + + assert_eq!( + staking_events_since_last_call(), + vec![ + StakingEvent::Bonded { stash: POOL1_BONDED, amount: 10 }, + StakingEvent::Bonded { stash: POOL1_BONDED, amount: 10 }, + StakingEvent::Bonded { stash: POOL1_BONDED, amount: 10 }, + ] + ); + assert_eq!( + pool_events_since_last_call(), + vec![ + PoolsEvent::Bonded { member: 20, pool_id: 1, bonded: 10, joined: true }, + PoolsEvent::Bonded { member: 21, pool_id: 1, bonded: 10, joined: true }, + PoolsEvent::Bonded { member: 22, pool_id: 1, bonded: 10, joined: true }, + ] + ); + + CurrentEra::::set(Some(2)); + // 20 is partially unbonding + assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 5)); + + CurrentEra::::set(Some(3)); + // 21 is fully unbonding + assert_ok!(Pools::unbond(RuntimeOrigin::signed(21), 21, 10)); + + assert_eq!( + staking_events_since_last_call(), + vec![ + StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 5 }, + StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 }, + ] + ); + assert_eq!( + pool_events_since_last_call(), + vec![ + PoolsEvent::Unbonded { member: 20, pool_id: 1, balance: 5, points: 5, era: 5 }, + PoolsEvent::Unbonded { member: 21, pool_id: 1, balance: 10, points: 10, era: 6 }, + ] + ); + + // with `TransferStake`, we can't migrate. + assert!(!Pools::api_pool_needs_delegate_migration(1)); + assert_noop!( + Pools::migrate_pool_to_delegate_stake(RuntimeOrigin::signed(10), 1), + PoolsError::::NotSupported + ); + + // we reset the adapter to `DelegateStake`. + LegacyAdapter::set(false); + + // cannot migrate the member delegation unless pool is migrated first. + assert_noop!( + Pools::migrate_delegation(RuntimeOrigin::signed(10), 20), + PoolsError::::NotMigrated + ); + + // migrate the pool. + assert!(Pools::api_pool_needs_delegate_migration(1)); + assert_ok!(Pools::migrate_pool_to_delegate_stake(RuntimeOrigin::signed(10), 1)); + + // migrate again does not work. + assert!(!Pools::api_pool_needs_delegate_migration(1)); + assert_noop!( + Pools::migrate_pool_to_delegate_stake(RuntimeOrigin::signed(10), 1), + PoolsError::::AlreadyMigrated + ); + + // unclaimed delegations to the pool are stored in this account. + let proxy_delegator_1 = + DelegatedStaking::generate_proxy_delegator(Agent::from(POOL1_BONDED)).get(); + + assert_eq!( + delegated_staking_events_since_last_call(), + // delegated also contains the extra ED that we minted when pool was `TransferStake` . + vec![DelegatedStakingEvent::Delegated { + agent: POOL1_BONDED, + delegator: proxy_delegator_1, + amount: 50 + 10 * 3 + 5 + }] + ); + + // move to era 5 when 20 can withdraw unbonded funds. + CurrentEra::::set(Some(5)); + + // Cannot unbond without claiming delegation. Lets unbond 22. + assert_noop!( + Pools::unbond(RuntimeOrigin::signed(22), 22, 5), + PoolsError::::NotMigrated + ); + + // withdraw fails for 20 before claiming delegation + assert_noop!( + Pools::withdraw_unbonded(RuntimeOrigin::signed(20), 20, 10), + PoolsError::::NotMigrated + ); + + let pre_claim_balance_20 = Balances::total_balance(&20); + assert_eq!(Balances::total_balance_on_hold(&20), 0); + + // migrate delegation for 20. This is permissionless and can be called by anyone. + assert!(Pools::api_member_needs_delegate_migration(20)); + assert_ok!(Pools::migrate_delegation(RuntimeOrigin::signed(10), 20)); + + // tokens moved to 20's account and held there. + assert_eq!(Balances::total_balance(&20), pre_claim_balance_20 + 10); + assert_eq!(Balances::total_balance_on_hold(&20), 10); + + // withdraw works now + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(20), 20, 5)); + + // balance unlocked in 20's account + assert_eq!(Balances::total_balance_on_hold(&20), 5); + assert_eq!(Balances::total_balance(&20), pre_claim_balance_20 + 10); + + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Withdrawn { stash: POOL1_BONDED, amount: 5 }] + ); + assert_eq!( + pool_events_since_last_call(), + vec![PoolsEvent::Withdrawn { member: 20, pool_id: 1, balance: 5, points: 5 },] + ); + assert_eq!( + delegated_staking_events_since_last_call(), + vec![ + DelegatedStakingEvent::MigratedDelegation { + agent: POOL1_BONDED, + delegator: 20, + amount: 10 + }, + DelegatedStakingEvent::Released { agent: POOL1_BONDED, delegator: 20, amount: 5 } + ] + ); + + // MIGRATE 21 + let pre_migrate_balance_21 = Balances::total_balance(&21); + assert_eq!(Balances::total_balance_on_hold(&21), 0); + + // migrate delegation for 21. + assert!(Pools::api_member_needs_delegate_migration(21)); + assert_ok!(Pools::migrate_delegation(RuntimeOrigin::signed(10), 21)); + + // tokens moved to 21's account and held there. + assert_eq!(Balances::total_balance(&21), pre_migrate_balance_21 + 10); + assert_eq!(Balances::total_balance_on_hold(&21), 10); + + // withdraw fails since 21 only unbonds at era 6. + assert_noop!( + Pools::withdraw_unbonded(RuntimeOrigin::signed(21), 21, 10), + PoolsError::::CannotWithdrawAny + ); + + // go to era when 21 can unbond + CurrentEra::::set(Some(6)); + + // withdraw works now + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(21), 21, 10)); + + // all balance unlocked in 21's account + assert_eq!(Balances::total_balance_on_hold(&21), 0); + assert_eq!(Balances::total_balance(&21), pre_migrate_balance_21 + 10); + + // MIGRATE 22 + assert_eq!(Balances::total_balance_on_hold(&22), 0); + // make balance of 22 as 0. + let _ = Balances::make_free_balance_be(&22, 0); + + // migrate delegation for 22. + assert!(Pools::api_member_needs_delegate_migration(22)); + assert_ok!(Pools::migrate_delegation(RuntimeOrigin::signed(10), 22)); + + // cannot migrate a pool member again. + assert!(!Pools::api_member_needs_delegate_migration(22)); + assert_noop!( + Pools::migrate_delegation(RuntimeOrigin::signed(10), 22), + PoolsError::::AlreadyMigrated + ); + + // tokens moved to 22's account and held there. + assert_eq!(Balances::total_balance(&22), 10); + assert_eq!(Balances::total_balance_on_hold(&22), 10); + + // unbond 22 should work now + assert_ok!(Pools::unbond(RuntimeOrigin::signed(22), 22, 5)); + + // withdraw fails since 22 only unbonds after era 9. + assert_noop!( + Pools::withdraw_unbonded(RuntimeOrigin::signed(22), 22, 5), + PoolsError::::CannotWithdrawAny + ); + + // go to era when 22 can unbond + CurrentEra::::set(Some(9)); + + // withdraw works now + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(22), 22, 10)); + + // balance of 5 unlocked in 22's account + assert_eq!(Balances::total_balance_on_hold(&22), 10 - 5); + + // assert events for 21 and 22. + assert_eq!( + staking_events_since_last_call(), + vec![ + StakingEvent::Withdrawn { stash: POOL1_BONDED, amount: 10 }, + StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 5 }, + StakingEvent::Withdrawn { stash: POOL1_BONDED, amount: 5 } + ] + ); + + assert_eq!( + pool_events_since_last_call(), + vec![ + PoolsEvent::Withdrawn { member: 21, pool_id: 1, balance: 10, points: 10 }, + // 21 was fully unbonding and removed from pool. + PoolsEvent::MemberRemoved { member: 21, pool_id: 1, released_balance: 0 }, + PoolsEvent::Unbonded { member: 22, pool_id: 1, balance: 5, points: 5, era: 9 }, + PoolsEvent::Withdrawn { member: 22, pool_id: 1, balance: 5, points: 5 }, + ] + ); + assert_eq!( + delegated_staking_events_since_last_call(), + vec![ + DelegatedStakingEvent::MigratedDelegation { + agent: POOL1_BONDED, + delegator: 21, + amount: 10 + }, + DelegatedStakingEvent::Released { agent: POOL1_BONDED, delegator: 21, amount: 10 }, + DelegatedStakingEvent::MigratedDelegation { + agent: POOL1_BONDED, + delegator: 22, + amount: 10 + }, + DelegatedStakingEvent::Released { agent: POOL1_BONDED, delegator: 22, amount: 5 } + ] + ); + }) +} + +#[test] +fn disable_pool_operations_on_non_migrated() { + new_test_ext().execute_with(|| { + LegacyAdapter::set(true); + assert_eq!(Balances::minimum_balance(), 5); + assert_eq!(CurrentEra::::get(), None); + + // hack: mint ED to pool so that the deprecated `TransferStake` works correctly with + // staking. + assert_eq!(Balances::minimum_balance(), 5); + assert_ok!(Balances::mint_into(&POOL1_BONDED, 5)); + + // create the pool with TransferStake strategy. + assert_ok!(Pools::create(RuntimeOrigin::signed(10), 50, 10, 10, 10)); + assert_eq!(LastPoolId::::get(), 1); + + // have the pool nominate. + assert_ok!(Pools::nominate(RuntimeOrigin::signed(10), 1, vec![1, 2, 3])); + + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: 50 }] + ); + assert_eq!( + pool_events_since_last_call(), + vec![ + PoolsEvent::Created { depositor: 10, pool_id: 1 }, + PoolsEvent::Bonded { member: 10, pool_id: 1, bonded: 50, joined: true }, + ] + ); + + let pre_20 = Balances::free_balance(20); + assert_ok!(Pools::join(RuntimeOrigin::signed(20), 10, 1)); + + // verify members balance is moved to pool. + assert_eq!(Balances::free_balance(20), pre_20 - 10); + + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: 10 },] + ); + assert_eq!( + pool_events_since_last_call(), + vec![PoolsEvent::Bonded { member: 20, pool_id: 1, bonded: 10, joined: true },] + ); + + // we reset the adapter to `DelegateStake`. + LegacyAdapter::set(false); + + // pool is pending migration. + assert!(Pools::api_pool_needs_delegate_migration(1)); + + // ensure pool mutation is not allowed until pool is migrated. + assert_noop!( + Pools::join(RuntimeOrigin::signed(21), 10, 1), + PoolsError::::NotMigrated + ); + assert_noop!( + Pools::pool_withdraw_unbonded(RuntimeOrigin::signed(10), 1, 0), + PoolsError::::NotMigrated + ); + assert_noop!( + Pools::nominate(RuntimeOrigin::signed(10), 1, vec![1, 2, 3]), + PoolsError::::NotMigrated + ); + assert_noop!( + Pools::set_state(RuntimeOrigin::signed(10), 1, PoolState::Blocked), + PoolsError::::NotMigrated + ); + assert_noop!( + Pools::set_metadata(RuntimeOrigin::signed(10), 1, vec![1, 1]), + PoolsError::::NotMigrated + ); + assert_noop!( + Pools::update_roles( + RuntimeOrigin::signed(10), + 1, + ConfigOp::Set(5), + ConfigOp::Set(6), + ConfigOp::Set(7) + ), + PoolsError::::NotMigrated + ); + assert_noop!( + Pools::chill(RuntimeOrigin::signed(10), 1), + PoolsError::::NotMigrated + ); + assert_noop!( + Pools::set_commission(RuntimeOrigin::signed(10), 1, None), + PoolsError::::NotMigrated + ); + assert_noop!( + Pools::set_commission_max(RuntimeOrigin::signed(10), 1, Zero::zero()), + PoolsError::::NotMigrated + ); + assert_noop!( + Pools::set_commission_change_rate( + RuntimeOrigin::signed(10), + 1, + CommissionChangeRate { max_increase: Perbill::from_percent(1), min_delay: 2_u64 } + ), + PoolsError::::NotMigrated + ); + assert_noop!( + Pools::claim_commission(RuntimeOrigin::signed(10), 1), + PoolsError::::NotMigrated + ); + assert_noop!( + Pools::adjust_pool_deposit(RuntimeOrigin::signed(10), 1), + PoolsError::::NotMigrated + ); + assert_noop!( + Pools::set_commission_claim_permission(RuntimeOrigin::signed(10), 1, None), + PoolsError::::NotMigrated + ); + + // migrate the pool. + assert_ok!(Pools::migrate_pool_to_delegate_stake(RuntimeOrigin::signed(10), 1)); + assert_eq!( + delegated_staking_events_since_last_call(), + // delegated also contains the extra ED that we minted when pool was `TransferStake` . + vec![DelegatedStakingEvent::Delegated { + agent: POOL1_BONDED, + delegator: DelegatedStaking::generate_proxy_delegator(Agent::from(POOL1_BONDED)) + .get(), + amount: 50 + 10 + 5 + },] + ); + + // member is pending migration. + assert!(Pools::api_member_needs_delegate_migration(20)); + + // ensure member mutation is not allowed until member's delegation is migrated. + assert_noop!( + Pools::bond_extra(RuntimeOrigin::signed(20), BondExtra::FreeBalance(5)), + PoolsError::::NotMigrated + ); + assert_noop!( + Pools::bond_extra_other(RuntimeOrigin::signed(10), 20, BondExtra::Rewards), + PoolsError::::NotMigrated + ); + assert_noop!( + Pools::claim_payout(RuntimeOrigin::signed(20)), + PoolsError::::NotMigrated + ); + assert_noop!( + Pools::unbond(RuntimeOrigin::signed(20), 20, 5), + PoolsError::::NotMigrated + ); + assert_noop!( + Pools::withdraw_unbonded(RuntimeOrigin::signed(20), 20, 0), + PoolsError::::NotMigrated + ); + + // migrate 20 + assert_ok!(Pools::migrate_delegation(RuntimeOrigin::signed(10), 20)); + // now `bond_extra` for 20 works. + assert_ok!(Pools::bond_extra(RuntimeOrigin::signed(20), BondExtra::FreeBalance(5))); + + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: 5 },] + ); + + assert_eq!( + pool_events_since_last_call(), + vec![PoolsEvent::Bonded { member: 20, pool_id: 1, bonded: 5, joined: false },] + ); + + assert_eq!( + delegated_staking_events_since_last_call(), + vec![ + DelegatedStakingEvent::MigratedDelegation { + agent: POOL1_BONDED, + delegator: 20, + amount: 10 + }, + DelegatedStakingEvent::Delegated { agent: POOL1_BONDED, delegator: 20, amount: 5 }, + ] + ); + }) +} + #[test] fn pool_no_dangling_delegation() { new_test_ext().execute_with(|| { diff --git a/substrate/frame/nomination-pools/test-delegate-stake/src/mock.rs b/substrate/frame/nomination-pools/test-delegate-stake/src/mock.rs index cc871b9e56bd..d943ba6f5333 100644 --- a/substrate/frame/nomination-pools/test-delegate-stake/src/mock.rs +++ b/substrate/frame/nomination-pools/test-delegate-stake/src/mock.rs @@ -15,6 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +// Disable warnings for `TransferStake` being deprecated. #![allow(deprecated)] use frame_election_provider_support::VoteWeight; @@ -26,6 +27,10 @@ use frame_support::{ PalletId, }; use frame_system::EnsureRoot; +use pallet_nomination_pools::{ + adapter::{Member, Pool, StakeStrategyType}, + BondType, +}; use sp_runtime::{ traits::{Convert, IdentityLookup}, BuildStorage, FixedU128, Perbill, @@ -135,10 +140,120 @@ impl Convert for U256ToBalance { parameter_types! { pub const PostUnbondingPoolsWindow: u32 = 10; pub const PoolsPalletId: PalletId = PalletId(*b"py/nopls"); + pub static LegacyAdapter: bool = false; } +pub struct MockAdapter; type DelegateStake = pallet_nomination_pools::adapter::DelegateStake; +type TransferStake = pallet_nomination_pools::adapter::TransferStake; +impl pallet_nomination_pools::adapter::StakeStrategy for MockAdapter { + type Balance = Balance; + type AccountId = AccountId; + type CoreStaking = Staking; + + fn strategy_type() -> StakeStrategyType { + if LegacyAdapter::get() { + return TransferStake::strategy_type() + } + DelegateStake::strategy_type() + } + fn transferable_balance( + pool_account: Pool, + member_account: Member, + ) -> Self::Balance { + if LegacyAdapter::get() { + return TransferStake::transferable_balance(pool_account, member_account) + } + DelegateStake::transferable_balance(pool_account, member_account) + } + + fn total_balance(pool_account: Pool) -> Option { + if LegacyAdapter::get() { + return TransferStake::total_balance(pool_account) + } + DelegateStake::total_balance(pool_account) + } + + fn member_delegation_balance(member_account: Member) -> Option { + if LegacyAdapter::get() { + return TransferStake::member_delegation_balance(member_account) + } + DelegateStake::member_delegation_balance(member_account) + } + + fn pledge_bond( + who: Member, + pool_account: Pool, + reward_account: &Self::AccountId, + amount: Self::Balance, + bond_type: BondType, + ) -> DispatchResult { + if LegacyAdapter::get() { + return TransferStake::pledge_bond(who, pool_account, reward_account, amount, bond_type) + } + DelegateStake::pledge_bond(who, pool_account, reward_account, amount, bond_type) + } + + fn member_withdraw( + who: Member, + pool_account: Pool, + amount: Self::Balance, + num_slashing_spans: u32, + ) -> DispatchResult { + if LegacyAdapter::get() { + return TransferStake::member_withdraw(who, pool_account, amount, num_slashing_spans) + } + DelegateStake::member_withdraw(who, pool_account, amount, num_slashing_spans) + } + + fn dissolve(pool_account: Pool) -> DispatchResult { + if LegacyAdapter::get() { + return TransferStake::dissolve(pool_account) + } + DelegateStake::dissolve(pool_account) + } + + fn pending_slash(pool_account: Pool) -> Self::Balance { + if LegacyAdapter::get() { + return TransferStake::pending_slash(pool_account) + } + DelegateStake::pending_slash(pool_account) + } + + fn member_slash( + who: Member, + pool_account: Pool, + amount: Self::Balance, + maybe_reporter: Option, + ) -> DispatchResult { + if LegacyAdapter::get() { + return TransferStake::member_slash(who, pool_account, amount, maybe_reporter) + } + DelegateStake::member_slash(who, pool_account, amount, maybe_reporter) + } + + fn migrate_nominator_to_agent( + agent: Pool, + reward_account: &Self::AccountId, + ) -> DispatchResult { + if LegacyAdapter::get() { + return TransferStake::migrate_nominator_to_agent(agent, reward_account) + } + DelegateStake::migrate_nominator_to_agent(agent, reward_account) + } + + fn migrate_delegation( + agent: Pool, + delegator: Member, + value: Self::Balance, + ) -> DispatchResult { + if LegacyAdapter::get() { + return TransferStake::migrate_delegation(agent, delegator, value) + } + DelegateStake::migrate_delegation(agent, delegator, value) + } +} impl pallet_nomination_pools::Config for Runtime { type RuntimeEvent = RuntimeEvent; type WeightInfo = (); @@ -147,7 +262,7 @@ impl pallet_nomination_pools::Config for Runtime { type RewardCounter = FixedU128; type BalanceToU256 = BalanceToU256; type U256ToBalance = U256ToBalance; - type StakeAdapter = DelegateStake; + type StakeAdapter = MockAdapter; type PostUnbondingPoolsWindow = PostUnbondingPoolsWindow; type MaxMetadataLen = ConstU32<256>; type MaxUnbonding = ConstU32<8>; From 3182687a88c810cb966ae3d2a06458bddb3b0a2f Mon Sep 17 00:00:00 2001 From: Ankan Date: Thu, 28 Nov 2024 12:53:11 +0100 Subject: [PATCH 132/142] remove purge_keys --- substrate/frame/staking/src/lib.rs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/substrate/frame/staking/src/lib.rs b/substrate/frame/staking/src/lib.rs index 007f584519b6..32f69b2cffbf 100644 --- a/substrate/frame/staking/src/lib.rs +++ b/substrate/frame/staking/src/lib.rs @@ -855,8 +855,6 @@ pub trait SessionInterface { fn validators() -> Vec; /// Prune historical session tries up to but not including the given index. fn prune_historical_up_to(up_to: SessionIndex); - /// Purge session key of the validator. - fn purge_keys(stash: AccountId) -> DispatchResult; } impl SessionInterface<::AccountId> for T @@ -888,10 +886,6 @@ where fn prune_historical_up_to(up_to: SessionIndex) { >::prune_up_to(up_to); } - - fn purge_keys(stash: ::AccountId) -> DispatchResult { - >::purge_keys(RawOrigin::Signed(stash.clone()).into()) - } } impl SessionInterface for () { @@ -907,9 +901,6 @@ impl SessionInterface for () { fn prune_historical_up_to(_: SessionIndex) { () } - fn purge_keys(_stash: AccountId) -> DispatchResult { - Ok(()) - } } /// Handler for determining how much of a balance should be paid out on the current era. From 60b0018254d600cff1b42268d2ae9129b40c7ca9 Mon Sep 17 00:00:00 2001 From: Ankan Date: Thu, 28 Nov 2024 12:58:23 +0100 Subject: [PATCH 133/142] revert treasury changes --- substrate/frame/treasury/src/lib.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/substrate/frame/treasury/src/lib.rs b/substrate/frame/treasury/src/lib.rs index 4460ec0a5ee0..281012ffb4c9 100644 --- a/substrate/frame/treasury/src/lib.rs +++ b/substrate/frame/treasury/src/lib.rs @@ -100,8 +100,8 @@ use frame_support::{ dispatch::{DispatchResult, DispatchResultWithPostInfo}, ensure, print, traits::{ - fungible::Credit, tokens::Pay, Currency, Defensive, ExistenceRequirement::KeepAlive, Get, - Imbalance, OnUnbalanced, ReservableCurrency, WithdrawReasons, + tokens::Pay, Currency, ExistenceRequirement::KeepAlive, Get, Imbalance, OnUnbalanced, + ReservableCurrency, WithdrawReasons, }, weights::Weight, BoundedVec, PalletId, @@ -212,9 +212,7 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { /// The staking balance. - type Currency: Currency - + ReservableCurrency - + frame_support::traits::fungible::Balanced>; + type Currency: Currency + ReservableCurrency; /// Origin from which rejections must come. type RejectOrigin: EnsureOrigin; From 5483e96870fff6b015d1554d92944d057c0de642 Mon Sep 17 00:00:00 2001 From: Ankan Date: Thu, 28 Nov 2024 13:59:10 +0100 Subject: [PATCH 134/142] fmt --- .../frame/nomination-pools/test-delegate-stake/src/lib.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/substrate/frame/nomination-pools/test-delegate-stake/src/lib.rs b/substrate/frame/nomination-pools/test-delegate-stake/src/lib.rs index 50048c36982f..54783332aa3e 100644 --- a/substrate/frame/nomination-pools/test-delegate-stake/src/lib.rs +++ b/substrate/frame/nomination-pools/test-delegate-stake/src/lib.rs @@ -21,7 +21,10 @@ mod mock; use frame_support::{ assert_noop, assert_ok, hypothetically, - traits::{fungible::{InspectHold, Mutate}, Currency}, + traits::{ + fungible::{InspectHold, Mutate}, + Currency, + }, }; use mock::*; use pallet_nomination_pools::{ From 7c9a4b9d69bae8251cab61346ca469f29a301146 Mon Sep 17 00:00:00 2001 From: Ankan Date: Thu, 28 Nov 2024 14:30:05 +0100 Subject: [PATCH 135/142] remove unused import --- substrate/frame/staking/src/lib.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/substrate/frame/staking/src/lib.rs b/substrate/frame/staking/src/lib.rs index 32f69b2cffbf..42230cb27b75 100644 --- a/substrate/frame/staking/src/lib.rs +++ b/substrate/frame/staking/src/lib.rs @@ -318,12 +318,11 @@ use frame_support::{ weights::Weight, BoundedVec, CloneNoBound, EqNoBound, PartialEqNoBound, RuntimeDebugNoBound, }; -use frame_system::RawOrigin; use scale_info::TypeInfo; use sp_runtime::{ curve::PiecewiseLinear, traits::{AtLeast32BitUnsigned, Convert, StaticLookup, Zero}, - DispatchResult, Perbill, Perquintill, Rounding, RuntimeDebug, Saturating, + Perbill, Perquintill, Rounding, RuntimeDebug, Saturating, }; use sp_staking::{ offence::{Offence, OffenceError, OffenceSeverity, ReportOffence}, From 5cdc7852d5b0489f2b2c557f1ef9275bec13be03 Mon Sep 17 00:00:00 2001 From: Ankan Date: Sun, 1 Dec 2024 02:39:24 +0100 Subject: [PATCH 136/142] fix staking stake balance --- polkadot/runtime/westend/src/tests.rs | 2 +- substrate/frame/staking/src/asset.rs | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/polkadot/runtime/westend/src/tests.rs b/polkadot/runtime/westend/src/tests.rs index bf75dfa0e469..d1fdca0f0bf7 100644 --- a/polkadot/runtime/westend/src/tests.rs +++ b/polkadot/runtime/westend/src/tests.rs @@ -252,7 +252,7 @@ mod remote_tests { } sp_tracing::try_init_simple(); - let transport: Transport = var("WS").unwrap_or("ws://127.0.0.1:9900".to_string()).into(); + let transport: Transport = var("WS").unwrap_or("ws://127.0.0.1:9944".to_string()).into(); let maybe_state_snapshot: Option = var("SNAP").map(|s| s.into()).ok(); let online_config = OnlineConfig { transport, diff --git a/substrate/frame/staking/src/asset.rs b/substrate/frame/staking/src/asset.rs index 9c3d483f9427..26eb554a0459 100644 --- a/substrate/frame/staking/src/asset.rs +++ b/substrate/frame/staking/src/asset.rs @@ -61,7 +61,9 @@ pub fn staked(who: &T::AccountId) -> BalanceOf { /// /// Does not include the current stake. pub fn free_to_stake(who: &T::AccountId) -> BalanceOf { - T::Currency::reducible_balance(who, Preservation::Preserve, Fortitude::Polite) + // since we want to be able to use frozen funds for staking, we force the reduction. + // todo(ank4n): test above scenario. + T::Currency::reducible_balance(who, Preservation::Preserve, Fortitude::Force) } /// Set balance that can be staked for `who`. From 07b5e3c549d635310c4d1bd4eadd657f7ff53f88 Mon Sep 17 00:00:00 2001 From: Ankan Date: Sun, 1 Dec 2024 03:05:20 +0100 Subject: [PATCH 137/142] fix tests --- substrate/frame/staking/src/tests.rs | 455 ++++++++++++++------------- 1 file changed, 231 insertions(+), 224 deletions(-) diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 648e2b4d3ab4..22067dee0e15 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -6231,240 +6231,247 @@ fn force_apply_min_commission_works() { #[test] fn proportional_slash_stop_slashing_if_remaining_zero() { - let c = |era, value| UnlockChunk:: { era, value }; + ExtBuilder::default().nominate(true).build_and_execute(|| { + let c = |era, value| UnlockChunk:: { era, value }; - // we have some chunks, but they are not affected. - let unlocking = bounded_vec![c(1, 10), c(2, 10)]; + // we have some chunks, but they are not affected. + let unlocking = bounded_vec![c(1, 10), c(2, 10)]; - // Given - let mut ledger = StakingLedger::::new(123, 20); - ledger.total = 40; - ledger.unlocking = unlocking; + // Given + let mut ledger = StakingLedger::::new(123, 20); + ledger.total = 40; + ledger.unlocking = unlocking; - assert_eq!(BondingDuration::get(), 3); + assert_eq!(BondingDuration::get(), 3); - // should not slash more than the amount requested, by accidentally slashing the first chunk. - assert_eq!(ledger.slash(18, 1, 0), 18); + // should not slash more than the amount requested, by accidentally slashing the first chunk. + assert_eq!(ledger.slash(18, 1, 0), 18); + }); } #[test] fn proportional_ledger_slash_works() { - let c = |era, value| UnlockChunk:: { era, value }; - // Given - let mut ledger = StakingLedger::::new(123, 10); - assert_eq!(BondingDuration::get(), 3); - - // When we slash a ledger with no unlocking chunks - assert_eq!(ledger.slash(5, 1, 0), 5); - // Then - assert_eq!(ledger.total, 5); - assert_eq!(ledger.active, 5); - assert_eq!(LedgerSlashPerEra::get().0, 5); - assert_eq!(LedgerSlashPerEra::get().1, Default::default()); - - // When we slash a ledger with no unlocking chunks and the slash amount is greater then the - // total - assert_eq!(ledger.slash(11, 1, 0), 5); - // Then - assert_eq!(ledger.total, 0); - assert_eq!(ledger.active, 0); - assert_eq!(LedgerSlashPerEra::get().0, 0); - assert_eq!(LedgerSlashPerEra::get().1, Default::default()); - - // Given - ledger.unlocking = bounded_vec![c(4, 10), c(5, 10)]; - ledger.total = 2 * 10; - ledger.active = 0; - // When all the chunks overlap with the slash eras - assert_eq!(ledger.slash(20, 0, 0), 20); - // Then - assert_eq!(ledger.unlocking, vec![]); - assert_eq!(ledger.total, 0); - assert_eq!(LedgerSlashPerEra::get().0, 0); - assert_eq!(LedgerSlashPerEra::get().1, BTreeMap::from([(4, 0), (5, 0)])); - - // Given - ledger.unlocking = bounded_vec![c(4, 100), c(5, 100), c(6, 100), c(7, 100)]; - ledger.total = 4 * 100; - ledger.active = 0; - // When the first 2 chunks don't overlap with the affected range of unlock eras. - assert_eq!(ledger.slash(140, 0, 3), 140); - // Then - assert_eq!(ledger.unlocking, vec![c(4, 100), c(5, 100), c(6, 30), c(7, 30)]); - assert_eq!(ledger.total, 4 * 100 - 140); - assert_eq!(LedgerSlashPerEra::get().0, 0); - assert_eq!(LedgerSlashPerEra::get().1, BTreeMap::from([(6, 30), (7, 30)])); - - // Given - ledger.unlocking = bounded_vec![c(4, 100), c(5, 100), c(6, 100), c(7, 100)]; - ledger.total = 4 * 100; - ledger.active = 0; - // When the first 2 chunks don't overlap with the affected range of unlock eras. - assert_eq!(ledger.slash(15, 0, 3), 15); - // Then - assert_eq!(ledger.unlocking, vec![c(4, 100), c(5, 100), c(6, 100 - 8), c(7, 100 - 7)]); - assert_eq!(ledger.total, 4 * 100 - 15); - assert_eq!(LedgerSlashPerEra::get().0, 0); - assert_eq!(LedgerSlashPerEra::get().1, BTreeMap::from([(6, 92), (7, 93)])); - - // Given - ledger.unlocking = bounded_vec![c(4, 40), c(5, 100), c(6, 10), c(7, 250)]; - ledger.active = 500; - // 900 - ledger.total = 40 + 10 + 100 + 250 + 500; - // When we have a partial slash that touches all chunks - assert_eq!(ledger.slash(900 / 2, 0, 0), 450); - // Then - assert_eq!(ledger.active, 500 / 2); - assert_eq!(ledger.unlocking, vec![c(4, 40 / 2), c(5, 100 / 2), c(6, 10 / 2), c(7, 250 / 2)]); - assert_eq!(ledger.total, 900 / 2); - assert_eq!(LedgerSlashPerEra::get().0, 500 / 2); - assert_eq!( - LedgerSlashPerEra::get().1, - BTreeMap::from([(4, 40 / 2), (5, 100 / 2), (6, 10 / 2), (7, 250 / 2)]) - ); + ExtBuilder::default().nominate(true).build_and_execute(|| { + let c = |era, value| UnlockChunk:: { era, value }; + // Given + let mut ledger = StakingLedger::::new(123, 10); + assert_eq!(BondingDuration::get(), 3); - // slash 1/4th with not chunk. - ledger.unlocking = bounded_vec![]; - ledger.active = 500; - ledger.total = 500; - // When we have a partial slash that touches all chunks - assert_eq!(ledger.slash(500 / 4, 0, 0), 500 / 4); - // Then - assert_eq!(ledger.active, 3 * 500 / 4); - assert_eq!(ledger.unlocking, vec![]); - assert_eq!(ledger.total, ledger.active); - assert_eq!(LedgerSlashPerEra::get().0, 3 * 500 / 4); - assert_eq!(LedgerSlashPerEra::get().1, Default::default()); - - // Given we have the same as above, - ledger.unlocking = bounded_vec![c(4, 40), c(5, 100), c(6, 10), c(7, 250)]; - ledger.active = 500; - ledger.total = 40 + 10 + 100 + 250 + 500; // 900 - assert_eq!(ledger.total, 900); - // When we have a higher min balance - assert_eq!( - ledger.slash( - 900 / 2, - 25, /* min balance - chunks with era 0 & 2 will be slashed to <=25, causing it to - * get swept */ - 0 - ), - 450 - ); - assert_eq!(ledger.active, 500 / 2); - // the last chunk was not slashed 50% like all the rest, because some other earlier chunks got - // dusted. - assert_eq!(ledger.unlocking, vec![c(5, 100 / 2), c(7, 150)]); - assert_eq!(ledger.total, 900 / 2); - assert_eq!(LedgerSlashPerEra::get().0, 500 / 2); - assert_eq!( - LedgerSlashPerEra::get().1, - BTreeMap::from([(4, 0), (5, 100 / 2), (6, 0), (7, 150)]) - ); + // When we slash a ledger with no unlocking chunks + assert_eq!(ledger.slash(5, 1, 0), 5); + // Then + assert_eq!(ledger.total, 5); + assert_eq!(ledger.active, 5); + assert_eq!(LedgerSlashPerEra::get().0, 5); + assert_eq!(LedgerSlashPerEra::get().1, Default::default()); + + // When we slash a ledger with no unlocking chunks and the slash amount is greater then the + // total + assert_eq!(ledger.slash(11, 1, 0), 5); + // Then + assert_eq!(ledger.total, 0); + assert_eq!(ledger.active, 0); + assert_eq!(LedgerSlashPerEra::get().0, 0); + assert_eq!(LedgerSlashPerEra::get().1, Default::default()); - // Given - // slash order --------------------NA--------2----------0----------1---- - ledger.unlocking = bounded_vec![c(4, 40), c(5, 100), c(6, 10), c(7, 250)]; - ledger.active = 500; - ledger.total = 40 + 10 + 100 + 250 + 500; // 900 - assert_eq!( - ledger.slash( - 500 + 10 + 250 + 100 / 2, // active + era 6 + era 7 + era 5 / 2 - 0, - 3 /* slash era 6 first, so the affected parts are era 6, era 7 and - * ledge.active. This will cause the affected to go to zero, and then we will - * start slashing older chunks */ - ), - 500 + 250 + 10 + 100 / 2 - ); - // Then - assert_eq!(ledger.active, 0); - assert_eq!(ledger.unlocking, vec![c(4, 40), c(5, 100 / 2)]); - assert_eq!(ledger.total, 90); - assert_eq!(LedgerSlashPerEra::get().0, 0); - assert_eq!(LedgerSlashPerEra::get().1, BTreeMap::from([(5, 100 / 2), (6, 0), (7, 0)])); - - // Given - // iteration order------------------NA---------2----------0----------1---- - ledger.unlocking = bounded_vec![c(4, 100), c(5, 100), c(6, 100), c(7, 100)]; - ledger.active = 100; - ledger.total = 5 * 100; - // When - assert_eq!( - ledger.slash( - 351, // active + era 6 + era 7 + era 5 / 2 + 1 - 50, // min balance - everything slashed below 50 will get dusted - 3 /* slash era 3+3 first, so the affected parts are era 6, era 7 and - * ledge.active. This will cause the affected to go to zero, and then we will - * start slashing older chunks */ - ), - 400 - ); - // Then - assert_eq!(ledger.active, 0); - assert_eq!(ledger.unlocking, vec![c(4, 100)]); - assert_eq!(ledger.total, 100); - assert_eq!(LedgerSlashPerEra::get().0, 0); - assert_eq!(LedgerSlashPerEra::get().1, BTreeMap::from([(5, 0), (6, 0), (7, 0)])); - - // Tests for saturating arithmetic - - // Given - let slash = u64::MAX as Balance * 2; - // The value of the other parts of ledger that will get slashed - let value = slash - (10 * 4); - - ledger.active = 10; - ledger.unlocking = bounded_vec![c(4, 10), c(5, 10), c(6, 10), c(7, value)]; - ledger.total = value + 40; - // When - let slash_amount = ledger.slash(slash, 0, 0); - assert_eq_error_rate!(slash_amount, slash, 5); - // Then - assert_eq!(ledger.active, 0); // slash of 9 - assert_eq!(ledger.unlocking, vec![]); - assert_eq!(ledger.total, 0); - assert_eq!(LedgerSlashPerEra::get().0, 0); - assert_eq!(LedgerSlashPerEra::get().1, BTreeMap::from([(4, 0), (5, 0), (6, 0), (7, 0)])); - - // Given - use sp_runtime::PerThing as _; - let slash = u64::MAX as Balance * 2; - let value = u64::MAX as Balance * 2; - let unit = 100; - // slash * value that will saturate - assert!(slash.checked_mul(value).is_none()); - // but slash * unit won't. - assert!(slash.checked_mul(unit).is_some()); - ledger.unlocking = bounded_vec![c(4, unit), c(5, value), c(6, unit), c(7, unit)]; - //--------------------------------------note value^^^ - ledger.active = unit; - ledger.total = unit * 4 + value; - // When - assert_eq!(ledger.slash(slash, 0, 0), slash); - // Then - // The amount slashed out of `unit` - let affected_balance = value + unit * 4; - let ratio = - Perquintill::from_rational_with_rounding(slash, affected_balance, Rounding::Up).unwrap(); - // `unit` after the slash is applied - let unit_slashed = { - let unit_slash = ratio.mul_ceil(unit); - unit - unit_slash - }; - let value_slashed = { - let value_slash = ratio.mul_ceil(value); - value - value_slash - }; - assert_eq!(ledger.active, unit_slashed); - assert_eq!(ledger.unlocking, vec![c(5, value_slashed), c(7, 32)]); - assert_eq!(ledger.total, value_slashed + 32); - assert_eq!(LedgerSlashPerEra::get().0, 0); - assert_eq!( - LedgerSlashPerEra::get().1, - BTreeMap::from([(4, 0), (5, value_slashed), (6, 0), (7, 32)]) - ); + // Given + ledger.unlocking = bounded_vec![c(4, 10), c(5, 10)]; + ledger.total = 2 * 10; + ledger.active = 0; + // When all the chunks overlap with the slash eras + assert_eq!(ledger.slash(20, 0, 0), 20); + // Then + assert_eq!(ledger.unlocking, vec![]); + assert_eq!(ledger.total, 0); + assert_eq!(LedgerSlashPerEra::get().0, 0); + assert_eq!(LedgerSlashPerEra::get().1, BTreeMap::from([(4, 0), (5, 0)])); + + // Given + ledger.unlocking = bounded_vec![c(4, 100), c(5, 100), c(6, 100), c(7, 100)]; + ledger.total = 4 * 100; + ledger.active = 0; + // When the first 2 chunks don't overlap with the affected range of unlock eras. + assert_eq!(ledger.slash(140, 0, 3), 140); + // Then + assert_eq!(ledger.unlocking, vec![c(4, 100), c(5, 100), c(6, 30), c(7, 30)]); + assert_eq!(ledger.total, 4 * 100 - 140); + assert_eq!(LedgerSlashPerEra::get().0, 0); + assert_eq!(LedgerSlashPerEra::get().1, BTreeMap::from([(6, 30), (7, 30)])); + + // Given + ledger.unlocking = bounded_vec![c(4, 100), c(5, 100), c(6, 100), c(7, 100)]; + ledger.total = 4 * 100; + ledger.active = 0; + // When the first 2 chunks don't overlap with the affected range of unlock eras. + assert_eq!(ledger.slash(15, 0, 3), 15); + // Then + assert_eq!(ledger.unlocking, vec![c(4, 100), c(5, 100), c(6, 100 - 8), c(7, 100 - 7)]); + assert_eq!(ledger.total, 4 * 100 - 15); + assert_eq!(LedgerSlashPerEra::get().0, 0); + assert_eq!(LedgerSlashPerEra::get().1, BTreeMap::from([(6, 92), (7, 93)])); + + // Given + ledger.unlocking = bounded_vec![c(4, 40), c(5, 100), c(6, 10), c(7, 250)]; + ledger.active = 500; + // 900 + ledger.total = 40 + 10 + 100 + 250 + 500; + // When we have a partial slash that touches all chunks + assert_eq!(ledger.slash(900 / 2, 0, 0), 450); + // Then + assert_eq!(ledger.active, 500 / 2); + assert_eq!( + ledger.unlocking, + vec![c(4, 40 / 2), c(5, 100 / 2), c(6, 10 / 2), c(7, 250 / 2)] + ); + assert_eq!(ledger.total, 900 / 2); + assert_eq!(LedgerSlashPerEra::get().0, 500 / 2); + assert_eq!( + LedgerSlashPerEra::get().1, + BTreeMap::from([(4, 40 / 2), (5, 100 / 2), (6, 10 / 2), (7, 250 / 2)]) + ); + + // slash 1/4th with not chunk. + ledger.unlocking = bounded_vec![]; + ledger.active = 500; + ledger.total = 500; + // When we have a partial slash that touches all chunks + assert_eq!(ledger.slash(500 / 4, 0, 0), 500 / 4); + // Then + assert_eq!(ledger.active, 3 * 500 / 4); + assert_eq!(ledger.unlocking, vec![]); + assert_eq!(ledger.total, ledger.active); + assert_eq!(LedgerSlashPerEra::get().0, 3 * 500 / 4); + assert_eq!(LedgerSlashPerEra::get().1, Default::default()); + + // Given we have the same as above, + ledger.unlocking = bounded_vec![c(4, 40), c(5, 100), c(6, 10), c(7, 250)]; + ledger.active = 500; + ledger.total = 40 + 10 + 100 + 250 + 500; // 900 + assert_eq!(ledger.total, 900); + // When we have a higher min balance + assert_eq!( + ledger.slash( + 900 / 2, + 25, /* min balance - chunks with era 0 & 2 will be slashed to <=25, causing it + * to get swept */ + 0 + ), + 450 + ); + assert_eq!(ledger.active, 500 / 2); + // the last chunk was not slashed 50% like all the rest, because some other earlier chunks + // got dusted. + assert_eq!(ledger.unlocking, vec![c(5, 100 / 2), c(7, 150)]); + assert_eq!(ledger.total, 900 / 2); + assert_eq!(LedgerSlashPerEra::get().0, 500 / 2); + assert_eq!( + LedgerSlashPerEra::get().1, + BTreeMap::from([(4, 0), (5, 100 / 2), (6, 0), (7, 150)]) + ); + + // Given + // slash order --------------------NA--------2----------0----------1---- + ledger.unlocking = bounded_vec![c(4, 40), c(5, 100), c(6, 10), c(7, 250)]; + ledger.active = 500; + ledger.total = 40 + 10 + 100 + 250 + 500; // 900 + assert_eq!( + ledger.slash( + 500 + 10 + 250 + 100 / 2, // active + era 6 + era 7 + era 5 / 2 + 0, + 3 /* slash era 6 first, so the affected parts are era 6, era 7 and + * ledge.active. This will cause the affected to go to zero, and then we will + * start slashing older chunks */ + ), + 500 + 250 + 10 + 100 / 2 + ); + // Then + assert_eq!(ledger.active, 0); + assert_eq!(ledger.unlocking, vec![c(4, 40), c(5, 100 / 2)]); + assert_eq!(ledger.total, 90); + assert_eq!(LedgerSlashPerEra::get().0, 0); + assert_eq!(LedgerSlashPerEra::get().1, BTreeMap::from([(5, 100 / 2), (6, 0), (7, 0)])); + + // Given + // iteration order------------------NA---------2----------0----------1---- + ledger.unlocking = bounded_vec![c(4, 100), c(5, 100), c(6, 100), c(7, 100)]; + ledger.active = 100; + ledger.total = 5 * 100; + // When + assert_eq!( + ledger.slash( + 351, // active + era 6 + era 7 + era 5 / 2 + 1 + 50, // min balance - everything slashed below 50 will get dusted + 3 /* slash era 3+3 first, so the affected parts are era 6, era 7 and + * ledge.active. This will cause the affected to go to zero, and then we + * will start slashing older chunks */ + ), + 400 + ); + // Then + assert_eq!(ledger.active, 0); + assert_eq!(ledger.unlocking, vec![c(4, 100)]); + assert_eq!(ledger.total, 100); + assert_eq!(LedgerSlashPerEra::get().0, 0); + assert_eq!(LedgerSlashPerEra::get().1, BTreeMap::from([(5, 0), (6, 0), (7, 0)])); + + // Tests for saturating arithmetic + + // Given + let slash = u64::MAX as Balance * 2; + // The value of the other parts of ledger that will get slashed + let value = slash - (10 * 4); + + ledger.active = 10; + ledger.unlocking = bounded_vec![c(4, 10), c(5, 10), c(6, 10), c(7, value)]; + ledger.total = value + 40; + // When + let slash_amount = ledger.slash(slash, 0, 0); + assert_eq_error_rate!(slash_amount, slash, 5); + // Then + assert_eq!(ledger.active, 0); // slash of 9 + assert_eq!(ledger.unlocking, vec![]); + assert_eq!(ledger.total, 0); + assert_eq!(LedgerSlashPerEra::get().0, 0); + assert_eq!(LedgerSlashPerEra::get().1, BTreeMap::from([(4, 0), (5, 0), (6, 0), (7, 0)])); + + // Given + use sp_runtime::PerThing as _; + let slash = u64::MAX as Balance * 2; + let value = u64::MAX as Balance * 2; + let unit = 100; + // slash * value that will saturate + assert!(slash.checked_mul(value).is_none()); + // but slash * unit won't. + assert!(slash.checked_mul(unit).is_some()); + ledger.unlocking = bounded_vec![c(4, unit), c(5, value), c(6, unit), c(7, unit)]; + //--------------------------------------note value^^^ + ledger.active = unit; + ledger.total = unit * 4 + value; + // When + assert_eq!(ledger.slash(slash, 0, 0), slash); + // Then + // The amount slashed out of `unit` + let affected_balance = value + unit * 4; + let ratio = Perquintill::from_rational_with_rounding(slash, affected_balance, Rounding::Up) + .unwrap(); + // `unit` after the slash is applied + let unit_slashed = { + let unit_slash = ratio.mul_ceil(unit); + unit - unit_slash + }; + let value_slashed = { + let value_slash = ratio.mul_ceil(value); + value - value_slash + }; + assert_eq!(ledger.active, unit_slashed); + assert_eq!(ledger.unlocking, vec![c(5, value_slashed), c(7, 32)]); + assert_eq!(ledger.total, value_slashed + 32); + assert_eq!(LedgerSlashPerEra::get().0, 0); + assert_eq!( + LedgerSlashPerEra::get().1, + BTreeMap::from([(4, 0), (5, value_slashed), (6, 0), (7, 32)]) + ); + }); } #[test] From 1a31c65cc38a48420e8b0b60a7cf08bb27d274fa Mon Sep 17 00:00:00 2001 From: Ankan Date: Sun, 1 Dec 2024 03:05:54 +0100 Subject: [PATCH 138/142] fmt --- substrate/frame/staking/src/tests.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 22067dee0e15..8ec07cdaa41e 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -6244,7 +6244,8 @@ fn proportional_slash_stop_slashing_if_remaining_zero() { assert_eq!(BondingDuration::get(), 3); - // should not slash more than the amount requested, by accidentally slashing the first chunk. + // should not slash more than the amount requested, by accidentally slashing the first + // chunk. assert_eq!(ledger.slash(18, 1, 0), 18); }); } From 1cd44d17bd9cc914db556271426e8443ac413393 Mon Sep 17 00:00:00 2001 From: Ankan Date: Thu, 5 Dec 2024 09:29:15 +0100 Subject: [PATCH 139/142] replace stakeable balance with free to stake --- substrate/frame/staking/src/pallet/impls.rs | 2 +- substrate/frame/staking/src/pallet/mod.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index aa4e55977da6..8c3ff23315a4 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -1174,7 +1174,7 @@ impl Pallet { T::OldCurrency::remove_lock(STAKING_ID, &stash); // check if we can hold all stake. - let max_hold = asset::stakeable_balance::(&stash); + let max_hold = asset::free_to_stake::(&stash); let force_withdraw = if max_hold >= staked { // this means we can hold all stake. yay! asset::update_stake::(&stash, staked)?; diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 8101c017e05c..557cd416baf4 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -795,7 +795,7 @@ pub mod pallet { status ); assert!( - asset::stakeable_balance::(stash) >= balance, + asset::free_to_stake::(stash) >= balance, "Stash does not have enough balance to bond." ); frame_support::assert_ok!(>::bond( @@ -1209,7 +1209,7 @@ pub mod pallet { return Err(Error::::InsufficientBond.into()) } - let stash_balance = asset::stakeable_balance::(&stash); + let stash_balance = asset::free_to_stake::(&stash); let value = value.min(stash_balance); Self::deposit_event(Event::::Bonded { stash: stash.clone(), amount: value }); let ledger = StakingLedger::::new(stash.clone(), value); From ecb87d9042c5c1e4ceb37d0687f2dd3ad55e1c86 Mon Sep 17 00:00:00 2001 From: Ankan Date: Thu, 5 Dec 2024 09:41:52 +0100 Subject: [PATCH 140/142] fmt --- substrate/frame/offences/benchmarking/src/inner.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/substrate/frame/offences/benchmarking/src/inner.rs b/substrate/frame/offences/benchmarking/src/inner.rs index cc355030ff51..3d3cd470bc24 100644 --- a/substrate/frame/offences/benchmarking/src/inner.rs +++ b/substrate/frame/offences/benchmarking/src/inner.rs @@ -183,7 +183,10 @@ where // deposit to reporter + reporter account endowed. assert_eq!(System::::read_events_for_pallet::>().len(), 2); // (n nominators + one validator) * slashed + Slash Reported - assert_eq!(System::::read_events_for_pallet::>().len(), 1 * (offender_count + 1) as usize + 1); + assert_eq!( + System::::read_events_for_pallet::>().len(), + 1 * (offender_count + 1) as usize + 1 + ); // offence assert_eq!(System::::read_events_for_pallet::().len(), 1); // reporter new account From 7a2365ad569ab03e1db25dcf4f6f0384b624e924 Mon Sep 17 00:00:00 2001 From: Ankan Date: Thu, 5 Dec 2024 11:20:17 +0100 Subject: [PATCH 141/142] remove todo from code --- substrate/frame/staking/src/asset.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/substrate/frame/staking/src/asset.rs b/substrate/frame/staking/src/asset.rs index 26eb554a0459..f852c2fb538f 100644 --- a/substrate/frame/staking/src/asset.rs +++ b/substrate/frame/staking/src/asset.rs @@ -62,7 +62,6 @@ pub fn staked(who: &T::AccountId) -> BalanceOf { /// Does not include the current stake. pub fn free_to_stake(who: &T::AccountId) -> BalanceOf { // since we want to be able to use frozen funds for staking, we force the reduction. - // todo(ank4n): test above scenario. T::Currency::reducible_balance(who, Preservation::Preserve, Fortitude::Force) } From 8f9b0c6b33d0b98cd8631fb0c223f2c8c58d9ffc Mon Sep 17 00:00:00 2001 From: Ankan Date: Thu, 5 Dec 2024 11:37:04 +0100 Subject: [PATCH 142/142] add test to ensure locked amount can be staked --- substrate/frame/staking/src/tests.rs | 58 +++++++++++++++++++++++++--- 1 file changed, 52 insertions(+), 6 deletions(-) diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 8ec07cdaa41e..908415143994 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -28,7 +28,10 @@ use frame_support::{ dispatch::{extract_actual_weight, GetDispatchInfo, WithPostDispatchInfo}, hypothetically, pallet_prelude::*, - traits::{fungible::Inspect, Currency, Get, InspectLockableCurrency, ReservableCurrency}, + traits::{ + fungible::Inspect, Currency, Get, InspectLockableCurrency, LockableCurrency, + ReservableCurrency, WithdrawReasons, + }, }; use mock::*; @@ -1046,18 +1049,61 @@ fn cannot_reserve_staked_balance() { ExtBuilder::default().build_and_execute(|| { // Confirm account 11 is stashed assert_eq!(Staking::bonded(&11), Some(11)); - // Confirm account 11 has some stakeable balance. - assert_eq!(asset::stakeable_balance::(&11), 1000); // Confirm account 11 is totally staked - assert_eq!(Staking::eras_stakers(active_era(), &11).own, 1000); + assert_eq!(asset::staked::(&11), 1000); + // Confirm account 11 cannot reserve as a result assert_noop!(Balances::reserve(&11, 2), BalancesError::::InsufficientBalance); assert_noop!(Balances::reserve(&11, 1), DispatchError::ConsumerRemaining); // Give account 11 extra free balance - let _ = asset::set_stakeable_balance::(&11, 10000); + let _ = asset::set_stakeable_balance::(&11, 1000 + 1000); + assert_eq!(asset::free_to_stake::(&11), 1000); + // Confirm account 11 can now reserve balance - assert_ok!(Balances::reserve(&11, 1)); + assert_ok!(Balances::reserve(&11, 500)); + + // free to stake balance has reduced + assert_eq!(asset::free_to_stake::(&11), 500); + }); +} + +#[test] +fn locked_balance_can_be_staked() { + // Checks that a bonded account cannot reserve balance from free balance + ExtBuilder::default().build_and_execute(|| { + // Confirm account 11 is stashed + assert_eq!(Staking::bonded(&11), Some(11)); + assert_eq!(asset::staked::(&11), 1000); + assert_eq!(asset::free_to_stake::(&11), 0); + + // add some staking balance to 11 + let _ = asset::set_stakeable_balance::(&11, 1000 + 1000); + // free to stake is 1000 + assert_eq!(asset::free_to_stake::(&11), 1000); + + // lock some balance + Balances::set_lock(*b"somelock", &11, 500, WithdrawReasons::all()); + + // locked balance still available for staking + assert_eq!(asset::free_to_stake::(&11), 1000); + + // can stake free balance + assert_ok!(Staking::bond_extra(RuntimeOrigin::signed(11), 500)); + assert_eq!(asset::staked::(&11), 1500); + + // Can stake the locked balance + assert_ok!(Staking::bond_extra(RuntimeOrigin::signed(11), 500)); + assert_eq!(asset::staked::(&11), 2000); + // no balance left to stake + assert_eq!(asset::free_to_stake::(&11), 0); + + // this does not fail if someone tries to stake more than free balance but just stakes + // whatever is available. (not sure if that is the best way, but we keep it backward + // compatible) + assert_ok!(Staking::bond_extra(RuntimeOrigin::signed(11), 10)); + // no extra balance staked. + assert_eq!(asset::staked::(&11), 2000); }); }