Compare commits

...

1 Commits

Author SHA1 Message Date
Georgios Konstantopoulos
4bcd6e03db feat(trie): add trie_nodes_batch API to TrieNodeProvider trait
Adds batch node fetching capability to reduce O(n²) proof walks when
revealing multiple blinded nodes. Default implementation falls back to
sequential fetching.

Amp-Thread-ID: https://ampcode.com/threads/T-019bfe25-43f3-75ac-98f7-32bf937b69e1
Co-authored-by: Amp <amp@ampcode.com>
2026-01-27 07:34:41 +00:00
2 changed files with 20 additions and 3 deletions

View File

@@ -1,6 +1,6 @@
//! Traits and default implementations related to retrieval of blinded trie nodes.
use alloy_primitives::{Bytes, B256};
use alloy_primitives::{map::HashMap, Bytes, B256};
use reth_execution_errors::SparseTrieError;
use reth_trie_common::{Nibbles, TrieMask};
@@ -35,6 +35,23 @@ pub struct RevealedNode {
pub trait TrieNodeProvider {
/// Retrieve trie node by path.
fn trie_node(&self, path: &Nibbles) -> Result<Option<RevealedNode>, SparseTrieError>;
/// Batch retrieve trie nodes by paths.
///
/// Returns a map from path to revealed node. Missing nodes are omitted.
/// Default implementation falls back to sequential fetching.
fn trie_nodes_batch(
&self,
paths: &[Nibbles],
) -> Result<HashMap<Nibbles, RevealedNode>, SparseTrieError> {
let mut result = HashMap::with_capacity_and_hasher(paths.len(), Default::default());
for path in paths {
if let Some(node) = self.trie_node(path)? {
result.insert(path.clone(), node);
}
}
Ok(result)
}
}
/// Default trie node provider factory that creates [`DefaultTrieNodeProviderFactory`].

View File

@@ -1417,7 +1417,7 @@ impl SerialSparseTrie {
while let Some((mut path, level)) = paths.pop() {
match self.nodes.get(&path).unwrap() {
SparseNode::Empty | SparseNode::Hash(_) => {}
SparseNode::Leaf { key: _, hash } => {
SparseNode::Leaf { key: _, hash, .. } => {
if hash.is_some() && !prefix_set.contains(&path) {
continue
}
@@ -1438,7 +1438,7 @@ impl SerialSparseTrie {
paths.push((path, level + 1));
}
}
SparseNode::Branch { state_mask, hash, store_in_db_trie: _ } => {
SparseNode::Branch { state_mask, hash, .. } => {
if hash.is_some() && !prefix_set.contains(&path) {
continue
}