inject the network ID into the hash chain and the arguments hash

Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
This commit is contained in:
Uncle Stinky 2026-09-16 14:10:12 +03:00
parent cc45fb5f9c
commit 414604f296
Signed by: st1nky
GPG Key ID: 016064BD97603B40
5 changed files with 165 additions and 242 deletions

View File

@ -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

View File

@ -8,7 +8,8 @@ use sp_std::vec;
use ghost_helpers::networks::NetworkDataBuilder;
fn prepare_pallet<T: Config>(
authorities_len: u32
authorities_len: u32,
maybe_network_id: Option<u64>,
) -> (NetworkIdOf<T>, 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<T: Config>(
Authorities::<T>::put(bounded_authorities);
let network_id = NetworkIdOf::<T>::default();
let network_id_u64 = maybe_network_id.unwrap_or_default();
let network_id: NetworkIdOf<T> = 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::<T>(a);
let (network_id, authority, authority_index) = prepare_pallet::<T>(a, None);
TapestryDrafts::<T>::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::<T>(a);
let (network_id, authority, authority_index) = prepare_pallet::<T>(a, None);
let tapestry_key = (network_id, weaving_session, next_session, root_hash);
TapestryStrands::<T>::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::<T>(1);
let (network_id, _, _) = prepare_pallet::<T>(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::<T>::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::<T>(1);
let session = 0;
let sepolia_network_id = 11155111;
let (network_id, _, _) = prepare_pallet::<T>(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::<T>::insert(&network_id, &session, expected_root);
@ -352,8 +356,8 @@ mod benchmarks {
let transfer_amount: BalanceOf<T> = 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::<T>::contains_key(&pulled_thread_key));

View File

@ -439,7 +439,7 @@ pub mod pallet {
.ok_or(Error::<T>::NonExistentNetworkId)?;
let root_hash = LoomStates::<T>::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::<T>::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::<T>::InvalidMerkleProof)?;
let receiver_bytes: &[u8; 32] = receiver_account.as_ref();

View File

@ -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::<TestRuntime>::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::<TestRuntime>::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::<TestRuntime>::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::<TestRuntime>::contains_key(

View File

@ -288,31 +288,40 @@ where
Balance: Copy + Clone + Eq + PartialEq + UniqueSaturatedInto<u128>,
u64: UniqueSaturatedInto<Balance>,
{
pub fn is_evm_proof_correct(&self) -> bool {
pub fn verify_thread_proof<NetworkId>(
&self,
root_hash: H256,
network_id: NetworkId,
gatekeeper: &[u8]
) -> Option<(AccountId32, Balance)>
where
NetworkId: Copy + Clone + Eq + PartialEq + UniqueSaturatedInto<u64>,
{
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<NetworkId>(
&self,
session: WeavingSession,
network_id: NetworkId,
) -> H256
where
NetworkId: Copy + Clone + Eq + PartialEq + UniqueSaturatedInto<u64>,
{
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<Balance> EvmThreadProof<Balance>
where
Balance: Copy + Clone + Eq + PartialEq + UniqueSaturatedInto<u128>,
{
pub fn verify_thread_proof(&self, root_hash: H256) -> Option<(AccountId32, Balance)> {
pub fn verify_thread_proof<NetworkId>(
&self,
root_hash: H256,
network_id: NetworkId,
) -> Option<(AccountId32, Balance)>
where
NetworkId: Copy + Clone + Eq + PartialEq + UniqueSaturatedInto<u64>,
{
if EVM_MERKLE_DEPTH as usize != self.proof.len() { return None; }
let proof_valid = verify_tree_proof::<SubstrateKeccakHasher, _>(
&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<NetworkId>(&self, network_id: NetworkId) -> H256
where
NetworkId: Copy + Clone + Eq + PartialEq + UniqueSaturatedInto<u64>,
{
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<NetworkId>(
&self,
session: WeavingSession,
network_id: NetworkId,
) -> H256
where
NetworkId: Copy + Clone + Eq + PartialEq + UniqueSaturatedInto<u64>,
{
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::<SubstrateBlake2Hasher, _>(metadata)
}
fn compute_arguments_hash<NetworkId>(&self, network_id: NetworkId) -> H256
where
NetworkId: Copy + Clone + Eq + PartialEq + UniqueSaturatedInto<u64>,
{
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::<SubstrateKeccakHasher, _>(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::<SubstrateKeccakHasher, _>(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<u128>,
u64: UniqueSaturatedInto<Balance>,
{
@ -488,10 +527,17 @@ impl UtxoThreadProof {
))
}
pub fn get_unique_key(&self) -> H256 {
pub fn get_unique_key<NetworkId>(&self, network_id: NetworkId) -> H256
where
NetworkId: Copy + Clone + Eq + PartialEq + UniqueSaturatedInto<u64>,
{
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::<SubstrateBlake2Hasher, _>(metadata)