Compare commits
6 Commits
75268b4c0a
...
6fa5e5ed97
| Author | SHA1 | Date | |
|---|---|---|---|
| 6fa5e5ed97 | |||
| 58c5f1f33d | |||
| 55a77cd3d4 | |||
| 2cf4637d0c | |||
| 8123295f91 | |||
| 092679eb0c |
4
Cargo.lock
generated
4
Cargo.lock
generated
@ -1186,7 +1186,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "casper-runtime"
|
||||
version = "3.5.34"
|
||||
version = "3.5.36"
|
||||
dependencies = [
|
||||
"casper-runtime-constants",
|
||||
"frame-benchmarking",
|
||||
@ -3836,7 +3836,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ghost-slow-clap"
|
||||
version = "0.3.51"
|
||||
version = "0.3.53"
|
||||
dependencies = [
|
||||
"frame-benchmarking",
|
||||
"frame-support",
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "ghost-slow-clap"
|
||||
version = "0.3.51"
|
||||
version = "0.3.53"
|
||||
description = "Applause protocol for the EVM bridge"
|
||||
license.workspace = true
|
||||
authors.workspace = true
|
||||
|
||||
@ -9,8 +9,7 @@ use frame_support::{
|
||||
pallet_prelude::*,
|
||||
traits::{
|
||||
tokens::fungible::{Inspect, Mutate},
|
||||
DisabledValidators, EstimateNextSessionRotation, Get, OneSessionHandler, ValidatorSet,
|
||||
ValidatorSetWithIdentification,
|
||||
DisabledValidators, Get, OneSessionHandler, ValidatorSet, ValidatorSetWithIdentification,
|
||||
},
|
||||
WeakBoundedVec,
|
||||
};
|
||||
@ -35,11 +34,7 @@ use sp_staking::{
|
||||
offence::{Kind, Offence, ReportOffence},
|
||||
SessionIndex,
|
||||
};
|
||||
use sp_std::{
|
||||
collections::btree_map::BTreeMap,
|
||||
prelude::*,
|
||||
vec::Vec,
|
||||
};
|
||||
use sp_std::{collections::btree_map::BTreeMap, prelude::*, vec::Vec};
|
||||
|
||||
use ghost_networks::{
|
||||
NetworkData, NetworkDataBasicHandler, NetworkDataInspectHandler, NetworkDataMutateHandler,
|
||||
@ -118,7 +113,6 @@ enum OffchainErr<NetworkId> {
|
||||
UnknownNetworkType(NetworkId),
|
||||
OffchainTimeoutPeriod(NetworkId),
|
||||
TooManyRequests(NetworkId),
|
||||
AuthorityDisabled(AuthIndex),
|
||||
}
|
||||
|
||||
impl<NetworkId: core::fmt::Debug> core::fmt::Debug for OffchainErr<NetworkId> {
|
||||
@ -144,7 +138,6 @@ impl<NetworkId: core::fmt::Debug> core::fmt::Debug for OffchainErr<NetworkId> {
|
||||
OffchainErr::UnknownNetworkType(ref network_id) => write!(fmt, "Unknown type for network #{:?}.", network_id),
|
||||
OffchainErr::OffchainTimeoutPeriod(ref network_id) => write!(fmt, "Offchain request should be in-flight for network #{:?}.", network_id),
|
||||
OffchainErr::TooManyRequests(ref network_id) => write!(fmt, "Too many requests over RPC endpoint for network #{:?}.", network_id),
|
||||
OffchainErr::AuthorityDisabled(ref authority_index) => write!(fmt, "Authority index {:?} is disabled in current session.", authority_index),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -188,7 +181,6 @@ pub mod pallet {
|
||||
+ MaybeSerializeDeserialize
|
||||
+ MaxEncodedLen;
|
||||
|
||||
type NextSessionRotation: EstimateNextSessionRotation<BlockNumberFor<Self>>;
|
||||
type ValidatorSet: ValidatorSetWithIdentification<Self::AccountId>;
|
||||
type Currency: Inspect<Self::AccountId> + Mutate<Self::AccountId>;
|
||||
type NetworkDataHandler: NetworkDataBasicHandler
|
||||
@ -217,12 +209,16 @@ pub mod pallet {
|
||||
#[pallet::constant]
|
||||
type HistoryDepth: Get<SessionIndex>;
|
||||
|
||||
#[pallet::constant]
|
||||
type MinAuthoritiesNumber: Get<u32>;
|
||||
|
||||
type WeightInfo: WeightInfo;
|
||||
}
|
||||
|
||||
#[pallet::event]
|
||||
#[pallet::generate_deposit(pub(super) fn deposit_event)]
|
||||
pub enum Event<T: Config> {
|
||||
BlackSwan,
|
||||
AuthoritiesEquilibrium,
|
||||
SomeAuthoritiesTrottling {
|
||||
throttling: Vec<IdentificationTuple<T>>,
|
||||
@ -630,7 +626,8 @@ impl<T: Config> Pallet<T> {
|
||||
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 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() {
|
||||
if !info.disabled {
|
||||
@ -658,14 +655,9 @@ impl<T: Config> Pallet<T> {
|
||||
}
|
||||
}
|
||||
|
||||
let disabled_authorities = previous_claps
|
||||
.values()
|
||||
.filter(|info| info.disabled)
|
||||
.count();
|
||||
let disabled_authorities = previous_claps.values().filter(|info| info.disabled).count();
|
||||
|
||||
let active_authorities = prev_authorities
|
||||
.len()
|
||||
.saturating_sub(disabled_authorities);
|
||||
let active_authorities = prev_authorities.len().saturating_sub(disabled_authorities);
|
||||
|
||||
let clap = Clap {
|
||||
authority_index: Default::default(),
|
||||
@ -678,10 +670,9 @@ impl<T: Config> Pallet<T> {
|
||||
amount,
|
||||
};
|
||||
|
||||
let enough_authorities = Perbill::from_rational(
|
||||
total_received_claps.len() as u32,
|
||||
active_authorities as u32,
|
||||
) > Perbill::from_percent(T::ApplauseThreshold::get());
|
||||
let enough_authorities =
|
||||
Perbill::from_rational(total_received_claps.len() as u32, active_authorities as u32)
|
||||
> Perbill::from_percent(T::ApplauseThreshold::get());
|
||||
|
||||
ensure!(enough_authorities, Error::<T>::NotEnoughClaps);
|
||||
Self::try_applause(&clap, &prev_received_claps_key)?;
|
||||
@ -768,14 +759,6 @@ impl<T: Config> Pallet<T> {
|
||||
network_id: NetworkIdOf<T>,
|
||||
network_data: &NetworkData,
|
||||
) -> OffchainResult<T, ()> {
|
||||
if ClapsInSession::<T>::get(&session_index)
|
||||
.get(&authority_index)
|
||||
.map(|info| info.disabled)
|
||||
.unwrap_or_default()
|
||||
{
|
||||
return Err(OffchainErr::AuthorityDisabled(authority_index));
|
||||
}
|
||||
|
||||
let network_id_encoded = network_id.encode();
|
||||
|
||||
let block_number_key = Self::create_storage_key(b"block-", &network_id_encoded);
|
||||
@ -914,6 +897,20 @@ impl<T: Config> Pallet<T> {
|
||||
Ok(Some(new_evm_block))
|
||||
}
|
||||
EvmResponseType::TransactionLogs(evm_logs) => {
|
||||
if ClapsInSession::<T>::get(&session_index)
|
||||
.get(&authority_index)
|
||||
.map(|info| info.disabled)
|
||||
.unwrap_or_default()
|
||||
{
|
||||
log::info!(
|
||||
target: LOG_TARGET,
|
||||
"🧐 Authority #{:?} disabled in session {:?}; no claps available",
|
||||
authority_index,
|
||||
session_index
|
||||
);
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let claps: Vec<_> = evm_logs
|
||||
.iter()
|
||||
.filter_map(|log| {
|
||||
@ -1221,8 +1218,21 @@ impl<T: Config> OneSessionHandler<T::AccountId> for Pallet<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);
|
||||
} else if authorities_left < T::MinAuthoritiesNumber::get() {
|
||||
Self::deposit_event(Event::<T>::BlackSwan);
|
||||
} else {
|
||||
Self::deposit_event(Event::<T>::SomeAuthoritiesTrottling {
|
||||
throttling: offenders.clone(),
|
||||
|
||||
@ -3,7 +3,6 @@
|
||||
use frame_support::{
|
||||
derive_impl, parameter_types,
|
||||
traits::{ConstU32, ConstU64},
|
||||
weights::Weight,
|
||||
};
|
||||
use frame_system::EnsureRoot;
|
||||
use pallet_session::historical as pallet_session_historical;
|
||||
@ -140,27 +139,6 @@ parameter_types! {
|
||||
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 {
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
type Currency = Balances;
|
||||
@ -200,7 +178,6 @@ impl Config for Runtime {
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
type AuthorityId = UintAuthorityId;
|
||||
|
||||
type NextSessionRotation = TestNextSessionRotation;
|
||||
type ValidatorSet = Historical;
|
||||
type Currency = Balances;
|
||||
type NetworkDataHandler = Networks;
|
||||
@ -210,9 +187,10 @@ impl Config for Runtime {
|
||||
|
||||
type MaxAuthorities = ConstU32<5>;
|
||||
type ApplauseThreshold = ConstU32<50>;
|
||||
type OffenceThreshold = ConstU32<75>;
|
||||
type OffenceThreshold = ConstU32<0>;
|
||||
type UnsignedPriority = ConstU64<{ 1 << 20 }>;
|
||||
type HistoryDepth = HistoryDepth;
|
||||
type MinAuthoritiesNumber = ConstU32<2>;
|
||||
|
||||
type WeightInfo = ();
|
||||
}
|
||||
|
||||
@ -979,7 +979,8 @@ fn should_self_applause_after_diabled() {
|
||||
let curr_session_index = Session::session_index();
|
||||
|
||||
pallet::ClapsInSession::<Runtime>::mutate(&session_index, |claps| {
|
||||
claps.entry(1 as AuthIndex)
|
||||
claps
|
||||
.entry(1 as AuthIndex)
|
||||
.and_modify(|individual| (*individual).disabled = true)
|
||||
.or_insert(SessionAuthorityInfo {
|
||||
claps: 0u32,
|
||||
@ -988,7 +989,8 @@ fn should_self_applause_after_diabled() {
|
||||
});
|
||||
|
||||
pallet::ClapsInSession::<Runtime>::mutate(&curr_session_index, |claps| {
|
||||
claps.entry(2 as AuthIndex)
|
||||
claps
|
||||
.entry(2 as AuthIndex)
|
||||
.and_modify(|individual| (*individual).disabled = true)
|
||||
.or_insert(SessionAuthorityInfo {
|
||||
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 {
|
||||
advance_session();
|
||||
assert_eq!(Session::validators(), Vec::<u64>::new());
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "casper-runtime"
|
||||
version = "3.5.34"
|
||||
version = "3.5.36"
|
||||
build = "build.rs"
|
||||
description = "Runtime of the Casper Network"
|
||||
edition.workspace = true
|
||||
|
||||
@ -117,8 +117,8 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
|
||||
spec_name: create_runtime_str!("casper"),
|
||||
impl_name: create_runtime_str!("casper-svengali"),
|
||||
authoring_version: 0,
|
||||
spec_version: 4,
|
||||
impl_version: 2,
|
||||
spec_version: 6,
|
||||
impl_version: 4,
|
||||
apis: RUNTIME_API_VERSIONS,
|
||||
transaction_version: 1,
|
||||
state_version: 1,
|
||||
@ -1062,6 +1062,8 @@ parameter_types! {
|
||||
pub const ApplauseThreshold: u32 = 66;
|
||||
// will be used in `Perbill::from_percent()`
|
||||
pub const OffenceThreshold: u32 = 5;
|
||||
// 4 validators should be functional if 1 is offline
|
||||
pub const MinAuthoritiesNumber: u32 = 5;
|
||||
pub const SlowClapUnsignedPriority: TransactionPriority = TransactionPriority::MAX;
|
||||
pub const SlowClapHistoryDepth: sp_staking::SessionIndex =
|
||||
StakingHistoryDepth::get() * SessionsPerEra::get();
|
||||
@ -1071,7 +1073,6 @@ impl ghost_slow_clap::Config for Runtime {
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
type AuthorityId = SlowClapId;
|
||||
|
||||
type NextSessionRotation = Babe;
|
||||
type ValidatorSet = Historical;
|
||||
type Currency = Balances;
|
||||
type NetworkDataHandler = GhostNetworks;
|
||||
@ -1084,6 +1085,7 @@ impl ghost_slow_clap::Config for Runtime {
|
||||
type OffenceThreshold = OffenceThreshold;
|
||||
type UnsignedPriority = SlowClapUnsignedPriority;
|
||||
type HistoryDepth = SlowClapHistoryDepth;
|
||||
type MinAuthoritiesNumber = MinAuthoritiesNumber;
|
||||
|
||||
type WeightInfo = weights::ghost_slow_clap::WeightInfo<Runtime>;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user