diff --git a/pallets/slow-clap/Cargo.toml b/pallets/slow-clap/Cargo.toml index aae9eda..9ebe35f 100644 --- a/pallets/slow-clap/Cargo.toml +++ b/pallets/slow-clap/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ghost-slow-clap" -version = "0.4.29" +version = "0.4.30" description = "Applause protocol for the EVM bridge" license.workspace = true authors.workspace = true diff --git a/pallets/slow-clap/src/lib.rs b/pallets/slow-clap/src/lib.rs index 52d9fa9..c583f56 100644 --- a/pallets/slow-clap/src/lib.rs +++ b/pallets/slow-clap/src/lib.rs @@ -42,6 +42,7 @@ use ghost_networks::{ NetworkType, }; use ghost_traits::exposure::ExposureListener; +use ghost_traits::evictor::StakingEvictor; pub mod migrations; pub mod weights; @@ -309,6 +310,7 @@ pub mod pallet { >; type DisabledValidators: DisabledValidators; type ExposureListener: ExposureListener, Self::AccountId>; + type StakingEvictor: StakingEvictor; #[pallet::constant] type MaxAuthorities: Get; @@ -1455,7 +1457,15 @@ impl Pallet { let authority_index = index as AuthIndex; if offence_bitmap.exists(&authority_index) { - weight.saturating_accrue(T::DbWeight::get().reads(1)); + weight.saturating_accrue(T::DbWeight::get().reads(2)); + + if let Some(account_id) = T::ExposureListener::get_account_by_index(index) { + weight.saturating_accrue(T::DbWeight::get().reads(1)); + if T::StakingEvictor::try_evict_validator(&account_id) { + weight.saturating_accrue(T::DbWeight::get().writes(2)); + } + } + if let Some(full_id) = >::IdentificationOf::convert(id.clone()) diff --git a/pallets/slow-clap/src/mock.rs b/pallets/slow-clap/src/mock.rs index a64d3e6..10d543d 100644 --- a/pallets/slow-clap/src/mock.rs +++ b/pallets/slow-clap/src/mock.rs @@ -5,6 +5,7 @@ use frame_support::{ traits::{ConstU32, ConstU64}, }; use frame_system::EnsureRoot; +use ghost_traits::evictor::StakingEvictor; use pallet_session::historical as pallet_session_historical; use sp_runtime::{ curve::PiecewiseLinear, @@ -36,6 +37,7 @@ frame_support::construct_runtime!( ); parameter_types! { + pub static EvicatedValidators: Vec = vec![]; pub static FixedValidators: Vec = vec![0, 1, 2, 3]; } @@ -172,6 +174,25 @@ impl pallet_balances::Config for Runtime { type Balance = u64; +pub struct TestStakingEvictor; +impl StakingEvictor for TestStakingEvictor { + fn try_evict_validator(who: &u64) -> bool { + if !FixedValidators::get().contains(who) { + return false; + } + + let mut evicted_validators = EvicatedValidators::get(); + match evicted_validators.iter().position(|x| x == who) { + Some(_) => false, + None => { + evicted_validators.push(*who); + EvicatedValidators::set(evicted_validators); + true + } + } + } +} + pub struct TestExposureListener; impl ExposureListener for TestExposureListener where @@ -217,6 +238,7 @@ impl Config for Runtime { type ReportUnresponsiveness = OffenceHandler; type DisabledValidators = Session; type ExposureListener = TestExposureListener; + type StakingEvictor = TestStakingEvictor; type MaxAuthorities = ConstU32<5>; type ApplauseThreshold = ConstU32<500_000_000>; diff --git a/pallets/slow-clap/src/tests.rs b/pallets/slow-clap/src/tests.rs index 0500bdb..ceeda90 100644 --- a/pallets/slow-clap/src/tests.rs +++ b/pallets/slow-clap/src/tests.rs @@ -1691,6 +1691,40 @@ fn migration_from_v2_to_v3_works_fine() { }); } +#[test] +fn validators_are_evicted_during_offence() { + let (network_id, _, _) = generate_unique_hash(None, None, None, None, None); + + new_test_ext().execute_with(|| { + let session_index = advance_session_and_get_index(); + prepare_evm_network(None, None); + + assert_eq!(BlockCommitments::::get(network_id).len(), 0); + System::set_block_number(5 * EpochDuration::get() / 2); + let last_stored_block = 69; + + for i in 0..3 { + assert_ok!(do_block_commitment( + session_index, + network_id, + i, + last_stored_block, + )); + } + + assert_eq!(EvicatedValidators::get().len(), 0); + let current_block = SlowClap::current_block_number(); + + SlowClap::on_initialize(current_block); + System::assert_has_event(RuntimeEvent::SlowClap( + crate::Event::SomeAuthoritiesDelayed { + delayed: vec![(3, 3)], + }, + )); + assert_eq!(EvicatedValidators::get().len(), 1); + }); +} + fn assert_clapped_amount( session_index: &SessionIndex, unique_hash: &H256,