1use super::{
2 branch_child_idx::{BranchChildIdx, BranchChildIter},
3 ArenaSparseNode, ArenaSparseNodeBranchChild, ArenaSparseNodeState, Index, NodeArena,
4};
5use alloc::vec::Vec;
6use reth_trie_common::Nibbles;
7use tracing::{instrument, trace};
8
9const TRACE_TARGET: &str = "trie::arena::cursor";
10
11#[derive(Debug, Clone)]
13pub(super) struct ArenaCursorStackEntry {
14 pub(super) index: Index,
16 pub(super) path: Nibbles,
18 pub(super) next_dense_idx: usize,
21}
22
23#[derive(Debug)]
25pub(super) enum SeekResult {
26 EmptyRoot,
28 RevealedLeaf,
30 Blinded,
32 Diverged,
34 NoChild { child_nibble: u8 },
36 RevealedSubtrie,
38}
39
40#[derive(Debug)]
42pub(super) enum NextResult {
43 NonBranch,
46 Branch,
49 Done,
51}
52
53#[derive(Debug, Default, Clone)]
62pub(super) struct ArenaCursor {
63 stack: Vec<ArenaCursorStackEntry>,
64 needs_pop: bool,
67}
68
69impl ArenaCursor {
70 pub(super) fn head(&self) -> Option<&ArenaCursorStackEntry> {
72 self.stack.last()
73 }
74
75 pub(super) fn parent(&self) -> Option<&ArenaCursorStackEntry> {
77 let len = self.stack.len();
78 (len >= 2).then(|| &self.stack[len - 2])
79 }
80
81 pub(super) const fn depth(&self) -> usize {
87 self.stack.len() - 1
88 }
89
90 #[instrument(level = "trace", target = TRACE_TARGET, skip(self, arena))]
94 pub(super) fn reset(&mut self, arena: &NodeArena, idx: Index, path: Nibbles) {
95 debug_assert!(
96 self.stack.len() <= 1 && !self.needs_pop,
97 "cursor must be drained before reset; stack has {} entries, needs_pop={}",
98 self.stack.len(),
99 self.needs_pop,
100 );
101 self.stack.clear();
102 self.needs_pop = false;
103 self.push(arena, idx, path);
104 }
105
106 fn push(&mut self, arena: &NodeArena, idx: Index, path: Nibbles) {
108 debug_assert!(arena.contains_key(idx), "push called with invalid arena index");
109 self.stack.push(ArenaCursorStackEntry { index: idx, path, next_dense_idx: 0 });
110 trace!(target: TRACE_TARGET, entry = ?self.stack.last().expect("just pushed"), "Pushed stack entry");
111 }
112
113 #[instrument(level = "trace", target = TRACE_TARGET, skip(self, arena))]
119 pub(super) fn pop(&mut self, arena: &mut NodeArena) -> ArenaCursorStackEntry {
120 let entry = self.stack.pop().expect("pop can't be called on empty stack");
121 trace!(target: TRACE_TARGET, entry = ?entry, "Popped stack entry");
122
123 #[cfg(debug_assertions)]
124 if let Some(ArenaSparseNode::Subtrie(s)) = arena.get(entry.index) {
125 debug_assert_eq!(
126 s.path, entry.path,
127 "subtrie cached path {:?} does not match stack entry path {:?}",
128 s.path, entry.path,
129 );
130 }
131
132 if let Some(parent) = self.stack.last() {
133 let child_is_dirty = arena.get(entry.index).is_some_and(|node| match node {
134 ArenaSparseNode::Branch(b) => matches!(b.state, ArenaSparseNodeState::Dirty),
135 ArenaSparseNode::Leaf { state, .. } => matches!(state, ArenaSparseNodeState::Dirty),
136 ArenaSparseNode::Subtrie(s) => {
137 let root = &s.arena[s.root];
138 matches!(root, ArenaSparseNode::EmptyRoot) ||
139 matches!(root.state_ref(), Some(ArenaSparseNodeState::Dirty))
140 }
141 _ => false,
142 });
143 if child_is_dirty {
144 *arena[parent.index].state_mut() = ArenaSparseNodeState::Dirty;
145 }
146 }
147
148 entry
149 }
150
151 #[instrument(level = "trace", target = TRACE_TARGET, skip_all)]
154 pub(super) fn drain(&mut self, arena: &mut NodeArena) {
155 trace!(target: TRACE_TARGET, "Draining stack");
156 self.needs_pop = false;
157 while self.stack.len() > 1 {
158 self.pop(arena);
159 }
160 }
161
162 pub(super) fn head_logical_branch_path(&self, arena: &NodeArena) -> Nibbles {
165 logical_branch_path(arena, self.stack.last().expect("cursor is non-empty"))
166 }
167
168 pub(super) fn head_logical_branch_path_len(&self, arena: &NodeArena) -> usize {
171 logical_branch_path_len(arena, self.stack.last().expect("cursor is non-empty"))
172 }
173
174 pub(super) fn child_path(&self, arena: &NodeArena, child_nibble: u8) -> Nibbles {
177 let mut path = logical_branch_path(arena, self.stack.last().expect("cursor is non-empty"));
178 path.push_unchecked(child_nibble);
179 path
180 }
181
182 pub(super) fn parent_logical_branch_path(&self, arena: &NodeArena) -> Nibbles {
185 logical_branch_path(arena, self.parent().expect("cursor must have a parent"))
186 }
187
188 pub(super) fn replace_head_index(
192 &mut self,
193 arena: &mut NodeArena,
194 root: &mut Index,
195 new_idx: Index,
196 ) {
197 let head = self.stack.last_mut().expect("cursor must have head");
198 let old_idx = head.index;
199 let child_nibble = head.path.last();
200 head.index = new_idx;
201
202 let Some(parent) = self.parent() else {
203 *root = new_idx;
204 return;
205 };
206
207 let child_nibble =
208 child_nibble.expect("if cursor has a parent then the head path can't be empty");
209
210 let parent_branch = arena[parent.index].branch_mut();
211 let child_idx = BranchChildIdx::new(parent_branch.state_mask, child_nibble)
212 .expect("child nibble not found in parent state_mask");
213
214 debug_assert!(
215 matches!(
216 parent_branch.children[child_idx],
217 ArenaSparseNodeBranchChild::Revealed(idx)
218 if idx == old_idx
219 ),
220 "parent child at nibble {child_nibble} does not match old_idx",
221 );
222
223 parent_branch.children[child_idx] = ArenaSparseNodeBranchChild::Revealed(new_idx);
224 }
225
226 #[instrument(level = "trace", target = TRACE_TARGET, skip_all, ret)]
240 pub(super) fn next(
241 &mut self,
242 arena: &mut NodeArena,
243 should_descend: impl Fn(usize, &ArenaSparseNode) -> bool,
244 ) -> NextResult {
245 if self.needs_pop {
246 self.pop(arena);
247 self.needs_pop = false;
248 }
249
250 loop {
251 let Some(head) = self.stack.last_mut() else {
252 return NextResult::Done;
253 };
254 let head_idx = head.index;
255
256 let ArenaSparseNode::Branch(branch) = &arena[head_idx] else {
257 self.needs_pop = true;
258 return NextResult::NonBranch;
259 };
260
261 let state_mask = branch.state_mask;
262 let start = head.next_dense_idx;
263 let child_depth = self.stack.len();
264
265 let mut descended = false;
266 for (branch_child_idx, nibble) in BranchChildIter::new(state_mask) {
267 if branch_child_idx.get() < start {
268 continue;
269 }
270
271 let child_idx = match &arena[head_idx].branch_ref().children[branch_child_idx] {
272 ArenaSparseNodeBranchChild::Revealed(child_idx) => *child_idx,
273 ArenaSparseNodeBranchChild::Blinded(_) => continue,
274 };
275
276 if should_descend(child_depth, &arena[child_idx]) {
277 self.stack.last_mut().expect("head exists").next_dense_idx =
279 branch_child_idx.get() + 1;
280 let path = self.child_path(arena, nibble);
281 self.push(arena, child_idx, path);
282 descended = true;
283 break;
284 }
285 }
286
287 if !descended {
288 self.needs_pop = true;
289 return NextResult::Branch;
290 }
291 }
292 }
293
294 #[instrument(level = "trace", target = TRACE_TARGET, skip(self, arena), ret)]
300 pub(super) fn seek(&mut self, arena: &mut NodeArena, full_path: &Nibbles) -> SeekResult {
301 while self.stack.len() > 1 &&
303 !full_path.starts_with(&self.stack.last().expect("cursor has root").path)
304 {
305 self.pop(arena);
306 }
307
308 loop {
309 let head = self.stack.last().expect("cursor has root");
310 let head_idx = head.index;
311
312 let head_branch = match &arena[head_idx] {
313 ArenaSparseNode::EmptyRoot => {
314 return SeekResult::EmptyRoot;
315 }
316 ArenaSparseNode::Leaf { key, .. } => {
317 let mut leaf_full_path = head.path;
318 leaf_full_path.extend(key);
319 return if &leaf_full_path == full_path {
320 SeekResult::RevealedLeaf
321 } else {
322 SeekResult::Diverged
323 };
324 }
325 ArenaSparseNode::Branch(b) => b,
326 ArenaSparseNode::Subtrie(_) => {
327 return SeekResult::RevealedSubtrie;
328 }
329 _ => unreachable!("unexpected node type on stack: {:?}", arena[head_idx]),
330 };
331
332 let head_branch_logical_path = logical_branch_path(arena, head);
333
334 if full_path.len() <= head_branch_logical_path.len() ||
337 !full_path.starts_with(&head_branch_logical_path)
338 {
339 return SeekResult::Diverged;
340 }
341
342 let child_nibble = full_path.get_unchecked(head_branch_logical_path.len());
343 let Some(branch_child_idx) = BranchChildIdx::new(head_branch.state_mask, child_nibble)
344 else {
345 return SeekResult::NoChild { child_nibble };
346 };
347
348 match &head_branch.children[branch_child_idx] {
349 ArenaSparseNodeBranchChild::Blinded(_) => {
350 return SeekResult::Blinded;
351 }
352 ArenaSparseNodeBranchChild::Revealed(child_idx) => {
353 let child_idx = *child_idx;
354 let path = self.child_path(arena, child_nibble);
355 self.push(arena, child_idx, path);
356 }
357 }
358 }
359 }
360}
361
362fn logical_branch_path(arena: &NodeArena, entry: &ArenaCursorStackEntry) -> Nibbles {
365 let mut path = entry.path;
366 path.extend(&arena[entry.index].branch_ref().short_key);
367 path
368}
369
370fn logical_branch_path_len(arena: &NodeArena, entry: &ArenaCursorStackEntry) -> usize {
373 entry.path.len() + arena[entry.index].branch_ref().short_key.len()
374}