Compare commits

..

No commits in common. "decf6665dfc0eceaac76f7c3fb38e809c530a3f2" and "eb181c7f448f6f0fcba66b2b9310db1789a5908b" have entirely different histories.

3 changed files with 98 additions and 116 deletions

View File

@ -1,6 +1,6 @@
[package] [package]
name = "ghost-slow-clap" name = "ghost-slow-clap"
version = "0.3.45" version = "0.3.43"
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

View File

@ -35,11 +35,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, btree_set::BTreeSet},
prelude::*,
vec::Vec,
};
use ghost_networks::{ use ghost_networks::{
NetworkData, NetworkDataBasicHandler, NetworkDataInspectHandler, NetworkDataMutateHandler, NetworkData, NetworkDataBasicHandler, NetworkDataInspectHandler, NetworkDataMutateHandler,
@ -242,6 +238,7 @@ pub mod pallet {
#[pallet::error] #[pallet::error]
pub enum Error<T> { pub enum Error<T> {
NotEnoughClaps, NotEnoughClaps,
NotAnAuthority,
CurrentValidatorIsDisabled, CurrentValidatorIsDisabled,
AlreadyClapped, AlreadyClapped,
UnregisteredClapRemove, UnregisteredClapRemove,
@ -297,16 +294,6 @@ pub mod pallet {
ValueQuery, ValueQuery,
>; >;
#[pallet::storage]
#[pallet::getter(fn validators)]
pub(super) type Validators<T: Config> = StorageMap<
_,
Twox64Concat,
SessionIndex,
WeakBoundedVec<ValidatorId<T>, T::MaxAuthorities>,
OptionQuery,
>;
#[pallet::genesis_config] #[pallet::genesis_config]
#[derive(frame_support::DefaultNoBound)] #[derive(frame_support::DefaultNoBound)]
pub struct GenesisConfig<T: Config> { pub struct GenesisConfig<T: Config> {
@ -343,7 +330,7 @@ pub mod pallet {
pub fn self_applause( pub fn self_applause(
origin: OriginFor<T>, origin: OriginFor<T>,
network_id: NetworkIdOf<T>, network_id: NetworkIdOf<T>,
prev_session_index: SessionIndex, session_index: SessionIndex,
transaction_hash: H256, transaction_hash: H256,
receiver: T::AccountId, receiver: T::AccountId,
amount: BalanceOf<T>, amount: BalanceOf<T>,
@ -351,7 +338,7 @@ pub mod pallet {
let _ = ensure_signed(origin)?; let _ = ensure_signed(origin)?;
Self::applause_if_posible( Self::applause_if_posible(
network_id, network_id,
prev_session_index, session_index,
transaction_hash, transaction_hash,
receiver, receiver,
amount, amount,
@ -617,35 +604,29 @@ impl<T: Config> Pallet<T> {
) -> DispatchResult { ) -> DispatchResult {
let curr_session_index = prev_session_index.saturating_add(1); let curr_session_index = prev_session_index.saturating_add(1);
let clap_unique_hash = Self::generate_unique_hash(&receiver, &amount, &network_id); let clap_unique_hash = Self::generate_unique_hash(&receiver, &amount, &network_id);
let prev_received_claps_key = (prev_session_index, &transaction_hash, &clap_unique_hash);
let curr_received_claps_key = (curr_session_index, &transaction_hash, &clap_unique_hash);
let prev_authorities = Authorities::<T>::get(&prev_session_index); let prev_authorities = Authorities::<T>::get(&prev_session_index);
let curr_authorities = Authorities::<T>::get(&curr_session_index); let curr_authorities = Authorities::<T>::get(&curr_session_index);
let prev_received_claps_key = (prev_session_index, &transaction_hash, &clap_unique_hash); let prev_received_claps = ReceivedClaps::<T>::get(&prev_received_claps_key).into_inner();
let curr_received_claps_key = (curr_session_index, &transaction_hash, &clap_unique_hash); let curr_received_claps = ReceivedClaps::<T>::get(&curr_received_claps_key).into_inner();
let prev_received_claps = ReceivedClaps::<T>::get(&prev_received_claps_key)
.into_iter()
.filter_map(|auth_index| prev_authorities.get(auth_index as usize))
.cloned()
.collect::<BTreeSet<T::AuthorityId>>();
let curr_received_claps = ReceivedClaps::<T>::get(&curr_received_claps_key)
.into_iter()
.filter_map(|auth_index| curr_authorities.get(auth_index as usize))
.cloned()
.collect::<BTreeSet<T::AuthorityId>>();
let disabled_authorites = ClapsInSession::<T>::get(&prev_session_index)
.values()
.filter(|info| info.disabled)
.count();
let active_authorities = prev_authorities.len().saturating_sub(disabled_authorites);
let summary_authority_claps_length = curr_received_claps let summary_authority_claps_length = curr_received_claps
.symmetric_difference(&prev_received_claps) .difference(&prev_received_claps)
.count(); .filter_map(|&index| {
curr_authorities
.get(index as usize)
.map(|curr_authority| {
prev_authorities
.iter()
.position(|prev_authority| curr_authority == prev_authority)
})
.flatten()
})
.count()
.saturating_add(curr_received_claps.len());
let clap = Clap { let clap = Clap {
authority_index: Default::default(), authority_index: Default::default(),
@ -660,7 +641,7 @@ impl<T: Config> Pallet<T> {
let enough_authorities = Perbill::from_rational( let enough_authorities = Perbill::from_rational(
summary_authority_claps_length as u32, summary_authority_claps_length as u32,
active_authorities as u32, Authorities::<T>::get(prev_session_index).len() 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);
@ -1094,23 +1075,16 @@ impl<T: Config> Pallet<T> {
let bounded_authorities = WeakBoundedVec::<_, T::MaxAuthorities>::try_from(authorities) let bounded_authorities = WeakBoundedVec::<_, T::MaxAuthorities>::try_from(authorities)
.expect("more than the maximum number of authorities"); .expect("more than the maximum number of authorities");
let validators = T::ValidatorSet::validators();
let bounded_validators = WeakBoundedVec::<_, T::MaxAuthorities>::try_from(validators)
.expect("more than the maximum number of validators");
if let Some(target_session_index) = session_index.checked_sub(T::HistoryDepth::get()) { if let Some(target_session_index) = session_index.checked_sub(T::HistoryDepth::get()) {
Self::clear_history(&target_session_index); Self::clear_history(&target_session_index);
} }
Validators::<T>::insert(&session_index, bounded_validators);
Authorities::<T>::set(&session_index, bounded_authorities); Authorities::<T>::set(&session_index, bounded_authorities);
ClapsInSession::<T>::set(&session_index, Default::default()); ClapsInSession::<T>::set(&session_index, Default::default());
} }
fn clear_history(target_session_index: &SessionIndex) { fn clear_history(target_session_index: &SessionIndex) {
ClapsInSession::<T>::remove(target_session_index); ClapsInSession::<T>::remove(target_session_index);
Authorities::<T>::remove(target_session_index);
Validators::<T>::remove(target_session_index);
let mut cursor = ReceivedClaps::<T>::clear_prefix((target_session_index,), u32::MAX, None); let mut cursor = ReceivedClaps::<T>::clear_prefix((target_session_index,), u32::MAX, None);
debug_assert!(cursor.maybe_cursor.is_none()); debug_assert!(cursor.maybe_cursor.is_none());
cursor = cursor =
@ -1162,8 +1136,8 @@ impl<T: Config> OneSessionHandler<T::AccountId> for Pallet<T> {
} }
fn on_before_session_ending() { fn on_before_session_ending() {
let validators = T::ValidatorSet::validators();
let session_index = T::ValidatorSet::session_index().saturating_sub(1); let session_index = T::ValidatorSet::session_index().saturating_sub(1);
let validators = Validators::<T>::get(&session_index).unwrap_or_default();
let authorities_len = Authorities::<T>::get(&session_index).len(); let authorities_len = Authorities::<T>::get(&session_index).len();
let claps_in_session = ClapsInSession::<T>::get(&session_index); let claps_in_session = ClapsInSession::<T>::get(&session_index);

View File

@ -665,14 +665,15 @@ fn should_throw_error_if_session_index_is_not_current() {
network_id, network_id,
authority_prev authority_prev
)); ));
assert_err!( assert_ok!(do_clap_from_first_authority(
do_clap_from_first_authority(session_index_next, network_id, authority_next), session_index_next,
DispatchError::Other("Transaction has a bad signature") network_id,
); authority_next
));
assert_claps_info_correct(&storage_key_curr, &session_index_curr, 1); assert_claps_info_correct(&storage_key_curr, &session_index_curr, 1);
assert_claps_info_correct(&storage_key_prev, &session_index_prev, 1); assert_claps_info_correct(&storage_key_prev, &session_index_prev, 1);
assert_claps_info_correct(&storage_key_next, &session_index_next, 0); assert_claps_info_correct(&storage_key_next, &session_index_next, 1);
} }
}); });
} }
@ -687,12 +688,22 @@ fn should_throw_error_if_signer_has_incorrect_index() {
let storage_key = (session_index, transaction_hash, unique_transaction_hash); let storage_key = (session_index, transaction_hash, unique_transaction_hash);
assert_claps_info_correct(&storage_key, &session_index, 0); assert_claps_info_correct(&storage_key, &session_index, 0);
assert_invalid_signing_address(session_index, network_id, 69); let clap = Clap {
assert_transaction_has_bad_signature(session_index, network_id, 69); block_number: 420,
assert_invalid_signing_address(session_index, network_id, 420); removed: false,
assert_transaction_has_bad_signature(session_index, network_id, 420); transaction_hash,
assert_invalid_signing_address(session_index, network_id, 1337); session_index,
assert_transaction_has_bad_signature(session_index, network_id, 1337); authority_index: 1337,
network_id,
receiver: 69,
amount: 420,
};
let authority = UintAuthorityId::from((1) as u64);
let signature = authority.sign(&clap.encode()).unwrap();
assert_err!(
SlowClap::slow_clap(RuntimeOrigin::none(), clap, signature),
Error::<Runtime>::NotAnAuthority
);
assert_claps_info_correct(&storage_key, &session_index, 0); assert_claps_info_correct(&storage_key, &session_index, 0);
}); });
} }
@ -945,8 +956,8 @@ fn should_avoid_applause_during_nullification_period() {
} }
#[test] #[test]
fn should_self_applause_if_enough_claps() { fn should_self_applause_if_enough_received_claps() {
let zero = 0u64; let zero: u64 = 0u64;
let (network_id, transaction_hash, unique_transaction_hash) = let (network_id, transaction_hash, unique_transaction_hash) =
generate_unique_hash(None, None, None, None); generate_unique_hash(None, None, None, None);
let (_, receiver, amount) = get_mocked_metadata(); let (_, receiver, amount) = get_mocked_metadata();
@ -954,7 +965,6 @@ fn should_self_applause_if_enough_claps() {
new_test_ext().execute_with(|| { new_test_ext().execute_with(|| {
let _ = prepare_evm_network(Some(network_id), Some(0)); let _ = prepare_evm_network(Some(network_id), Some(0));
let session_index = advance_session_and_get_index(); let session_index = advance_session_and_get_index();
let next_session_index = session_index.saturating_add(1);
let storage_key = (session_index, transaction_hash, unique_transaction_hash); let storage_key = (session_index, transaction_hash, unique_transaction_hash);
assert_err!( assert_err!(
@ -966,7 +976,7 @@ fn should_self_applause_if_enough_claps() {
receiver, receiver,
amount, amount,
), ),
Error::<Runtime>::NotEnoughClaps, Error::<Runtime>::NotEnoughClaps
); );
assert_eq!( assert_eq!(
@ -974,34 +984,59 @@ fn should_self_applause_if_enough_claps() {
false false
); );
assert_eq!(Balances::balance(&receiver), zero); assert_eq!(Balances::balance(&receiver), zero);
assert_eq!(
BridgedInflationCurve::<RewardCurve, Runtime>::era_payout(zero, zero, zero),
(zero, zero)
);
assert_ok!(do_clap_from(session_index, network_id, 0, false)); assert_ok!(do_clap_from(session_index, network_id, 0, false));
assert_ok!(do_clap_from(session_index, network_id, 1, false));
assert_eq!(
pallet::ApplausesForTransaction::<Runtime>::get(&storage_key),
false
);
assert_eq!(Balances::balance(&receiver), 0);
assert_err!(
SlowClap::self_applause(
RuntimeOrigin::signed(receiver),
network_id,
session_index,
transaction_hash,
receiver,
amount,
),
Error::<Runtime>::NotEnoughClaps
);
assert_eq!(
pallet::ApplausesForTransaction::<Runtime>::get(&storage_key),
false
);
assert_eq!(Balances::balance(&receiver), 0);
Networks::on_finalize(System::block_number());
advance_session(); advance_session();
let next_session_index = Session::session_index();
let mut fake_claps_in_session = sp_std::collections::btree_map::BTreeMap::new(); let next_storage_key = (
fake_claps_in_session.insert( next_session_index,
1, transaction_hash,
SessionAuthorityInfo { unique_transaction_hash,
claps: 1,
disabled: false,
},
); );
fake_claps_in_session.insert( assert_ok!(do_clap_from(next_session_index, network_id, 2, false));
2,
SessionAuthorityInfo { assert_err!(
claps: 1, SlowClap::self_applause(
disabled: false, RuntimeOrigin::signed(receiver),
}, network_id,
next_session_index,
transaction_hash,
receiver,
amount,
),
Error::<Runtime>::NotEnoughClaps
); );
let mut fake_received_clap =
BoundedBTreeSet::<AuthIndex, <Runtime as pallet::Config>::MaxAuthorities>::new();
assert_eq!(fake_received_clap.try_insert(1).unwrap(), true);
assert_eq!(fake_received_clap.try_insert(2).unwrap(), true);
pallet::ReceivedClaps::<Runtime>::insert(&storage_key, fake_received_clap);
pallet::ClapsInSession::<Runtime>::insert(&next_session_index, fake_claps_in_session);
assert_ok!(SlowClap::self_applause( assert_ok!(SlowClap::self_applause(
RuntimeOrigin::signed(receiver), RuntimeOrigin::signed(receiver),
network_id, network_id,
@ -1014,37 +1049,10 @@ fn should_self_applause_if_enough_claps() {
pallet::ApplausesForTransaction::<Runtime>::get(&storage_key), pallet::ApplausesForTransaction::<Runtime>::get(&storage_key),
true true
); );
assert_eq!(Balances::balance(&receiver), amount);
});
}
#[test]
fn should_avoid_session_overlap_on_mended_session_index() {
let (network_id, transaction_hash, unique_transaction_hash) =
generate_unique_hash(None, None, None, None);
let (_, receiver, amount) = get_mocked_metadata();
new_test_ext().execute_with(|| {
let _ = prepare_evm_network(Some(network_id), Some(0));
let session_index = advance_session_and_get_index();
let storage_key = (session_index, transaction_hash, unique_transaction_hash);
assert_ok!(do_clap_from(session_index, network_id, 0, false));
advance_session();
assert_eq!( assert_eq!(
pallet::ApplausesForTransaction::<Runtime>::get(&storage_key), pallet::ApplausesForTransaction::<Runtime>::get(&next_storage_key),
false false
); );
assert_eq!(Balances::balance(&receiver), 0u64);
assert_ok!(do_clap_from(session_index, network_id, 1, false));
assert_ok!(do_clap_from(session_index, network_id, 2, false));
assert_eq!(
pallet::ApplausesForTransaction::<Runtime>::get(&storage_key),
true
);
assert_eq!(Balances::balance(&receiver), amount); assert_eq!(Balances::balance(&receiver), amount);
}); });
} }