Merge branch 'pallet-weaver' into pallet-combined
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
This commit is contained in:
commit
8e44a7f5d2
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "ghost-weaver"
|
||||
version = "0.0.16"
|
||||
version = "0.0.21"
|
||||
description = "Weaving a secure cryptographic tapestry across different external chains."
|
||||
license.workspace = true
|
||||
authors.workspace = true
|
||||
|
||||
@ -35,6 +35,9 @@ fn prepare_pallet<T: Config>(
|
||||
T::NetworkDataHandler::register(network_id, network_data)
|
||||
.expect("network should be valid for insertion");
|
||||
|
||||
let current_block = T::BlockNumberProvider::current_block_number();
|
||||
Pallet::<T>::on_initialize(current_block);
|
||||
|
||||
(network_id, authority, 0)
|
||||
}
|
||||
|
||||
@ -53,6 +56,7 @@ mod benchmarks {
|
||||
let block_attestation = AttestationContext::default()
|
||||
.with_network_id(network_id)
|
||||
.with_authority_index(authority_index)
|
||||
.with_current_block(1337u16.into())
|
||||
.build_block_attestation(420);
|
||||
|
||||
let signature = authority
|
||||
@ -101,6 +105,7 @@ mod benchmarks {
|
||||
.with_network_id(network_id)
|
||||
.with_weaving_session(weaving_session)
|
||||
.with_authority_index(authority_index)
|
||||
.with_current_block(1337u16.into())
|
||||
.build_hash_attestation(root_hash, next_session);
|
||||
|
||||
let signature = authority
|
||||
@ -320,9 +325,12 @@ mod benchmarks {
|
||||
let first_sha = sp_io::hashing::sha2_256(&last_header[..80]);
|
||||
let mut native_le = sp_io::hashing::sha2_256(&first_sha);
|
||||
native_le.reverse();
|
||||
let dynamic_trusted_root = H256::from(native_le);
|
||||
|
||||
LoomStates::<T>::insert(&network_id, &session, dynamic_trusted_root);
|
||||
let at_block = 420;
|
||||
let dynamic_trusted_root = H256::from(native_le);
|
||||
let loom_state = LoomState { at_block, root_hash: dynamic_trusted_root };
|
||||
|
||||
LoomStates::<T>::insert(&network_id, &session, loom_state);
|
||||
|
||||
let utxo_thread_proof = UtxoThreadProof::new(
|
||||
gettxproof_bytes,
|
||||
@ -360,8 +368,11 @@ mod benchmarks {
|
||||
let root_string =
|
||||
hex::decode("07f4a5ba4750d9ddfc080429287cbcbde7464aa2f8ae13feaade0dcb45ca6129")
|
||||
.expect("EVM Root hex should be valid");
|
||||
|
||||
let at_block = 420;
|
||||
let expected_root = H256::from_slice(&root_string);
|
||||
LoomStates::<T>::insert(&network_id, &session, expected_root);
|
||||
let loom_state = LoomState { at_block, root_hash: expected_root };
|
||||
LoomStates::<T>::insert(&network_id, &session, loom_state);
|
||||
|
||||
let receiver_32: [u8; 32] =
|
||||
hex::decode("0ae3ba32f8555fe3031461e2cb6feeadb67029ef7490b982824fc90751a4cb3e")
|
||||
|
||||
@ -22,7 +22,7 @@ use sp_runtime::{
|
||||
storage::StorageValueRef,
|
||||
storage_lock::{StorageLock, Time},
|
||||
},
|
||||
traits::{BlockNumberProvider, UniqueSaturatedInto},
|
||||
traits::{BlockNumberProvider, Saturating, UniqueSaturatedInto},
|
||||
RuntimeAppPublic,
|
||||
};
|
||||
|
||||
@ -182,6 +182,15 @@ pub mod pallet {
|
||||
CouldNotRegisterIncoming,
|
||||
}
|
||||
|
||||
#[pallet::storage]
|
||||
#[pallet::getter(fn attested_blocks)]
|
||||
pub(super) type AttestedBlocks<T: Config> = StorageMap<
|
||||
_,
|
||||
Twox64Concat, AuthIndex,
|
||||
BlockNumberFor<T>,
|
||||
ValueQuery,
|
||||
>;
|
||||
|
||||
#[pallet::storage]
|
||||
#[pallet::getter(fn current_weaving_session)]
|
||||
pub(super) type CurrentWeavingSession<T: Config> =
|
||||
@ -202,7 +211,7 @@ pub mod pallet {
|
||||
_,
|
||||
Twox64Concat, NetworkIdOf<T>,
|
||||
Twox64Concat, WeavingSession,
|
||||
H256,
|
||||
LoomState,
|
||||
ValueQuery,
|
||||
>;
|
||||
|
||||
@ -288,7 +297,12 @@ pub mod pallet {
|
||||
);
|
||||
return;
|
||||
}
|
||||
LoomStates::<T>::insert(&data.0, data.1, data.2);
|
||||
let initial_loom_state = LoomState {
|
||||
at_block: 0u16.into(),
|
||||
root_hash: data.2,
|
||||
};
|
||||
|
||||
LoomStates::<T>::insert(&data.0, data.1, initial_loom_state);
|
||||
});
|
||||
|
||||
if !self.authorities.is_empty() {
|
||||
@ -330,26 +344,20 @@ pub mod pallet {
|
||||
|
||||
let external_block = block_attestation.external_block;
|
||||
|
||||
let current_authorities_count = Authorities::<T>::decode_len().
|
||||
unwrap_or_default();
|
||||
|
||||
NetworkAttestations::<T>::try_mutate(
|
||||
&network_id,
|
||||
|attestations| -> DispatchResult {
|
||||
if attestations.is_empty() {
|
||||
attestations.bounded_resize(current_authorities_count, None);
|
||||
}
|
||||
let index = authority_index as usize;
|
||||
|
||||
ensure!(
|
||||
(authority_index as usize) < attestations.len(),
|
||||
Error::<T>::TooManyAttestations,
|
||||
);
|
||||
|
||||
attestations[authority_index as usize] = Some(external_block);
|
||||
ensure!(index < attestations.len(), Error::<T>::TooManyAttestations);
|
||||
attestations[index] = Some(external_block);
|
||||
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
let current_block = T::BlockNumberProvider::current_block_number();
|
||||
AttestedBlocks::<T>::insert(&authority_index, current_block);
|
||||
|
||||
Self::deposit_event(Event::<T>::BlockAttestated {
|
||||
network_id,
|
||||
authority_index,
|
||||
@ -406,6 +414,9 @@ pub mod pallet {
|
||||
}
|
||||
});
|
||||
|
||||
let current_block = T::BlockNumberProvider::current_block_number();
|
||||
AttestedBlocks::<T>::insert(&authority_index, current_block);
|
||||
|
||||
Self::deposit_event(Event::<T>::HashAttestated {
|
||||
authority_index,
|
||||
next_session,
|
||||
@ -438,7 +449,7 @@ pub mod pallet {
|
||||
let network_data = T::NetworkDataHandler::get(&network_id)
|
||||
.ok_or(Error::<T>::NonExistentNetworkId)?;
|
||||
|
||||
let root_hash = LoomStates::<T>::get(&network_id, &session);
|
||||
let state = LoomStates::<T>::get(&network_id, &session);
|
||||
let pulled_thread_key = thread_proof.get_unique_key(session, network_id);
|
||||
|
||||
ensure!(
|
||||
@ -447,7 +458,7 @@ pub mod pallet {
|
||||
);
|
||||
|
||||
let (receiver_account, amount) = thread_proof
|
||||
.verify_thread_proof(root_hash, network_id, &network_data.gatekeeper)
|
||||
.verify_thread_proof(state.root_hash, network_id, &network_data.gatekeeper)
|
||||
.ok_or(Error::<T>::InvalidMerkleProof)?;
|
||||
|
||||
let receiver_bytes: &[u8; 32] = receiver_account.as_ref();
|
||||
@ -504,11 +515,13 @@ pub mod pallet {
|
||||
let current_session = CurrentWeavingSession::<T>::get(&network_id);
|
||||
let loom_state_changed =
|
||||
LoomStates::<T>::mutate(&network_id, ¤t_session, |loom_state| {
|
||||
if *loom_state != weaving_state.hash && threshold_reached {
|
||||
*loom_state = weaving_state.hash;
|
||||
return true;
|
||||
}
|
||||
false
|
||||
if !threshold_reached { return false; }
|
||||
|
||||
let hash_changed = loom_state.root_hash != weaving_state.hash;
|
||||
loom_state.at_block = tapestry_draft.median;
|
||||
if hash_changed { loom_state.root_hash = weaving_state.hash; }
|
||||
|
||||
hash_changed
|
||||
});
|
||||
|
||||
if loom_state_changed && weaving_state.next_session != current_session {
|
||||
@ -518,8 +531,9 @@ pub mod pallet {
|
||||
CurrentWeavingSession::<T>::insert(&network_id, next_session);
|
||||
}
|
||||
|
||||
weight.saturating_accrue(T::DbWeight::get().writes(1));
|
||||
weight.saturating_accrue(T::DbWeight::get().writes(2));
|
||||
TapestryDrafts::<T>::remove(&network_id);
|
||||
WeavingStates::<T>::remove(&network_id);
|
||||
}
|
||||
}
|
||||
None => {
|
||||
@ -532,9 +546,11 @@ pub mod pallet {
|
||||
weight.saturating_accrue(T::DbWeight::get().reads(1));
|
||||
let attestation_len = NetworkAttestations::<T>::decode_len(&network_id);
|
||||
|
||||
if attestation_len.unwrap_or(0) > len {
|
||||
weight.saturating_accrue(T::DbWeight::get().writes(1));
|
||||
NetworkAttestations::<T>::remove(&network_id);
|
||||
if attestation_len.unwrap_or(0) != len {
|
||||
weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1));
|
||||
NetworkAttestations::<T>::mutate(&network_id, |attestations| {
|
||||
attestations.bounded_resize(len, None);
|
||||
});
|
||||
return weight;
|
||||
}
|
||||
|
||||
@ -616,6 +632,21 @@ pub mod pallet {
|
||||
.propagate(true)
|
||||
.build()
|
||||
}
|
||||
Call::pull_thread {
|
||||
network_id,
|
||||
session,
|
||||
thread_proof,
|
||||
} => {
|
||||
let thread_context =
|
||||
Self::validate_thread(network_id, session, thread_proof)?;
|
||||
|
||||
ValidTransaction::with_tag_prefix("WeaverThread")
|
||||
.priority(T::UnsignedPriority::get())
|
||||
.and_provides(thread_context.to_fixed_bytes())
|
||||
.longevity(LOCK_BLOCK_EXPIRATION)
|
||||
.propagate(true)
|
||||
.build()
|
||||
}
|
||||
_ => InvalidTransaction::Call.into(),
|
||||
}
|
||||
}
|
||||
@ -623,6 +654,31 @@ pub mod pallet {
|
||||
}
|
||||
|
||||
impl<T: Config> Pallet<T> {
|
||||
fn validate_thread(
|
||||
network_id: &NetworkIdOf<T>,
|
||||
session: &WeavingSession,
|
||||
thread_proof: &ThreadProof<BalanceOf<T>>,
|
||||
) -> Result<H256, InvalidTransaction> {
|
||||
let network_data = T::NetworkDataHandler::get(&network_id)
|
||||
.ok_or(InvalidTransaction::BadProof)?;
|
||||
|
||||
let root_hash = LoomStates::<T>::get(&network_id, &session).root_hash;
|
||||
if root_hash == Default::default() {
|
||||
return Err(InvalidTransaction::BadProof);
|
||||
}
|
||||
|
||||
thread_proof
|
||||
.verify_thread_proof(root_hash, *network_id, &network_data.gatekeeper)
|
||||
.ok_or(InvalidTransaction::BadProof)?;
|
||||
|
||||
let pulled_thread_key = thread_proof.get_unique_key(*session, *network_id);
|
||||
if PulledThreads::<T>::contains_key(&pulled_thread_key) {
|
||||
return Err(InvalidTransaction::Stale);
|
||||
}
|
||||
|
||||
Ok(pulled_thread_key)
|
||||
}
|
||||
|
||||
fn validate_attestation_signature<A>(
|
||||
attestation: &A,
|
||||
signature: &<T::AuthorityId as RuntimeAppPublic>::Signature,
|
||||
@ -632,16 +688,6 @@ impl<T: Config> Pallet<T> {
|
||||
A: Encode,
|
||||
{
|
||||
let authority_index = attestation.authority_index();
|
||||
let attestation_block = attestation.block();
|
||||
let network_id = attestation.network_id();
|
||||
|
||||
if DisabledAuthorities::<T>::get().contains(authority_index) {
|
||||
return Err(InvalidTransaction::BadSigner);
|
||||
}
|
||||
|
||||
if T::BlockNumberProvider::current_block_number() <= attestation_block {
|
||||
return Err(InvalidTransaction::BadProof);
|
||||
}
|
||||
|
||||
Authorities::<T>::get()
|
||||
.get(authority_index as usize)
|
||||
@ -653,6 +699,31 @@ impl<T: Config> Pallet<T> {
|
||||
.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);
|
||||
}
|
||||
|
||||
@ -76,6 +76,7 @@ fn should_successfully_compute_median_and_start_weaving_round() {
|
||||
let networks = vec![(network_id, network_data, Default::default())];
|
||||
|
||||
new_test_ext(authorities, networks).execute_with(|| {
|
||||
GhostWeaver::on_initialize(1);
|
||||
System::set_block_number(2);
|
||||
|
||||
let context = AttestationContext::default()
|
||||
@ -120,6 +121,7 @@ fn should_apply_cooldown_delay_on_consensus_failure() {
|
||||
let networks = vec![(network_id, network_data, Default::default())];
|
||||
|
||||
new_test_ext(authorities, networks).execute_with(|| {
|
||||
GhostWeaver::on_initialize(9);
|
||||
System::set_block_number(10);
|
||||
|
||||
let context = AttestationContext::default()
|
||||
@ -168,6 +170,7 @@ fn validate_unsigned_should_prevent_mempool_dos_via_tags() {
|
||||
let networks = vec![(network_id, network_data, Default::default())];
|
||||
|
||||
new_test_ext(authorities, networks).execute_with(|| {
|
||||
GhostWeaver::on_initialize(1);
|
||||
System::set_block_number(2);
|
||||
|
||||
let att = AttestationContext::default()
|
||||
@ -240,6 +243,9 @@ fn offchain_worker_should_fetch_block_and_submit_unsigned_tx() {
|
||||
ext.register_extension(TransactionPoolExt::new(pool));
|
||||
|
||||
ext.execute_with(|| {
|
||||
GhostWeaver::on_initialize(1);
|
||||
GhostWeaver::on_initialize(2);
|
||||
|
||||
let network_id_encoded = evm_network_id.encode();
|
||||
|
||||
let mut endpoint_key = b"ghost-weaver::".to_vec();
|
||||
@ -313,7 +319,6 @@ fn offchain_worker_should_fetch_block_and_submit_unsigned_tx() {
|
||||
ext.execute_with(|| {
|
||||
System::set_block_number(1u64);
|
||||
GhostWeaver::offchain_worker(1u64);
|
||||
System::set_block_number(2u64);
|
||||
|
||||
let state = pool_state.read();
|
||||
assert_eq!(state.transactions.len(), 1);
|
||||
@ -341,7 +346,6 @@ fn offchain_worker_should_fetch_block_and_submit_unsigned_tx() {
|
||||
ext.execute_with(|| {
|
||||
System::set_block_number(2u64);
|
||||
GhostWeaver::offchain_worker(2u64);
|
||||
System::set_block_number(3u64);
|
||||
|
||||
let state = pool_state.read();
|
||||
assert_eq!(state.transactions.len(), 2);
|
||||
@ -362,6 +366,7 @@ fn offchain_worker_should_fetch_block_and_submit_unsigned_tx() {
|
||||
assert_eq!(curr_evm_block, 25639556);
|
||||
|
||||
assert!(TapestryDrafts::<TestRuntime>::get(&evm_network_id).is_none());
|
||||
GhostWeaver::on_initialize(3u64);
|
||||
GhostWeaver::on_initialize(4u64);
|
||||
assert!(TapestryDrafts::<TestRuntime>::get(&evm_network_id).is_some());
|
||||
});
|
||||
@ -372,6 +377,9 @@ fn offchain_worker_should_fetch_hash_and_submit_unsigned_tx() {
|
||||
let evm_network_id = 1u32;
|
||||
let utxo_network_id = 69u32;
|
||||
|
||||
let median_utxo_block = 960129;
|
||||
let median_evm_block = 25639556;
|
||||
|
||||
let pair = AuthorityPair::from_string("//Alice", None).expect("Should be valid seed");
|
||||
|
||||
let new_evm_network_data = NetworkDataBuilder::default()
|
||||
@ -406,11 +414,12 @@ fn offchain_worker_should_fetch_hash_and_submit_unsigned_tx() {
|
||||
ext.register_extension(TransactionPoolExt::new(pool));
|
||||
|
||||
ext.execute_with(|| {
|
||||
GhostWeaver::on_initialize(1);
|
||||
GhostWeaver::on_initialize(2);
|
||||
|
||||
let tapestry_draft = TapestryDraftBuilder::<crate::ExternalBlockNumber, u32>::default();
|
||||
|
||||
let evm_tapestry_draft = tapestry_draft.with_median_external(25639556).build();
|
||||
|
||||
let utxo_tapestry_draft = tapestry_draft.with_median_external(960129).build();
|
||||
let evm_tapestry_draft = tapestry_draft.with_median_external(median_evm_block).build();
|
||||
let utxo_tapestry_draft = tapestry_draft.with_median_external(median_utxo_block).build();
|
||||
|
||||
CurrentWeavingSession::<TestRuntime>::insert(&evm_network_id, evm_session);
|
||||
CurrentWeavingSession::<TestRuntime>::insert(&utxo_network_id, utxo_session);
|
||||
@ -492,7 +501,6 @@ fn offchain_worker_should_fetch_hash_and_submit_unsigned_tx() {
|
||||
ext.execute_with(|| {
|
||||
System::set_block_number(1u64);
|
||||
GhostWeaver::offchain_worker(1u64);
|
||||
System::set_block_number(2u64);
|
||||
|
||||
let state = pool_state.read();
|
||||
assert_eq!(state.transactions.len(), 1);
|
||||
@ -518,14 +526,15 @@ fn offchain_worker_should_fetch_hash_and_submit_unsigned_tx() {
|
||||
GhostWeaver::on_initialize(3u64);
|
||||
let curr_state = LoomStates::<TestRuntime>::get(&utxo_network_id, &utxo_session);
|
||||
|
||||
assert_eq!(prev_state, H256::default());
|
||||
assert_eq!(curr_state, block_hash);
|
||||
assert_eq!(prev_state.root_hash, H256::default());
|
||||
assert_eq!(curr_state.root_hash, block_hash);
|
||||
assert_eq!(prev_state.at_block, 0);
|
||||
assert_eq!(curr_state.at_block, median_utxo_block);
|
||||
});
|
||||
|
||||
ext.execute_with(|| {
|
||||
System::set_block_number(2u64);
|
||||
GhostWeaver::offchain_worker(2u64);
|
||||
System::set_block_number(3u64);
|
||||
|
||||
let state = pool_state.read();
|
||||
assert_eq!(state.transactions.len(), 2);
|
||||
@ -542,17 +551,20 @@ fn offchain_worker_should_fetch_hash_and_submit_unsigned_tx() {
|
||||
assert_eq!(curr_weaving_state.next_session, evm_session + 1);
|
||||
|
||||
let bytes = hex::decode("f72b9ef0b66c8cc3952ffd11dc0b85f3b02e6edfa9236da400138f2fcba4668d")
|
||||
.expect("UTXO block hash should be valid");
|
||||
.expect("EVM block hash should be valid");
|
||||
let block_hash = H256::from_slice(&bytes);
|
||||
|
||||
assert_eq!(curr_weaving_state.hash, block_hash);
|
||||
|
||||
let prev_state = LoomStates::<TestRuntime>::get(&evm_network_id, &evm_session);
|
||||
GhostWeaver::on_initialize(3u64);
|
||||
GhostWeaver::on_initialize(4u64);
|
||||
let curr_state = LoomStates::<TestRuntime>::get(&evm_network_id, &evm_session);
|
||||
|
||||
assert_eq!(prev_state, H256::default());
|
||||
assert_eq!(curr_state, block_hash);
|
||||
assert_eq!(prev_state.root_hash, H256::default());
|
||||
assert_eq!(curr_state.root_hash, block_hash);
|
||||
assert_eq!(prev_state.at_block, 0);
|
||||
assert_eq!(curr_state.at_block, median_evm_block);
|
||||
});
|
||||
}
|
||||
|
||||
@ -635,14 +647,18 @@ fn should_successfully_pull_evm_thread_and_mint_currency() {
|
||||
];
|
||||
|
||||
new_test_ext(authorities, networks).execute_with(|| {
|
||||
GhostWeaver::on_initialize(1);
|
||||
|
||||
// https://sepolia.etherscan.io/address/0x7fec11e652f4d54e8cf11c4b52c360380332f2bd#readContract
|
||||
// getRoot: session 0, atBlock 11716130
|
||||
let session = 0;
|
||||
let root_string =
|
||||
hex::decode("07f4a5ba4750d9ddfc080429287cbcbde7464aa2f8ae13feaade0dcb45ca6129")
|
||||
.expect("Root hex should be valid");
|
||||
|
||||
let expected_root = H256::from_slice(&root_string);
|
||||
LoomStates::<TestRuntime>::insert(&network_id, &session, expected_root);
|
||||
let expected_loom_state = LoomState { at_block: 420, root_hash: expected_root };
|
||||
LoomStates::<TestRuntime>::insert(&network_id, &session, expected_loom_state);
|
||||
|
||||
let mut total_issuance = 0;
|
||||
|
||||
@ -755,7 +771,8 @@ fn should_successfully_pull_utxo_thread_and_mint_currency() {
|
||||
.expect("Bitcoin Root hex should be valid");
|
||||
|
||||
let expected_root = H256::from_slice(&block_hash);
|
||||
LoomStates::<TestRuntime>::insert(&network_id, &session, expected_root);
|
||||
let expected_loom_state = LoomState { at_block: 420, root_hash: expected_root };
|
||||
LoomStates::<TestRuntime>::insert(&network_id, &session, expected_loom_state);
|
||||
|
||||
let expected_receiver_bytes = hex::decode("1657090d02985f0cdb41436fe2d5a83a3acb1995d963a698e7e619e927bdcc5e").unwrap();
|
||||
let mut receiver_raw = [0u8; 32];
|
||||
@ -853,7 +870,8 @@ fn should_successfully_pull_utxo_thread_and_reject_nominal_varint_encoding() {
|
||||
.expect("Bitcoin Root hex should be valid");
|
||||
|
||||
let expected_root = H256::from_slice(&block_hash);
|
||||
LoomStates::<TestRuntime>::insert(&network_id, &session, expected_root);
|
||||
let expected_loom_state = LoomState { at_block: 420, root_hash: expected_root };
|
||||
LoomStates::<TestRuntime>::insert(&network_id, &session, expected_loom_state);
|
||||
|
||||
let expected_receiver_bytes = hex::decode("1657090d02985f0cdb41436fe2d5a83a3acb1995d963a698e7e619e927bdcc5e").unwrap();
|
||||
let mut receiver_raw = [0u8; 32];
|
||||
@ -928,6 +946,7 @@ fn on_initialize_should_finalize_session_when_timeout_is_reached() {
|
||||
|
||||
new_test_ext(authorities, networks).execute_with(|| {
|
||||
let current_substrate_block = 10;
|
||||
GhostWeaver::on_initialize(current_substrate_block);
|
||||
System::set_block_number(current_substrate_block + 1);
|
||||
|
||||
let tapestry_draft = TapestryDraftBuilder::default()
|
||||
@ -975,8 +994,96 @@ fn on_initialize_should_finalize_session_when_timeout_is_reached() {
|
||||
GhostWeaver::on_initialize(current_substrate_block);
|
||||
|
||||
let saved_loom = LoomStates::<TestRuntime>::get(&network_id, current_session);
|
||||
assert_ne!(saved_loom, target_hash);
|
||||
assert_eq!(saved_loom, saved_loom);
|
||||
assert_ne!(saved_loom.root_hash, target_hash);
|
||||
assert_eq!(saved_loom.at_block, 0);
|
||||
|
||||
let updated_session = CurrentWeavingSession::<TestRuntime>::get(&network_id);
|
||||
assert_eq!(updated_session, current_session);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn on_initialize_should_update_at_block_when_threshold_reached_with_same_hash() {
|
||||
let pair1 = AuthorityPair::from_string("//Alice", None).expect("Should be valid seed");
|
||||
let pair2 = AuthorityPair::from_string("//Bob", None).expect("Should be valid seed");
|
||||
let pair3 = AuthorityPair::from_string("//Charlie", None).expect("Should be valid seed");
|
||||
|
||||
let network_id = 1;
|
||||
|
||||
let new_network_data = NetworkDataBuilder::default()
|
||||
.with_network_type(NetworkType::Evm)
|
||||
.build();
|
||||
|
||||
let authorities = vec![pair1.clone(), pair2.clone(), pair3.clone()];
|
||||
let networks = vec![(network_id, new_network_data, 0u64)];
|
||||
|
||||
new_test_ext(authorities, networks).execute_with(|| {
|
||||
let current_substrate_block = 10;
|
||||
let current_session = CurrentWeavingSession::<TestRuntime>::get(&network_id);
|
||||
|
||||
let target_hash = H256::repeat_byte(0xAA);
|
||||
LoomStates::<TestRuntime>::insert(&network_id, ¤t_session, crate::LoomState {
|
||||
root_hash: target_hash,
|
||||
at_block: 0,
|
||||
});
|
||||
|
||||
System::set_block_number(current_substrate_block);
|
||||
GhostWeaver::on_initialize(current_substrate_block);
|
||||
|
||||
let tapestry_draft = TapestryDraftBuilder::default()
|
||||
.with_current_block(current_substrate_block)
|
||||
.with_block_delay(5u32)
|
||||
.with_median_external(100)
|
||||
.build();
|
||||
|
||||
TapestryDrafts::<TestRuntime>::insert(&network_id, tapestry_draft);
|
||||
|
||||
let attestation = AttestationContext::default()
|
||||
.with_current_block(current_substrate_block)
|
||||
.with_network_id(network_id)
|
||||
.with_weaving_session(current_session);
|
||||
|
||||
let hash_att1 = attestation
|
||||
.with_authority_index(0)
|
||||
.build_hash_attestation(target_hash, current_session);
|
||||
|
||||
let hash_att2 = attestation
|
||||
.with_authority_index(1)
|
||||
.build_hash_attestation(target_hash, current_session);
|
||||
|
||||
let hash_att3 = attestation
|
||||
.with_authority_index(2)
|
||||
.build_hash_attestation(target_hash, current_session);
|
||||
|
||||
assert!(GhostWeaver::weave_weft(
|
||||
RuntimeOrigin::none(),
|
||||
hash_att1,
|
||||
pair1.sign(&hash_att1.encode())
|
||||
)
|
||||
.is_ok());
|
||||
assert!(GhostWeaver::weave_weft(
|
||||
RuntimeOrigin::none(),
|
||||
hash_att2,
|
||||
pair2.sign(&hash_att2.encode())
|
||||
)
|
||||
.is_ok());
|
||||
assert!(GhostWeaver::weave_weft(
|
||||
RuntimeOrigin::none(),
|
||||
hash_att3,
|
||||
pair3.sign(&hash_att3.encode())
|
||||
)
|
||||
.is_ok());
|
||||
|
||||
let state_before = WeavingStates::<TestRuntime>::get(&network_id);
|
||||
assert_eq!(state_before.count, 3);
|
||||
assert_eq!(state_before.hash, target_hash);
|
||||
|
||||
GhostWeaver::on_initialize(current_substrate_block);
|
||||
|
||||
let saved_loom = LoomStates::<TestRuntime>::get(&network_id, current_session);
|
||||
|
||||
assert_eq!(saved_loom.root_hash, target_hash);
|
||||
assert_eq!(saved_loom.at_block, 100);
|
||||
|
||||
let updated_session = CurrentWeavingSession::<TestRuntime>::get(&network_id);
|
||||
assert_eq!(updated_session, current_session);
|
||||
|
||||
@ -14,7 +14,6 @@ use ghost_helpers::{
|
||||
merkle_tree::verify_tree_proof,
|
||||
SubstrateBlake2Hasher, SubstrateKeccakHasher, UtxoSha2Hasher,
|
||||
};
|
||||
use ghost_traits::hashing::GhostHasher;
|
||||
|
||||
use crate::{ExternalBlockNumber, ThreadId, WeavingSession};
|
||||
|
||||
@ -53,6 +52,25 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Default,
|
||||
RuntimeDebug,
|
||||
Clone,
|
||||
Copy,
|
||||
Eq,
|
||||
PartialEq,
|
||||
Ord,
|
||||
PartialOrd,
|
||||
Encode,
|
||||
Decode,
|
||||
TypeInfo,
|
||||
MaxEncodedLen,
|
||||
)]
|
||||
pub struct LoomState {
|
||||
pub at_block: ExternalBlockNumber,
|
||||
pub root_hash: H256,
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Default,
|
||||
RuntimeDebug,
|
||||
@ -350,8 +368,10 @@ where
|
||||
{
|
||||
if EVM_MERKLE_DEPTH as usize != self.proof.len() { return None; }
|
||||
|
||||
let preimage_hash = self.get_preimage_hash(network_id)?;
|
||||
|
||||
let proof_valid = verify_tree_proof::<SubstrateKeccakHasher, _>(
|
||||
&self.get_preimage_slice(network_id).to_fixed_bytes(),
|
||||
&preimage_hash.to_fixed_bytes(),
|
||||
self.proof.as_ref(),
|
||||
root_hash,
|
||||
self.proof_index,
|
||||
@ -362,22 +382,17 @@ where
|
||||
Some((self.receiver.clone(), self.amount))
|
||||
}
|
||||
|
||||
fn get_preimage_slice<NetworkId>(&self, network_id: NetworkId) -> H256
|
||||
fn get_preimage_hash<NetworkId>(&self, network_id: NetworkId) -> Option<H256>
|
||||
where
|
||||
NetworkId: Copy + Clone + Eq + PartialEq + UniqueSaturatedInto<u64>,
|
||||
{
|
||||
let slot_index_usize: usize = self.slot_index.unique_saturated_into();
|
||||
let mut slot_values: Vec<H256> = self.slots.to_vec();
|
||||
|
||||
match slot_values.get_mut(slot_index_usize) {
|
||||
Some(slot) => {
|
||||
*slot = self.compute_arguments_hash(network_id);
|
||||
cumulative_hash::<SubstrateKeccakHasher, _>(slot_values)
|
||||
}
|
||||
None => {
|
||||
SubstrateKeccakHasher::empty()
|
||||
}
|
||||
}
|
||||
self.slots.get(slot_index_usize)
|
||||
.filter(|&&provided_hash| {
|
||||
provided_hash == self.compute_arguments_hash(network_id)
|
||||
})
|
||||
.map(|_| cumulative_hash::<SubstrateKeccakHasher, _>(self.slots.iter()))
|
||||
}
|
||||
|
||||
pub fn get_unique_key<NetworkId>(
|
||||
|
||||
Loading…
Reference in New Issue
Block a user