From 70e9f8e920fbd8353b640641eca20286d1cb5865 Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Fri, 23 Dec 2022 08:04:47 +0100 Subject: [PATCH] Fix fast-unstake for accounts with slashing (#12963) * Fix fast-unstake for accounts with slashing * ".git/.scripts/fmt.sh" 1 * fmt * fix * fix weight tracking * Adds tests for withdraw_unbonded with slashing * Removes tests for withdraw_unbonded with slashing * ".git/.scripts/fmt.sh" * Adds slash spans calculation test for withdraw_unbonded Co-authored-by: command-bot <> Co-authored-by: gpestana <g6pestana@gmail.com> --- substrate/frame/fast-unstake/src/lib.rs | 14 +++--- substrate/frame/staking/src/pallet/impls.rs | 2 +- substrate/frame/staking/src/pallet/mod.rs | 3 +- substrate/frame/staking/src/tests.rs | 51 +++++++++++++++++++++ 4 files changed, 62 insertions(+), 8 deletions(-) diff --git a/substrate/frame/fast-unstake/src/lib.rs b/substrate/frame/fast-unstake/src/lib.rs index 7f226826cbc..f2faeebc134 100644 --- a/substrate/frame/fast-unstake/src/lib.rs +++ b/substrate/frame/fast-unstake/src/lib.rs @@ -91,7 +91,7 @@ pub mod pallet { DispatchResult, }; use sp_staking::{EraIndex, StakingInterface}; - use sp_std::{prelude::*, vec::Vec}; + use sp_std::{collections::btree_set::BTreeSet, prelude::*, vec::Vec}; pub use weights::WeightInfo; #[derive(scale_info::TypeInfo, codec::Encode, codec::Decode, codec::MaxEncodedLen)] @@ -429,9 +429,9 @@ pub mod pallet { } }; - let check_stash = |stash, deposit, eras_checked: &mut u32| { + let check_stash = |stash, deposit, eras_checked: &mut BTreeSet<EraIndex>| { let is_exposed = unchecked_eras_to_check.iter().any(|e| { - eras_checked.saturating_inc(); + eras_checked.insert(*e); T::Staking::is_exposed_in_era(&stash, e) }); @@ -452,7 +452,7 @@ pub mod pallet { <T as Config>::WeightInfo::on_idle_unstake() } else { // eras checked so far. - let mut eras_checked = 0u32; + let mut eras_checked = BTreeSet::<EraIndex>::new(); let pre_length = stashes.len(); let stashes: BoundedVec<(T::AccountId, BalanceOf<T>), T::BatchSize> = stashes @@ -468,7 +468,7 @@ pub mod pallet { log!( debug, "checked {:?} eras, pre stashes: {:?}, post: {:?}", - eras_checked, + eras_checked.len(), pre_length, post_length, ); @@ -489,7 +489,9 @@ pub mod pallet { }, } - <T as Config>::WeightInfo::on_idle_check(validator_count * eras_checked) + <T as Config>::WeightInfo::on_idle_check( + validator_count * eras_checked.len() as u32, + ) } } } diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index a7190d70c70..db9aeba6fb5 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -1569,7 +1569,7 @@ impl<T: Config> StakingInterface for Pallet<T> { } fn force_unstake(who: Self::AccountId) -> sp_runtime::DispatchResult { - let num_slashing_spans = Self::slashing_spans(&who).iter().count() as u32; + let num_slashing_spans = Self::slashing_spans(&who).map_or(0, |s| s.iter().count() as u32); Self::force_unstake(RawOrigin::Root.into(), who.clone(), num_slashing_spans) } diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 1d5babe7ffa..f04d13d05f4 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -982,7 +982,8 @@ pub mod pallet { // `BondingDuration` to proceed with the unbonding. let maybe_withdraw_weight = { if unlocking == T::MaxUnlockingChunks::get() as usize { - let real_num_slashing_spans = Self::slashing_spans(&controller).iter().count(); + let real_num_slashing_spans = + Self::slashing_spans(&controller).map_or(0, |s| s.iter().count()); Some(Self::do_withdraw_unbonded(&controller, real_num_slashing_spans as u32)?) } else { None diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index fc6fc68e66d..5c2766deee3 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -5725,3 +5725,54 @@ fn scale_validator_count_errors() { ); }) } + +mod staking_interface { + use frame_support::storage::with_storage_layer; + use sp_staking::StakingInterface; + + use super::*; + + #[test] + fn force_unstake_with_slash_works() { + ExtBuilder::default().build_and_execute(|| { + // without slash + let _ = with_storage_layer::<(), _, _>(|| { + // bond an account, can unstake + assert_eq!(Staking::bonded(&11), Some(10)); + assert_ok!(<Staking as StakingInterface>::force_unstake(11)); + Err(DispatchError::from("revert")) + }); + + // bond again and add a slash, still can unstake. + assert_eq!(Staking::bonded(&11), Some(10)); + add_slash(&11); + assert_ok!(<Staking as StakingInterface>::force_unstake(11)); + }); + } + + #[test] + fn do_withdraw_unbonded_with_wrong_slash_spans_works_as_expected() { + ExtBuilder::default().build_and_execute(|| { + on_offence_now( + &[OffenceDetails { + offender: (11, Staking::eras_stakers(active_era(), 11)), + reporters: vec![], + }], + &[Perbill::from_percent(100)], + ); + + assert_eq!(Staking::bonded(&11), Some(10)); + + assert_noop!( + Staking::withdraw_unbonded(RuntimeOrigin::signed(10), 0), + Error::<Test>::IncorrectSlashingSpans + ); + + let num_slashing_spans = Staking::slashing_spans(&11).map_or(0, |s| s.iter().count()); + assert_ok!(Staking::withdraw_unbonded( + RuntimeOrigin::signed(10), + num_slashing_spans as u32 + )); + }); + } +} -- GitLab