Compare commits

...

5 Commits

Author SHA1 Message Date
1196cc9faa
changes to runtime based on the new version of ghost-slow claps
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2025-06-17 13:54:32 +03:00
66fa8409fa
additional tests for the pallet
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2025-06-17 13:50:38 +03:00
5beb22f116
avoid errors from minting sub-existential balance
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2025-06-13 16:42:14 +03:00
7be24ed139
use latest version of ghost-networks
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
2025-06-13 16:22:21 +03:00
b5fc86aa9e
separate bridged imbalance and gatekeeper amount. requested by @st1nky for ghost-slow-clap
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
2025-06-13 16:16:01 +03:00
11 changed files with 190 additions and 111 deletions

8
Cargo.lock generated
View File

@ -1186,7 +1186,7 @@ dependencies = [
[[package]] [[package]]
name = "casper-runtime" name = "casper-runtime"
version = "3.5.20" version = "3.5.21"
dependencies = [ dependencies = [
"casper-runtime-constants", "casper-runtime-constants",
"frame-benchmarking", "frame-benchmarking",
@ -3648,7 +3648,7 @@ dependencies = [
[[package]] [[package]]
name = "ghost-networks" name = "ghost-networks"
version = "0.1.5" version = "0.1.6"
dependencies = [ dependencies = [
"frame-benchmarking", "frame-benchmarking",
"frame-support", "frame-support",
@ -3834,7 +3834,7 @@ dependencies = [
[[package]] [[package]]
name = "ghost-slow-clap" name = "ghost-slow-clap"
version = "0.3.23" version = "0.3.24"
dependencies = [ dependencies = [
"frame-benchmarking", "frame-benchmarking",
"frame-support", "frame-support",
@ -3870,7 +3870,7 @@ dependencies = [
[[package]] [[package]]
name = "ghost-traits" name = "ghost-traits"
version = "0.3.21" version = "0.3.22"
dependencies = [ dependencies = [
"frame-support", "frame-support",
"sp-runtime 31.0.1", "sp-runtime 31.0.1",

View File

@ -1,6 +1,6 @@
[package] [package]
name = "ghost-networks" name = "ghost-networks"
version = "0.1.5" version = "0.1.6"
license.workspace = true license.workspace = true
authors.workspace = true authors.workspace = true
edition.workspace = true edition.workspace = true

View File

@ -631,17 +631,7 @@ impl<T: Config> NetworkDataMutateHandler<NetworkData, BalanceOf<T>> for Pallet<T
fn increase_gatekeeper_amount( fn increase_gatekeeper_amount(
network_id: &T::NetworkId, network_id: &T::NetworkId,
amount: &BalanceOf<T>, amount: &BalanceOf<T>,
) -> Result<(BalanceOf<T>, BalanceOf<T>), ()> { ) -> Result<BalanceOf<T>, ()> {
let new_bridged_in_amount = BridgedImbalance::<T>::mutate(|bridged_imbalance| {
match bridged_imbalance.bridged_in.checked_add(amount) {
Some(value) => {
(*bridged_imbalance).bridged_in = value;
Ok(value)
},
None => Err(())
}
})?;
let new_gatekeeper_amount = GatekeeperAmount::<T>::mutate(network_id, |gatekeeper_amount| { let new_gatekeeper_amount = GatekeeperAmount::<T>::mutate(network_id, |gatekeeper_amount| {
match gatekeeper_amount.checked_add(amount) { match gatekeeper_amount.checked_add(amount) {
Some(value) => { Some(value) => {
@ -652,13 +642,13 @@ impl<T: Config> NetworkDataMutateHandler<NetworkData, BalanceOf<T>> for Pallet<T
} }
})?; })?;
Ok((new_gatekeeper_amount, new_bridged_in_amount)) Ok(new_gatekeeper_amount)
} }
fn decrease_gatekeeper_amount( fn decrease_gatekeeper_amount(
network_id: &T::NetworkId, network_id: &T::NetworkId,
amount: &BalanceOf<T>, amount: &BalanceOf<T>,
) -> Result<(BalanceOf<T>, BalanceOf<T>), ()> { ) -> Result<BalanceOf<T>, ()> {
let new_gatekeeper_amount = GatekeeperAmount::<T>::mutate(network_id, |gatekeeper_amount| { let new_gatekeeper_amount = GatekeeperAmount::<T>::mutate(network_id, |gatekeeper_amount| {
match gatekeeper_amount.checked_sub(amount) { match gatekeeper_amount.checked_sub(amount) {
Some(value) => { Some(value) => {
@ -669,6 +659,10 @@ impl<T: Config> NetworkDataMutateHandler<NetworkData, BalanceOf<T>> for Pallet<T
} }
})?; })?;
Ok(new_gatekeeper_amount)
}
fn accumulate_outgoing_imbalance(amount: &BalanceOf<T>) -> Result<BalanceOf<T>, ()> {
let new_bridged_out_amount = BridgedImbalance::<T>::mutate(|bridged_imbalance| { let new_bridged_out_amount = BridgedImbalance::<T>::mutate(|bridged_imbalance| {
match bridged_imbalance.bridged_out.checked_add(amount) { match bridged_imbalance.bridged_out.checked_add(amount) {
Some(value) => { Some(value) => {
@ -679,7 +673,21 @@ impl<T: Config> NetworkDataMutateHandler<NetworkData, BalanceOf<T>> for Pallet<T
} }
})?; })?;
Ok((new_gatekeeper_amount, new_bridged_out_amount)) Ok(new_bridged_out_amount)
}
fn accumulate_incoming_imbalance(amount: &BalanceOf<T>) -> Result<BalanceOf<T>, ()> {
let new_bridged_in_amount = BridgedImbalance::<T>::mutate(|bridged_imbalance| {
match bridged_imbalance.bridged_in.checked_add(amount) {
Some(value) => {
(*bridged_imbalance).bridged_in = value;
Ok(value)
},
None => Err(())
}
})?;
Ok(new_bridged_in_amount)
} }
fn accumulate_commission(commission: &BalanceOf<T>) -> Result<BalanceOf<T>, ()> { fn accumulate_commission(commission: &BalanceOf<T>) -> Result<BalanceOf<T>, ()> {

View File

@ -656,8 +656,6 @@ fn gatekeeper_amount_changes_correctly() {
let result = amount_in - 3 * amount_out; let result = amount_in - 3 * amount_out;
assert_eq!(GatekeeperAmount::<Test>::get(&chain_id), 0); assert_eq!(GatekeeperAmount::<Test>::get(&chain_id), 0);
assert_eq!(BridgedImbalance::<Test>::get(),
BridgeAdjustment::default());
assert_ok!(GhostNetworks::increase_gatekeeper_amount(&chain_id, &amount_in)); assert_ok!(GhostNetworks::increase_gatekeeper_amount(&chain_id, &amount_in));
assert_ok!(GhostNetworks::decrease_gatekeeper_amount(&chain_id, &amount_out)); assert_ok!(GhostNetworks::decrease_gatekeeper_amount(&chain_id, &amount_out));
@ -665,9 +663,26 @@ fn gatekeeper_amount_changes_correctly() {
assert_ok!(GhostNetworks::decrease_gatekeeper_amount(&chain_id, &amount_out)); assert_ok!(GhostNetworks::decrease_gatekeeper_amount(&chain_id, &amount_out));
assert_eq!(GatekeeperAmount::<Test>::get(&chain_id), result); assert_eq!(GatekeeperAmount::<Test>::get(&chain_id), result);
assert_eq!(BridgedImbalance::<Test>::get(), BridgeAdjustment { });
bridged_out: 3 * amount_out, }
bridged_in: amount_in });
#[test]
fn bridged_imbalance_accumulated_correctly() {
ExtBuilder::build()
.execute_with(|| {
let amount_in: u128 = 420;
let amount_out: u128 = 69;
let imbalance_before = BridgedImbalance::<Test>::get();
assert_eq!(imbalance_before.bridged_in, 0);
assert_eq!(imbalance_before.bridged_out, 0);
assert_ok!(GhostNetworks::accumulate_incoming_imbalance(&amount_in));
assert_ok!(GhostNetworks::accumulate_outgoing_imbalance(&amount_out));
let imbalance_after = BridgedImbalance::<Test>::get();
assert_eq!(imbalance_after.bridged_in, amount_in);
assert_eq!(imbalance_after.bridged_out, amount_out);
}); });
} }
@ -708,7 +723,7 @@ fn gatekeeper_amount_overflow_and_underflow_emits_error() {
assert_ok!(GhostNetworks::increase_gatekeeper_amount( assert_ok!(GhostNetworks::increase_gatekeeper_amount(
&chain_id, &chain_id,
&commission, &commission,
), (commission, commission)); ), commission);
assert_err!(GhostNetworks::increase_gatekeeper_amount( assert_err!(GhostNetworks::increase_gatekeeper_amount(
&chain_id, &chain_id,
&commission, &commission,
@ -717,16 +732,33 @@ fn gatekeeper_amount_overflow_and_underflow_emits_error() {
assert_ok!(GhostNetworks::decrease_gatekeeper_amount( assert_ok!(GhostNetworks::decrease_gatekeeper_amount(
&chain_id, &chain_id,
&commission, &commission,
), (0, commission)); ), 0);
assert_err!(GhostNetworks::decrease_gatekeeper_amount( assert_err!(GhostNetworks::decrease_gatekeeper_amount(
&chain_id, &chain_id,
&commission, &commission,
), ()); ), ());
assert_eq!(GatekeeperAmount::<Test>::get(&chain_id), 0); assert_eq!(GatekeeperAmount::<Test>::get(&chain_id), 0);
assert_eq!(BridgedImbalance::<Test>::get(), BridgeAdjustment {
bridged_out: commission,
bridged_in: commission,
}); });
}
#[test]
fn bridged_imbalance_overflow_emits_error() {
ExtBuilder::build()
.execute_with(|| {
let chain_id: u32 = 1;
let amount: u128 = u128::MAX - 69;
assert_eq!(GatekeeperAmount::<Test>::get(&chain_id), 0);
assert_ok!(GhostNetworks::accumulate_outgoing_imbalance(&amount), amount);
assert_ok!(GhostNetworks::accumulate_incoming_imbalance(&amount), amount);
assert_err!(GhostNetworks::accumulate_outgoing_imbalance(&amount), ());
assert_err!(GhostNetworks::accumulate_incoming_imbalance(&amount), ());
assert_err!(GhostNetworks::accumulate_outgoing_imbalance(&u128::MAX), ());
assert_err!(GhostNetworks::accumulate_incoming_imbalance(&u128::MAX), ());
let bridged_imbalance = BridgedImbalance::<Test>::get();
assert_eq!(bridged_imbalance.bridged_out, amount);
assert_eq!(bridged_imbalance.bridged_in, amount);
}); });
} }
@ -737,18 +769,16 @@ fn bridged_amount_overflow_and_underflow_emits_error() {
let chain_id_first: u32 = 1; let chain_id_first: u32 = 1;
let chain_id_second: u32 = 2; let chain_id_second: u32 = 2;
let commission: u128 = u128::MAX - 69; let commission: u128 = u128::MAX - 69;
assert_eq!(BridgedImbalance::<Test>::get(), BridgeAdjustment {
bridged_out: 0,
bridged_in: 0,
});
assert_ok!(GhostNetworks::increase_gatekeeper_amount( assert_ok!(GhostNetworks::increase_gatekeeper_amount(
&chain_id_first, &chain_id_first,
&commission, &commission,
), (commission, commission)); ), commission);
assert_err!(GhostNetworks::increase_gatekeeper_amount( assert_ok!(GhostNetworks::increase_gatekeeper_amount(
&chain_id_second, &chain_id_second,
&commission, &commission,
), ()); ), commission);
assert_err!(GhostNetworks::increase_gatekeeper_amount( assert_err!(GhostNetworks::increase_gatekeeper_amount(
&chain_id_first, &chain_id_first,
&u128::MAX, &u128::MAX,
@ -757,12 +787,18 @@ fn bridged_amount_overflow_and_underflow_emits_error() {
&chain_id_first, &chain_id_first,
&commission, &commission,
), ()); ), ());
assert_eq!(GatekeeperAmount::<Test>::get(&chain_id_first), commission);
assert_eq!(GatekeeperAmount::<Test>::get(&chain_id_second), 0);
assert_err!(GhostNetworks::decrease_gatekeeper_amount( assert_err!(GhostNetworks::decrease_gatekeeper_amount(
&chain_id_second, &chain_id_second,
&commission, &u128::MAX,
), ()); ), ());
assert_ok!(GhostNetworks::decrease_gatekeeper_amount(
&chain_id_second,
&commission,
), 0);
assert_eq!(GatekeeperAmount::<Test>::get(&chain_id_first), commission);
assert_eq!(GatekeeperAmount::<Test>::get(&chain_id_second), 0);
}); });
} }
@ -791,7 +827,6 @@ fn accumulated_commission_could_be_nullified() {
fn bridged_inlation_reward_works() { fn bridged_inlation_reward_works() {
ExtBuilder::build() ExtBuilder::build()
.execute_with(|| { .execute_with(|| {
let chain_id: u32 = 1;
let amount: u128 = 1337 * 1_000_000_000; let amount: u128 = 1337 * 1_000_000_000;
let commission: u128 = amount / 100; // 1% commission let commission: u128 = amount / 100; // 1% commission
let total_staked_ideal: u128 = 69; let total_staked_ideal: u128 = 69;
@ -832,7 +867,7 @@ fn bridged_inlation_reward_works() {
1, total_issuance * 1_000_000_000_000_000_000_000_000, 0), (0, 0)); 1, total_issuance * 1_000_000_000_000_000_000_000_000, 0), (0, 0));
assert_ok!(GhostNetworks::accumulate_commission(&commission)); assert_ok!(GhostNetworks::accumulate_commission(&commission));
assert_ok!(GhostNetworks::increase_gatekeeper_amount(&chain_id, &amount)); assert_ok!(GhostNetworks::accumulate_incoming_imbalance(&amount));
assert_eq!(BridgedInflationCurve::<RewardCurve, Test>::era_payout( assert_eq!(BridgedInflationCurve::<RewardCurve, Test>::era_payout(
total_staked_ideal * 1_000, total_staked_ideal * 1_000,
@ -917,14 +952,13 @@ fn bridged_inlation_reward_works() {
fn bridged_inflation_era_payout_triggers_need_of_nullification() { fn bridged_inflation_era_payout_triggers_need_of_nullification() {
ExtBuilder::build() ExtBuilder::build()
.execute_with(|| { .execute_with(|| {
let chain_id: u32 = 1;
let amount: u128 = 1337 * 1_000_000_000; let amount: u128 = 1337 * 1_000_000_000;
let commission: u128 = amount / 100; // 1% commission let commission: u128 = amount / 100; // 1% commission
let total_staked_ideal: u128 = 69; let total_staked_ideal: u128 = 69;
let total_issuance: u128 = 100; let total_issuance: u128 = 100;
assert_ok!(GhostNetworks::accumulate_commission(&commission)); assert_ok!(GhostNetworks::accumulate_commission(&commission));
assert_ok!(GhostNetworks::increase_gatekeeper_amount(&chain_id, &amount)); assert_ok!(GhostNetworks::accumulate_incoming_imbalance(&amount));
assert_eq!(NullifyNeeded::<Test>::get(), false); assert_eq!(NullifyNeeded::<Test>::get(), false);
assert_eq!(BridgedInflationCurve::<RewardCurve, Test>::era_payout( assert_eq!(BridgedInflationCurve::<RewardCurve, Test>::era_payout(
total_staked_ideal * 1_000, total_staked_ideal * 1_000,

View File

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

@ -28,7 +28,7 @@ use sp_runtime::{
self as rt_offchain, HttpError, self as rt_offchain, HttpError,
storage::{MutateStorageError, StorageRetrievalError, StorageValueRef}, storage::{MutateStorageError, StorageRetrievalError, StorageValueRef},
}, },
traits::{CheckedSub, BlockNumberProvider, Convert, Saturating}, traits::{BlockNumberProvider, Convert, Saturating},
}; };
use sp_std::{ use sp_std::{
vec::Vec, prelude::*, vec::Vec, prelude::*,
@ -330,6 +330,7 @@ pub mod pallet {
UnregisteredClapRemove, UnregisteredClapRemove,
TooMuchAuthorities, TooMuchAuthorities,
CouldNotAccumulateCommission, CouldNotAccumulateCommission,
CouldNotAccumulateIncomingImbalance,
CouldNotIncreaseGatekeeperAmount, CouldNotIncreaseGatekeeperAmount,
} }
@ -487,7 +488,7 @@ pub mod pallet {
ValidTransaction::with_tag_prefix("SlowClap") ValidTransaction::with_tag_prefix("SlowClap")
.priority(T::UnsignedPriority::get()) .priority(T::UnsignedPriority::get())
.and_provides(authority) .and_provides(signature)
.longevity(LOCK_BLOCK_EXPIRATION) .longevity(LOCK_BLOCK_EXPIRATION)
.propagate(true) .propagate(true)
.build() .build()
@ -580,25 +581,21 @@ impl<T: Config> Pallet<T> {
.map(|network_data| Perbill::from_parts(network_data.incoming_fee)) .map(|network_data| Perbill::from_parts(network_data.incoming_fee))
.unwrap_or_default() .unwrap_or_default()
.mul_ceil(clap.amount); .mul_ceil(clap.amount);
let final_amount = clap.amount.saturating_sub(commission);
let final_amount = clap.amount let _ = T::NetworkDataHandler::increase_gatekeeper_amount(&clap.network_id, &clap.amount)
.checked_sub(&commission)
.map(|value| T::Currency::minimum_balance()
.lt(&value)
.then(|| value)
)
.flatten()
.unwrap_or_default();
let _ = T::NetworkDataHandler::increase_gatekeeper_amount(&clap.network_id, &final_amount)
.map_err(|_| Error::<T>::CouldNotIncreaseGatekeeperAmount)?; .map_err(|_| Error::<T>::CouldNotIncreaseGatekeeperAmount)?;
let _ = T::NetworkDataHandler::accumulate_incoming_imbalance(&final_amount)
.map_err(|_| Error::<T>::CouldNotAccumulateIncomingImbalance)?;
let _ = T::NetworkDataHandler::accumulate_commission(&commission) let _ = T::NetworkDataHandler::accumulate_commission(&commission)
.map_err(|_| Error::<T>::CouldNotAccumulateCommission)?; .map_err(|_| Error::<T>::CouldNotAccumulateCommission)?;
if final_amount > T::Currency::minimum_balance() {
T::Currency::mint_into( T::Currency::mint_into(
&clap.receiver, &clap.receiver,
final_amount final_amount
)?; )?;
}
*is_applaused = true; *is_applaused = true;
@ -715,7 +712,7 @@ impl<T: Config> Pallet<T> {
Ok(match maybe_block_range { Ok(match maybe_block_range {
Some((from_block, to_block)) => match new_evm_block { Some((from_block, to_block)) => match new_evm_block {
0 => (to_block, new_evm_block), 0 => (to_block, to_block),
_ => (from_block, estimated_block), _ => (from_block, estimated_block),
}, },
None => (estimated_block, estimated_block), None => (estimated_block, estimated_block),
@ -788,6 +785,7 @@ impl<T: Config> Pallet<T> {
let signature = authority_key.sign(&clap.encode()) let signature = authority_key.sign(&clap.encode())
.ok_or(OffchainErr::FailedSigning)?; .ok_or(OffchainErr::FailedSigning)?;
let call = Call::slow_clap { clap, signature }; let call = Call::slow_clap { clap, signature };
SubmitTransaction::<T, Call<T>>::submit_unsigned_transaction(call.into()) SubmitTransaction::<T, Call<T>>::submit_unsigned_transaction(call.into())
.map_err(|_| OffchainErr::SubmitTransaction)?; .map_err(|_| OffchainErr::SubmitTransaction)?;
} }
@ -802,6 +800,7 @@ impl<T: Config> Pallet<T> {
let authorities = Authorities::<T>::get(&session_index); let authorities = Authorities::<T>::get(&session_index);
let mut local_authorities = T::AuthorityId::all(); let mut local_authorities = T::AuthorityId::all();
local_authorities.sort(); local_authorities.sort();
authorities.into_iter().enumerate().filter_map(move |(index, authority)| { authorities.into_iter().enumerate().filter_map(move |(index, authority)| {
local_authorities local_authorities
.binary_search(&authority) .binary_search(&authority)

View File

@ -151,12 +151,13 @@ fn should_make_http_call_for_block_number() {
evm_block_response(&mut state.write()); evm_block_response(&mut state.write());
t.execute_with(|| { let _: Result<(), OffchainErr<u32>> = t.execute_with(|| {
let rpc_endpoint = get_rpc_endpoint(); let rpc_endpoint = get_rpc_endpoint();
let network_data = prepare_evm_network(Some(1), None); let network_data = prepare_evm_network(Some(1), None);
let request_body = SlowClap::prepare_request_body_for_latest_block(&network_data); let request_body = SlowClap::prepare_request_body_for_latest_block(&network_data);
let raw_response = SlowClap::fetch_from_remote(&rpc_endpoint, &request_body).unwrap(); let raw_response = SlowClap::fetch_from_remote(&rpc_endpoint, &request_body)?;
assert_eq!(raw_response.len(), 45usize); // precalculated assert_eq!(raw_response.len(), 45usize); // precalculated
Ok(())
}); });
} }
@ -168,17 +169,17 @@ fn should_make_http_call_for_logs() {
evm_logs_response(&mut state.write()); evm_logs_response(&mut state.write());
t.execute_with(|| { let _: Result<(), OffchainErr<u32>> = t.execute_with(|| {
let from_block: u64 = 420; let from_block: u64 = 20335770;
let to_block: u64 = 1337; let to_block: u64 = 20335858;
let rpc_endpoint = get_rpc_endpoint(); let rpc_endpoint = get_rpc_endpoint();
let network_data = prepare_evm_network(Some(1), None); let network_data = prepare_evm_network(Some(1), None);
let request_body = SlowClap::prepare_request_body_for_latest_transfers( let request_body = SlowClap::prepare_request_body_for_latest_transfers(
from_block, to_block, &network_data); from_block, to_block, &network_data);
let raw_response = SlowClap::fetch_from_remote(&rpc_endpoint, &request_body) let raw_response = SlowClap::fetch_from_remote(&rpc_endpoint, &request_body)?;
.unwrap();
assert_eq!(raw_response.len(), 1805); // precalculated assert_eq!(raw_response.len(), 1805); // precalculated
Ok(())
}); });
} }
@ -190,23 +191,23 @@ fn should_make_http_call_and_parse_block_number() {
evm_block_response(&mut state.write()); evm_block_response(&mut state.write());
t.execute_with(|| { let _: Result<(), OffchainErr<u32>> = t.execute_with(|| {
let rpc_endpoint = get_rpc_endpoint(); let rpc_endpoint = get_rpc_endpoint();
let network_data = prepare_evm_network(Some(1), None); let network_data = prepare_evm_network(Some(1), None);
let request_body = SlowClap::prepare_request_body_for_latest_block(&network_data); let request_body = SlowClap::prepare_request_body_for_latest_block(&network_data);
let raw_response = SlowClap::fetch_from_remote(&rpc_endpoint, &request_body).unwrap(); let raw_response = SlowClap::fetch_from_remote(&rpc_endpoint, &request_body)?;
let evm_block_number = SlowClap::apply_evm_response( let evm_block_number = SlowClap::apply_evm_response(&raw_response, 69, Default::default(), 420, 1)?;
&raw_response, 69, Default::default(), 420, 1).unwrap_or_default();
assert_eq!(evm_block_number, 20335745); assert_eq!(evm_block_number, 20335745);
Ok(())
}); });
} }
#[test] #[test]
fn should_make_http_call_and_parse_logs() { fn should_make_http_call_and_parse_logs() {
let (offchain, state) = TestOffchainExt::new(); let (offchain, state) = TestOffchainExt::new();
let (pool, _state) = TestTransactionPoolExt::new(); let (pool, _) = TestTransactionPoolExt::new();
let mut t = sp_io::TestExternalities::default(); let mut t = sp_io::TestExternalities::default();
t.register_extension(OffchainDbExt::new(offchain.clone())); t.register_extension(OffchainDbExt::new(offchain.clone()));
@ -215,19 +216,34 @@ fn should_make_http_call_and_parse_logs() {
evm_logs_response(&mut state.write()); evm_logs_response(&mut state.write());
t.execute_with(|| { let _: Result<(), OffchainErr<u32>> = t.execute_with(|| {
let from_block: u64 = 420; let session_index = advance_session_and_get_index();
let to_block: u64 = 1337;
let rpc_endpoint = get_rpc_endpoint(); let rpc_endpoint = get_rpc_endpoint();
let network_data = prepare_evm_network(Some(1), None); let from_block: u64 = 20335770;
let to_block: u64 = 20335858;
let network_id: u32 = 1;
let network_data = prepare_evm_network(Some(network_id), None);
let request_body = SlowClap::prepare_request_body_for_latest_transfers( let request_body = SlowClap::prepare_request_body_for_latest_transfers(
from_block, to_block, &network_data); from_block, to_block, &network_data);
let raw_response = SlowClap::fetch_from_remote(&rpc_endpoint, &request_body).unwrap();
let raw_response = SlowClap::fetch_from_remote(&rpc_endpoint, &request_body)?;
match SlowClap::parse_evm_response(&raw_response)? {
EvmResponseType::BlockNumber(_) => assert_eq!(1, 0), // force break
EvmResponseType::TransactionLogs(evm_logs) => assert_eq!(evm_logs.len(), 2),
}
let evm_block_number = SlowClap::apply_evm_response( let evm_block_number = SlowClap::apply_evm_response(
&raw_response, 69, Default::default(), 420, 1).unwrap_or(20335745); &raw_response,
1,
UintAuthorityId::from(2),
session_index,
network_id,
)?;
assert_eq!(evm_block_number, 0); assert_eq!(evm_block_number, 0);
Ok(())
}); });
} }
@ -265,7 +281,7 @@ fn should_increase_gatkeeper_amount_accordingly() {
assert_ok!(do_clap_from(session_index, network_id, 1, false)); assert_ok!(do_clap_from(session_index, network_id, 1, false));
assert_ok!(do_clap_from(session_index, network_id, 2, false)); assert_ok!(do_clap_from(session_index, network_id, 2, false));
assert_eq!(Networks::gatekeeper_amount(network_id), amount.saturating_div(2)); assert_eq!(Networks::gatekeeper_amount(network_id), amount);
assert_eq!(Networks::bridged_imbalance().bridged_in, amount.saturating_div(2)); assert_eq!(Networks::bridged_imbalance().bridged_in, amount.saturating_div(2));
assert_eq!(Networks::bridged_imbalance().bridged_out, 0); assert_eq!(Networks::bridged_imbalance().bridged_out, 0);
}); });
@ -594,7 +610,7 @@ fn should_throw_error_on_commission_overflow() {
assert_ok!(SlowClap::slow_clap(RuntimeOrigin::none(), clap, signature)); assert_ok!(SlowClap::slow_clap(RuntimeOrigin::none(), clap, signature));
} else { } else {
assert_err!(SlowClap::slow_clap(RuntimeOrigin::none(), clap, signature), assert_err!(SlowClap::slow_clap(RuntimeOrigin::none(), clap, signature),
Error::<Runtime>::CouldNotIncreaseGatekeeperAmount); Error::<Runtime>::CouldNotAccumulateIncomingImbalance);
} }
} }
@ -617,19 +633,19 @@ fn should_nullify_commission_on_finalize() {
let (_, _, amount) = get_mocked_metadata(); let (_, _, amount) = get_mocked_metadata();
new_test_ext().execute_with(|| { new_test_ext().execute_with(|| {
let _ = prepare_evm_network(Some(network_id), Some(500_000_000)); let _ = prepare_evm_network(Some(network_id), Some(1_000_000_000));
let session_index = advance_session_and_get_index(); let session_index = advance_session_and_get_index();
assert_eq!(Networks::accumulated_commission(), 0); assert_eq!(Networks::accumulated_commission(), 0);
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_ok!(do_clap_from(session_index, network_id, 1, false));
assert_eq!(Networks::accumulated_commission(), amount.saturating_div(2)); assert_eq!(Networks::accumulated_commission(), amount);
assert_eq!(Networks::is_nullification_period(), false); assert_eq!(Networks::is_nullification_period(), false);
assert_eq!(BridgedInflationCurve::<RewardCurve, Runtime>::era_payout( assert_eq!(BridgedInflationCurve::<RewardCurve, Runtime>::era_payout(
total_staked, total_staked,
(total_issuance + amount).into(), total_issuance,
0), (1260099399952u128, 208739900600048u128)); // precomputed values 0), (420000000000000, 0)); // precomputed values
assert_eq!(Networks::is_nullification_period(), true); assert_eq!(Networks::is_nullification_period(), true);
Networks::on_finalize(System::block_number()); Networks::on_finalize(System::block_number());
@ -793,10 +809,36 @@ fn should_emit_event_on_each_clap_and_on_applause() {
}); });
} }
// TODO: multiple logs will create multiple records #[test]
// TODO: errors should be checked as much as possible fn should_not_fail_on_sub_existential_balance() {
// TODO: offences generated as expected let (network_id, transaction_hash, unique_transaction_hash)
// TODO: deal with below existential amount after commission = 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(1_000_000_000)); // 100%
let session_index = advance_session_and_get_index();
let received_claps_key = (session_index, transaction_hash, unique_transaction_hash);
assert_eq!(Networks::accumulated_commission(), 0);
assert_eq!(Networks::gatekeeper_amount(network_id), 0);
assert_eq!(Networks::bridged_imbalance().bridged_in, 0);
assert_eq!(Networks::bridged_imbalance().bridged_out, 0);
assert_eq!(Balances::balance(&receiver), 0);
assert_eq!(SlowClap::applauses_for_transaction(&received_claps_key), false);
assert_ok!(do_clap_from(session_index, network_id, 0, false));
assert_ok!(do_clap_from(session_index, network_id, 1, false));
assert_ok!(do_clap_from(session_index, network_id, 2, false));
assert_eq!(Networks::accumulated_commission(), amount);
assert_eq!(Networks::gatekeeper_amount(network_id), amount);
assert_eq!(Networks::bridged_imbalance().bridged_in, 0);
assert_eq!(Networks::bridged_imbalance().bridged_out, 0);
assert_eq!(Balances::balance(&receiver), 0);
assert_eq!(SlowClap::applauses_for_transaction(&received_claps_key), true);
});
}
fn advance_session_and_get_index() -> u32 { fn advance_session_and_get_index() -> u32 {
advance_session(); advance_session();
@ -892,11 +934,11 @@ fn evm_block_response(state: &mut testing::OffchainState) {
} }
fn evm_logs_response(state: &mut testing::OffchainState) { fn evm_logs_response(state: &mut testing::OffchainState) {
let expected_body = br#"{"id":0,"jsonrpc":"2.0","method":"eth_getLogs","params":[{"fromBlock":"0x1a4","toBlock":"0x539","address":"0x4d224452801ACEd8B2F0aebE155379bb5D594381","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]}]}"#.to_vec(); let expected_body = br#"{"id":0,"jsonrpc":"2.0","method":"eth_getLogs","params":[{"fromBlock":"0x1364c9a","toBlock":"0x1364cf2","address":"0x4d224452801ACEd8B2F0aebE155379bb5D594381","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]}]}"#.to_vec();
let expected_response = br#"{ let expected_response = br#"{
"jsonrpc":"2.0",
"id":0, "id":0,
"jsonrpc":"2.0",
"result":[ "result":[
{ {
"address":"0x4d224452801aced8b2f0aebe155379bb5d594381", "address":"0x4d224452801aced8b2f0aebe155379bb5d594381",
@ -938,6 +980,10 @@ fn evm_logs_response(state: &mut testing::OffchainState) {
("Accept".to_string(), "application/json".to_string()), ("Accept".to_string(), "application/json".to_string()),
("Content-Type".to_string(), "application/json".to_string()), ("Content-Type".to_string(), "application/json".to_string()),
], ],
response_headers: vec![
("Accept".to_string(), "application/json".to_string()),
("Content-Type".to_string(), "application/json".to_string()),
],
body: expected_body, body: expected_body,
response: Some(expected_response), response: Some(expected_response),
sent: true, sent: true,

View File

@ -1,6 +1,6 @@
[package] [package]
name = "ghost-traits" name = "ghost-traits"
version = "0.3.21" version = "0.3.22"
license.workspace = true license.workspace = true
authors.workspace = true authors.workspace = true
edition.workspace = true edition.workspace = true

View File

@ -28,14 +28,12 @@ pub trait NetworkDataMutateHandler<Network, Balance>: NetworkDataInspectHandler<
fn register(chain_id: Self::NetworkId, network: Network) -> DispatchResult; fn register(chain_id: Self::NetworkId, network: Network) -> DispatchResult;
fn remove(chain_id: Self::NetworkId) -> DispatchResult; fn remove(chain_id: Self::NetworkId) -> DispatchResult;
fn increase_gatekeeper_amount( fn increase_gatekeeper_amount(chain_id: &Self::NetworkId, amount: &Balance) -> Result<Balance, ()>;
chain_id: &Self::NetworkId, fn decrease_gatekeeper_amount(chain_id: &Self::NetworkId, amount: &Balance) -> Result<Balance, ()>;
amount: &Balance,
) -> Result<(Balance, Balance), ()>; fn accumulate_outgoing_imbalance(amount: &Balance) -> Result<Balance, ()>;
fn decrease_gatekeeper_amount( fn accumulate_incoming_imbalance(amount: &Balance) -> Result<Balance, ()>;
chain_id: &Self::NetworkId,
amount: &Balance,
) -> Result<(Balance, Balance), ()>;
fn accumulate_commission(commission: &Balance) -> Result<Balance, ()>; fn accumulate_commission(commission: &Balance) -> Result<Balance, ()>;
fn nullify_commission(); fn nullify_commission();
fn trigger_nullification(); fn trigger_nullification();

View File

@ -1,6 +1,6 @@
[package] [package]
name = "casper-runtime" name = "casper-runtime"
version = "3.5.20" version = "3.5.21"
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

@ -1035,6 +1035,7 @@ impl pallet_alliance::Config for Runtime {
impl ghost_networks::Config for Runtime { impl ghost_networks::Config for Runtime {
type RuntimeEvent = RuntimeEvent; type RuntimeEvent = RuntimeEvent;
type NetworkId = u64; type NetworkId = u64;
type Currency = Balances;
type RegisterOrigin = EitherOf< type RegisterOrigin = EitherOf<
EnsureRootWithSuccess<Self::AccountId, ConstU16<65535>>, EnsureRootWithSuccess<Self::AccountId, ConstU16<65535>>,
@ -1073,14 +1074,11 @@ impl ghost_claims::Config<CultCollectiveInstance> for Runtime {
} }
parameter_types! { parameter_types! {
// maximum number of claps in one tx
pub MaxNumberOfClaps: u32 = 5;
// will be used in `Perbill::from_percent()` // will be used in `Perbill::from_percent()`
pub ApplauseThreshold: u32 = 70; pub ApplauseThreshold: u32 = 70;
// will be used in `Perbill::from_percent()` // will be used in `Perbill::from_percent()`
pub OffenceThreshold: u32 = 40; pub OffenceThreshold: u32 = 40;
pub const SlowClapUnsignedPriority: TransactionPriority = pub const SlowClapUnsignedPriority: TransactionPriority = TransactionPriority::MAX;
TransactionPriority::max_value();
} }
impl ghost_slow_clap::Config for Runtime { impl ghost_slow_clap::Config for Runtime {
@ -1095,15 +1093,11 @@ impl ghost_slow_clap::Config for Runtime {
type ReportUnresponsiveness = Offences; type ReportUnresponsiveness = Offences;
type MaxAuthorities = MaxAuthorities; type MaxAuthorities = MaxAuthorities;
type MaxNumberOfClaps = MaxNumberOfClaps;
type ApplauseThreshold = ApplauseThreshold; type ApplauseThreshold = ApplauseThreshold;
type MaxAuthorityInfoInSession = MaxAuthorities;
type OffenceThreshold = OffenceThreshold; type OffenceThreshold = OffenceThreshold;
type UnsignedPriority = SlowClapUnsignedPriority; type UnsignedPriority = SlowClapUnsignedPriority;
type TreasuryPalletId = TreasuryPalletId;
type WeightInfo = weights::ghost_slow_clap::WeightInfo<Runtime>; type WeightInfo = Default::default();
} }
construct_runtime! { construct_runtime! {