replacing the average claps in session with median to determine a harmful authority

Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
This commit is contained in:
Uncle Stinky 2025-06-03 19:38:07 +03:00
parent 04a63e234d
commit 9cb7f3c782
Signed by: st1nky
GPG Key ID: 016064BD97603B40
2 changed files with 30 additions and 17 deletions

View File

@ -1,6 +1,6 @@
[package]
name = "ghost-slow-clap"
version = "0.3.17"
version = "0.3.18"
description = "Applause protocol for the EVM bridge"
license.workspace = true
authors.workspace = true

View File

@ -858,9 +858,9 @@ impl<T: Config> Pallet<T> {
fn is_good_actor(
authority_index: usize,
session_index: SessionIndex,
average_claps: u32,
median_claps: u32,
) -> bool {
if average_claps == 0 {
if median_claps == 0 {
return true;
}
@ -869,10 +869,10 @@ impl<T: Config> Pallet<T> {
.or_default()
.claps;
let authority_deviation = if number_of_claps < average_claps {
Perbill::from_rational(average_claps - number_of_claps, average_claps)
let authority_deviation = if number_of_claps < median_claps {
Perbill::from_rational(median_claps - number_of_claps, median_claps)
} else {
Perbill::from_rational(number_of_claps - average_claps, average_claps)
Perbill::from_rational(number_of_claps - median_claps, median_claps)
};
authority_deviation < Perbill::from_percent(T::OffenceThreshold::get())
}
@ -886,6 +886,28 @@ impl<T: Config> Pallet<T> {
}
}
fn calculate_median_claps(session_index: &SessionIndex) -> u32 {
let mut claps_in_session = ClapsInSession::<T>::get(session_index)
.values()
.filter_map(|value| (!value.disabled).then(|| value.claps))
.collect::<Vec<_>>();
if claps_in_session.is_empty() {
return 0;
}
claps_in_session.sort();
let number_of_claps = claps_in_session.len();
if number_of_claps % 2 == 0 {
let mid_left = claps_in_session[number_of_claps / 2 - 1];
let mid_right = claps_in_session[number_of_claps / 2];
(mid_left + mid_right) / 2
} else {
claps_in_session[number_of_claps / 2]
}
}
#[cfg(test)]
fn set_test_authorities(authorities: Vec<T::AuthorityId>) {
let bounded_authorities = WeakBoundedVec::<_, T::MaxAuthorities>::try_from(authorities)
@ -931,21 +953,12 @@ impl<T: Config> OneSessionHandler<T::AccountId> for Pallet<T> {
let validators = T::ValidatorSet::validators();
let authorities = Authorities::<T>::get();
let (sum_claps, total_claps) = ClapsInSession::<T>::get(&session_index)
.iter()
.filter(|(_, value)| !value.disabled)
.fold((0u32, 0u32), |(sum, total), (_, value)|
(sum.saturating_add(value.claps), total.saturating_add(1))
);
let average_claps = sum_claps
.checked_div(total_claps)
.unwrap_or_default();
let median_claps = Self::calculate_median_claps(&session_index);
let offenders = validators
.into_iter()
.enumerate()
.filter(|(index, _)| !Self::is_good_actor(*index, session_index, average_claps))
.filter(|(index, _)| !Self::is_good_actor(*index, session_index, median_claps))
.filter_map(|(_, id)| {
<T::ValidatorSet as ValidatorSetWithIdentification<T::AccountId>>::IdentificationOf::convert(
id.clone(),