1use crate::{
2 prefix_set::PrefixSet,
3 trie_cursor::{CursorSubNode, TrieCursor},
4 BranchNodeCompact, Nibbles,
5};
6use alloy_primitives::{map::HashSet, B256};
7use reth_storage_errors::db::DatabaseError;
8
9#[cfg(feature = "metrics")]
10use crate::metrics::WalkerMetrics;
11
12#[derive(Debug)]
16pub struct TrieWalker<C> {
17 pub cursor: C,
19 pub stack: Vec<CursorSubNode>,
21 pub can_skip_current_node: bool,
25 pub changes: PrefixSet,
27 removed_keys: Option<HashSet<Nibbles>>,
29 #[cfg(feature = "metrics")]
30 metrics: WalkerMetrics,
32}
33
34impl<C> TrieWalker<C> {
35 pub fn from_stack(cursor: C, stack: Vec<CursorSubNode>, changes: PrefixSet) -> Self {
37 let mut this = Self {
38 cursor,
39 changes,
40 stack,
41 can_skip_current_node: false,
42 removed_keys: None,
43 #[cfg(feature = "metrics")]
44 metrics: WalkerMetrics::default(),
45 };
46 this.update_skip_node();
47 this
48 }
49
50 pub fn with_deletions_retained(mut self, retained: bool) -> Self {
52 if retained {
53 self.removed_keys = Some(HashSet::default());
54 }
55 self
56 }
57
58 pub fn split(mut self) -> (Vec<CursorSubNode>, HashSet<Nibbles>) {
60 let keys = self.take_removed_keys();
61 (self.stack, keys)
62 }
63
64 pub fn take_removed_keys(&mut self) -> HashSet<Nibbles> {
66 self.removed_keys.take().unwrap_or_default()
67 }
68
69 pub fn print_stack(&self) {
71 println!("====================== STACK ======================");
72 for node in &self.stack {
73 println!("{node:?}");
74 }
75 println!("====================== END STACK ======================\n");
76 }
77
78 pub fn removed_keys_len(&self) -> usize {
80 self.removed_keys.as_ref().map_or(0, |u| u.len())
81 }
82
83 pub fn key(&self) -> Option<&Nibbles> {
85 self.stack.last().map(|n| n.full_key())
86 }
87
88 pub fn hash(&self) -> Option<B256> {
90 self.stack.last().and_then(|n| n.hash())
91 }
92
93 pub fn children_are_in_trie(&self) -> bool {
95 self.stack.last().is_some_and(|n| n.tree_flag())
96 }
97
98 pub fn next_unprocessed_key(&self) -> Option<B256> {
100 self.key()
101 .and_then(|key| {
102 if self.can_skip_current_node {
103 key.increment().map(|inc| inc.pack())
104 } else {
105 Some(key.pack())
106 }
107 })
108 .map(|mut key| {
109 key.resize(32, 0);
110 B256::from_slice(key.as_slice())
111 })
112 }
113
114 fn update_skip_node(&mut self) {
116 self.can_skip_current_node = self
117 .stack
118 .last()
119 .is_some_and(|node| !self.changes.contains(node.full_key()) && node.hash_flag());
120 }
121}
122
123impl<C: TrieCursor> TrieWalker<C> {
124 pub fn new(cursor: C, changes: PrefixSet) -> Self {
126 let mut this = Self {
128 cursor,
129 changes,
130 stack: vec![CursorSubNode::default()],
131 can_skip_current_node: false,
132 removed_keys: None,
133 #[cfg(feature = "metrics")]
134 metrics: WalkerMetrics::default(),
135 };
136
137 if let Some((key, value)) = this.node(true).unwrap() {
139 this.stack[0] = CursorSubNode::new(key, Some(value));
140 }
141
142 this.update_skip_node();
144 this
145 }
146
147 pub fn advance(&mut self) -> Result<(), DatabaseError> {
154 if let Some(last) = self.stack.last() {
155 if !self.can_skip_current_node && self.children_are_in_trie() {
156 match last.nibble() {
159 -1 => self.move_to_next_sibling(true)?,
160 _ => self.consume_node()?,
161 }
162 } else {
163 self.move_to_next_sibling(false)?;
165 }
166
167 self.update_skip_node();
169 }
170
171 Ok(())
172 }
173
174 fn node(&mut self, exact: bool) -> Result<Option<(Nibbles, BranchNodeCompact)>, DatabaseError> {
176 let key = self.key().expect("key must exist").clone();
177 let entry = if exact { self.cursor.seek_exact(key)? } else { self.cursor.seek(key)? };
178
179 if let Some((_, node)) = &entry {
180 assert!(!node.state_mask.is_empty());
181 }
182
183 Ok(entry)
184 }
185
186 fn consume_node(&mut self) -> Result<(), DatabaseError> {
188 let Some((key, node)) = self.node(false)? else {
189 self.stack.clear();
191 return Ok(())
192 };
193
194 if !key.is_empty() && !self.stack.is_empty() {
198 self.stack[0].set_nibble(key[0] as i8);
199 }
200
201 if let Some(subnode) = self.stack.last() {
206 if !key.starts_with(subnode.full_key()) {
207 #[cfg(feature = "metrics")]
208 self.metrics.inc_out_of_order_subnode(1);
209 self.move_to_next_sibling(false)?;
210 return Ok(())
211 }
212 }
213
214 let subnode = CursorSubNode::new(key, Some(node));
216 let nibble = subnode.nibble();
217 self.stack.push(subnode);
218 self.update_skip_node();
219
220 if !self.can_skip_current_node || nibble != -1 {
223 if let Some((keys, key)) = self.removed_keys.as_mut().zip(self.cursor.current()?) {
224 keys.insert(key);
225 }
226 }
227
228 Ok(())
229 }
230
231 fn move_to_next_sibling(
233 &mut self,
234 allow_root_to_child_nibble: bool,
235 ) -> Result<(), DatabaseError> {
236 let Some(subnode) = self.stack.last_mut() else { return Ok(()) };
237
238 if subnode.nibble() >= 0xf || (subnode.nibble() < 0 && !allow_root_to_child_nibble) {
241 self.stack.pop();
242 self.move_to_next_sibling(false)?;
243 return Ok(())
244 }
245
246 subnode.inc_nibble();
247
248 if subnode.node.is_none() {
249 return self.consume_node()
250 }
251
252 loop {
254 if subnode.state_flag() {
255 return Ok(())
256 }
257 if subnode.nibble() == 0xf {
258 break
259 }
260 subnode.inc_nibble();
261 }
262
263 self.stack.pop();
265 self.move_to_next_sibling(false)?;
266
267 Ok(())
268 }
269}