feat(trie): decode proofs in multiproof task (#16098)

Co-authored-by: Alexey Shekhirin <5773434+shekhirin@users.noreply.github.com>
This commit is contained in:
Dan Cline
2025-05-20 18:10:04 -04:00
committed by GitHub
parent a62bde37ca
commit 6e88d7fb3b
8 changed files with 231 additions and 91 deletions

1
Cargo.lock generated
View File

@@ -10344,6 +10344,7 @@ version = "1.4.3"
dependencies = [
"alloy-primitives",
"alloy-rlp",
"alloy-trie",
"arbitrary",
"assert_matches",
"auto_impl",

View File

@@ -17,8 +17,8 @@ use reth_provider::{
};
use reth_revm::state::EvmState;
use reth_trie::{
prefix_set::TriePrefixSetsMut, updates::TrieUpdatesSorted, HashedPostState,
HashedPostStateSorted, HashedStorage, MultiProof, MultiProofTargets, TrieInput,
prefix_set::TriePrefixSetsMut, updates::TrieUpdatesSorted, DecodedMultiProof, HashedPostState,
HashedPostStateSorted, HashedStorage, MultiProofTargets, TrieInput,
};
use reth_trie_parallel::{proof::ParallelProof, proof_task::ProofTaskManagerHandle};
use std::{
@@ -42,7 +42,7 @@ pub struct SparseTrieUpdate {
/// The state update that was used to calculate the proof
pub(crate) state: HashedPostState,
/// The calculated multiproof
pub(crate) multiproof: MultiProof,
pub(crate) multiproof: DecodedMultiProof,
}
impl SparseTrieUpdate {
@@ -53,8 +53,8 @@ impl SparseTrieUpdate {
/// Construct update from multiproof.
#[cfg(test)]
pub(super) fn from_multiproof(multiproof: MultiProof) -> Self {
Self { multiproof, ..Default::default() }
pub(super) fn from_multiproof(multiproof: reth_trie::MultiProof) -> alloy_rlp::Result<Self> {
Ok(Self { multiproof: multiproof.try_into()?, ..Default::default() })
}
/// Extend update with contents of the other.
@@ -455,7 +455,7 @@ where
storage_proof_task_handle.clone(),
)
.with_branch_node_masks(true)
.storage_proof(hashed_address, proof_targets);
.decoded_storage_proof(hashed_address, proof_targets);
let elapsed = start.elapsed();
trace!(
target: "engine::root",
@@ -473,7 +473,10 @@ where
sequence_number: proof_sequence_number,
update: SparseTrieUpdate {
state: hashed_state_update,
multiproof: MultiProof::from_storage_proof(hashed_address, proof),
multiproof: DecodedMultiProof::from_storage_proof(
hashed_address,
proof,
),
},
elapsed,
}),
@@ -523,7 +526,7 @@ where
storage_proof_task_handle.clone(),
)
.with_branch_node_masks(true)
.multiproof(proof_targets);
.decoded_multiproof(proof_targets);
let elapsed = start.elapsed();
trace!(
target: "engine::root",
@@ -973,7 +976,7 @@ where
if let Some(combined_update) = self.on_proof(
sequence_number,
SparseTrieUpdate { state, multiproof: MultiProof::default() },
SparseTrieUpdate { state, multiproof: Default::default() },
) {
let _ = self.to_sparse_trie.send(combined_update);
}
@@ -1117,7 +1120,7 @@ mod tests {
use super::*;
use alloy_primitives::map::B256Set;
use reth_provider::{providers::ConsistentDbView, test_utils::create_test_provider_factory};
use reth_trie::TrieInput;
use reth_trie::{MultiProof, TrieInput};
use reth_trie_parallel::proof_task::{ProofTaskCtx, ProofTaskManager};
use revm_primitives::{B256, U256};
use std::sync::Arc;
@@ -1169,11 +1172,11 @@ mod tests {
let proof2 = MultiProof::default();
sequencer.next_sequence = 2;
let ready = sequencer.add_proof(0, SparseTrieUpdate::from_multiproof(proof1));
let ready = sequencer.add_proof(0, SparseTrieUpdate::from_multiproof(proof1).unwrap());
assert_eq!(ready.len(), 1);
assert!(!sequencer.has_pending());
let ready = sequencer.add_proof(1, SparseTrieUpdate::from_multiproof(proof2));
let ready = sequencer.add_proof(1, SparseTrieUpdate::from_multiproof(proof2).unwrap());
assert_eq!(ready.len(), 1);
assert!(!sequencer.has_pending());
}
@@ -1186,15 +1189,15 @@ mod tests {
let proof3 = MultiProof::default();
sequencer.next_sequence = 3;
let ready = sequencer.add_proof(2, SparseTrieUpdate::from_multiproof(proof3));
let ready = sequencer.add_proof(2, SparseTrieUpdate::from_multiproof(proof3).unwrap());
assert_eq!(ready.len(), 0);
assert!(sequencer.has_pending());
let ready = sequencer.add_proof(0, SparseTrieUpdate::from_multiproof(proof1));
let ready = sequencer.add_proof(0, SparseTrieUpdate::from_multiproof(proof1).unwrap());
assert_eq!(ready.len(), 1);
assert!(sequencer.has_pending());
let ready = sequencer.add_proof(1, SparseTrieUpdate::from_multiproof(proof2));
let ready = sequencer.add_proof(1, SparseTrieUpdate::from_multiproof(proof2).unwrap());
assert_eq!(ready.len(), 2);
assert!(!sequencer.has_pending());
}
@@ -1206,10 +1209,10 @@ mod tests {
let proof3 = MultiProof::default();
sequencer.next_sequence = 3;
let ready = sequencer.add_proof(0, SparseTrieUpdate::from_multiproof(proof1));
let ready = sequencer.add_proof(0, SparseTrieUpdate::from_multiproof(proof1).unwrap());
assert_eq!(ready.len(), 1);
let ready = sequencer.add_proof(2, SparseTrieUpdate::from_multiproof(proof3));
let ready = sequencer.add_proof(2, SparseTrieUpdate::from_multiproof(proof3).unwrap());
assert_eq!(ready.len(), 0);
assert!(sequencer.has_pending());
}
@@ -1220,10 +1223,10 @@ mod tests {
let proof1 = MultiProof::default();
let proof2 = MultiProof::default();
let ready = sequencer.add_proof(0, SparseTrieUpdate::from_multiproof(proof1));
let ready = sequencer.add_proof(0, SparseTrieUpdate::from_multiproof(proof1).unwrap());
assert_eq!(ready.len(), 1);
let ready = sequencer.add_proof(0, SparseTrieUpdate::from_multiproof(proof2));
let ready = sequencer.add_proof(0, SparseTrieUpdate::from_multiproof(proof2).unwrap());
assert_eq!(ready.len(), 0);
assert!(!sequencer.has_pending());
}
@@ -1234,12 +1237,13 @@ mod tests {
let proofs: Vec<_> = (0..5).map(|_| MultiProof::default()).collect();
sequencer.next_sequence = 5;
sequencer.add_proof(4, SparseTrieUpdate::from_multiproof(proofs[4].clone()));
sequencer.add_proof(2, SparseTrieUpdate::from_multiproof(proofs[2].clone()));
sequencer.add_proof(1, SparseTrieUpdate::from_multiproof(proofs[1].clone()));
sequencer.add_proof(3, SparseTrieUpdate::from_multiproof(proofs[3].clone()));
sequencer.add_proof(4, SparseTrieUpdate::from_multiproof(proofs[4].clone()).unwrap());
sequencer.add_proof(2, SparseTrieUpdate::from_multiproof(proofs[2].clone()).unwrap());
sequencer.add_proof(1, SparseTrieUpdate::from_multiproof(proofs[1].clone()).unwrap());
sequencer.add_proof(3, SparseTrieUpdate::from_multiproof(proofs[3].clone()).unwrap());
let ready = sequencer.add_proof(0, SparseTrieUpdate::from_multiproof(proofs[0].clone()));
let ready =
sequencer.add_proof(0, SparseTrieUpdate::from_multiproof(proofs[0].clone()).unwrap());
assert_eq!(ready.len(), 5);
assert!(!sequencer.has_pending());
}

View File

@@ -137,7 +137,7 @@ where
let started_at = Instant::now();
// Reveal new accounts and storage slots.
trie.reveal_multiproof(multiproof)?;
trie.reveal_decoded_multiproof(multiproof)?;
let reveal_multiproof_elapsed = started_at.elapsed();
trace!(
target: "engine::root::sparse",

View File

@@ -308,6 +308,14 @@ pub struct DecodedMultiProof {
}
impl DecodedMultiProof {
/// Returns true if the multiproof is empty.
pub fn is_empty(&self) -> bool {
self.account_subtree.is_empty() &&
self.branch_node_hash_masks.is_empty() &&
self.branch_node_tree_masks.is_empty() &&
self.storages.is_empty()
}
/// Return the account proof nodes for the given account path.
pub fn account_proof_nodes(&self, path: &Nibbles) -> Vec<(Nibbles, TrieNode)> {
self.account_subtree.matching_nodes_sorted(path)
@@ -404,6 +412,36 @@ impl DecodedMultiProof {
}
}
}
/// Create a [`DecodedMultiProof`] from a [`DecodedStorageMultiProof`].
pub fn from_storage_proof(
hashed_address: B256,
storage_proof: DecodedStorageMultiProof,
) -> Self {
Self {
storages: B256Map::from_iter([(hashed_address, storage_proof)]),
..Default::default()
}
}
}
impl TryFrom<MultiProof> for DecodedMultiProof {
type Error = alloy_rlp::Error;
fn try_from(multi_proof: MultiProof) -> Result<Self, Self::Error> {
let account_subtree = DecodedProofNodes::try_from(multi_proof.account_subtree)?;
let storages = multi_proof
.storages
.into_iter()
.map(|(address, storage)| Ok((address, storage.try_into()?)))
.collect::<Result<B256Map<_>, alloy_rlp::Error>>()?;
Ok(Self {
account_subtree,
branch_node_hash_masks: multi_proof.branch_node_hash_masks,
branch_node_tree_masks: multi_proof.branch_node_tree_masks,
storages,
})
}
}
/// The merkle multiproof of storage trie.
@@ -513,6 +551,20 @@ impl DecodedStorageMultiProof {
}
}
impl TryFrom<StorageMultiProof> for DecodedStorageMultiProof {
type Error = alloy_rlp::Error;
fn try_from(multi_proof: StorageMultiProof) -> Result<Self, Self::Error> {
let subtree = DecodedProofNodes::try_from(multi_proof.subtree)?;
Ok(Self {
root: multi_proof.root,
subtree,
branch_node_hash_masks: multi_proof.branch_node_hash_masks,
branch_node_tree_masks: multi_proof.branch_node_tree_masks,
})
}
}
/// The merkle proof with the relevant account info.
#[derive(Clone, PartialEq, Eq, Debug)]
#[cfg_attr(any(test, feature = "serde"), derive(serde::Serialize, serde::Deserialize))]

View File

@@ -25,8 +25,8 @@ use reth_trie::{
trie_cursor::{InMemoryTrieCursorFactory, TrieCursorFactory},
updates::TrieUpdatesSorted,
walker::TrieWalker,
HashBuilder, HashedPostStateSorted, MultiProof, MultiProofTargets, Nibbles, StorageMultiProof,
TRIE_ACCOUNT_RLP_MAX_SIZE,
DecodedMultiProof, DecodedStorageMultiProof, HashBuilder, HashedPostStateSorted, MultiProof,
MultiProofTargets, Nibbles, StorageMultiProof, TRIE_ACCOUNT_RLP_MAX_SIZE,
};
use reth_trie_common::proof::ProofRetainer;
use reth_trie_db::{DatabaseHashedCursorFactory, DatabaseTrieCursorFactory};
@@ -145,6 +145,21 @@ where
proof_result
}
/// Generate a [`DecodedStorageMultiProof`] for the given proof by first calling
/// `storage_proof`, then decoding the proof nodes.
pub fn decoded_storage_proof(
self,
hashed_address: B256,
target_slots: B256Set,
) -> Result<DecodedStorageMultiProof, ParallelStateRootError> {
let proof = self.storage_proof(hashed_address, target_slots)?;
// Now decode the nodes of the proof
let proof = proof.try_into()?;
Ok(proof)
}
/// Generate a state multiproof according to specified targets.
pub fn multiproof(
self,
@@ -317,6 +332,21 @@ where
Ok(MultiProof { account_subtree, branch_node_hash_masks, branch_node_tree_masks, storages })
}
/// Returns a [`DecodedMultiProof`] for the given proof.
///
/// Uses `multiproof` first to get the proof, and then decodes the nodes of the multiproof.
pub fn decoded_multiproof(
self,
targets: MultiProofTargets,
) -> Result<DecodedMultiProof, ParallelStateRootError> {
let multiproof = self.multiproof(targets)?;
// Now decode the nodes of the multiproof
let multiproof = multiproof.try_into()?;
Ok(multiproof)
}
}
#[cfg(test)]

View File

@@ -250,6 +250,12 @@ impl From<ParallelStateRootError> for ProviderError {
}
}
impl From<alloy_rlp::Error> for ParallelStateRootError {
fn from(error: alloy_rlp::Error) -> Self {
Self::Provider(ProviderError::Rlp(error))
}
}
#[cfg(test)]
mod tests {
use super::*;

View File

@@ -17,6 +17,7 @@ reth-primitives-traits.workspace = true
reth-execution-errors.workspace = true
reth-trie-common.workspace = true
tracing.workspace = true
alloy-trie.workspace = true
# alloy
alloy-primitives.workspace = true
@@ -53,12 +54,13 @@ rand_08.workspace = true
[features]
default = ["std", "metrics"]
std = [
"reth-storage-api/std",
"reth-primitives-traits/std",
"reth-execution-errors/std",
"reth-trie-common/std",
"alloy-primitives/std",
"alloy-rlp/std",
"alloy-trie/std",
"reth-execution-errors/std",
"reth-primitives-traits/std",
"reth-storage-api/std",
"reth-trie-common/std",
"tracing/std",
]
metrics = ["dep:reth-metrics", "dep:metrics", "std"]
@@ -72,9 +74,10 @@ test-utils = [
]
arbitrary = [
"std",
"alloy-primitives/arbitrary",
"alloy-trie/arbitrary",
"reth-primitives-traits/arbitrary",
"reth-trie-common/arbitrary",
"alloy-primitives/arbitrary",
"smallvec/arbitrary",
]

View File

@@ -9,14 +9,15 @@ use alloy_primitives::{
Bytes, B256,
};
use alloy_rlp::{Decodable, Encodable};
use alloy_trie::proof::DecodedProofNodes;
use core::{fmt, iter::Peekable};
use reth_execution_errors::{SparseStateTrieErrorKind, SparseStateTrieResult, SparseTrieErrorKind};
use reth_primitives_traits::Account;
use reth_trie_common::{
proof::ProofNodes,
updates::{StorageTrieUpdates, TrieUpdates},
MultiProof, Nibbles, RlpNode, StorageMultiProof, TrieAccount, TrieMask, TrieNode,
EMPTY_ROOT_HASH, TRIE_ACCOUNT_RLP_MAX_SIZE,
DecodedMultiProof, DecodedStorageMultiProof, MultiProof, Nibbles, RlpNode, StorageMultiProof,
TrieAccount, TrieMask, TrieNode, EMPTY_ROOT_HASH, TRIE_ACCOUNT_RLP_MAX_SIZE,
};
use tracing::trace;
@@ -282,7 +283,20 @@ impl<F: BlindedProviderFactory> SparseStateTrie<F> {
/// Reveal unknown trie paths from multiproof.
/// NOTE: This method does not extensively validate the proof.
pub fn reveal_multiproof(&mut self, multiproof: MultiProof) -> SparseStateTrieResult<()> {
let MultiProof {
// first decode the multiproof
let decoded_multiproof = multiproof.try_into()?;
// then reveal the decoded multiproof
self.reveal_decoded_multiproof(decoded_multiproof)
}
/// Reveal unknown trie paths from decoded multiproof.
/// NOTE: This method does not extensively validate the proof.
pub fn reveal_decoded_multiproof(
&mut self,
multiproof: DecodedMultiProof,
) -> SparseStateTrieResult<()> {
let DecodedMultiProof {
account_subtree,
storages,
branch_node_hash_masks,
@@ -290,7 +304,7 @@ impl<F: BlindedProviderFactory> SparseStateTrie<F> {
} = multiproof;
// first reveal the account proof nodes
self.reveal_account_multiproof(
self.reveal_decoded_account_multiproof(
account_subtree,
branch_node_hash_masks,
branch_node_tree_masks,
@@ -298,7 +312,7 @@ impl<F: BlindedProviderFactory> SparseStateTrie<F> {
// then reveal storage proof nodes for each storage trie
for (account, storage_subtree) in storages {
self.reveal_storage_multiproof(account, storage_subtree)?;
self.reveal_decoded_storage_multiproof(account, storage_subtree)?;
}
Ok(())
@@ -311,12 +325,28 @@ impl<F: BlindedProviderFactory> SparseStateTrie<F> {
branch_node_hash_masks: HashMap<Nibbles, TrieMask>,
branch_node_tree_masks: HashMap<Nibbles, TrieMask>,
) -> SparseStateTrieResult<()> {
let DecodedProofNodes {
// decode the multiproof first
let decoded_multiproof = account_subtree.try_into()?;
self.reveal_decoded_account_multiproof(
decoded_multiproof,
branch_node_hash_masks,
branch_node_tree_masks,
)
}
/// Reveals a decoded account multiproof.
pub fn reveal_decoded_account_multiproof(
&mut self,
account_subtree: DecodedProofNodes,
branch_node_hash_masks: HashMap<Nibbles, TrieMask>,
branch_node_tree_masks: HashMap<Nibbles, TrieMask>,
) -> SparseStateTrieResult<()> {
let FilteredProofNodes {
nodes,
new_nodes,
total_nodes: _total_nodes,
skipped_nodes: _skipped_nodes,
} = decode_proof_nodes(account_subtree, &self.revealed_account_paths)?;
} = filter_revealed_nodes(account_subtree, &self.revealed_account_paths)?;
#[cfg(feature = "metrics")]
{
self.metrics.increment_total_account_nodes(_total_nodes as u64);
@@ -366,15 +396,26 @@ impl<F: BlindedProviderFactory> SparseStateTrie<F> {
&mut self,
account: B256,
storage_subtree: StorageMultiProof,
) -> SparseStateTrieResult<()> {
// decode the multiproof first
let decoded_multiproof = storage_subtree.try_into()?;
self.reveal_decoded_storage_multiproof(account, decoded_multiproof)
}
/// Reveals a decoded storage multiproof for the given address.
pub fn reveal_decoded_storage_multiproof(
&mut self,
account: B256,
storage_subtree: DecodedStorageMultiProof,
) -> SparseStateTrieResult<()> {
let revealed_nodes = self.revealed_storage_paths.entry(account).or_default();
let DecodedProofNodes {
let FilteredProofNodes {
nodes,
new_nodes,
total_nodes: _total_nodes,
skipped_nodes: _skipped_nodes,
} = decode_proof_nodes(storage_subtree.subtree, revealed_nodes)?;
} = filter_revealed_nodes(storage_subtree.subtree, revealed_nodes)?;
#[cfg(feature = "metrics")]
{
self.metrics.increment_total_storage_nodes(_total_nodes as u64);
@@ -829,9 +870,9 @@ impl<F: BlindedProviderFactory> SparseStateTrie<F> {
}
}
/// Result of [`decode_proof_nodes`].
/// Result of [`filter_revealed_nodes`].
#[derive(Debug, PartialEq, Eq)]
struct DecodedProofNodes {
struct FilteredProofNodes {
/// Filtered, decoded and sorted proof nodes.
nodes: Vec<(Nibbles, TrieNode)>,
/// Number of nodes in the proof.
@@ -843,20 +884,20 @@ struct DecodedProofNodes {
new_nodes: usize,
}
/// Decodes the proof nodes returning additional information about the number of total, skipped, and
/// new nodes.
fn decode_proof_nodes(
proof_nodes: ProofNodes,
/// Filters the decoded nodes that are already revealed and returns additional information about the
/// number of total, skipped, and new nodes.
fn filter_revealed_nodes(
proof_nodes: DecodedProofNodes,
revealed_nodes: &HashSet<Nibbles>,
) -> alloy_rlp::Result<DecodedProofNodes> {
let mut result = DecodedProofNodes {
) -> alloy_rlp::Result<FilteredProofNodes> {
let mut result = FilteredProofNodes {
nodes: Vec::with_capacity(proof_nodes.len()),
total_nodes: 0,
skipped_nodes: 0,
new_nodes: 0,
};
for (path, bytes) in proof_nodes.into_inner() {
for (path, node) in proof_nodes.into_inner() {
result.total_nodes += 1;
// If the node is already revealed, skip it.
if revealed_nodes.contains(&path) {
@@ -864,7 +905,6 @@ fn decode_proof_nodes(
continue
}
let node = TrieNode::decode(&mut &bytes[..])?;
result.new_nodes += 1;
// If it's a branch node, increase the number of new nodes by the number of children
// according to the state mask.
@@ -892,7 +932,7 @@ mod tests {
use assert_matches::assert_matches;
use rand::{rngs::StdRng, Rng, SeedableRng};
use reth_primitives_traits::Account;
use reth_trie::{updates::StorageTrieUpdates, HashBuilder, EMPTY_ROOT_HASH};
use reth_trie::{updates::StorageTrieUpdates, HashBuilder, MultiProof, EMPTY_ROOT_HASH};
use reth_trie_common::{
proof::{ProofNodes, ProofRetainer},
BranchNode, LeafNode, StorageMultiProof, TrieMask,
@@ -987,7 +1027,7 @@ mod tests {
};
// Reveal multiproof and check that the state trie contains the leaf node and value
sparse.reveal_multiproof(multiproof.clone()).unwrap();
sparse.reveal_decoded_multiproof(multiproof.clone().try_into().unwrap()).unwrap();
assert!(sparse
.state_trie_ref()
.unwrap()
@@ -1014,7 +1054,7 @@ mod tests {
// Reveal multiproof again and check that the state trie still does not contain the leaf
// node and value, because they were already revealed before
sparse.reveal_multiproof(multiproof).unwrap();
sparse.reveal_decoded_multiproof(multiproof.try_into().unwrap()).unwrap();
assert!(!sparse
.state_trie_ref()
.unwrap()
@@ -1066,7 +1106,7 @@ mod tests {
};
// Reveal multiproof and check that the storage trie contains the leaf node and value
sparse.reveal_multiproof(multiproof.clone()).unwrap();
sparse.reveal_decoded_multiproof(multiproof.clone().try_into().unwrap()).unwrap();
assert!(sparse
.storage_trie_ref(&B256::ZERO)
.unwrap()
@@ -1096,7 +1136,7 @@ mod tests {
// Reveal multiproof again and check that the storage trie still does not contain the leaf
// node and value, because they were already revealed before
sparse.reveal_multiproof(multiproof).unwrap();
sparse.reveal_decoded_multiproof(multiproof.try_into().unwrap()).unwrap();
assert!(!sparse
.storage_trie_ref(&B256::ZERO)
.unwrap()
@@ -1166,34 +1206,38 @@ mod tests {
let mut sparse = SparseStateTrie::default().with_updates(true);
sparse
.reveal_multiproof(MultiProof {
account_subtree: proof_nodes,
branch_node_hash_masks: HashMap::from_iter([(
Nibbles::from_nibbles([0x1]),
TrieMask::new(0b00),
)]),
branch_node_tree_masks: HashMap::default(),
storages: HashMap::from_iter([
(
address_1,
StorageMultiProof {
root,
subtree: storage_proof_nodes.clone(),
branch_node_hash_masks: storage_branch_node_hash_masks.clone(),
branch_node_tree_masks: HashMap::default(),
},
),
(
address_2,
StorageMultiProof {
root,
subtree: storage_proof_nodes,
branch_node_hash_masks: storage_branch_node_hash_masks,
branch_node_tree_masks: HashMap::default(),
},
),
]),
})
.reveal_decoded_multiproof(
MultiProof {
account_subtree: proof_nodes,
branch_node_hash_masks: HashMap::from_iter([(
Nibbles::from_nibbles([0x1]),
TrieMask::new(0b00),
)]),
branch_node_tree_masks: HashMap::default(),
storages: HashMap::from_iter([
(
address_1,
StorageMultiProof {
root,
subtree: storage_proof_nodes.clone(),
branch_node_hash_masks: storage_branch_node_hash_masks.clone(),
branch_node_tree_masks: HashMap::default(),
},
),
(
address_2,
StorageMultiProof {
root,
subtree: storage_proof_nodes,
branch_node_hash_masks: storage_branch_node_hash_masks,
branch_node_tree_masks: HashMap::default(),
},
),
]),
}
.try_into()
.unwrap(),
)
.unwrap();
assert_eq!(sparse.root().unwrap(), root);
@@ -1235,7 +1279,7 @@ mod tests {
}
#[test]
fn test_decode_proof_nodes() {
fn test_filter_revealed_nodes() {
let revealed_nodes = HashSet::from_iter([Nibbles::from_nibbles([0x0])]);
let leaf = TrieNode::Leaf(LeafNode::new(Nibbles::default(), alloy_rlp::encode([])));
let leaf_encoded = alloy_rlp::encode(&leaf);
@@ -1243,17 +1287,17 @@ mod tests {
vec![RlpNode::from_rlp(&leaf_encoded), RlpNode::from_rlp(&leaf_encoded)],
TrieMask::new(0b11),
));
let proof_nodes = ProofNodes::from_iter([
(Nibbles::default(), alloy_rlp::encode(&branch).into()),
(Nibbles::from_nibbles([0x0]), leaf_encoded.clone().into()),
(Nibbles::from_nibbles([0x1]), leaf_encoded.into()),
let proof_nodes = alloy_trie::proof::DecodedProofNodes::from_iter([
(Nibbles::default(), branch.clone()),
(Nibbles::from_nibbles([0x0]), leaf.clone()),
(Nibbles::from_nibbles([0x1]), leaf.clone()),
]);
let decoded = decode_proof_nodes(proof_nodes, &revealed_nodes).unwrap();
let decoded = filter_revealed_nodes(proof_nodes, &revealed_nodes).unwrap();
assert_eq!(
decoded,
DecodedProofNodes {
FilteredProofNodes {
nodes: vec![(Nibbles::default(), branch), (Nibbles::from_nibbles([0x1]), leaf)],
// Branch, leaf, leaf
total_nodes: 3,