diff --git a/crates/trie/trie/src/node_iter.rs b/crates/trie/trie/src/node_iter.rs index d8839ee242..26528ae2d3 100644 --- a/crates/trie/trie/src/node_iter.rs +++ b/crates/trie/trie/src/node_iter.rs @@ -229,21 +229,31 @@ mod tests { #[test] fn test_trie_node_iter() { + fn empty_leaf_rlp_for_key(key: Nibbles) -> RlpNode { + RlpNode::from_rlp(&alloy_rlp::encode(LeafNode::new( + key, + alloy_rlp::encode(TrieAccount::default()), + ))) + } + reth_tracing::init_test_tracing(); - // Extension (Key = 0000000000000000000000000000000000000000000000000000000000000) - // └── Branch (`branch_node`) - // ├── 0 -> Branch (`child_branch_node`) - // │ ├── 0 -> Leaf (account_1, marked as changed) - // │ └── 1 -> Leaf (account_2) - // ├── 1 -> Branch (`child_branch_node`) - // │ ├── 0 -> Leaf (account_5) - // │ └── 1 -> Leaf (account_6) + // Extension (Key = 0x0000000000000000000000000000000000000000000000000000000000000) + // └── Branch (`branch_node_0`) + // ├── 0 -> Branch (`branch_node_1`) + // │ ├── 0 -> Leaf (`account_1`, Key = 0x0) + // │ └── 1 -> Leaf (`account_2`, Key = 0x0) + // ├── 1 -> Branch (`branch_node_2`) + // │ ├── 0 -> Branch (`branch_node_3`) + // │ │ ├── 0 -> Leaf (`account_3`, marked as changed) + // │ │ └── 1 -> Leaf (`account_4`) + // │ └── 1 -> Leaf (`account_5`, Key = 0x0) let account_1 = b256!("0x0000000000000000000000000000000000000000000000000000000000000000"); - let account_2 = b256!("0x0000000000000000000000000000000000000000000000000000000000000001"); - let account_3 = b256!("0x0000000000000000000000000000000000000000000000000000000000000010"); - let account_4 = b256!("0x0000000000000000000000000000000000000000000000000000000000000011"); + let account_2 = b256!("0x0000000000000000000000000000000000000000000000000000000000000010"); + let account_3 = b256!("0x0000000000000000000000000000000000000000000000000000000000000100"); + let account_4 = b256!("0x0000000000000000000000000000000000000000000000000000000000000101"); + let account_5 = b256!("0x0000000000000000000000000000000000000000000000000000000000000110"); let empty_account = Account::default(); let hash_builder_branch_nodes = get_hash_builder_branch_nodes(vec![ @@ -251,36 +261,51 @@ mod tests { (Nibbles::unpack(account_2), empty_account), (Nibbles::unpack(account_3), empty_account), (Nibbles::unpack(account_4), empty_account), + (Nibbles::unpack(account_5), empty_account), ]); - let empty_leaf_rlp = RlpNode::from_rlp(&alloy_rlp::encode(LeafNode::new( - Nibbles::default(), - alloy_rlp::encode(TrieAccount::default()), - ))); - - let child_branch_node_rlp = RlpNode::from_rlp(&alloy_rlp::encode(BranchNode::new( - vec![empty_leaf_rlp.clone(), empty_leaf_rlp], + let branch_node_1_rlp = RlpNode::from_rlp(&alloy_rlp::encode(BranchNode::new( + vec![ + empty_leaf_rlp_for_key(Nibbles::from_nibbles([0])), + empty_leaf_rlp_for_key(Nibbles::from_nibbles([0])), + ], TrieMask::new(0b11), ))); - let branch_node = ( - Nibbles::from_nibbles([0; 62]), + let branch_node_3_rlp = RlpNode::from_rlp(&alloy_rlp::encode(BranchNode::new( + vec![ + empty_leaf_rlp_for_key(Nibbles::default()), + empty_leaf_rlp_for_key(Nibbles::default()), + ], + TrieMask::new(0b11), + ))); + + let branch_node_2 = ( + Nibbles::from_nibbles([vec![0; 61], vec![1]].concat()), BranchNodeCompact::new( TrieMask::new(0b11), - // Tree mask has no bits set, because both child branch nodes have empty tree and - // hash masks. TrieMask::new(0b00), - // Hash mask bits are set, because both child nodes are branches. + TrieMask::new(0b01), + vec![branch_node_3_rlp.as_hash().unwrap()], + None, + ), + ); + let branch_node_2_rlp = RlpNode::from_rlp(&alloy_rlp::encode(BranchNode::new( + vec![branch_node_3_rlp, empty_leaf_rlp_for_key(Nibbles::from_nibbles([0]))], + TrieMask::new(0b11), + ))); + let branch_node_0 = ( + Nibbles::from_nibbles([0; 61]), + BranchNodeCompact::new( TrieMask::new(0b11), - vec![ - child_branch_node_rlp.as_hash().unwrap(), - child_branch_node_rlp.as_hash().unwrap(), - ], + TrieMask::new(0b10), + TrieMask::new(0b11), + vec![branch_node_1_rlp.as_hash().unwrap(), branch_node_2_rlp.as_hash().unwrap()], None, ), ); - let mock_trie_nodes = vec![branch_node.clone()]; + let mock_trie_nodes = vec![branch_node_0.clone(), branch_node_2.clone()]; pretty_assertions::assert_eq!( hash_builder_branch_nodes.into_iter().sorted().collect::>(), mock_trie_nodes, @@ -289,9 +314,9 @@ mod tests { let trie_cursor_factory = MockTrieCursorFactory::new(mock_trie_nodes.into_iter().collect(), B256Map::default()); - // Mark the account 1 as changed. + // Mark the account 3 as changed. let mut prefix_set = PrefixSetMut::default(); - prefix_set.insert(Nibbles::unpack(account_1)); + prefix_set.insert(Nibbles::unpack(account_3)); let prefix_set = prefix_set.freeze(); let walker = @@ -303,6 +328,7 @@ mod tests { (account_2, empty_account), (account_3, empty_account), (account_4, empty_account), + (account_5, empty_account), ]), B256Map::default(), ); @@ -322,7 +348,11 @@ mod tests { }, KeyVisit { visit_type: KeyVisitType::SeekNonExact(Nibbles::from_nibbles([0x0])), - visited_key: Some(branch_node.0) + visited_key: Some(branch_node_0.0) + }, + KeyVisit { + visit_type: KeyVisitType::SeekNonExact(branch_node_2.0.clone()), + visited_key: Some(branch_node_2.0) }, KeyVisit { visit_type: KeyVisitType::SeekNonExact(Nibbles::from_nibbles([0x1])), @@ -333,23 +363,35 @@ mod tests { pretty_assertions::assert_eq!( *hashed_cursor_factory.visited_account_keys(), vec![ - // Why do we seek account 1 one additional times? + // Why do we always seek this key first? KeyVisit { visit_type: KeyVisitType::SeekNonExact(account_1), visited_key: Some(account_1) }, + // Seek to the modified account. KeyVisit { - visit_type: KeyVisitType::SeekNonExact(account_1), - visited_key: Some(account_1) + visit_type: KeyVisitType::SeekNonExact(account_3), + visited_key: Some(account_3) }, - KeyVisit { visit_type: KeyVisitType::Next, visited_key: Some(account_2) }, - KeyVisit { visit_type: KeyVisitType::Next, visited_key: Some(account_3) }, + // Why do we seek the modified account two more times? KeyVisit { - visit_type: KeyVisitType::SeekNonExact(b256!( - "0x0000000000000000000000000000000000000000000000000000000000000020" - )), - visited_key: None + visit_type: KeyVisitType::SeekNonExact(account_3), + visited_key: Some(account_3) }, + KeyVisit { + visit_type: KeyVisitType::SeekNonExact(account_3), + visited_key: Some(account_3) + }, + // Collect the siblings of the modified account + KeyVisit { visit_type: KeyVisitType::Next, visited_key: Some(account_4) }, + KeyVisit { visit_type: KeyVisitType::Next, visited_key: Some(account_5) }, + // We seek the account 5 because its hash is not in the branch node, but we already + // walked it before, so there should be no need for it. + KeyVisit { + visit_type: KeyVisitType::SeekNonExact(account_5), + visited_key: Some(account_5) + }, + KeyVisit { visit_type: KeyVisitType::Next, visited_key: None }, ], ); }