From 414604f2967c0e0366539052a7340060b032424e Mon Sep 17 00:00:00 2001 From: Uncle Stinky Date: Wed, 16 Sep 2026 14:10:12 +0300 Subject: [PATCH] inject the network ID into the hash chain and the arguments hash Signed-off-by: Uncle Stinky --- pallets/weaver/Cargo.toml | 2 +- pallets/weaver/src/benchmarking.rs | 34 ++--- pallets/weaver/src/lib.rs | 4 +- pallets/weaver/src/tests.rs | 207 ++++++----------------------- pallets/weaver/src/types.rs | 160 ++++++++++++++-------- 5 files changed, 165 insertions(+), 242 deletions(-) diff --git a/pallets/weaver/Cargo.toml b/pallets/weaver/Cargo.toml index d3ec3a0..1f976e9 100644 --- a/pallets/weaver/Cargo.toml +++ b/pallets/weaver/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ghost-weaver" -version = "0.0.8" +version = "0.0.9" 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 8e6d1f7..bdca0bc 100644 --- a/pallets/weaver/src/benchmarking.rs +++ b/pallets/weaver/src/benchmarking.rs @@ -8,7 +8,8 @@ use sp_std::vec; use ghost_helpers::networks::NetworkDataBuilder; fn prepare_pallet( - authorities_len: u32 + authorities_len: u32, + maybe_network_id: Option, ) -> (NetworkIdOf, T::AuthorityId, AuthIndex) { let authority = T::AuthorityId::generate_pair(None); let authorities = vec![authority.clone(); authorities_len as usize]; @@ -18,7 +19,9 @@ fn prepare_pallet( Authorities::::put(bounded_authorities); - let network_id = NetworkIdOf::::default(); + let network_id_u64 = maybe_network_id.unwrap_or_default(); + let network_id: NetworkIdOf = network_id_u64.unique_saturated_into(); + let network_data = NetworkDataBuilder::default() .with_network_type(NetworkType::Utxo) .with_gatekeeper( @@ -42,7 +45,7 @@ mod benchmarks { fn extend_warp( a: Linear<1, { T::MaxAuthorities::get() as u32 }>, ) -> Result<(), BenchmarkError> { - let (network_id, authority, authority_index) = prepare_pallet::(a); + let (network_id, authority, authority_index) = prepare_pallet::(a, None); TapestryDrafts::::remove(&network_id); @@ -73,7 +76,7 @@ mod benchmarks { let next_session = weaving_session + 1; let root_hash = H256::repeat_byte(0x69); - let (network_id, authority, authority_index) = prepare_pallet::(a); + let (network_id, authority, authority_index) = prepare_pallet::(a, None); let tapestry_key = (network_id, weaving_session, next_session, root_hash); TapestryStrands::::mutate(&tapestry_key, |tapestry| { @@ -139,7 +142,7 @@ mod benchmarks { ) -> Result<(), BenchmarkError> { let session = 69; let max_history_depth = a as usize; - let (network_id, _, _) = prepare_pallet::(1); + let (network_id, _, _) = prepare_pallet::(1, None); // Real world tx at block #481838 // Block https://blockstream.info/block/0000000000000000011bdccb39e19e942a60edffdccd9779653c5b46b337904a @@ -316,7 +319,7 @@ mod benchmarks { ); let thread_proof = ThreadProof::UtxoThreadProof(utxo_thread_proof); - let pulled_thread_key = thread_proof.get_unique_key(session); + let pulled_thread_key = thread_proof.get_unique_key(session, network_id); assert!(!PulledThreads::::contains_key(&pulled_thread_key)); @@ -330,14 +333,15 @@ mod benchmarks { #[benchmark] fn pull_evm_thread() -> Result<(), BenchmarkError> { - let session = 69; - let (network_id, _, _) = prepare_pallet::(1); + let session = 0; + let sepolia_network_id = 11155111; + let (network_id, _, _) = prepare_pallet::(1, Some(sepolia_network_id)); - // https://sepolia.etherscan.io/address/0x81acdf2da6b50d806c96aecd9a498a5359e373c0#readContract - // getRoot: session 0, atBlock 11660400 + // https://sepolia.etherscan.io/address/0x7fec11e652f4d54e8cf11c4b52c360380332f2bd#readContract + // getRoot: session 0, atBlock 11716130 let root_string = - hex::decode("28d1e6b476b03a464f74d531d532572db29d6b57349e4f17f84e92843f6c4ee7") + hex::decode("07f4a5ba4750d9ddfc080429287cbcbde7464aa2f8ae13feaade0dcb45ca6129") .expect("EVM Root hex should be valid"); let expected_root = H256::from_slice(&root_string); LoomStates::::insert(&network_id, &session, expected_root); @@ -352,8 +356,8 @@ mod benchmarks { let transfer_amount: BalanceOf = 420u64.unique_saturated_into(); let proof = vec![ - H256::from_slice(&hex::decode("c5354289f0397c916949373043eb1d5ea99447f67fe014324d96c58ef02a2d11").expect("Proof should be valid")), - H256::from_slice(&hex::decode("da1fbdfefa1e9aedfedcfc48fb17cb0e731529f7a3695114e0a9caa1989dd420").expect("Proof should be valid")), + H256::from_slice(&hex::decode("7d831a4be9e37572687117870c3f96669a66bf07971e4fd705a36a0a4d6365b0").expect("Proof should be valid")), + H256::from_slice(&hex::decode("9f00b99751b7ccea1903949210408edb3ce50343985708c36a0b1d44e0a7628c").expect("Proof should be valid")), H256::from_slice(&hex::decode("1c792b14bf66f82af36f00f5fba7014fa0c1e2ff3c7c273bfe523c1acf67dc3f").expect("Proof should be valid")), H256::from_slice(&hex::decode("5fa080a686a5a0d05c3d4822fd54d632dc9cc04b1616046eba2ce499eb9af79f").expect("Proof should be valid")), H256::from_slice(&hex::decode("5eb949690a0404abf4cebafc7cfffa382191b7dd9e7df778581e6fb78efab35f").expect("Proof should be valid")), @@ -362,14 +366,14 @@ mod benchmarks { H256::from_slice(&hex::decode("de9c446fab46a8d27db1e3100f275a777d385b44e3cbc045cabac9da36cae040").expect("Proof should be valid")), ]; let slots = vec![H256::from_slice( - &hex::decode("2e474dabf492786b3505d7b7cf0bf07c9dbce92c91982fa7344c77e24fd4310d") + &hex::decode("f6182b8c276793f53d1820ad0405665177516e46e40af45e0dfea73c39a2306e") .expect("Slot should be valid hex"), )]; let evm_thread_proof = EvmThreadProof::new(0, 1, receiver_account, transfer_amount, proof, slots); let thread_proof = ThreadProof::EvmThreadProof(evm_thread_proof); - let pulled_thread_key = thread_proof.get_unique_key(session); + let pulled_thread_key = thread_proof.get_unique_key(session, network_id); assert!(!PulledThreads::::contains_key(&pulled_thread_key)); diff --git a/pallets/weaver/src/lib.rs b/pallets/weaver/src/lib.rs index fc41931..62911d6 100644 --- a/pallets/weaver/src/lib.rs +++ b/pallets/weaver/src/lib.rs @@ -439,7 +439,7 @@ pub mod pallet { .ok_or(Error::::NonExistentNetworkId)?; let root_hash = LoomStates::::get(&network_id, &session); - let pulled_thread_key = thread_proof.get_unique_key(session); + let pulled_thread_key = thread_proof.get_unique_key(session, network_id); ensure!( !PulledThreads::::contains_key(&pulled_thread_key), @@ -447,7 +447,7 @@ pub mod pallet { ); let (receiver_account, amount) = thread_proof - .verify_thread_proof(root_hash, &network_data.gatekeeper) + .verify_thread_proof(root_hash, network_id, &network_data.gatekeeper) .ok_or(Error::::InvalidMerkleProof)?; let receiver_bytes: &[u8; 32] = receiver_account.as_ref(); diff --git a/pallets/weaver/src/tests.rs b/pallets/weaver/src/tests.rs index 4162698..cb26757 100644 --- a/pallets/weaver/src/tests.rs +++ b/pallets/weaver/src/tests.rs @@ -560,7 +560,7 @@ fn offchain_worker_should_fetch_hash_and_submit_unsigned_tx() { fn should_successfully_pull_evm_thread_and_mint_currency() { let pair = AuthorityPair::from_string("//Alice", None).expect("Should be valid seed"); - let network_id = 1; + let network_id = 11155111; let network_data = NetworkDataBuilder::default() .with_network_type(NetworkType::Evm) .build(); @@ -568,204 +568,78 @@ fn should_successfully_pull_evm_thread_and_mint_currency() { let authorities = vec![pair.clone()]; let networks = vec![(network_id, network_data, Default::default())]; - // Contract address: 0x9a52C28dA655b69d8ddc430d6ebD04630BA0e845 + // Contract address: 0x7fec11e652f4d54e8cf11c4b52c360380332f2bd // // three inserts // 69 sfJ9hc4A7r578XM35nd48B3FWcd33XjpVnAbGC5tvtwthMWdU - 0xc477f0a42fdd861485bd854c7a5851614ea163bd295f7844e1c5493d662fdc4e // 420 sfDxNicCEPts6CVttVMPCs2eoymDpQahu1GUVyGPWu6dhwADJ - 0x0ae3ba32f8555fe3031461e2cb6feeadb67029ef7490b982824fc90751a4cb3e // 1337 sfH6zJ63fcxrFAZ1RmiHbxgy2t3sEufY26WdsBSS359AzJd4w - 0x962a2794f66c89e55d9b9692ce59f67345b99f6fddb51d90462c7eca8b5a7e1b - // https://sepolia.etherscan.io/address/0x81acdf2da6b50d806c96aecd9a498a5359e373c0#readContract - // getRoot: atBlock 11660400, globalIndexes from 0 to 2 + // https://sepolia.etherscan.io/address/0x7fec11e652f4d54e8cf11c4b52c360380332f2bd#readContract + // getRoot: atBlock 11716130, globalIndexes from 0 to 2 let inserts = vec![ ( 0, - hex::decode("c477f0a42fdd861485bd854c7a5851614ea163bd295f7844e1c5493d662fdc4e") - .expect("Bytes32 from EVM should be valid"), + hex::decode("c477f0a42fdd861485bd854c7a5851614ea163bd295f7844e1c5493d662fdc4e").expect("Bytes32 from EVM should be valid"), 69u64, vec![ - H256::from_slice( - &hex::decode( - "675a2e7b05b8b3932cd0faf88f1bc29767b7462667f56d051b8d5325bda0ee73", - ) - .expect("Proof should be valid"), - ), - H256::from_slice( - &hex::decode( - "da1fbdfefa1e9aedfedcfc48fb17cb0e731529f7a3695114e0a9caa1989dd420", - ) - .expect("Proof should be valid"), - ), - H256::from_slice( - &hex::decode( - "1c792b14bf66f82af36f00f5fba7014fa0c1e2ff3c7c273bfe523c1acf67dc3f", - ) - .expect("Proof should be valid"), - ), - H256::from_slice( - &hex::decode( - "5fa080a686a5a0d05c3d4822fd54d632dc9cc04b1616046eba2ce499eb9af79f", - ) - .expect("Proof should be valid"), - ), - H256::from_slice( - &hex::decode( - "5eb949690a0404abf4cebafc7cfffa382191b7dd9e7df778581e6fb78efab35f", - ) - .expect("Proof should be valid"), - ), - H256::from_slice( - &hex::decode( - "d364c9d5dadad4569b6dd47f7feabafa3571f842434425548335ac6e690dd071", - ) - .expect("Proof should be valid"), - ), - H256::from_slice( - &hex::decode( - "68d8bc5b77979c1a6702334f529f5783f79e942fd2cd03f6e55ac2cf496e849f", - ) - .expect("Proof should be valid"), - ), - H256::from_slice( - &hex::decode( - "de9c446fab46a8d27db1e3100f275a777d385b44e3cbc045cabac9da36cae040", - ) - .expect("Proof should be valid"), - ), + H256::from_slice(&hex::decode("2d931b11b1652669a04e7b5b50418f5e1e2fabb6791dabc9a196e719ad5cf9c6").expect("Proof should be valid")), + H256::from_slice(&hex::decode("9f00b99751b7ccea1903949210408edb3ce50343985708c36a0b1d44e0a7628c").expect("Proof should be valid")), + H256::from_slice(&hex::decode("1c792b14bf66f82af36f00f5fba7014fa0c1e2ff3c7c273bfe523c1acf67dc3f").expect("Proof should be valid")), + H256::from_slice(&hex::decode("5fa080a686a5a0d05c3d4822fd54d632dc9cc04b1616046eba2ce499eb9af79f").expect("Proof should be valid")), + H256::from_slice(&hex::decode("5eb949690a0404abf4cebafc7cfffa382191b7dd9e7df778581e6fb78efab35f").expect("Proof should be valid")), + H256::from_slice(&hex::decode("d364c9d5dadad4569b6dd47f7feabafa3571f842434425548335ac6e690dd071").expect("Proof should be valid")), + H256::from_slice(&hex::decode("68d8bc5b77979c1a6702334f529f5783f79e942fd2cd03f6e55ac2cf496e849f").expect("Proof should be valid")), + H256::from_slice(&hex::decode("de9c446fab46a8d27db1e3100f275a777d385b44e3cbc045cabac9da36cae040").expect("Proof should be valid")), ], vec![H256::from_slice( - &hex::decode("350a78f78c810898b7c60ddba671543bfbe683ffb0ac393df0e132f607b5f738") - .expect("Slot should be valid hex"), + &hex::decode("f494b2065ca61f2af007a3dd5f1f3d228a3ad09f4f7b7c5ef3eeb3aee6718ee2").expect("Slot should be valid hex"), )], ), ( 1, - hex::decode("0ae3ba32f8555fe3031461e2cb6feeadb67029ef7490b982824fc90751a4cb3e") - .expect("Bytes32 from EVM should be valid"), + hex::decode("0ae3ba32f8555fe3031461e2cb6feeadb67029ef7490b982824fc90751a4cb3e").expect("Bytes32 from EVM should be valid"), 420u64, vec![ - H256::from_slice( - &hex::decode( - "c5354289f0397c916949373043eb1d5ea99447f67fe014324d96c58ef02a2d11", - ) - .expect("Proof should be valid"), - ), - H256::from_slice( - &hex::decode( - "da1fbdfefa1e9aedfedcfc48fb17cb0e731529f7a3695114e0a9caa1989dd420", - ) - .expect("Proof should be valid"), - ), - H256::from_slice( - &hex::decode( - "1c792b14bf66f82af36f00f5fba7014fa0c1e2ff3c7c273bfe523c1acf67dc3f", - ) - .expect("Proof should be valid"), - ), - H256::from_slice( - &hex::decode( - "5fa080a686a5a0d05c3d4822fd54d632dc9cc04b1616046eba2ce499eb9af79f", - ) - .expect("Proof should be valid"), - ), - H256::from_slice( - &hex::decode( - "5eb949690a0404abf4cebafc7cfffa382191b7dd9e7df778581e6fb78efab35f", - ) - .expect("Proof should be valid"), - ), - H256::from_slice( - &hex::decode( - "d364c9d5dadad4569b6dd47f7feabafa3571f842434425548335ac6e690dd071", - ) - .expect("Proof should be valid"), - ), - H256::from_slice( - &hex::decode( - "68d8bc5b77979c1a6702334f529f5783f79e942fd2cd03f6e55ac2cf496e849f", - ) - .expect("Proof should be valid"), - ), - H256::from_slice( - &hex::decode( - "de9c446fab46a8d27db1e3100f275a777d385b44e3cbc045cabac9da36cae040", - ) - .expect("Proof should be valid"), - ), + H256::from_slice(&hex::decode("7d831a4be9e37572687117870c3f96669a66bf07971e4fd705a36a0a4d6365b0").expect("Proof should be valid")), + H256::from_slice(&hex::decode("9f00b99751b7ccea1903949210408edb3ce50343985708c36a0b1d44e0a7628c").expect("Proof should be valid")), + H256::from_slice(&hex::decode("1c792b14bf66f82af36f00f5fba7014fa0c1e2ff3c7c273bfe523c1acf67dc3f").expect("Proof should be valid")), + H256::from_slice(&hex::decode("5fa080a686a5a0d05c3d4822fd54d632dc9cc04b1616046eba2ce499eb9af79f").expect("Proof should be valid")), + H256::from_slice(&hex::decode("5eb949690a0404abf4cebafc7cfffa382191b7dd9e7df778581e6fb78efab35f").expect("Proof should be valid")), + H256::from_slice(&hex::decode("d364c9d5dadad4569b6dd47f7feabafa3571f842434425548335ac6e690dd071").expect("Proof should be valid")), + H256::from_slice(&hex::decode("68d8bc5b77979c1a6702334f529f5783f79e942fd2cd03f6e55ac2cf496e849f").expect("Proof should be valid")), + H256::from_slice(&hex::decode("de9c446fab46a8d27db1e3100f275a777d385b44e3cbc045cabac9da36cae040").expect("Proof should be valid")), ], vec![H256::from_slice( - &hex::decode("2e474dabf492786b3505d7b7cf0bf07c9dbce92c91982fa7344c77e24fd4310d") - .expect("Slot should be valid hex"), + &hex::decode("f6182b8c276793f53d1820ad0405665177516e46e40af45e0dfea73c39a2306e").expect("Slot should be valid hex"), )], ), ( 2, - hex::decode("962a2794f66c89e55d9b9692ce59f67345b99f6fddb51d90462c7eca8b5a7e1b") - .expect("Bytes32 from EVM should be valid"), + hex::decode("962a2794f66c89e55d9b9692ce59f67345b99f6fddb51d90462c7eca8b5a7e1b").expect("Bytes32 from EVM should be valid"), 1337u64, vec![ - H256::from_slice( - &hex::decode( - "f39a869f62e75cf5f0bf914688a6b289caf2049435d8e68c5c5e6d05e44913f3", - ) - .expect("Proof should be valid"), - ), - H256::from_slice( - &hex::decode( - "e0090094ce1d7af8a81ba78bef4b137c1ab32d20d5487224a9f8df95b516c1e4", - ) - .expect("Proof should be valid"), - ), - H256::from_slice( - &hex::decode( - "1c792b14bf66f82af36f00f5fba7014fa0c1e2ff3c7c273bfe523c1acf67dc3f", - ) - .expect("Proof should be valid"), - ), - H256::from_slice( - &hex::decode( - "5fa080a686a5a0d05c3d4822fd54d632dc9cc04b1616046eba2ce499eb9af79f", - ) - .expect("Proof should be valid"), - ), - H256::from_slice( - &hex::decode( - "5eb949690a0404abf4cebafc7cfffa382191b7dd9e7df778581e6fb78efab35f", - ) - .expect("Proof should be valid"), - ), - H256::from_slice( - &hex::decode( - "d364c9d5dadad4569b6dd47f7feabafa3571f842434425548335ac6e690dd071", - ) - .expect("Proof should be valid"), - ), - H256::from_slice( - &hex::decode( - "68d8bc5b77979c1a6702334f529f5783f79e942fd2cd03f6e55ac2cf496e849f", - ) - .expect("Proof should be valid"), - ), - H256::from_slice( - &hex::decode( - "de9c446fab46a8d27db1e3100f275a777d385b44e3cbc045cabac9da36cae040", - ) - .expect("Proof should be valid"), - ), + H256::from_slice(&hex::decode("f39a869f62e75cf5f0bf914688a6b289caf2049435d8e68c5c5e6d05e44913f3").expect("Proof should be valid")), + H256::from_slice(&hex::decode("385de173dc8295d4153b2de3bd705dd96556c8c316a996b3e56adce0970ffa36").expect("Proof should be valid")), + H256::from_slice(&hex::decode("1c792b14bf66f82af36f00f5fba7014fa0c1e2ff3c7c273bfe523c1acf67dc3f").expect("Proof should be valid")), + H256::from_slice(&hex::decode("5fa080a686a5a0d05c3d4822fd54d632dc9cc04b1616046eba2ce499eb9af79f").expect("Proof should be valid")), + H256::from_slice(&hex::decode("5eb949690a0404abf4cebafc7cfffa382191b7dd9e7df778581e6fb78efab35f").expect("Proof should be valid")), + H256::from_slice(&hex::decode("d364c9d5dadad4569b6dd47f7feabafa3571f842434425548335ac6e690dd071").expect("Proof should be valid")), + H256::from_slice(&hex::decode("68d8bc5b77979c1a6702334f529f5783f79e942fd2cd03f6e55ac2cf496e849f").expect("Proof should be valid")), + H256::from_slice(&hex::decode("de9c446fab46a8d27db1e3100f275a777d385b44e3cbc045cabac9da36cae040").expect("Proof should be valid")), ], vec![H256::from_slice( - &hex::decode("bde870fce92d701a7a5d6f63003e1cd2cb61c3266fc1be256844b8ca61d9c9ab") - .expect("Slot should be valid hex"), + &hex::decode("2f52c7d2d3f4167c436f3b6cc0a7d944a45846ba87f74998100b83122d5eb0ad").expect("Slot should be valid hex"), )], ), ]; new_test_ext(authorities, networks).execute_with(|| { - // https://sepolia.etherscan.io/address/0x81acdf2da6b50d806c96aecd9a498a5359e373c0#readContract - // getRoot: session 0, atBlock 11660400 + // https://sepolia.etherscan.io/address/0x7fec11e652f4d54e8cf11c4b52c360380332f2bd#readContract + // getRoot: session 0, atBlock 11716130 let session = 0; let root_string = - hex::decode("28d1e6b476b03a464f74d531d532572db29d6b57349e4f17f84e92843f6c4ee7") + hex::decode("07f4a5ba4750d9ddfc080429287cbcbde7464aa2f8ae13feaade0dcb45ca6129") .expect("Root hex should be valid"); let expected_root = H256::from_slice(&root_string); LoomStates::::insert(&network_id, &session, expected_root); @@ -795,7 +669,7 @@ fn should_successfully_pull_evm_thread_and_mint_currency() { ); let thread_info = ThreadProof::EvmThreadProof(evm_thread_proof); - let pulled_thread_key = thread_info.get_unique_key(session); + let pulled_thread_key = thread_info.get_unique_key(session, network_id); assert_eq!(Balances::free_balance(&receiver_account), 0); assert!(!PulledThreads::::contains_key( @@ -806,8 +680,7 @@ fn should_successfully_pull_evm_thread_and_mint_currency() { network_id, session, thread_info - ) - .is_ok()); + ).is_ok()); assert!(PulledThreads::::contains_key( &pulled_thread_key @@ -887,7 +760,7 @@ fn should_successfully_pull_utxo_thread_and_mint_currency() { let utxo_thread_proof = UtxoThreadProof::new(payload.0, payload.1, payload.2); let thread_info = ThreadProof::UtxoThreadProof(utxo_thread_proof); - let pulled_thread_key = thread_info.get_unique_key(session); + let pulled_thread_key = thread_info.get_unique_key(session, network_id); assert_eq!(Balances::free_balance(&receiver_account), 0); assert!(!PulledThreads::::contains_key( diff --git a/pallets/weaver/src/types.rs b/pallets/weaver/src/types.rs index 028c7d7..5db3ce2 100644 --- a/pallets/weaver/src/types.rs +++ b/pallets/weaver/src/types.rs @@ -288,31 +288,40 @@ where Balance: Copy + Clone + Eq + PartialEq + UniqueSaturatedInto, u64: UniqueSaturatedInto, { - pub fn is_evm_proof_correct(&self) -> bool { + pub fn verify_thread_proof( + &self, + root_hash: H256, + network_id: NetworkId, + gatekeeper: &[u8] + ) -> Option<(AccountId32, Balance)> + where + NetworkId: Copy + Clone + Eq + PartialEq + UniqueSaturatedInto, + { match self { - Self::EvmThreadProof(_) => true, - Self::UtxoThreadProof(_) => false, + Self::UtxoThreadProof(utxo_thread) => { + utxo_thread.verify_thread_proof(root_hash, gatekeeper) + }, + Self::EvmThreadProof(evm_thread) => { + evm_thread.verify_thread_proof(root_hash, network_id) + }, } } - pub fn is_utxo_proof_correct(&self) -> bool { + pub fn get_unique_key( + &self, + session: WeavingSession, + network_id: NetworkId, + ) -> H256 + where + NetworkId: Copy + Clone + Eq + PartialEq + UniqueSaturatedInto, + { match self { - Self::UtxoThreadProof(_) => true, - Self::EvmThreadProof(_) => false, - } - } - - pub fn verify_thread_proof(&self, root_hash: H256, gatekeeper: &[u8]) -> Option<(AccountId32, Balance)> { - match self { - Self::UtxoThreadProof(utxo_thread) => utxo_thread.verify_thread_proof(root_hash, gatekeeper), - Self::EvmThreadProof(evm_thread) => evm_thread.verify_thread_proof(root_hash), - } - } - - pub fn get_unique_key(&self, session: WeavingSession) -> H256 { - match self { - Self::EvmThreadProof(thread_info) => thread_info.get_unique_key(session), - Self::UtxoThreadProof(utxo_thread) => utxo_thread.get_unique_key(), + Self::EvmThreadProof(thread_info) => { + thread_info.get_unique_key(session, network_id) + }, + Self::UtxoThreadProof(utxo_thread) => { + utxo_thread.get_unique_key(network_id) + }, } } } @@ -331,11 +340,18 @@ impl EvmThreadProof where Balance: Copy + Clone + Eq + PartialEq + UniqueSaturatedInto, { - pub fn verify_thread_proof(&self, root_hash: H256) -> Option<(AccountId32, Balance)> { + pub fn verify_thread_proof( + &self, + root_hash: H256, + network_id: NetworkId, + ) -> Option<(AccountId32, Balance)> + where + NetworkId: Copy + Clone + Eq + PartialEq + UniqueSaturatedInto, + { if EVM_MERKLE_DEPTH as usize != self.proof.len() { return None; } let proof_valid = verify_tree_proof::( - &self.get_preimage_slice().to_fixed_bytes(), + &self.get_preimage_slice(network_id).to_fixed_bytes(), self.proof.as_ref(), root_hash, self.proof_index, @@ -346,8 +362,17 @@ where Some((self.receiver.clone(), self.amount)) } - fn get_preimage_slice(&self) -> H256 { + fn get_preimage_slice(&self, network_id: NetworkId) -> H256 + where + NetworkId: Copy + Clone + Eq + PartialEq + UniqueSaturatedInto, + { let slot_index_usize: usize = self.slot_index.unique_saturated_into(); + let slot_index_out_of_range = slot_index_usize >= self.slots.len(); + let too_many_slots_given = (EVM_VALUES_DEPTH as usize) < self.slots.len(); + + if slot_index_out_of_range || too_many_slots_given { + return SubstrateKeccakHasher::empty(); + } (slot_index_usize < self.slots.len()) .then(|| { @@ -356,7 +381,7 @@ where .enumerate() .map(|(index, &preimage)| { if index == slot_index_usize { - self.compute_arguments_hash() + self.compute_arguments_hash(network_id) } else { preimage } @@ -367,20 +392,55 @@ where .unwrap_or(SubstrateKeccakHasher::empty()) } - pub fn get_unique_key(&self, session: WeavingSession) -> H256 { - let session_bytes = (session as u64).to_be_bytes(); - let slot_bytes = (self.slot_index as u64).to_be_bytes(); - let proof_bytes = (self.proof_index as u64).to_be_bytes(); - - let mut h1 = [0u8; 32]; h1[24..32].copy_from_slice(&session_bytes); - let mut h2 = [0u8; 32]; h2[24..32].copy_from_slice(&slot_bytes); - let mut h3 = [0u8; 32]; h3[24..32].copy_from_slice(&proof_bytes); - - let metadata: [H256; 3] = [H256::from(h1), H256::from(h2), H256::from(h3)]; + pub fn get_unique_key( + &self, + session: WeavingSession, + network_id: NetworkId, + ) -> H256 + where + NetworkId: Copy + Clone + Eq + PartialEq + UniqueSaturatedInto, + { + let metadata: [H256; 4] = [ + H256::from_low_u64_be(session as u64), + H256::from_low_u64_be(self.slot_index.unique_saturated_into()), + H256::from_low_u64_be(self.proof_index.unique_saturated_into()), + H256::from_low_u64_be(network_id.unique_saturated_into()), + ]; sequential_hash::(metadata) } + fn compute_arguments_hash(&self, network_id: NetworkId) -> H256 + where + NetworkId: Copy + Clone + Eq + PartialEq + UniqueSaturatedInto, + { + let amount_u128: u128 = self.amount.unique_saturated_into(); + let slot_index_u64: u64 = self.slot_index.unique_saturated_into(); + let network_id_u64: u64 = network_id.unique_saturated_into(); + + let amount_u256 = U256::from(amount_u128); + let slot_index_u256 = U256::from(slot_index_u64); + let network_id_u256 = U256::from(network_id_u64); + + let mut padded_amount = [0u8; 32]; + amount_u256.to_big_endian(&mut padded_amount); + + let mut padded_slot_index = [0u8; 32]; + slot_index_u256.to_big_endian(&mut padded_slot_index); + + let mut padded_network_id = [0u8; 32]; + network_id_u256.to_big_endian(&mut padded_network_id); + + let inputs: [&[u8]; 4] = [ + padded_amount.as_ref(), + self.receiver.as_ref(), + padded_slot_index.as_ref(), + padded_network_id.as_ref(), + ]; + + sequential_hash::(inputs) + } + pub fn new( slot_index: ThreadId, proof_index: ThreadId, @@ -404,27 +464,6 @@ where slots, } } - - fn compute_arguments_hash(&self) -> H256 { - let amount_u128: u128 = self.amount.unique_saturated_into(); - let amount_u256 = U256::from(amount_u128); - - let slot_index_u64: u64 = self.slot_index.unique_saturated_into(); - let slot_index_u256 = U256::from(slot_index_u64); - - let mut padded_amount = [0u8; 32]; - amount_u256.to_big_endian(&mut padded_amount); - - let mut padded_slot_index = [0u8; 32]; - slot_index_u256.to_big_endian(&mut padded_slot_index); - - let inputs: [&[u8]; 3] = [ - padded_amount.as_ref(), - self.receiver.as_ref(), - padded_slot_index.as_ref(), - ]; - sequential_hash::(inputs) - } } #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] @@ -447,7 +486,7 @@ impl UtxoThreadProof { root_hash: H256, gatekeeper_ref: &[u8], ) -> Option<(AccountId32, Balance)> - where + where Balance: Copy + Clone + Eq + PartialEq + UniqueSaturatedInto, u64: UniqueSaturatedInto, { @@ -488,10 +527,17 @@ impl UtxoThreadProof { )) } - pub fn get_unique_key(&self) -> H256 { + pub fn get_unique_key(&self, network_id: NetworkId) -> H256 + where + NetworkId: Copy + Clone + Eq + PartialEq + UniqueSaturatedInto, + { + let network_id_u64: u64 = network_id.unique_saturated_into(); + let network_id_bytes = network_id_u64.to_be_bytes(); + let metadata: &[&[u8]] = &[ self.gettxproof_bytes.as_ref(), self.getrawtransaction_bytes.as_ref(), + network_id_bytes.as_ref(), ]; sequential_hash::(metadata)