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 fn merge_ancestors_into_overlay(
280 ancestors: &[Self],
281 sorted_hashed_state: &HashedPostStateSorted,
282 sorted_trie_updates: &TrieUpdatesSorted,
283 ) -> TrieInputSorted {
284 let _span = debug_span!(target: "engine::tree::deferred_trie", "merge_ancestors", num_ancestors = ancestors.len()).entered();
285 let mut overlay = TrieInputSorted::default();
286
287 let state_mut = Arc::make_mut(&mut overlay.state);
288 let nodes_mut = Arc::make_mut(&mut overlay.nodes);
289
290 for ancestor in ancestors {
291 let ancestor_data = ancestor.wait_cloned();
292 state_mut.extend_ref_and_sort(ancestor_data.hashed_state.as_ref());
293 nodes_mut.extend_ref_and_sort(ancestor_data.trie_updates.as_ref());
294 }
295
296 #[cfg(feature = "rayon")]
298 rayon::join(
299 || state_mut.extend_ref_and_sort(sorted_hashed_state),
300 || nodes_mut.extend_ref_and_sort(sorted_trie_updates),
301 );
302
303 #[cfg(not(feature = "rayon"))]
304 {
305 state_mut.extend_ref_and_sort(sorted_hashed_state);
306 nodes_mut.extend_ref_and_sort(sorted_trie_updates);
307 }
308
309 overlay
310 }
311
312 #[instrument(level = "debug", target = "engine::tree::deferred_trie", skip_all)]
324 pub fn wait_cloned(&self) -> ComputedTrieData {
325 let mut state = self.state.lock();
326 match &mut *state {
327 DeferredState::Ready(bundle) => {
329 DEFERRED_TRIE_METRICS.deferred_trie_async_ready.increment(1);
330 bundle.clone()
331 }
332 DeferredState::Pending(maybe_inputs) => {
335 DEFERRED_TRIE_METRICS.deferred_trie_sync_fallback.increment(1);
336
337 let inputs = maybe_inputs.take().expect("inputs must be present in Pending state");
338
339 let computed = Self::sort_and_build_trie_input(
340 inputs.hashed_state,
341 inputs.trie_updates,
342 inputs.anchor_hash,
343 &inputs.ancestors,
344 );
345 *state = DeferredState::Ready(computed.clone());
346
347 drop(state);
350
351 computed
352 }
353 }
354 }
355}
356
357impl ComputedTrieData {
358 pub const fn with_trie_input(
360 hashed_state: Arc<HashedPostStateSorted>,
361 trie_updates: Arc<TrieUpdatesSorted>,
362 anchor_hash: B256,
363 trie_input: Arc<TrieInputSorted>,
364 ) -> Self {
365 Self {
366 hashed_state,
367 trie_updates,
368 anchored_trie_input: Some(AnchoredTrieInput { anchor_hash, trie_input }),
369 }
370 }
371
372 pub const fn without_trie_input(
381 hashed_state: Arc<HashedPostStateSorted>,
382 trie_updates: Arc<TrieUpdatesSorted>,
383 ) -> Self {
384 Self { hashed_state, trie_updates, anchored_trie_input: None }
385 }
386
387 pub fn anchor_hash(&self) -> Option<B256> {
389 self.anchored_trie_input.as_ref().map(|anchored| anchored.anchor_hash)
390 }
391
392 pub fn trie_input(&self) -> Option<&Arc<TrieInputSorted>> {
394 self.anchored_trie_input.as_ref().map(|anchored| &anchored.trie_input)
395 }
396}
397
398#[cfg(test)]
399mod tests {
400 use super::*;
401 use alloy_primitives::{map::B256Map, U256};
402 use reth_primitives_traits::Account;
403 use reth_trie::updates::TrieUpdates;
404 use std::{
405 sync::Arc,
406 thread,
407 time::{Duration, Instant},
408 };
409
410 fn empty_bundle() -> ComputedTrieData {
411 ComputedTrieData {
412 hashed_state: Arc::default(),
413 trie_updates: Arc::default(),
414 anchored_trie_input: None,
415 }
416 }
417
418 fn empty_pending() -> DeferredTrieData {
419 empty_pending_with_anchor(B256::ZERO)
420 }
421
422 fn empty_pending_with_anchor(anchor: B256) -> DeferredTrieData {
423 DeferredTrieData::pending(
424 Arc::new(HashedPostState::default()),
425 Arc::new(TrieUpdates::default()),
426 anchor,
427 Vec::new(),
428 )
429 }
430
431 #[test]
433 fn ready_returns_immediately() {
434 let bundle = empty_bundle();
435 let deferred = DeferredTrieData::ready(bundle.clone());
436
437 let start = Instant::now();
438 let result = deferred.wait_cloned();
439 let elapsed = start.elapsed();
440
441 assert_eq!(result.hashed_state, bundle.hashed_state);
442 assert_eq!(result.trie_updates, bundle.trie_updates);
443 assert_eq!(result.anchor_hash(), bundle.anchor_hash());
444 assert!(elapsed < Duration::from_millis(20));
445 }
446
447 #[test]
449 fn pending_computes_fallback() {
450 let deferred = empty_pending();
451
452 let start = Instant::now();
454 let result = deferred.wait_cloned();
455 let elapsed = start.elapsed();
456
457 assert!(elapsed < Duration::from_millis(100));
459 assert!(result.hashed_state.is_empty());
460 }
461
462 #[test]
464 fn fallback_result_is_cached() {
465 let deferred = empty_pending();
466
467 let first = deferred.wait_cloned();
469 let second = deferred.wait_cloned();
471
472 assert!(Arc::ptr_eq(&first.hashed_state, &second.hashed_state));
473 assert!(Arc::ptr_eq(&first.trie_updates, &second.trie_updates));
474 assert_eq!(first.anchor_hash(), second.anchor_hash());
475 }
476
477 #[test]
480 fn concurrent_wait_cloned_computes_once() {
481 let deferred = empty_pending();
482
483 let handles: Vec<_> = (0..10)
485 .map(|_| {
486 let d = deferred.clone();
487 thread::spawn(move || d.wait_cloned())
488 })
489 .collect();
490
491 let results: Vec<_> = handles.into_iter().map(|h| h.join().unwrap()).collect();
493
494 let first = &results[0];
496 for result in &results[1..] {
497 assert!(Arc::ptr_eq(&first.hashed_state, &result.hashed_state));
498 assert!(Arc::ptr_eq(&first.trie_updates, &result.trie_updates));
499 }
500 }
501
502 #[test]
505 fn ancestors_are_merged() {
506 let ancestor_bundle = ComputedTrieData {
508 hashed_state: Arc::default(),
509 trie_updates: Arc::default(),
510 anchored_trie_input: Some(AnchoredTrieInput {
511 anchor_hash: B256::with_last_byte(1),
512 trie_input: Arc::new(TrieInputSorted::default()),
513 }),
514 };
515 let ancestor = DeferredTrieData::ready(ancestor_bundle);
516
517 let deferred = DeferredTrieData::pending(
519 Arc::new(HashedPostState::default()),
520 Arc::new(TrieUpdates::default()),
521 B256::with_last_byte(2),
522 vec![ancestor],
523 );
524
525 let result = deferred.wait_cloned();
526 assert_eq!(result.anchor_hash(), Some(B256::with_last_byte(2)));
528 }
529
530 #[test]
533 fn ancestors_merge_in_chronological_order() {
534 let key = B256::with_last_byte(1);
535 let oldest_state = HashedPostStateSorted::new(
537 vec![(key, Some(Account { nonce: 1, balance: U256::ZERO, bytecode_hash: None }))],
538 B256Map::default(),
539 );
540 let newest_state = HashedPostStateSorted::new(
542 vec![(key, Some(Account { nonce: 2, balance: U256::ZERO, bytecode_hash: None }))],
543 B256Map::default(),
544 );
545
546 let oldest = ComputedTrieData {
547 hashed_state: Arc::new(oldest_state),
548 trie_updates: Arc::default(),
549 anchored_trie_input: None,
550 };
551 let newest = ComputedTrieData {
552 hashed_state: Arc::new(newest_state),
553 trie_updates: Arc::default(),
554 anchored_trie_input: None,
555 };
556
557 let deferred = DeferredTrieData::pending(
559 Arc::new(HashedPostState::default()),
560 Arc::new(TrieUpdates::default()),
561 B256::ZERO,
562 vec![DeferredTrieData::ready(oldest), DeferredTrieData::ready(newest)],
563 );
564
565 let result = deferred.wait_cloned();
566 let overlay_state = &result.anchored_trie_input.as_ref().unwrap().trie_input.state.accounts;
567 assert_eq!(overlay_state.len(), 1);
568 let (_, account) = &overlay_state[0];
569 assert_eq!(account.unwrap().nonce, 2);
570 }
571
572 fn ready_block_with_state(
574 anchor_hash: B256,
575 accounts: Vec<(B256, Option<Account>)>,
576 ) -> DeferredTrieData {
577 let hashed_state = Arc::new(HashedPostStateSorted::new(accounts, B256Map::default()));
578 let trie_updates = Arc::default();
579 let mut overlay = TrieInputSorted::default();
580 Arc::make_mut(&mut overlay.state).extend_ref_and_sort(hashed_state.as_ref());
581
582 DeferredTrieData::ready(ComputedTrieData {
583 hashed_state,
584 trie_updates,
585 anchored_trie_input: Some(AnchoredTrieInput {
586 anchor_hash,
587 trie_input: Arc::new(overlay),
588 }),
589 })
590 }
591
592 #[test]
594 fn first_block_after_anchor_creates_empty_base() {
595 let anchor = B256::with_last_byte(1);
596 let key = B256::with_last_byte(42);
597 let account = Account { nonce: 1, balance: U256::ZERO, bytecode_hash: None };
598
599 let first_block = DeferredTrieData::pending(
601 Arc::new(HashedPostState::default().with_accounts([(key, Some(account))])),
602 Arc::new(TrieUpdates::default()),
603 anchor,
604 vec![], );
606
607 let result = first_block.wait_cloned();
608
609 let overlay = result.anchored_trie_input.as_ref().unwrap();
611 assert_eq!(overlay.anchor_hash, anchor);
612 assert_eq!(overlay.trie_input.state.accounts.len(), 1);
613 let (found_key, found_account) = &overlay.trie_input.state.accounts[0];
614 assert_eq!(*found_key, key);
615 assert_eq!(found_account.unwrap().nonce, 1);
616 }
617
618 #[test]
620 fn reuses_parent_overlay() {
621 let anchor = B256::with_last_byte(1);
622 let key = B256::with_last_byte(42);
623 let account = Account { nonce: 100, balance: U256::ZERO, bytecode_hash: None };
624
625 let parent = ready_block_with_state(anchor, vec![(key, Some(account))]);
627
628 let child = DeferredTrieData::pending(
630 Arc::new(HashedPostState::default()),
631 Arc::new(TrieUpdates::default()),
632 anchor,
633 vec![parent],
634 );
635
636 let result = child.wait_cloned();
637
638 let overlay = result.anchored_trie_input.as_ref().unwrap();
640 assert_eq!(overlay.anchor_hash, anchor);
641 assert_eq!(overlay.trie_input.state.accounts.len(), 1);
642 let (found_key, found_account) = &overlay.trie_input.state.accounts[0];
643 assert_eq!(*found_key, key);
644 assert_eq!(found_account.unwrap().nonce, 100);
645 }
646
647 #[test]
651 fn rebuilds_overlay_when_anchor_changes() {
652 let old_anchor = B256::with_last_byte(1);
653 let new_anchor = B256::with_last_byte(2);
654 let key = B256::with_last_byte(42);
655 let account = Account { nonce: 50, balance: U256::ZERO, bytecode_hash: None };
656
657 let parent = ready_block_with_state(old_anchor, vec![(key, Some(account))]);
659
660 let child = DeferredTrieData::pending(
663 Arc::new(HashedPostState::default()),
664 Arc::new(TrieUpdates::default()),
665 new_anchor,
666 vec![parent],
667 );
668
669 let result = child.wait_cloned();
670
671 let overlay = result.anchored_trie_input.as_ref().unwrap();
673 assert_eq!(overlay.anchor_hash, new_anchor);
674
675 assert_eq!(overlay.trie_input.state.accounts.len(), 1);
681 let (found_key, found_account) = &overlay.trie_input.state.accounts[0];
682 assert_eq!(*found_key, key);
683 assert_eq!(found_account.unwrap().nonce, 50);
684 }
685
686 #[test]
688 fn rebuilds_when_parent_has_no_anchored_input() {
689 let anchor = B256::with_last_byte(1);
690 let key = B256::with_last_byte(42);
691 let account = Account { nonce: 25, balance: U256::ZERO, bytecode_hash: None };
692
693 let parent_state =
695 HashedPostStateSorted::new(vec![(key, Some(account))], B256Map::default());
696 let parent = DeferredTrieData::ready(ComputedTrieData {
697 hashed_state: Arc::new(parent_state),
698 trie_updates: Arc::default(),
699 anchored_trie_input: None, });
701
702 let child = DeferredTrieData::pending(
704 Arc::new(HashedPostState::default()),
705 Arc::new(TrieUpdates::default()),
706 anchor,
707 vec![parent],
708 );
709
710 let result = child.wait_cloned();
711
712 let overlay = result.anchored_trie_input.as_ref().unwrap();
714 assert_eq!(overlay.anchor_hash, anchor);
715 assert_eq!(overlay.trie_input.state.accounts.len(), 1);
716 }
717
718 #[test]
720 fn chain_of_blocks_builds_cumulative_overlay() {
721 let anchor = B256::with_last_byte(1);
722 let key1 = B256::with_last_byte(1);
723 let key2 = B256::with_last_byte(2);
724 let key3 = B256::with_last_byte(3);
725
726 let block1 = ready_block_with_state(
728 anchor,
729 vec![(key1, Some(Account { nonce: 1, balance: U256::ZERO, bytecode_hash: None }))],
730 );
731
732 let block2_hashed = HashedPostState::default().with_accounts([(
734 key2,
735 Some(Account { nonce: 2, balance: U256::ZERO, bytecode_hash: None }),
736 )]);
737 let block2 = DeferredTrieData::pending(
738 Arc::new(block2_hashed),
739 Arc::new(TrieUpdates::default()),
740 anchor,
741 vec![block1.clone()],
742 );
743 let block2_computed = block2.wait_cloned();
745 let block2_ready = DeferredTrieData::ready(block2_computed);
746
747 let block3_hashed = HashedPostState::default().with_accounts([(
749 key3,
750 Some(Account { nonce: 3, balance: U256::ZERO, bytecode_hash: None }),
751 )]);
752 let block3 = DeferredTrieData::pending(
753 Arc::new(block3_hashed),
754 Arc::new(TrieUpdates::default()),
755 anchor,
756 vec![block1, block2_ready],
757 );
758
759 let result = block3.wait_cloned();
760
761 let overlay = result.anchored_trie_input.as_ref().unwrap();
763 assert_eq!(overlay.trie_input.state.accounts.len(), 3);
764
765 let accounts = &overlay.trie_input.state.accounts;
767 assert!(accounts.iter().any(|(k, a)| *k == key1 && a.unwrap().nonce == 1));
768 assert!(accounts.iter().any(|(k, a)| *k == key2 && a.unwrap().nonce == 2));
769 assert!(accounts.iter().any(|(k, a)| *k == key3 && a.unwrap().nonce == 3));
770 }
771
772 #[test]
774 fn child_state_overwrites_parent() {
775 let anchor = B256::with_last_byte(1);
776 let key = B256::with_last_byte(42);
777
778 let parent = ready_block_with_state(
780 anchor,
781 vec![(key, Some(Account { nonce: 10, balance: U256::ZERO, bytecode_hash: None }))],
782 );
783
784 let child_hashed = HashedPostState::default().with_accounts([(
786 key,
787 Some(Account { nonce: 99, balance: U256::ZERO, bytecode_hash: None }),
788 )]);
789 let child = DeferredTrieData::pending(
790 Arc::new(child_hashed),
791 Arc::new(TrieUpdates::default()),
792 anchor,
793 vec![parent],
794 );
795
796 let result = child.wait_cloned();
797
798 let overlay = result.anchored_trie_input.as_ref().unwrap();
800 let accounts = &overlay.trie_input.state.accounts;
802 let last_account = accounts.iter().rfind(|(k, _)| *k == key).unwrap();
803 assert_eq!(last_account.1.unwrap().nonce, 99);
804 }
805
806 #[test]
809 fn long_chain_builds_in_linear_time() {
810 let anchor = B256::with_last_byte(1);
811 let num_blocks = 50; let mut ancestors: Vec<DeferredTrieData> = Vec::new();
814
815 let start = Instant::now();
816
817 for i in 0..num_blocks {
818 let key = B256::with_last_byte(i as u8);
819 let account = Account { nonce: i as u64, balance: U256::ZERO, bytecode_hash: None };
820 let hashed = HashedPostState::default().with_accounts([(key, Some(account))]);
821
822 let block = DeferredTrieData::pending(
823 Arc::new(hashed),
824 Arc::new(TrieUpdates::default()),
825 anchor,
826 ancestors.clone(),
827 );
828
829 let computed = block.wait_cloned();
831 ancestors.push(DeferredTrieData::ready(computed));
832 }
833
834 let elapsed = start.elapsed();
835
836 assert!(
839 elapsed < Duration::from_secs(2),
840 "Chain of {num_blocks} blocks took {:?}, possible O(N²) regression",
841 elapsed
842 );
843
844 let final_result = ancestors.last().unwrap().wait_cloned();
846 let overlay = final_result.anchored_trie_input.as_ref().unwrap();
847 assert_eq!(overlay.trie_input.state.accounts.len(), num_blocks);
848 }
849
850 #[test]
856 fn multi_ancestor_overlay_rebuilt_after_anchor_change() {
857 let old_anchor = B256::with_last_byte(1);
858 let new_anchor = B256::with_last_byte(2);
859 let key1 = B256::with_last_byte(1);
860 let key2 = B256::with_last_byte(2);
861 let key3 = B256::with_last_byte(3);
862 let key4 = B256::with_last_byte(4);
863
864 let block1 = ready_block_with_state(
866 old_anchor,
867 vec![(key1, Some(Account { nonce: 1, balance: U256::ZERO, bytecode_hash: None }))],
868 );
869
870 let block2_hashed = HashedPostState::default().with_accounts([(
871 key2,
872 Some(Account { nonce: 2, balance: U256::ZERO, bytecode_hash: None }),
873 )]);
874 let block2 = DeferredTrieData::pending(
875 Arc::new(block2_hashed),
876 Arc::new(TrieUpdates::default()),
877 old_anchor,
878 vec![block1.clone()],
879 );
880 let block2_ready = DeferredTrieData::ready(block2.wait_cloned());
881
882 let block3_hashed = HashedPostState::default().with_accounts([(
883 key3,
884 Some(Account { nonce: 3, balance: U256::ZERO, bytecode_hash: None }),
885 )]);
886 let block3 = DeferredTrieData::pending(
887 Arc::new(block3_hashed),
888 Arc::new(TrieUpdates::default()),
889 old_anchor,
890 vec![block1.clone(), block2_ready.clone()],
891 );
892 let block3_ready = DeferredTrieData::ready(block3.wait_cloned());
893
894 let block3_overlay = block3_ready.wait_cloned().anchored_trie_input.unwrap();
896 assert_eq!(block3_overlay.anchor_hash, old_anchor);
897 assert_eq!(block3_overlay.trie_input.state.accounts.len(), 3);
898
899 let block4_hashed = HashedPostState::default().with_accounts([(
905 key4,
906 Some(Account { nonce: 4, balance: U256::ZERO, bytecode_hash: None }),
907 )]);
908 let block4 = DeferredTrieData::pending(
909 Arc::new(block4_hashed),
910 Arc::new(TrieUpdates::default()),
911 new_anchor, vec![block1, block2_ready, block3_ready],
913 );
914
915 let result = block4.wait_cloned();
916
917 assert_eq!(result.anchor_hash(), Some(new_anchor));
920
921 let overlay = result.anchored_trie_input.as_ref().unwrap();
923 assert_eq!(overlay.trie_input.state.accounts.len(), 4);
924
925 let accounts = &overlay.trie_input.state.accounts;
927 assert!(accounts.iter().any(|(k, a)| *k == key1 && a.unwrap().nonce == 1));
928 assert!(accounts.iter().any(|(k, a)| *k == key2 && a.unwrap().nonce == 2));
929 assert!(accounts.iter().any(|(k, a)| *k == key3 && a.unwrap().nonce == 3));
930 assert!(accounts.iter().any(|(k, a)| *k == key4 && a.unwrap().nonce == 4));
931 }
932}