Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

staking: only disable slashed validators and keep them disabled for whole era #9448

Merged
11 commits merged into from
Oct 6, 2021
7 changes: 2 additions & 5 deletions bin/node/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -444,10 +444,6 @@ impl_opaque_keys! {
}
}

parameter_types! {
pub const DisabledValidatorsThreshold: Perbill = Perbill::from_percent(17);
}

impl pallet_session::Config for Runtime {
type Event = Event;
type ValidatorId = <Self as frame_system::Config>::AccountId;
Expand All @@ -457,7 +453,6 @@ impl pallet_session::Config for Runtime {
type SessionManager = pallet_session::historical::NoteHistoricalRoot<Self, Staking>;
type SessionHandler = <SessionKeys as OpaqueKeys>::KeyTypeIdProviders;
type Keys = SessionKeys;
type DisabledValidatorsThreshold = DisabledValidatorsThreshold;
type WeightInfo = pallet_session::weights::SubstrateWeight<Runtime>;
}

Expand All @@ -483,6 +478,7 @@ parameter_types! {
pub const SlashDeferDuration: pallet_staking::EraIndex = 24 * 7; // 1/4 the bonding duration.
pub const RewardCurve: &'static PiecewiseLinear<'static> = &REWARD_CURVE;
pub const MaxNominatorRewardedPerValidator: u32 = 256;
pub const OffendingValidatorsThreshold: Perbill = Perbill::from_percent(17);
andresilva marked this conversation as resolved.
Show resolved Hide resolved
pub OffchainRepeat: BlockNumber = 5;
}

Expand All @@ -509,6 +505,7 @@ impl pallet_staking::Config for Runtime {
type EraPayout = pallet_staking::ConvertCurve<RewardCurve>;
type NextNewSession = Session;
type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator;
type OffendingValidatorsThreshold = OffendingValidatorsThreshold;
type ElectionProvider = ElectionProviderMultiPhase;
type GenesisElectionProvider = onchain::OnChainSequentialPhragmen<
pallet_election_provider_multi_phase::OnChainConfig<Self>,
Expand Down
2 changes: 1 addition & 1 deletion frame/aura/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ impl<T: Config> OneSessionHandler<T::AccountId> for Pallet<T> {
}
}

fn on_disabled(i: usize) {
fn on_disabled(i: u32) {
let log: DigestItem<T::Hash> = DigestItem::Consensus(
AURA_ENGINE_ID,
ConsensusLog::<T::AuthorityId>::OnDisabled(i as AuthorityIndex).encode(),
Expand Down
11 changes: 3 additions & 8 deletions frame/authority-discovery/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ impl<T: Config> OneSessionHandler<T::AccountId> for Pallet<T> {
}
}

fn on_disabled(_i: usize) {
fn on_disabled(_i: u32) {
// ignore
}
}
Expand All @@ -148,7 +148,7 @@ mod tests {
use sp_runtime::{
testing::{Header, UintAuthorityId},
traits::{ConvertInto, IdentityLookup, OpaqueKeys},
KeyTypeId, Perbill,
KeyTypeId,
};

type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Test>;
Expand All @@ -168,10 +168,6 @@ mod tests {

impl Config for Test {}

parameter_types! {
pub const DisabledValidatorsThreshold: Perbill = Perbill::from_percent(33);
}

impl pallet_session::Config for Test {
type SessionManager = ();
type Keys = UintAuthorityId;
Expand All @@ -180,7 +176,6 @@ mod tests {
type Event = Event;
type ValidatorId = AuthorityId;
type ValidatorIdOf = ConvertInto;
type DisabledValidatorsThreshold = DisabledValidatorsThreshold;
type NextSessionRotation = pallet_session::PeriodicSessions<Period, Offset>;
type WeightInfo = ();
}
Expand Down Expand Up @@ -238,7 +233,7 @@ mod tests {
) {
}

fn on_disabled(_validator_index: usize) {}
fn on_disabled(_validator_index: u32) {}

fn on_genesis_session<Ks: OpaqueKeys>(_validators: &[(AuthorityId, Ks)]) {}
}
Expand Down
4 changes: 2 additions & 2 deletions frame/babe/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -884,8 +884,8 @@ impl<T: Config> OneSessionHandler<T::AccountId> for Pallet<T> {
Self::enact_epoch_change(authorities, next_authorities)
}

fn on_disabled(i: usize) {
Self::deposit_consensus(ConsensusLog::OnDisabled(i as u32))
fn on_disabled(i: u32) {
Self::deposit_consensus(ConsensusLog::OnDisabled(i))
}
}

Expand Down
4 changes: 2 additions & 2 deletions frame/babe/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@ frame_support::construct_runtime!(

parameter_types! {
pub const BlockHashCount: u64 = 250;
pub const DisabledValidatorsThreshold: Perbill = Perbill::from_percent(16);
pub BlockWeights: frame_system::limits::BlockWeights =
frame_system::limits::BlockWeights::simple_max(1024);
}
Expand Down Expand Up @@ -122,7 +121,6 @@ impl pallet_session::Config for Test {
type SessionManager = pallet_session::historical::NoteHistoricalRoot<Self, Staking>;
type SessionHandler = <MockSessionKeys as OpaqueKeys>::KeyTypeIdProviders;
type Keys = MockSessionKeys;
type DisabledValidatorsThreshold = DisabledValidatorsThreshold;
type WeightInfo = ();
}

Expand Down Expand Up @@ -189,6 +187,7 @@ parameter_types! {
pub const MaxNominatorRewardedPerValidator: u32 = 64;
pub const ElectionLookahead: u64 = 0;
pub const StakingUnsignedPriority: u64 = u64::MAX / 2;
pub const OffendingValidatorsThreshold: Perbill = Perbill::from_percent(16);
}

impl onchain::Config for Test {
Expand All @@ -214,6 +213,7 @@ impl pallet_staking::Config for Test {
type UnixTime = pallet_timestamp::Pallet<Test>;
type EraPayout = pallet_staking::ConvertCurve<RewardCurve>;
type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator;
type OffendingValidatorsThreshold = OffendingValidatorsThreshold;
type NextNewSession = Session;
type ElectionProvider = onchain::OnChainSequentialPhragmen<Self>;
type GenesisElectionProvider = Self::ElectionProvider;
Expand Down
2 changes: 1 addition & 1 deletion frame/grandpa/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -644,7 +644,7 @@ where
SetIdSession::<T>::insert(current_set_id, &session_index);
}

fn on_disabled(i: usize) {
fn on_disabled(i: u32) {
Self::deposit_log(ConsensusLog::OnDisabled(i as u64))
}
}
4 changes: 2 additions & 2 deletions frame/grandpa/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,6 @@ where
parameter_types! {
pub const Period: u64 = 1;
pub const Offset: u64 = 0;
pub const DisabledValidatorsThreshold: Perbill = Perbill::from_percent(17);
}

/// Custom `SessionHandler` since we use `TestSessionKeys` as `Keys`.
Expand All @@ -124,7 +123,6 @@ impl pallet_session::Config for Test {
type SessionManager = pallet_session::historical::NoteHistoricalRoot<Self, Staking>;
type SessionHandler = <TestSessionKeys as OpaqueKeys>::KeyTypeIdProviders;
type Keys = TestSessionKeys;
type DisabledValidatorsThreshold = DisabledValidatorsThreshold;
type WeightInfo = ();
}

Expand Down Expand Up @@ -191,6 +189,7 @@ parameter_types! {
pub const MaxNominatorRewardedPerValidator: u32 = 64;
pub const ElectionLookahead: u64 = 0;
pub const StakingUnsignedPriority: u64 = u64::MAX / 2;
pub const OffendingValidatorsThreshold: Perbill = Perbill::from_percent(17);
}

impl onchain::Config for Test {
Expand All @@ -216,6 +215,7 @@ impl pallet_staking::Config for Test {
type UnixTime = pallet_timestamp::Pallet<Test>;
type EraPayout = pallet_staking::ConvertCurve<RewardCurve>;
type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator;
type OffendingValidatorsThreshold = OffendingValidatorsThreshold;
type NextNewSession = Session;
type ElectionProvider = onchain::OnChainSequentialPhragmen<Self>;
type GenesisElectionProvider = Self::ElectionProvider;
Expand Down
2 changes: 1 addition & 1 deletion frame/im-online/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -814,7 +814,7 @@ impl<T: Config> OneSessionHandler<T::AccountId> for Pallet<T> {
}
}

fn on_disabled(_i: usize) {
fn on_disabled(_i: u32) {
// ignore
}
}
Expand Down
7 changes: 1 addition & 6 deletions frame/im-online/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use sp_core::H256;
use sp_runtime::{
testing::{Header, TestXt, UintAuthorityId},
traits::{BlakeTwo256, ConvertInto, IdentityLookup},
Perbill, Permill,
Permill,
};
use sp_staking::{
offence::{OffenceError, ReportOffence},
Expand Down Expand Up @@ -146,10 +146,6 @@ parameter_types! {
pub const Offset: u64 = 0;
}

parameter_types! {
pub const DisabledValidatorsThreshold: Perbill = Perbill::from_percent(33);
}

impl pallet_session::Config for Runtime {
type ShouldEndSession = pallet_session::PeriodicSessions<Period, Offset>;
type SessionManager =
Expand All @@ -159,7 +155,6 @@ impl pallet_session::Config for Runtime {
type ValidatorIdOf = ConvertInto;
type Keys = UintAuthorityId;
type Event = Event;
type DisabledValidatorsThreshold = DisabledValidatorsThreshold;
type NextSessionRotation = pallet_session::PeriodicSessions<Period, Offset>;
type WeightInfo = ();
}
Expand Down
4 changes: 2 additions & 2 deletions frame/offences/benchmarking/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ impl pallet_session::SessionHandler<AccountId> for TestSessionHandler {
) {
}

fn on_disabled(_: usize) {}
fn on_disabled(_: u32) {}
}

parameter_types! {
Expand All @@ -129,7 +129,6 @@ impl pallet_session::Config for Test {
type Event = Event;
type ValidatorId = AccountId;
type ValidatorIdOf = pallet_staking::StashOf<Test>;
type DisabledValidatorsThreshold = ();
type WeightInfo = ();
}

Expand Down Expand Up @@ -174,6 +173,7 @@ impl pallet_staking::Config for Test {
type EraPayout = pallet_staking::ConvertCurve<RewardCurve>;
type NextNewSession = Session;
type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator;
type OffendingValidatorsThreshold = ();
type ElectionProvider = onchain::OnChainSequentialPhragmen<Self>;
type GenesisElectionProvider = Self::ElectionProvider;
type WeightInfo = ();
Expand Down
4 changes: 2 additions & 2 deletions frame/session/benchmarking/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ impl pallet_session::SessionHandler<AccountId> for TestSessionHandler {
) {
}

fn on_disabled(_: usize) {}
fn on_disabled(_: u32) {}
}

impl pallet_session::Config for Test {
Expand All @@ -129,7 +129,6 @@ impl pallet_session::Config for Test {
type Event = Event;
type ValidatorId = AccountId;
type ValidatorIdOf = pallet_staking::StashOf<Test>;
type DisabledValidatorsThreshold = ();
type WeightInfo = ();
}
pallet_staking_reward_curve::build! {
Expand Down Expand Up @@ -182,6 +181,7 @@ impl pallet_staking::Config for Test {
type EraPayout = pallet_staking::ConvertCurve<RewardCurve>;
type NextNewSession = Session;
type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator;
type OffendingValidatorsThreshold = ();
type ElectionProvider = onchain::OnChainSequentialPhragmen<Self>;
type GenesisElectionProvider = Self::ElectionProvider;
type WeightInfo = ();
Expand Down
54 changes: 20 additions & 34 deletions frame/session/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ use frame_support::{
use frame_system::ensure_signed;
use sp_runtime::{
traits::{AtLeast32BitUnsigned, Convert, Member, One, OpaqueKeys, Zero},
KeyTypeId, Perbill, Permill, RuntimeAppPublic,
KeyTypeId, Permill, RuntimeAppPublic,
};
use sp_staking::SessionIndex;
use sp_std::{
Expand Down Expand Up @@ -297,7 +297,7 @@ pub trait SessionHandler<ValidatorId> {
fn on_before_session_ending() {}

/// A validator got disabled. Act accordingly until a new session begins.
fn on_disabled(validator_index: usize);
fn on_disabled(validator_index: u32);
}

#[impl_trait_for_tuples::impl_for_tuples(1, 30)]
Expand Down Expand Up @@ -341,7 +341,7 @@ impl<AId> SessionHandler<AId> for Tuple {
for_tuples!( #( Tuple::on_before_session_ending(); )* )
}

fn on_disabled(i: usize) {
fn on_disabled(i: u32) {
for_tuples!( #( Tuple::on_disabled(i); )* )
}
}
Expand All @@ -353,7 +353,7 @@ impl<AId> SessionHandler<AId> for TestSessionHandler {
fn on_genesis_session<Ks: OpaqueKeys>(_: &[(AId, Ks)]) {}
fn on_new_session<Ks: OpaqueKeys>(_: bool, _: &[(AId, Ks)], _: &[(AId, Ks)]) {}
fn on_before_session_ending() {}
fn on_disabled(_: usize) {}
fn on_disabled(_: u32) {}
}

impl<T: Config> ValidatorRegistration<T::ValidatorId> for Module<T> {
Expand Down Expand Up @@ -391,12 +391,6 @@ pub trait Config: frame_system::Config {
/// The keys.
type Keys: OpaqueKeys + Member + Parameter + Default;

/// The fraction of validators set that is safe to be disabled.
///
/// After the threshold is reached `disabled` method starts to return true,
/// which in combination with `pallet_staking` forces a new era.
type DisabledValidatorsThreshold: Get<Perbill>;

/// Weight information for extrinsics in this pallet.
type WeightInfo: WeightInfo;
}
Expand Down Expand Up @@ -664,42 +658,34 @@ impl<T: Config> Module<T> {
T::SessionHandler::on_new_session::<T::Keys>(changed, &session_keys, &queued_amalgamated);
}

/// Disable the validator of index `i`.
///
/// Returns `true` if this causes a `DisabledValidatorsThreshold` of validators
/// to be already disabled.
pub fn disable_index(i: usize) -> bool {
let (fire_event, threshold_reached) = DisabledValidators::mutate(|disabled| {
let i = i as u32;
/// Disable the validator of index `i`, returns `false` if the validator was already disabled.
pub fn disable_index(i: u32) -> bool {
if i >= Validators::<T>::decode_len().unwrap_or(0) as u32 {
return false
}

DisabledValidators::mutate(|disabled| {
andresilva marked this conversation as resolved.
Show resolved Hide resolved
if let Err(index) = disabled.binary_search(&i) {
andresilva marked this conversation as resolved.
Show resolved Hide resolved
let count = <Validators<T>>::decode_len().unwrap_or(0) as u32;
let threshold = T::DisabledValidatorsThreshold::get() * count;
disabled.insert(index, i);
(true, disabled.len() as u32 > threshold)
} else {
(false, false)
T::SessionHandler::on_disabled(i);
andresilva marked this conversation as resolved.
Show resolved Hide resolved
return true
}
});

if fire_event {
T::SessionHandler::on_disabled(i);
}

threshold_reached
false
})
}

/// Disable the validator identified by `c`. (If using with the staking module,
/// this would be their *stash* account.)
///
/// Returns `Ok(true)` if more than `DisabledValidatorsThreshold` validators in current
/// session is already disabled.
/// If used with the staking module it allows to force a new era in such case.
pub fn disable(c: &T::ValidatorId) -> sp_std::result::Result<bool, ()> {
/// Returns `false` either if the validator could not be found or it was already
/// disabled.
pub fn disable(c: &T::ValidatorId) -> bool {
Self::validators()
.iter()
.position(|i| i == c)
.map(Self::disable_index)
.ok_or(())
.map(|i| Self::disable_index(i as u32))
.unwrap_or(false)
}

/// Upgrade the key type from some old type to a new type. Supports adding
Expand Down
Loading