diff --git a/crates/trie/common/src/proofs.rs b/crates/trie/common/src/proofs.rs index b35edd96d560c..17297dcd781f1 100644 --- a/crates/trie/common/src/proofs.rs +++ b/crates/trie/common/src/proofs.rs @@ -2,7 +2,7 @@ use crate::{Nibbles, TrieAccount}; use alloy_primitives::{keccak256, Address, Bytes, B256, U256}; -use alloy_rlp::{encode_fixed_size, Decodable}; +use alloy_rlp::{encode_fixed_size, Decodable, EMPTY_STRING_CODE}; use alloy_trie::{ nodes::TrieNode, proof::{verify_proof, ProofNodes, ProofVerificationError}, @@ -88,7 +88,13 @@ pub struct StorageMultiProof { impl Default for StorageMultiProof { fn default() -> Self { - Self { root: EMPTY_ROOT_HASH, subtree: Default::default() } + Self { + root: EMPTY_ROOT_HASH, + subtree: ProofNodes::from_iter([( + Nibbles::default(), + Bytes::from([EMPTY_STRING_CODE]), + )]), + } } } diff --git a/crates/trie/db/tests/witness.rs b/crates/trie/db/tests/witness.rs index 248ec3b981eda..949f4900bb343 100644 --- a/crates/trie/db/tests/witness.rs +++ b/crates/trie/db/tests/witness.rs @@ -1,5 +1,6 @@ +use alloy_primitives::{keccak256, Address}; use alloy_rlp::EMPTY_STRING_CODE; -use reth_primitives::{constants::EMPTY_ROOT_HASH, keccak256, Account, Address, Bytes, B256, U256}; +use reth_primitives::{constants::EMPTY_ROOT_HASH, Account, Bytes, B256, U256}; use reth_provider::{test_utils::create_test_provider_factory, HashingWriter}; use reth_trie::{proof::Proof, witness::TrieWitness, HashedPostState, HashedStorage, StateRoot}; use reth_trie_db::{DatabaseProof, DatabaseStateRoot, DatabaseTrieWitness}; @@ -10,16 +11,21 @@ fn includes_empty_node_preimage() { let factory = create_test_provider_factory(); let provider = factory.provider_rw().unwrap(); + let address = Address::random(); + let hashed_address = keccak256(address); + let hashed_slot = B256::random(); + // witness includes empty state trie root node assert_eq!( - TrieWitness::from_tx(provider.tx_ref()).compute(HashedPostState::default()).unwrap(), + TrieWitness::from_tx(provider.tx_ref()) + .compute(HashedPostState { + accounts: HashMap::from([(hashed_address, Some(Account::default()))]), + storages: HashMap::default(), + }) + .unwrap(), HashMap::from([(EMPTY_ROOT_HASH, Bytes::from([EMPTY_STRING_CODE]))]) ); - let address = Address::random(); - let hashed_address = keccak256(address); - let hashed_slot = B256::random(); - // Insert account into database provider.insert_account_for_hashing([(address, Some(Account::default()))]).unwrap(); @@ -34,7 +40,7 @@ fn includes_empty_node_preimage() { accounts: HashMap::from([(hashed_address, Some(Account::default()))]), storages: HashMap::from([( hashed_address, - HashedStorage::from_iter(false, [(hashed_slot, U256::ZERO)]), + HashedStorage::from_iter(false, [(hashed_slot, U256::from(1))]), )]), }) .unwrap(); diff --git a/crates/trie/trie/src/witness.rs b/crates/trie/trie/src/witness.rs index 61576aabe36e5..aaa28b49ff6e2 100644 --- a/crates/trie/trie/src/witness.rs +++ b/crates/trie/trie/src/witness.rs @@ -202,7 +202,8 @@ where proof: impl IntoIterator, ) -> Result>>, TrieWitnessError> { let mut trie_nodes = BTreeMap::default(); - for (path, encoded) in proof { + let mut proof_iter = proof.into_iter().enumerate().peekable(); + while let Some((idx, (path, encoded))) = proof_iter.next() { // Record the node in witness. self.witness.insert(keccak256(encoded.as_ref()), encoded.clone()); @@ -226,7 +227,11 @@ where trie_nodes.insert(next_path.clone(), Either::Right(leaf.value.clone())); } } - TrieNode::EmptyRoot => return Err(TrieWitnessError::UnexpectedEmptyRoot(next_path)), + TrieNode::EmptyRoot => { + if idx != 0 || proof_iter.peek().is_some() { + return Err(TrieWitnessError::UnexpectedEmptyRoot(next_path)) + } + } }; }