use internal block number as last_update for block commitments
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
This commit is contained in:
parent
f082dfc4e0
commit
028afc089f
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "ghost-slow-clap"
|
||||
version = "0.4.18"
|
||||
version = "0.4.19"
|
||||
description = "Applause protocol for the EVM bridge"
|
||||
license.workspace = true
|
||||
authors.workspace = true
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
use sp_runtime::SaturatedConversion;
|
||||
use sp_runtime::{traits::UniqueSaturatedInto, SaturatedConversion, Saturating};
|
||||
use sp_staking::SessionIndex;
|
||||
|
||||
use crate::{
|
||||
@ -6,9 +6,9 @@ use crate::{
|
||||
de_string_to_bytes, de_string_to_h256, de_string_to_u64, de_string_to_u64_pure,
|
||||
de_string_to_vec_of_bytes,
|
||||
},
|
||||
AuthIndex, BalanceOf, BlockCommitment, BlockCommitments, Call, Clap, CommitmentDetails, Config,
|
||||
AuthIndex, BalanceOf, BlockCommitment, BlockCommitments, BlockNumberFor, Call, Clap, Config,
|
||||
Decode, Deserialize, Encode, NetworkIdOf, RuntimeAppPublic, RuntimeDebug, SubmitTransaction,
|
||||
Vec, COMMITMENT_DELAY_MILLIS, H256, LOG_TARGET,
|
||||
Vec, BLOCK_COMMITMENT_DELAY, H256, LOG_TARGET,
|
||||
};
|
||||
|
||||
const NUMBER_OF_TOPICS: usize = 3;
|
||||
@ -46,26 +46,6 @@ pub struct Log {
|
||||
}
|
||||
|
||||
impl EvmResponseType {
|
||||
fn prepare_block_commitment<T: Config>(
|
||||
&self,
|
||||
from_block: u64,
|
||||
authority_index: AuthIndex,
|
||||
session_index: SessionIndex,
|
||||
network_id: NetworkIdOf<T>,
|
||||
) -> BlockCommitment<NetworkIdOf<T>> {
|
||||
let last_updated = sp_io::offchain::timestamp().unix_millis();
|
||||
BlockCommitment {
|
||||
session_index,
|
||||
authority_index,
|
||||
network_id,
|
||||
commitment: CommitmentDetails {
|
||||
last_stored_block: from_block,
|
||||
last_updated,
|
||||
commits: 420,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn prepare_clap<T: Config>(
|
||||
&self,
|
||||
authority_index: AuthIndex,
|
||||
@ -164,30 +144,30 @@ impl EvmResponseType {
|
||||
|
||||
fn sign_and_submit_block_commitment<T: Config>(
|
||||
&self,
|
||||
block_now: BlockNumberFor<T>,
|
||||
from_block: u64,
|
||||
authority_index: AuthIndex,
|
||||
authority_key: T::AuthorityId,
|
||||
session_index: SessionIndex,
|
||||
network_id: NetworkIdOf<T>,
|
||||
) {
|
||||
let block_commitment = self.prepare_block_commitment::<T>(
|
||||
from_block,
|
||||
authority_index,
|
||||
let block_commitment = BlockCommitment {
|
||||
session_index,
|
||||
authority_index,
|
||||
network_id,
|
||||
);
|
||||
last_stored_block: from_block,
|
||||
};
|
||||
|
||||
let stored_last_updated = BlockCommitments::<T>::get(&network_id)
|
||||
.get(&authority_index)
|
||||
.map(|details| details.last_updated)
|
||||
.map(|details| {
|
||||
details
|
||||
.last_updated
|
||||
.saturating_add(BLOCK_COMMITMENT_DELAY.unique_saturated_into())
|
||||
})
|
||||
.unwrap_or_default();
|
||||
|
||||
let current_last_updated = block_commitment
|
||||
.commitment
|
||||
.last_updated
|
||||
.saturating_sub(COMMITMENT_DELAY_MILLIS);
|
||||
|
||||
if current_last_updated < stored_last_updated {
|
||||
if block_now < stored_last_updated {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -229,6 +209,7 @@ impl EvmResponseType {
|
||||
|
||||
pub fn sign_and_submit<T: Config>(
|
||||
&self,
|
||||
block_now: BlockNumberFor<T>,
|
||||
from_block: u64,
|
||||
authority_index: AuthIndex,
|
||||
authority_key: T::AuthorityId,
|
||||
@ -243,6 +224,7 @@ impl EvmResponseType {
|
||||
network_id,
|
||||
),
|
||||
EvmResponseType::BlockNumber(_) => self.sign_and_submit_block_commitment::<T>(
|
||||
block_now,
|
||||
from_block,
|
||||
authority_index,
|
||||
authority_key,
|
||||
|
||||
@ -28,7 +28,7 @@ use sp_runtime::{
|
||||
storage::StorageValueRef,
|
||||
storage_lock::{StorageLock, Time},
|
||||
},
|
||||
traits::{BlockNumberProvider, Convert, Saturating, UniqueSaturatedInto},
|
||||
traits::{AtLeast32BitUnsigned, BlockNumberProvider, Convert, Saturating, UniqueSaturatedInto},
|
||||
Perbill, RuntimeAppPublic, RuntimeDebug,
|
||||
};
|
||||
use sp_staking::{
|
||||
@ -78,11 +78,13 @@ const MIN_LOCK_GUARD_PERIOD: u64 = 15_000;
|
||||
const FETCH_TIMEOUT_PERIOD: u64 = 3_000;
|
||||
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;
|
||||
const BLOCK_COMMITMENT_DELAY: u64 = 100;
|
||||
|
||||
pub type AuthIndex = u32;
|
||||
pub type ExternalBlockNumber = u64;
|
||||
|
||||
#[derive(
|
||||
RuntimeDebug,
|
||||
@ -98,10 +100,10 @@ pub type AuthIndex = u32;
|
||||
TypeInfo,
|
||||
MaxEncodedLen,
|
||||
)]
|
||||
pub struct CommitmentDetails {
|
||||
pub last_stored_block: u64,
|
||||
pub last_updated: u64,
|
||||
pub commits: u64,
|
||||
pub struct CommitmentDetails<BlockNumberFor> {
|
||||
pub last_stored_block: ExternalBlockNumber,
|
||||
pub last_updated: BlockNumberFor,
|
||||
pub commits: u8,
|
||||
}
|
||||
|
||||
#[derive(
|
||||
@ -111,7 +113,7 @@ pub struct BlockCommitment<NetworkId> {
|
||||
pub session_index: SessionIndex,
|
||||
pub authority_index: AuthIndex,
|
||||
pub network_id: NetworkId,
|
||||
pub commitment: CommitmentDetails,
|
||||
pub last_stored_block: ExternalBlockNumber,
|
||||
}
|
||||
|
||||
#[derive(
|
||||
@ -366,6 +368,7 @@ pub mod pallet {
|
||||
CouldNotIncreaseGatekeeperAmount,
|
||||
NonExistentAuthorityIndex,
|
||||
TimeWentBackwards,
|
||||
InnerTimeWentBackwards,
|
||||
DisabledAuthority,
|
||||
ExecutedBlockIsHigher,
|
||||
CommitInWrongSession,
|
||||
@ -386,7 +389,7 @@ pub mod pallet {
|
||||
_,
|
||||
Twox64Concat,
|
||||
NetworkIdOf<T>,
|
||||
BTreeMap<AuthIndex, CommitmentDetails>,
|
||||
BTreeMap<AuthIndex, CommitmentDetails<BlockNumberFor<T>>>,
|
||||
ValueQuery,
|
||||
>;
|
||||
|
||||
@ -495,28 +498,53 @@ pub mod pallet {
|
||||
{
|
||||
weight = weight.saturating_add(T::DbWeight::get().reads_writes(3, 1));
|
||||
|
||||
// TODO: put wrapper function with precalculated weight here
|
||||
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 {
|
||||
let validators_len = validators.len() as u32;
|
||||
|
||||
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
|
||||
let max_external_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(
|
||||
let mut stored_blocks: Vec<(AuthIndex, ExternalBlockNumber)> = Vec::new();
|
||||
let mut block_updates: Vec<(AuthIndex, BlockNumberFor<T>)> = Vec::new();
|
||||
|
||||
for authority_index in 0..validators_len {
|
||||
let data = block_commitments
|
||||
.get(&authority_index)
|
||||
.copied()
|
||||
.unwrap_or_default();
|
||||
stored_blocks.push((authority_index, data.last_stored_block));
|
||||
block_updates.push((authority_index, data.last_updated));
|
||||
}
|
||||
|
||||
let stored_blocks_offence_bitmap = Self::capture_deviation_in_commitments(
|
||||
&disabled_bitmap,
|
||||
&block_commitments,
|
||||
&validators,
|
||||
max_block_deviation,
|
||||
&mut stored_blocks,
|
||||
validators_len,
|
||||
max_external_block_deviation,
|
||||
);
|
||||
|
||||
let block_updates_offence_bitmap = Self::capture_deviation_in_commitments(
|
||||
&disabled_bitmap,
|
||||
&mut block_updates,
|
||||
validators_len,
|
||||
CHECK_BLOCK_INTERVAL.unique_saturated_into(), // TODO: revisit
|
||||
);
|
||||
|
||||
let offence_bitmap =
|
||||
stored_blocks_offence_bitmap.bitor(block_updates_offence_bitmap);
|
||||
|
||||
let offence_type = OffenceType::CommitmentOffence;
|
||||
let extra_weight = Self::try_offend_validators(
|
||||
&session_index,
|
||||
@ -572,7 +600,7 @@ pub mod pallet {
|
||||
|
||||
ValidTransaction::with_tag_prefix("SlowClap")
|
||||
.priority(T::UnsignedPriority::get())
|
||||
.and_provides(block_commitment.commitment.encode())
|
||||
.and_provides(block_commitment.encode())
|
||||
.longevity(LOCK_BLOCK_EXPIRATION)
|
||||
.propagate(true)
|
||||
.build()
|
||||
@ -782,10 +810,12 @@ impl<T: Config> Pallet<T> {
|
||||
fn try_commit_block(new_commitment: &BlockCommitment<NetworkIdOf<T>>) -> DispatchResult {
|
||||
let authority_index = new_commitment.authority_index;
|
||||
let network_id = new_commitment.network_id;
|
||||
|
||||
let session_index = T::ValidatorSet::session_index();
|
||||
let latest_executed_block = LatestExecutedBlock::<T>::get(&network_id);
|
||||
|
||||
ensure!(
|
||||
T::NetworkDataHandler::get(&network_id).is_some(),
|
||||
T::NetworkDataHandler::contains_key(&network_id),
|
||||
Error::<T>::UnregistedNetwork
|
||||
);
|
||||
|
||||
@ -795,24 +825,36 @@ impl<T: Config> Pallet<T> {
|
||||
);
|
||||
|
||||
BlockCommitments::<T>::try_mutate(&network_id, |current_commitments| -> DispatchResult {
|
||||
let mut new_commitment_details = new_commitment.commitment;
|
||||
let current_block_number = Self::current_block_number();
|
||||
|
||||
let (current_commits, current_last_updated) = current_commitments
|
||||
.get(&authority_index)
|
||||
.map(|details| {
|
||||
(
|
||||
details.commits.saturating_add(1),
|
||||
details.last_updated.saturating_add(COMMITMENT_DELAY_MILLIS),
|
||||
details
|
||||
.last_updated
|
||||
.saturating_add(BLOCK_COMMITMENT_DELAY.unique_saturated_into()),
|
||||
)
|
||||
})
|
||||
.unwrap_or((1, 0));
|
||||
.unwrap_or((1, Default::default()));
|
||||
|
||||
ensure!(
|
||||
new_commitment_details.last_updated > current_last_updated,
|
||||
Error::<T>::TimeWentBackwards
|
||||
current_block_number >= current_last_updated,
|
||||
Error::<T>::TimeWentBackwards,
|
||||
);
|
||||
|
||||
new_commitment_details.commits = current_commits;
|
||||
ensure!(
|
||||
new_commitment.last_stored_block > latest_executed_block,
|
||||
Error::<T>::InnerTimeWentBackwards,
|
||||
);
|
||||
|
||||
let new_commitment_details = CommitmentDetails {
|
||||
last_stored_block: new_commitment.last_stored_block,
|
||||
last_updated: Self::current_block_number(),
|
||||
commits: current_commits,
|
||||
};
|
||||
|
||||
current_commitments.insert(authority_index, new_commitment_details);
|
||||
|
||||
Ok(())
|
||||
@ -959,6 +1001,7 @@ impl<T: Config> Pallet<T> {
|
||||
|
||||
for (authority_index, authority_key) in Self::local_authorities(&session_index) {
|
||||
parsed_evm_response.sign_and_submit::<T>(
|
||||
block_number,
|
||||
new_block_range.0,
|
||||
authority_index,
|
||||
authority_key,
|
||||
@ -1275,6 +1318,7 @@ impl<T: Config> Pallet<T> {
|
||||
Authorities::<T>::set(&session_index, bounded_authorities);
|
||||
|
||||
let mut disabled_bitmap = BitMap::new(authorities_len as AuthIndex);
|
||||
// TODO: make me better
|
||||
for disabled_index in T::DisabledValidators::disabled_validators() {
|
||||
disabled_bitmap.set(disabled_index);
|
||||
}
|
||||
@ -1290,73 +1334,47 @@ impl<T: Config> Pallet<T> {
|
||||
debug_assert!(cursor.maybe_cursor.is_none());
|
||||
}
|
||||
|
||||
fn calculate_median_value(values: &mut Vec<(AuthIndex, u64)>) -> u64 {
|
||||
fn calculate_median_value<InnerValue>(values: &mut Vec<(AuthIndex, InnerValue)>) -> InnerValue
|
||||
where
|
||||
InnerValue: AtLeast32BitUnsigned + Copy,
|
||||
{
|
||||
values.sort_by_key(|data| data.1);
|
||||
|
||||
let length = values.len();
|
||||
if length % 2 == 0 {
|
||||
let mid_left = values[length / 2 - 1].1;
|
||||
let mid_right = values[length / 2].1;
|
||||
(mid_left + mid_right) / 2
|
||||
(mid_left + mid_right) / 2u32.into()
|
||||
} else {
|
||||
values[length / 2].1
|
||||
}
|
||||
}
|
||||
|
||||
fn apply_median_deviation(
|
||||
bitmap: &mut BitMap,
|
||||
disabled: &BitMap,
|
||||
values: &Vec<(AuthIndex, u64)>,
|
||||
median: u64,
|
||||
max_deviation: u64,
|
||||
) {
|
||||
values.iter().for_each(|(authority_index, value)| {
|
||||
if !disabled.exists(authority_index) && value.abs_diff(median) > max_deviation {
|
||||
bitmap.set(*authority_index);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn capture_deviation_in_commitments_and_remove(
|
||||
fn capture_deviation_in_commitments<InnerValue>(
|
||||
disabled_bitmap: &BitMap,
|
||||
block_commitments: &BTreeMap<AuthIndex, CommitmentDetails>,
|
||||
validators: &WeakBoundedVec<ValidatorId<T>, T::MaxAuthorities>,
|
||||
max_block_deviation: u64,
|
||||
) -> BitMap {
|
||||
let validators_len = validators.len() as u32;
|
||||
mut values: &mut Vec<(AuthIndex, InnerValue)>,
|
||||
validators_len: u32,
|
||||
max_deviation: InnerValue,
|
||||
) -> BitMap
|
||||
where
|
||||
InnerValue: AtLeast32BitUnsigned + Copy,
|
||||
{
|
||||
let mut delayed_bitmap = BitMap::new(validators_len);
|
||||
let median_value = Self::calculate_median_value(&mut values);
|
||||
|
||||
let mut delayed = BitMap::new(validators_len);
|
||||
let mut stored_blocks: Vec<(AuthIndex, u64)> = Vec::new();
|
||||
let mut time_updates: Vec<(AuthIndex, u64)> = Vec::new();
|
||||
values.iter().for_each(|(authority_index, value)| {
|
||||
let abs_diff = if *value > median_value {
|
||||
*value - median_value
|
||||
} else {
|
||||
median_value - *value
|
||||
};
|
||||
|
||||
for authority_index in 0..validators_len {
|
||||
let data = block_commitments
|
||||
.get(&authority_index)
|
||||
.copied()
|
||||
.unwrap_or_default();
|
||||
stored_blocks.push((authority_index, data.last_stored_block));
|
||||
time_updates.push((authority_index, data.last_updated));
|
||||
}
|
||||
if !disabled_bitmap.exists(authority_index) && abs_diff > max_deviation {
|
||||
delayed_bitmap.set(*authority_index);
|
||||
}
|
||||
});
|
||||
|
||||
let stored_block_median = Self::calculate_median_value(&mut stored_blocks);
|
||||
let time_update_median = Self::calculate_median_value(&mut time_updates);
|
||||
|
||||
Self::apply_median_deviation(
|
||||
&mut delayed,
|
||||
disabled_bitmap,
|
||||
&stored_blocks,
|
||||
stored_block_median,
|
||||
max_block_deviation,
|
||||
);
|
||||
Self::apply_median_deviation(
|
||||
&mut delayed,
|
||||
disabled_bitmap,
|
||||
&time_updates,
|
||||
time_update_median,
|
||||
ONE_HOUR_MILLIS,
|
||||
);
|
||||
|
||||
delayed
|
||||
delayed_bitmap
|
||||
}
|
||||
|
||||
fn get_cumulative_missing_clapped_amount(
|
||||
@ -1508,8 +1526,8 @@ impl<T: Config> OneSessionHandler<T::AccountId> for Pallet<T> {
|
||||
where
|
||||
I: Iterator<Item = (&'a T::AccountId, T::AuthorityId)>,
|
||||
{
|
||||
for (network_id, _) in BlockCommitments::<T>::iter() {
|
||||
BlockCommitments::<T>::remove(network_id);
|
||||
for network_id in T::NetworkDataHandler::iter_indexes() {
|
||||
BlockCommitments::<T>::remove(&network_id);
|
||||
}
|
||||
|
||||
let total_exposure = T::ExposureListener::get_total_exposure();
|
||||
|
||||
@ -1,9 +1,6 @@
|
||||
#![cfg(test)]
|
||||
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
time::{SystemTime, UNIX_EPOCH},
|
||||
};
|
||||
use std::collections::HashMap;
|
||||
|
||||
use super::*;
|
||||
use crate::evm_types::Log;
|
||||
@ -1064,47 +1061,38 @@ fn should_register_block_commitments() {
|
||||
let session_index = advance_session_and_get_index();
|
||||
prepare_evm_network(None, None);
|
||||
|
||||
for commitment_details in BlockCommitments::<Runtime>::get(network_id).values() {
|
||||
assert_eq!(commitment_details.last_stored_block, 0);
|
||||
assert_eq!(commitment_details.last_updated, 0);
|
||||
assert_eq!(commitment_details.commits, 0);
|
||||
}
|
||||
assert_eq!(BlockCommitments::<Runtime>::get(network_id).len(), 0);
|
||||
|
||||
let last_stored_block = 69;
|
||||
let current_block = SlowClap::current_block_number();
|
||||
|
||||
let mut block_commitment = CommitmentDetails {
|
||||
last_stored_block: 69,
|
||||
commits: 420,
|
||||
last_updated: 1337,
|
||||
};
|
||||
for i in 0..=3 {
|
||||
assert_ok!(do_block_commitment(
|
||||
session_index,
|
||||
network_id,
|
||||
i,
|
||||
&block_commitment
|
||||
last_stored_block,
|
||||
));
|
||||
}
|
||||
|
||||
block_commitment.last_updated = 1000;
|
||||
for i in 0..=3 {
|
||||
assert_err!(
|
||||
do_block_commitment(session_index, network_id, i, &block_commitment),
|
||||
do_block_commitment(session_index, network_id, i, last_stored_block),
|
||||
Error::<Runtime>::TimeWentBackwards,
|
||||
);
|
||||
}
|
||||
|
||||
for commitment_details in BlockCommitments::<Runtime>::get(network_id).values() {
|
||||
assert_eq!(commitment_details.last_stored_block, 69);
|
||||
assert_eq!(commitment_details.last_updated, 1337);
|
||||
assert_eq!(commitment_details.commits, 1);
|
||||
}
|
||||
let block_commitments = BlockCommitments::<Runtime>::get(network_id);
|
||||
assert_eq!(block_commitments.len(), 4);
|
||||
block_commitments.values().for_each(|details| {
|
||||
assert_eq!(details.last_stored_block, last_stored_block);
|
||||
assert_eq!(details.last_updated, current_block);
|
||||
assert_eq!(details.commits, 1);
|
||||
});
|
||||
|
||||
advance_session();
|
||||
|
||||
for commitment_details in BlockCommitments::<Runtime>::get(network_id).values() {
|
||||
assert_eq!(commitment_details.last_stored_block, 0);
|
||||
assert_eq!(commitment_details.last_updated, 0);
|
||||
assert_eq!(commitment_details.commits, 0);
|
||||
}
|
||||
assert_eq!(BlockCommitments::<Runtime>::get(network_id).len(), 0);
|
||||
});
|
||||
}
|
||||
|
||||
@ -1116,35 +1104,23 @@ fn should_disable_on_commitment_inactivity() {
|
||||
let session_index = advance_session_and_get_index();
|
||||
prepare_evm_network(None, None);
|
||||
|
||||
for commitment_details in BlockCommitments::<Runtime>::get(network_id).values() {
|
||||
assert_eq!(commitment_details.last_stored_block, 0);
|
||||
assert_eq!(commitment_details.last_updated, 0);
|
||||
assert_eq!(commitment_details.commits, 0);
|
||||
assert_eq!(BlockCommitments::<Runtime>::get(network_id).len(), 0);
|
||||
System::set_block_number(420);
|
||||
|
||||
let last_stored_block = 1337;
|
||||
let current_block = SlowClap::current_block_number();
|
||||
|
||||
for i in 0..3 {
|
||||
assert_ok!(do_block_commitment(
|
||||
session_index,
|
||||
network_id,
|
||||
i,
|
||||
last_stored_block,
|
||||
));
|
||||
}
|
||||
|
||||
let timestamp = SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.expect("Time went backwards")
|
||||
.as_millis() as u64;
|
||||
|
||||
let mut block_commitment = CommitmentDetails {
|
||||
last_stored_block: 69,
|
||||
commits: 420,
|
||||
last_updated: timestamp,
|
||||
};
|
||||
|
||||
// two block commitments
|
||||
for extra_time in 1..=3 {
|
||||
block_commitment.last_updated += COMMITMENT_DELAY_MILLIS + extra_time;
|
||||
for i in 0..3 {
|
||||
assert_ok!(do_block_commitment(
|
||||
session_index,
|
||||
network_id,
|
||||
i,
|
||||
&block_commitment
|
||||
));
|
||||
}
|
||||
}
|
||||
let delay = ONE_HOUR_MILLIS.saturating_mul(6);
|
||||
System::set_block_number(current_block + delay + 1);
|
||||
|
||||
SlowClap::on_initialize(CHECK_BLOCK_INTERVAL);
|
||||
System::assert_has_event(RuntimeEvent::SlowClap(
|
||||
@ -1153,12 +1129,50 @@ fn should_disable_on_commitment_inactivity() {
|
||||
},
|
||||
));
|
||||
|
||||
for commitment_details in BlockCommitments::<Runtime>::get(network_id)
|
||||
.values()
|
||||
.take(2)
|
||||
{
|
||||
assert_eq!(commitment_details.commits, 3);
|
||||
let block_commitments = BlockCommitments::<Runtime>::get(network_id);
|
||||
assert_eq!(block_commitments.get(&3), None);
|
||||
block_commitments.values().for_each(|details| {
|
||||
assert_eq!(details.commits, 1);
|
||||
assert_eq!(details.last_stored_block, last_stored_block);
|
||||
assert_eq!(details.last_updated, current_block);
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_ignore_commitments_below_latest_executed_block() {
|
||||
let (network_id, _, _) = generate_unique_hash(None, None, None, None, None);
|
||||
let (_, _, _, block_number) = get_mocked_metadata();
|
||||
|
||||
new_test_ext().execute_with(|| {
|
||||
let session_index = advance_session_and_get_index();
|
||||
prepare_evm_network(None, None);
|
||||
|
||||
assert_eq!(LatestExecutedBlock::<Runtime>::get(network_id), 0);
|
||||
assert_eq!(BlockCommitments::<Runtime>::get(network_id).len(), 0);
|
||||
|
||||
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_ok!(do_clap_from(session_index, network_id, 3, false));
|
||||
|
||||
let latest_executed_block = LatestExecutedBlock::<Runtime>::get(&network_id);
|
||||
assert_eq!(latest_executed_block, block_number);
|
||||
|
||||
for low_block in 0..=block_number {
|
||||
assert_err!(
|
||||
do_block_commitment(session_index, network_id, 0, low_block),
|
||||
Error::<Runtime>::InnerTimeWentBackwards,
|
||||
);
|
||||
}
|
||||
|
||||
let next_block_number = block_number.saturating_add(1);
|
||||
assert_ok!(do_block_commitment(
|
||||
session_index,
|
||||
network_id,
|
||||
0,
|
||||
next_block_number,
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
@ -1170,47 +1184,26 @@ fn should_disable_on_commitment_block_deviation() {
|
||||
let session_index = advance_session_and_get_index();
|
||||
prepare_evm_network(None, None);
|
||||
|
||||
for commitment_details in BlockCommitments::<Runtime>::get(network_id).values() {
|
||||
assert_eq!(commitment_details.last_stored_block, 0);
|
||||
assert_eq!(commitment_details.last_updated, 0);
|
||||
}
|
||||
assert_eq!(BlockCommitments::<Runtime>::get(network_id).len(), 0);
|
||||
|
||||
let timestamp = SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.expect("Time went backwards")
|
||||
.as_millis() as u64;
|
||||
let good_last_stored_block = 9_500_000;
|
||||
let bad_last_stored_block = 9_100_000;
|
||||
|
||||
let mut block_commitment = CommitmentDetails {
|
||||
last_stored_block: 9_500_000,
|
||||
commits: 420,
|
||||
last_updated: timestamp,
|
||||
};
|
||||
|
||||
let mut bad_block_commitment = CommitmentDetails {
|
||||
last_stored_block: 9_100_000,
|
||||
commits: 420,
|
||||
last_updated: timestamp,
|
||||
};
|
||||
|
||||
// two block commitments
|
||||
for extra_time in 1..=3 {
|
||||
block_commitment.last_updated += COMMITMENT_DELAY_MILLIS + extra_time;
|
||||
bad_block_commitment.last_updated += COMMITMENT_DELAY_MILLIS + extra_time;
|
||||
for i in 0..3 {
|
||||
assert_ok!(do_block_commitment(
|
||||
session_index,
|
||||
network_id,
|
||||
i,
|
||||
&block_commitment
|
||||
));
|
||||
}
|
||||
let current_block = SlowClap::current_block_number();
|
||||
for i in 0..3 {
|
||||
assert_ok!(do_block_commitment(
|
||||
session_index,
|
||||
network_id,
|
||||
3,
|
||||
&bad_block_commitment
|
||||
i,
|
||||
good_last_stored_block,
|
||||
));
|
||||
}
|
||||
assert_ok!(do_block_commitment(
|
||||
session_index,
|
||||
network_id,
|
||||
3,
|
||||
bad_last_stored_block,
|
||||
));
|
||||
|
||||
SlowClap::on_initialize(CHECK_BLOCK_INTERVAL);
|
||||
System::assert_has_event(RuntimeEvent::SlowClap(
|
||||
@ -1218,6 +1211,20 @@ fn should_disable_on_commitment_block_deviation() {
|
||||
delayed: vec![(3, 3)],
|
||||
},
|
||||
));
|
||||
|
||||
BlockCommitments::<Runtime>::get(network_id)
|
||||
.iter()
|
||||
.for_each(|(account_id, details)| {
|
||||
let block_to_be_stored = if *account_id == 3 {
|
||||
bad_last_stored_block
|
||||
} else {
|
||||
good_last_stored_block
|
||||
};
|
||||
|
||||
assert_eq!(details.commits, 1);
|
||||
assert_eq!(details.last_stored_block, block_to_be_stored);
|
||||
assert_eq!(details.last_updated, current_block);
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
@ -1229,107 +1236,50 @@ fn should_throw_error_on_fast_commitments() {
|
||||
let session_index = advance_session_and_get_index();
|
||||
prepare_evm_network(None, None);
|
||||
|
||||
let timestamp = SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.expect("Time went backwards")
|
||||
.as_millis() as u64;
|
||||
assert_eq!(BlockCommitments::<Runtime>::get(network_id).len(), 0);
|
||||
|
||||
let mut block_commitment = CommitmentDetails {
|
||||
last_stored_block: 9_500_000,
|
||||
commits: 420,
|
||||
last_updated: timestamp,
|
||||
};
|
||||
let last_stored_block = 9_500_000;
|
||||
let next_stored_block = 9_600_000;
|
||||
let current_block = SlowClap::current_block_number();
|
||||
|
||||
assert_ok!(do_block_commitment(
|
||||
session_index,
|
||||
network_id,
|
||||
0,
|
||||
&block_commitment
|
||||
last_stored_block,
|
||||
));
|
||||
assert_err!(
|
||||
do_block_commitment(session_index, network_id, 0, &block_commitment),
|
||||
do_block_commitment(session_index, network_id, 0, next_stored_block),
|
||||
Error::<Runtime>::TimeWentBackwards,
|
||||
);
|
||||
|
||||
block_commitment.last_updated += COMMITMENT_DELAY_MILLIS / 2;
|
||||
assert_err!(
|
||||
do_block_commitment(session_index, network_id, 0, &block_commitment),
|
||||
Error::<Runtime>::TimeWentBackwards,
|
||||
);
|
||||
BlockCommitments::<Runtime>::get(network_id)
|
||||
.get(&0)
|
||||
.map(|details| {
|
||||
assert_eq!(details.last_stored_block, last_stored_block);
|
||||
assert_eq!(details.last_updated, current_block);
|
||||
assert_eq!(details.commits, 1);
|
||||
})
|
||||
.expect("authority_index 0 has voted; qed");
|
||||
|
||||
block_commitment.last_updated += COMMITMENT_DELAY_MILLIS / 2;
|
||||
assert_err!(
|
||||
do_block_commitment(session_index, network_id, 0, &block_commitment),
|
||||
Error::<Runtime>::TimeWentBackwards,
|
||||
);
|
||||
System::set_block_number(current_block + BLOCK_COMMITMENT_DELAY);
|
||||
|
||||
block_commitment.last_updated += 1;
|
||||
let new_current_block = SlowClap::current_block_number();
|
||||
assert_ok!(do_block_commitment(
|
||||
session_index,
|
||||
network_id,
|
||||
0,
|
||||
&block_commitment
|
||||
next_stored_block,
|
||||
));
|
||||
|
||||
block_commitment.last_updated = timestamp;
|
||||
assert_err!(
|
||||
do_block_commitment(session_index, network_id, 0, &block_commitment),
|
||||
Error::<Runtime>::TimeWentBackwards,
|
||||
);
|
||||
|
||||
for commitment_details in BlockCommitments::<Runtime>::get(network_id).values() {
|
||||
assert_eq!(commitment_details.last_stored_block, 9_500_000);
|
||||
assert_eq!(
|
||||
commitment_details.last_updated,
|
||||
timestamp + COMMITMENT_DELAY_MILLIS + 1
|
||||
);
|
||||
assert_eq!(commitment_details.commits, 2);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_not_offend_disabled_authorities() {
|
||||
let (network_id, _, _) = generate_unique_hash(None, None, None, None, None);
|
||||
|
||||
new_test_ext().execute_with(|| {
|
||||
let session_index = advance_session_and_get_index();
|
||||
prepare_evm_network(None, None);
|
||||
|
||||
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));
|
||||
|
||||
let timestamp = SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.expect("Time went backwards")
|
||||
.as_millis() as u64;
|
||||
|
||||
let mut block_commitment = CommitmentDetails {
|
||||
last_stored_block: 9_500_000,
|
||||
commits: 420,
|
||||
last_updated: timestamp,
|
||||
};
|
||||
|
||||
Session::disable_index(3);
|
||||
|
||||
// two block commitments
|
||||
for extra_time in 1..=3 {
|
||||
block_commitment.last_updated += COMMITMENT_DELAY_MILLIS + extra_time;
|
||||
for i in 0..3 {
|
||||
assert_ok!(do_block_commitment(
|
||||
session_index,
|
||||
network_id,
|
||||
i,
|
||||
&block_commitment
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
SlowClap::on_initialize(CHECK_BLOCK_INTERVAL);
|
||||
System::assert_has_event(RuntimeEvent::SlowClap(
|
||||
crate::Event::AuthoritiesCommitmentEquilibrium,
|
||||
));
|
||||
BlockCommitments::<Runtime>::get(network_id)
|
||||
.get(&0)
|
||||
.map(|details| {
|
||||
assert_eq!(details.last_stored_block, next_stored_block);
|
||||
assert_eq!(details.last_updated, new_current_block);
|
||||
assert_eq!(details.commits, 2);
|
||||
})
|
||||
.expect("authority_index 0 has voted; qed");
|
||||
});
|
||||
}
|
||||
|
||||
@ -1341,83 +1291,90 @@ fn should_not_slash_by_applause_if_disabled_by_commitment() {
|
||||
let session_index = advance_session_and_get_index();
|
||||
prepare_evm_network(None, None);
|
||||
|
||||
for commitment_details in BlockCommitments::<Runtime>::get(network_id).values() {
|
||||
assert_eq!(commitment_details.last_stored_block, 0);
|
||||
assert_eq!(commitment_details.last_updated, 0);
|
||||
}
|
||||
assert_eq!(BlockCommitments::<Runtime>::get(network_id).len(), 0);
|
||||
|
||||
let timestamp = SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.expect("Time went backwards")
|
||||
.as_millis() as u64;
|
||||
|
||||
let mut block_commitment = CommitmentDetails {
|
||||
last_stored_block: 9_500_000,
|
||||
commits: 420,
|
||||
last_updated: timestamp,
|
||||
};
|
||||
let last_stored_block = 9_500_000;
|
||||
let current_block = SlowClap::current_block_number();
|
||||
let mut disabled_bitmp = BitMap::new(4);
|
||||
|
||||
assert_eq!(
|
||||
DisabledAuthorityIndexes::<Runtime>::get(&session_index),
|
||||
Some(disabled_bitmp.clone())
|
||||
);
|
||||
Session::disable_index(3);
|
||||
disabled_bitmp.set(3);
|
||||
assert_eq!(
|
||||
DisabledAuthorityIndexes::<Runtime>::get(&session_index),
|
||||
Some(disabled_bitmp.clone())
|
||||
);
|
||||
|
||||
// two block commitments
|
||||
for extra_time in 1..=3 {
|
||||
block_commitment.last_updated += COMMITMENT_DELAY_MILLIS + extra_time;
|
||||
for i in 0..3 {
|
||||
assert_ok!(do_block_commitment(
|
||||
session_index,
|
||||
network_id,
|
||||
i,
|
||||
&block_commitment
|
||||
));
|
||||
}
|
||||
for i in 0..=3 {
|
||||
assert_ok!(do_block_commitment(
|
||||
session_index,
|
||||
network_id,
|
||||
i,
|
||||
last_stored_block,
|
||||
));
|
||||
}
|
||||
|
||||
SlowClap::on_initialize(CHECK_BLOCK_INTERVAL);
|
||||
System::assert_has_event(RuntimeEvent::SlowClap(
|
||||
crate::Event::AuthoritiesCommitmentEquilibrium,
|
||||
));
|
||||
|
||||
let block_commitments = BlockCommitments::<Runtime>::get(network_id);
|
||||
assert_eq!(
|
||||
DisabledAuthorityIndexes::<Runtime>::get(&session_index),
|
||||
Some(disabled_bitmp)
|
||||
);
|
||||
assert_eq!(block_commitments.len(), 4);
|
||||
block_commitments.values().for_each(|details| {
|
||||
assert_eq!(details.last_stored_block, last_stored_block);
|
||||
assert_eq!(details.last_updated, current_block);
|
||||
assert_eq!(details.commits, 1);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_not_nullify_on_incorrect_block_commitment() {
|
||||
fn should_not_register_block_commitment_on_old_blocks() {
|
||||
let (network_id, _, _) = generate_unique_hash(None, None, None, None, None);
|
||||
|
||||
new_test_ext().execute_with(|| {
|
||||
let session_index = advance_session_and_get_index();
|
||||
prepare_evm_network(None, None);
|
||||
|
||||
let timestamp = SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.expect("Time went backwards")
|
||||
.as_millis() as u64;
|
||||
assert_eq!(BlockCommitments::<Runtime>::get(network_id).len(), 0);
|
||||
|
||||
let mut block_commitment = CommitmentDetails {
|
||||
last_stored_block: 9_500_000,
|
||||
commits: 420,
|
||||
last_updated: timestamp,
|
||||
};
|
||||
let very_old_block = 9_499_999;
|
||||
let last_stored_block = 9_500_000;
|
||||
let current_block = SlowClap::current_block_number();
|
||||
|
||||
for i in 0..4 {
|
||||
assert_ok!(do_block_commitment(
|
||||
session_index,
|
||||
network_id,
|
||||
i,
|
||||
&block_commitment
|
||||
last_stored_block,
|
||||
));
|
||||
}
|
||||
|
||||
block_commitment.last_updated = 0;
|
||||
assert_err!(
|
||||
do_block_commitment(session_index, network_id, 3, &block_commitment),
|
||||
do_block_commitment(session_index, network_id, 3, last_stored_block),
|
||||
Error::<Runtime>::TimeWentBackwards
|
||||
);
|
||||
assert_err!(
|
||||
do_block_commitment(session_index, network_id, 3, very_old_block),
|
||||
Error::<Runtime>::TimeWentBackwards
|
||||
);
|
||||
|
||||
for commitment_details in BlockCommitments::<Runtime>::get(network_id).values() {
|
||||
assert_eq!(commitment_details.last_stored_block, 9_500_000);
|
||||
assert_eq!(commitment_details.last_updated, timestamp);
|
||||
assert_eq!(commitment_details.commits, 1);
|
||||
}
|
||||
BlockCommitments::<Runtime>::get(network_id)
|
||||
.values()
|
||||
.for_each(|details| {
|
||||
assert_eq!(details.commits, 1);
|
||||
assert_eq!(details.last_stored_block, last_stored_block);
|
||||
assert_eq!(details.last_updated, current_block);
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
@ -1429,33 +1386,21 @@ fn should_split_commit_slash_between_active_validators() {
|
||||
let session_index = advance_session_and_get_index();
|
||||
prepare_evm_network(None, None);
|
||||
|
||||
let timestamp = SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.expect("Time went backwards")
|
||||
.as_millis() as u64;
|
||||
assert_eq!(BlockCommitments::<Runtime>::get(network_id).len(), 0);
|
||||
|
||||
let mut block_commitment = CommitmentDetails {
|
||||
last_stored_block: 9_500_000,
|
||||
commits: 420,
|
||||
last_updated: timestamp,
|
||||
};
|
||||
let last_stored_block = 9_500_000;
|
||||
let current_block = SlowClap::current_block_number();
|
||||
|
||||
for extra_time in 1..=3 {
|
||||
if extra_time < 3 {
|
||||
let offences = Offences::get();
|
||||
assert_eq!(offences.len(), 0);
|
||||
}
|
||||
|
||||
block_commitment.last_updated += COMMITMENT_DELAY_MILLIS + extra_time;
|
||||
for i in 0..3 {
|
||||
assert_ok!(do_block_commitment(
|
||||
session_index,
|
||||
network_id,
|
||||
i,
|
||||
&block_commitment
|
||||
));
|
||||
}
|
||||
for i in 0..3 {
|
||||
assert_ok!(do_block_commitment(
|
||||
session_index,
|
||||
network_id,
|
||||
i,
|
||||
last_stored_block,
|
||||
));
|
||||
}
|
||||
let offences = Offences::get();
|
||||
assert_eq!(offences.len(), 0);
|
||||
|
||||
SlowClap::on_initialize(CHECK_BLOCK_INTERVAL);
|
||||
System::assert_has_event(RuntimeEvent::SlowClap(
|
||||
@ -1471,9 +1416,16 @@ fn should_split_commit_slash_between_active_validators() {
|
||||
assert_eq!(offence.1.session_index, session_index);
|
||||
assert_eq!(offence.1.validator_set_count, 4);
|
||||
assert_eq!(offence.1.offenders, vec![(3, 3)]);
|
||||
assert_eq!(offence.1.validator_set_count, 4);
|
||||
assert_eq!(offence.1.offence_type, OffenceType::CommitmentOffence);
|
||||
}
|
||||
|
||||
let block_commitments = BlockCommitments::<Runtime>::get(network_id);
|
||||
assert_eq!(block_commitments.get(&3), None);
|
||||
block_commitments.values().for_each(|details| {
|
||||
assert_eq!(details.last_stored_block, last_stored_block);
|
||||
assert_eq!(details.last_updated, current_block);
|
||||
assert_eq!(details.commits, 1);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@ -1720,13 +1672,13 @@ fn do_block_commitment(
|
||||
session_index: u32,
|
||||
network_id: u32,
|
||||
authority_index: u32,
|
||||
commitment: &CommitmentDetails,
|
||||
last_stored_block: ExternalBlockNumber,
|
||||
) -> dispatch::DispatchResult {
|
||||
let block_commitment = BlockCommitment {
|
||||
session_index,
|
||||
authority_index,
|
||||
network_id,
|
||||
commitment: *commitment,
|
||||
last_stored_block,
|
||||
};
|
||||
let authority = UintAuthorityId::from(authority_index as u64);
|
||||
let signature = authority.sign(&block_commitment.encode()).unwrap();
|
||||
|
||||
Loading…
Reference in New Issue
Block a user