1use alloy_primitives::B256;
2use parking_lot::Mutex;
3use reth_metrics::{metrics::Counter, Metrics};
4use reth_trie::{
5 updates::{TrieUpdates, TrieUpdatesSorted},
6 HashedPostState, HashedPostStateSorted, TrieInputSorted,
7};
8use std::{
9 fmt,
10 sync::{Arc, LazyLock},
11};
12use tracing::{debug_span, instrument};
13
14#[derive(Clone)]
20pub struct DeferredTrieData {
21 state: Arc<Mutex<DeferredState>>,
23}
24
25#[derive(Clone, Debug, Default)]
29pub struct ComputedTrieData {
30 pub hashed_state: Arc<HashedPostStateSorted>,
32 pub trie_updates: Arc<TrieUpdatesSorted>,
34 pub anchored_trie_input: Option<AnchoredTrieInput>,
36}
37
38#[derive(Clone, Debug)]
49pub struct AnchoredTrieInput {
50 pub anchor_hash: B256,
52 pub trie_input: Arc<TrieInputSorted>,
54}
55
56#[derive(Metrics)]
58#[metrics(scope = "sync.block_validation")]
59struct DeferredTrieMetrics {
60 deferred_trie_async_ready: Counter,
62 deferred_trie_sync_fallback: Counter,
64}
65
66static DEFERRED_TRIE_METRICS: LazyLock<DeferredTrieMetrics> =
67 LazyLock::new(DeferredTrieMetrics::default);
68
69enum DeferredState {
71 Pending(Option<PendingInputs>),
74 Ready(ComputedTrieData),
76}
77
78#[derive(Clone, Debug)]
80struct PendingInputs {
81 hashed_state: Arc<HashedPostState>,
83 trie_updates: Arc<TrieUpdates>,
85 anchor_hash: B256,
87 ancestors: Vec<DeferredTrieData>,
89}
90
91impl fmt::Debug for DeferredTrieData {
92 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
93 let state = self.state.lock();
94 match &*state {
95 DeferredState::Pending(_) => {
96 f.debug_struct("DeferredTrieData").field("state", &"pending").finish()
97 }
98 DeferredState::Ready(_) => {
99 f.debug_struct("DeferredTrieData").field("state", &"ready").finish()
100 }
101 }
102 }
103}
104
105impl DeferredTrieData {
106 pub fn pending(
117 hashed_state: Arc<HashedPostState>,
118 trie_updates: Arc<TrieUpdates>,
119 anchor_hash: B256,
120 ancestors: Vec<Self>,
121 ) -> Self {
122 Self {
123 state: Arc::new(Mutex::new(DeferredState::Pending(Some(PendingInputs {
124 hashed_state,
125 trie_updates,
126 anchor_hash,
127 ancestors,
128 })))),
129 }
130 }
131
132 pub fn ready(bundle: ComputedTrieData) -> Self {
137 Self { state: Arc::new(Mutex::new(DeferredState::Ready(bundle))) }
138 }
139
140 pub fn sort_and_build_trie_input(
161 hashed_state: Arc<HashedPostState>,
162 trie_updates: Arc<TrieUpdates>,
163 anchor_hash: B256,
164 ancestors: &[Self],
165 ) -> ComputedTrieData {
166 let _span = debug_span!(target: "engine::tree::deferred_trie", "sort_inputs").entered();
167
168 #[cfg(feature = "rayon")]
169 let (sorted_hashed_state, sorted_trie_updates) = rayon::join(
170 || match Arc::try_unwrap(hashed_state) {
171 Ok(state) => state.into_sorted(),
172 Err(arc) => arc.clone_into_sorted(),
173 },
174 || match Arc::try_unwrap(trie_updates) {
175 Ok(updates) => updates.into_sorted(),
176 Err(arc) => arc.clone_into_sorted(),
177 },
178 );
179
180 #[cfg(not(feature = "rayon"))]
181 let (sorted_hashed_state, sorted_trie_updates) = (
182 match Arc::try_unwrap(hashed_state) {
183 Ok(state) => state.into_sorted(),
184 Err(arc) => arc.clone_into_sorted(),
185 },
186 match Arc::try_unwrap(trie_updates) {
187 Ok(updates) => updates.into_sorted(),
188 Err(arc) => arc.clone_into_sorted(),
189 },
190 );
191
192 drop(_span);
193
194 let _span = debug_span!(target: "engine::tree::deferred_trie", "build_overlay").entered();
195
196 let overlay = if let Some(parent) = ancestors.last() {
201 let parent_data = parent.wait_cloned();
202
203 match &parent_data.anchored_trie_input {
204 Some(AnchoredTrieInput { anchor_hash: parent_anchor, trie_input })
206 if *parent_anchor == anchor_hash =>
207 {
208 let mut overlay = TrieInputSorted::new(
210 Arc::clone(&trie_input.nodes),
211 Arc::clone(&trie_input.state),
212 Default::default(), );
214 let _span =
215 debug_span!(target: "engine::tree::deferred_trie", "extend_overlay")
216 .entered();
217 #[cfg(feature = "rayon")]
219 {
220 rayon::join(
221 || {
222 if !sorted_hashed_state.is_empty() {
223 Arc::make_mut(&mut overlay.state)
224 .extend_ref_and_sort(&sorted_hashed_state);
225 }
226 },
227 || {
228 if !sorted_trie_updates.is_empty() {
229 Arc::make_mut(&mut overlay.nodes)
230 .extend_ref_and_sort(&sorted_trie_updates);
231 }
232 },
233 );
234 }
235 #[cfg(not(feature = "rayon"))]
236 {
237 if !sorted_hashed_state.is_empty() {
238 Arc::make_mut(&mut overlay.state)
239 .extend_ref_and_sort(&sorted_hashed_state);
240 }
241 if !sorted_trie_updates.is_empty() {
242 Arc::make_mut(&mut overlay.nodes)
243 .extend_ref_and_sort(&sorted_trie_updates);
244 }
245 }
246 overlay
247 }
248 _ => Self::merge_ancestors_into_overlay(
251 ancestors,
252 &sorted_hashed_state,
253 &sorted_trie_updates,
254 ),
255 }
256 } else {
257 Self::merge_ancestors_into_overlay(&[], &sorted_hashed_state, &sorted_trie_updates)
260 };
261
262 ComputedTrieData::with_trie_input(
263 Arc::new(sorted_hashed_state),
264 Arc::new(sorted_trie_updates),
265 anchor_hash,
266 Arc::new(overlay),
267 )
268 }
269
270 #[cfg(feature = "rayon")]
281 fn merge_ancestors_into_overlay(
282 ancestors: &[Self],
283 sorted_hashed_state: &HashedPostStateSorted,
284 sorted_trie_updates: &TrieUpdatesSorted,
285 ) -> TrieInputSorted {
286 if ancestors.is_empty() {
288 return TrieInputSorted::new(
289 Arc::new(sorted_trie_updates.clone()),
290 Arc::new(sorted_hashed_state.clone()),
291 Default::default(),
292 );
293 }
294
295 let (states, updates): (Vec<_>, Vec<_>) = ancestors
297 .iter()
298 .rev()
299 .map(|a| {
300 let data = a.wait_cloned();
302 (data.hashed_state, data.trie_updates)
303 })
304 .unzip();
305
306 let (state, nodes) = rayon::join(
308 || {
309 let mut merged = HashedPostStateSorted::merge_slice(&states);
310 merged.extend_ref_and_sort(sorted_hashed_state);
311 merged
312 },
313 || {
314 let mut merged = TrieUpdatesSorted::merge_slice(&updates);
315 merged.extend_ref_and_sort(sorted_trie_updates);
316 merged
317 },
318 );
319
320 TrieInputSorted::new(Arc::new(nodes), Arc::new(state), Default::default())
321 }
322
323 #[cfg(not(feature = "rayon"))]
325 fn merge_ancestors_into_overlay(
326 ancestors: &[Self],
327 sorted_hashed_state: &HashedPostStateSorted,
328 sorted_trie_updates: &TrieUpdatesSorted,
329 ) -> TrieInputSorted {
330 let _span = debug_span!(target: "engine::tree::deferred_trie", "merge_ancestors", num_ancestors = ancestors.len()).entered();
331 let mut overlay = TrieInputSorted::default();
332
333 let state_mut = Arc::make_mut(&mut overlay.state);
334 let nodes_mut = Arc::make_mut(&mut overlay.nodes);
335
336 for ancestor in ancestors {
337 let ancestor_data = ancestor.wait_cloned();
338 state_mut.extend_ref_and_sort(ancestor_data.hashed_state.as_ref());
339 nodes_mut.extend_ref_and_sort(ancestor_data.trie_updates.as_ref());
340 }
341
342 state_mut.extend_ref_and_sort(sorted_hashed_state);
343 nodes_mut.extend_ref_and_sort(sorted_trie_updates);
344
345 overlay
346 }
347
348 #[instrument(level = "debug", target = "engine::tree::deferred_trie", skip_all)]
360 pub fn wait_cloned(&self) -> ComputedTrieData {
361 let mut state = self.state.lock();
362 match &mut *state {
363 DeferredState::Ready(bundle) => {
365 DEFERRED_TRIE_METRICS.deferred_trie_async_ready.increment(1);
366 bundle.clone()
367 }
368 DeferredState::Pending(maybe_inputs) => {
371 DEFERRED_TRIE_METRICS.deferred_trie_sync_fallback.increment(1);
372
373 let inputs = maybe_inputs.take().expect("inputs must be present in Pending state");
374
375 let computed = Self::sort_and_build_trie_input(
376 inputs.hashed_state,
377 inputs.trie_updates,
378 inputs.anchor_hash,
379 &inputs.ancestors,
380 );
381 *state = DeferredState::Ready(computed.clone());
382
383 drop(state);
386
387 computed
388 }
389 }
390 }
391}
392
393impl ComputedTrieData {
394 pub const fn with_trie_input(
396 hashed_state: Arc<HashedPostStateSorted>,
397 trie_updates: Arc<TrieUpdatesSorted>,
398 anchor_hash: B256,
399 trie_input: Arc<TrieInputSorted>,
400 ) -> Self {
401 Self {
402 hashed_state,
403 trie_updates,
404 anchored_trie_input: Some(AnchoredTrieInput { anchor_hash, trie_input }),
405 }
406 }
407
408 pub const fn without_trie_input(
417 hashed_state: Arc<HashedPostStateSorted>,
418 trie_updates: Arc<TrieUpdatesSorted>,
419 ) -> Self {
420 Self { hashed_state, trie_updates, anchored_trie_input: None }
421 }
422
423 pub fn anchor_hash(&self) -> Option<B256> {
425 self.anchored_trie_input.as_ref().map(|anchored| anchored.anchor_hash)
426 }
427
428 pub fn trie_input(&self) -> Option<&Arc<TrieInputSorted>> {
430 self.anchored_trie_input.as_ref().map(|anchored| &anchored.trie_input)
431 }
432}
433
434#[cfg(test)]
435mod tests {
436 use super::*;
437 use alloy_primitives::{map::B256Map, U256};
438 use reth_primitives_traits::Account;
439 use reth_trie::updates::TrieUpdates;
440 use std::{
441 sync::Arc,
442 thread,
443 time::{Duration, Instant},
444 };
445
446 fn empty_bundle() -> ComputedTrieData {
447 ComputedTrieData {
448 hashed_state: Arc::default(),
449 trie_updates: Arc::default(),
450 anchored_trie_input: None,
451 }
452 }
453
454 fn empty_pending() -> DeferredTrieData {
455 empty_pending_with_anchor(B256::ZERO)
456 }
457
458 fn empty_pending_with_anchor(anchor: B256) -> DeferredTrieData {
459 DeferredTrieData::pending(
460 Arc::new(HashedPostState::default()),
461 Arc::new(TrieUpdates::default()),
462 anchor,
463 Vec::new(),
464 )
465 }
466
467 #[test]
469 fn ready_returns_immediately() {
470 let bundle = empty_bundle();
471 let deferred = DeferredTrieData::ready(bundle.clone());
472
473 let start = Instant::now();
474 let result = deferred.wait_cloned();
475 let elapsed = start.elapsed();
476
477 assert_eq!(result.hashed_state, bundle.hashed_state);
478 assert_eq!(result.trie_updates, bundle.trie_updates);
479 assert_eq!(result.anchor_hash(), bundle.anchor_hash());
480 assert!(elapsed < Duration::from_millis(20));
481 }
482
483 #[test]
485 fn pending_computes_fallback() {
486 let deferred = empty_pending();
487
488 let start = Instant::now();
490 let result = deferred.wait_cloned();
491 let elapsed = start.elapsed();
492
493 assert!(elapsed < Duration::from_millis(100));
495 assert!(result.hashed_state.is_empty());
496 }
497
498 #[test]
500 fn fallback_result_is_cached() {
501 let deferred = empty_pending();
502
503 let first = deferred.wait_cloned();
505 let second = deferred.wait_cloned();
507
508 assert!(Arc::ptr_eq(&first.hashed_state, &second.hashed_state));
509 assert!(Arc::ptr_eq(&first.trie_updates, &second.trie_updates));
510 assert_eq!(first.anchor_hash(), second.anchor_hash());
511 }
512
513 #[test]
516 fn concurrent_wait_cloned_computes_once() {
517 let deferred = empty_pending();
518
519 let handles: Vec<_> = (0..10)
521 .map(|_| {
522 let d = deferred.clone();
523 thread::spawn(move || d.wait_cloned())
524 })
525 .collect();
526
527 let results: Vec<_> = handles.into_iter().map(|h| h.join().unwrap()).collect();
529
530 let first = &results[0];
532 for result in &results[1..] {
533 assert!(Arc::ptr_eq(&first.hashed_state, &result.hashed_state));
534 assert!(Arc::ptr_eq(&first.trie_updates, &result.trie_updates));
535 }
536 }
537
538 #[test]
541 fn ancestors_are_merged() {
542 let ancestor_bundle = ComputedTrieData {
544 hashed_state: Arc::default(),
545 trie_updates: Arc::default(),
546 anchored_trie_input: Some(AnchoredTrieInput {
547 anchor_hash: B256::with_last_byte(1),
548 trie_input: Arc::new(TrieInputSorted::default()),
549 }),
550 };
551 let ancestor = DeferredTrieData::ready(ancestor_bundle);
552
553 let deferred = DeferredTrieData::pending(
555 Arc::new(HashedPostState::default()),
556 Arc::new(TrieUpdates::default()),
557 B256::with_last_byte(2),
558 vec![ancestor],
559 );
560
561 let result = deferred.wait_cloned();
562 assert_eq!(result.anchor_hash(), Some(B256::with_last_byte(2)));
564 }
565
566 #[test]
569 fn ancestors_merge_in_chronological_order() {
570 let key = B256::with_last_byte(1);
571 let oldest_state = HashedPostStateSorted::new(
573 vec![(key, Some(Account { nonce: 1, balance: U256::ZERO, bytecode_hash: None }))],
574 B256Map::default(),
575 );
576 let newest_state = HashedPostStateSorted::new(
578 vec![(key, Some(Account { nonce: 2, balance: U256::ZERO, bytecode_hash: None }))],
579 B256Map::default(),
580 );
581
582 let oldest = ComputedTrieData {
583 hashed_state: Arc::new(oldest_state),
584 trie_updates: Arc::default(),
585 anchored_trie_input: None,
586 };
587 let newest = ComputedTrieData {
588 hashed_state: Arc::new(newest_state),
589 trie_updates: Arc::default(),
590 anchored_trie_input: None,
591 };
592
593 let deferred = DeferredTrieData::pending(
595 Arc::new(HashedPostState::default()),
596 Arc::new(TrieUpdates::default()),
597 B256::ZERO,
598 vec![DeferredTrieData::ready(oldest), DeferredTrieData::ready(newest)],
599 );
600
601 let result = deferred.wait_cloned();
602 let overlay_state = &result.anchored_trie_input.as_ref().unwrap().trie_input.state.accounts;
603 assert_eq!(overlay_state.len(), 1);
604 let (_, account) = &overlay_state[0];
605 assert_eq!(account.unwrap().nonce, 2);
606 }
607
608 fn ready_block_with_state(
610 anchor_hash: B256,
611 accounts: Vec<(B256, Option<Account>)>,
612 ) -> DeferredTrieData {
613 let hashed_state = Arc::new(HashedPostStateSorted::new(accounts, B256Map::default()));
614 let trie_updates = Arc::default();
615 let mut overlay = TrieInputSorted::default();
616 Arc::make_mut(&mut overlay.state).extend_ref_and_sort(hashed_state.as_ref());
617
618 DeferredTrieData::ready(ComputedTrieData {
619 hashed_state,
620 trie_updates,
621 anchored_trie_input: Some(AnchoredTrieInput {
622 anchor_hash,
623 trie_input: Arc::new(overlay),
624 }),
625 })
626 }
627
628 #[test]
630 fn first_block_after_anchor_creates_empty_base() {
631 let anchor = B256::with_last_byte(1);
632 let key = B256::with_last_byte(42);
633 let account = Account { nonce: 1, balance: U256::ZERO, bytecode_hash: None };
634
635 let first_block = DeferredTrieData::pending(
637 Arc::new(HashedPostState::default().with_accounts([(key, Some(account))])),
638 Arc::new(TrieUpdates::default()),
639 anchor,
640 vec![], );
642
643 let result = first_block.wait_cloned();
644
645 let overlay = result.anchored_trie_input.as_ref().unwrap();
647 assert_eq!(overlay.anchor_hash, anchor);
648 assert_eq!(overlay.trie_input.state.accounts.len(), 1);
649 let (found_key, found_account) = &overlay.trie_input.state.accounts[0];
650 assert_eq!(*found_key, key);
651 assert_eq!(found_account.unwrap().nonce, 1);
652 }
653
654 #[test]
656 fn reuses_parent_overlay() {
657 let anchor = B256::with_last_byte(1);
658 let key = B256::with_last_byte(42);
659 let account = Account { nonce: 100, balance: U256::ZERO, bytecode_hash: None };
660
661 let parent = ready_block_with_state(anchor, vec![(key, Some(account))]);
663
664 let child = DeferredTrieData::pending(
666 Arc::new(HashedPostState::default()),
667 Arc::new(TrieUpdates::default()),
668 anchor,
669 vec![parent],
670 );
671
672 let result = child.wait_cloned();
673
674 let overlay = result.anchored_trie_input.as_ref().unwrap();
676 assert_eq!(overlay.anchor_hash, anchor);
677 assert_eq!(overlay.trie_input.state.accounts.len(), 1);
678 let (found_key, found_account) = &overlay.trie_input.state.accounts[0];
679 assert_eq!(*found_key, key);
680 assert_eq!(found_account.unwrap().nonce, 100);
681 }
682
683 #[test]
687 fn rebuilds_overlay_when_anchor_changes() {
688 let old_anchor = B256::with_last_byte(1);
689 let new_anchor = B256::with_last_byte(2);
690 let key = B256::with_last_byte(42);
691 let account = Account { nonce: 50, balance: U256::ZERO, bytecode_hash: None };
692
693 let parent = ready_block_with_state(old_anchor, vec![(key, Some(account))]);
695
696 let child = DeferredTrieData::pending(
699 Arc::new(HashedPostState::default()),
700 Arc::new(TrieUpdates::default()),
701 new_anchor,
702 vec![parent],
703 );
704
705 let result = child.wait_cloned();
706
707 let overlay = result.anchored_trie_input.as_ref().unwrap();
709 assert_eq!(overlay.anchor_hash, new_anchor);
710
711 assert_eq!(overlay.trie_input.state.accounts.len(), 1);
717 let (found_key, found_account) = &overlay.trie_input.state.accounts[0];
718 assert_eq!(*found_key, key);
719 assert_eq!(found_account.unwrap().nonce, 50);
720 }
721
722 #[test]
724 fn rebuilds_when_parent_has_no_anchored_input() {
725 let anchor = B256::with_last_byte(1);
726 let key = B256::with_last_byte(42);
727 let account = Account { nonce: 25, balance: U256::ZERO, bytecode_hash: None };
728
729 let parent_state =
731 HashedPostStateSorted::new(vec![(key, Some(account))], B256Map::default());
732 let parent = DeferredTrieData::ready(ComputedTrieData {
733 hashed_state: Arc::new(parent_state),
734 trie_updates: Arc::default(),
735 anchored_trie_input: None, });
737
738 let child = DeferredTrieData::pending(
740 Arc::new(HashedPostState::default()),
741 Arc::new(TrieUpdates::default()),
742 anchor,
743 vec![parent],
744 );
745
746 let result = child.wait_cloned();
747
748 let overlay = result.anchored_trie_input.as_ref().unwrap();
750 assert_eq!(overlay.anchor_hash, anchor);
751 assert_eq!(overlay.trie_input.state.accounts.len(), 1);
752 }
753
754 #[test]
756 fn chain_of_blocks_builds_cumulative_overlay() {
757 let anchor = B256::with_last_byte(1);
758 let key1 = B256::with_last_byte(1);
759 let key2 = B256::with_last_byte(2);
760 let key3 = B256::with_last_byte(3);
761
762 let block1 = ready_block_with_state(
764 anchor,
765 vec![(key1, Some(Account { nonce: 1, balance: U256::ZERO, bytecode_hash: None }))],
766 );
767
768 let block2_hashed = HashedPostState::default().with_accounts([(
770 key2,
771 Some(Account { nonce: 2, balance: U256::ZERO, bytecode_hash: None }),
772 )]);
773 let block2 = DeferredTrieData::pending(
774 Arc::new(block2_hashed),
775 Arc::new(TrieUpdates::default()),
776 anchor,
777 vec![block1.clone()],
778 );
779 let block2_computed = block2.wait_cloned();
781 let block2_ready = DeferredTrieData::ready(block2_computed);
782
783 let block3_hashed = HashedPostState::default().with_accounts([(
785 key3,
786 Some(Account { nonce: 3, balance: U256::ZERO, bytecode_hash: None }),
787 )]);
788 let block3 = DeferredTrieData::pending(
789 Arc::new(block3_hashed),
790 Arc::new(TrieUpdates::default()),
791 anchor,
792 vec![block1, block2_ready],
793 );
794
795 let result = block3.wait_cloned();
796
797 let overlay = result.anchored_trie_input.as_ref().unwrap();
799 assert_eq!(overlay.trie_input.state.accounts.len(), 3);
800
801 let accounts = &overlay.trie_input.state.accounts;
803 assert!(accounts.iter().any(|(k, a)| *k == key1 && a.unwrap().nonce == 1));
804 assert!(accounts.iter().any(|(k, a)| *k == key2 && a.unwrap().nonce == 2));
805 assert!(accounts.iter().any(|(k, a)| *k == key3 && a.unwrap().nonce == 3));
806 }
807
808 #[test]
810 fn child_state_overwrites_parent() {
811 let anchor = B256::with_last_byte(1);
812 let key = B256::with_last_byte(42);
813
814 let parent = ready_block_with_state(
816 anchor,
817 vec![(key, Some(Account { nonce: 10, balance: U256::ZERO, bytecode_hash: None }))],
818 );
819
820 let child_hashed = HashedPostState::default().with_accounts([(
822 key,
823 Some(Account { nonce: 99, balance: U256::ZERO, bytecode_hash: None }),
824 )]);
825 let child = DeferredTrieData::pending(
826 Arc::new(child_hashed),
827 Arc::new(TrieUpdates::default()),
828 anchor,
829 vec![parent],
830 );
831
832 let result = child.wait_cloned();
833
834 let overlay = result.anchored_trie_input.as_ref().unwrap();
836 let accounts = &overlay.trie_input.state.accounts;
838 let last_account = accounts.iter().rfind(|(k, _)| *k == key).unwrap();
839 assert_eq!(last_account.1.unwrap().nonce, 99);
840 }
841
842 #[test]
845 fn long_chain_builds_in_linear_time() {
846 let anchor = B256::with_last_byte(1);
847 let num_blocks = 50; let mut ancestors: Vec<DeferredTrieData> = Vec::new();
850
851 let start = Instant::now();
852
853 for i in 0..num_blocks {
854 let key = B256::with_last_byte(i as u8);
855 let account = Account { nonce: i as u64, balance: U256::ZERO, bytecode_hash: None };
856 let hashed = HashedPostState::default().with_accounts([(key, Some(account))]);
857
858 let block = DeferredTrieData::pending(
859 Arc::new(hashed),
860 Arc::new(TrieUpdates::default()),
861 anchor,
862 ancestors.clone(),
863 );
864
865 let computed = block.wait_cloned();
867 ancestors.push(DeferredTrieData::ready(computed));
868 }
869
870 let elapsed = start.elapsed();
871
872 assert!(
875 elapsed < Duration::from_secs(2),
876 "Chain of {num_blocks} blocks took {:?}, possible O(N²) regression",
877 elapsed
878 );
879
880 let final_result = ancestors.last().unwrap().wait_cloned();
882 let overlay = final_result.anchored_trie_input.as_ref().unwrap();
883 assert_eq!(overlay.trie_input.state.accounts.len(), num_blocks);
884 }
885
886 #[test]
892 fn multi_ancestor_overlay_rebuilt_after_anchor_change() {
893 let old_anchor = B256::with_last_byte(1);
894 let new_anchor = B256::with_last_byte(2);
895 let key1 = B256::with_last_byte(1);
896 let key2 = B256::with_last_byte(2);
897 let key3 = B256::with_last_byte(3);
898 let key4 = B256::with_last_byte(4);
899
900 let block1 = ready_block_with_state(
902 old_anchor,
903 vec![(key1, Some(Account { nonce: 1, balance: U256::ZERO, bytecode_hash: None }))],
904 );
905
906 let block2_hashed = HashedPostState::default().with_accounts([(
907 key2,
908 Some(Account { nonce: 2, balance: U256::ZERO, bytecode_hash: None }),
909 )]);
910 let block2 = DeferredTrieData::pending(
911 Arc::new(block2_hashed),
912 Arc::new(TrieUpdates::default()),
913 old_anchor,
914 vec![block1.clone()],
915 );
916 let block2_ready = DeferredTrieData::ready(block2.wait_cloned());
917
918 let block3_hashed = HashedPostState::default().with_accounts([(
919 key3,
920 Some(Account { nonce: 3, balance: U256::ZERO, bytecode_hash: None }),
921 )]);
922 let block3 = DeferredTrieData::pending(
923 Arc::new(block3_hashed),
924 Arc::new(TrieUpdates::default()),
925 old_anchor,
926 vec![block1.clone(), block2_ready.clone()],
927 );
928 let block3_ready = DeferredTrieData::ready(block3.wait_cloned());
929
930 let block3_overlay = block3_ready.wait_cloned().anchored_trie_input.unwrap();
932 assert_eq!(block3_overlay.anchor_hash, old_anchor);
933 assert_eq!(block3_overlay.trie_input.state.accounts.len(), 3);
934
935 let block4_hashed = HashedPostState::default().with_accounts([(
941 key4,
942 Some(Account { nonce: 4, balance: U256::ZERO, bytecode_hash: None }),
943 )]);
944 let block4 = DeferredTrieData::pending(
945 Arc::new(block4_hashed),
946 Arc::new(TrieUpdates::default()),
947 new_anchor, vec![block1, block2_ready, block3_ready],
949 );
950
951 let result = block4.wait_cloned();
952
953 assert_eq!(result.anchor_hash(), Some(new_anchor));
956
957 let overlay = result.anchored_trie_input.as_ref().unwrap();
959 assert_eq!(overlay.trie_input.state.accounts.len(), 4);
960
961 let accounts = &overlay.trie_input.state.accounts;
963 assert!(accounts.iter().any(|(k, a)| *k == key1 && a.unwrap().nonce == 1));
964 assert!(accounts.iter().any(|(k, a)| *k == key2 && a.unwrap().nonce == 2));
965 assert!(accounts.iter().any(|(k, a)| *k == key3 && a.unwrap().nonce == 3));
966 assert!(accounts.iter().any(|(k, a)| *k == key4 && a.unwrap().nonce == 4));
967 }
968}