From ba575d0ab8c7906a1f7706faa89593501f0475a9 Mon Sep 17 00:00:00 2001 From: Uncle Stinky Date: Wed, 21 Oct 2026 18:46:47 +0300 Subject: [PATCH] secure unsigned validation with help of sliding window Signed-off-by: Uncle Stinky --- pallets/weaver/Cargo.toml | 2 +- pallets/weaver/src/benchmarking.rs | 2 + pallets/weaver/src/lib.rs | 59 +++++++++++++++++++++--------- pallets/weaver/src/tests.rs | 6 +-- 4 files changed, 46 insertions(+), 23 deletions(-) diff --git a/pallets/weaver/Cargo.toml b/pallets/weaver/Cargo.toml index 1507fa2..c2aed44 100644 --- a/pallets/weaver/Cargo.toml +++ b/pallets/weaver/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ghost-weaver" -version = "0.0.19" +version = "0.0.20" description = "Weaving a secure cryptographic tapestry across different external chains." license.workspace = true authors.workspace = true diff --git a/pallets/weaver/src/benchmarking.rs b/pallets/weaver/src/benchmarking.rs index 37e01bb..5e047b8 100644 --- a/pallets/weaver/src/benchmarking.rs +++ b/pallets/weaver/src/benchmarking.rs @@ -56,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 @@ -104,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 diff --git a/pallets/weaver/src/lib.rs b/pallets/weaver/src/lib.rs index f8935bc..c92c456 100644 --- a/pallets/weaver/src/lib.rs +++ b/pallets/weaver/src/lib.rs @@ -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 = StorageMap< + _, + Twox64Concat, AuthIndex, + BlockNumberFor, + ValueQuery, + >; + #[pallet::storage] #[pallet::getter(fn current_weaving_session)] pub(super) type CurrentWeavingSession = @@ -341,6 +350,9 @@ pub mod pallet { Ok(()) })?; + let current_block = T::BlockNumberProvider::current_block_number(); + AttestedBlocks::::insert(&authority_index, current_block); + Self::deposit_event(Event::::BlockAttestated { network_id, authority_index, @@ -397,6 +409,9 @@ pub mod pallet { } }); + let current_block = T::BlockNumberProvider::current_block_number(); + AttestedBlocks::::insert(&authority_index, current_block); + Self::deposit_event(Event::::HashAttestated { authority_index, next_session, @@ -666,23 +681,6 @@ impl Pallet { A: Encode, { let authority_index = attestation.authority_index(); - let attestation_block = attestation.block(); - let network_id = attestation.network_id(); - - let current_attestation_len = NetworkAttestations::::decode_len(&network_id) - .unwrap_or(0); - - if authority_index as usize >= current_attestation_len { - return Err(InvalidTransaction::BadSigner.into()); - } - - if DisabledAuthorities::::get().contains(authority_index) { - return Err(InvalidTransaction::BadSigner); - } - - if T::BlockNumberProvider::current_block_number() <= attestation_block { - return Err(InvalidTransaction::BadProof); - } Authorities::::get() .get(authority_index as usize) @@ -694,6 +692,31 @@ impl Pallet { .ok_or(InvalidTransaction::BadSigner) })?; + let attestation_block = attestation.block(); + let current_block = T::BlockNumberProvider::current_block_number(); + let lock: BlockNumberFor = 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::::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::::decode_len(&network_id) + .unwrap_or(0); + + if authority_index as usize >= current_attestation_len { + return Err(InvalidTransaction::BadSigner.into()); + } + + if DisabledAuthorities::::get().contains(authority_index) { + return Err(InvalidTransaction::BadSigner); + } + if !T::NetworkDataHandler::contains_key(&network_id) { return Err(InvalidTransaction::BadProof); } diff --git a/pallets/weaver/src/tests.rs b/pallets/weaver/src/tests.rs index 82181c9..97fd8e4 100644 --- a/pallets/weaver/src/tests.rs +++ b/pallets/weaver/src/tests.rs @@ -319,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); @@ -347,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); @@ -368,6 +366,7 @@ fn offchain_worker_should_fetch_block_and_submit_unsigned_tx() { assert_eq!(curr_evm_block, 25639556); assert!(TapestryDrafts::::get(&evm_network_id).is_none()); + GhostWeaver::on_initialize(3u64); GhostWeaver::on_initialize(4u64); assert!(TapestryDrafts::::get(&evm_network_id).is_some()); }); @@ -499,7 +498,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); @@ -532,7 +530,6 @@ fn offchain_worker_should_fetch_hash_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); @@ -555,6 +552,7 @@ fn offchain_worker_should_fetch_hash_and_submit_unsigned_tx() { assert_eq!(curr_weaving_state.hash, block_hash); let prev_state = LoomStates::::get(&evm_network_id, &evm_session); + GhostWeaver::on_initialize(3u64); GhostWeaver::on_initialize(4u64); let curr_state = LoomStates::::get(&evm_network_id, &evm_session);