introduce black swan event e.g. disable everybody
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
This commit is contained in:
parent
092679eb0c
commit
55a77cd3d4
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "ghost-slow-clap"
|
name = "ghost-slow-clap"
|
||||||
version = "0.3.52"
|
version = "0.3.53"
|
||||||
description = "Applause protocol for the EVM bridge"
|
description = "Applause protocol for the EVM bridge"
|
||||||
license.workspace = true
|
license.workspace = true
|
||||||
authors.workspace = true
|
authors.workspace = true
|
||||||
|
|||||||
@ -9,8 +9,7 @@ use frame_support::{
|
|||||||
pallet_prelude::*,
|
pallet_prelude::*,
|
||||||
traits::{
|
traits::{
|
||||||
tokens::fungible::{Inspect, Mutate},
|
tokens::fungible::{Inspect, Mutate},
|
||||||
DisabledValidators, EstimateNextSessionRotation, Get, OneSessionHandler, ValidatorSet,
|
DisabledValidators, Get, OneSessionHandler, ValidatorSet, ValidatorSetWithIdentification,
|
||||||
ValidatorSetWithIdentification,
|
|
||||||
},
|
},
|
||||||
WeakBoundedVec,
|
WeakBoundedVec,
|
||||||
};
|
};
|
||||||
@ -35,11 +34,7 @@ use sp_staking::{
|
|||||||
offence::{Kind, Offence, ReportOffence},
|
offence::{Kind, Offence, ReportOffence},
|
||||||
SessionIndex,
|
SessionIndex,
|
||||||
};
|
};
|
||||||
use sp_std::{
|
use sp_std::{collections::btree_map::BTreeMap, prelude::*, vec::Vec};
|
||||||
collections::btree_map::BTreeMap,
|
|
||||||
prelude::*,
|
|
||||||
vec::Vec,
|
|
||||||
};
|
|
||||||
|
|
||||||
use ghost_networks::{
|
use ghost_networks::{
|
||||||
NetworkData, NetworkDataBasicHandler, NetworkDataInspectHandler, NetworkDataMutateHandler,
|
NetworkData, NetworkDataBasicHandler, NetworkDataInspectHandler, NetworkDataMutateHandler,
|
||||||
@ -186,7 +181,6 @@ pub mod pallet {
|
|||||||
+ MaybeSerializeDeserialize
|
+ MaybeSerializeDeserialize
|
||||||
+ MaxEncodedLen;
|
+ MaxEncodedLen;
|
||||||
|
|
||||||
type NextSessionRotation: EstimateNextSessionRotation<BlockNumberFor<Self>>;
|
|
||||||
type ValidatorSet: ValidatorSetWithIdentification<Self::AccountId>;
|
type ValidatorSet: ValidatorSetWithIdentification<Self::AccountId>;
|
||||||
type Currency: Inspect<Self::AccountId> + Mutate<Self::AccountId>;
|
type Currency: Inspect<Self::AccountId> + Mutate<Self::AccountId>;
|
||||||
type NetworkDataHandler: NetworkDataBasicHandler
|
type NetworkDataHandler: NetworkDataBasicHandler
|
||||||
@ -215,12 +209,16 @@ pub mod pallet {
|
|||||||
#[pallet::constant]
|
#[pallet::constant]
|
||||||
type HistoryDepth: Get<SessionIndex>;
|
type HistoryDepth: Get<SessionIndex>;
|
||||||
|
|
||||||
|
#[pallet::constant]
|
||||||
|
type MinAuthoritiesNumber: Get<u32>;
|
||||||
|
|
||||||
type WeightInfo: WeightInfo;
|
type WeightInfo: WeightInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pallet::event]
|
#[pallet::event]
|
||||||
#[pallet::generate_deposit(pub(super) fn deposit_event)]
|
#[pallet::generate_deposit(pub(super) fn deposit_event)]
|
||||||
pub enum Event<T: Config> {
|
pub enum Event<T: Config> {
|
||||||
|
BlackSwan,
|
||||||
AuthoritiesEquilibrium,
|
AuthoritiesEquilibrium,
|
||||||
SomeAuthoritiesTrottling {
|
SomeAuthoritiesTrottling {
|
||||||
throttling: Vec<IdentificationTuple<T>>,
|
throttling: Vec<IdentificationTuple<T>>,
|
||||||
@ -628,7 +626,8 @@ impl<T: Config> Pallet<T> {
|
|||||||
let curr_received_claps_key = (curr_session_index, &transaction_hash, &clap_unique_hash);
|
let curr_received_claps_key = (curr_session_index, &transaction_hash, &clap_unique_hash);
|
||||||
|
|
||||||
let mut previous_claps = ClapsInSession::<T>::get(&prev_session_index);
|
let mut previous_claps = ClapsInSession::<T>::get(&prev_session_index);
|
||||||
let mut total_received_claps = ReceivedClaps::<T>::get(&prev_received_claps_key).into_inner();
|
let mut total_received_claps =
|
||||||
|
ReceivedClaps::<T>::get(&prev_received_claps_key).into_inner();
|
||||||
|
|
||||||
for (auth_index, info) in ClapsInSession::<T>::get(&curr_session_index).iter() {
|
for (auth_index, info) in ClapsInSession::<T>::get(&curr_session_index).iter() {
|
||||||
if !info.disabled {
|
if !info.disabled {
|
||||||
@ -656,14 +655,9 @@ impl<T: Config> Pallet<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let disabled_authorities = previous_claps
|
let disabled_authorities = previous_claps.values().filter(|info| info.disabled).count();
|
||||||
.values()
|
|
||||||
.filter(|info| info.disabled)
|
|
||||||
.count();
|
|
||||||
|
|
||||||
let active_authorities = prev_authorities
|
let active_authorities = prev_authorities.len().saturating_sub(disabled_authorities);
|
||||||
.len()
|
|
||||||
.saturating_sub(disabled_authorities);
|
|
||||||
|
|
||||||
let clap = Clap {
|
let clap = Clap {
|
||||||
authority_index: Default::default(),
|
authority_index: Default::default(),
|
||||||
@ -676,10 +670,9 @@ impl<T: Config> Pallet<T> {
|
|||||||
amount,
|
amount,
|
||||||
};
|
};
|
||||||
|
|
||||||
let enough_authorities = Perbill::from_rational(
|
let enough_authorities =
|
||||||
total_received_claps.len() as u32,
|
Perbill::from_rational(total_received_claps.len() as u32, active_authorities as u32)
|
||||||
active_authorities as u32,
|
> Perbill::from_percent(T::ApplauseThreshold::get());
|
||||||
) > Perbill::from_percent(T::ApplauseThreshold::get());
|
|
||||||
|
|
||||||
ensure!(enough_authorities, Error::<T>::NotEnoughClaps);
|
ensure!(enough_authorities, Error::<T>::NotEnoughClaps);
|
||||||
Self::try_applause(&clap, &prev_received_claps_key)?;
|
Self::try_applause(&clap, &prev_received_claps_key)?;
|
||||||
@ -1225,8 +1218,21 @@ impl<T: Config> OneSessionHandler<T::AccountId> for Pallet<T> {
|
|||||||
})
|
})
|
||||||
.collect::<Vec<IdentificationTuple<T>>>();
|
.collect::<Vec<IdentificationTuple<T>>>();
|
||||||
|
|
||||||
if offenders.is_empty() {
|
let disabled_validators = T::DisabledValidators::disabled_validators()
|
||||||
|
.into_iter()
|
||||||
|
.count();
|
||||||
|
|
||||||
|
let offenders_length = offenders.len();
|
||||||
|
let authorities_left: u32 = authorities_len
|
||||||
|
.saturating_sub(disabled_validators)
|
||||||
|
.saturating_sub(offenders_length)
|
||||||
|
.try_into()
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
|
if offenders_length == 0 {
|
||||||
Self::deposit_event(Event::<T>::AuthoritiesEquilibrium);
|
Self::deposit_event(Event::<T>::AuthoritiesEquilibrium);
|
||||||
|
} else if authorities_left < T::MinAuthoritiesNumber::get() {
|
||||||
|
Self::deposit_event(Event::<T>::BlackSwan);
|
||||||
} else {
|
} else {
|
||||||
Self::deposit_event(Event::<T>::SomeAuthoritiesTrottling {
|
Self::deposit_event(Event::<T>::SomeAuthoritiesTrottling {
|
||||||
throttling: offenders.clone(),
|
throttling: offenders.clone(),
|
||||||
|
|||||||
@ -3,7 +3,6 @@
|
|||||||
use frame_support::{
|
use frame_support::{
|
||||||
derive_impl, parameter_types,
|
derive_impl, parameter_types,
|
||||||
traits::{ConstU32, ConstU64},
|
traits::{ConstU32, ConstU64},
|
||||||
weights::Weight,
|
|
||||||
};
|
};
|
||||||
use frame_system::EnsureRoot;
|
use frame_system::EnsureRoot;
|
||||||
use pallet_session::historical as pallet_session_historical;
|
use pallet_session::historical as pallet_session_historical;
|
||||||
@ -140,27 +139,6 @@ parameter_types! {
|
|||||||
pub static MockAverageSessionLength: Option<u64> = None;
|
pub static MockAverageSessionLength: Option<u64> = None;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct TestNextSessionRotation;
|
|
||||||
impl frame_support::traits::EstimateNextSessionRotation<u64> for TestNextSessionRotation {
|
|
||||||
fn average_session_length() -> u64 {
|
|
||||||
let mock = MockAverageSessionLength::mutate(|p| p.take());
|
|
||||||
mock.unwrap_or(pallet_session::PeriodicSessions::<Period, Offset>::average_session_length())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn estimate_current_session_progress(now: u64) -> (Option<Permill>, Weight) {
|
|
||||||
let (estimate, weight) =
|
|
||||||
pallet_session::PeriodicSessions::<Period, Offset>::estimate_current_session_progress(
|
|
||||||
now,
|
|
||||||
);
|
|
||||||
let mock = MockCurrentSessionProgress::mutate(|p| p.take());
|
|
||||||
(mock.unwrap_or(estimate), weight)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn estimate_next_session_rotation(now: u64) -> (Option<u64>, Weight) {
|
|
||||||
pallet_session::PeriodicSessions::<Period, Offset>::estimate_next_session_rotation(now)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ghost_networks::Config for Runtime {
|
impl ghost_networks::Config for Runtime {
|
||||||
type RuntimeEvent = RuntimeEvent;
|
type RuntimeEvent = RuntimeEvent;
|
||||||
type Currency = Balances;
|
type Currency = Balances;
|
||||||
@ -200,7 +178,6 @@ impl Config for Runtime {
|
|||||||
type RuntimeEvent = RuntimeEvent;
|
type RuntimeEvent = RuntimeEvent;
|
||||||
type AuthorityId = UintAuthorityId;
|
type AuthorityId = UintAuthorityId;
|
||||||
|
|
||||||
type NextSessionRotation = TestNextSessionRotation;
|
|
||||||
type ValidatorSet = Historical;
|
type ValidatorSet = Historical;
|
||||||
type Currency = Balances;
|
type Currency = Balances;
|
||||||
type NetworkDataHandler = Networks;
|
type NetworkDataHandler = Networks;
|
||||||
@ -210,9 +187,10 @@ impl Config for Runtime {
|
|||||||
|
|
||||||
type MaxAuthorities = ConstU32<5>;
|
type MaxAuthorities = ConstU32<5>;
|
||||||
type ApplauseThreshold = ConstU32<50>;
|
type ApplauseThreshold = ConstU32<50>;
|
||||||
type OffenceThreshold = ConstU32<75>;
|
type OffenceThreshold = ConstU32<0>;
|
||||||
type UnsignedPriority = ConstU64<{ 1 << 20 }>;
|
type UnsignedPriority = ConstU64<{ 1 << 20 }>;
|
||||||
type HistoryDepth = HistoryDepth;
|
type HistoryDepth = HistoryDepth;
|
||||||
|
type MinAuthoritiesNumber = ConstU32<2>;
|
||||||
|
|
||||||
type WeightInfo = ();
|
type WeightInfo = ();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -979,7 +979,8 @@ fn should_self_applause_after_diabled() {
|
|||||||
let curr_session_index = Session::session_index();
|
let curr_session_index = Session::session_index();
|
||||||
|
|
||||||
pallet::ClapsInSession::<Runtime>::mutate(&session_index, |claps| {
|
pallet::ClapsInSession::<Runtime>::mutate(&session_index, |claps| {
|
||||||
claps.entry(1 as AuthIndex)
|
claps
|
||||||
|
.entry(1 as AuthIndex)
|
||||||
.and_modify(|individual| (*individual).disabled = true)
|
.and_modify(|individual| (*individual).disabled = true)
|
||||||
.or_insert(SessionAuthorityInfo {
|
.or_insert(SessionAuthorityInfo {
|
||||||
claps: 0u32,
|
claps: 0u32,
|
||||||
@ -988,7 +989,8 @@ fn should_self_applause_after_diabled() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
pallet::ClapsInSession::<Runtime>::mutate(&curr_session_index, |claps| {
|
pallet::ClapsInSession::<Runtime>::mutate(&curr_session_index, |claps| {
|
||||||
claps.entry(2 as AuthIndex)
|
claps
|
||||||
|
.entry(2 as AuthIndex)
|
||||||
.and_modify(|individual| (*individual).disabled = true)
|
.and_modify(|individual| (*individual).disabled = true)
|
||||||
.or_insert(SessionAuthorityInfo {
|
.or_insert(SessionAuthorityInfo {
|
||||||
claps: 0u32,
|
claps: 0u32,
|
||||||
@ -1207,6 +1209,22 @@ fn should_not_fail_on_sub_existential_balance() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_emit_black_swan_if_not_enough_authorities_left() {
|
||||||
|
let (network_id, _, _) = generate_unique_hash(None, None, None, None);
|
||||||
|
|
||||||
|
new_test_ext().execute_with(|| {
|
||||||
|
let session_index = advance_session_and_get_index();
|
||||||
|
assert_ok!(do_clap_from(session_index, network_id, 0, false));
|
||||||
|
Session::disable_index(1);
|
||||||
|
Session::disable_index(2);
|
||||||
|
|
||||||
|
advance_session();
|
||||||
|
advance_session();
|
||||||
|
System::assert_has_event(RuntimeEvent::SlowClap(crate::Event::BlackSwan));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
fn advance_session_and_get_index() -> u32 {
|
fn advance_session_and_get_index() -> u32 {
|
||||||
advance_session();
|
advance_session();
|
||||||
assert_eq!(Session::validators(), Vec::<u64>::new());
|
assert_eq!(Session::validators(), Vec::<u64>::new());
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user