fix(trie): use correct store_in_db_trie value for sparse extension nodes (#13826)

This commit is contained in:
Alexey Shekhirin
2025-01-16 16:45:23 +00:00
committed by GitHub
parent a90ecd9057
commit 7e972ea23d

View File

@ -381,6 +381,7 @@ impl<P> RevealedSparseTrie<P> {
// Memoize the hash of a previously blinded node in a new extension // Memoize the hash of a previously blinded node in a new extension
// node. // node.
hash: Some(*hash), hash: Some(*hash),
store_in_db_trie: None,
}); });
self.reveal_node_or_hash(child_path, &ext.child)?; self.reveal_node_or_hash(child_path, &ext.child)?;
} }
@ -602,14 +603,14 @@ impl<P> RevealedSparseTrie<P> {
while let Some((mut path, level)) = paths.pop() { while let Some((mut path, level)) = paths.pop() {
match self.nodes.get(&path).unwrap() { match self.nodes.get(&path).unwrap() {
SparseNode::Empty | SparseNode::Hash(_) => {} SparseNode::Empty | SparseNode::Hash(_) => {}
SparseNode::Leaf { hash, .. } => { SparseNode::Leaf { key: _, hash } => {
if hash.is_some() && !prefix_set.contains(&path) { if hash.is_some() && !prefix_set.contains(&path) {
continue continue
} }
targets.push(path); targets.push(path);
} }
SparseNode::Extension { key, hash } => { SparseNode::Extension { key, hash, store_in_db_trie: _ } => {
if hash.is_some() && !prefix_set.contains(&path) { if hash.is_some() && !prefix_set.contains(&path) {
continue continue
} }
@ -621,7 +622,7 @@ impl<P> RevealedSparseTrie<P> {
paths.push((path, level + 1)); paths.push((path, level + 1));
} }
} }
SparseNode::Branch { state_mask, hash, .. } => { SparseNode::Branch { state_mask, hash, store_in_db_trie: _ } => {
if hash.is_some() && !prefix_set.contains(&path) { if hash.is_some() && !prefix_set.contains(&path) {
continue continue
} }
@ -673,26 +674,37 @@ impl<P> RevealedSparseTrie<P> {
(rlp_node, SparseNodeType::Leaf) (rlp_node, SparseNodeType::Leaf)
} }
} }
SparseNode::Extension { key, hash } => { SparseNode::Extension { key, hash, store_in_db_trie } => {
let mut child_path = path.clone(); let mut child_path = path.clone();
child_path.extend_from_slice_unchecked(key); child_path.extend_from_slice_unchecked(key);
if let Some(hash) = hash.filter(|_| !prefix_set_contains(&path)) { if let Some((hash, store_in_db_trie)) =
( hash.zip(*store_in_db_trie).filter(|_| !prefix_set_contains(&path))
RlpNode::word_rlp(&hash), {
SparseNodeType::Extension { store_in_db_trie: true }, (RlpNode::word_rlp(&hash), SparseNodeType::Extension { store_in_db_trie })
)
} else if buffers.rlp_node_stack.last().is_some_and(|e| e.0 == child_path) { } else if buffers.rlp_node_stack.last().is_some_and(|e| e.0 == child_path) {
let (_, child, child_node_type) = buffers.rlp_node_stack.pop().unwrap(); let (_, child, child_node_type) = buffers.rlp_node_stack.pop().unwrap();
self.rlp_buf.clear(); self.rlp_buf.clear();
let rlp_node = ExtensionNodeRef::new(key, &child).rlp(&mut self.rlp_buf); let rlp_node = ExtensionNodeRef::new(key, &child).rlp(&mut self.rlp_buf);
*hash = rlp_node.as_hash(); *hash = rlp_node.as_hash();
let store_in_db_trie_value = child_node_type.store_in_db_trie();
trace!(
target: "trie::sparse",
?path,
?child_path,
?child_node_type,
"Extension node"
);
*store_in_db_trie = Some(store_in_db_trie_value);
( (
rlp_node, rlp_node,
SparseNodeType::Extension { SparseNodeType::Extension {
// Inherit the `store_in_db_trie` flag from the child node, which is // Inherit the `store_in_db_trie` flag from the child node, which is
// always the branch node // always the branch node
store_in_db_trie: child_node_type.store_in_db_trie(), store_in_db_trie: store_in_db_trie_value,
}, },
) )
} else { } else {
@ -1228,7 +1240,14 @@ pub enum SparseNode {
key: Nibbles, key: Nibbles,
/// Pre-computed hash of the sparse node. /// Pre-computed hash of the sparse node.
/// Can be reused unless this trie path has been updated. /// Can be reused unless this trie path has been updated.
///
/// If [`None`], then the value is not known and should be calculated from scratch.
hash: Option<B256>, hash: Option<B256>,
/// Pre-computed flag indicating whether the trie node should be stored in the database.
/// Can be reused unless this trie path has been updated.
///
/// If [`None`], then the value is not known and should be calculated from scratch.
store_in_db_trie: Option<bool>,
}, },
/// Sparse branch node with state mask. /// Sparse branch node with state mask.
Branch { Branch {
@ -1236,9 +1255,13 @@ pub enum SparseNode {
state_mask: TrieMask, state_mask: TrieMask,
/// Pre-computed hash of the sparse node. /// Pre-computed hash of the sparse node.
/// Can be reused unless this trie path has been updated. /// Can be reused unless this trie path has been updated.
///
/// If [`None`], then the value is not known and should be calculated from scratch.
hash: Option<B256>, hash: Option<B256>,
/// Pre-computed flag indicating whether the trie node should be stored in the database. /// Pre-computed flag indicating whether the trie node should be stored in the database.
/// Can be reused unless this trie path has been updated. /// Can be reused unless this trie path has been updated.
///
/// If [`None`], then the value is not known and should be calculated from scratch.
store_in_db_trie: Option<bool>, store_in_db_trie: Option<bool>,
}, },
} }
@ -1270,7 +1293,7 @@ impl SparseNode {
/// Create new [`SparseNode::Extension`] from the key slice. /// Create new [`SparseNode::Extension`] from the key slice.
pub const fn new_ext(key: Nibbles) -> Self { pub const fn new_ext(key: Nibbles) -> Self {
Self::Extension { key, hash: None } Self::Extension { key, hash: None, store_in_db_trie: None }
} }
/// Create new [`SparseNode::Leaf`] from leaf key and value. /// Create new [`SparseNode::Leaf`] from leaf key and value.
@ -2308,7 +2331,7 @@ mod tests {
// Check that the root extension node exists // Check that the root extension node exists
assert_matches!( assert_matches!(
sparse.nodes.get(&Nibbles::default()), sparse.nodes.get(&Nibbles::default()),
Some(SparseNode::Extension { key, hash: None }) if *key == Nibbles::from_nibbles([0x00]) Some(SparseNode::Extension { key, hash: None, store_in_db_trie: None }) if *key == Nibbles::from_nibbles([0x00])
); );
// Insert the leaf with a different prefix // Insert the leaf with a different prefix