Compare commits

..

8 Commits

Author SHA1 Message Date
da271a6f22
cargo clean only if the compiler version is downgraded
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2025-07-31 16:35:07 +03:00
b9b7d84466
update ghost-node and specification to the latest version
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2025-07-31 16:32:44 +03:00
8ff588cce9
remove spoiled rpc endpoint from the genesis file
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2025-07-31 16:18:47 +03:00
298a332681
make staking rewards dependant on bridged amount
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2025-07-31 16:17:10 +03:00
1c4c517728
avoiding back in time travel
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2025-07-31 15:30:28 +03:00
b969081cbf
make sure that disabled validator will not be checked with is_good_actor
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2025-07-31 14:21:55 +03:00
9bdb7b5d5c
add an early check for the disabled validator
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2025-07-31 14:02:14 +03:00
c4b16805f7
fix calculation of median, include special case when there're no claps
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2025-07-31 13:56:05 +03:00
10 changed files with 217 additions and 59 deletions

16
Cargo.lock generated
View File

@ -1186,7 +1186,7 @@ dependencies = [
[[package]] [[package]]
name = "casper-runtime" name = "casper-runtime"
version = "3.5.29" version = "3.5.30"
dependencies = [ dependencies = [
"casper-runtime-constants", "casper-runtime-constants",
"frame-benchmarking", "frame-benchmarking",
@ -3529,7 +3529,7 @@ dependencies = [
[[package]] [[package]]
name = "ghost-cli" name = "ghost-cli"
version = "0.8.0" version = "0.8.1"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"clap 4.5.4", "clap 4.5.4",
@ -3585,7 +3585,7 @@ dependencies = [
[[package]] [[package]]
name = "ghost-machine-primitives" name = "ghost-machine-primitives"
version = "0.8.0" version = "0.8.1"
dependencies = [ dependencies = [
"lazy_static", "lazy_static",
"sc-sysinfo", "sc-sysinfo",
@ -3594,7 +3594,7 @@ dependencies = [
[[package]] [[package]]
name = "ghost-metrics" name = "ghost-metrics"
version = "0.8.0" version = "0.8.1"
dependencies = [ dependencies = [
"assert_cmd", "assert_cmd",
"bs58 0.5.1", "bs58 0.5.1",
@ -3668,7 +3668,7 @@ dependencies = [
[[package]] [[package]]
name = "ghost-node" name = "ghost-node"
version = "0.8.0" version = "0.8.1"
dependencies = [ dependencies = [
"assert_cmd", "assert_cmd",
"color-eyre", "color-eyre",
@ -3699,7 +3699,7 @@ dependencies = [
[[package]] [[package]]
name = "ghost-rpc" name = "ghost-rpc"
version = "0.8.0" version = "0.8.1"
dependencies = [ dependencies = [
"ghost-core-primitives", "ghost-core-primitives",
"jsonrpsee", "jsonrpsee",
@ -3751,7 +3751,7 @@ dependencies = [
[[package]] [[package]]
name = "ghost-service" name = "ghost-service"
version = "0.8.0" version = "0.8.1"
dependencies = [ dependencies = [
"assert_matches", "assert_matches",
"async-trait", "async-trait",
@ -3835,7 +3835,7 @@ dependencies = [
[[package]] [[package]]
name = "ghost-slow-clap" name = "ghost-slow-clap"
version = "0.3.35" version = "0.3.39"
dependencies = [ dependencies = [
"frame-benchmarking", "frame-benchmarking",
"frame-support", "frame-support",

View File

@ -17,7 +17,7 @@ homepage.workspace = true
[workspace.package] [workspace.package]
license = "GPL-3.0-only" license = "GPL-3.0-only"
authors = ["571nky", "57r37ch", "f4750"] authors = ["571nky", "57r37ch", "f4750"]
version = "0.8.0" version = "0.8.1"
edition = "2021" edition = "2021"
homepage = "https://ghostchain.io" homepage = "https://ghostchain.io"
repository = "https://git.ghostchain.io/ghostchain/ghost-node" repository = "https://git.ghostchain.io/ghostchain/ghost-node"

View File

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

@ -90,7 +90,7 @@ pub struct Clap<AccountId, NetworkId, Balance> {
pub amount: Balance, pub amount: Balance,
} }
#[derive(Default, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)] #[derive(Default, Clone, Copy, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)]
pub struct SessionAuthorityInfo { pub struct SessionAuthorityInfo {
pub claps: u32, pub claps: u32,
pub disabled: bool, pub disabled: bool,
@ -465,6 +465,13 @@ impl<T: Config> Pallet<T> {
authorities.get(clap.authority_index as usize).is_some(), authorities.get(clap.authority_index as usize).is_some(),
Error::<T>::NotAnAuthority Error::<T>::NotAnAuthority
); );
ensure!(
ClapsInSession::<T>::get(&clap.session_index)
.get(&clap.authority_index)
.map(|info| !info.disabled)
.unwrap_or(true),
Error::<T>::CurrentValidatorIsDisabled
);
let clap_unique_hash = let clap_unique_hash =
Self::generate_unique_hash(&clap.receiver, &clap.amount, &clap.network_id); Self::generate_unique_hash(&clap.receiver, &clap.amount, &clap.network_id);
@ -491,15 +498,7 @@ impl<T: Config> Pallet<T> {
} }
})?; })?;
ClapsInSession::<T>::try_mutate(&clap.session_index, |claps_details| { ClapsInSession::<T>::mutate(&clap.session_index, |claps_details| {
if claps_details
.get(&clap.authority_index)
.map(|x| x.disabled)
.unwrap_or_default()
{
return Err(Error::<T>::CurrentValidatorIsDisabled);
}
(*claps_details) (*claps_details)
.entry(clap.authority_index) .entry(clap.authority_index)
.and_modify(|individual| (*individual).claps.saturating_inc()) .and_modify(|individual| (*individual).claps.saturating_inc())
@ -507,9 +506,7 @@ impl<T: Config> Pallet<T> {
claps: 1u32, claps: 1u32,
disabled: false, disabled: false,
}); });
});
Ok(())
})?;
Self::deposit_event(Event::<T>::Clapped { Self::deposit_event(Event::<T>::Clapped {
authority_id: clap.authority_index, authority_id: clap.authority_index,
@ -766,23 +763,20 @@ impl<T: Config> Pallet<T> {
Ok(match maybe_block_range { Ok(match maybe_block_range {
Some((from_block, to_block)) => match maybe_new_evm_block { Some((from_block, to_block)) => match maybe_new_evm_block {
Some(_) => { Some(_) if from_block.le(&to_block) => {
match estimated_block.checked_sub(from_block) { let adjusted_to_block = estimated_block
Some(current_distance) .checked_sub(from_block)
if current_distance .map(|current_distance| current_distance
< max_block_distance => .le(&max_block_distance)
{ .then(|| estimated_block)
(from_block, estimated_block) )
} .flatten()
_ => ( .unwrap_or(from_block
from_block, .saturating_add(max_block_distance)
from_block .min(estimated_block));
.saturating_add(max_block_distance) (from_block, adjusted_to_block)
.min(estimated_block),
),
}
} }
None => (to_block, to_block), _ => (to_block, to_block),
}, },
None => (estimated_block, estimated_block), None => (estimated_block, estimated_block),
}) })
@ -967,10 +961,18 @@ impl<T: Config> Pallet<T> {
.ok_or(OffchainErr::ErrorInEvmResponse)?) .ok_or(OffchainErr::ErrorInEvmResponse)?)
} }
fn calculate_median_claps(session_index: &SessionIndex) -> u32 { fn calculate_median_claps(
let mut claps_in_session = ClapsInSession::<T>::get(session_index) actual_claps_in_session: &BTreeMap<AuthIndex, SessionAuthorityInfo>,
.values() authorities_len: usize,
.filter_map(|value| (!value.disabled).then(|| value.claps)) ) -> u32 {
let mut claps_in_session = (0..authorities_len)
.filter_map(|authority_index| {
let clap_info = actual_claps_in_session
.get(&(authority_index as AuthIndex))
.copied()
.unwrap_or_default();
(!clap_info.disabled).then(|| clap_info.claps)
})
.collect::<Vec<_>>(); .collect::<Vec<_>>();
if claps_in_session.is_empty() { if claps_in_session.is_empty() {
@ -991,17 +993,21 @@ impl<T: Config> Pallet<T> {
fn is_good_actor( fn is_good_actor(
authority_index: usize, authority_index: usize,
session_index: SessionIndex,
median_claps: u32, median_claps: u32,
claps_in_session: &BTreeMap<AuthIndex, SessionAuthorityInfo>,
) -> bool { ) -> bool {
if median_claps == 0 { if median_claps == 0 {
return true; return true;
} }
let number_of_claps = ClapsInSession::<T>::get(session_index) let number_of_claps = claps_in_session
.entry(authority_index as AuthIndex) .get(&(authority_index as AuthIndex))
.or_default() .copied()
.claps; .map(|info| match info.disabled {
true => median_claps,
false => info.claps,
})
.unwrap_or_default();
let authority_deviation = if number_of_claps < median_claps { let authority_deviation = if number_of_claps < median_claps {
Perbill::from_rational(median_claps - number_of_claps, median_claps) Perbill::from_rational(median_claps - number_of_claps, median_claps)
@ -1083,14 +1089,15 @@ impl<T: Config> OneSessionHandler<T::AccountId> for Pallet<T> {
fn on_before_session_ending() { fn on_before_session_ending() {
let session_index = T::ValidatorSet::session_index(); let session_index = T::ValidatorSet::session_index();
let validators = T::ValidatorSet::validators(); let validators = T::ValidatorSet::validators();
let authorities = Authorities::<T>::get(&session_index); let authorities_len = Authorities::<T>::get(&session_index).len();
let claps_in_session = ClapsInSession::<T>::get(&session_index);
let median_claps = Self::calculate_median_claps(&session_index); let median_claps = Self::calculate_median_claps(&claps_in_session, authorities_len);
let offenders = validators let offenders = validators
.into_iter() .into_iter()
.enumerate() .enumerate()
.filter(|(index, _)| !Self::is_good_actor(*index, session_index, median_claps)) .filter(|(index, _)| !Self::is_good_actor(*index, median_claps, &claps_in_session))
.filter_map(|(_, id)| { .filter_map(|(_, id)| {
<T::ValidatorSet as ValidatorSetWithIdentification<T::AccountId>>::IdentificationOf::convert( <T::ValidatorSet as ValidatorSetWithIdentification<T::AccountId>>::IdentificationOf::convert(
id.clone(), id.clone(),
@ -1105,7 +1112,7 @@ impl<T: Config> OneSessionHandler<T::AccountId> for Pallet<T> {
throttling: offenders.clone(), throttling: offenders.clone(),
}); });
let validator_set_count = authorities.len() as u32; let validator_set_count = authorities_len as u32;
let offence = ThrottlingOffence { let offence = ThrottlingOffence {
session_index, session_index,
validator_set_count, validator_set_count,

View File

@ -119,6 +119,157 @@ fn test_throttling_slash_function() {
); );
} }
#[test]
fn test_median_calculations_are_correct() {
new_test_ext().execute_with(|| {
let data = BTreeMap::from([
(
0u32,
SessionAuthorityInfo {
claps: 0,
disabled: true,
},
),
(
3u32,
SessionAuthorityInfo {
claps: 1,
disabled: false,
},
),
]);
assert_eq!(SlowClap::calculate_median_claps(&data, 4), 0);
let data = BTreeMap::from([
(
0u32,
SessionAuthorityInfo {
claps: 0,
disabled: false,
},
),
(
1u32,
SessionAuthorityInfo {
claps: 69,
disabled: false,
},
),
(
2u32,
SessionAuthorityInfo {
claps: 69,
disabled: false,
},
),
(
3u32,
SessionAuthorityInfo {
claps: 420,
disabled: false,
},
),
]);
assert_eq!(SlowClap::calculate_median_claps(&data, 4), 69);
let data = BTreeMap::from([
(
0u32,
SessionAuthorityInfo {
claps: 31,
disabled: false,
},
),
(
1u32,
SessionAuthorityInfo {
claps: 420,
disabled: true,
},
),
(
2u32,
SessionAuthorityInfo {
claps: 69,
disabled: false,
},
),
(
3u32,
SessionAuthorityInfo {
claps: 156,
disabled: true,
},
),
]);
assert_eq!(SlowClap::calculate_median_claps(&data, 4), 50);
let data = BTreeMap::from([
(
0u32,
SessionAuthorityInfo {
claps: 0,
disabled: true,
},
),
(
1u32,
SessionAuthorityInfo {
claps: 420,
disabled: false,
},
),
(
2u32,
SessionAuthorityInfo {
claps: 0,
disabled: true,
},
),
(
3u32,
SessionAuthorityInfo {
claps: 0,
disabled: false,
},
),
]);
assert_eq!(SlowClap::calculate_median_claps(&data, 4), 210);
let data = BTreeMap::from([
(
0u32,
SessionAuthorityInfo {
claps: 0,
disabled: false,
},
),
(
1u32,
SessionAuthorityInfo {
claps: 420,
disabled: true,
},
),
(
2u32,
SessionAuthorityInfo {
claps: 69,
disabled: true,
},
),
(
3u32,
SessionAuthorityInfo {
claps: 0,
disabled: false,
},
),
]);
assert_eq!(SlowClap::calculate_median_claps(&data, 4), 0);
});
}
#[test] #[test]
fn request_body_is_correct_for_get_block_number() { fn request_body_is_correct_for_get_block_number() {
let (offchain, _) = TestOffchainExt::new(); let (offchain, _) = TestOffchainExt::new();

View File

@ -1,6 +1,6 @@
[package] [package]
name = "casper-runtime" name = "casper-runtime"
version = "3.5.29" version = "3.5.30"
build = "build.rs" build = "build.rs"
description = "Runtime of the Casper Network" description = "Runtime of the Casper Network"
edition.workspace = true edition.workspace = true

View File

@ -505,7 +505,7 @@ impl pallet_staking::Config for Runtime {
type SlashDeferDuration = SlashDeferDuration; type SlashDeferDuration = SlashDeferDuration;
type AdminOrigin = EitherOf<EnsureRootWithSuccess<Self::AccountId, ConstU16<65535>>, Skeletons>; type AdminOrigin = EitherOf<EnsureRootWithSuccess<Self::AccountId, ConstU16<65535>>, Skeletons>;
type SessionInterface = Self; type SessionInterface = Self;
type EraPayout = pallet_staking::ConvertCurve<RewardCurve>; type EraPayout = ghost_networks::BridgedInflationCurve<RewardCurve, Self>;
type MaxExposurePageSize = MaxExposurePageSize; type MaxExposurePageSize = MaxExposurePageSize;
type DisablingStrategy = pallet_staking::UpToLimitDisablingStrategy; type DisablingStrategy = pallet_staking::UpToLimitDisablingStrategy;
type NextNewSession = Session; type NextNewSession = Session;

View File

@ -98,6 +98,9 @@ downgrade_compiler_if_needed() {
toolchain_name=$(rustup show | grep default | head -n 1 | cut -d' ' -f1) toolchain_name=$(rustup show | grep default | head -n 1 | cut -d' ' -f1)
rustup target add wasm32-unknown-unknown --toolchain $toolchain_name rustup target add wasm32-unknown-unknown --toolchain $toolchain_name
rustup component add rust-src --toolchain $toolchain_name rustup component add rust-src --toolchain $toolchain_name
cd $PROJECT_FOLDER
echo "[+] clean build cache..."
cargo clean
else else
echo "[+] rustc compiler version is compatible" echo "[+] rustc compiler version is compatible"
fi fi
@ -226,8 +229,6 @@ if [[ $HARD_RESET = true ]]; then
sudo rm -rf "$BASE_PATH/chains/casper_staging_testnet" sudo rm -rf "$BASE_PATH/chains/casper_staging_testnet"
cd $PROJECT_FOLDER cd $PROJECT_FOLDER
echo "[+] clean build cache..."
cargo clean
echo "[+] starting build in 3 seconds..." echo "[+] starting build in 3 seconds..."
sleep 3 sleep 3
cargo build --release cargo build --release

File diff suppressed because one or more lines are too long

View File

@ -198,7 +198,6 @@ fn casper_testnet_evm_networks() -> Vec<(u32, Vec<u8>)> {
"https://api.zan.top/eth-sepolia".into(), "https://api.zan.top/eth-sepolia".into(),
"https://rpc.sepolia.ethpandaops.io".into(), "https://rpc.sepolia.ethpandaops.io".into(),
"https://ethereum-sepolia-rpc.publicnode.com".into(), "https://ethereum-sepolia-rpc.publicnode.com".into(),
"https://rpc-sepolia.rockx.com".into(),
"https://1rpc.io/sepolia".into(), "https://1rpc.io/sepolia".into(),
"https://0xrpc.io/sep".into(), "https://0xrpc.io/sep".into(),
"https://eth-sepolia.api.onfinality.io/public".into(), "https://eth-sepolia.api.onfinality.io/public".into(),