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.state_ref(), Some(ArenaSparseNodeState::Dirty))
139 }
140 _ => false,
141 });
142 if child_is_dirty {
143 *arena[parent.index].state_mut() = ArenaSparseNodeState::Dirty;
144 }
145 }
146
147 entry
148 }
149
150 #[instrument(level = "trace", target = TRACE_TARGET, skip_all)]
153 pub(super) fn drain(&mut self, arena: &mut NodeArena) {
154 trace!(target: TRACE_TARGET, "Draining stack");
155 self.needs_pop = false;
156 while self.stack.len() > 1 {
157 self.pop(arena);
158 }
159 }
160
161 pub(super) fn head_logical_branch_path(&self, arena: &NodeArena) -> Nibbles {
164 logical_branch_path(arena, self.stack.last().expect("cursor is non-empty"))
165 }
166
167 pub(super) fn head_logical_branch_path_len(&self, arena: &NodeArena) -> usize {
170 logical_branch_path_len(arena, self.stack.last().expect("cursor is non-empty"))
171 }
172
173 pub(super) fn child_path(&self, arena: &NodeArena, child_nibble: u8) -> Nibbles {
176 let mut path = logical_branch_path(arena, self.stack.last().expect("cursor is non-empty"));
177 path.push_unchecked(child_nibble);
178 path
179 }
180
181 pub(super) fn parent_logical_branch_path(&self, arena: &NodeArena) -> Nibbles {
184 logical_branch_path(arena, self.parent().expect("cursor must have a parent"))
185 }
186
187 pub(super) fn replace_head_index(
191 &mut self,
192 arena: &mut NodeArena,
193 root: &mut Index,
194 new_idx: Index,
195 ) {
196 let head = self.stack.last_mut().expect("cursor must have head");
197 let old_idx = head.index;
198 let child_nibble = head.path.last();
199 head.index = new_idx;
200
201 let Some(parent) = self.parent() else {
202 *root = new_idx;
203 return;
204 };
205
206 let child_nibble =
207 child_nibble.expect("if cursor has a parent then the head path can't be empty");
208
209 let parent_branch = arena[parent.index].branch_mut();
210 let child_idx = BranchChildIdx::new(parent_branch.state_mask, child_nibble)
211 .expect("child nibble not found in parent state_mask");
212
213 debug_assert!(
214 matches!(
215 parent_branch.children[child_idx],
216 ArenaSparseNodeBranchChild::Revealed(idx)
217 if idx == old_idx
218 ),
219 "parent child at nibble {child_nibble} does not match old_idx",
220 );
221
222 parent_branch.children[child_idx] = ArenaSparseNodeBranchChild::Revealed(new_idx);
223 }
224
225 #[instrument(level = "trace", target = TRACE_TARGET, skip_all, ret)]
239 pub(super) fn next(
240 &mut self,
241 arena: &mut NodeArena,
242 should_descend: impl Fn(usize, &ArenaSparseNode) -> bool,
243 ) -> NextResult {
244 if self.needs_pop {
245 self.pop(arena);
246 self.needs_pop = false;
247 }
248
249 loop {
250 let Some(head) = self.stack.last_mut() else {
251 return NextResult::Done;
252 };
253 let head_idx = head.index;
254
255 let ArenaSparseNode::Branch(branch) = &arena[head_idx] else {
256 self.needs_pop = true;
257 return NextResult::NonBranch;
258 };
259
260 let state_mask = branch.state_mask;
261 let start = head.next_dense_idx;
262 let child_depth = self.stack.len();
263
264 let mut descended = false;
265 for (branch_child_idx, nibble) in BranchChildIter::new(state_mask) {
266 if branch_child_idx.get() < start {
267 continue;
268 }
269
270 let child_idx = match &arena[head_idx].branch_ref().children[branch_child_idx] {
271 ArenaSparseNodeBranchChild::Revealed(child_idx) => *child_idx,
272 ArenaSparseNodeBranchChild::Blinded(_) => continue,
273 };
274
275 if should_descend(child_depth, &arena[child_idx]) {
276 self.stack.last_mut().expect("head exists").next_dense_idx =
278 branch_child_idx.get() + 1;
279 let path = self.child_path(arena, nibble);
280 self.push(arena, child_idx, path);
281 descended = true;
282 break;
283 }
284 }
285
286 if !descended {
287 self.needs_pop = true;
288 return NextResult::Branch;
289 }
290 }
291 }
292
293 #[instrument(level = "trace", target = TRACE_TARGET, skip(self, arena), ret)]
299 pub(super) fn seek(&mut self, arena: &mut NodeArena, full_path: &Nibbles) -> SeekResult {
300 while self.stack.len() > 1 &&
302 !full_path.starts_with(&self.stack.last().expect("cursor has root").path)
303 {
304 self.pop(arena);
305 }
306
307 loop {
308 let head = self.stack.last().expect("cursor has root");
309 let head_idx = head.index;
310
311 let head_branch = match &arena[head_idx] {
312 ArenaSparseNode::EmptyRoot { .. } => {
313 return SeekResult::EmptyRoot;
314 }
315 ArenaSparseNode::Leaf { key, .. } => {
316 let mut leaf_full_path = head.path;
317 leaf_full_path.extend(key);
318 return if &leaf_full_path == full_path {
319 SeekResult::RevealedLeaf
320 } else {
321 SeekResult::Diverged
322 };
323 }
324 ArenaSparseNode::Branch(b) => b,
325 ArenaSparseNode::Subtrie(_) => {
326 return SeekResult::RevealedSubtrie;
327 }
328 _ => unreachable!("unexpected node type on stack: {:?}", arena[head_idx]),
329 };
330
331 let head_branch_logical_path = logical_branch_path(arena, head);
332
333 if full_path.len() <= head_branch_logical_path.len() ||
336 !full_path.starts_with(&head_branch_logical_path)
337 {
338 return SeekResult::Diverged;
339 }
340
341 let child_nibble = full_path.get_unchecked(head_branch_logical_path.len());
342 let Some(branch_child_idx) = BranchChildIdx::new(head_branch.state_mask, child_nibble)
343 else {
344 return SeekResult::NoChild { child_nibble };
345 };
346
347 match &head_branch.children[branch_child_idx] {
348 ArenaSparseNodeBranchChild::Blinded(_) => {
349 return SeekResult::Blinded;
350 }
351 ArenaSparseNodeBranchChild::Revealed(child_idx) => {
352 let child_idx = *child_idx;
353 let path = self.child_path(arena, child_nibble);
354 self.push(arena, child_idx, path);
355 }
356 }
357 }
358 }
359}
360
361fn logical_branch_path(arena: &NodeArena, entry: &ArenaCursorStackEntry) -> Nibbles {
364 let mut path = entry.path;
365 path.extend(&arena[entry.index].branch_ref().short_key);
366 path
367}
368
369fn logical_branch_path_len(arena: &NodeArena, entry: &ArenaCursorStackEntry) -> usize {
372 entry.path.len() + arena[entry.index].branch_ref().short_key.len()
373}