mirror of
https://github.com/paradigmxyz/reth.git
synced 2026-02-19 03:04:27 -05:00
perf(trie): reuse proof nodes buffer in reveal_nodes (#21648)
Co-authored-by: Amp <amp@ampcode.com> Co-authored-by: Alexey Shekhirin <github@shekhirin.com>
This commit is contained in:
committed by
GitHub
parent
543c77a374
commit
12d0b74a16
@@ -587,11 +587,14 @@ where
|
||||
target: "engine::tree::payload_processor",
|
||||
"State root receiver dropped, clearing trie"
|
||||
);
|
||||
let trie = task.into_cleared_trie(
|
||||
let (trie, deferred) = task.into_cleared_trie(
|
||||
SPARSE_TRIE_MAX_NODES_SHRINK_CAPACITY,
|
||||
SPARSE_TRIE_MAX_VALUES_SHRINK_CAPACITY,
|
||||
);
|
||||
guard.store(PreservedSparseTrie::cleared(trie));
|
||||
// Drop guard before deferred to release lock before expensive deallocations
|
||||
drop(guard);
|
||||
drop(deferred);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -599,9 +602,9 @@ where
|
||||
// A failed computation may have left the trie in a partially updated state.
|
||||
let _enter =
|
||||
debug_span!(target: "engine::tree::payload_processor", "preserve").entered();
|
||||
if let Some(state_root) = computed_state_root {
|
||||
let deferred = if let Some(state_root) = computed_state_root {
|
||||
let start = std::time::Instant::now();
|
||||
let trie = task.into_trie_for_reuse(
|
||||
let (trie, deferred) = task.into_trie_for_reuse(
|
||||
prune_depth,
|
||||
max_storage_tries,
|
||||
SPARSE_TRIE_MAX_NODES_SHRINK_CAPACITY,
|
||||
@@ -611,17 +614,22 @@ where
|
||||
.into_trie_for_reuse_duration_histogram
|
||||
.record(start.elapsed().as_secs_f64());
|
||||
guard.store(PreservedSparseTrie::anchored(trie, state_root));
|
||||
deferred
|
||||
} else {
|
||||
debug!(
|
||||
target: "engine::tree::payload_processor",
|
||||
"State root computation failed, clearing trie"
|
||||
);
|
||||
let trie = task.into_cleared_trie(
|
||||
let (trie, deferred) = task.into_cleared_trie(
|
||||
SPARSE_TRIE_MAX_NODES_SHRINK_CAPACITY,
|
||||
SPARSE_TRIE_MAX_VALUES_SHRINK_CAPACITY,
|
||||
);
|
||||
guard.store(PreservedSparseTrie::cleared(trie));
|
||||
}
|
||||
deferred
|
||||
};
|
||||
// Drop guard before deferred to release lock before expensive deallocations
|
||||
drop(guard);
|
||||
drop(deferred);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ use reth_trie_parallel::{
|
||||
use reth_trie_sparse::{
|
||||
errors::{SparseStateTrieResult, SparseTrieErrorKind, SparseTrieResult},
|
||||
provider::{TrieNodeProvider, TrieNodeProviderFactory},
|
||||
LeafUpdate, SerialSparseTrie, SparseStateTrie, SparseTrie, SparseTrieExt,
|
||||
DeferredDrops, LeafUpdate, SerialSparseTrie, SparseStateTrie, SparseTrie, SparseTrieExt,
|
||||
};
|
||||
use revm_primitives::{hash_map::Entry, B256Map};
|
||||
use smallvec::SmallVec;
|
||||
@@ -72,7 +72,7 @@ where
|
||||
max_storage_tries: usize,
|
||||
max_nodes_capacity: usize,
|
||||
max_values_capacity: usize,
|
||||
) -> SparseStateTrie<A, S> {
|
||||
) -> (SparseStateTrie<A, S>, DeferredDrops) {
|
||||
match self {
|
||||
Self::Cleared(task) => task.into_cleared_trie(max_nodes_capacity, max_values_capacity),
|
||||
Self::Cached(task) => task.into_trie_for_reuse(
|
||||
@@ -88,7 +88,7 @@ where
|
||||
self,
|
||||
max_nodes_capacity: usize,
|
||||
max_values_capacity: usize,
|
||||
) -> SparseStateTrie<A, S> {
|
||||
) -> (SparseStateTrie<A, S>, DeferredDrops) {
|
||||
match self {
|
||||
Self::Cleared(task) => task.into_cleared_trie(max_nodes_capacity, max_values_capacity),
|
||||
Self::Cached(task) => task.into_cleared_trie(max_nodes_capacity, max_values_capacity),
|
||||
@@ -199,10 +199,11 @@ where
|
||||
mut self,
|
||||
max_nodes_capacity: usize,
|
||||
max_values_capacity: usize,
|
||||
) -> SparseStateTrie<A, S> {
|
||||
) -> (SparseStateTrie<A, S>, DeferredDrops) {
|
||||
self.trie.clear();
|
||||
self.trie.shrink_to(max_nodes_capacity, max_values_capacity);
|
||||
self.trie
|
||||
let deferred = self.trie.take_deferred_drops();
|
||||
(self.trie, deferred)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -312,10 +313,11 @@ where
|
||||
max_storage_tries: usize,
|
||||
max_nodes_capacity: usize,
|
||||
max_values_capacity: usize,
|
||||
) -> SparseStateTrie<A, S> {
|
||||
) -> (SparseStateTrie<A, S>, DeferredDrops) {
|
||||
self.trie.prune(prune_depth, max_storage_tries);
|
||||
self.trie.shrink_to(max_nodes_capacity, max_values_capacity);
|
||||
self.trie
|
||||
let deferred = self.trie.take_deferred_drops();
|
||||
(self.trie, deferred)
|
||||
}
|
||||
|
||||
/// Clears and shrinks the trie, discarding all state.
|
||||
@@ -326,10 +328,11 @@ where
|
||||
mut self,
|
||||
max_nodes_capacity: usize,
|
||||
max_values_capacity: usize,
|
||||
) -> SparseStateTrie<A, S> {
|
||||
) -> (SparseStateTrie<A, S>, DeferredDrops) {
|
||||
self.trie.clear();
|
||||
self.trie.shrink_to(max_nodes_capacity, max_values_capacity);
|
||||
self.trie
|
||||
let deferred = self.trie.take_deferred_drops();
|
||||
(self.trie, deferred)
|
||||
}
|
||||
|
||||
/// Runs the sparse trie task to completion.
|
||||
|
||||
@@ -175,7 +175,7 @@ impl SparseTrie for ParallelSparseTrie {
|
||||
self.updates = retain_updates.then(Default::default);
|
||||
}
|
||||
|
||||
fn reveal_nodes(&mut self, mut nodes: Vec<ProofTrieNode>) -> SparseTrieResult<()> {
|
||||
fn reveal_nodes(&mut self, nodes: &mut [ProofTrieNode]) -> SparseTrieResult<()> {
|
||||
if nodes.is_empty() {
|
||||
return Ok(())
|
||||
}
|
||||
@@ -192,7 +192,7 @@ impl SparseTrie for ParallelSparseTrie {
|
||||
|
||||
// Update the top-level branch node masks. This is simple and can't be done in parallel.
|
||||
self.branch_node_masks.reserve(nodes.len());
|
||||
for ProofTrieNode { path, masks, .. } in &nodes {
|
||||
for ProofTrieNode { path, masks, .. } in nodes.iter() {
|
||||
if let Some(branch_masks) = masks {
|
||||
self.branch_node_masks.insert(*path, *branch_masks);
|
||||
}
|
||||
@@ -4095,7 +4095,7 @@ mod tests {
|
||||
let node = create_leaf_node([0x2, 0x3], 42);
|
||||
let masks = None;
|
||||
|
||||
trie.reveal_nodes(vec![ProofTrieNode { path, node, masks }]).unwrap();
|
||||
trie.reveal_nodes(&mut [ProofTrieNode { path, node, masks }]).unwrap();
|
||||
|
||||
assert_matches!(
|
||||
trie.upper_subtrie.nodes.get(&path),
|
||||
@@ -4116,7 +4116,7 @@ mod tests {
|
||||
let node = create_leaf_node([0x3, 0x4], 42);
|
||||
let masks = None;
|
||||
|
||||
trie.reveal_nodes(vec![ProofTrieNode { path, node, masks }]).unwrap();
|
||||
trie.reveal_nodes(&mut [ProofTrieNode { path, node, masks }]).unwrap();
|
||||
|
||||
// Check that the lower subtrie was created
|
||||
let idx = path_subtrie_index_unchecked(&path);
|
||||
@@ -4140,7 +4140,7 @@ mod tests {
|
||||
let node = create_leaf_node([0x4, 0x5], 42);
|
||||
let masks = None;
|
||||
|
||||
trie.reveal_nodes(vec![ProofTrieNode { path, node, masks }]).unwrap();
|
||||
trie.reveal_nodes(&mut [ProofTrieNode { path, node, masks }]).unwrap();
|
||||
|
||||
// Check that the lower subtrie's path hasn't changed
|
||||
let idx = path_subtrie_index_unchecked(&path);
|
||||
@@ -4201,7 +4201,7 @@ mod tests {
|
||||
let node = create_extension_node([0x2], child_hash);
|
||||
let masks = None;
|
||||
|
||||
trie.reveal_nodes(vec![ProofTrieNode { path, node, masks }]).unwrap();
|
||||
trie.reveal_nodes(&mut [ProofTrieNode { path, node, masks }]).unwrap();
|
||||
|
||||
// Extension node should be in upper trie
|
||||
assert_matches!(
|
||||
@@ -4263,7 +4263,7 @@ mod tests {
|
||||
let node = create_branch_node_with_children(&[0x0, 0x7, 0xf], child_hashes.clone());
|
||||
let masks = None;
|
||||
|
||||
trie.reveal_nodes(vec![ProofTrieNode { path, node, masks }]).unwrap();
|
||||
trie.reveal_nodes(&mut [ProofTrieNode { path, node, masks }]).unwrap();
|
||||
|
||||
// Branch node should be in upper trie
|
||||
assert_matches!(
|
||||
@@ -4319,7 +4319,7 @@ mod tests {
|
||||
let branch_node = create_branch_node_with_children(&[0x0, 0x1, 0x2], child_hashes);
|
||||
|
||||
// Reveal nodes using reveal_nodes
|
||||
trie.reveal_nodes(vec![
|
||||
trie.reveal_nodes(&mut [
|
||||
ProofTrieNode { path: branch_path, node: branch_node, masks: None },
|
||||
ProofTrieNode { path: leaf_1_path, node: leaf_1, masks: None },
|
||||
ProofTrieNode { path: leaf_2_path, node: leaf_2, masks: None },
|
||||
@@ -5022,7 +5022,7 @@ mod tests {
|
||||
let removed_branch_path = Nibbles::from_nibbles([0x4, 0xf, 0x8, 0x8, 0x0, 0x7, 0x2]);
|
||||
|
||||
// Convert the logs into reveal_nodes call on a fresh ParallelSparseTrie
|
||||
let nodes = vec![
|
||||
let mut nodes = vec![
|
||||
// Branch at 0x4f8807
|
||||
ProofTrieNode {
|
||||
path: branch_path,
|
||||
@@ -5153,7 +5153,7 @@ mod tests {
|
||||
.unwrap();
|
||||
|
||||
// Call reveal_nodes
|
||||
trie.reveal_nodes(nodes).unwrap();
|
||||
trie.reveal_nodes(&mut nodes).unwrap();
|
||||
|
||||
// Remove the leaf at "0x4f88072c077f86613088dfcae648abe831fadca55ad43ab165d1680dd567b5d6"
|
||||
let leaf_key = Nibbles::from_nibbles([
|
||||
@@ -5239,7 +5239,7 @@ mod tests {
|
||||
|
||||
// Step 2: Reveal nodes in the trie
|
||||
let mut trie = ParallelSparseTrie::from_root(extension, None, true).unwrap();
|
||||
trie.reveal_nodes(vec![
|
||||
trie.reveal_nodes(&mut [
|
||||
ProofTrieNode { path: branch_path, node: branch, masks: None },
|
||||
ProofTrieNode { path: leaf_1_path, node: leaf_1, masks: None },
|
||||
ProofTrieNode { path: leaf_2_path, node: leaf_2, masks: None },
|
||||
@@ -5779,7 +5779,7 @@ mod tests {
|
||||
// ├── 0 -> Hash (Path = 0)
|
||||
// └── 1 -> Leaf (Path = 1)
|
||||
sparse
|
||||
.reveal_nodes(vec![
|
||||
.reveal_nodes(&mut [
|
||||
ProofTrieNode {
|
||||
path: Nibbles::default(),
|
||||
node: branch,
|
||||
@@ -5834,7 +5834,7 @@ mod tests {
|
||||
// ├── 0 -> Hash (Path = 0)
|
||||
// └── 1 -> Leaf (Path = 1)
|
||||
sparse
|
||||
.reveal_nodes(vec![
|
||||
.reveal_nodes(&mut [
|
||||
ProofTrieNode {
|
||||
path: Nibbles::default(),
|
||||
node: branch,
|
||||
@@ -6200,7 +6200,7 @@ mod tests {
|
||||
Default::default(),
|
||||
[key1()],
|
||||
);
|
||||
let revealed_nodes: Vec<ProofTrieNode> = hash_builder_proof_nodes
|
||||
let mut revealed_nodes: Vec<ProofTrieNode> = hash_builder_proof_nodes
|
||||
.nodes_sorted()
|
||||
.into_iter()
|
||||
.map(|(path, node)| {
|
||||
@@ -6210,7 +6210,7 @@ mod tests {
|
||||
ProofTrieNode { path, node: TrieNode::decode(&mut &node[..]).unwrap(), masks }
|
||||
})
|
||||
.collect();
|
||||
sparse.reveal_nodes(revealed_nodes).unwrap();
|
||||
sparse.reveal_nodes(&mut revealed_nodes).unwrap();
|
||||
|
||||
// Check that the branch node exists with only two nibbles set
|
||||
assert_eq!(
|
||||
@@ -6235,7 +6235,7 @@ mod tests {
|
||||
Default::default(),
|
||||
[key3()],
|
||||
);
|
||||
let revealed_nodes: Vec<ProofTrieNode> = hash_builder_proof_nodes
|
||||
let mut revealed_nodes: Vec<ProofTrieNode> = hash_builder_proof_nodes
|
||||
.nodes_sorted()
|
||||
.into_iter()
|
||||
.map(|(path, node)| {
|
||||
@@ -6245,7 +6245,7 @@ mod tests {
|
||||
ProofTrieNode { path, node: TrieNode::decode(&mut &node[..]).unwrap(), masks }
|
||||
})
|
||||
.collect();
|
||||
sparse.reveal_nodes(revealed_nodes).unwrap();
|
||||
sparse.reveal_nodes(&mut revealed_nodes).unwrap();
|
||||
|
||||
// Check that nothing changed in the branch node
|
||||
assert_eq!(
|
||||
@@ -6321,7 +6321,7 @@ mod tests {
|
||||
Default::default(),
|
||||
[key1(), Nibbles::from_nibbles_unchecked([0x01])],
|
||||
);
|
||||
let revealed_nodes: Vec<ProofTrieNode> = hash_builder_proof_nodes
|
||||
let mut revealed_nodes: Vec<ProofTrieNode> = hash_builder_proof_nodes
|
||||
.nodes_sorted()
|
||||
.into_iter()
|
||||
.map(|(path, node)| {
|
||||
@@ -6331,7 +6331,7 @@ mod tests {
|
||||
ProofTrieNode { path, node: TrieNode::decode(&mut &node[..]).unwrap(), masks }
|
||||
})
|
||||
.collect();
|
||||
sparse.reveal_nodes(revealed_nodes).unwrap();
|
||||
sparse.reveal_nodes(&mut revealed_nodes).unwrap();
|
||||
|
||||
// Check that the branch node exists
|
||||
assert_eq!(
|
||||
@@ -6356,7 +6356,7 @@ mod tests {
|
||||
Default::default(),
|
||||
[key2()],
|
||||
);
|
||||
let revealed_nodes: Vec<ProofTrieNode> = hash_builder_proof_nodes
|
||||
let mut revealed_nodes: Vec<ProofTrieNode> = hash_builder_proof_nodes
|
||||
.nodes_sorted()
|
||||
.into_iter()
|
||||
.map(|(path, node)| {
|
||||
@@ -6366,7 +6366,7 @@ mod tests {
|
||||
ProofTrieNode { path, node: TrieNode::decode(&mut &node[..]).unwrap(), masks }
|
||||
})
|
||||
.collect();
|
||||
sparse.reveal_nodes(revealed_nodes).unwrap();
|
||||
sparse.reveal_nodes(&mut revealed_nodes).unwrap();
|
||||
|
||||
// Check that nothing changed in the extension node
|
||||
assert_eq!(
|
||||
@@ -6448,7 +6448,7 @@ mod tests {
|
||||
Default::default(),
|
||||
[key1()],
|
||||
);
|
||||
let revealed_nodes: Vec<ProofTrieNode> = hash_builder_proof_nodes
|
||||
let mut revealed_nodes: Vec<ProofTrieNode> = hash_builder_proof_nodes
|
||||
.nodes_sorted()
|
||||
.into_iter()
|
||||
.map(|(path, node)| {
|
||||
@@ -6458,7 +6458,7 @@ mod tests {
|
||||
ProofTrieNode { path, node: TrieNode::decode(&mut &node[..]).unwrap(), masks }
|
||||
})
|
||||
.collect();
|
||||
sparse.reveal_nodes(revealed_nodes).unwrap();
|
||||
sparse.reveal_nodes(&mut revealed_nodes).unwrap();
|
||||
|
||||
// Check that the branch node wasn't overwritten by the extension node in the proof
|
||||
assert_matches!(
|
||||
@@ -7422,7 +7422,7 @@ mod tests {
|
||||
let leaf_node = LeafNode::new(leaf_key, leaf_value);
|
||||
let leaf_masks = None;
|
||||
|
||||
trie.reveal_nodes(vec![
|
||||
trie.reveal_nodes(&mut [
|
||||
ProofTrieNode {
|
||||
path: Nibbles::from_nibbles([0x3]),
|
||||
node: TrieNode::Branch(branch_0x3_node),
|
||||
@@ -7732,7 +7732,7 @@ mod tests {
|
||||
);
|
||||
|
||||
// Reveal the trie structure using ProofTrieNode
|
||||
let proof_nodes = vec![
|
||||
let mut proof_nodes = vec![
|
||||
ProofTrieNode {
|
||||
path: Nibbles::from_nibbles([0x3]),
|
||||
node: branch_0x3_node,
|
||||
@@ -7763,7 +7763,7 @@ mod tests {
|
||||
)
|
||||
.expect("root revealed");
|
||||
|
||||
trie.reveal_nodes(proof_nodes).unwrap();
|
||||
trie.reveal_nodes(&mut proof_nodes).unwrap();
|
||||
|
||||
// Update the leaf in order to reveal it in the trie
|
||||
trie.update_leaf(leaf_nibbles, leaf_value, &provider).unwrap();
|
||||
@@ -7811,7 +7811,7 @@ mod tests {
|
||||
let leaf_node = create_leaf_node(leaf_key.to_vec(), 42);
|
||||
|
||||
// Reveal the leaf node
|
||||
trie.reveal_nodes(vec![ProofTrieNode { path: leaf_path, node: leaf_node, masks: None }])
|
||||
trie.reveal_nodes(&mut [ProofTrieNode { path: leaf_path, node: leaf_node, masks: None }])
|
||||
.unwrap();
|
||||
|
||||
// The full path is leaf_path + leaf_key
|
||||
@@ -8999,7 +8999,7 @@ mod tests {
|
||||
|
||||
// Create a trie with some data
|
||||
let mut trie = ParallelSparseTrie::default();
|
||||
let nodes = vec![
|
||||
let mut nodes = vec![
|
||||
ProofTrieNode {
|
||||
path: Nibbles::from_nibbles_unchecked([0x1, 0x2]),
|
||||
node: TrieNode::Leaf(LeafNode {
|
||||
@@ -9017,7 +9017,7 @@ mod tests {
|
||||
masks: None,
|
||||
},
|
||||
];
|
||||
trie.reveal_nodes(nodes).unwrap();
|
||||
trie.reveal_nodes(&mut nodes).unwrap();
|
||||
|
||||
let populated_size = trie.memory_size();
|
||||
|
||||
|
||||
@@ -23,6 +23,16 @@ use reth_trie_common::{
|
||||
use tracing::debug;
|
||||
use tracing::{instrument, trace};
|
||||
|
||||
/// Holds data that should be dropped after any locks are released.
|
||||
///
|
||||
/// This is used to defer expensive deallocations (like proof node buffers) until after final state
|
||||
/// root is calculated
|
||||
#[derive(Debug, Default)]
|
||||
pub struct DeferredDrops {
|
||||
/// Each nodes reveal operation creates a new buffer, uses it, and pushes it here.
|
||||
pub proof_nodes_bufs: Vec<Vec<ProofTrieNode>>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
/// Sparse state trie representing lazy-loaded Ethereum state trie.
|
||||
pub struct SparseStateTrie<
|
||||
@@ -39,6 +49,8 @@ pub struct SparseStateTrie<
|
||||
retain_updates: bool,
|
||||
/// Reusable buffer for RLP encoding of trie accounts.
|
||||
account_rlp_buf: Vec<u8>,
|
||||
/// Holds data that should be dropped after final state root is calculated.
|
||||
deferred_drops: DeferredDrops,
|
||||
/// Metrics for the sparse state trie.
|
||||
#[cfg(feature = "metrics")]
|
||||
metrics: crate::metrics::SparseStateTrieMetrics,
|
||||
@@ -56,6 +68,7 @@ where
|
||||
storage: Default::default(),
|
||||
retain_updates: false,
|
||||
account_rlp_buf: Vec::with_capacity(TRIE_ACCOUNT_RLP_MAX_SIZE),
|
||||
deferred_drops: DeferredDrops::default(),
|
||||
#[cfg(feature = "metrics")]
|
||||
metrics: Default::default(),
|
||||
}
|
||||
@@ -105,6 +118,14 @@ impl<A, S> SparseStateTrie<A, S> {
|
||||
self.set_default_storage_trie(trie);
|
||||
self
|
||||
}
|
||||
|
||||
/// Takes the data structures for deferred dropping.
|
||||
///
|
||||
/// This allows the caller to drop the buffers later, avoiding expensive deallocations while
|
||||
/// calculating the state root.
|
||||
pub fn take_deferred_drops(&mut self) -> DeferredDrops {
|
||||
core::mem::take(&mut self.deferred_drops)
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, S> SparseStateTrie<A, S>
|
||||
@@ -273,22 +294,24 @@ where
|
||||
})
|
||||
.par_bridge_buffered()
|
||||
.map(|(account, storage_subtree, mut revealed_nodes, mut trie)| {
|
||||
let mut bufs = Vec::new();
|
||||
let result = Self::reveal_decoded_storage_multiproof_inner(
|
||||
account,
|
||||
storage_subtree,
|
||||
&mut revealed_nodes,
|
||||
&mut trie,
|
||||
&mut bufs,
|
||||
retain_updates,
|
||||
);
|
||||
|
||||
(account, revealed_nodes, trie, result)
|
||||
(account, revealed_nodes, trie, result, bufs)
|
||||
})
|
||||
.collect();
|
||||
|
||||
// Return `revealed_nodes` and `RevealableSparseTrie` for each account, incrementing
|
||||
// metrics and returning the last error seen if any.
|
||||
let mut any_err = Ok(());
|
||||
for (account, revealed_nodes, trie, result) in results {
|
||||
for (account, revealed_nodes, trie, result, bufs) in results {
|
||||
self.storage.revealed_paths.insert(account, revealed_nodes);
|
||||
self.storage.tries.insert(account, trie);
|
||||
// Mark this storage trie as hot (accessed this tick)
|
||||
@@ -304,6 +327,9 @@ where
|
||||
} else {
|
||||
any_err = result.map(|_| ());
|
||||
}
|
||||
|
||||
// Keep buffers for deferred dropping
|
||||
self.deferred_drops.proof_nodes_bufs.extend(bufs);
|
||||
}
|
||||
|
||||
any_err
|
||||
@@ -369,19 +395,21 @@ where
|
||||
})
|
||||
.par_bridge_buffered()
|
||||
.map(|(account, storage_proofs, mut revealed_nodes, mut trie)| {
|
||||
let mut bufs = Vec::new();
|
||||
let result = Self::reveal_storage_v2_proof_nodes_inner(
|
||||
account,
|
||||
storage_proofs,
|
||||
&mut revealed_nodes,
|
||||
&mut trie,
|
||||
&mut bufs,
|
||||
retain_updates,
|
||||
);
|
||||
(account, result, revealed_nodes, trie)
|
||||
(account, result, revealed_nodes, trie, bufs)
|
||||
})
|
||||
.collect();
|
||||
|
||||
let mut any_err = Ok(());
|
||||
for (account, result, revealed_nodes, trie) in results {
|
||||
for (account, result, revealed_nodes, trie, bufs) in results {
|
||||
self.storage.revealed_paths.insert(account, revealed_nodes);
|
||||
self.storage.tries.insert(account, trie);
|
||||
// Mark this storage trie as hot (accessed this tick)
|
||||
@@ -397,6 +425,9 @@ where
|
||||
} else {
|
||||
any_err = result.map(|_| ());
|
||||
}
|
||||
|
||||
// Keep buffers for deferred dropping
|
||||
self.deferred_drops.proof_nodes_bufs.extend(bufs);
|
||||
}
|
||||
|
||||
any_err
|
||||
@@ -420,12 +451,16 @@ where
|
||||
account_subtree: DecodedProofNodes,
|
||||
branch_node_masks: BranchNodeMasksMap,
|
||||
) -> SparseStateTrieResult<()> {
|
||||
let FilterMappedProofNodes { root_node, nodes, new_nodes, metric_values: _metric_values } =
|
||||
filter_map_revealed_nodes(
|
||||
account_subtree,
|
||||
&mut self.revealed_account_paths,
|
||||
&branch_node_masks,
|
||||
)?;
|
||||
let FilterMappedProofNodes {
|
||||
root_node,
|
||||
mut nodes,
|
||||
new_nodes,
|
||||
metric_values: _metric_values,
|
||||
} = filter_map_revealed_nodes(
|
||||
account_subtree,
|
||||
&mut self.revealed_account_paths,
|
||||
&branch_node_masks,
|
||||
)?;
|
||||
#[cfg(feature = "metrics")]
|
||||
{
|
||||
self.metrics.increment_total_account_nodes(_metric_values.total_nodes as u64);
|
||||
@@ -443,9 +478,12 @@ where
|
||||
trie.reserve_nodes(new_nodes);
|
||||
|
||||
trace!(target: "trie::sparse", total_nodes = ?nodes.len(), "Revealing account nodes");
|
||||
trie.reveal_nodes(nodes)?;
|
||||
trie.reveal_nodes(&mut nodes)?;
|
||||
}
|
||||
|
||||
// Keep buffer for deferred dropping
|
||||
self.deferred_drops.proof_nodes_bufs.push(nodes);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -457,7 +495,7 @@ where
|
||||
&mut self,
|
||||
nodes: Vec<ProofTrieNode>,
|
||||
) -> SparseStateTrieResult<()> {
|
||||
let FilteredV2ProofNodes { root_node, nodes, new_nodes, metric_values: _metric_values } =
|
||||
let FilteredV2ProofNodes { root_node, mut nodes, new_nodes, metric_values: _metric_values } =
|
||||
filter_revealed_v2_proof_nodes(nodes, &mut self.revealed_account_paths)?;
|
||||
|
||||
#[cfg(feature = "metrics")]
|
||||
@@ -476,7 +514,10 @@ where
|
||||
trie.reserve_nodes(new_nodes);
|
||||
|
||||
trace!(target: "trie::sparse", total_nodes = ?nodes.len(), "Revealing account nodes from V2 proof");
|
||||
trie.reveal_nodes(nodes)?;
|
||||
trie.reveal_nodes(&mut nodes)?;
|
||||
|
||||
// Keep buffer for deferred dropping
|
||||
self.deferred_drops.proof_nodes_bufs.push(nodes);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -496,6 +537,7 @@ where
|
||||
nodes,
|
||||
revealed_paths,
|
||||
trie,
|
||||
&mut self.deferred_drops.proof_nodes_bufs,
|
||||
self.retain_updates,
|
||||
)?;
|
||||
|
||||
@@ -515,9 +557,10 @@ where
|
||||
nodes: Vec<ProofTrieNode>,
|
||||
revealed_nodes: &mut HashSet<Nibbles>,
|
||||
trie: &mut RevealableSparseTrie<S>,
|
||||
bufs: &mut Vec<Vec<ProofTrieNode>>,
|
||||
retain_updates: bool,
|
||||
) -> SparseStateTrieResult<ProofNodesMetricValues> {
|
||||
let FilteredV2ProofNodes { root_node, nodes, new_nodes, metric_values } =
|
||||
let FilteredV2ProofNodes { root_node, mut nodes, new_nodes, metric_values } =
|
||||
filter_revealed_v2_proof_nodes(nodes, revealed_nodes)?;
|
||||
|
||||
let trie = if let Some(root_node) = root_node {
|
||||
@@ -530,7 +573,10 @@ where
|
||||
trie.reserve_nodes(new_nodes);
|
||||
|
||||
trace!(target: "trie::sparse", ?account, total_nodes = ?nodes.len(), "Revealing storage nodes from V2 proof");
|
||||
trie.reveal_nodes(nodes)?;
|
||||
trie.reveal_nodes(&mut nodes)?;
|
||||
|
||||
// Keep buffer for deferred dropping
|
||||
bufs.push(nodes);
|
||||
|
||||
Ok(metric_values)
|
||||
}
|
||||
@@ -558,6 +604,7 @@ where
|
||||
storage_subtree,
|
||||
revealed_paths,
|
||||
trie,
|
||||
&mut self.deferred_drops.proof_nodes_bufs,
|
||||
self.retain_updates,
|
||||
)?;
|
||||
|
||||
@@ -577,9 +624,10 @@ where
|
||||
storage_subtree: DecodedStorageMultiProof,
|
||||
revealed_nodes: &mut HashSet<Nibbles>,
|
||||
trie: &mut RevealableSparseTrie<S>,
|
||||
bufs: &mut Vec<Vec<ProofTrieNode>>,
|
||||
retain_updates: bool,
|
||||
) -> SparseStateTrieResult<ProofNodesMetricValues> {
|
||||
let FilterMappedProofNodes { root_node, nodes, new_nodes, metric_values } =
|
||||
let FilterMappedProofNodes { root_node, mut nodes, new_nodes, metric_values } =
|
||||
filter_map_revealed_nodes(
|
||||
storage_subtree.subtree,
|
||||
revealed_nodes,
|
||||
@@ -596,9 +644,12 @@ where
|
||||
trie.reserve_nodes(new_nodes);
|
||||
|
||||
trace!(target: "trie::sparse", ?account, total_nodes = ?nodes.len(), "Revealing storage nodes");
|
||||
trie.reveal_nodes(nodes)?;
|
||||
trie.reveal_nodes(&mut nodes)?;
|
||||
}
|
||||
|
||||
// Keep buffer for deferred dropping
|
||||
bufs.push(nodes);
|
||||
|
||||
Ok(metric_values)
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
use core::fmt::Debug;
|
||||
|
||||
use alloc::{borrow::Cow, vec, vec::Vec};
|
||||
use alloc::{borrow::Cow, vec::Vec};
|
||||
use alloy_primitives::{
|
||||
map::{B256Map, HashMap, HashSet},
|
||||
B256,
|
||||
@@ -102,7 +102,7 @@ pub trait SparseTrie: Sized + Debug + Send + Sync {
|
||||
node: TrieNode,
|
||||
masks: Option<BranchNodeMasks>,
|
||||
) -> SparseTrieResult<()> {
|
||||
self.reveal_nodes(vec![ProofTrieNode { path, node, masks }])
|
||||
self.reveal_nodes(&mut [ProofTrieNode { path, node, masks }])
|
||||
}
|
||||
|
||||
/// Reveals one or more trie nodes if they have not been revealed before.
|
||||
@@ -119,7 +119,12 @@ pub trait SparseTrie: Sized + Debug + Send + Sync {
|
||||
/// # Returns
|
||||
///
|
||||
/// `Ok(())` if successful, or an error if any of the nodes was not revealed.
|
||||
fn reveal_nodes(&mut self, nodes: Vec<ProofTrieNode>) -> SparseTrieResult<()>;
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
/// The implementation may modify the input nodes. A common thing to do is [`std::mem::replace`]
|
||||
/// each node with [`TrieNode::EmptyRoot`] to avoid cloning.
|
||||
fn reveal_nodes(&mut self, nodes: &mut [ProofTrieNode]) -> SparseTrieResult<()>;
|
||||
|
||||
/// Updates the value of a leaf node at the specified path.
|
||||
///
|
||||
|
||||
@@ -476,6 +476,7 @@ impl SparseTrieTrait for SerialSparseTrie {
|
||||
fn reserve_nodes(&mut self, additional: usize) {
|
||||
self.nodes.reserve(additional);
|
||||
}
|
||||
|
||||
fn reveal_node(
|
||||
&mut self,
|
||||
path: Nibbles,
|
||||
@@ -618,10 +619,14 @@ impl SparseTrieTrait for SerialSparseTrie {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn reveal_nodes(&mut self, mut nodes: Vec<ProofTrieNode>) -> SparseTrieResult<()> {
|
||||
fn reveal_nodes(&mut self, nodes: &mut [ProofTrieNode]) -> SparseTrieResult<()> {
|
||||
nodes.sort_unstable_by_key(|node| node.path);
|
||||
for node in nodes {
|
||||
self.reveal_node(node.path, node.node, node.masks)?;
|
||||
for node in nodes.iter_mut() {
|
||||
self.reveal_node(
|
||||
node.path,
|
||||
core::mem::replace(&mut node.node, TrieNode::EmptyRoot),
|
||||
node.masks.take(),
|
||||
)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user