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::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 #[cfg(feature = "rayon")]
167 let (sorted_hashed_state, sorted_trie_updates) = rayon::join(
168 || match Arc::try_unwrap(hashed_state) {
169 Ok(state) => state.into_sorted(),
170 Err(arc) => arc.clone_into_sorted(),
171 },
172 || match Arc::try_unwrap(trie_updates) {
173 Ok(updates) => updates.into_sorted(),
174 Err(arc) => arc.clone_into_sorted(),
175 },
176 );
177
178 #[cfg(not(feature = "rayon"))]
179 let (sorted_hashed_state, sorted_trie_updates) = (
180 match Arc::try_unwrap(hashed_state) {
181 Ok(state) => state.into_sorted(),
182 Err(arc) => arc.clone_into_sorted(),
183 },
184 match Arc::try_unwrap(trie_updates) {
185 Ok(updates) => updates.into_sorted(),
186 Err(arc) => arc.clone_into_sorted(),
187 },
188 );
189
190 let overlay = if let Some(parent) = ancestors.last() {
195 let parent_data = parent.wait_cloned();
196
197 match &parent_data.anchored_trie_input {
198 Some(AnchoredTrieInput { anchor_hash: parent_anchor, trie_input })
200 if *parent_anchor == anchor_hash =>
201 {
202 let mut overlay = TrieInputSorted::new(
204 Arc::clone(&trie_input.nodes),
205 Arc::clone(&trie_input.state),
206 Default::default(), );
208 #[cfg(feature = "rayon")]
210 {
211 rayon::join(
212 || {
213 if !sorted_hashed_state.is_empty() {
214 Arc::make_mut(&mut overlay.state)
215 .extend_ref_and_sort(&sorted_hashed_state);
216 }
217 },
218 || {
219 if !sorted_trie_updates.is_empty() {
220 Arc::make_mut(&mut overlay.nodes)
221 .extend_ref_and_sort(&sorted_trie_updates);
222 }
223 },
224 );
225 }
226 #[cfg(not(feature = "rayon"))]
227 {
228 if !sorted_hashed_state.is_empty() {
229 Arc::make_mut(&mut overlay.state)
230 .extend_ref_and_sort(&sorted_hashed_state);
231 }
232 if !sorted_trie_updates.is_empty() {
233 Arc::make_mut(&mut overlay.nodes)
234 .extend_ref_and_sort(&sorted_trie_updates);
235 }
236 }
237 overlay
238 }
239 _ => Self::merge_ancestors_into_overlay(
242 ancestors,
243 &sorted_hashed_state,
244 &sorted_trie_updates,
245 ),
246 }
247 } else {
248 Self::merge_ancestors_into_overlay(&[], &sorted_hashed_state, &sorted_trie_updates)
251 };
252
253 ComputedTrieData::with_trie_input(
254 Arc::new(sorted_hashed_state),
255 Arc::new(sorted_trie_updates),
256 anchor_hash,
257 Arc::new(overlay),
258 )
259 }
260
261 fn merge_ancestors_into_overlay(
271 ancestors: &[Self],
272 sorted_hashed_state: &HashedPostStateSorted,
273 sorted_trie_updates: &TrieUpdatesSorted,
274 ) -> TrieInputSorted {
275 let mut overlay = TrieInputSorted::default();
276
277 let state_mut = Arc::make_mut(&mut overlay.state);
278 let nodes_mut = Arc::make_mut(&mut overlay.nodes);
279
280 for ancestor in ancestors {
281 let ancestor_data = ancestor.wait_cloned();
282 state_mut.extend_ref_and_sort(ancestor_data.hashed_state.as_ref());
283 nodes_mut.extend_ref_and_sort(ancestor_data.trie_updates.as_ref());
284 }
285
286 #[cfg(feature = "rayon")]
288 rayon::join(
289 || state_mut.extend_ref_and_sort(sorted_hashed_state),
290 || nodes_mut.extend_ref_and_sort(sorted_trie_updates),
291 );
292
293 #[cfg(not(feature = "rayon"))]
294 {
295 state_mut.extend_ref_and_sort(sorted_hashed_state);
296 nodes_mut.extend_ref_and_sort(sorted_trie_updates);
297 }
298
299 overlay
300 }
301
302 #[instrument(level = "debug", target = "engine::tree::deferred_trie", skip_all)]
314 pub fn wait_cloned(&self) -> ComputedTrieData {
315 let mut state = self.state.lock();
316 match &mut *state {
317 DeferredState::Ready(bundle) => {
319 DEFERRED_TRIE_METRICS.deferred_trie_async_ready.increment(1);
320 bundle.clone()
321 }
322 DeferredState::Pending(maybe_inputs) => {
325 DEFERRED_TRIE_METRICS.deferred_trie_sync_fallback.increment(1);
326
327 let inputs = maybe_inputs.take().expect("inputs must be present in Pending state");
328
329 let computed = Self::sort_and_build_trie_input(
330 inputs.hashed_state,
331 inputs.trie_updates,
332 inputs.anchor_hash,
333 &inputs.ancestors,
334 );
335 *state = DeferredState::Ready(computed.clone());
336
337 drop(state);
340
341 computed
342 }
343 }
344 }
345}
346
347impl ComputedTrieData {
348 pub const fn with_trie_input(
350 hashed_state: Arc<HashedPostStateSorted>,
351 trie_updates: Arc<TrieUpdatesSorted>,
352 anchor_hash: B256,
353 trie_input: Arc<TrieInputSorted>,
354 ) -> Self {
355 Self {
356 hashed_state,
357 trie_updates,
358 anchored_trie_input: Some(AnchoredTrieInput { anchor_hash, trie_input }),
359 }
360 }
361
362 pub const fn without_trie_input(
371 hashed_state: Arc<HashedPostStateSorted>,
372 trie_updates: Arc<TrieUpdatesSorted>,
373 ) -> Self {
374 Self { hashed_state, trie_updates, anchored_trie_input: None }
375 }
376
377 pub fn anchor_hash(&self) -> Option<B256> {
379 self.anchored_trie_input.as_ref().map(|anchored| anchored.anchor_hash)
380 }
381
382 pub fn trie_input(&self) -> Option<&Arc<TrieInputSorted>> {
384 self.anchored_trie_input.as_ref().map(|anchored| &anchored.trie_input)
385 }
386}
387
388#[cfg(test)]
389mod tests {
390 use super::*;
391 use alloy_primitives::{map::B256Map, U256};
392 use reth_primitives_traits::Account;
393 use reth_trie::updates::TrieUpdates;
394 use std::{
395 sync::Arc,
396 thread,
397 time::{Duration, Instant},
398 };
399
400 fn empty_bundle() -> ComputedTrieData {
401 ComputedTrieData {
402 hashed_state: Arc::default(),
403 trie_updates: Arc::default(),
404 anchored_trie_input: None,
405 }
406 }
407
408 fn empty_pending() -> DeferredTrieData {
409 empty_pending_with_anchor(B256::ZERO)
410 }
411
412 fn empty_pending_with_anchor(anchor: B256) -> DeferredTrieData {
413 DeferredTrieData::pending(
414 Arc::new(HashedPostState::default()),
415 Arc::new(TrieUpdates::default()),
416 anchor,
417 Vec::new(),
418 )
419 }
420
421 #[test]
423 fn ready_returns_immediately() {
424 let bundle = empty_bundle();
425 let deferred = DeferredTrieData::ready(bundle.clone());
426
427 let start = Instant::now();
428 let result = deferred.wait_cloned();
429 let elapsed = start.elapsed();
430
431 assert_eq!(result.hashed_state, bundle.hashed_state);
432 assert_eq!(result.trie_updates, bundle.trie_updates);
433 assert_eq!(result.anchor_hash(), bundle.anchor_hash());
434 assert!(elapsed < Duration::from_millis(20));
435 }
436
437 #[test]
439 fn pending_computes_fallback() {
440 let deferred = empty_pending();
441
442 let start = Instant::now();
444 let result = deferred.wait_cloned();
445 let elapsed = start.elapsed();
446
447 assert!(elapsed < Duration::from_millis(100));
449 assert!(result.hashed_state.is_empty());
450 }
451
452 #[test]
454 fn fallback_result_is_cached() {
455 let deferred = empty_pending();
456
457 let first = deferred.wait_cloned();
459 let second = deferred.wait_cloned();
461
462 assert!(Arc::ptr_eq(&first.hashed_state, &second.hashed_state));
463 assert!(Arc::ptr_eq(&first.trie_updates, &second.trie_updates));
464 assert_eq!(first.anchor_hash(), second.anchor_hash());
465 }
466
467 #[test]
470 fn concurrent_wait_cloned_computes_once() {
471 let deferred = empty_pending();
472
473 let handles: Vec<_> = (0..10)
475 .map(|_| {
476 let d = deferred.clone();
477 thread::spawn(move || d.wait_cloned())
478 })
479 .collect();
480
481 let results: Vec<_> = handles.into_iter().map(|h| h.join().unwrap()).collect();
483
484 let first = &results[0];
486 for result in &results[1..] {
487 assert!(Arc::ptr_eq(&first.hashed_state, &result.hashed_state));
488 assert!(Arc::ptr_eq(&first.trie_updates, &result.trie_updates));
489 }
490 }
491
492 #[test]
495 fn ancestors_are_merged() {
496 let ancestor_bundle = ComputedTrieData {
498 hashed_state: Arc::default(),
499 trie_updates: Arc::default(),
500 anchored_trie_input: Some(AnchoredTrieInput {
501 anchor_hash: B256::with_last_byte(1),
502 trie_input: Arc::new(TrieInputSorted::default()),
503 }),
504 };
505 let ancestor = DeferredTrieData::ready(ancestor_bundle);
506
507 let deferred = DeferredTrieData::pending(
509 Arc::new(HashedPostState::default()),
510 Arc::new(TrieUpdates::default()),
511 B256::with_last_byte(2),
512 vec![ancestor],
513 );
514
515 let result = deferred.wait_cloned();
516 assert_eq!(result.anchor_hash(), Some(B256::with_last_byte(2)));
518 }
519
520 #[test]
523 fn ancestors_merge_in_chronological_order() {
524 let key = B256::with_last_byte(1);
525 let oldest_state = HashedPostStateSorted::new(
527 vec![(key, Some(Account { nonce: 1, balance: U256::ZERO, bytecode_hash: None }))],
528 B256Map::default(),
529 );
530 let newest_state = HashedPostStateSorted::new(
532 vec![(key, Some(Account { nonce: 2, balance: U256::ZERO, bytecode_hash: None }))],
533 B256Map::default(),
534 );
535
536 let oldest = ComputedTrieData {
537 hashed_state: Arc::new(oldest_state),
538 trie_updates: Arc::default(),
539 anchored_trie_input: None,
540 };
541 let newest = ComputedTrieData {
542 hashed_state: Arc::new(newest_state),
543 trie_updates: Arc::default(),
544 anchored_trie_input: None,
545 };
546
547 let deferred = DeferredTrieData::pending(
549 Arc::new(HashedPostState::default()),
550 Arc::new(TrieUpdates::default()),
551 B256::ZERO,
552 vec![DeferredTrieData::ready(oldest), DeferredTrieData::ready(newest)],
553 );
554
555 let result = deferred.wait_cloned();
556 let overlay_state = &result.anchored_trie_input.as_ref().unwrap().trie_input.state.accounts;
557 assert_eq!(overlay_state.len(), 1);
558 let (_, account) = &overlay_state[0];
559 assert_eq!(account.unwrap().nonce, 2);
560 }
561
562 fn ready_block_with_state(
564 anchor_hash: B256,
565 accounts: Vec<(B256, Option<Account>)>,
566 ) -> DeferredTrieData {
567 let hashed_state = Arc::new(HashedPostStateSorted::new(accounts, B256Map::default()));
568 let trie_updates = Arc::default();
569 let mut overlay = TrieInputSorted::default();
570 Arc::make_mut(&mut overlay.state).extend_ref_and_sort(hashed_state.as_ref());
571
572 DeferredTrieData::ready(ComputedTrieData {
573 hashed_state,
574 trie_updates,
575 anchored_trie_input: Some(AnchoredTrieInput {
576 anchor_hash,
577 trie_input: Arc::new(overlay),
578 }),
579 })
580 }
581
582 #[test]
584 fn first_block_after_anchor_creates_empty_base() {
585 let anchor = B256::with_last_byte(1);
586 let key = B256::with_last_byte(42);
587 let account = Account { nonce: 1, balance: U256::ZERO, bytecode_hash: None };
588
589 let first_block = DeferredTrieData::pending(
591 Arc::new(HashedPostState::default().with_accounts([(key, Some(account))])),
592 Arc::new(TrieUpdates::default()),
593 anchor,
594 vec![], );
596
597 let result = first_block.wait_cloned();
598
599 let overlay = result.anchored_trie_input.as_ref().unwrap();
601 assert_eq!(overlay.anchor_hash, anchor);
602 assert_eq!(overlay.trie_input.state.accounts.len(), 1);
603 let (found_key, found_account) = &overlay.trie_input.state.accounts[0];
604 assert_eq!(*found_key, key);
605 assert_eq!(found_account.unwrap().nonce, 1);
606 }
607
608 #[test]
610 fn reuses_parent_overlay() {
611 let anchor = B256::with_last_byte(1);
612 let key = B256::with_last_byte(42);
613 let account = Account { nonce: 100, balance: U256::ZERO, bytecode_hash: None };
614
615 let parent = ready_block_with_state(anchor, vec![(key, Some(account))]);
617
618 let child = DeferredTrieData::pending(
620 Arc::new(HashedPostState::default()),
621 Arc::new(TrieUpdates::default()),
622 anchor,
623 vec![parent],
624 );
625
626 let result = child.wait_cloned();
627
628 let overlay = result.anchored_trie_input.as_ref().unwrap();
630 assert_eq!(overlay.anchor_hash, anchor);
631 assert_eq!(overlay.trie_input.state.accounts.len(), 1);
632 let (found_key, found_account) = &overlay.trie_input.state.accounts[0];
633 assert_eq!(*found_key, key);
634 assert_eq!(found_account.unwrap().nonce, 100);
635 }
636
637 #[test]
641 fn rebuilds_overlay_when_anchor_changes() {
642 let old_anchor = B256::with_last_byte(1);
643 let new_anchor = B256::with_last_byte(2);
644 let key = B256::with_last_byte(42);
645 let account = Account { nonce: 50, balance: U256::ZERO, bytecode_hash: None };
646
647 let parent = ready_block_with_state(old_anchor, vec![(key, Some(account))]);
649
650 let child = DeferredTrieData::pending(
653 Arc::new(HashedPostState::default()),
654 Arc::new(TrieUpdates::default()),
655 new_anchor,
656 vec![parent],
657 );
658
659 let result = child.wait_cloned();
660
661 let overlay = result.anchored_trie_input.as_ref().unwrap();
663 assert_eq!(overlay.anchor_hash, new_anchor);
664
665 assert_eq!(overlay.trie_input.state.accounts.len(), 1);
671 let (found_key, found_account) = &overlay.trie_input.state.accounts[0];
672 assert_eq!(*found_key, key);
673 assert_eq!(found_account.unwrap().nonce, 50);
674 }
675
676 #[test]
678 fn rebuilds_when_parent_has_no_anchored_input() {
679 let anchor = B256::with_last_byte(1);
680 let key = B256::with_last_byte(42);
681 let account = Account { nonce: 25, balance: U256::ZERO, bytecode_hash: None };
682
683 let parent_state =
685 HashedPostStateSorted::new(vec![(key, Some(account))], B256Map::default());
686 let parent = DeferredTrieData::ready(ComputedTrieData {
687 hashed_state: Arc::new(parent_state),
688 trie_updates: Arc::default(),
689 anchored_trie_input: None, });
691
692 let child = DeferredTrieData::pending(
694 Arc::new(HashedPostState::default()),
695 Arc::new(TrieUpdates::default()),
696 anchor,
697 vec![parent],
698 );
699
700 let result = child.wait_cloned();
701
702 let overlay = result.anchored_trie_input.as_ref().unwrap();
704 assert_eq!(overlay.anchor_hash, anchor);
705 assert_eq!(overlay.trie_input.state.accounts.len(), 1);
706 }
707
708 #[test]
710 fn chain_of_blocks_builds_cumulative_overlay() {
711 let anchor = B256::with_last_byte(1);
712 let key1 = B256::with_last_byte(1);
713 let key2 = B256::with_last_byte(2);
714 let key3 = B256::with_last_byte(3);
715
716 let block1 = ready_block_with_state(
718 anchor,
719 vec![(key1, Some(Account { nonce: 1, balance: U256::ZERO, bytecode_hash: None }))],
720 );
721
722 let block2_hashed = HashedPostState::default().with_accounts([(
724 key2,
725 Some(Account { nonce: 2, balance: U256::ZERO, bytecode_hash: None }),
726 )]);
727 let block2 = DeferredTrieData::pending(
728 Arc::new(block2_hashed),
729 Arc::new(TrieUpdates::default()),
730 anchor,
731 vec![block1.clone()],
732 );
733 let block2_computed = block2.wait_cloned();
735 let block2_ready = DeferredTrieData::ready(block2_computed);
736
737 let block3_hashed = HashedPostState::default().with_accounts([(
739 key3,
740 Some(Account { nonce: 3, balance: U256::ZERO, bytecode_hash: None }),
741 )]);
742 let block3 = DeferredTrieData::pending(
743 Arc::new(block3_hashed),
744 Arc::new(TrieUpdates::default()),
745 anchor,
746 vec![block1, block2_ready],
747 );
748
749 let result = block3.wait_cloned();
750
751 let overlay = result.anchored_trie_input.as_ref().unwrap();
753 assert_eq!(overlay.trie_input.state.accounts.len(), 3);
754
755 let accounts = &overlay.trie_input.state.accounts;
757 assert!(accounts.iter().any(|(k, a)| *k == key1 && a.unwrap().nonce == 1));
758 assert!(accounts.iter().any(|(k, a)| *k == key2 && a.unwrap().nonce == 2));
759 assert!(accounts.iter().any(|(k, a)| *k == key3 && a.unwrap().nonce == 3));
760 }
761
762 #[test]
764 fn child_state_overwrites_parent() {
765 let anchor = B256::with_last_byte(1);
766 let key = B256::with_last_byte(42);
767
768 let parent = ready_block_with_state(
770 anchor,
771 vec![(key, Some(Account { nonce: 10, balance: U256::ZERO, bytecode_hash: None }))],
772 );
773
774 let child_hashed = HashedPostState::default().with_accounts([(
776 key,
777 Some(Account { nonce: 99, balance: U256::ZERO, bytecode_hash: None }),
778 )]);
779 let child = DeferredTrieData::pending(
780 Arc::new(child_hashed),
781 Arc::new(TrieUpdates::default()),
782 anchor,
783 vec![parent],
784 );
785
786 let result = child.wait_cloned();
787
788 let overlay = result.anchored_trie_input.as_ref().unwrap();
790 let accounts = &overlay.trie_input.state.accounts;
792 let last_account = accounts.iter().rfind(|(k, _)| *k == key).unwrap();
793 assert_eq!(last_account.1.unwrap().nonce, 99);
794 }
795
796 #[test]
799 fn long_chain_builds_in_linear_time() {
800 let anchor = B256::with_last_byte(1);
801 let num_blocks = 50; let mut ancestors: Vec<DeferredTrieData> = Vec::new();
804
805 let start = Instant::now();
806
807 for i in 0..num_blocks {
808 let key = B256::with_last_byte(i as u8);
809 let account = Account { nonce: i as u64, balance: U256::ZERO, bytecode_hash: None };
810 let hashed = HashedPostState::default().with_accounts([(key, Some(account))]);
811
812 let block = DeferredTrieData::pending(
813 Arc::new(hashed),
814 Arc::new(TrieUpdates::default()),
815 anchor,
816 ancestors.clone(),
817 );
818
819 let computed = block.wait_cloned();
821 ancestors.push(DeferredTrieData::ready(computed));
822 }
823
824 let elapsed = start.elapsed();
825
826 assert!(
829 elapsed < Duration::from_secs(2),
830 "Chain of {num_blocks} blocks took {:?}, possible O(N²) regression",
831 elapsed
832 );
833
834 let final_result = ancestors.last().unwrap().wait_cloned();
836 let overlay = final_result.anchored_trie_input.as_ref().unwrap();
837 assert_eq!(overlay.trie_input.state.accounts.len(), num_blocks);
838 }
839
840 #[test]
846 fn multi_ancestor_overlay_rebuilt_after_anchor_change() {
847 let old_anchor = B256::with_last_byte(1);
848 let new_anchor = B256::with_last_byte(2);
849 let key1 = B256::with_last_byte(1);
850 let key2 = B256::with_last_byte(2);
851 let key3 = B256::with_last_byte(3);
852 let key4 = B256::with_last_byte(4);
853
854 let block1 = ready_block_with_state(
856 old_anchor,
857 vec![(key1, Some(Account { nonce: 1, balance: U256::ZERO, bytecode_hash: None }))],
858 );
859
860 let block2_hashed = HashedPostState::default().with_accounts([(
861 key2,
862 Some(Account { nonce: 2, balance: U256::ZERO, bytecode_hash: None }),
863 )]);
864 let block2 = DeferredTrieData::pending(
865 Arc::new(block2_hashed),
866 Arc::new(TrieUpdates::default()),
867 old_anchor,
868 vec![block1.clone()],
869 );
870 let block2_ready = DeferredTrieData::ready(block2.wait_cloned());
871
872 let block3_hashed = HashedPostState::default().with_accounts([(
873 key3,
874 Some(Account { nonce: 3, balance: U256::ZERO, bytecode_hash: None }),
875 )]);
876 let block3 = DeferredTrieData::pending(
877 Arc::new(block3_hashed),
878 Arc::new(TrieUpdates::default()),
879 old_anchor,
880 vec![block1.clone(), block2_ready.clone()],
881 );
882 let block3_ready = DeferredTrieData::ready(block3.wait_cloned());
883
884 let block3_overlay = block3_ready.wait_cloned().anchored_trie_input.unwrap();
886 assert_eq!(block3_overlay.anchor_hash, old_anchor);
887 assert_eq!(block3_overlay.trie_input.state.accounts.len(), 3);
888
889 let block4_hashed = HashedPostState::default().with_accounts([(
895 key4,
896 Some(Account { nonce: 4, balance: U256::ZERO, bytecode_hash: None }),
897 )]);
898 let block4 = DeferredTrieData::pending(
899 Arc::new(block4_hashed),
900 Arc::new(TrieUpdates::default()),
901 new_anchor, vec![block1, block2_ready, block3_ready],
903 );
904
905 let result = block4.wait_cloned();
906
907 assert_eq!(result.anchor_hash(), Some(new_anchor));
910
911 let overlay = result.anchored_trie_input.as_ref().unwrap();
913 assert_eq!(overlay.trie_input.state.accounts.len(), 4);
914
915 let accounts = &overlay.trie_input.state.accounts;
917 assert!(accounts.iter().any(|(k, a)| *k == key1 && a.unwrap().nonce == 1));
918 assert!(accounts.iter().any(|(k, a)| *k == key2 && a.unwrap().nonce == 2));
919 assert!(accounts.iter().any(|(k, a)| *k == key3 && a.unwrap().nonce == 3));
920 assert!(accounts.iter().any(|(k, a)| *k == key4 && a.unwrap().nonce == 4));
921 }
922}