Skip to content

Commit d4837cb

Browse files
kianenigmaordianAnk4n
authored
Remove implicit approval chilling upon slash. (paritytech#12420)
* don't read slashing spans when taking election snapshot * update cargo.toml * bring back remote test * fix merge stuff * fix npos-voters function sig * remove as much redundant diff as you can * Update frame/staking/src/pallet/mod.rs Co-authored-by: Andronik <write@reusable.software> * fix * Update frame/staking/src/pallet/impls.rs * update lock * fix all tests * review comments * fmt * fix offence bench * clippy * ".git/.scripts/bench-bot.sh" pallet dev pallet_staking Co-authored-by: Andronik <write@reusable.software> Co-authored-by: Ankan <ankan.anurag@gmail.com> Co-authored-by: command-bot <>
1 parent f3c95e6 commit d4837cb

File tree

9 files changed

+526
-546
lines changed

9 files changed

+526
-546
lines changed

frame/election-provider-multi-phase/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2293,6 +2293,8 @@ mod tests {
22932293
assert_eq!(MultiPhase::elect().unwrap_err(), ElectionError::Fallback("NoFallback."));
22942294
// phase is now emergency.
22952295
assert_eq!(MultiPhase::current_phase(), Phase::Emergency);
2296+
// snapshot is still there until election finalizes.
2297+
assert!(MultiPhase::snapshot().is_some());
22962298

22972299
assert_eq!(
22982300
multi_phase_events(),
@@ -2318,6 +2320,7 @@ mod tests {
23182320
// phase is now emergency.
23192321
assert_eq!(MultiPhase::current_phase(), Phase::Emergency);
23202322
assert!(MultiPhase::queued_solution().is_none());
2323+
assert!(MultiPhase::snapshot().is_some());
23212324

23222325
// no single account can trigger this
23232326
assert_noop!(

frame/offences/benchmarking/src/lib.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -308,17 +308,20 @@ benchmarks! {
308308
let slash_amount = slash_fraction * bond_amount;
309309
let reward_amount = slash_amount.saturating_mul(1 + n) / 2;
310310
let reward = reward_amount / r;
311+
let slash_report = |id| core::iter::once(
312+
<T as StakingConfig>::RuntimeEvent::from(StakingEvent::<T>::SlashReported{ validator: id, fraction: slash_fraction, slash_era: 0})
313+
);
311314
let slash = |id| core::iter::once(
312-
<T as StakingConfig>::RuntimeEvent::from(StakingEvent::<T>::Slashed{staker: id, amount: BalanceOf::<T>::from(slash_amount)})
315+
<T as StakingConfig>::RuntimeEvent::from(StakingEvent::<T>::Slashed{ staker: id, amount: BalanceOf::<T>::from(slash_amount) })
313316
);
314317
let balance_slash = |id| core::iter::once(
315-
<T as BalancesConfig>::RuntimeEvent::from(pallet_balances::Event::<T>::Slashed{who: id, amount: slash_amount.into()})
318+
<T as BalancesConfig>::RuntimeEvent::from(pallet_balances::Event::<T>::Slashed{ who: id, amount: slash_amount.into() })
316319
);
317320
let chill = |id| core::iter::once(
318-
<T as StakingConfig>::RuntimeEvent::from(StakingEvent::<T>::Chilled{stash: id})
321+
<T as StakingConfig>::RuntimeEvent::from(StakingEvent::<T>::Chilled{ stash: id })
319322
);
320323
let balance_deposit = |id, amount: u32|
321-
<T as BalancesConfig>::RuntimeEvent::from(pallet_balances::Event::<T>::Deposit{who: id, amount: amount.into()});
324+
<T as BalancesConfig>::RuntimeEvent::from(pallet_balances::Event::<T>::Deposit{ who: id, amount: amount.into() });
322325
let mut first = true;
323326
let slash_events = raw_offenders.into_iter()
324327
.flat_map(|offender| {
@@ -328,6 +331,7 @@ benchmarks! {
328331
});
329332

330333
let mut events = chill(offender.stash.clone()).map(Into::into)
334+
.chain(slash_report(offender.stash.clone()).map(Into::into))
331335
.chain(balance_slash(offender.stash.clone()).map(Into::into))
332336
.chain(slash(offender.stash).map(Into::into))
333337
.chain(nom_slashes)
@@ -407,6 +411,7 @@ benchmarks! {
407411
System::<T>::event_count(), 0
408412
+ 1 // offence
409413
+ 3 // reporter (reward + endowment)
414+
+ 1 // offenders reported
410415
+ 2 // offenders slashed
411416
+ 1 // offenders chilled
412417
+ 2 * n // nominators slashed
@@ -443,6 +448,7 @@ benchmarks! {
443448
System::<T>::event_count(), 0
444449
+ 1 // offence
445450
+ 3 // reporter (reward + endowment)
451+
+ 1 // offenders reported
446452
+ 2 // offenders slashed
447453
+ 1 // offenders chilled
448454
+ 2 * n // nominators slashed

frame/staking/src/benchmarking.rs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -792,12 +792,10 @@ benchmarks! {
792792
}
793793

794794
get_npos_voters {
795-
// number of validator intention.
795+
// number of validator intention. we will iterate all of them.
796796
let v in (MaxValidators::<T>::get() / 2) .. MaxValidators::<T>::get();
797-
// number of nominator intention.
797+
// number of nominator intention. we will iterate all of them.
798798
let n in (MaxNominators::<T>::get() / 2) .. MaxNominators::<T>::get();
799-
// total number of slashing spans. Assigned to validators randomly.
800-
let s in 1 .. 20;
801799

802800
let validators = create_validators_with_nominators_for_era::<T>(
803801
v, n, T::MaxNominations::get() as usize, false, None
@@ -806,9 +804,8 @@ benchmarks! {
806804
.map(|v| T::Lookup::lookup(v).unwrap())
807805
.collect::<Vec<_>>();
808806

809-
(0..s).for_each(|index| {
810-
add_slashing_spans::<T>(&validators[index as usize], 10);
811-
});
807+
assert_eq!(Validators::<T>::count(), v);
808+
assert_eq!(Nominators::<T>::count(), n);
812809

813810
let num_voters = (v + n) as usize;
814811
}: {

frame/staking/src/pallet/impls.rs

Lines changed: 14 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ use sp_staking::{
4040
offence::{DisableStrategy, OffenceDetails, OnOffenceHandler},
4141
EraIndex, SessionIndex, Stake, StakingInterface,
4242
};
43-
use sp_std::{collections::btree_map::BTreeMap, prelude::*};
43+
use sp_std::prelude::*;
4444

4545
use crate::{
4646
log, slashing, weights::WeightInfo, ActiveEraInfo, BalanceOf, EraPayout, Exposure, ExposureOf,
@@ -351,6 +351,7 @@ impl<T: Config> Pallet<T> {
351351
}
352352
}
353353

354+
/// Start a new era. It does:
354355
///
355356
/// * Increment `active_era.index`,
356357
/// * reset `active_era.start`,
@@ -704,11 +705,6 @@ impl<T: Config> Pallet<T> {
704705
/// `maybe_max_len` can imposes a cap on the number of voters returned;
705706
///
706707
/// This function is self-weighing as [`DispatchClass::Mandatory`].
707-
///
708-
/// ### Slashing
709-
///
710-
/// All votes that have been submitted before the last non-zero slash of the corresponding
711-
/// target are *auto-chilled*, but still count towards the limit imposed by `maybe_max_len`.
712708
pub fn get_npos_voters(maybe_max_len: Option<usize>) -> Vec<VoterOf<Self>> {
713709
let max_allowed_len = {
714710
let all_voter_count = T::VoterList::count() as usize;
@@ -719,7 +715,6 @@ impl<T: Config> Pallet<T> {
719715

720716
// cache a few things.
721717
let weight_of = Self::weight_of_fn();
722-
let slashing_spans = <SlashingSpans<T>>::iter().collect::<BTreeMap<_, _>>();
723718

724719
let mut voters_seen = 0u32;
725720
let mut validators_taken = 0u32;
@@ -737,18 +732,12 @@ impl<T: Config> Pallet<T> {
737732
None => break,
738733
};
739734

740-
if let Some(Nominations { submitted_in, mut targets, suppressed: _ }) =
741-
<Nominators<T>>::get(&voter)
742-
{
743-
// if this voter is a nominator:
744-
targets.retain(|stash| {
745-
slashing_spans
746-
.get(stash)
747-
.map_or(true, |spans| submitted_in >= spans.last_nonzero_slash())
748-
});
749-
if !targets.len().is_zero() {
735+
if let Some(Nominations { targets, .. }) = <Nominators<T>>::get(&voter) {
736+
if !targets.is_empty() {
750737
all_voters.push((voter.clone(), weight_of(&voter), targets));
751738
nominators_taken.saturating_inc();
739+
} else {
740+
// Technically should never happen, but not much we can do about it.
752741
}
753742
} else if Validators::<T>::contains_key(&voter) {
754743
// if this voter is a validator:
@@ -771,18 +760,14 @@ impl<T: Config> Pallet<T> {
771760
warn,
772761
"DEFENSIVE: invalid item in `VoterList`: {:?}, this nominator probably has too many nominations now",
773762
voter
774-
)
763+
);
775764
}
776765
}
777766

778767
// all_voters should have not re-allocated.
779768
debug_assert!(all_voters.capacity() == max_allowed_len);
780769

781-
Self::register_weight(T::WeightInfo::get_npos_voters(
782-
validators_taken,
783-
nominators_taken,
784-
slashing_spans.len() as u32,
785-
));
770+
Self::register_weight(T::WeightInfo::get_npos_voters(validators_taken, nominators_taken));
786771

787772
log!(
788773
info,
@@ -1285,6 +1270,12 @@ where
12851270
disable_strategy,
12861271
});
12871272

1273+
Self::deposit_event(Event::<T>::SlashReported {
1274+
validator: stash.clone(),
1275+
fraction: *slash_fraction,
1276+
slash_era,
1277+
});
1278+
12881279
if let Some(mut unapplied) = unapplied {
12891280
let nominators_len = unapplied.others.len() as u64;
12901281
let reporters_len = details.reporters.len() as u64;

frame/staking/src/pallet/mod.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -517,7 +517,7 @@ pub mod pallet {
517517
#[pallet::storage]
518518
#[pallet::getter(fn slashing_spans)]
519519
#[pallet::unbounded]
520-
pub(crate) type SlashingSpans<T: Config> =
520+
pub type SlashingSpans<T: Config> =
521521
StorageMap<_, Twox64Concat, T::AccountId, slashing::SlashingSpans>;
522522

523523
/// Records information about the maximum slash of a stash within a slashing span,
@@ -671,8 +671,11 @@ pub mod pallet {
671671
EraPaid { era_index: EraIndex, validator_payout: BalanceOf<T>, remainder: BalanceOf<T> },
672672
/// The nominator has been rewarded by this amount.
673673
Rewarded { stash: T::AccountId, amount: BalanceOf<T> },
674-
/// One staker (and potentially its nominators) has been slashed by the given amount.
674+
/// A staker (validator or nominator) has been slashed by the given amount.
675675
Slashed { staker: T::AccountId, amount: BalanceOf<T> },
676+
/// A slash for the given validator, for the given percentage of their stake, at the given
677+
/// era as been reported.
678+
SlashReported { validator: T::AccountId, fraction: Perbill, slash_era: EraIndex },
676679
/// An old slashing report from a prior era was discarded because it could
677680
/// not be processed.
678681
OldSlashingReportDiscarded { session_index: SessionIndex },

frame/staking/src/slashing.rs

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -239,9 +239,9 @@ pub(crate) fn compute_slash<T: Config>(
239239
return None
240240
}
241241

242-
let (prior_slash_p, _era_slash) =
242+
let prior_slash_p =
243243
<Pallet<T> as Store>::ValidatorSlashInEra::get(&params.slash_era, params.stash)
244-
.unwrap_or((Perbill::zero(), Zero::zero()));
244+
.map_or(Zero::zero(), |(prior_slash_proportion, _)| prior_slash_proportion);
245245

246246
// compare slash proportions rather than slash values to avoid issues due to rounding
247247
// error.
@@ -390,9 +390,7 @@ fn slash_nominators<T: Config>(
390390
let mut era_slash =
391391
<Pallet<T> as Store>::NominatorSlashInEra::get(&params.slash_era, stash)
392392
.unwrap_or_else(Zero::zero);
393-
394393
era_slash += own_slash_difference;
395-
396394
<Pallet<T> as Store>::NominatorSlashInEra::insert(&params.slash_era, stash, &era_slash);
397395

398396
era_slash
@@ -411,12 +409,10 @@ fn slash_nominators<T: Config>(
411409
let target_span = spans.compare_and_update_span_slash(params.slash_era, era_slash);
412410

413411
if target_span == Some(spans.span_index()) {
414-
// End the span, but don't chill the nominator. its nomination
415-
// on this validator will be ignored in the future.
412+
// end the span, but don't chill the nominator.
416413
spans.end_span(params.now);
417414
}
418415
}
419-
420416
nominators_slashed.push((stash.clone(), nom_slashed));
421417
}
422418

0 commit comments

Comments
 (0)