1use crate::engine::EngineApiKind;
4use alloy_eips::BlockNumHash;
5use alloy_primitives::{
6 map::{B256Map, B256Set},
7 BlockNumber, B256,
8};
9use reth_chain_state::{DeferredTrieData, EthPrimitives, ExecutedBlock, LazyOverlay};
10use reth_primitives_traits::{AlloyBlockHeader, NodePrimitives, SealedHeader};
11use std::{
12 collections::{btree_map, hash_map, BTreeMap, VecDeque},
13 ops::Bound,
14};
15use tracing::debug;
16
17#[derive(Debug, Default)]
24pub struct TreeState<N: NodePrimitives = EthPrimitives> {
25 pub(crate) blocks_by_hash: B256Map<ExecutedBlock<N>>,
29 pub(crate) blocks_by_number: BTreeMap<BlockNumber, Vec<ExecutedBlock<N>>>,
35 pub(crate) parent_to_child: B256Map<B256Set>,
37 pub(crate) current_canonical_head: BlockNumHash,
39 pub(crate) engine_kind: EngineApiKind,
41 pub(crate) cached_canonical_overlay: Option<PreparedCanonicalOverlay>,
47}
48
49impl<N: NodePrimitives> TreeState<N> {
50 pub fn new(current_canonical_head: BlockNumHash, engine_kind: EngineApiKind) -> Self {
52 Self {
53 blocks_by_hash: B256Map::default(),
54 blocks_by_number: BTreeMap::new(),
55 current_canonical_head,
56 parent_to_child: B256Map::default(),
57 engine_kind,
58 cached_canonical_overlay: None,
59 }
60 }
61
62 pub fn reset(&mut self, current_canonical_head: BlockNumHash) {
64 *self = Self::new(current_canonical_head, self.engine_kind);
65 }
66
67 pub fn block_count(&self) -> usize {
69 self.blocks_by_hash.len()
70 }
71
72 pub fn executed_block_by_hash(&self, hash: B256) -> Option<&ExecutedBlock<N>> {
74 self.blocks_by_hash.get(&hash)
75 }
76
77 pub fn contains_hash(&self, hash: &B256) -> bool {
79 self.blocks_by_hash.contains_key(hash)
80 }
81
82 pub fn sealed_header_by_hash(&self, hash: &B256) -> Option<SealedHeader<N::BlockHeader>> {
84 self.blocks_by_hash.get(hash).map(|b| b.sealed_block().sealed_header().clone())
85 }
86
87 pub fn blocks_by_hash(&self, hash: B256) -> Option<(B256, Vec<ExecutedBlock<N>>)> {
93 let block = self.blocks_by_hash.get(&hash).cloned()?;
94 let mut parent_hash = block.recovered_block().parent_hash();
95 let mut blocks = vec![block];
96 while let Some(executed) = self.blocks_by_hash.get(&parent_hash) {
97 parent_hash = executed.recovered_block().parent_hash();
98 blocks.push(executed.clone());
99 }
100
101 Some((parent_hash, blocks))
102 }
103
104 pub(crate) fn prepare_canonical_overlay(&mut self) -> Option<LazyOverlay> {
113 let canonical_hash = self.current_canonical_head.hash;
114
115 let Some((anchor_hash, blocks)) = self.blocks_by_hash(canonical_hash) else {
117 self.cached_canonical_overlay = None;
119 return None;
120 };
121
122 let handles: Vec<DeferredTrieData> = blocks.iter().map(|b| b.trie_data_handle()).collect();
124
125 let overlay = LazyOverlay::new(anchor_hash, handles);
126 self.cached_canonical_overlay = Some(PreparedCanonicalOverlay {
127 parent_hash: canonical_hash,
128 overlay: overlay.clone(),
129 anchor_hash,
130 });
131
132 debug!(
133 target: "engine::tree",
134 %canonical_hash,
135 %anchor_hash,
136 num_blocks = blocks.len(),
137 "Prepared cached canonical overlay"
138 );
139
140 Some(overlay)
141 }
142
143 pub fn get_cached_overlay(
148 &self,
149 parent_hash: B256,
150 expected_anchor: B256,
151 ) -> Option<&PreparedCanonicalOverlay> {
152 self.cached_canonical_overlay.as_ref().filter(|cached| {
153 cached.parent_hash == parent_hash && cached.anchor_hash == expected_anchor
154 })
155 }
156
157 pub(crate) fn invalidate_cached_overlay(&mut self) {
161 self.cached_canonical_overlay = None;
162 }
163
164 pub fn insert_executed(&mut self, executed: ExecutedBlock<N>) {
166 let hash = executed.recovered_block().hash();
167 let parent_hash = executed.recovered_block().parent_hash();
168 let block_number = executed.recovered_block().number();
169
170 if self.blocks_by_hash.contains_key(&hash) {
171 return;
172 }
173
174 self.blocks_by_hash.insert(hash, executed.clone());
175
176 self.blocks_by_number.entry(block_number).or_default().push(executed);
177
178 self.parent_to_child.entry(parent_hash).or_default().insert(hash);
179 }
180
181 fn remove_by_hash(&mut self, hash: B256) -> Option<(ExecutedBlock<N>, B256Set)> {
187 let executed = self.blocks_by_hash.remove(&hash)?;
188
189 let parent_entry = self.parent_to_child.entry(executed.recovered_block().parent_hash());
191 if let hash_map::Entry::Occupied(mut entry) = parent_entry {
192 entry.get_mut().remove(&hash);
193
194 if entry.get().is_empty() {
195 entry.remove();
196 }
197 }
198
199 let children = self.parent_to_child.remove(&hash).unwrap_or_default();
201
202 let block_number_entry = self.blocks_by_number.entry(executed.recovered_block().number());
204 if let btree_map::Entry::Occupied(mut entry) = block_number_entry {
205 if let Some(index) = entry.get().iter().position(|b| b.recovered_block().hash() == hash)
207 {
208 entry.get_mut().swap_remove(index);
209
210 if entry.get().is_empty() {
212 entry.remove();
213 }
214 }
215 }
216
217 Some((executed, children))
218 }
219
220 pub fn is_canonical(&self, hash: B256) -> bool {
222 let mut current_block = self.current_canonical_head.hash;
223 if current_block == hash {
224 return true
225 }
226
227 while let Some(executed) = self.blocks_by_hash.get(¤t_block) {
228 current_block = executed.recovered_block().parent_hash();
229 if current_block == hash {
230 return true
231 }
232 }
233
234 false
235 }
236
237 pub fn remove_canonical_until(&mut self, upper_bound: BlockNumber, last_persisted_hash: B256) {
240 debug!(target: "engine::tree", ?upper_bound, ?last_persisted_hash, "Removing canonical blocks from the tree");
241
242 if !self.is_canonical(last_persisted_hash) {
245 return
246 }
247
248 let mut current_block = self.current_canonical_head.hash;
251 while let Some(executed) = self.blocks_by_hash.get(¤t_block) {
252 current_block = executed.recovered_block().parent_hash();
253 if executed.recovered_block().number() <= upper_bound {
254 let num_hash = executed.recovered_block().num_hash();
255 debug!(target: "engine::tree", ?num_hash, "Attempting to remove block walking back from the head");
256 self.remove_by_hash(executed.recovered_block().hash());
257 }
258 }
259 debug!(target: "engine::tree", ?upper_bound, ?last_persisted_hash, "Removed canonical blocks from the tree");
260 }
261
262 pub fn prune_finalized_sidechains(&mut self, finalized_num_hash: BlockNumHash) {
265 let BlockNumHash { number: finalized_num, hash: finalized_hash } = finalized_num_hash;
266
267 let blocks_to_remove = self
276 .blocks_by_number
277 .range((Bound::Unbounded, Bound::Excluded(finalized_num)))
278 .flat_map(|(_, blocks)| blocks.iter().map(|b| b.recovered_block().hash()))
279 .collect::<Vec<_>>();
280 for hash in blocks_to_remove {
281 if let Some((removed, _)) = self.remove_by_hash(hash) {
282 debug!(target: "engine::tree", num_hash=?removed.recovered_block().num_hash(), "Removed finalized sidechain block");
283 }
284 }
285
286 let mut blocks_to_remove = self.blocks_by_number.remove(&finalized_num).unwrap_or_default();
293
294 if let Some(position) =
296 blocks_to_remove.iter().position(|b| b.recovered_block().hash() == finalized_hash)
297 {
298 let finalized_block = blocks_to_remove.swap_remove(position);
299 self.blocks_by_number.insert(finalized_num, vec![finalized_block]);
300 }
301
302 let mut blocks_to_remove = blocks_to_remove
303 .into_iter()
304 .map(|e| e.recovered_block().hash())
305 .collect::<VecDeque<_>>();
306 while let Some(block) = blocks_to_remove.pop_front() {
307 if let Some((removed, children)) = self.remove_by_hash(block) {
308 debug!(target: "engine::tree", num_hash=?removed.recovered_block().num_hash(), "Removed finalized sidechain child block");
309 blocks_to_remove.extend(children);
310 }
311 }
312 }
313
314 pub fn remove_until(
325 &mut self,
326 upper_bound: BlockNumHash,
327 last_persisted_hash: B256,
328 finalized_num_hash: Option<BlockNumHash>,
329 ) {
330 debug!(target: "engine::tree", ?upper_bound, ?finalized_num_hash, "Removing blocks from the tree");
331
332 let finalized_num_hash = finalized_num_hash.map(|mut finalized| {
335 if upper_bound.number < finalized.number {
336 finalized = upper_bound;
337 debug!(target: "engine::tree", ?finalized, "Adjusted upper bound");
338 }
339 finalized
340 });
341
342 self.remove_canonical_until(upper_bound.number, last_persisted_hash);
350
351 if let Some(finalized_num_hash) = finalized_num_hash {
354 self.prune_finalized_sidechains(finalized_num_hash);
355 }
356
357 self.invalidate_cached_overlay();
359 }
360
361 pub const fn set_canonical_head(&mut self, new_head: BlockNumHash) {
363 self.current_canonical_head = new_head;
364 }
365
366 pub const fn canonical_head(&self) -> &BlockNumHash {
368 &self.current_canonical_head
369 }
370
371 pub const fn canonical_block_hash(&self) -> B256 {
373 self.canonical_head().hash
374 }
375
376 pub const fn canonical_block_number(&self) -> BlockNumber {
378 self.canonical_head().number
379 }
380}
381
382#[cfg(test)]
383impl<N: NodePrimitives> TreeState<N> {
384 pub fn is_descendant(
388 &self,
389 first: BlockNumHash,
390 second: alloy_eips::eip1898::BlockWithParent,
391 ) -> bool {
392 if second.parent == first.hash {
395 return true
396 }
397
398 if second.block.number <= first.number {
401 return false
402 }
403
404 let Some(mut current_block) = self.blocks_by_hash.get(&second.parent) else {
406 return false
408 };
409
410 while current_block.recovered_block().number() > first.number + 1 {
411 let Some(block) =
412 self.blocks_by_hash.get(¤t_block.recovered_block().parent_hash())
413 else {
414 return false
416 };
417
418 current_block = block;
419 }
420
421 current_block.recovered_block().parent_hash() == first.hash
423 }
424}
425
426#[derive(Debug, Clone)]
443pub struct PreparedCanonicalOverlay {
444 pub parent_hash: B256,
448 pub overlay: LazyOverlay,
453 pub anchor_hash: B256,
457}
458
459#[cfg(test)]
460mod tests {
461 use super::*;
462 use reth_chain_state::test_utils::TestBlockBuilder;
463
464 #[test]
465 fn test_tree_state_normal_descendant() {
466 let mut tree_state = TreeState::new(BlockNumHash::default(), EngineApiKind::Ethereum);
467 let blocks: Vec<_> = TestBlockBuilder::eth().get_executed_blocks(1..4).collect();
468
469 tree_state.insert_executed(blocks[0].clone());
470 assert!(tree_state.is_descendant(
471 blocks[0].recovered_block().num_hash(),
472 blocks[1].recovered_block().block_with_parent()
473 ));
474
475 tree_state.insert_executed(blocks[1].clone());
476
477 assert!(tree_state.is_descendant(
478 blocks[0].recovered_block().num_hash(),
479 blocks[2].recovered_block().block_with_parent()
480 ));
481 assert!(tree_state.is_descendant(
482 blocks[1].recovered_block().num_hash(),
483 blocks[2].recovered_block().block_with_parent()
484 ));
485 }
486
487 #[tokio::test]
488 async fn test_tree_state_insert_executed() {
489 let mut tree_state = TreeState::new(BlockNumHash::default(), EngineApiKind::Ethereum);
490 let blocks: Vec<_> = TestBlockBuilder::eth().get_executed_blocks(1..4).collect();
491
492 tree_state.insert_executed(blocks[0].clone());
493 tree_state.insert_executed(blocks[1].clone());
494
495 assert_eq!(
496 tree_state.parent_to_child.get(&blocks[0].recovered_block().hash()),
497 Some(&B256Set::from_iter([blocks[1].recovered_block().hash()]))
498 );
499
500 assert!(!tree_state.parent_to_child.contains_key(&blocks[1].recovered_block().hash()));
501
502 tree_state.insert_executed(blocks[2].clone());
503
504 assert_eq!(
505 tree_state.parent_to_child.get(&blocks[1].recovered_block().hash()),
506 Some(&B256Set::from_iter([blocks[2].recovered_block().hash()]))
507 );
508 assert!(tree_state.parent_to_child.contains_key(&blocks[1].recovered_block().hash()));
509
510 assert!(!tree_state.parent_to_child.contains_key(&blocks[2].recovered_block().hash()));
511 }
512
513 #[tokio::test]
514 async fn test_tree_state_insert_executed_with_reorg() {
515 let mut tree_state = TreeState::new(BlockNumHash::default(), EngineApiKind::Ethereum);
516 let mut test_block_builder = TestBlockBuilder::eth();
517 let blocks: Vec<_> = test_block_builder.get_executed_blocks(1..6).collect();
518
519 for block in &blocks {
520 tree_state.insert_executed(block.clone());
521 }
522 assert_eq!(tree_state.blocks_by_hash.len(), 5);
523
524 let fork_block_3 = test_block_builder
525 .get_executed_block_with_number(3, blocks[1].recovered_block().hash());
526 let fork_block_4 = test_block_builder
527 .get_executed_block_with_number(4, fork_block_3.recovered_block().hash());
528 let fork_block_5 = test_block_builder
529 .get_executed_block_with_number(5, fork_block_4.recovered_block().hash());
530
531 tree_state.insert_executed(fork_block_3.clone());
532 tree_state.insert_executed(fork_block_4.clone());
533 tree_state.insert_executed(fork_block_5.clone());
534
535 assert_eq!(tree_state.blocks_by_hash.len(), 8);
536 assert_eq!(tree_state.blocks_by_number[&3].len(), 2); assert_eq!(tree_state.parent_to_child[&blocks[1].recovered_block().hash()].len(), 2); tree_state.insert_executed(fork_block_4.clone());
541 assert_eq!(tree_state.blocks_by_hash.len(), 8);
542
543 assert!(tree_state.parent_to_child[&fork_block_3.recovered_block().hash()]
544 .contains(&fork_block_4.recovered_block().hash()));
545 assert!(tree_state.parent_to_child[&fork_block_4.recovered_block().hash()]
546 .contains(&fork_block_5.recovered_block().hash()));
547
548 assert_eq!(tree_state.blocks_by_number[&4].len(), 2);
549 assert_eq!(tree_state.blocks_by_number[&5].len(), 2);
550 }
551
552 #[tokio::test]
553 async fn test_tree_state_remove_before() {
554 let start_num_hash = BlockNumHash::default();
555 let mut tree_state = TreeState::new(start_num_hash, EngineApiKind::Ethereum);
556 let blocks: Vec<_> = TestBlockBuilder::eth().get_executed_blocks(1..6).collect();
557
558 for block in &blocks {
559 tree_state.insert_executed(block.clone());
560 }
561
562 let last = blocks.last().unwrap();
563
564 tree_state.set_canonical_head(last.recovered_block().num_hash());
566
567 tree_state.remove_until(
569 BlockNumHash::new(2, blocks[1].recovered_block().hash()),
570 start_num_hash.hash,
571 Some(blocks[1].recovered_block().num_hash()),
572 );
573
574 assert!(!tree_state.blocks_by_hash.contains_key(&blocks[0].recovered_block().hash()));
575 assert!(!tree_state.blocks_by_hash.contains_key(&blocks[1].recovered_block().hash()));
576 assert!(!tree_state.blocks_by_number.contains_key(&1));
577 assert!(!tree_state.blocks_by_number.contains_key(&2));
578
579 assert!(tree_state.blocks_by_hash.contains_key(&blocks[2].recovered_block().hash()));
580 assert!(tree_state.blocks_by_hash.contains_key(&blocks[3].recovered_block().hash()));
581 assert!(tree_state.blocks_by_hash.contains_key(&blocks[4].recovered_block().hash()));
582 assert!(tree_state.blocks_by_number.contains_key(&3));
583 assert!(tree_state.blocks_by_number.contains_key(&4));
584 assert!(tree_state.blocks_by_number.contains_key(&5));
585
586 assert!(!tree_state.parent_to_child.contains_key(&blocks[0].recovered_block().hash()));
587 assert!(!tree_state.parent_to_child.contains_key(&blocks[1].recovered_block().hash()));
588 assert!(tree_state.parent_to_child.contains_key(&blocks[2].recovered_block().hash()));
589 assert!(tree_state.parent_to_child.contains_key(&blocks[3].recovered_block().hash()));
590 assert!(!tree_state.parent_to_child.contains_key(&blocks[4].recovered_block().hash()));
591
592 assert_eq!(
593 tree_state.parent_to_child.get(&blocks[2].recovered_block().hash()),
594 Some(&B256Set::from_iter([blocks[3].recovered_block().hash()]))
595 );
596 assert_eq!(
597 tree_state.parent_to_child.get(&blocks[3].recovered_block().hash()),
598 Some(&B256Set::from_iter([blocks[4].recovered_block().hash()]))
599 );
600 }
601
602 #[tokio::test]
603 async fn test_tree_state_remove_before_finalized() {
604 let start_num_hash = BlockNumHash::default();
605 let mut tree_state = TreeState::new(start_num_hash, EngineApiKind::Ethereum);
606 let blocks: Vec<_> = TestBlockBuilder::eth().get_executed_blocks(1..6).collect();
607
608 for block in &blocks {
609 tree_state.insert_executed(block.clone());
610 }
611
612 let last = blocks.last().unwrap();
613
614 tree_state.set_canonical_head(last.recovered_block().num_hash());
616
617 tree_state.remove_until(
619 BlockNumHash::new(2, blocks[1].recovered_block().hash()),
620 start_num_hash.hash,
621 None,
622 );
623
624 assert!(!tree_state.blocks_by_hash.contains_key(&blocks[0].recovered_block().hash()));
625 assert!(!tree_state.blocks_by_hash.contains_key(&blocks[1].recovered_block().hash()));
626 assert!(!tree_state.blocks_by_number.contains_key(&1));
627 assert!(!tree_state.blocks_by_number.contains_key(&2));
628
629 assert!(tree_state.blocks_by_hash.contains_key(&blocks[2].recovered_block().hash()));
630 assert!(tree_state.blocks_by_hash.contains_key(&blocks[3].recovered_block().hash()));
631 assert!(tree_state.blocks_by_hash.contains_key(&blocks[4].recovered_block().hash()));
632 assert!(tree_state.blocks_by_number.contains_key(&3));
633 assert!(tree_state.blocks_by_number.contains_key(&4));
634 assert!(tree_state.blocks_by_number.contains_key(&5));
635
636 assert!(!tree_state.parent_to_child.contains_key(&blocks[0].recovered_block().hash()));
637 assert!(!tree_state.parent_to_child.contains_key(&blocks[1].recovered_block().hash()));
638 assert!(tree_state.parent_to_child.contains_key(&blocks[2].recovered_block().hash()));
639 assert!(tree_state.parent_to_child.contains_key(&blocks[3].recovered_block().hash()));
640 assert!(!tree_state.parent_to_child.contains_key(&blocks[4].recovered_block().hash()));
641
642 assert_eq!(
643 tree_state.parent_to_child.get(&blocks[2].recovered_block().hash()),
644 Some(&B256Set::from_iter([blocks[3].recovered_block().hash()]))
645 );
646 assert_eq!(
647 tree_state.parent_to_child.get(&blocks[3].recovered_block().hash()),
648 Some(&B256Set::from_iter([blocks[4].recovered_block().hash()]))
649 );
650 }
651
652 #[tokio::test]
653 async fn test_tree_state_remove_before_lower_finalized() {
654 let start_num_hash = BlockNumHash::default();
655 let mut tree_state = TreeState::new(start_num_hash, EngineApiKind::Ethereum);
656 let blocks: Vec<_> = TestBlockBuilder::eth().get_executed_blocks(1..6).collect();
657
658 for block in &blocks {
659 tree_state.insert_executed(block.clone());
660 }
661
662 let last = blocks.last().unwrap();
663
664 tree_state.set_canonical_head(last.recovered_block().num_hash());
666
667 tree_state.remove_until(
669 BlockNumHash::new(2, blocks[1].recovered_block().hash()),
670 start_num_hash.hash,
671 Some(blocks[0].recovered_block().num_hash()),
672 );
673
674 assert!(!tree_state.blocks_by_hash.contains_key(&blocks[0].recovered_block().hash()));
675 assert!(!tree_state.blocks_by_hash.contains_key(&blocks[1].recovered_block().hash()));
676 assert!(!tree_state.blocks_by_number.contains_key(&1));
677 assert!(!tree_state.blocks_by_number.contains_key(&2));
678
679 assert!(tree_state.blocks_by_hash.contains_key(&blocks[2].recovered_block().hash()));
680 assert!(tree_state.blocks_by_hash.contains_key(&blocks[3].recovered_block().hash()));
681 assert!(tree_state.blocks_by_hash.contains_key(&blocks[4].recovered_block().hash()));
682 assert!(tree_state.blocks_by_number.contains_key(&3));
683 assert!(tree_state.blocks_by_number.contains_key(&4));
684 assert!(tree_state.blocks_by_number.contains_key(&5));
685
686 assert!(!tree_state.parent_to_child.contains_key(&blocks[0].recovered_block().hash()));
687 assert!(!tree_state.parent_to_child.contains_key(&blocks[1].recovered_block().hash()));
688 assert!(tree_state.parent_to_child.contains_key(&blocks[2].recovered_block().hash()));
689 assert!(tree_state.parent_to_child.contains_key(&blocks[3].recovered_block().hash()));
690 assert!(!tree_state.parent_to_child.contains_key(&blocks[4].recovered_block().hash()));
691
692 assert_eq!(
693 tree_state.parent_to_child.get(&blocks[2].recovered_block().hash()),
694 Some(&B256Set::from_iter([blocks[3].recovered_block().hash()]))
695 );
696 assert_eq!(
697 tree_state.parent_to_child.get(&blocks[3].recovered_block().hash()),
698 Some(&B256Set::from_iter([blocks[4].recovered_block().hash()]))
699 );
700 }
701}