diff --git a/bin/node/runtime/pangolin/src/weights/darwinia_staking.rs b/bin/node/runtime/pangolin/src/weights/darwinia_staking.rs index 8c735e828b..48aa793eaa 100644 --- a/bin/node/runtime/pangolin/src/weights/darwinia_staking.rs +++ b/bin/node/runtime/pangolin/src/weights/darwinia_staking.rs @@ -102,6 +102,12 @@ impl darwinia_staking::WeightInfo for WeightInfo { .saturating_add(T::DbWeight::get().writes(3 as Weight)) .saturating_add(T::DbWeight::get().writes((3 as Weight).saturating_mul(n as Weight))) } + fn rebond(l: u32) -> Weight { + (46_569_000 as Weight) + .saturating_add((104_000 as Weight).saturating_mul(l as Weight)) + .saturating_add(T::DbWeight::get().reads(4 as Weight)) + .saturating_add(T::DbWeight::get().writes(3 as Weight)) + } fn set_history_depth(e: u32) -> Weight { (0 as Weight) .saturating_add((36_641_000 as Weight).saturating_mul(e as Weight)) diff --git a/frame/staking/src/default_weights.rs b/frame/staking/src/default_weights.rs index e56729fb81..557374b570 100644 --- a/frame/staking/src/default_weights.rs +++ b/frame/staking/src/default_weights.rs @@ -96,6 +96,13 @@ impl crate::WeightInfo for () { .saturating_add(DbWeight::get().reads((5 as Weight).saturating_mul(n as Weight))) .saturating_add(DbWeight::get().writes((3 as Weight).saturating_mul(n as Weight))) } + fn rebond(l: u32) -> Weight { + (71316000 as Weight) + .saturating_add((142000 as Weight).saturating_mul(l as Weight)) + .saturating_add(DbWeight::get().reads(4 as Weight)) + .saturating_add(DbWeight::get().writes(3 as Weight)) + } + fn set_history_depth(e: u32) -> Weight { (0 as Weight) .saturating_add((51901000 as Weight).saturating_mul(e as Weight)) diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 6f06f39de1..f9d3f7946e 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -351,7 +351,10 @@ use frame_support::{ Currency, EnsureOrigin, EstimateNextNewSession, ExistenceRequirement::KeepAlive, Get, Imbalance, OnUnbalanced, UnixTime, }, - weights::{constants::WEIGHT_PER_MICROS, Weight}, + weights::{ + constants::{WEIGHT_PER_MICROS, WEIGHT_PER_NANOS}, + Weight, + }, }; use frame_system::{ensure_none, ensure_root, ensure_signed, offchain::SendTransactionTypes}; use sp_npos_elections::{ @@ -576,6 +579,8 @@ pub trait WeightInfo { fn cancel_deferred_slash(s: u32) -> Weight; fn payout_stakers_alive_staked(n: u32) -> Weight; fn payout_stakers_dead_controller(n: u32) -> Weight; + + fn rebond(l: u32) -> Weight; fn set_history_depth(e: u32) -> Weight; fn reap_stash(s: u32) -> Weight; fn new_era(v: u32, n: u32) -> Weight; @@ -899,6 +904,8 @@ decl_error! { InsufficientValue, /// Can not schedule more unlock chunks. NoMoreChunks, + /// Can not rebond without unlocking chunks. + NoUnlockChunk, /// Attempting to target a stash that still has funds. FundedTarget, /// Invalid era to reward. @@ -1297,7 +1304,7 @@ decl_module! { /// - Read: Era Election Status, Bonded, Ledger, [Origin Account] /// - Write: [Origin Account], Ledger /// # - #[weight = T::WeightInfo::unbond()] + #[weight = T::WeightInfo::deposit_extra()] fn deposit_extra(origin, value: RingBalance, promise_month: u8) { let stash = ensure_signed(origin)?; let controller = Self::bonded(&stash).ok_or(>::NotStash)?; @@ -1385,8 +1392,6 @@ decl_module! { kton_staking_lock, .. } = &mut ledger; - let origin_active_ring = *active_ring; - let origin_active_kton = *active_kton; let now = >::block_number(); ring_staking_lock.update(now); @@ -1480,12 +1485,7 @@ decl_module! { }, } - Self::update_ledger( - &controller, - Some(origin_active_ring), - Some(origin_active_kton), - &mut ledger - ); + Self::update_ledger(&controller, &mut ledger); // TODO: https://github.com/darwinia-network/darwinia-common/issues/96 // FIXME: https://github.com/darwinia-network/darwinia-common/issues/121 @@ -1984,6 +1984,55 @@ decl_module! { Self::do_payout_stakers(validator_stash, era) } + /// Rebond a portion of the stash scheduled to be unlocked. + /// + /// The dispatch origin must be signed by the controller, and it can be only called when + /// [`EraElectionStatus`] is `Closed`. + /// + /// # + /// - Time complexity: O(L), where L is unlocking chunks + /// - Bounded by `MAX_UNLOCKING_CHUNKS`. + /// - Storage changes: Can't increase storage, only decrease it. + /// --------------- + /// - DB Weight: + /// - Reads: EraElectionStatus, Ledger, Locks, [Origin Account] + /// - Writes: [Origin Account], Locks, Ledger + /// # + #[weight = T::WeightInfo::rebond(MAX_UNLOCKING_CHUNKS as u32)] + fn rebond( + origin, + #[compact] plan_to_rebond_ring: RingBalance, + #[compact] plan_to_rebond_kton: KtonBalance + ) -> DispatchResultWithPostInfo { + ensure!(Self::era_election_status().is_closed(), >::CallNotAllowed); + + let controller = ensure_signed(origin)?; + let mut ledger = Self::ledger(&controller).ok_or(>::NotController)?; + let now = >::block_number(); + + ledger.ring_staking_lock.update(now); + ledger.kton_staking_lock.update(now); + + ensure!( + !ledger.ring_staking_lock.unbondings.is_empty() + || !ledger.kton_staking_lock.unbondings.is_empty(), + >::NoUnlockChunk + ); + + ledger.rebond(plan_to_rebond_ring, plan_to_rebond_kton); + + Self::update_ledger(&controller, &mut ledger); + + Ok(Some( + 35 * WEIGHT_PER_MICROS + + 50 * WEIGHT_PER_NANOS * ( + ledger.ring_staking_lock.unbondings.len() as Weight + + ledger.kton_staking_lock.unbondings.len() as Weight + ) + + T::DbWeight::get().reads_writes(3, 2) + ).into()) + } + /// Set `HistoryDepth` value. This function will delete any history information /// when `HistoryDepth` is reduced. /// @@ -2185,7 +2234,6 @@ impl Module { deposit_items, .. } = &mut ledger; - let origin_active_ring = *active_ring; let start_time = T::UnixTime::now().as_millis().saturated_into::(); let mut expire_time = start_time; @@ -2208,18 +2256,16 @@ impl Module { }); } - Self::update_ledger(&controller, Some(origin_active_ring), None, &mut ledger); + Self::update_ledger(&controller, &mut ledger); (start_time, expire_time) } /// Update the ledger while bonding controller with *KTON* fn bond_kton(controller: &T::AccountId, value: KtonBalance, mut ledger: StakingLedgerT) { - let origin_active_kton = ledger.active_kton; - ledger.active_kton += value; - Self::update_ledger(&controller, None, Some(origin_active_kton), &mut ledger); + Self::update_ledger(&controller, &mut ledger); } /// Turn the expired deposit items into normal bond @@ -2458,19 +2504,10 @@ impl Module { /// Update the ledger for a controller. /// - /// This will also update the stash lock. - fn update_ledger( - controller: &T::AccountId, - // The origin active ring, none means - // there's no change on this field during this update, - // just ignore it - maybe_origin_active_ring: Option>, - // The origin active kton, none means - // there's no change on this field during this update, - // just ignore it - maybe_origin_active_kton: Option>, - ledger: &mut StakingLedgerT, - ) { + /// BE CAREFUL: + /// This will also update the stash lock. + /// DO NOT modify the locks' staking amount outside this function. + fn update_ledger(controller: &T::AccountId, ledger: &mut StakingLedgerT) { let StakingLedger { active_ring, active_kton, @@ -2480,19 +2517,17 @@ impl Module { } = ledger; if *active_ring != ring_staking_lock.staking_amount { + let origin_active_ring = ring_staking_lock.staking_amount; + ring_staking_lock.staking_amount = *active_ring; - // If the active ring != staking amount, there must be a difference - // The origin active ring MUST be some, but better safe here - if let Some(origin_active_ring) = maybe_origin_active_ring { - >::mutate(|pool| { - if origin_active_ring > *active_ring { - *pool = pool.saturating_sub(origin_active_ring - *active_ring); - } else { - *pool = pool.saturating_add(*active_ring - origin_active_ring); - } - }); - } + >::mutate(|pool| { + if origin_active_ring > *active_ring { + *pool = pool.saturating_sub(origin_active_ring - *active_ring); + } else { + *pool = pool.saturating_add(*active_ring - origin_active_ring); + } + }); T::RingCurrency::set_lock( STAKING_ID, @@ -2503,19 +2538,17 @@ impl Module { } if *active_kton != kton_staking_lock.staking_amount { + let origin_active_kton = kton_staking_lock.staking_amount; + kton_staking_lock.staking_amount = *active_kton; - // If the active kton != staking amount, there must be a difference - // The origin active kton MUST be some, but better safe here - if let Some(origin_active_kton) = maybe_origin_active_kton { - >::mutate(|pool| { - if origin_active_kton > *active_kton { - *pool = pool.saturating_sub(origin_active_kton - *active_kton); - } else { - *pool = pool.saturating_add(*active_kton - origin_active_kton); - } - }); - } + >::mutate(|pool| { + if origin_active_kton > *active_kton { + *pool = pool.saturating_sub(origin_active_kton - *active_kton); + } else { + *pool = pool.saturating_add(*active_kton - origin_active_kton); + } + }); T::KtonCurrency::set_lock( STAKING_ID, @@ -2552,11 +2585,9 @@ impl Module { let r = T::RingCurrency::deposit_into_existing(stash, amount).ok(); if r.is_some() { - let origin_active_ring = l.active_ring; - l.active_ring += amount; - Self::update_ledger(&c, Some(origin_active_ring), None, &mut l); + Self::update_ledger(&c, &mut l); } r @@ -2669,12 +2700,12 @@ impl Module { // candidates. let snapshot_validators_length = >::decode_len() .map(|l| l as u32) - .ok_or_else(|| Error::::SnapshotUnavailable)?; + .ok_or_else(|| >::SnapshotUnavailable)?; // size of the solution must be correct. ensure!( snapshot_validators_length == u32::from(election_size.validators), - Error::::OffchainElectionBogusElectionSize, + >::OffchainElectionBogusElectionSize, ); // check the winner length only here and when we know the length of the snapshot validators @@ -2801,7 +2832,7 @@ impl Module { // build the support map thereof in order to evaluate. let supports = build_support_map::(&winners, &staked_assignments) - .map_err(|_| Error::::OffchainElectionBogusEdge)?; + .map_err(|_| >::OffchainElectionBogusEdge)?; // Check if the score is the same as the claimed one. let submitted_score = evaluate_support(&supports); @@ -3565,7 +3596,6 @@ impl OnDepositRedeem> for Module { deposit_items, .. } = &mut ledger; - let origin_active_ring = *active_ring; *active_ring = active_ring.saturating_add(amount); *active_deposit_ring = active_deposit_ring.saturating_add(amount); @@ -3575,7 +3605,7 @@ impl OnDepositRedeem> for Module { expire_time, }); - Self::update_ledger(&controller, Some(origin_active_ring), None, &mut ledger); + Self::update_ledger(&controller, &mut ledger); } else { ensure!( !>::contains_key(&stash), @@ -3613,7 +3643,7 @@ impl OnDepositRedeem> for Module { ..Default::default() }; - Self::update_ledger(controller, Some(0.into()), None, &mut ledger); + Self::update_ledger(controller, &mut ledger); }; Self::deposit_event(RawEvent::BondRing(amount, start_time, expire_time)); @@ -3980,6 +4010,51 @@ where self.kton_staking_lock.locked_amount(at) } + /// Re-bond funds that were scheduled for unlocking. + fn rebond(&mut self, plan_to_rebond_ring: RingBalance, plan_to_rebond_kton: KtonBalance) { + fn update( + bonded: &mut Balance, + lock: &mut StakingLock, + plan_to_rebond: Balance, + ) where + Balance: Copy + AtLeast32BitUnsigned + Saturating, + { + let mut rebonded = Balance::zero(); + + while let Some(Unbonding { amount, .. }) = lock.unbondings.last_mut() { + let new_rebonded = rebonded.saturating_add(*amount); + + if new_rebonded <= plan_to_rebond { + rebonded = new_rebonded; + *bonded = bonded.saturating_add(*amount); + + lock.unbondings.pop(); + } else { + let diff = plan_to_rebond.saturating_sub(rebonded); + + rebonded = rebonded.saturating_add(diff); + *bonded = bonded.saturating_add(diff); + *amount = amount.saturating_sub(diff); + } + + if rebonded >= plan_to_rebond { + break; + } + } + } + + update( + &mut self.active_ring, + &mut self.ring_staking_lock, + plan_to_rebond_ring, + ); + update( + &mut self.active_kton, + &mut self.kton_staking_lock, + plan_to_rebond_kton, + ); + } + /// Slash the validator for a given amount of balance. This can grow the value /// of the slash in the case that the validator has less than `minimum_balance` /// active funds. Returns the amount of funds actually slashed. diff --git a/frame/staking/src/offchain_election.rs b/frame/staking/src/offchain_election.rs index 306ae69cc3..bb662f6497 100644 --- a/frame/staking/src/offchain_election.rs +++ b/frame/staking/src/offchain_election.rs @@ -487,6 +487,9 @@ mod test { fn payout_stakers_alive_staked(n: u32) -> Weight { unimplemented!() } + fn rebond(l: u32) -> Weight { + unimplemented!() + } fn set_history_depth(e: u32) -> Weight { unimplemented!() } diff --git a/frame/staking/src/slashing.rs b/frame/staking/src/slashing.rs index c50ae5bdab..d8bfcf5a5f 100644 --- a/frame/staking/src/slashing.rs +++ b/frame/staking/src/slashing.rs @@ -703,7 +703,6 @@ pub fn do_slash( Some(ledger) => ledger, None => return, // nothing to do. }; - let (origin_active_ring, origin_active_kton) = (ledger.active_ring, ledger.active_kton); let (slash_ring, slash_kton) = ledger.slash( value.r, value.k, @@ -738,12 +737,7 @@ pub fn do_slash( } if slashed { - >::update_ledger( - &controller, - Some(origin_active_ring), - Some(origin_active_kton), - &mut ledger, - ); + >::update_ledger(&controller, &mut ledger); >::deposit_event(RawEvent::Slash(stash.clone(), value.r, value.k)); } } diff --git a/frame/staking/src/substrate_tests.rs b/frame/staking/src/substrate_tests.rs index ce33e8b62c..5295e405c2 100644 --- a/frame/staking/src/substrate_tests.rs +++ b/frame/staking/src/substrate_tests.rs @@ -1338,13 +1338,325 @@ fn too_many_unbond_calls_should_not_work() { }) } -// #[deprecated] -// #[test] -// fn rebond_works() {} +#[test] +fn rebond_works() { + // * Should test + // * Given an account being bonded [and chosen as a validator](not mandatory) + // * it can unbond a portion of its funds from the stash account. + // * it can re-bond a portion of the funds scheduled to unlock. + ExtBuilder::default() + .nominate(false) + .build() + .execute_with(|| { + // Set payee to controller. avoids confusion + assert_ok!(Staking::set_payee( + Origin::signed(10), + RewardDestination::Controller + )); -// #[deprecated] -// #[test] -// fn rebond_is_fifo() {} + // Give account 11 some large free balance greater than total + let _ = Ring::make_free_balance_be(&11, 1000000); + + // confirm that 10 is a normal validator and gets paid at the end of the era. + start_era(1); + + // Initial state of 10 + assert_eq!( + Staking::ledger(&10), + Some(StakingLedger { + stash: 11, + active_ring: 1000, + ring_staking_lock: StakingLock { + staking_amount: 1000, + unbondings: vec![] + }, + ..Default::default() + }) + ); + + start_era(2); + assert_eq!(Staking::active_era().unwrap().index, 2); + + // Try to rebond some funds. We get an error since no fund is unbonded. + assert_noop!( + Staking::rebond(Origin::signed(10), 500, 0), + >::NoUnlockChunk, + ); + + // Unbond almost all of the funds in stash. + Staking::unbond(Origin::signed(10), StakingBalance::RingBalance(900)).unwrap(); + assert_eq!( + Staking::ledger(&10), + Some(StakingLedger { + stash: 11, + active_ring: 100, + ring_staking_lock: StakingLock { + staking_amount: 100, + unbondings: vec![Unbonding { + amount: 900, + until: System::block_number() + BondingDurationInBlockNumber::get(), + }] + }, + ..Default::default() + }) + ); + + // Re-bond all the funds unbonded. + Staking::rebond(Origin::signed(10), 900, 0).unwrap(); + assert_eq!( + Staking::ledger(&10), + Some(StakingLedger { + stash: 11, + active_ring: 1000, + ring_staking_lock: StakingLock { + staking_amount: 1000, + unbondings: vec![] + }, + ..Default::default() + }) + ); + + // Unbond almost all of the funds in stash. + Staking::unbond(Origin::signed(10), StakingBalance::RingBalance(900)).unwrap(); + assert_eq!( + Staking::ledger(&10), + Some(StakingLedger { + stash: 11, + active_ring: 100, + ring_staking_lock: StakingLock { + staking_amount: 100, + unbondings: vec![Unbonding { + amount: 900, + until: System::block_number() + BondingDurationInBlockNumber::get(), + }] + }, + ..Default::default() + }) + ); + + // Re-bond part of the funds unbonded. + Staking::rebond(Origin::signed(10), 500, 0).unwrap(); + assert_eq!( + Staking::ledger(&10), + Some(StakingLedger { + stash: 11, + active_ring: 600, + ring_staking_lock: StakingLock { + staking_amount: 600, + unbondings: vec![Unbonding { + amount: 400, + until: System::block_number() + BondingDurationInBlockNumber::get(), + }] + }, + ..Default::default() + }) + ); + + // Re-bond the remainder of the funds unbonded. + Staking::rebond(Origin::signed(10), 500, 0).unwrap(); + assert_eq!( + Staking::ledger(&10), + Some(StakingLedger { + stash: 11, + active_ring: 1000, + ring_staking_lock: StakingLock { + staking_amount: 1000, + unbondings: vec![] + }, + ..Default::default() + }) + ); + + // Unbond parts of the funds in stash. + Staking::unbond(Origin::signed(10), StakingBalance::RingBalance(300)).unwrap(); + Staking::unbond(Origin::signed(10), StakingBalance::RingBalance(300)).unwrap(); + Staking::unbond(Origin::signed(10), StakingBalance::RingBalance(300)).unwrap(); + assert_eq!( + Staking::ledger(&10), + Some(StakingLedger { + stash: 11, + active_ring: 100, + ring_staking_lock: StakingLock { + staking_amount: 100, + unbondings: vec![ + Unbonding { + amount: 300, + until: System::block_number() + BondingDurationInBlockNumber::get(), + }, + Unbonding { + amount: 300, + until: System::block_number() + BondingDurationInBlockNumber::get(), + }, + Unbonding { + amount: 300, + until: System::block_number() + BondingDurationInBlockNumber::get(), + } + ] + }, + ..Default::default() + }) + ); + + // Re-bond part of the funds unbonded. + Staking::rebond(Origin::signed(10), 500, 0).unwrap(); + assert_eq!( + Staking::ledger(&10), + Some(StakingLedger { + stash: 11, + active_ring: 600, + ring_staking_lock: StakingLock { + staking_amount: 600, + unbondings: vec![ + Unbonding { + amount: 300, + until: System::block_number() + BondingDurationInBlockNumber::get(), + }, + Unbonding { + amount: 100, + until: System::block_number() + BondingDurationInBlockNumber::get(), + } + ] + }, + ..Default::default() + }) + ); + }); +} + +#[test] +fn rebond_is_fifo() { + // Rebond should proceed by reversing the most recent bond operations. + ExtBuilder::default() + .nominate(false) + .build() + .execute_with(|| { + // Set payee to controller. avoids confusion + assert_ok!(Staking::set_payee( + Origin::signed(10), + RewardDestination::Controller + )); + + // Give account 11 some large free balance greater than total + let _ = Ring::make_free_balance_be(&11, 1000000); + + // confirm that 10 is a normal validator and gets paid at the end of the era. + start_era(1); + + // Initial state of 10 + assert_eq!( + Staking::ledger(&10), + Some(StakingLedger { + stash: 11, + active_ring: 1000, + ring_staking_lock: StakingLock { + staking_amount: 1000, + unbondings: vec![] + }, + ..Default::default() + }) + ); + + start_era(2); + + // Unbond some of the funds in stash. + Staking::unbond(Origin::signed(10), StakingBalance::RingBalance(400)).unwrap(); + assert_eq!( + Staking::ledger(&10), + Some(StakingLedger { + stash: 11, + active_ring: 600, + ring_staking_lock: StakingLock { + staking_amount: 600, + unbondings: vec![Unbonding { + amount: 400, + until: 6 + BondingDurationInBlockNumber::get(), + }] + }, + ..Default::default() + }) + ); + + start_era(3); + + // Unbond more of the funds in stash. + Staking::unbond(Origin::signed(10), StakingBalance::RingBalance(300)).unwrap(); + assert_eq!( + Staking::ledger(&10), + Some(StakingLedger { + stash: 11, + active_ring: 300, + ring_staking_lock: StakingLock { + staking_amount: 300, + unbondings: vec![ + Unbonding { + amount: 400, + until: 6 + BondingDurationInBlockNumber::get(), + }, + Unbonding { + amount: 300, + until: 9 + BondingDurationInBlockNumber::get(), + }, + ] + }, + ..Default::default() + }) + ); + + start_era(4); + + // Unbond yet more of the funds in stash. + Staking::unbond(Origin::signed(10), StakingBalance::RingBalance(200)).unwrap(); + assert_eq!( + Staking::ledger(&10), + Some(StakingLedger { + stash: 11, + active_ring: 100, + ring_staking_lock: StakingLock { + staking_amount: 100, + unbondings: vec![ + Unbonding { + amount: 400, + until: 6 + BondingDurationInBlockNumber::get(), + }, + Unbonding { + amount: 300, + until: 9 + BondingDurationInBlockNumber::get(), + }, + Unbonding { + amount: 200, + until: 12 + BondingDurationInBlockNumber::get(), + }, + ] + }, + ..Default::default() + }) + ); + + // Re-bond half of the unbonding funds. + Staking::rebond(Origin::signed(10), 400, 0).unwrap(); + assert_eq!( + Staking::ledger(&10), + Some(StakingLedger { + stash: 11, + active_ring: 500, + ring_staking_lock: StakingLock { + staking_amount: 500, + unbondings: vec![ + Unbonding { + amount: 400, + until: 6 + BondingDurationInBlockNumber::get(), + }, + Unbonding { + amount: 100, + until: 9 + BondingDurationInBlockNumber::get(), + }, + ] + }, + ..Default::default() + }) + ); + }); +} #[test] fn reward_to_stake_works() { @@ -3430,7 +3742,7 @@ fn test_max_nominator_rewarded_per_validator_and_cant_steal_someone_else_reward( #[test] fn set_history_depth_works() { ExtBuilder::default().build_and_execute(|| { - mock::start_era(10); + start_era(10); Staking::set_history_depth(Origin::root(), 20, 0).unwrap(); assert!(::ErasTotalStake::contains_key(10 - 4)); assert!(::ErasTotalStake::contains_key(10 - 5)); @@ -3467,12 +3779,12 @@ fn test_payout_stakers() { ); } - mock::start_era(1); + start_era(1); Staking::reward_by_ids(vec![(11, 1)]); // Compute total payout now for whole duration as other parameter won't change let total_payout_0 = current_total_payout_for_duration(3 * 1000); assert!(total_payout_0 > 100); // Test is meaningful if reward something - mock::start_era(2); + start_era(2); assert_ok!(Staking::payout_stakers(Origin::signed(1337), 11, 1)); // Top 64 nominators of validator 11 automatically paid out, including the validator @@ -3506,7 +3818,7 @@ fn test_payout_stakers() { // Compute total payout now for whole duration as other parameter won't change let total_payout_0 = current_total_payout_for_duration(3 * 1000); assert!(total_payout_0 > 100); // Test is meaningful if reward something - mock::start_era(i); + start_era(i); assert_ok!(Staking::payout_stakers(Origin::signed(1337), 11, i - 1)); } @@ -3530,7 +3842,7 @@ fn test_payout_stakers() { // Compute total payout now for whole duration as other parameter won't change let total_payout_0 = current_total_payout_for_duration(3 * 1000); assert!(total_payout_0 > 100); // Test is meaningful if reward something - mock::start_era(i); + start_era(i); } // We clean it up as history passes @@ -3590,12 +3902,12 @@ fn payout_stakers_handles_basic_errors() { ); } - mock::start_era(1); + start_era(1); Staking::reward_by_ids(vec![(11, 1)]); // Compute total payout now for whole duration as other parameter won't change let total_payout_0 = current_total_payout_for_duration(3 * 1000); assert!(total_payout_0 > 100); // Test is meaningful if reward something - mock::start_era(2); + start_era(2); // Wrong Era, too big assert_noop!( @@ -3613,7 +3925,7 @@ fn payout_stakers_handles_basic_errors() { // Compute total payout now for whole duration as other parameter won't change let total_payout_0 = current_total_payout_for_duration(3 * 1000); assert!(total_payout_0 > 100); // Test is meaningful if reward something - mock::start_era(i); + start_era(i); } // We are at era 99, with history depth of 84 // We should be able to payout era 15 through 98 (84 total eras), but not 14 or 99. @@ -3805,12 +4117,12 @@ fn payout_creates_controller() { assert_ok!(Ring::transfer(Origin::signed(1337), 1234, 100)); assert_eq!(Ring::free_balance(1337), 0); - mock::start_era(1); + start_era(1); Staking::reward_by_ids(vec![(11, 1)]); // Compute total payout now for whole duration as other parameter won't change let total_payout_0 = current_total_payout_for_duration(3 * 1000); assert!(total_payout_0 > 100); // Test is meaningful if reward something - mock::start_era(2); + start_era(2); assert_ok!(Staking::payout_stakers(Origin::signed(1337), 11, 1)); // Controller is created @@ -3839,12 +4151,12 @@ fn payout_to_any_account_works() { // Reward Destination account doesn't exist assert_eq!(Ring::free_balance(42), 0); - mock::start_era(1); + start_era(1); Staking::reward_by_ids(vec![(11, 1)]); // Compute total payout now for whole duration as other parameter won't change let total_payout_0 = current_total_payout_for_duration(3 * 1000); assert!(total_payout_0 > 100); // Test is meaningful if reward something - mock::start_era(2); + start_era(2); assert_ok!(Staking::payout_stakers(Origin::signed(1337), 11, 1)); // Payment is successful diff --git a/frame/support/src/structs.rs b/frame/support/src/structs.rs index f873bb0d46..b43103fea7 100644 --- a/frame/support/src/structs.rs +++ b/frame/support/src/structs.rs @@ -128,16 +128,7 @@ where #[inline] pub fn update(&mut self, at: Moment) { - let mut locked_amount = self.staking_amount; - - self.unbondings.retain(|unbonding| { - let valid = unbonding.valid_at(at); - if valid { - locked_amount = locked_amount.saturating_add(unbonding.amount); - } - - valid - }); + self.unbondings.retain(|unbonding| unbonding.valid_at(at)); } }