resolve global dos vulnerability by isolating attested blocks per network
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
This commit is contained in:
parent
52a1aa0fab
commit
d43c616749
4
Cargo.lock
generated
4
Cargo.lock
generated
@ -1195,7 +1195,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "casper-runtime"
|
name = "casper-runtime"
|
||||||
version = "4.0.17"
|
version = "4.0.18"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"casper-runtime-constants",
|
"casper-runtime-constants",
|
||||||
"frame-benchmarking",
|
"frame-benchmarking",
|
||||||
@ -3762,7 +3762,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ghost-helpers"
|
name = "ghost-helpers"
|
||||||
version = "0.0.15"
|
version = "0.0.16"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"frame-support",
|
"frame-support",
|
||||||
"ghost-traits",
|
"ghost-traits",
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "ghost-helpers"
|
name = "ghost-helpers"
|
||||||
version = "0.0.15"
|
version = "0.0.16"
|
||||||
description = "Cryptographic utility suite for custom runtimes: optimized Bitmaps, UTXO parsing, Merkle Tree proofs, and Hash Chain components."
|
description = "Cryptographic utility suite for custom runtimes: optimized Bitmaps, UTXO parsing, Merkle Tree proofs, and Hash Chain components."
|
||||||
license.workspace = true
|
license.workspace = true
|
||||||
authors.workspace = true
|
authors.workspace = true
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
use ghost_traits::hashing::GhostHasher;
|
use ghost_traits::hashing::GhostHasher;
|
||||||
use sp_core::H256;
|
use sp_core::H256;
|
||||||
use sp_io::hashing::{blake2_256, keccak_256, sha2_256};
|
use sp_io::hashing::{blake2_256, keccak_256, sha2_256};
|
||||||
|
use sp_runtime::{Perbill, traits::{Saturating, UniqueSaturatedInto}};
|
||||||
|
|
||||||
pub mod bounded_bitmap;
|
pub mod bounded_bitmap;
|
||||||
pub mod hash_chain;
|
pub mod hash_chain;
|
||||||
@ -49,6 +50,34 @@ where
|
|||||||
value - f
|
value - f
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_submission_probability<B>(
|
||||||
|
participants_count: usize,
|
||||||
|
values_count: usize,
|
||||||
|
blocks_left: B
|
||||||
|
) -> Perbill
|
||||||
|
where
|
||||||
|
B: UniqueSaturatedInto<u32>,
|
||||||
|
{
|
||||||
|
// y = min(1, (1/6) + (A-C)/2x)
|
||||||
|
let a: u32 = participants_count.unique_saturated_into();
|
||||||
|
let c: u32 = values_count.unique_saturated_into();
|
||||||
|
let x: u32 = blocks_left.unique_saturated_into();
|
||||||
|
|
||||||
|
if a == 0 { return Perbill::zero(); }
|
||||||
|
|
||||||
|
let part_1 = Perbill::from_percent(6);
|
||||||
|
let part_2 = if x > 0 {
|
||||||
|
let numerator = a.saturating_sub(c);
|
||||||
|
let denominator = x.saturating_mul(2);
|
||||||
|
Perbill::from_rational(numerator, denominator)
|
||||||
|
} else {
|
||||||
|
if c < a { Perbill::one() }
|
||||||
|
else { Perbill::zero() }
|
||||||
|
};
|
||||||
|
|
||||||
|
part_1.saturating_add(part_2)
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! impl_ghost_hasher {
|
macro_rules! impl_ghost_hasher {
|
||||||
(
|
(
|
||||||
struct $name:ident;
|
struct $name:ident;
|
||||||
@ -155,4 +184,38 @@ mod tests {
|
|||||||
assert_eq!(get_byzantium_quorum_threshold(4u64), 3u64);
|
assert_eq!(get_byzantium_quorum_threshold(4u64), 3u64);
|
||||||
assert_eq!(get_byzantium_quorum_threshold(4usize), 3usize);
|
assert_eq!(get_byzantium_quorum_threshold(4usize), 3usize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_base_probability_when_plenty_of_time() {
|
||||||
|
let prob = get_submission_probability(100, 0, 10000u32);
|
||||||
|
assert!(prob > Perbill::from_percent(6));
|
||||||
|
assert!(prob < Perbill::from_percent(7));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_urgency_increases_as_blocks_shrink() {
|
||||||
|
let prob_far = get_submission_probability(20, 10, 10u32);
|
||||||
|
assert_eq!(prob_far, Perbill::from_percent(56));
|
||||||
|
|
||||||
|
let prob_close = get_submission_probability(20, 10, 2u32);
|
||||||
|
assert_eq!(prob_close, Perbill::one());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_deadline_reached_but_votes_missing() {
|
||||||
|
let prob = get_submission_probability(10, 5, 0u32);
|
||||||
|
assert_eq!(prob, Perbill::one());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_all_votes_collected() {
|
||||||
|
let prob = get_submission_probability(10, 10, 5u32);
|
||||||
|
assert_eq!(prob, Perbill::from_percent(6));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_zero_participants_edge_case() {
|
||||||
|
let prob = get_submission_probability(0, 0, 5u32);
|
||||||
|
assert_eq!(prob, Perbill::zero());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,13 +22,16 @@ use sp_runtime::{
|
|||||||
storage::StorageValueRef,
|
storage::StorageValueRef,
|
||||||
storage_lock::{StorageLock, Time},
|
storage_lock::{StorageLock, Time},
|
||||||
},
|
},
|
||||||
traits::{BlockNumberProvider, Saturating, UniqueSaturatedInto},
|
traits::{
|
||||||
RuntimeAppPublic,
|
TrailingZeroInput, BlockNumberProvider, Saturating,
|
||||||
|
UniqueSaturatedInto,
|
||||||
|
},
|
||||||
|
RuntimeAppPublic, Perbill, PerThing,
|
||||||
};
|
};
|
||||||
|
|
||||||
use ghost_helpers::{
|
use ghost_helpers::{
|
||||||
bounded_bitmap::{validate_bitmap_sizes, BoundedBitmap},
|
bounded_bitmap::{validate_bitmap_sizes, BoundedBitmap},
|
||||||
get_byzantium_quorum_threshold,
|
get_byzantium_quorum_threshold, get_submission_probability,
|
||||||
networks::{NetworkData, NetworkType},
|
networks::{NetworkData, NetworkType},
|
||||||
};
|
};
|
||||||
use ghost_traits::{
|
use ghost_traits::{
|
||||||
@ -39,6 +42,7 @@ use ghost_traits::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub mod migrations;
|
||||||
mod errors;
|
mod errors;
|
||||||
mod impls;
|
mod impls;
|
||||||
mod types;
|
mod types;
|
||||||
@ -99,7 +103,7 @@ type WeaversBitmap<T> = BoundedBitmap<BitmapChunk, <T as Config>::MaxAuthorities
|
|||||||
pub mod pallet {
|
pub mod pallet {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
const STORAGE_VERSION: StorageVersion = StorageVersion::new(0);
|
const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
|
||||||
|
|
||||||
#[pallet::pallet]
|
#[pallet::pallet]
|
||||||
#[pallet::storage_version(STORAGE_VERSION)]
|
#[pallet::storage_version(STORAGE_VERSION)]
|
||||||
@ -183,9 +187,10 @@ pub mod pallet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[pallet::storage]
|
#[pallet::storage]
|
||||||
#[pallet::getter(fn attested_blocks)]
|
#[pallet::getter(fn network_attested_blocks)]
|
||||||
pub(super) type AttestedBlocks<T: Config> = StorageMap<
|
pub(super) type NetworkAttestedBlocks<T: Config> = StorageDoubleMap<
|
||||||
_,
|
_,
|
||||||
|
Twox64Concat, NetworkIdOf<T>,
|
||||||
Twox64Concat, AuthIndex,
|
Twox64Concat, AuthIndex,
|
||||||
BlockNumberFor<T>,
|
BlockNumberFor<T>,
|
||||||
ValueQuery,
|
ValueQuery,
|
||||||
@ -356,7 +361,10 @@ pub mod pallet {
|
|||||||
})?;
|
})?;
|
||||||
|
|
||||||
let current_block = T::BlockNumberProvider::current_block_number();
|
let current_block = T::BlockNumberProvider::current_block_number();
|
||||||
AttestedBlocks::<T>::insert(&authority_index, current_block);
|
NetworkAttestedBlocks::<T>::insert(
|
||||||
|
&network_id, &authority_index,
|
||||||
|
current_block
|
||||||
|
);
|
||||||
|
|
||||||
Self::deposit_event(Event::<T>::BlockAttestated {
|
Self::deposit_event(Event::<T>::BlockAttestated {
|
||||||
network_id,
|
network_id,
|
||||||
@ -410,12 +418,19 @@ pub mod pallet {
|
|||||||
|
|
||||||
WeavingStates::<T>::mutate(&network_id, |weaving_state| {
|
WeavingStates::<T>::mutate(&network_id, |weaving_state| {
|
||||||
if weaving_state.count < weavers_count {
|
if weaving_state.count < weavers_count {
|
||||||
*weaving_state = WeavingState::new(root_hash, next_session, weavers_count);
|
*weaving_state = WeavingState::new(
|
||||||
|
root_hash,
|
||||||
|
next_session,
|
||||||
|
weavers_count
|
||||||
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let current_block = T::BlockNumberProvider::current_block_number();
|
let current_block = T::BlockNumberProvider::current_block_number();
|
||||||
AttestedBlocks::<T>::insert(&authority_index, current_block);
|
NetworkAttestedBlocks::<T>::insert(
|
||||||
|
&network_id, &authority_index,
|
||||||
|
current_block
|
||||||
|
);
|
||||||
|
|
||||||
Self::deposit_event(Event::<T>::HashAttestated {
|
Self::deposit_event(Event::<T>::HashAttestated {
|
||||||
authority_index,
|
authority_index,
|
||||||
@ -688,6 +703,41 @@ impl<T: Config> Pallet<T> {
|
|||||||
A: Encode,
|
A: Encode,
|
||||||
{
|
{
|
||||||
let authority_index = attestation.authority_index();
|
let authority_index = attestation.authority_index();
|
||||||
|
let network_id = attestation.network_id();
|
||||||
|
|
||||||
|
if !T::NetworkDataHandler::contains_key(&network_id) {
|
||||||
|
return Err(InvalidTransaction::BadProof);
|
||||||
|
}
|
||||||
|
|
||||||
|
let current_attestation_len =
|
||||||
|
NetworkAttestations::<T>::decode_len(&network_id).unwrap_or(0);
|
||||||
|
|
||||||
|
if authority_index as usize >= current_attestation_len {
|
||||||
|
return Err(InvalidTransaction::BadSigner.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
if DisabledAuthorities::<T>::get().contains(authority_index) {
|
||||||
|
return Err(InvalidTransaction::BadSigner);
|
||||||
|
}
|
||||||
|
|
||||||
|
let attestation_block = attestation.block();
|
||||||
|
let current_block = T::BlockNumberProvider::current_block_number();
|
||||||
|
let lock: BlockNumberFor<T> = LOCK_BLOCK_EXPIRATION.unique_saturated_into();
|
||||||
|
let block_expiration = attestation_block.saturating_add(lock);
|
||||||
|
|
||||||
|
if current_block >= block_expiration {
|
||||||
|
return Err(InvalidTransaction::Stale);
|
||||||
|
}
|
||||||
|
|
||||||
|
let last_attested = NetworkAttestedBlocks::<T>::get(
|
||||||
|
&network_id,
|
||||||
|
&authority_index
|
||||||
|
);
|
||||||
|
let cooling_off_until = last_attested.saturating_add(lock);
|
||||||
|
|
||||||
|
if attestation_block < cooling_off_until {
|
||||||
|
return Err(InvalidTransaction::Stale);
|
||||||
|
}
|
||||||
|
|
||||||
Authorities::<T>::get()
|
Authorities::<T>::get()
|
||||||
.get(authority_index as usize)
|
.get(authority_index as usize)
|
||||||
@ -699,35 +749,6 @@ impl<T: Config> Pallet<T> {
|
|||||||
.ok_or(InvalidTransaction::BadSigner)
|
.ok_or(InvalidTransaction::BadSigner)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let attestation_block = attestation.block();
|
|
||||||
let current_block = T::BlockNumberProvider::current_block_number();
|
|
||||||
let lock: BlockNumberFor<T> = LOCK_BLOCK_EXPIRATION.unique_saturated_into();
|
|
||||||
let block_expiration = attestation_block.saturating_add(lock);
|
|
||||||
|
|
||||||
let block_expired = current_block >= block_expiration;
|
|
||||||
let block_attested = AttestedBlocks::<T>::get(authority_index)
|
|
||||||
.ge(&attestation_block);
|
|
||||||
|
|
||||||
if block_expired || block_attested {
|
|
||||||
return Err(InvalidTransaction::BadProof);
|
|
||||||
}
|
|
||||||
|
|
||||||
let network_id = attestation.network_id();
|
|
||||||
let current_attestation_len = NetworkAttestations::<T>::decode_len(&network_id)
|
|
||||||
.unwrap_or(0);
|
|
||||||
|
|
||||||
if authority_index as usize >= current_attestation_len {
|
|
||||||
return Err(InvalidTransaction::BadSigner.into());
|
|
||||||
}
|
|
||||||
|
|
||||||
if DisabledAuthorities::<T>::get().contains(authority_index) {
|
|
||||||
return Err(InvalidTransaction::BadSigner);
|
|
||||||
}
|
|
||||||
|
|
||||||
if !T::NetworkDataHandler::contains_key(&network_id) {
|
|
||||||
return Err(InvalidTransaction::BadProof);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok((authority_index, network_id))
|
Ok((authority_index, network_id))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -780,14 +801,31 @@ impl<T: Config> Pallet<T> {
|
|||||||
return Err(WeavingError::NoEndpointsAvailable(network_id));
|
return Err(WeavingError::NoEndpointsAvailable(network_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let check_probability = |values_count: usize, blocks_left: BlockNumberFor<T>| -> bool {
|
||||||
|
let total_authorities = Authorities::<T>::decode_len().unwrap_or(1);
|
||||||
|
let submission_probability = get_submission_probability(
|
||||||
|
total_authorities,
|
||||||
|
values_count,
|
||||||
|
blocks_left,
|
||||||
|
);
|
||||||
|
|
||||||
|
let seed = sp_io::offchain::random_seed();
|
||||||
|
let randomness = <u32>::decode(&mut TrailingZeroInput::new(seed.as_ref()))
|
||||||
|
.expect("input is padded with zeroes; qed");
|
||||||
|
let random_roll = Perbill::from_parts(randomness % Perbill::ACCURACY);
|
||||||
|
|
||||||
|
random_roll > submission_probability
|
||||||
|
};
|
||||||
|
|
||||||
match TapestryDrafts::<T>::get(&network_id) {
|
match TapestryDrafts::<T>::get(&network_id) {
|
||||||
Some(tapestry_draft) => Self::try_request_and_submit_hash(
|
Some(tapestry_draft) => Self::try_request_and_submit_hash(
|
||||||
network_id,
|
network_id,
|
||||||
current_block,
|
current_block,
|
||||||
tapestry_draft.median,
|
tapestry_draft,
|
||||||
deadline,
|
deadline,
|
||||||
&network_data,
|
&network_data,
|
||||||
&rpc_endpoints,
|
&rpc_endpoints,
|
||||||
|
check_probability,
|
||||||
),
|
),
|
||||||
None => Self::try_request_and_submit_block(
|
None => Self::try_request_and_submit_block(
|
||||||
network_id,
|
network_id,
|
||||||
@ -795,6 +833,7 @@ impl<T: Config> Pallet<T> {
|
|||||||
deadline,
|
deadline,
|
||||||
&network_data,
|
&network_data,
|
||||||
&rpc_endpoints,
|
&rpc_endpoints,
|
||||||
|
check_probability,
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -802,13 +841,22 @@ impl<T: Config> Pallet<T> {
|
|||||||
fn try_request_and_submit_hash(
|
fn try_request_and_submit_hash(
|
||||||
network_id: NetworkIdOf<T>,
|
network_id: NetworkIdOf<T>,
|
||||||
current_block: BlockNumberFor<T>,
|
current_block: BlockNumberFor<T>,
|
||||||
target_block: ExternalBlockNumber,
|
tapestry_draft: TapestryDraft<BlockNumberFor<T>>,
|
||||||
deadline: rt_offchain::Timestamp,
|
deadline: rt_offchain::Timestamp,
|
||||||
network_data: &NetworkData,
|
network_data: &NetworkData,
|
||||||
rpc_endpoints: &Vec<Vec<u8>>,
|
rpc_endpoints: &Vec<Vec<u8>>,
|
||||||
|
check_probability: impl Fn(usize, BlockNumberFor<T>) -> bool,
|
||||||
) -> WeavingResult<T, WeavingOk<NetworkIdOf<T>>> {
|
) -> WeavingResult<T, WeavingOk<NetworkIdOf<T>>> {
|
||||||
let weaving_session = CurrentWeavingSession::<T>::get(&network_id);
|
let weaving_session = CurrentWeavingSession::<T>::get(&network_id);
|
||||||
|
|
||||||
|
let block_until = tapestry_draft.until.saturating_sub(current_block);
|
||||||
|
let weaving_count = WeavingStates::<T>::get(&network_id).count as usize;
|
||||||
|
|
||||||
|
if check_probability(weaving_count, block_until) {
|
||||||
|
return Ok(WeavingOk::Skipped(network_id));
|
||||||
|
}
|
||||||
|
|
||||||
|
let target_block = tapestry_draft.median;
|
||||||
let request_id = current_block.unique_saturated_into();
|
let request_id = current_block.unique_saturated_into();
|
||||||
|
|
||||||
let request_body = network_data.r#type.get_hash_request_body(
|
let request_body = network_data.r#type.get_hash_request_body(
|
||||||
@ -902,7 +950,20 @@ impl<T: Config> Pallet<T> {
|
|||||||
deadline: rt_offchain::Timestamp,
|
deadline: rt_offchain::Timestamp,
|
||||||
network_data: &NetworkData,
|
network_data: &NetworkData,
|
||||||
rpc_endpoints: &Vec<Vec<u8>>,
|
rpc_endpoints: &Vec<Vec<u8>>,
|
||||||
|
check_probability: impl Fn(usize, BlockNumberFor<T>) -> bool,
|
||||||
) -> WeavingResult<T, WeavingOk<NetworkIdOf<T>>> {
|
) -> WeavingResult<T, WeavingOk<NetworkIdOf<T>>> {
|
||||||
|
let next_attempt_block = NextConsensusAttemptBlocks::<T>::get(&network_id);
|
||||||
|
let block_until = next_attempt_block.saturating_sub(current_block);
|
||||||
|
|
||||||
|
let attestations_count = NetworkAttestations::<T>::get(&network_id)
|
||||||
|
.iter()
|
||||||
|
.flatten()
|
||||||
|
.count();
|
||||||
|
|
||||||
|
if check_probability(attestations_count, block_until) {
|
||||||
|
return Ok(WeavingOk::Skipped(network_id));
|
||||||
|
}
|
||||||
|
|
||||||
let network_id_encoded = network_id.encode();
|
let network_id_encoded = network_id.encode();
|
||||||
let distance_key = Self::create_storage_key(b"distance-", &network_id_encoded);
|
let distance_key = Self::create_storage_key(b"distance-", &network_id_encoded);
|
||||||
let block_deviation =
|
let block_deviation =
|
||||||
|
|||||||
9
pallets/weaver/src/migrations/mod.rs
Normal file
9
pallets/weaver/src/migrations/mod.rs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
pub mod v1;
|
||||||
|
|
||||||
|
pub type MigrateV0ToV1<T> = frame_support::migrations::VersionedMigration<
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
v1::RemoveAttestedBlocksStorage<T>,
|
||||||
|
crate::Pallet::<T>,
|
||||||
|
<T as frame_system::Config>::DbWeight,
|
||||||
|
>;
|
||||||
33
pallets/weaver/src/migrations/v1.rs
Normal file
33
pallets/weaver/src/migrations/v1.rs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
use frame_support::{
|
||||||
|
traits::{Get, UncheckedOnRuntimeUpgrade},
|
||||||
|
weights::Weight,
|
||||||
|
};
|
||||||
|
|
||||||
|
use core::marker::PhantomData;
|
||||||
|
use crate::{Config, LOG_TARGET};
|
||||||
|
|
||||||
|
pub struct RemoveAttestedBlocksStorage<T>(PhantomData<T>);
|
||||||
|
impl<T: Config> UncheckedOnRuntimeUpgrade for RemoveAttestedBlocksStorage<T> {
|
||||||
|
fn on_runtime_upgrade() -> Weight {
|
||||||
|
let clear_key = frame_support::storage::storage_prefix(
|
||||||
|
b"GhostWeaver",
|
||||||
|
b"AttestedBlocks"
|
||||||
|
);
|
||||||
|
|
||||||
|
let removal_results = frame_support::storage::unhashed::clear_prefix(
|
||||||
|
&clear_key,
|
||||||
|
None,
|
||||||
|
None
|
||||||
|
);
|
||||||
|
|
||||||
|
let killed_keys = removal_results.unique;
|
||||||
|
|
||||||
|
log::info!(
|
||||||
|
target: LOG_TARGET,
|
||||||
|
"🧹 Success: Purged deprecated AttestedBlocks storage. Wiped {} keys from Trie.",
|
||||||
|
killed_keys
|
||||||
|
);
|
||||||
|
|
||||||
|
T::DbWeight::get().reads_writes(1, killed_keys as u64)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,6 +1,6 @@
|
|||||||
#![cfg(test)]
|
#![cfg(test)]
|
||||||
|
|
||||||
use crate::sr25519::AuthorityPair;
|
use crate::{LOCK_BLOCK_EXPIRATION, sr25519::AuthorityPair};
|
||||||
|
|
||||||
use crate::mock::*;
|
use crate::mock::*;
|
||||||
use crate::pallet::*;
|
use crate::pallet::*;
|
||||||
@ -76,11 +76,11 @@ fn should_successfully_compute_median_and_start_weaving_round() {
|
|||||||
let networks = vec![(network_id, network_data, Default::default())];
|
let networks = vec![(network_id, network_data, Default::default())];
|
||||||
|
|
||||||
new_test_ext(authorities, networks).execute_with(|| {
|
new_test_ext(authorities, networks).execute_with(|| {
|
||||||
GhostWeaver::on_initialize(1);
|
GhostWeaver::on_initialize(LOCK_BLOCK_EXPIRATION + 1);
|
||||||
System::set_block_number(2);
|
System::set_block_number(LOCK_BLOCK_EXPIRATION + 2);
|
||||||
|
|
||||||
let context = AttestationContext::default()
|
let context = AttestationContext::default()
|
||||||
.with_current_block(1)
|
.with_current_block(LOCK_BLOCK_EXPIRATION + 1)
|
||||||
.with_network_id(network_id);
|
.with_network_id(network_id);
|
||||||
|
|
||||||
let att1 = context.with_authority_index(0).build_block_attestation(100);
|
let att1 = context.with_authority_index(0).build_block_attestation(100);
|
||||||
@ -97,12 +97,12 @@ fn should_successfully_compute_median_and_start_weaving_round() {
|
|||||||
|
|
||||||
assert!(GhostWeaver::tapestry_drafts(network_id).is_none());
|
assert!(GhostWeaver::tapestry_drafts(network_id).is_none());
|
||||||
|
|
||||||
System::set_block_number(3);
|
System::set_block_number(LOCK_BLOCK_EXPIRATION + 3);
|
||||||
GhostWeaver::on_initialize(3);
|
GhostWeaver::on_initialize(LOCK_BLOCK_EXPIRATION + 3);
|
||||||
|
|
||||||
let round = GhostWeaver::tapestry_drafts(network_id);
|
let round = GhostWeaver::tapestry_drafts(network_id);
|
||||||
assert!(round.is_some());
|
assert!(round.is_some());
|
||||||
assert_eq!(round.unwrap().until, 3 + WeavingDelay::get());
|
assert_eq!(round.unwrap().until, LOCK_BLOCK_EXPIRATION + 3 + WeavingDelay::get());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,11 +121,11 @@ fn should_apply_cooldown_delay_on_consensus_failure() {
|
|||||||
let networks = vec![(network_id, network_data, Default::default())];
|
let networks = vec![(network_id, network_data, Default::default())];
|
||||||
|
|
||||||
new_test_ext(authorities, networks).execute_with(|| {
|
new_test_ext(authorities, networks).execute_with(|| {
|
||||||
GhostWeaver::on_initialize(9);
|
GhostWeaver::on_initialize(LOCK_BLOCK_EXPIRATION + 9);
|
||||||
System::set_block_number(10);
|
System::set_block_number(LOCK_BLOCK_EXPIRATION + 10);
|
||||||
|
|
||||||
let context = AttestationContext::default()
|
let context = AttestationContext::default()
|
||||||
.with_current_block(9)
|
.with_current_block(LOCK_BLOCK_EXPIRATION + 9)
|
||||||
.with_network_id(network_id);
|
.with_network_id(network_id);
|
||||||
|
|
||||||
let att1 = context.with_authority_index(0).build_block_attestation(100);
|
let att1 = context.with_authority_index(0).build_block_attestation(100);
|
||||||
@ -140,20 +140,20 @@ fn should_apply_cooldown_delay_on_consensus_failure() {
|
|||||||
assert!(GhostWeaver::extend_warp(RuntimeOrigin::none(), att2, sig2).is_ok());
|
assert!(GhostWeaver::extend_warp(RuntimeOrigin::none(), att2, sig2).is_ok());
|
||||||
assert!(GhostWeaver::extend_warp(RuntimeOrigin::none(), att3, sig3).is_ok());
|
assert!(GhostWeaver::extend_warp(RuntimeOrigin::none(), att3, sig3).is_ok());
|
||||||
|
|
||||||
System::set_block_number(11);
|
System::set_block_number(LOCK_BLOCK_EXPIRATION + 11);
|
||||||
GhostWeaver::on_initialize(11);
|
GhostWeaver::on_initialize(LOCK_BLOCK_EXPIRATION + 11);
|
||||||
|
|
||||||
let cooldown_block = GhostWeaver::next_consensus_attempt_blocks(network_id);
|
let cooldown_block = GhostWeaver::next_consensus_attempt_blocks(network_id);
|
||||||
assert_eq!(cooldown_block, 14);
|
assert_eq!(cooldown_block, LOCK_BLOCK_EXPIRATION + 14);
|
||||||
|
|
||||||
TapestryDrafts::<TestRuntime>::remove(network_id);
|
TapestryDrafts::<TestRuntime>::remove(network_id);
|
||||||
|
|
||||||
System::set_block_number(12);
|
System::set_block_number(LOCK_BLOCK_EXPIRATION + 12);
|
||||||
GhostWeaver::on_initialize(12);
|
GhostWeaver::on_initialize(LOCK_BLOCK_EXPIRATION+ 12);
|
||||||
assert!(TapestryDrafts::<TestRuntime>::get(network_id).is_none());
|
assert!(TapestryDrafts::<TestRuntime>::get(network_id).is_none());
|
||||||
|
|
||||||
System::set_block_number(14);
|
System::set_block_number(LOCK_BLOCK_EXPIRATION + 14);
|
||||||
GhostWeaver::on_initialize(14);
|
GhostWeaver::on_initialize(LOCK_BLOCK_EXPIRATION + 14);
|
||||||
assert!(TapestryDrafts::<TestRuntime>::get(network_id).is_some());
|
assert!(TapestryDrafts::<TestRuntime>::get(network_id).is_some());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -170,11 +170,11 @@ fn validate_unsigned_should_prevent_mempool_dos_via_tags() {
|
|||||||
let networks = vec![(network_id, network_data, Default::default())];
|
let networks = vec![(network_id, network_data, Default::default())];
|
||||||
|
|
||||||
new_test_ext(authorities, networks).execute_with(|| {
|
new_test_ext(authorities, networks).execute_with(|| {
|
||||||
GhostWeaver::on_initialize(1);
|
GhostWeaver::on_initialize(LOCK_BLOCK_EXPIRATION + 1);
|
||||||
System::set_block_number(2);
|
System::set_block_number(LOCK_BLOCK_EXPIRATION + 2);
|
||||||
|
|
||||||
let att = AttestationContext::default()
|
let att = AttestationContext::default()
|
||||||
.with_current_block(1)
|
.with_current_block(LOCK_BLOCK_EXPIRATION + 1)
|
||||||
.with_network_id(network_id)
|
.with_network_id(network_id)
|
||||||
.with_authority_index(0)
|
.with_authority_index(0)
|
||||||
.build_block_attestation(100);
|
.build_block_attestation(100);
|
||||||
@ -187,7 +187,9 @@ fn validate_unsigned_should_prevent_mempool_dos_via_tags() {
|
|||||||
signature: valid_sig,
|
signature: valid_sig,
|
||||||
};
|
};
|
||||||
|
|
||||||
let validity = GhostWeaver::validate_unsigned(TransactionSource::External, &call);
|
let validity =
|
||||||
|
GhostWeaver::validate_unsigned(TransactionSource::External, &call);
|
||||||
|
|
||||||
assert!(validity.is_ok());
|
assert!(validity.is_ok());
|
||||||
let valid_info = validity.unwrap();
|
let valid_info = validity.unwrap();
|
||||||
|
|
||||||
@ -202,7 +204,9 @@ fn validate_unsigned_should_prevent_mempool_dos_via_tags() {
|
|||||||
signature: invalid_sig,
|
signature: invalid_sig,
|
||||||
};
|
};
|
||||||
|
|
||||||
let spam_validity = GhostWeaver::validate_unsigned(TransactionSource::External, &spam_call);
|
let spam_validity =
|
||||||
|
GhostWeaver::validate_unsigned(TransactionSource::External, &spam_call);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
spam_validity,
|
spam_validity,
|
||||||
Err(TransactionValidityError::Invalid(InvalidTransaction::BadSigner).into())
|
Err(TransactionValidityError::Invalid(InvalidTransaction::BadSigner).into())
|
||||||
@ -243,8 +247,8 @@ fn offchain_worker_should_fetch_block_and_submit_unsigned_tx() {
|
|||||||
ext.register_extension(TransactionPoolExt::new(pool));
|
ext.register_extension(TransactionPoolExt::new(pool));
|
||||||
|
|
||||||
ext.execute_with(|| {
|
ext.execute_with(|| {
|
||||||
GhostWeaver::on_initialize(1);
|
GhostWeaver::on_initialize(LOCK_BLOCK_EXPIRATION + 1);
|
||||||
GhostWeaver::on_initialize(2);
|
GhostWeaver::on_initialize(LOCK_BLOCK_EXPIRATION + 2);
|
||||||
|
|
||||||
let network_id_encoded = evm_network_id.encode();
|
let network_id_encoded = evm_network_id.encode();
|
||||||
|
|
||||||
@ -258,6 +262,7 @@ fn offchain_worker_should_fetch_block_and_submit_unsigned_tx() {
|
|||||||
|
|
||||||
let target_endpoint = b"http://localhost:8545".to_vec();
|
let target_endpoint = b"http://localhost:8545".to_vec();
|
||||||
let rpc_endpoints: Vec<Vec<u8>> = vec![target_endpoint.clone()];
|
let rpc_endpoints: Vec<Vec<u8>> = vec![target_endpoint.clone()];
|
||||||
|
|
||||||
sp_io::offchain::local_storage_set(
|
sp_io::offchain::local_storage_set(
|
||||||
sp_core::offchain::StorageKind::PERSISTENT,
|
sp_core::offchain::StorageKind::PERSISTENT,
|
||||||
&endpoint_key,
|
&endpoint_key,
|
||||||
@ -294,8 +299,8 @@ fn offchain_worker_should_fetch_block_and_submit_unsigned_tx() {
|
|||||||
("Accept".into(), "application/json".into()),
|
("Accept".into(), "application/json".into()),
|
||||||
("Content-Type".into(), "application/json".into()),
|
("Content-Type".into(), "application/json".into()),
|
||||||
],
|
],
|
||||||
body: b"{\"id\":1,\"jsonrpc\":\"2.0\",\"method\":\"getblockcount\"}".to_vec(),
|
body: b"{\"id\":21,\"jsonrpc\":\"2.0\",\"method\":\"getblockcount\"}".to_vec(),
|
||||||
response: Some(b"{\"jsonrpc\":\"2.0\",\"id\":1,\"result\":960127}".to_vec()),
|
response: Some(b"{\"jsonrpc\":\"2.0\",\"id\":21,\"result\":960127}".to_vec()),
|
||||||
sent: true,
|
sent: true,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
@ -309,16 +314,16 @@ fn offchain_worker_should_fetch_block_and_submit_unsigned_tx() {
|
|||||||
("X-Custom-Provider".into(), "GhostWeaverNode".into()),
|
("X-Custom-Provider".into(), "GhostWeaverNode".into()),
|
||||||
("Authorization".into(), "Bearer new-api-token-123".into()),
|
("Authorization".into(), "Bearer new-api-token-123".into()),
|
||||||
],
|
],
|
||||||
body: b"{\"id\":2,\"jsonrpc\":\"2.0\",\"method\":\"eth_blockNumber\"}".to_vec(),
|
body: b"{\"id\":22,\"jsonrpc\":\"2.0\",\"method\":\"eth_blockNumber\"}".to_vec(),
|
||||||
response: Some(b"{\"jsonrpc\":\"2.0\",\"id\":2,\"result\":\"0x1873a84\"}".to_vec()),
|
response: Some(b"{\"jsonrpc\":\"2.0\",\"id\":22,\"result\":\"0x1873a84\"}".to_vec()),
|
||||||
sent: true,
|
sent: true,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ext.execute_with(|| {
|
ext.execute_with(|| {
|
||||||
System::set_block_number(1u64);
|
System::set_block_number(LOCK_BLOCK_EXPIRATION + 1u64);
|
||||||
GhostWeaver::offchain_worker(1u64);
|
GhostWeaver::offchain_worker(LOCK_BLOCK_EXPIRATION + 1u64);
|
||||||
|
|
||||||
let state = pool_state.read();
|
let state = pool_state.read();
|
||||||
assert_eq!(state.transactions.len(), 1);
|
assert_eq!(state.transactions.len(), 1);
|
||||||
@ -339,13 +344,13 @@ fn offchain_worker_should_fetch_block_and_submit_unsigned_tx() {
|
|||||||
assert_eq!(curr_utxo_block, 960127);
|
assert_eq!(curr_utxo_block, 960127);
|
||||||
|
|
||||||
assert!(TapestryDrafts::<TestRuntime>::get(&utxo_network_id).is_none());
|
assert!(TapestryDrafts::<TestRuntime>::get(&utxo_network_id).is_none());
|
||||||
GhostWeaver::on_initialize(3u64);
|
GhostWeaver::on_initialize(LOCK_BLOCK_EXPIRATION + 3u64);
|
||||||
assert!(TapestryDrafts::<TestRuntime>::get(&utxo_network_id).is_some());
|
assert!(TapestryDrafts::<TestRuntime>::get(&utxo_network_id).is_some());
|
||||||
});
|
});
|
||||||
|
|
||||||
ext.execute_with(|| {
|
ext.execute_with(|| {
|
||||||
System::set_block_number(2u64);
|
System::set_block_number(LOCK_BLOCK_EXPIRATION + 2u64);
|
||||||
GhostWeaver::offchain_worker(2u64);
|
GhostWeaver::offchain_worker(LOCK_BLOCK_EXPIRATION + 2u64);
|
||||||
|
|
||||||
let state = pool_state.read();
|
let state = pool_state.read();
|
||||||
assert_eq!(state.transactions.len(), 2);
|
assert_eq!(state.transactions.len(), 2);
|
||||||
@ -366,8 +371,8 @@ fn offchain_worker_should_fetch_block_and_submit_unsigned_tx() {
|
|||||||
assert_eq!(curr_evm_block, 25639556);
|
assert_eq!(curr_evm_block, 25639556);
|
||||||
|
|
||||||
assert!(TapestryDrafts::<TestRuntime>::get(&evm_network_id).is_none());
|
assert!(TapestryDrafts::<TestRuntime>::get(&evm_network_id).is_none());
|
||||||
GhostWeaver::on_initialize(3u64);
|
GhostWeaver::on_initialize(LOCK_BLOCK_EXPIRATION + 3u64);
|
||||||
GhostWeaver::on_initialize(4u64);
|
GhostWeaver::on_initialize(LOCK_BLOCK_EXPIRATION + 4u64);
|
||||||
assert!(TapestryDrafts::<TestRuntime>::get(&evm_network_id).is_some());
|
assert!(TapestryDrafts::<TestRuntime>::get(&evm_network_id).is_some());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -414,8 +419,8 @@ fn offchain_worker_should_fetch_hash_and_submit_unsigned_tx() {
|
|||||||
ext.register_extension(TransactionPoolExt::new(pool));
|
ext.register_extension(TransactionPoolExt::new(pool));
|
||||||
|
|
||||||
ext.execute_with(|| {
|
ext.execute_with(|| {
|
||||||
GhostWeaver::on_initialize(1);
|
GhostWeaver::on_initialize(LOCK_BLOCK_EXPIRATION + 1);
|
||||||
GhostWeaver::on_initialize(2);
|
GhostWeaver::on_initialize(LOCK_BLOCK_EXPIRATION + 2);
|
||||||
|
|
||||||
let tapestry_draft = TapestryDraftBuilder::<crate::ExternalBlockNumber, u32>::default();
|
let tapestry_draft = TapestryDraftBuilder::<crate::ExternalBlockNumber, u32>::default();
|
||||||
let evm_tapestry_draft = tapestry_draft.with_median_external(median_evm_block).build();
|
let evm_tapestry_draft = tapestry_draft.with_median_external(median_evm_block).build();
|
||||||
@ -475,8 +480,8 @@ fn offchain_worker_should_fetch_hash_and_submit_unsigned_tx() {
|
|||||||
("Accept".into(), "application/json".into()),
|
("Accept".into(), "application/json".into()),
|
||||||
("Content-Type".into(), "application/json".into()),
|
("Content-Type".into(), "application/json".into()),
|
||||||
],
|
],
|
||||||
body: b"{\"id\":1,\"jsonrpc\":\"2.0\",\"method\":\"getblockhash\",\"params\":[960129]}".to_vec(),
|
body: b"{\"id\":21,\"jsonrpc\":\"2.0\",\"method\":\"getblockhash\",\"params\":[960129]}".to_vec(),
|
||||||
response: Some(b"{\"jsonrpc\":\"2.0\",\"id\":1,\"result\":\"0000000000000000000091c72779c83d76dfa8149e950f3a5287377a9708d5c1\"}".to_vec()),
|
response: Some(b"{\"jsonrpc\":\"2.0\",\"id\":21,\"result\":\"0000000000000000000091c72779c83d76dfa8149e950f3a5287377a9708d5c1\"}".to_vec()),
|
||||||
sent: true,
|
sent: true,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
@ -491,16 +496,16 @@ fn offchain_worker_should_fetch_hash_and_submit_unsigned_tx() {
|
|||||||
("Authorization".into(), "Bearer new-api-token-123".into()),
|
("Authorization".into(), "Bearer new-api-token-123".into()),
|
||||||
],
|
],
|
||||||
// Match the EXACT field order: data first, then to
|
// Match the EXACT field order: data first, then to
|
||||||
body: b"{\"id\":2,\"jsonrpc\":\"2.0\",\"method\":\"eth_call\",\"params\":[{\"data\":\"0x00000000000000000000000000000000000000000000000000000000000000450000000000000000000000000000000000000000000000000000000001873a84\",\"to\":\"0x02f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9\"},\"latest\"]}".to_vec(),
|
body: b"{\"id\":22,\"jsonrpc\":\"2.0\",\"method\":\"eth_call\",\"params\":[{\"data\":\"0x00000000000000000000000000000000000000000000000000000000000000450000000000000000000000000000000000000000000000000000000001873a84\",\"to\":\"0x02f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9\"},\"latest\"]}".to_vec(),
|
||||||
response: Some(b"{\"jsonrpc\":\"2.0\",\"id\":2,\"result\":\"0xf72b9ef0b66c8cc3952ffd11dc0b85f3b02e6edfa9236da400138f2fcba4668d0000000000000000000000000000000000000000000000000000000000000046\"}".to_vec()),
|
response: Some(b"{\"jsonrpc\":\"2.0\",\"id\":22,\"result\":\"0xf72b9ef0b66c8cc3952ffd11dc0b85f3b02e6edfa9236da400138f2fcba4668d0000000000000000000000000000000000000000000000000000000000000046\"}".to_vec()),
|
||||||
sent: true,
|
sent: true,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ext.execute_with(|| {
|
ext.execute_with(|| {
|
||||||
System::set_block_number(1u64);
|
System::set_block_number(LOCK_BLOCK_EXPIRATION + 1u64);
|
||||||
GhostWeaver::offchain_worker(1u64);
|
GhostWeaver::offchain_worker(LOCK_BLOCK_EXPIRATION + 1u64);
|
||||||
|
|
||||||
let state = pool_state.read();
|
let state = pool_state.read();
|
||||||
assert_eq!(state.transactions.len(), 1);
|
assert_eq!(state.transactions.len(), 1);
|
||||||
@ -533,8 +538,8 @@ fn offchain_worker_should_fetch_hash_and_submit_unsigned_tx() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
ext.execute_with(|| {
|
ext.execute_with(|| {
|
||||||
System::set_block_number(2u64);
|
System::set_block_number(LOCK_BLOCK_EXPIRATION + 2u64);
|
||||||
GhostWeaver::offchain_worker(2u64);
|
GhostWeaver::offchain_worker(LOCK_BLOCK_EXPIRATION + 2u64);
|
||||||
|
|
||||||
let state = pool_state.read();
|
let state = pool_state.read();
|
||||||
assert_eq!(state.transactions.len(), 2);
|
assert_eq!(state.transactions.len(), 2);
|
||||||
@ -557,8 +562,8 @@ fn offchain_worker_should_fetch_hash_and_submit_unsigned_tx() {
|
|||||||
assert_eq!(curr_weaving_state.hash, block_hash);
|
assert_eq!(curr_weaving_state.hash, block_hash);
|
||||||
|
|
||||||
let prev_state = LoomStates::<TestRuntime>::get(&evm_network_id, &evm_session);
|
let prev_state = LoomStates::<TestRuntime>::get(&evm_network_id, &evm_session);
|
||||||
GhostWeaver::on_initialize(3u64);
|
GhostWeaver::on_initialize(LOCK_BLOCK_EXPIRATION + 3u64);
|
||||||
GhostWeaver::on_initialize(4u64);
|
GhostWeaver::on_initialize(LOCK_BLOCK_EXPIRATION + 4u64);
|
||||||
let curr_state = LoomStates::<TestRuntime>::get(&evm_network_id, &evm_session);
|
let curr_state = LoomStates::<TestRuntime>::get(&evm_network_id, &evm_session);
|
||||||
|
|
||||||
assert_eq!(prev_state.root_hash, H256::default());
|
assert_eq!(prev_state.root_hash, H256::default());
|
||||||
@ -945,7 +950,8 @@ fn on_initialize_should_finalize_session_when_timeout_is_reached() {
|
|||||||
let networks = vec![(network_id, new_network_data, 0u64)];
|
let networks = vec![(network_id, new_network_data, 0u64)];
|
||||||
|
|
||||||
new_test_ext(authorities, networks).execute_with(|| {
|
new_test_ext(authorities, networks).execute_with(|| {
|
||||||
let current_substrate_block = 10;
|
let current_substrate_block = LOCK_BLOCK_EXPIRATION + 10;
|
||||||
|
|
||||||
GhostWeaver::on_initialize(current_substrate_block);
|
GhostWeaver::on_initialize(current_substrate_block);
|
||||||
System::set_block_number(current_substrate_block + 1);
|
System::set_block_number(current_substrate_block + 1);
|
||||||
|
|
||||||
@ -1018,7 +1024,7 @@ fn on_initialize_should_update_at_block_when_threshold_reached_with_same_hash()
|
|||||||
let networks = vec![(network_id, new_network_data, 0u64)];
|
let networks = vec![(network_id, new_network_data, 0u64)];
|
||||||
|
|
||||||
new_test_ext(authorities, networks).execute_with(|| {
|
new_test_ext(authorities, networks).execute_with(|| {
|
||||||
let current_substrate_block = 10;
|
let current_substrate_block = LOCK_BLOCK_EXPIRATION + 10;
|
||||||
let current_session = CurrentWeavingSession::<TestRuntime>::get(&network_id);
|
let current_session = CurrentWeavingSession::<TestRuntime>::get(&network_id);
|
||||||
|
|
||||||
let target_hash = H256::repeat_byte(0xAA);
|
let target_hash = H256::repeat_byte(0xAA);
|
||||||
|
|||||||
@ -36,6 +36,7 @@ const PROTOCOL_PREFIX: [u8; 7] = [0x69, 0x64, 0x2b, 0x5b, 0xb6, 0x66, 0xac];
|
|||||||
const PROTOCOL_PREFIX: [u8; 7] = [0x47, 0x48, 0x53, 0x54, 0x74, 0x6F, 0x3A];
|
const PROTOCOL_PREFIX: [u8; 7] = [0x47, 0x48, 0x53, 0x54, 0x74, 0x6F, 0x3A];
|
||||||
|
|
||||||
pub enum WeavingOk<NetworkId> {
|
pub enum WeavingOk<NetworkId> {
|
||||||
|
Skipped(NetworkId),
|
||||||
Block(ExternalBlockNumber, u32, NetworkId),
|
Block(ExternalBlockNumber, u32, NetworkId),
|
||||||
Hash(ExternalBlockNumber, H256, WeavingSession, NetworkId),
|
Hash(ExternalBlockNumber, H256, WeavingSession, NetworkId),
|
||||||
}
|
}
|
||||||
@ -46,6 +47,7 @@ where
|
|||||||
{
|
{
|
||||||
fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {
|
fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
|
Self::Skipped(network_id) => write!(fmt, "Submission step skipped for network: {:?} based on probability distribution.", network_id),
|
||||||
Self::Block(block, count, network_id) => write!(fmt, "Verified block height #{:?} for network: {:?} based on {} parsed requests.", block, network_id, count),
|
Self::Block(block, count, network_id) => write!(fmt, "Verified block height #{:?} for network: {:?} based on {} parsed requests.", block, network_id, count),
|
||||||
Self::Hash(block, hash, next_session, network_id) => write!(fmt, "Extracted Merkle Root {:?} (next session is {:?}) from block #{:?} for network: {:?}.", hash, next_session, block, network_id),
|
Self::Hash(block, hash, next_session, network_id) => write!(fmt, "Extracted Merkle Root {:?} (next session is {:?}) from block #{:?} for network: {:?}.", hash, next_session, block, network_id),
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "casper-runtime"
|
name = "casper-runtime"
|
||||||
version = "4.0.17"
|
version = "4.0.18"
|
||||||
build = "build.rs"
|
build = "build.rs"
|
||||||
description = "Runtime of the Casper Network"
|
description = "Runtime of the Casper Network"
|
||||||
edition.workspace = true
|
edition.workspace = true
|
||||||
|
|||||||
@ -124,7 +124,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
|
|||||||
spec_name: create_runtime_str!("casper"),
|
spec_name: create_runtime_str!("casper"),
|
||||||
impl_name: create_runtime_str!("casper-svengali"),
|
impl_name: create_runtime_str!("casper-svengali"),
|
||||||
authoring_version: 0,
|
authoring_version: 0,
|
||||||
spec_version: 10,
|
spec_version: 12,
|
||||||
impl_version: 0,
|
impl_version: 0,
|
||||||
apis: RUNTIME_API_VERSIONS,
|
apis: RUNTIME_API_VERSIONS,
|
||||||
transaction_version: 1,
|
transaction_version: 1,
|
||||||
@ -1035,7 +1035,9 @@ pub type SignedExtra = (
|
|||||||
|
|
||||||
/// All migrations that will run on the next runtime upgrade.
|
/// All migrations that will run on the next runtime upgrade.
|
||||||
/// Should be cleared after release.
|
/// Should be cleared after release.
|
||||||
pub type Migrations = ();
|
pub type Migrations = (
|
||||||
|
ghost_weaver::migrations::MigrateV0ToV1,
|
||||||
|
);
|
||||||
|
|
||||||
/// Unchecked extrinsic type as expected by this runtime.
|
/// Unchecked extrinsic type as expected by this runtime.
|
||||||
pub type UncheckedExtrinsic =
|
pub type UncheckedExtrinsic =
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user