Compare commits
6 Commits
cce2910cf8
...
5dd0c73f7a
| Author | SHA1 | Date | |
|---|---|---|---|
| 5dd0c73f7a | |||
| 03262539aa | |||
| f524b01b03 | |||
| f99eee2e1a | |||
| d3cc3ac1b3 | |||
| 7a7712df0b |
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "ghost-networks"
|
||||
version = "0.1.20"
|
||||
version = "0.1.23"
|
||||
license.workspace = true
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
|
||||
@ -85,13 +85,15 @@ benchmarks! {
|
||||
let (chain_id, network) = prepare_network::<T>(i, j, k);
|
||||
let authority = T::RegisterOrigin::try_successful_origin()
|
||||
.map_err(|_| BenchmarkError::Weightless)?;
|
||||
let prev_network = GhostNetworks::<T>::networks(chain_id.clone());
|
||||
assert_eq!(GhostNetworks::<T>::networks(chain_id.clone()), None);
|
||||
assert!(GhostNetworks::<T>::network_indexes().is_empty());
|
||||
}: _<T::RuntimeOrigin>(authority, chain_id.clone(), network.clone())
|
||||
verify {
|
||||
assert_last_event::<T>(Event::NetworkRegistered {
|
||||
chain_id: chain_id.clone(), network,
|
||||
chain_id: chain_id.clone(), network: network.clone(),
|
||||
}.into());
|
||||
assert_ne!(GhostNetworks::<T>::networks(chain_id.clone()), prev_network);
|
||||
assert_eq!(GhostNetworks::<T>::networks(chain_id.clone()), Some(network));
|
||||
assert_eq!(GhostNetworks::<T>::network_indexes(), vec![chain_id]);
|
||||
}
|
||||
|
||||
update_network_name {
|
||||
@ -251,20 +253,23 @@ benchmarks! {
|
||||
assert_last_event::<T>(Event::NetworkAvgBlockSpeedUpdated {
|
||||
chain_id: chain_id.clone(), avg_block_speed,
|
||||
}.into());
|
||||
assert_ne!(GhostNetworks::<T>::networks(chain_id.clone()), prev_network);
|
||||
assert_ne!(GhostNetworks::<T>::networks(chain_id.clone()), None);
|
||||
}
|
||||
|
||||
remove_network {
|
||||
let (chain_id, network) = prepare_network::<T>(1, 1, 1);
|
||||
let authority = T::RemoveOrigin::try_successful_origin()
|
||||
.map_err(|_| BenchmarkError::Weightless)?;
|
||||
let prev_network = create_network::<T>(chain_id.clone(), network.clone())?;
|
||||
let _ = create_network::<T>(chain_id.clone(), network.clone())?;
|
||||
assert_eq!(GhostNetworks::<T>::networks(chain_id.clone()), Some(network));
|
||||
assert_eq!(GhostNetworks::<T>::network_indexes(), vec![chain_id.clone()]);
|
||||
}: _<T::RuntimeOrigin>(authority, chain_id.clone())
|
||||
verify {
|
||||
assert_last_event::<T>(Event::NetworkRemoved {
|
||||
chain_id: chain_id.clone(),
|
||||
}.into());
|
||||
assert_ne!(GhostNetworks::<T>::networks(chain_id.clone()), prev_network);
|
||||
assert_eq!(GhostNetworks::<T>::networks(chain_id.clone()), None);
|
||||
assert!(GhostNetworks::<T>::network_indexes().is_empty());
|
||||
}
|
||||
|
||||
impl_benchmark_test_suite!(GhostNetworks, crate::mock::ExtBuilder::build(), crate::mock::Test);
|
||||
|
||||
@ -12,7 +12,7 @@ use scale_info::TypeInfo;
|
||||
|
||||
use sp_runtime::{
|
||||
curve::PiecewiseLinear,
|
||||
traits::{AtLeast32BitUnsigned, CheckedAdd, CheckedSub, Member},
|
||||
traits::{AtLeast32BitUnsigned, CheckedAdd, CheckedSub, Member, UniqueSaturatedInto},
|
||||
DispatchResult,
|
||||
};
|
||||
use sp_std::{convert::TryInto, prelude::*};
|
||||
@ -21,12 +21,10 @@ pub use ghost_traits::networks::{
|
||||
NetworkDataBasicHandler, NetworkDataInspectHandler, NetworkDataMutateHandler,
|
||||
};
|
||||
|
||||
mod math;
|
||||
pub mod migrations;
|
||||
mod weights;
|
||||
|
||||
pub use crate::weights::WeightInfo;
|
||||
use math::MulDiv;
|
||||
pub use module::*;
|
||||
|
||||
#[cfg(any(feature = "runtime-benchmarks", test))]
|
||||
@ -99,23 +97,26 @@ where
|
||||
_era_duration_in_millis: u64,
|
||||
) -> (Balance, Balance) {
|
||||
let reward_curve = RewardCurve::get();
|
||||
let bridged_imbalance = BridgedImbalance::<T>::get();
|
||||
let accumulated_commission = AccumulatedCommission::<T>::get();
|
||||
let bridged_imbalance = BridgedImbalance::<T>::take();
|
||||
let accumulated_commission = AccumulatedCommission::<T>::take();
|
||||
|
||||
let accumulated_commission: Balance = accumulated_commission.into();
|
||||
let adjusted_issuance: Balance = total_issuance
|
||||
.saturating_add(bridged_imbalance.bridged_out.into())
|
||||
.saturating_sub(bridged_imbalance.bridged_in.into());
|
||||
|
||||
NullifyNeeded::<T>::set(true);
|
||||
|
||||
let estimated_reward =
|
||||
reward_curve.calculate_for_fraction_times_denominator(total_staked, adjusted_issuance);
|
||||
let payout = MulDiv::<Balance>::calculate(
|
||||
estimated_reward,
|
||||
accumulated_commission,
|
||||
adjusted_issuance,
|
||||
);
|
||||
|
||||
let payout: Balance = sp_runtime::helpers_128bit::multiply_by_rational_with_rounding(
|
||||
estimated_reward.unique_saturated_into(),
|
||||
accumulated_commission.unique_saturated_into(),
|
||||
adjusted_issuance.unique_saturated_into(),
|
||||
sp_runtime::Rounding::NearestPrefUp,
|
||||
)
|
||||
.map(|result| result.unique_saturated_into())
|
||||
.unwrap_or_default();
|
||||
|
||||
let rest_payout = accumulated_commission.saturating_sub(payout);
|
||||
|
||||
(payout, rest_payout)
|
||||
@ -240,10 +241,6 @@ pub mod module {
|
||||
},
|
||||
}
|
||||
|
||||
#[pallet::storage]
|
||||
#[pallet::getter(fn nullify_needed)]
|
||||
pub type NullifyNeeded<T: Config> = StorageValue<_, bool, ValueQuery>;
|
||||
|
||||
#[pallet::storage]
|
||||
#[pallet::getter(fn bridged_imbalance)]
|
||||
pub type BridgedImbalance<T: Config> =
|
||||
@ -301,20 +298,6 @@ pub mod module {
|
||||
#[pallet::without_storage_info]
|
||||
pub struct Pallet<T>(PhantomData<T>);
|
||||
|
||||
#[pallet::hooks]
|
||||
impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
|
||||
fn on_initialize(_: BlockNumberFor<T>) -> Weight {
|
||||
T::DbWeight::get().reads_writes(1, 1)
|
||||
}
|
||||
|
||||
fn on_finalize(_: BlockNumberFor<T>) {
|
||||
if Self::nullify_needed() {
|
||||
Self::nullify_commission();
|
||||
NullifyNeeded::<T>::put(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[pallet::call]
|
||||
impl<T: Config> Pallet<T> {
|
||||
#[pallet::call_index(0)]
|
||||
@ -754,9 +737,7 @@ impl<T: Config> NetworkDataInspectHandler<NetworkData> for Pallet<T> {
|
||||
Networks::<T>::get(n)
|
||||
}
|
||||
|
||||
fn next_network_for_block(
|
||||
block_number: impl Into<usize>,
|
||||
) -> Option<(Self::NetworkId, NetworkData)> {
|
||||
fn network_for_block(block_number: impl Into<usize>) -> Option<(Self::NetworkId, NetworkData)> {
|
||||
let network_indexes = NetworkIndexes::<T>::get();
|
||||
block_number
|
||||
.into()
|
||||
@ -772,10 +753,6 @@ impl<T: Config> NetworkDataInspectHandler<NetworkData> for Pallet<T> {
|
||||
fn iter() -> PrefixIterator<(Self::NetworkId, NetworkData)> {
|
||||
Networks::<T>::iter()
|
||||
}
|
||||
|
||||
fn is_nullification_period() -> bool {
|
||||
NullifyNeeded::<T>::get()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Config> NetworkDataMutateHandler<NetworkData, BalanceOf<T>> for Pallet<T> {
|
||||
@ -862,18 +839,4 @@ impl<T: Config> NetworkDataMutateHandler<NetworkData, BalanceOf<T>> for Pallet<T
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn nullify_commission() {
|
||||
AccumulatedCommission::<T>::set(Default::default());
|
||||
BridgedImbalance::<T>::set(Default::default());
|
||||
}
|
||||
|
||||
fn trigger_nullification() {
|
||||
if NullifyNeeded::<T>::get() {
|
||||
Self::nullify_commission();
|
||||
NullifyNeeded::<T>::put(false);
|
||||
} else {
|
||||
NullifyNeeded::<T>::put(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,134 +0,0 @@
|
||||
use crate::AtLeast32BitUnsigned;
|
||||
|
||||
pub struct MulDiv<Balance>(core::marker::PhantomData<Balance>);
|
||||
impl<Balance> MulDiv<Balance>
|
||||
where
|
||||
Balance: Copy
|
||||
+ AtLeast32BitUnsigned
|
||||
+ num_traits::ops::wrapping::WrappingAdd
|
||||
+ num_traits::ops::overflowing::OverflowingAdd
|
||||
+ sp_std::ops::AddAssign
|
||||
+ sp_std::ops::Not<Output = Balance>
|
||||
+ sp_std::ops::Shl<Output = Balance>
|
||||
+ sp_std::ops::Shr<Output = Balance>
|
||||
+ sp_std::ops::BitAnd<Balance, Output = Balance>,
|
||||
{
|
||||
fn zero(&self) -> Balance {
|
||||
0u32.into()
|
||||
}
|
||||
|
||||
fn one(&self) -> Balance {
|
||||
1u32.into()
|
||||
}
|
||||
|
||||
fn bit_shift(&self) -> Balance {
|
||||
let u32_shift: u32 = core::mem::size_of::<Balance>()
|
||||
.saturating_mul(4)
|
||||
.try_into()
|
||||
.unwrap_or_default();
|
||||
u32_shift.into()
|
||||
}
|
||||
|
||||
fn least_significant_bits(&self, a: Balance) -> Balance {
|
||||
a & ((self.one() << self.bit_shift()) - self.one())
|
||||
}
|
||||
|
||||
fn most_significant_bits(&self, a: Balance) -> Balance {
|
||||
a >> self.bit_shift()
|
||||
}
|
||||
|
||||
fn two_complement(&self, a: Balance) -> Balance {
|
||||
(!a).wrapping_add(&self.one())
|
||||
}
|
||||
|
||||
fn adjusted_ratio(&self, a: Balance) -> Balance {
|
||||
(self.two_complement(a) / a).wrapping_add(&self.one())
|
||||
}
|
||||
|
||||
fn modulo(&self, a: Balance) -> Balance {
|
||||
self.two_complement(a) % a
|
||||
}
|
||||
|
||||
fn overflow_resistant_addition(
|
||||
&self,
|
||||
a0: Balance,
|
||||
a1: Balance,
|
||||
b0: Balance,
|
||||
b1: Balance,
|
||||
) -> (Balance, Balance) {
|
||||
let (r0, overflow) = a0.overflowing_add(&b0);
|
||||
let overflow: Balance = overflow.then(|| 1u32).unwrap_or_default().into();
|
||||
let r1 = a1.wrapping_add(&b1).wrapping_add(&overflow);
|
||||
(r0, r1)
|
||||
}
|
||||
|
||||
fn overflow_resistant_multiplication(&self, a: Balance, b: Balance) -> (Balance, Balance) {
|
||||
let (a0, a1) = (
|
||||
self.least_significant_bits(a),
|
||||
self.most_significant_bits(a),
|
||||
);
|
||||
let (b0, b1) = (
|
||||
self.least_significant_bits(b),
|
||||
self.most_significant_bits(b),
|
||||
);
|
||||
let (x, y) = (a1 * b0, b1 * a0);
|
||||
|
||||
let (r0, r1) = (a0 * b0, a1 * b1);
|
||||
let (r0, r1) = self.overflow_resistant_addition(
|
||||
r0,
|
||||
r1,
|
||||
self.least_significant_bits(x) << self.bit_shift(),
|
||||
self.most_significant_bits(x),
|
||||
);
|
||||
let (r0, r1) = self.overflow_resistant_addition(
|
||||
r0,
|
||||
r1,
|
||||
self.least_significant_bits(y) << self.bit_shift(),
|
||||
self.most_significant_bits(y),
|
||||
);
|
||||
|
||||
(r0, r1)
|
||||
}
|
||||
|
||||
fn overflow_resistant_division(
|
||||
&self,
|
||||
mut a0: Balance,
|
||||
mut a1: Balance,
|
||||
b: Balance,
|
||||
) -> (Balance, Balance) {
|
||||
if b == self.one() {
|
||||
return (a0, a1);
|
||||
}
|
||||
|
||||
let zero: Balance = 0u32.into();
|
||||
let (q, r) = (self.adjusted_ratio(b), self.modulo(b));
|
||||
let (mut x0, mut x1) = (zero, zero);
|
||||
|
||||
while a1 != zero {
|
||||
let (t0, t1) = self.overflow_resistant_multiplication(a1, q);
|
||||
let (new_x0, new_x1) = self.overflow_resistant_addition(x0, x1, t0, t1);
|
||||
x0 = new_x0;
|
||||
x1 = new_x1;
|
||||
|
||||
let (t0, t1) = self.overflow_resistant_multiplication(a1, r);
|
||||
let (new_a0, new_a1) = self.overflow_resistant_addition(t0, t1, a0, zero);
|
||||
a0 = new_a0;
|
||||
a1 = new_a1;
|
||||
}
|
||||
|
||||
self.overflow_resistant_addition(x0, x1, a0 / b, zero)
|
||||
}
|
||||
|
||||
fn mul_div(&self, a: Balance, b: Balance, c: Balance) -> Balance {
|
||||
let (t0, t1) = self.overflow_resistant_multiplication(a, b);
|
||||
self.overflow_resistant_division(t0, t1, c).0
|
||||
}
|
||||
|
||||
pub fn calculate(a: Balance, b: Balance, c: Balance) -> Balance {
|
||||
let inner = MulDiv(core::marker::PhantomData);
|
||||
if c == inner.zero() {
|
||||
return c;
|
||||
}
|
||||
inner.mul_div(a, b, c)
|
||||
}
|
||||
}
|
||||
@ -1,10 +1,11 @@
|
||||
use frame_support::{
|
||||
traits::{Get, UncheckedOnRuntimeUpgrade},
|
||||
migration::clear_storage_prefix,
|
||||
traits::{Get, PalletInfoAccess, UncheckedOnRuntimeUpgrade},
|
||||
weights::Weight,
|
||||
};
|
||||
use sp_std::marker::PhantomData;
|
||||
|
||||
use crate::{BoundedVec, Config, NetworkIndexes, Networks, Vec, LOG_TARGET};
|
||||
use crate::{BoundedVec, Config, NetworkIndexes, Networks, Pallet, Vec, LOG_TARGET};
|
||||
|
||||
pub struct StoreNetworkIdsIntoBoundedVec<T>(PhantomData<T>);
|
||||
impl<T: Config> UncheckedOnRuntimeUpgrade for StoreNetworkIdsIntoBoundedVec<T> {
|
||||
@ -16,6 +17,23 @@ impl<T: Config> UncheckedOnRuntimeUpgrade for StoreNetworkIdsIntoBoundedVec<T> {
|
||||
|
||||
weight = weight.saturating_add(T::DbWeight::get().reads(networks_count as u64));
|
||||
|
||||
let clear_results = clear_storage_prefix(
|
||||
Pallet::<T>::name().as_bytes(),
|
||||
"NullifyNeeded".as_bytes(),
|
||||
&[],
|
||||
Some(1),
|
||||
None,
|
||||
);
|
||||
log::info!(
|
||||
target: LOG_TARGET,
|
||||
"⛓️ NullifyNeeded storage succesfully removed: Loops (reads): {}, Unique removed (writes): {}",
|
||||
clear_results.loops,
|
||||
clear_results.unique,
|
||||
);
|
||||
|
||||
weight = weight.saturating_add(T::DbWeight::get().reads(clear_results.loops as u64));
|
||||
weight = weight.saturating_add(T::DbWeight::get().writes(clear_results.unique as u64));
|
||||
|
||||
let writes = BoundedVec::<T::NetworkId, T::MaxNetworks>::try_from(network_ids)
|
||||
.inspect_err(|err| {
|
||||
log::error!(
|
||||
|
||||
@ -82,6 +82,7 @@ pallet_staking_reward_curve::build! {
|
||||
|
||||
parameter_types! {
|
||||
pub const RewardCurve: &'static PiecewiseLinear<'static> = &REWARD_CURVE;
|
||||
pub const MaxNetworks: u32 = 3;
|
||||
}
|
||||
|
||||
ord_parameter_types! {
|
||||
@ -98,7 +99,7 @@ impl ghost_networks::Config for Test {
|
||||
type RegisterOrigin = EnsureSignedBy<RegistererAccount, AccountId>;
|
||||
type UpdateOrigin = EnsureSignedBy<UpdaterAccount, AccountId>;
|
||||
type RemoveOrigin = EnsureSignedBy<RemoverAccount, AccountId>;
|
||||
type MaxNetworks = ConstU32<3>;
|
||||
type MaxNetworks = MaxNetworks;
|
||||
type WeightInfo = ();
|
||||
}
|
||||
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
use super::*;
|
||||
use frame_support::{assert_err, assert_ok};
|
||||
use mock::{
|
||||
ExtBuilder, GhostNetworks, RandomAccount, RegistererAccount, RemoverAccount, RewardCurve,
|
||||
RuntimeEvent, RuntimeOrigin, System, Test, UpdaterAccount,
|
||||
ExtBuilder, GhostNetworks, MaxNetworks, RandomAccount, RegistererAccount, RemoverAccount,
|
||||
RewardCurve, RuntimeEvent, RuntimeOrigin, System, Test, UpdaterAccount,
|
||||
};
|
||||
use pallet_staking::EraPayout;
|
||||
use sp_runtime::DispatchError;
|
||||
@ -1278,7 +1278,7 @@ fn bridged_amount_overflow_and_underflow_emits_error() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn accumulated_commission_could_be_nullified() {
|
||||
fn accumulated_commission_nullified_after_era_payout() {
|
||||
ExtBuilder::build().execute_with(|| {
|
||||
let commission_first: u128 = 420;
|
||||
let commission_second: u128 = 69;
|
||||
@ -1292,12 +1292,20 @@ fn accumulated_commission_could_be_nullified() {
|
||||
GhostNetworks::accumulate_commission(&commission_second,),
|
||||
commission_first + commission_second
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
AccumulatedCommission::<Test>::get(),
|
||||
commission_first + commission_second
|
||||
);
|
||||
GhostNetworks::nullify_commission();
|
||||
assert_eq!(
|
||||
BridgedInflationCurve::<RewardCurve, Test>::era_payout(1, 1, 1),
|
||||
(0, commission_first + commission_second)
|
||||
);
|
||||
assert_eq!(AccumulatedCommission::<Test>::get(), 0);
|
||||
assert_eq!(
|
||||
BridgedInflationCurve::<RewardCurve, Test>::era_payout(1, 1, 1),
|
||||
(0, 0)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@ -1385,7 +1393,6 @@ fn bridged_inlation_reward_works() {
|
||||
|
||||
assert_ok!(GhostNetworks::accumulate_commission(&commission));
|
||||
assert_ok!(GhostNetworks::accumulate_incoming_imbalance(&amount));
|
||||
|
||||
assert_eq!(
|
||||
BridgedInflationCurve::<RewardCurve, Test>::era_payout(
|
||||
total_staked_ideal * 1_000,
|
||||
@ -1394,6 +1401,9 @@ fn bridged_inlation_reward_works() {
|
||||
),
|
||||
(commission, 0)
|
||||
);
|
||||
|
||||
assert_ok!(GhostNetworks::accumulate_commission(&commission));
|
||||
assert_ok!(GhostNetworks::accumulate_incoming_imbalance(&amount));
|
||||
assert_eq!(
|
||||
BridgedInflationCurve::<RewardCurve, Test>::era_payout(
|
||||
total_staked_ideal * 1_000_000_000_000,
|
||||
@ -1402,6 +1412,9 @@ fn bridged_inlation_reward_works() {
|
||||
),
|
||||
(commission, 0)
|
||||
);
|
||||
|
||||
assert_ok!(GhostNetworks::accumulate_commission(&commission));
|
||||
assert_ok!(GhostNetworks::accumulate_incoming_imbalance(&amount));
|
||||
assert_eq!(
|
||||
BridgedInflationCurve::<RewardCurve, Test>::era_payout(
|
||||
total_staked_ideal * 1_000_000_000_000_000_000_000_000,
|
||||
@ -1411,6 +1424,8 @@ fn bridged_inlation_reward_works() {
|
||||
(commission, 0)
|
||||
);
|
||||
|
||||
assert_ok!(GhostNetworks::accumulate_commission(&commission));
|
||||
assert_ok!(GhostNetworks::accumulate_incoming_imbalance(&amount));
|
||||
assert_eq!(
|
||||
BridgedInflationCurve::<RewardCurve, Test>::era_payout(
|
||||
total_staked_not_ideal * 1_000,
|
||||
@ -1419,6 +1434,9 @@ fn bridged_inlation_reward_works() {
|
||||
),
|
||||
(13177472000, 192528000)
|
||||
);
|
||||
|
||||
assert_ok!(GhostNetworks::accumulate_commission(&commission));
|
||||
assert_ok!(GhostNetworks::accumulate_incoming_imbalance(&amount));
|
||||
assert_eq!(13177472000 + 192528000, commission);
|
||||
assert_eq!(
|
||||
BridgedInflationCurve::<RewardCurve, Test>::era_payout(
|
||||
@ -1428,6 +1446,9 @@ fn bridged_inlation_reward_works() {
|
||||
),
|
||||
(13177568884, 192431116)
|
||||
);
|
||||
|
||||
assert_ok!(GhostNetworks::accumulate_commission(&commission));
|
||||
assert_ok!(GhostNetworks::accumulate_incoming_imbalance(&amount));
|
||||
assert_eq!(13177568884 + 192431116, commission);
|
||||
assert_eq!(
|
||||
BridgedInflationCurve::<RewardCurve, Test>::era_payout(
|
||||
@ -1437,8 +1458,10 @@ fn bridged_inlation_reward_works() {
|
||||
),
|
||||
(13177568884, 192431116)
|
||||
);
|
||||
assert_eq!(13177568884 + 192431116, commission);
|
||||
|
||||
assert_ok!(GhostNetworks::accumulate_commission(&commission));
|
||||
assert_ok!(GhostNetworks::accumulate_incoming_imbalance(&amount));
|
||||
assert_eq!(13177568884 + 192431116, commission);
|
||||
assert_eq!(
|
||||
BridgedInflationCurve::<RewardCurve, Test>::era_payout(
|
||||
1,
|
||||
@ -1447,6 +1470,9 @@ fn bridged_inlation_reward_works() {
|
||||
),
|
||||
(92386700, 13277613300)
|
||||
);
|
||||
|
||||
assert_ok!(GhostNetworks::accumulate_commission(&commission));
|
||||
assert_ok!(GhostNetworks::accumulate_incoming_imbalance(&amount));
|
||||
assert_eq!(92386700 + 13277613300, commission);
|
||||
assert_eq!(
|
||||
BridgedInflationCurve::<RewardCurve, Test>::era_payout(
|
||||
@ -1456,6 +1482,9 @@ fn bridged_inlation_reward_works() {
|
||||
),
|
||||
(92253000, 13277747000)
|
||||
);
|
||||
|
||||
assert_ok!(GhostNetworks::accumulate_commission(&commission));
|
||||
assert_ok!(GhostNetworks::accumulate_incoming_imbalance(&amount));
|
||||
assert_eq!(92253000 + 13277747000, commission);
|
||||
assert_eq!(
|
||||
BridgedInflationCurve::<RewardCurve, Test>::era_payout(
|
||||
@ -1465,10 +1494,8 @@ fn bridged_inlation_reward_works() {
|
||||
),
|
||||
(92253000, 13277747000)
|
||||
);
|
||||
|
||||
assert_eq!(92253000 + 13277747000, commission);
|
||||
|
||||
GhostNetworks::nullify_commission();
|
||||
|
||||
assert_eq!(
|
||||
BridgedInflationCurve::<RewardCurve, Test>::era_payout(
|
||||
total_staked_ideal * 1_000,
|
||||
@ -1547,7 +1574,7 @@ fn bridged_inlation_reward_works() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bridged_inflation_era_payout_triggers_need_of_nullification() {
|
||||
fn bridged_inflation_era_payout_clears_storage() {
|
||||
ExtBuilder::build().execute_with(|| {
|
||||
let amount_full: u128 = 1337 * 1_000_000_000;
|
||||
let commission: u128 = amount_full / 100; // 1% commission
|
||||
@ -1558,7 +1585,13 @@ fn bridged_inflation_era_payout_triggers_need_of_nullification() {
|
||||
|
||||
assert_ok!(GhostNetworks::accumulate_commission(&commission));
|
||||
assert_ok!(GhostNetworks::accumulate_incoming_imbalance(&amount));
|
||||
assert_eq!(NullifyNeeded::<Test>::get(), false);
|
||||
|
||||
let bridged_adjustment = BridgeAdjustment {
|
||||
bridged_in: amount,
|
||||
bridged_out: 0,
|
||||
};
|
||||
assert_eq!(BridgedImbalance::<Test>::get(), bridged_adjustment);
|
||||
assert_eq!(AccumulatedCommission::<Test>::get(), commission);
|
||||
assert_eq!(
|
||||
BridgedInflationCurve::<RewardCurve, Test>::era_payout(
|
||||
total_staked_ideal * 1_000,
|
||||
@ -1567,37 +1600,8 @@ fn bridged_inflation_era_payout_triggers_need_of_nullification() {
|
||||
),
|
||||
(commission, 0)
|
||||
);
|
||||
assert_eq!(NullifyNeeded::<Test>::get(), true);
|
||||
GhostNetworks::on_finalize(69);
|
||||
assert_eq!(NullifyNeeded::<Test>::get(), false);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn trigger_nullification_works_as_expected() {
|
||||
ExtBuilder::build().execute_with(|| {
|
||||
let commission: u128 = 69;
|
||||
let imbalance = BridgeAdjustment {
|
||||
bridged_in: 1337u128,
|
||||
bridged_out: 420u128,
|
||||
};
|
||||
|
||||
assert_eq!(AccumulatedCommission::<Test>::get(), 0);
|
||||
assert_eq!(BridgedImbalance::<Test>::get(), BridgeAdjustment::default());
|
||||
|
||||
AccumulatedCommission::<Test>::set(commission);
|
||||
BridgedImbalance::<Test>::set(imbalance.clone());
|
||||
|
||||
assert_eq!(AccumulatedCommission::<Test>::get(), commission);
|
||||
assert_eq!(BridgedImbalance::<Test>::get(), imbalance);
|
||||
|
||||
assert_eq!(NullifyNeeded::<Test>::get(), false);
|
||||
GhostNetworks::trigger_nullification();
|
||||
assert_eq!(NullifyNeeded::<Test>::get(), true);
|
||||
GhostNetworks::trigger_nullification();
|
||||
assert_eq!(NullifyNeeded::<Test>::get(), false);
|
||||
assert_eq!(AccumulatedCommission::<Test>::get(), 0);
|
||||
assert_eq!(BridgedImbalance::<Test>::get(), BridgeAdjustment::default());
|
||||
assert_eq!(BridgedImbalance::<Test>::get(), Default::default());
|
||||
assert_eq!(AccumulatedCommission::<Test>::get(), Default::default());
|
||||
});
|
||||
}
|
||||
|
||||
@ -1673,123 +1677,6 @@ fn check_substrate_guarantees_not_to_overflow_u32() {
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_muldiv_guarantees_not_to_overflow_for_u128() {
|
||||
ExtBuilder::build().execute_with(|| {
|
||||
let mut a: u128 = 2;
|
||||
let mut b: u128 = 3;
|
||||
let mut c: u128 = 6;
|
||||
let mut result: u128 = 1;
|
||||
|
||||
loop {
|
||||
a = match a.checked_mul(1_000) {
|
||||
Some(value) => value,
|
||||
None => break,
|
||||
};
|
||||
b = match b.checked_mul(1_000) {
|
||||
Some(value) => value,
|
||||
None => break,
|
||||
};
|
||||
c = match c.checked_mul(1_000) {
|
||||
Some(value) => value,
|
||||
None => break,
|
||||
};
|
||||
result = match result.checked_mul(1_000) {
|
||||
Some(value) => value,
|
||||
None => break,
|
||||
};
|
||||
|
||||
assert_eq!(MulDiv::<u128>::calculate(a, b, c), result);
|
||||
}
|
||||
|
||||
assert_eq!(
|
||||
MulDiv::<u128>::calculate(u128::MAX, u128::MAX, u128::MAX),
|
||||
u128::MAX
|
||||
);
|
||||
assert_eq!(MulDiv::<u128>::calculate(u128::MAX, 0, 0), 0);
|
||||
assert_eq!(MulDiv::<u128>::calculate(0, u128::MAX, 0), 0);
|
||||
assert_eq!(MulDiv::<u128>::calculate(0, 0, u128::MAX), 0);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_muldiv_guarantees_not_to_overflow_for_u64() {
|
||||
ExtBuilder::build().execute_with(|| {
|
||||
let mut a: u64 = 2;
|
||||
let mut b: u64 = 3;
|
||||
let mut c: u64 = 6;
|
||||
let mut result: u64 = 1;
|
||||
|
||||
loop {
|
||||
a = match a.checked_mul(1_000) {
|
||||
Some(value) => value,
|
||||
None => break,
|
||||
};
|
||||
b = match b.checked_mul(1_000) {
|
||||
Some(value) => value,
|
||||
None => break,
|
||||
};
|
||||
c = match c.checked_mul(1_000) {
|
||||
Some(value) => value,
|
||||
None => break,
|
||||
};
|
||||
result = match result.checked_mul(1_000) {
|
||||
Some(value) => value,
|
||||
None => break,
|
||||
};
|
||||
|
||||
assert_eq!(MulDiv::<u64>::calculate(a, b, c), result);
|
||||
}
|
||||
|
||||
assert_eq!(
|
||||
MulDiv::<u64>::calculate(u64::MAX, u64::MAX, u64::MAX),
|
||||
u64::MAX
|
||||
);
|
||||
assert_eq!(MulDiv::<u64>::calculate(u64::MAX, 0, 0), 0);
|
||||
assert_eq!(MulDiv::<u64>::calculate(0, u64::MAX, 0), 0);
|
||||
assert_eq!(MulDiv::<u64>::calculate(0, 0, u64::MAX), 0);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_muldiv_guarantees_not_to_overflow_for_u32() {
|
||||
ExtBuilder::build().execute_with(|| {
|
||||
let mut a: u32 = 2;
|
||||
let mut b: u32 = 3;
|
||||
let mut c: u32 = 6;
|
||||
let mut result: u32 = 1;
|
||||
|
||||
loop {
|
||||
a = match a.checked_mul(1_000) {
|
||||
Some(value) => value,
|
||||
None => break,
|
||||
};
|
||||
b = match b.checked_mul(1_000) {
|
||||
Some(value) => value,
|
||||
None => break,
|
||||
};
|
||||
c = match c.checked_mul(1_000) {
|
||||
Some(value) => value,
|
||||
None => break,
|
||||
};
|
||||
result = match result.checked_mul(1_000) {
|
||||
Some(value) => value,
|
||||
None => break,
|
||||
};
|
||||
|
||||
assert_eq!(MulDiv::<u32>::calculate(a, b, c), result);
|
||||
}
|
||||
|
||||
assert_eq!(
|
||||
MulDiv::<u32>::calculate(u32::MAX, u32::MAX, u32::MAX),
|
||||
u32::MAX
|
||||
);
|
||||
assert_eq!(MulDiv::<u32>::calculate(u32::MAX, 0, 0), 0);
|
||||
assert_eq!(MulDiv::<u32>::calculate(0, u32::MAX, 0), 0);
|
||||
assert_eq!(MulDiv::<u32>::calculate(0, 0, u32::MAX), 0);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_bridged_inflation_curve_for_overflow() {
|
||||
ExtBuilder::build().execute_with(|| {
|
||||
@ -1797,7 +1684,6 @@ fn check_bridged_inflation_curve_for_overflow() {
|
||||
let commission: u128 = amount_full / 100; // 1% commission
|
||||
let amount: u128 = amount_full - commission;
|
||||
|
||||
let tollerance: u128 = commission / 100; // 1% tollerance
|
||||
let precomputed_payout: u128 = 13177568884;
|
||||
let precomputed_rest: u128 = 192431116;
|
||||
assert_eq!(precomputed_payout + precomputed_rest, commission);
|
||||
@ -1806,10 +1692,10 @@ fn check_bridged_inflation_curve_for_overflow() {
|
||||
let mut total_staked_not_ideal: u128 = 68_000;
|
||||
let mut total_issuance: u128 = 100_000;
|
||||
|
||||
loop {
|
||||
assert_ok!(GhostNetworks::accumulate_commission(&commission));
|
||||
assert_ok!(GhostNetworks::accumulate_incoming_imbalance(&amount));
|
||||
|
||||
loop {
|
||||
total_staked_ideal = match total_staked_ideal.checked_mul(1_000) {
|
||||
Some(value) => value,
|
||||
None => break,
|
||||
@ -1830,27 +1716,6 @@ fn check_bridged_inflation_curve_for_overflow() {
|
||||
),
|
||||
(commission, 0)
|
||||
);
|
||||
|
||||
let (payout, rest) = BridgedInflationCurve::<RewardCurve, Test>::era_payout(
|
||||
total_staked_not_ideal,
|
||||
total_issuance + amount,
|
||||
0,
|
||||
);
|
||||
|
||||
let payout_deviation = if precomputed_payout > payout {
|
||||
precomputed_payout - payout
|
||||
} else {
|
||||
payout - precomputed_payout
|
||||
};
|
||||
|
||||
let rest_deviation = if precomputed_rest > rest {
|
||||
precomputed_rest - rest
|
||||
} else {
|
||||
rest - precomputed_rest
|
||||
};
|
||||
|
||||
assert!(payout_deviation < tollerance);
|
||||
assert!(rest_deviation < tollerance);
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -1913,6 +1778,17 @@ fn migration_from_v0_to_v1_works() {
|
||||
let (chain_id, network) = prepare_network_data();
|
||||
let other_chain_id = chain_id.saturating_add(1);
|
||||
|
||||
let removed_pallet_name = <Pallet<Test> as PalletInfoAccess>::name();
|
||||
let removed_storage = "NullifyNeeded";
|
||||
|
||||
let key = [
|
||||
sp_io::hashing::twox_128(removed_pallet_name.as_bytes()).to_vec(),
|
||||
sp_io::hashing::twox_128(removed_storage.as_bytes()).to_vec(),
|
||||
]
|
||||
.concat();
|
||||
|
||||
frame_support::storage::unhashed::put_raw(&key, &true.encode());
|
||||
|
||||
assert_eq!(Networks::<Test>::get(chain_id), None);
|
||||
assert_ok!(GhostNetworks::register_network(
|
||||
RuntimeOrigin::signed(RegistererAccount::get()),
|
||||
@ -1926,12 +1802,15 @@ fn migration_from_v0_to_v1_works() {
|
||||
));
|
||||
NetworkIndexes::<Test>::kill();
|
||||
|
||||
assert!(frame_support::storage::unhashed::exists(&key));
|
||||
assert_eq!(Networks::<Test>::get(chain_id), Some(network.clone()));
|
||||
assert_eq!(Networks::<Test>::get(other_chain_id), Some(network));
|
||||
assert_eq!(NetworkIndexes::<Test>::get(), vec![]);
|
||||
|
||||
type Migrate = crate::migrations::MigrateV0ToV1<Test>;
|
||||
<Migrate as frame_support::traits::OnRuntimeUpgrade>::on_runtime_upgrade();
|
||||
|
||||
assert!(!frame_support::storage::unhashed::exists(&key));
|
||||
assert_eq!(
|
||||
NetworkIndexes::<Test>::get(),
|
||||
vec![chain_id, other_chain_id]
|
||||
@ -1939,6 +1818,32 @@ fn migration_from_v0_to_v1_works() {
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn error_on_max_networks_overflow() {
|
||||
ExtBuilder::build().execute_with(|| {
|
||||
let (chain_id, network) = prepare_network_data();
|
||||
|
||||
let max_networks = MaxNetworks::get();
|
||||
for index in 0..max_networks {
|
||||
let other_chain_id = chain_id.saturating_add(index);
|
||||
assert_ok!(GhostNetworks::register_network(
|
||||
RuntimeOrigin::signed(RegistererAccount::get()),
|
||||
other_chain_id,
|
||||
network.clone(),
|
||||
));
|
||||
}
|
||||
|
||||
assert_err!(
|
||||
GhostNetworks::register_network(
|
||||
RuntimeOrigin::signed(RegistererAccount::get()),
|
||||
chain_id.saturating_add(max_networks),
|
||||
network.clone(),
|
||||
),
|
||||
crate::Error::<Test>::TooManyNetworks,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn migration_from_v0_to_v1_does_not_run_twice() {
|
||||
ExtBuilder::build().execute_with(|| {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "ghost-slow-clap"
|
||||
version = "0.4.15"
|
||||
version = "0.4.16"
|
||||
description = "Applause protocol for the EVM bridge"
|
||||
license.workspace = true
|
||||
authors.workspace = true
|
||||
|
||||
@ -28,7 +28,7 @@ use sp_runtime::{
|
||||
storage::StorageValueRef,
|
||||
storage_lock::{StorageLock, Time},
|
||||
},
|
||||
traits::{BlockNumberProvider, Convert, Saturating},
|
||||
traits::{BlockNumberProvider, Convert, Saturating, UniqueSaturatedInto},
|
||||
Perbill, RuntimeAppPublic, RuntimeDebug,
|
||||
};
|
||||
use sp_staking::{
|
||||
@ -80,6 +80,7 @@ const LOCK_BLOCK_EXPIRATION: u64 = 20;
|
||||
|
||||
const COMMITMENT_DELAY_MILLIS: u64 = 600_000;
|
||||
const ONE_HOUR_MILLIS: u64 = 3_600_000;
|
||||
const CHECK_BLOCK_INTERVAL: u64 = 300;
|
||||
|
||||
pub type AuthIndex = u32;
|
||||
|
||||
@ -347,6 +348,10 @@ pub mod pallet {
|
||||
authority_id: AuthIndex,
|
||||
network_id: NetworkIdOf<T>,
|
||||
},
|
||||
BlockCommitmentsCheck {
|
||||
network_id: NetworkIdOf<T>,
|
||||
block_number: BlockNumberFor<T>,
|
||||
},
|
||||
}
|
||||
|
||||
#[pallet::error]
|
||||
@ -470,6 +475,68 @@ pub mod pallet {
|
||||
|
||||
#[pallet::hooks]
|
||||
impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
|
||||
fn on_initialize(current_block: BlockNumberFor<T>) -> Weight {
|
||||
// TODO: what about start of the session???
|
||||
let mut weight = T::DbWeight::get().reads(1);
|
||||
|
||||
let networks_count = T::NetworkDataHandler::count();
|
||||
let current_block_number: u64 = current_block.unique_saturated_into();
|
||||
//let cycle_start = (current_block_number / CHECK_BLOCK_INTERVAL) * CHECK_BLOCK_INTERVAL;
|
||||
let cycle_offset = current_block_number % CHECK_BLOCK_INTERVAL;
|
||||
|
||||
if cycle_offset >= networks_count.into() {
|
||||
return Default::default();
|
||||
}
|
||||
|
||||
let converted_block: usize = current_block_number.unique_saturated_into();
|
||||
|
||||
if let Some((network_id, network_data)) =
|
||||
T::NetworkDataHandler::network_for_block(converted_block)
|
||||
{
|
||||
weight = weight.saturating_add(T::DbWeight::get().reads_writes(3, 1));
|
||||
|
||||
let session_index = T::ValidatorSet::session_index();
|
||||
let block_commitments = BlockCommitments::<T>::get(&network_id);
|
||||
let validators = Validators::<T>::get(&session_index);
|
||||
|
||||
if validators.len() == 0 {
|
||||
return weight;
|
||||
}
|
||||
|
||||
let disabled_bitmap = DisabledAuthorityIndexes::<T>::get(&session_index)
|
||||
.unwrap_or(BitMap::new(validators.len() as u32));
|
||||
|
||||
let max_block_deviation = ONE_HOUR_MILLIS
|
||||
.saturating_mul(6) // TODO: make it constant or calculate
|
||||
.saturating_div(network_data.avg_block_speed);
|
||||
|
||||
let offence_bitmap = Self::capture_deviation_in_commitments_and_remove(
|
||||
&disabled_bitmap,
|
||||
&block_commitments,
|
||||
&validators,
|
||||
max_block_deviation,
|
||||
);
|
||||
|
||||
let offence_type = OffenceType::CommitmentOffence;
|
||||
let extra_weight = Self::try_offend_validators(
|
||||
&session_index,
|
||||
&validators,
|
||||
offence_bitmap,
|
||||
disabled_bitmap,
|
||||
offence_type,
|
||||
);
|
||||
|
||||
Self::deposit_event(Event::<T>::BlockCommitmentsCheck {
|
||||
block_number: current_block,
|
||||
network_id,
|
||||
});
|
||||
|
||||
weight = weight.saturating_add(extra_weight);
|
||||
}
|
||||
|
||||
weight
|
||||
}
|
||||
|
||||
fn offchain_worker(now: BlockNumberFor<T>) {
|
||||
match Self::start_slow_clapping(now) {
|
||||
Ok(_) => {
|
||||
@ -695,10 +762,6 @@ impl<T: Config> Pallet<T> {
|
||||
}
|
||||
|
||||
fn try_applause(clap: &Clap<T::AccountId, NetworkIdOf<T>, BalanceOf<T>>) -> DispatchResult {
|
||||
if T::NetworkDataHandler::is_nullification_period() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let commission = T::NetworkDataHandler::get(&clap.network_id)
|
||||
.map(|network_data| Perbill::from_parts(network_data.incoming_fee))
|
||||
.unwrap_or_default()
|
||||
@ -740,9 +803,7 @@ impl<T: Config> Pallet<T> {
|
||||
Error::<T>::CommitInWrongSession,
|
||||
);
|
||||
|
||||
let block_commitments = BlockCommitments::<T>::try_mutate(
|
||||
&network_id,
|
||||
|current_commitments| -> Result<BTreeMap<AuthIndex, CommitmentDetails>, DispatchError> {
|
||||
BlockCommitments::<T>::try_mutate(&network_id, |current_commitments| -> DispatchResult {
|
||||
let mut new_commitment_details = new_commitment.commitment;
|
||||
|
||||
let (current_commits, current_last_updated) = current_commitments
|
||||
@ -763,50 +824,14 @@ impl<T: Config> Pallet<T> {
|
||||
new_commitment_details.commits = current_commits;
|
||||
current_commitments.insert(authority_index, new_commitment_details);
|
||||
|
||||
Ok(current_commitments.clone())
|
||||
},
|
||||
)?;
|
||||
|
||||
let current_commits = block_commitments
|
||||
.get(&authority_index)
|
||||
.map(|details| details.commits)
|
||||
.unwrap_or(1);
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
Self::deposit_event(Event::<T>::BlockCommited {
|
||||
network_id,
|
||||
authority_id: authority_index,
|
||||
});
|
||||
|
||||
let validators = Validators::<T>::get(&session_index);
|
||||
let disabled_bitmap = DisabledAuthorityIndexes::<T>::get(&session_index)
|
||||
.unwrap_or(BitMap::new(validators.len() as u32));
|
||||
|
||||
let max_block_deviation = T::NetworkDataHandler::get(&network_id)
|
||||
.map(|network| {
|
||||
ONE_HOUR_MILLIS
|
||||
.saturating_mul(6)
|
||||
.saturating_div(network.avg_block_speed)
|
||||
})
|
||||
.unwrap_or_default();
|
||||
|
||||
if current_commits % 3 == 0 && validators.len() > 0 {
|
||||
let offence_bitmap = Self::capture_deviation_in_commitments_and_remove(
|
||||
&disabled_bitmap,
|
||||
&block_commitments,
|
||||
&validators,
|
||||
max_block_deviation,
|
||||
);
|
||||
|
||||
let offence_type = OffenceType::CommitmentOffence;
|
||||
Self::try_offend_validators(
|
||||
&session_index,
|
||||
&validators,
|
||||
offence_bitmap,
|
||||
disabled_bitmap,
|
||||
offence_type,
|
||||
);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -1394,7 +1419,7 @@ impl<T: Config> Pallet<T> {
|
||||
offence_bitmap: BitMap,
|
||||
disabled_bitmap: BitMap,
|
||||
offence_type: OffenceType,
|
||||
) {
|
||||
) -> Weight {
|
||||
let validator_set_count = validators.len() as u32;
|
||||
|
||||
let offenders = validators
|
||||
@ -1417,16 +1442,17 @@ impl<T: Config> Pallet<T> {
|
||||
|
||||
if not_enough_validators_left && offenders.len() > 0 {
|
||||
Self::deposit_event(Event::<T>::BlackSwan);
|
||||
return;
|
||||
return T::DbWeight::get().writes(1);
|
||||
}
|
||||
|
||||
if offenders.len() == 0 {
|
||||
let offenders_len = offenders.len() as u32;
|
||||
if offenders_len == 0 {
|
||||
let equilibrium_event = match offence_type {
|
||||
OffenceType::CommitmentOffence => Event::<T>::AuthoritiesCommitmentEquilibrium,
|
||||
OffenceType::ThrottlingOffence(_) => Event::<T>::AuthoritiesApplauseEquilibrium,
|
||||
};
|
||||
Self::deposit_event(equilibrium_event);
|
||||
return;
|
||||
return T::DbWeight::get().writes(1);
|
||||
}
|
||||
|
||||
let offence_event = match offence_type {
|
||||
@ -1460,6 +1486,8 @@ impl<T: Config> Pallet<T> {
|
||||
if let Err(e) = T::ReportUnresponsiveness::report_offence(reporters, offence) {
|
||||
sp_runtime::print(e);
|
||||
}
|
||||
|
||||
T::WeightInfo::try_offend_validators(offenders_len)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -130,6 +130,7 @@ parameter_types! {
|
||||
|
||||
parameter_types! {
|
||||
pub static MockAverageSessionLength: Option<u64> = None;
|
||||
pub const MaxNetworks: u32 = 5;
|
||||
}
|
||||
|
||||
impl ghost_networks::Config for Runtime {
|
||||
@ -139,6 +140,7 @@ impl ghost_networks::Config for Runtime {
|
||||
type RegisterOrigin = EnsureRoot<Self::AccountId>;
|
||||
type UpdateOrigin = EnsureRoot<Self::AccountId>;
|
||||
type RemoveOrigin = EnsureRoot<Self::AccountId>;
|
||||
type MaxNetworks = MaxNetworks;
|
||||
type WeightInfo = ();
|
||||
}
|
||||
|
||||
|
||||
@ -1,6 +1,9 @@
|
||||
#![cfg(test)]
|
||||
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
time::{SystemTime, UNIX_EPOCH},
|
||||
};
|
||||
|
||||
use super::*;
|
||||
use crate::evm_types::Log;
|
||||
@ -892,7 +895,6 @@ fn should_nullify_commission_on_finalize() {
|
||||
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::is_nullification_period(), false);
|
||||
assert_applaused(&session_index, &unique_hash);
|
||||
|
||||
assert_eq!(
|
||||
@ -903,63 +905,13 @@ fn should_nullify_commission_on_finalize() {
|
||||
),
|
||||
(amount, 0u64)
|
||||
); // precomputed values
|
||||
assert_eq!(Networks::is_nullification_period(), true);
|
||||
Networks::on_finalize(System::block_number());
|
||||
|
||||
assert_eq!(Networks::is_nullification_period(), false);
|
||||
assert_eq!(Networks::accumulated_commission(), 0);
|
||||
assert_ok!(do_clap_from(session_index, network_id, 3, false));
|
||||
assert_eq!(Networks::accumulated_commission(), 0);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_avoid_applause_during_nullification_period() {
|
||||
let zero: u64 = 0u64;
|
||||
let total_staked = 69_000_000;
|
||||
let total_issuance = 100_000_000;
|
||||
|
||||
let (network_id, _, unique_hash) = generate_unique_hash(None, None, None, None, None);
|
||||
let (_, receiver, amount, _) = get_mocked_metadata();
|
||||
|
||||
new_test_ext().execute_with(|| {
|
||||
let _ = prepare_evm_network(None, None);
|
||||
let session_index = advance_session_and_get_index();
|
||||
|
||||
assert_eq!(Networks::is_nullification_period(), false);
|
||||
assert_eq!(
|
||||
BridgedInflationCurve::<RewardCurve, Runtime>::era_payout(
|
||||
total_staked,
|
||||
total_issuance,
|
||||
zero
|
||||
),
|
||||
(zero, zero)
|
||||
);
|
||||
assert_eq!(Networks::is_nullification_period(), true);
|
||||
|
||||
assert_ok!(do_clap_from(session_index, network_id, 0, false));
|
||||
assert_ok!(do_clap_from(session_index, network_id, 1, false));
|
||||
assert_eq!(Balances::total_balance(&receiver), 0);
|
||||
assert_clapped(&session_index, &unique_hash, 0, true);
|
||||
assert_clapped(&session_index, &unique_hash, 1, true);
|
||||
assert_clapped(&session_index, &unique_hash, 2, false);
|
||||
assert_clapped(&session_index, &unique_hash, 3, false);
|
||||
|
||||
Networks::on_finalize(System::block_number());
|
||||
assert_eq!(Networks::is_nullification_period(), false);
|
||||
|
||||
assert_ok!(do_clap_from(session_index, network_id, 2, false));
|
||||
assert_ok!(do_clap_from(session_index, network_id, 3, false));
|
||||
assert_eq!(Balances::total_balance(&receiver), amount);
|
||||
|
||||
assert_applaused(&session_index, &unique_hash);
|
||||
assert_clapped(&session_index, &unique_hash, 0, true);
|
||||
assert_clapped(&session_index, &unique_hash, 1, true);
|
||||
assert_clapped(&session_index, &unique_hash, 2, true);
|
||||
assert_clapped(&session_index, &unique_hash, 3, true);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_avoid_session_overlap_on_mended_session_index() {
|
||||
let (network_id, _, unique_hash) = generate_unique_hash(None, None, None, None, None);
|
||||
@ -1194,6 +1146,7 @@ fn should_disable_on_commitment_inactivity() {
|
||||
}
|
||||
}
|
||||
|
||||
SlowClap::on_initialize(CHECK_BLOCK_INTERVAL);
|
||||
System::assert_has_event(RuntimeEvent::SlowClap(
|
||||
crate::Event::SomeAuthoritiesDelayed {
|
||||
delayed: vec![(3, 3)],
|
||||
@ -1259,6 +1212,7 @@ fn should_disable_on_commitment_block_deviation() {
|
||||
));
|
||||
}
|
||||
|
||||
SlowClap::on_initialize(CHECK_BLOCK_INTERVAL);
|
||||
System::assert_has_event(RuntimeEvent::SlowClap(
|
||||
crate::Event::SomeAuthoritiesDelayed {
|
||||
delayed: vec![(3, 3)],
|
||||
@ -1372,6 +1326,7 @@ fn should_not_offend_disabled_authorities() {
|
||||
}
|
||||
}
|
||||
|
||||
SlowClap::on_initialize(CHECK_BLOCK_INTERVAL);
|
||||
System::assert_has_event(RuntimeEvent::SlowClap(
|
||||
crate::Event::AuthoritiesCommitmentEquilibrium,
|
||||
));
|
||||
@ -1417,6 +1372,7 @@ fn should_not_slash_by_applause_if_disabled_by_commitment() {
|
||||
}
|
||||
}
|
||||
|
||||
SlowClap::on_initialize(CHECK_BLOCK_INTERVAL);
|
||||
System::assert_has_event(RuntimeEvent::SlowClap(
|
||||
crate::Event::AuthoritiesCommitmentEquilibrium,
|
||||
));
|
||||
@ -1501,6 +1457,7 @@ fn should_split_commit_slash_between_active_validators() {
|
||||
}
|
||||
}
|
||||
|
||||
SlowClap::on_initialize(CHECK_BLOCK_INTERVAL);
|
||||
System::assert_has_event(RuntimeEvent::SlowClap(
|
||||
crate::Event::SomeAuthoritiesDelayed {
|
||||
delayed: vec![(3, 3)],
|
||||
@ -1508,7 +1465,7 @@ fn should_split_commit_slash_between_active_validators() {
|
||||
));
|
||||
|
||||
let offences = Offences::get();
|
||||
assert_eq!(offences.len(), 3);
|
||||
assert_eq!(offences.len(), 1);
|
||||
for offence in offences {
|
||||
assert_eq!(offence.0, vec![0, 1, 2]);
|
||||
assert_eq!(offence.1.session_index, session_index);
|
||||
@ -1520,6 +1477,55 @@ fn should_split_commit_slash_between_active_validators() {
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_check_different_networks_during_on_initialize() {
|
||||
let times = 69;
|
||||
let networks_count = 3;
|
||||
|
||||
let mut check_commitment_events = HashMap::new();
|
||||
|
||||
new_test_ext().execute_with(|| {
|
||||
let _ = advance_session_and_get_index();
|
||||
for network_id in 0..networks_count {
|
||||
prepare_evm_network(Some(network_id), None);
|
||||
}
|
||||
|
||||
let check_interval = times * CHECK_BLOCK_INTERVAL;
|
||||
for check_block in 0..check_interval {
|
||||
SlowClap::on_initialize(check_block);
|
||||
}
|
||||
|
||||
let binding = System::events();
|
||||
let total_number_of_events = binding
|
||||
.iter()
|
||||
.filter(|x| {
|
||||
x.event == RuntimeEvent::SlowClap(crate::Event::AuthoritiesCommitmentEquilibrium)
|
||||
})
|
||||
.count();
|
||||
|
||||
binding
|
||||
.iter()
|
||||
.map(|record| record.event.clone())
|
||||
.for_each(|event| {
|
||||
if let RuntimeEvent::SlowClap(crate::Event::BlockCommitmentsCheck {
|
||||
network_id,
|
||||
..
|
||||
}) = event
|
||||
{
|
||||
*check_commitment_events.entry(network_id).or_insert(0) += 1;
|
||||
}
|
||||
});
|
||||
|
||||
let expected_events = networks_count * (times as u32);
|
||||
assert_eq!(total_number_of_events, expected_events as usize);
|
||||
assert_eq!(check_commitment_events.len() as u32, networks_count);
|
||||
for network_id in 0..networks_count {
|
||||
let network_id_count = check_commitment_events.get(&network_id).unwrap();
|
||||
assert_eq!(*network_id_count, times);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_check_responses_correctly() {
|
||||
new_test_ext().execute_with(|| {
|
||||
@ -1884,6 +1890,7 @@ fn evm_block_response(state: &mut testing::OffchainState) {
|
||||
headers: vec![
|
||||
("Accept".to_string(), "application/json".to_string()),
|
||||
("Content-Type".to_string(), "application/json".to_string()),
|
||||
("User-Agent".to_string(), "curl/8.9.0".to_string()),
|
||||
],
|
||||
response: Some(b"{\"id\":0,\"jsonrpc\":\"2.0\",\"result\":\"0x1364c81\"}".to_vec()),
|
||||
body: expected_body.clone(),
|
||||
@ -1897,6 +1904,7 @@ fn evm_block_response(state: &mut testing::OffchainState) {
|
||||
headers: vec![
|
||||
("Accept".to_string(), "application/json".to_string()),
|
||||
("Content-Type".to_string(), "application/json".to_string()),
|
||||
("User-Agent".to_string(), "curl/8.9.0".to_string()),
|
||||
],
|
||||
response: Some(b"{\"id\":0,\"jsonrpc\":\"2.0\",\"result\":\"0x1364c81\"}".to_vec()),
|
||||
body: expected_body,
|
||||
@ -1951,6 +1959,7 @@ fn evm_logs_response(state: &mut testing::OffchainState) {
|
||||
headers: vec![
|
||||
("Accept".to_string(), "application/json".to_string()),
|
||||
("Content-Type".to_string(), "application/json".to_string()),
|
||||
("User-Agent".to_string(), "curl/8.9.0".to_string()),
|
||||
],
|
||||
response_headers: vec![
|
||||
("Accept".to_string(), "application/json".to_string()),
|
||||
@ -1968,6 +1977,7 @@ fn evm_logs_response(state: &mut testing::OffchainState) {
|
||||
headers: vec![
|
||||
("Accept".to_string(), "application/json".to_string()),
|
||||
("Content-Type".to_string(), "application/json".to_string()),
|
||||
("User-Agent".to_string(), "curl/8.9.0".to_string()),
|
||||
],
|
||||
response_headers: vec![
|
||||
("Accept".to_string(), "application/json".to_string()),
|
||||
|
||||
@ -49,6 +49,7 @@ use core::marker::PhantomData;
|
||||
pub trait WeightInfo {
|
||||
fn slow_clap() -> Weight;
|
||||
fn commit_block()-> Weight;
|
||||
fn try_offend_validators(offenders_len: u32) -> Weight;
|
||||
}
|
||||
|
||||
impl WeightInfo for () {
|
||||
@ -86,4 +87,8 @@ impl WeightInfo for () {
|
||||
fn commit_block()-> Weight {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
fn try_offend_validators(offenders_len: u32) -> Weight {
|
||||
Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "ghost-traits"
|
||||
version = "0.3.27"
|
||||
version = "0.3.29"
|
||||
license.workspace = true
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
|
||||
@ -17,10 +17,9 @@ pub trait NetworkDataBasicHandler {
|
||||
|
||||
pub trait NetworkDataInspectHandler<Network>: NetworkDataBasicHandler {
|
||||
fn count() -> u32;
|
||||
fn next_network_for_block(b: impl Into<usize>) -> Option<(Self::NetworkId, Network)>;
|
||||
fn network_for_block(b: impl Into<usize>) -> Option<(Self::NetworkId, Network)>;
|
||||
fn get(n: &Self::NetworkId) -> Option<Network>;
|
||||
fn iter() -> PrefixIterator<(Self::NetworkId, Network)>;
|
||||
fn is_nullification_period() -> bool;
|
||||
}
|
||||
|
||||
pub trait NetworkDataMutateHandler<Network, Balance>: NetworkDataInspectHandler<Network> {
|
||||
@ -38,8 +37,5 @@ pub trait NetworkDataMutateHandler<Network, Balance>: NetworkDataInspectHandler<
|
||||
|
||||
fn accumulate_outgoing_imbalance(amount: &Balance) -> Result<Balance, ()>;
|
||||
fn accumulate_incoming_imbalance(amount: &Balance) -> Result<Balance, ()>;
|
||||
|
||||
fn accumulate_commission(commission: &Balance) -> Result<Balance, ()>;
|
||||
fn nullify_commission();
|
||||
fn trigger_nullification();
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user