1use crate::{
4 CanonStateNotification, CanonStateNotificationSender, CanonStateNotifications,
5 ChainInfoTracker, ComputedTrieData, DeferredTrieData, MemoryOverlayStateProvider,
6};
7use alloy_consensus::{transaction::TransactionMeta, BlockHeader};
8use alloy_eips::{BlockHashOrNumber, BlockNumHash};
9use alloy_primitives::{map::HashMap, BlockNumber, TxHash, B256};
10use parking_lot::RwLock;
11use reth_chainspec::ChainInfo;
12use reth_ethereum_primitives::EthPrimitives;
13use reth_execution_types::{Chain, ExecutionOutcome};
14use reth_metrics::{metrics::Gauge, Metrics};
15use reth_primitives_traits::{
16 BlockBody as _, IndexedTx, NodePrimitives, RecoveredBlock, SealedBlock, SealedHeader,
17 SignedTransaction,
18};
19use reth_storage_api::StateProviderBox;
20use reth_trie::{updates::TrieUpdatesSorted, HashedPostStateSorted, TrieInputSorted};
21use std::{collections::BTreeMap, ops::Deref, sync::Arc, time::Instant};
22use tokio::sync::{broadcast, watch};
23
24const CANON_STATE_NOTIFICATION_CHANNEL_SIZE: usize = 256;
26
27#[derive(Metrics)]
29#[metrics(scope = "blockchain_tree.in_mem_state")]
30pub(crate) struct InMemoryStateMetrics {
31 pub(crate) earliest_block: Gauge,
33 pub(crate) latest_block: Gauge,
35 pub(crate) num_blocks: Gauge,
37}
38
39#[derive(Debug, Default)]
55pub(crate) struct InMemoryState<N: NodePrimitives = EthPrimitives> {
56 blocks: RwLock<HashMap<B256, Arc<BlockState<N>>>>,
58 numbers: RwLock<BTreeMap<u64, B256>>,
60 pending: watch::Sender<Option<BlockState<N>>>,
62 metrics: InMemoryStateMetrics,
64}
65
66impl<N: NodePrimitives> InMemoryState<N> {
67 pub(crate) fn new(
68 blocks: HashMap<B256, Arc<BlockState<N>>>,
69 numbers: BTreeMap<u64, B256>,
70 pending: Option<BlockState<N>>,
71 ) -> Self {
72 let (pending, _) = watch::channel(pending);
73 let this = Self {
74 blocks: RwLock::new(blocks),
75 numbers: RwLock::new(numbers),
76 pending,
77 metrics: Default::default(),
78 };
79 this.update_metrics();
80 this
81 }
82
83 pub(crate) fn update_metrics(&self) {
89 let numbers = self.numbers.read();
90 if let Some((earliest_block_number, _)) = numbers.first_key_value() {
91 self.metrics.earliest_block.set(*earliest_block_number as f64);
92 }
93 if let Some((latest_block_number, _)) = numbers.last_key_value() {
94 self.metrics.latest_block.set(*latest_block_number as f64);
95 }
96 self.metrics.num_blocks.set(numbers.len() as f64);
97 }
98
99 pub(crate) fn state_by_hash(&self, hash: B256) -> Option<Arc<BlockState<N>>> {
101 self.blocks.read().get(&hash).cloned()
102 }
103
104 pub(crate) fn state_by_number(&self, number: u64) -> Option<Arc<BlockState<N>>> {
106 let hash = self.hash_by_number(number)?;
107 self.state_by_hash(hash)
108 }
109
110 pub(crate) fn hash_by_number(&self, number: u64) -> Option<B256> {
112 self.numbers.read().get(&number).copied()
113 }
114
115 pub(crate) fn head_state(&self) -> Option<Arc<BlockState<N>>> {
117 let hash = *self.numbers.read().last_key_value()?.1;
118 self.state_by_hash(hash)
119 }
120
121 pub(crate) fn pending_state(&self) -> Option<BlockState<N>> {
124 self.pending.borrow().clone()
125 }
126
127 #[cfg(test)]
128 fn block_count(&self) -> usize {
129 self.blocks.read().len()
130 }
131}
132
133#[derive(Debug)]
136pub(crate) struct CanonicalInMemoryStateInner<N: NodePrimitives> {
137 pub(crate) chain_info_tracker: ChainInfoTracker<N>,
140 pub(crate) in_memory_state: InMemoryState<N>,
142 pub(crate) canon_state_notification_sender: CanonStateNotificationSender<N>,
144}
145
146impl<N: NodePrimitives> CanonicalInMemoryStateInner<N> {
147 fn clear(&self) {
149 {
150 let mut numbers = self.in_memory_state.numbers.write();
152 let mut blocks = self.in_memory_state.blocks.write();
153 numbers.clear();
154 blocks.clear();
155 self.in_memory_state.pending.send_modify(|p| {
156 p.take();
157 });
158 }
159 self.in_memory_state.update_metrics();
160 }
161}
162
163type PendingBlockAndReceipts<N> =
164 (RecoveredBlock<<N as NodePrimitives>::Block>, Vec<reth_primitives_traits::ReceiptTy<N>>);
165
166#[derive(Debug, Clone)]
170pub struct CanonicalInMemoryState<N: NodePrimitives = EthPrimitives> {
171 pub(crate) inner: Arc<CanonicalInMemoryStateInner<N>>,
172}
173
174impl<N: NodePrimitives> CanonicalInMemoryState<N> {
175 pub fn new(
178 blocks: HashMap<B256, Arc<BlockState<N>>>,
179 numbers: BTreeMap<u64, B256>,
180 pending: Option<BlockState<N>>,
181 finalized: Option<SealedHeader<N::BlockHeader>>,
182 safe: Option<SealedHeader<N::BlockHeader>>,
183 ) -> Self {
184 let in_memory_state = InMemoryState::new(blocks, numbers, pending);
185 let header = in_memory_state.head_state().map_or_else(SealedHeader::default, |state| {
186 state.block_ref().recovered_block().clone_sealed_header()
187 });
188 let chain_info_tracker = ChainInfoTracker::new(header, finalized, safe);
189 let (canon_state_notification_sender, _) =
190 broadcast::channel(CANON_STATE_NOTIFICATION_CHANNEL_SIZE);
191
192 Self {
193 inner: Arc::new(CanonicalInMemoryStateInner {
194 chain_info_tracker,
195 in_memory_state,
196 canon_state_notification_sender,
197 }),
198 }
199 }
200
201 pub fn empty() -> Self {
203 Self::new(HashMap::default(), BTreeMap::new(), None, None, None)
204 }
205
206 pub fn with_head(
209 head: SealedHeader<N::BlockHeader>,
210 finalized: Option<SealedHeader<N::BlockHeader>>,
211 safe: Option<SealedHeader<N::BlockHeader>>,
212 ) -> Self {
213 let chain_info_tracker = ChainInfoTracker::new(head, finalized, safe);
214 let in_memory_state = InMemoryState::default();
215 let (canon_state_notification_sender, _) =
216 broadcast::channel(CANON_STATE_NOTIFICATION_CHANNEL_SIZE);
217 let inner = CanonicalInMemoryStateInner {
218 chain_info_tracker,
219 in_memory_state,
220 canon_state_notification_sender,
221 };
222
223 Self { inner: Arc::new(inner) }
224 }
225
226 pub fn hash_by_number(&self, number: u64) -> Option<B256> {
228 self.inner.in_memory_state.hash_by_number(number)
229 }
230
231 pub fn header_by_hash(&self, hash: B256) -> Option<SealedHeader<N::BlockHeader>> {
233 self.state_by_hash(hash)
234 .map(|block| block.block_ref().recovered_block().clone_sealed_header())
235 }
236
237 pub fn clear_state(&self) {
239 self.inner.clear()
240 }
241
242 pub fn set_pending_block(&self, pending: ExecutedBlock<N>) {
246 let parent = self.state_by_hash(pending.recovered_block().parent_hash());
248 let pending = BlockState::with_parent(pending, parent);
249 self.inner.in_memory_state.pending.send_modify(|p| {
250 p.replace(pending);
251 });
252 self.inner.in_memory_state.update_metrics();
253 }
254
255 fn update_blocks<I, R>(&self, new_blocks: I, reorged: R)
260 where
261 I: IntoIterator<Item = ExecutedBlock<N>>,
262 R: IntoIterator<Item = ExecutedBlock<N>>,
263 {
264 {
265 let mut numbers = self.inner.in_memory_state.numbers.write();
267 let mut blocks = self.inner.in_memory_state.blocks.write();
268
269 for block in reorged {
271 let hash = block.recovered_block().hash();
272 let number = block.recovered_block().number();
273 blocks.remove(&hash);
274 numbers.remove(&number);
275 }
276
277 for block in new_blocks {
279 let parent = blocks.get(&block.recovered_block().parent_hash()).cloned();
280 let block_state = BlockState::with_parent(block, parent);
281 let hash = block_state.hash();
282 let number = block_state.number();
283
284 blocks.insert(hash, Arc::new(block_state));
286 numbers.insert(number, hash);
287 }
288
289 self.inner.in_memory_state.pending.send_modify(|p| {
291 p.take();
292 });
293 }
294 self.inner.in_memory_state.update_metrics();
295 }
296
297 pub fn update_chain(&self, new_chain: NewCanonicalChain<N>) {
299 match new_chain {
300 NewCanonicalChain::Commit { new } => {
301 self.update_blocks(new, vec![]);
302 }
303 NewCanonicalChain::Reorg { new, old } => {
304 self.update_blocks(new, old);
305 }
306 }
307 }
308
309 pub fn remove_persisted_blocks(&self, persisted_num_hash: BlockNumHash) {
314 {
319 if self.inner.in_memory_state.blocks.read().get(&persisted_num_hash.hash).is_none() {
320 return
322 }
323 }
324
325 {
326 let mut numbers = self.inner.in_memory_state.numbers.write();
328 let mut blocks = self.inner.in_memory_state.blocks.write();
329
330 let BlockNumHash { number: persisted_height, hash: _ } = persisted_num_hash;
331
332 numbers.clear();
334
335 let mut old_blocks = blocks
338 .drain()
339 .filter(|(_, b)| b.block_ref().recovered_block().number() > persisted_height)
340 .map(|(_, b)| b.block.clone())
341 .collect::<Vec<_>>();
342
343 old_blocks.sort_unstable_by_key(|block| block.recovered_block().number());
345
346 for block in old_blocks {
348 let parent = blocks.get(&block.recovered_block().parent_hash()).cloned();
349 let block_state = BlockState::with_parent(block, parent);
350 let hash = block_state.hash();
351 let number = block_state.number();
352
353 blocks.insert(hash, Arc::new(block_state));
355 numbers.insert(number, hash);
356 }
357
358 self.inner.in_memory_state.pending.send_modify(|p| {
360 if let Some(p) = p.as_mut() {
361 p.parent = blocks.get(&p.block_ref().recovered_block().parent_hash()).cloned();
362 }
363 });
364 }
365 self.inner.in_memory_state.update_metrics();
366 }
367
368 pub fn state_by_hash(&self, hash: B256) -> Option<Arc<BlockState<N>>> {
370 self.inner.in_memory_state.state_by_hash(hash)
371 }
372
373 pub fn state_by_number(&self, number: u64) -> Option<Arc<BlockState<N>>> {
375 self.inner.in_memory_state.state_by_number(number)
376 }
377
378 pub fn head_state(&self) -> Option<Arc<BlockState<N>>> {
380 self.inner.in_memory_state.head_state()
381 }
382
383 pub fn pending_state(&self) -> Option<BlockState<N>> {
385 self.inner.in_memory_state.pending_state()
386 }
387
388 pub fn pending_block_num_hash(&self) -> Option<BlockNumHash> {
390 self.inner
391 .in_memory_state
392 .pending_state()
393 .map(|state| BlockNumHash { number: state.number(), hash: state.hash() })
394 }
395
396 pub fn chain_info(&self) -> ChainInfo {
398 self.inner.chain_info_tracker.chain_info()
399 }
400
401 pub fn get_canonical_block_number(&self) -> u64 {
403 self.inner.chain_info_tracker.get_canonical_block_number()
404 }
405
406 pub fn get_safe_num_hash(&self) -> Option<BlockNumHash> {
408 self.inner.chain_info_tracker.get_safe_num_hash()
409 }
410
411 pub fn get_finalized_num_hash(&self) -> Option<BlockNumHash> {
413 self.inner.chain_info_tracker.get_finalized_num_hash()
414 }
415
416 pub fn on_forkchoice_update_received(&self) {
418 self.inner.chain_info_tracker.on_forkchoice_update_received();
419 }
420
421 pub fn last_received_update_timestamp(&self) -> Option<Instant> {
423 self.inner.chain_info_tracker.last_forkchoice_update_received_at()
424 }
425
426 pub fn set_canonical_head(&self, header: SealedHeader<N::BlockHeader>) {
428 self.inner.chain_info_tracker.set_canonical_head(header);
429 }
430
431 pub fn set_safe(&self, header: SealedHeader<N::BlockHeader>) {
433 self.inner.chain_info_tracker.set_safe(header);
434 }
435
436 pub fn set_finalized(&self, header: SealedHeader<N::BlockHeader>) {
438 self.inner.chain_info_tracker.set_finalized(header);
439 }
440
441 pub fn get_canonical_head(&self) -> SealedHeader<N::BlockHeader> {
443 self.inner.chain_info_tracker.get_canonical_head()
444 }
445
446 pub fn get_finalized_header(&self) -> Option<SealedHeader<N::BlockHeader>> {
448 self.inner.chain_info_tracker.get_finalized_header()
449 }
450
451 pub fn get_safe_header(&self) -> Option<SealedHeader<N::BlockHeader>> {
453 self.inner.chain_info_tracker.get_safe_header()
454 }
455
456 pub fn pending_sealed_header(&self) -> Option<SealedHeader<N::BlockHeader>> {
458 self.pending_state().map(|h| h.block_ref().recovered_block().clone_sealed_header())
459 }
460
461 pub fn pending_header(&self) -> Option<N::BlockHeader> {
463 self.pending_sealed_header().map(|sealed_header| sealed_header.unseal())
464 }
465
466 pub fn pending_block(&self) -> Option<SealedBlock<N::Block>> {
468 self.pending_state()
469 .map(|block_state| block_state.block_ref().recovered_block().sealed_block().clone())
470 }
471
472 pub fn pending_recovered_block(&self) -> Option<RecoveredBlock<N::Block>>
474 where
475 N::SignedTx: SignedTransaction,
476 {
477 self.pending_state().map(|block_state| block_state.block_ref().recovered_block().clone())
478 }
479
480 pub fn pending_block_and_receipts(&self) -> Option<PendingBlockAndReceipts<N>> {
483 self.pending_state().map(|block_state| {
484 (
485 block_state.block_ref().recovered_block().clone(),
486 block_state.executed_block_receipts(),
487 )
488 })
489 }
490
491 pub fn subscribe_canon_state(&self) -> CanonStateNotifications<N> {
493 self.inner.canon_state_notification_sender.subscribe()
494 }
495
496 pub fn subscribe_safe_block(&self) -> watch::Receiver<Option<SealedHeader<N::BlockHeader>>> {
498 self.inner.chain_info_tracker.subscribe_safe_block()
499 }
500
501 pub fn subscribe_finalized_block(
503 &self,
504 ) -> watch::Receiver<Option<SealedHeader<N::BlockHeader>>> {
505 self.inner.chain_info_tracker.subscribe_finalized_block()
506 }
507
508 pub fn notify_canon_state(&self, event: CanonStateNotification<N>) {
510 self.inner.canon_state_notification_sender.send(event).ok();
511 }
512
513 pub fn state_provider(
518 &self,
519 hash: B256,
520 historical: StateProviderBox,
521 ) -> MemoryOverlayStateProvider<N> {
522 let in_memory = if let Some(state) = self.state_by_hash(hash) {
523 state.chain().map(|block_state| block_state.block()).collect()
524 } else {
525 Vec::new()
526 };
527
528 MemoryOverlayStateProvider::new(historical, in_memory)
529 }
530
531 pub fn canonical_chain(&self) -> impl Iterator<Item = Arc<BlockState<N>>> {
536 self.inner.in_memory_state.head_state().into_iter().flat_map(|head| head.iter())
537 }
538
539 pub fn transaction_by_hash(&self, hash: TxHash) -> Option<N::SignedTx> {
541 for block_state in self.canonical_chain() {
542 if let Some(tx) =
543 block_state.block_ref().recovered_block().body().transaction_by_hash(&hash)
544 {
545 return Some(tx.clone())
546 }
547 }
548 None
549 }
550
551 pub fn transaction_by_hash_with_meta(
554 &self,
555 tx_hash: TxHash,
556 ) -> Option<(N::SignedTx, TransactionMeta)> {
557 for block_state in self.canonical_chain() {
558 if let Some(indexed) = block_state.find_indexed(tx_hash) {
559 return Some((indexed.tx().clone(), indexed.meta()));
560 }
561 }
562 None
563 }
564}
565
566#[derive(Debug, Clone)]
569pub struct BlockState<N: NodePrimitives = EthPrimitives> {
570 block: ExecutedBlock<N>,
572 parent: Option<Arc<Self>>,
574}
575
576impl<N: NodePrimitives> PartialEq for BlockState<N> {
577 fn eq(&self, other: &Self) -> bool {
578 self.block == other.block && self.parent == other.parent
579 }
580}
581
582impl<N: NodePrimitives> BlockState<N> {
583 pub const fn new(block: ExecutedBlock<N>) -> Self {
585 Self { block, parent: None }
586 }
587
588 pub const fn with_parent(block: ExecutedBlock<N>, parent: Option<Arc<Self>>) -> Self {
590 Self { block, parent }
591 }
592
593 pub fn anchor(&self) -> BlockNumHash {
595 let mut current = self;
596 while let Some(parent) = ¤t.parent {
597 current = parent;
598 }
599 current.block.recovered_block().parent_num_hash()
600 }
601
602 pub fn block(&self) -> ExecutedBlock<N> {
604 self.block.clone()
605 }
606
607 pub const fn block_ref(&self) -> &ExecutedBlock<N> {
609 &self.block
610 }
611
612 pub fn hash(&self) -> B256 {
614 self.block.recovered_block().hash()
615 }
616
617 pub fn number(&self) -> u64 {
619 self.block.recovered_block().number()
620 }
621
622 pub fn state_root(&self) -> B256 {
625 self.block.recovered_block().state_root()
626 }
627
628 pub fn receipts(&self) -> &Vec<Vec<N::Receipt>> {
630 &self.block.execution_outcome().receipts
631 }
632
633 pub fn executed_block_receipts(&self) -> Vec<N::Receipt> {
640 let receipts = self.receipts();
641
642 debug_assert!(
643 receipts.len() <= 1,
644 "Expected at most one block's worth of receipts, found {}",
645 receipts.len()
646 );
647
648 receipts.first().cloned().unwrap_or_default()
649 }
650
651 pub fn executed_block_receipts_ref(&self) -> &[N::Receipt] {
656 let receipts = self.receipts();
657
658 debug_assert!(
659 receipts.len() <= 1,
660 "Expected at most one block's worth of receipts, found {}",
661 receipts.len()
662 );
663
664 receipts.first().map(|receipts| receipts.deref()).unwrap_or_default()
665 }
666
667 pub fn parent_state_chain(&self) -> Vec<&Self> {
674 let mut parents = Vec::new();
675 let mut current = self.parent.as_deref();
676
677 while let Some(parent) = current {
678 parents.push(parent);
679 current = parent.parent.as_deref();
680 }
681
682 parents
683 }
684
685 pub fn chain(&self) -> impl Iterator<Item = &Self> {
689 std::iter::successors(Some(self), |state| state.parent.as_deref())
690 }
691
692 pub fn append_parent_chain<'a>(&'a self, chain: &mut Vec<&'a Self>) {
694 chain.extend(self.parent_state_chain());
695 }
696
697 pub fn iter(self: Arc<Self>) -> impl Iterator<Item = Arc<Self>> {
701 std::iter::successors(Some(self), |state| state.parent.clone())
702 }
703
704 pub fn state_provider(&self, historical: StateProviderBox) -> MemoryOverlayStateProvider<N> {
709 let in_memory = self.chain().map(|block_state| block_state.block()).collect();
710
711 MemoryOverlayStateProvider::new(historical, in_memory)
712 }
713
714 pub fn block_on_chain(&self, hash_or_num: BlockHashOrNumber) -> Option<&Self> {
716 self.chain().find(|block| match hash_or_num {
717 BlockHashOrNumber::Hash(hash) => block.hash() == hash,
718 BlockHashOrNumber::Number(number) => block.number() == number,
719 })
720 }
721
722 pub fn transaction_on_chain(&self, hash: TxHash) -> Option<N::SignedTx> {
724 self.chain().find_map(|block_state| {
725 block_state.block_ref().recovered_block().body().transaction_by_hash(&hash).cloned()
726 })
727 }
728
729 pub fn transaction_meta_on_chain(
731 &self,
732 tx_hash: TxHash,
733 ) -> Option<(N::SignedTx, TransactionMeta)> {
734 self.chain().find_map(|block_state| {
735 block_state.find_indexed(tx_hash).map(|indexed| (indexed.tx().clone(), indexed.meta()))
736 })
737 }
738
739 pub fn find_indexed(&self, tx_hash: TxHash) -> Option<IndexedTx<'_, N::Block>> {
741 self.block_ref().recovered_block().find_indexed(tx_hash)
742 }
743}
744
745#[derive(Clone, Debug)]
747pub struct ExecutedBlock<N: NodePrimitives = EthPrimitives> {
748 pub recovered_block: Arc<RecoveredBlock<N::Block>>,
750 pub execution_output: Arc<ExecutionOutcome<N::Receipt>>,
752 pub trie_data: DeferredTrieData,
757}
758
759impl<N: NodePrimitives> Default for ExecutedBlock<N> {
760 fn default() -> Self {
761 Self {
762 recovered_block: Default::default(),
763 execution_output: Default::default(),
764 trie_data: DeferredTrieData::ready(ComputedTrieData::default()),
765 }
766 }
767}
768
769impl<N: NodePrimitives> PartialEq for ExecutedBlock<N> {
770 fn eq(&self, other: &Self) -> bool {
771 self.recovered_block == other.recovered_block &&
773 self.execution_output == other.execution_output
774 }
775}
776
777impl<N: NodePrimitives> ExecutedBlock<N> {
778 pub fn new(
783 recovered_block: Arc<RecoveredBlock<N::Block>>,
784 execution_output: Arc<ExecutionOutcome<N::Receipt>>,
785 trie_data: ComputedTrieData,
786 ) -> Self {
787 Self { recovered_block, execution_output, trie_data: DeferredTrieData::ready(trie_data) }
788 }
789
790 pub const fn with_deferred_trie_data(
805 recovered_block: Arc<RecoveredBlock<N::Block>>,
806 execution_output: Arc<ExecutionOutcome<N::Receipt>>,
807 trie_data: DeferredTrieData,
808 ) -> Self {
809 Self { recovered_block, execution_output, trie_data }
810 }
811
812 #[inline]
814 pub fn sealed_block(&self) -> &SealedBlock<N::Block> {
815 self.recovered_block.sealed_block()
816 }
817
818 #[inline]
820 pub fn recovered_block(&self) -> &RecoveredBlock<N::Block> {
821 &self.recovered_block
822 }
823
824 #[inline]
826 pub fn execution_outcome(&self) -> &ExecutionOutcome<N::Receipt> {
827 &self.execution_output
828 }
829
830 #[inline]
836 #[tracing::instrument(level = "debug", target = "engine::tree", name = "trie_data", skip_all)]
837 pub fn trie_data(&self) -> ComputedTrieData {
838 self.trie_data.wait_cloned()
839 }
840
841 #[inline]
847 pub fn trie_data_handle(&self) -> DeferredTrieData {
848 self.trie_data.clone()
849 }
850
851 #[inline]
855 pub fn hashed_state(&self) -> Arc<HashedPostStateSorted> {
856 self.trie_data().hashed_state
857 }
858
859 #[inline]
863 pub fn trie_updates(&self) -> Arc<TrieUpdatesSorted> {
864 self.trie_data().trie_updates
865 }
866
867 #[inline]
871 pub fn trie_input(&self) -> Option<Arc<TrieInputSorted>> {
872 self.trie_data().trie_input().cloned()
873 }
874
875 #[inline]
877 pub fn anchor_hash(&self) -> Option<B256> {
878 self.trie_data().anchor_hash()
879 }
880
881 #[inline]
883 pub fn block_number(&self) -> BlockNumber {
884 self.recovered_block.header().number()
885 }
886}
887
888#[derive(Debug)]
890pub enum NewCanonicalChain<N: NodePrimitives = EthPrimitives> {
891 Commit {
893 new: Vec<ExecutedBlock<N>>,
895 },
896 Reorg {
899 new: Vec<ExecutedBlock<N>>,
901 old: Vec<ExecutedBlock<N>>,
903 },
904}
905
906impl<N: NodePrimitives<SignedTx: SignedTransaction>> NewCanonicalChain<N> {
907 pub const fn new_block_count(&self) -> usize {
909 match self {
910 Self::Commit { new } | Self::Reorg { new, .. } => new.len(),
911 }
912 }
913
914 pub const fn reorged_block_count(&self) -> usize {
916 match self {
917 Self::Commit { .. } => 0,
918 Self::Reorg { old, .. } => old.len(),
919 }
920 }
921
922 pub fn to_chain_notification(&self) -> CanonStateNotification<N> {
924 match self {
925 Self::Commit { new } => {
926 let new = Arc::new(new.iter().fold(Chain::default(), |mut chain, exec| {
927 chain.append_block(
928 exec.recovered_block().clone(),
929 exec.execution_outcome().clone(),
930 );
931 chain
932 }));
933 CanonStateNotification::Commit { new }
934 }
935 Self::Reorg { new, old } => {
936 let new = Arc::new(new.iter().fold(Chain::default(), |mut chain, exec| {
937 chain.append_block(
938 exec.recovered_block().clone(),
939 exec.execution_outcome().clone(),
940 );
941 chain
942 }));
943 let old = Arc::new(old.iter().fold(Chain::default(), |mut chain, exec| {
944 chain.append_block(
945 exec.recovered_block().clone(),
946 exec.execution_outcome().clone(),
947 );
948 chain
949 }));
950 CanonStateNotification::Reorg { new, old }
951 }
952 }
953 }
954
955 pub fn tip(&self) -> &SealedBlock<N::Block> {
960 match self {
961 Self::Commit { new } | Self::Reorg { new, .. } => {
962 new.last().expect("non empty blocks").recovered_block()
963 }
964 }
965 }
966}
967
968#[cfg(test)]
969mod tests {
970 use super::*;
971 use crate::test_utils::TestBlockBuilder;
972 use alloy_eips::eip7685::Requests;
973 use alloy_primitives::{Address, BlockNumber, Bytes, StorageKey, StorageValue};
974 use rand::Rng;
975 use reth_errors::ProviderResult;
976 use reth_ethereum_primitives::{EthPrimitives, Receipt};
977 use reth_primitives_traits::{Account, Bytecode};
978 use reth_storage_api::{
979 AccountReader, BlockHashReader, BytecodeReader, HashedPostStateProvider,
980 StateProofProvider, StateProvider, StateRootProvider, StorageRootProvider,
981 };
982 use reth_trie::{
983 updates::TrieUpdates, AccountProof, HashedPostState, HashedStorage, MultiProof,
984 MultiProofTargets, StorageMultiProof, StorageProof, TrieInput,
985 };
986
987 fn create_mock_state(
988 test_block_builder: &mut TestBlockBuilder<EthPrimitives>,
989 block_number: u64,
990 parent_hash: B256,
991 ) -> BlockState {
992 BlockState::new(
993 test_block_builder.get_executed_block_with_number(block_number, parent_hash),
994 )
995 }
996
997 fn create_mock_state_chain(
998 test_block_builder: &mut TestBlockBuilder<EthPrimitives>,
999 num_blocks: u64,
1000 ) -> Vec<BlockState> {
1001 let mut chain = Vec::with_capacity(num_blocks as usize);
1002 let mut parent_hash = B256::random();
1003 let mut parent_state: Option<BlockState> = None;
1004
1005 for i in 1..=num_blocks {
1006 let mut state = create_mock_state(test_block_builder, i, parent_hash);
1007 if let Some(parent) = parent_state {
1008 state.parent = Some(Arc::new(parent));
1009 }
1010 parent_hash = state.hash();
1011 parent_state = Some(state.clone());
1012 chain.push(state);
1013 }
1014
1015 chain
1016 }
1017
1018 struct MockStateProvider;
1019
1020 impl StateProvider for MockStateProvider {
1021 fn storage(
1022 &self,
1023 _address: Address,
1024 _storage_key: StorageKey,
1025 ) -> ProviderResult<Option<StorageValue>> {
1026 Ok(None)
1027 }
1028 }
1029
1030 impl BytecodeReader for MockStateProvider {
1031 fn bytecode_by_hash(&self, _code_hash: &B256) -> ProviderResult<Option<Bytecode>> {
1032 Ok(None)
1033 }
1034 }
1035
1036 impl BlockHashReader for MockStateProvider {
1037 fn block_hash(&self, _number: BlockNumber) -> ProviderResult<Option<B256>> {
1038 Ok(None)
1039 }
1040
1041 fn canonical_hashes_range(
1042 &self,
1043 _start: BlockNumber,
1044 _end: BlockNumber,
1045 ) -> ProviderResult<Vec<B256>> {
1046 Ok(vec![])
1047 }
1048 }
1049
1050 impl AccountReader for MockStateProvider {
1051 fn basic_account(&self, _address: &Address) -> ProviderResult<Option<Account>> {
1052 Ok(None)
1053 }
1054 }
1055
1056 impl StateRootProvider for MockStateProvider {
1057 fn state_root(&self, _hashed_state: HashedPostState) -> ProviderResult<B256> {
1058 Ok(B256::random())
1059 }
1060
1061 fn state_root_from_nodes(&self, _input: TrieInput) -> ProviderResult<B256> {
1062 Ok(B256::random())
1063 }
1064
1065 fn state_root_with_updates(
1066 &self,
1067 _hashed_state: HashedPostState,
1068 ) -> ProviderResult<(B256, TrieUpdates)> {
1069 Ok((B256::random(), TrieUpdates::default()))
1070 }
1071
1072 fn state_root_from_nodes_with_updates(
1073 &self,
1074 _input: TrieInput,
1075 ) -> ProviderResult<(B256, TrieUpdates)> {
1076 Ok((B256::random(), TrieUpdates::default()))
1077 }
1078 }
1079
1080 impl HashedPostStateProvider for MockStateProvider {
1081 fn hashed_post_state(&self, _bundle_state: &revm_database::BundleState) -> HashedPostState {
1082 HashedPostState::default()
1083 }
1084 }
1085
1086 impl StorageRootProvider for MockStateProvider {
1087 fn storage_root(
1088 &self,
1089 _address: Address,
1090 _hashed_storage: HashedStorage,
1091 ) -> ProviderResult<B256> {
1092 Ok(B256::random())
1093 }
1094
1095 fn storage_proof(
1096 &self,
1097 _address: Address,
1098 slot: B256,
1099 _hashed_storage: HashedStorage,
1100 ) -> ProviderResult<StorageProof> {
1101 Ok(StorageProof::new(slot))
1102 }
1103
1104 fn storage_multiproof(
1105 &self,
1106 _address: Address,
1107 _slots: &[B256],
1108 _hashed_storage: HashedStorage,
1109 ) -> ProviderResult<StorageMultiProof> {
1110 Ok(StorageMultiProof::empty())
1111 }
1112 }
1113
1114 impl StateProofProvider for MockStateProvider {
1115 fn proof(
1116 &self,
1117 _input: TrieInput,
1118 _address: Address,
1119 _slots: &[B256],
1120 ) -> ProviderResult<AccountProof> {
1121 Ok(AccountProof::new(Address::random()))
1122 }
1123
1124 fn multiproof(
1125 &self,
1126 _input: TrieInput,
1127 _targets: MultiProofTargets,
1128 ) -> ProviderResult<MultiProof> {
1129 Ok(MultiProof::default())
1130 }
1131
1132 fn witness(
1133 &self,
1134 _input: TrieInput,
1135 _target: HashedPostState,
1136 ) -> ProviderResult<Vec<Bytes>> {
1137 Ok(Vec::default())
1138 }
1139 }
1140
1141 #[test]
1142 fn test_in_memory_state_impl_state_by_hash() {
1143 let mut state_by_hash = HashMap::default();
1144 let number = rand::rng().random::<u64>();
1145 let mut test_block_builder: TestBlockBuilder = TestBlockBuilder::default();
1146 let state = Arc::new(create_mock_state(&mut test_block_builder, number, B256::random()));
1147 state_by_hash.insert(state.hash(), state.clone());
1148
1149 let in_memory_state = InMemoryState::new(state_by_hash, BTreeMap::new(), None);
1150
1151 assert_eq!(in_memory_state.state_by_hash(state.hash()), Some(state));
1152 assert_eq!(in_memory_state.state_by_hash(B256::random()), None);
1153 }
1154
1155 #[test]
1156 fn test_in_memory_state_impl_state_by_number() {
1157 let mut state_by_hash = HashMap::default();
1158 let mut hash_by_number = BTreeMap::new();
1159
1160 let number = rand::rng().random::<u64>();
1161 let mut test_block_builder: TestBlockBuilder = TestBlockBuilder::default();
1162 let state = Arc::new(create_mock_state(&mut test_block_builder, number, B256::random()));
1163 let hash = state.hash();
1164
1165 state_by_hash.insert(hash, state.clone());
1166 hash_by_number.insert(number, hash);
1167
1168 let in_memory_state = InMemoryState::new(state_by_hash, hash_by_number, None);
1169
1170 assert_eq!(in_memory_state.state_by_number(number), Some(state));
1171 assert_eq!(in_memory_state.state_by_number(number + 1), None);
1172 }
1173
1174 #[test]
1175 fn test_in_memory_state_impl_head_state() {
1176 let mut state_by_hash = HashMap::default();
1177 let mut hash_by_number = BTreeMap::new();
1178 let mut test_block_builder: TestBlockBuilder = TestBlockBuilder::default();
1179 let state1 = Arc::new(create_mock_state(&mut test_block_builder, 1, B256::random()));
1180 let hash1 = state1.hash();
1181 let state2 = Arc::new(create_mock_state(&mut test_block_builder, 2, hash1));
1182 let hash2 = state2.hash();
1183 hash_by_number.insert(1, hash1);
1184 hash_by_number.insert(2, hash2);
1185 state_by_hash.insert(hash1, state1);
1186 state_by_hash.insert(hash2, state2);
1187
1188 let in_memory_state = InMemoryState::new(state_by_hash, hash_by_number, None);
1189 let head_state = in_memory_state.head_state().unwrap();
1190
1191 assert_eq!(head_state.hash(), hash2);
1192 assert_eq!(head_state.number(), 2);
1193 }
1194
1195 #[test]
1196 fn test_in_memory_state_impl_pending_state() {
1197 let pending_number = rand::rng().random::<u64>();
1198 let mut test_block_builder: TestBlockBuilder = TestBlockBuilder::default();
1199 let pending_state =
1200 create_mock_state(&mut test_block_builder, pending_number, B256::random());
1201 let pending_hash = pending_state.hash();
1202
1203 let in_memory_state =
1204 InMemoryState::new(HashMap::default(), BTreeMap::new(), Some(pending_state));
1205
1206 let result = in_memory_state.pending_state();
1207 assert!(result.is_some());
1208 let actual_pending_state = result.unwrap();
1209 assert_eq!(actual_pending_state.block.recovered_block().hash(), pending_hash);
1210 assert_eq!(actual_pending_state.block.recovered_block().number, pending_number);
1211 }
1212
1213 #[test]
1214 fn test_in_memory_state_impl_no_pending_state() {
1215 let in_memory_state: InMemoryState =
1216 InMemoryState::new(HashMap::default(), BTreeMap::new(), None);
1217
1218 assert_eq!(in_memory_state.pending_state(), None);
1219 }
1220
1221 #[test]
1222 fn test_state() {
1223 let number = rand::rng().random::<u64>();
1224 let mut test_block_builder: TestBlockBuilder = TestBlockBuilder::default();
1225 let block = test_block_builder.get_executed_block_with_number(number, B256::random());
1226
1227 let state = BlockState::new(block.clone());
1228
1229 assert_eq!(state.block(), block);
1230 assert_eq!(state.hash(), block.recovered_block().hash());
1231 assert_eq!(state.number(), number);
1232 assert_eq!(state.state_root(), block.recovered_block().state_root);
1233 }
1234
1235 #[test]
1236 fn test_state_receipts() {
1237 let receipts = vec![vec![Receipt::default()]];
1238 let mut test_block_builder: TestBlockBuilder = TestBlockBuilder::default();
1239 let block =
1240 test_block_builder.get_executed_block_with_receipts(receipts.clone(), B256::random());
1241
1242 let state = BlockState::new(block);
1243
1244 assert_eq!(state.receipts(), &receipts);
1245 }
1246
1247 #[test]
1248 fn test_in_memory_state_chain_update() {
1249 let state: CanonicalInMemoryState = CanonicalInMemoryState::empty();
1250 let mut test_block_builder: TestBlockBuilder = TestBlockBuilder::default();
1251 let block1 = test_block_builder.get_executed_block_with_number(0, B256::random());
1252 let block2 = test_block_builder.get_executed_block_with_number(0, B256::random());
1253 let chain = NewCanonicalChain::Commit { new: vec![block1.clone()] };
1254 state.update_chain(chain);
1255 assert_eq!(
1256 state.head_state().unwrap().block_ref().recovered_block().hash(),
1257 block1.recovered_block().hash()
1258 );
1259 assert_eq!(
1260 state.state_by_number(0).unwrap().block_ref().recovered_block().hash(),
1261 block1.recovered_block().hash()
1262 );
1263
1264 let chain = NewCanonicalChain::Reorg { new: vec![block2.clone()], old: vec![block1] };
1265 state.update_chain(chain);
1266 assert_eq!(
1267 state.head_state().unwrap().block_ref().recovered_block().hash(),
1268 block2.recovered_block().hash()
1269 );
1270 assert_eq!(
1271 state.state_by_number(0).unwrap().block_ref().recovered_block().hash(),
1272 block2.recovered_block().hash()
1273 );
1274
1275 assert_eq!(state.inner.in_memory_state.block_count(), 1);
1276 }
1277
1278 #[test]
1279 fn test_in_memory_state_set_pending_block() {
1280 let state: CanonicalInMemoryState = CanonicalInMemoryState::empty();
1281 let mut test_block_builder: TestBlockBuilder = TestBlockBuilder::default();
1282
1283 let block1 = test_block_builder.get_executed_block_with_number(0, B256::random());
1285
1286 let block2 =
1288 test_block_builder.get_executed_block_with_number(1, block1.recovered_block().hash());
1289
1290 let chain = NewCanonicalChain::Commit { new: vec![block1.clone(), block2.clone()] };
1292 state.update_chain(chain);
1293
1294 assert!(state.pending_state().is_none());
1296
1297 state.set_pending_block(block2.clone());
1299
1300 assert_eq!(
1302 state.pending_state().unwrap(),
1303 BlockState::with_parent(block2.clone(), Some(Arc::new(BlockState::new(block1))))
1304 );
1305
1306 assert_eq!(state.pending_block().unwrap(), block2.recovered_block().sealed_block().clone());
1308
1309 assert_eq!(
1311 state.pending_block_num_hash().unwrap(),
1312 BlockNumHash { number: 1, hash: block2.recovered_block().hash() }
1313 );
1314
1315 assert_eq!(state.pending_header().unwrap(), block2.recovered_block().header().clone());
1317
1318 assert_eq!(
1320 state.pending_sealed_header().unwrap(),
1321 block2.recovered_block().clone_sealed_header()
1322 );
1323
1324 assert_eq!(state.pending_recovered_block().unwrap(), block2.recovered_block().clone());
1326
1327 assert_eq!(
1329 state.pending_block_and_receipts().unwrap(),
1330 (block2.recovered_block().clone(), vec![])
1331 );
1332 }
1333
1334 #[test]
1335 fn test_canonical_in_memory_state_state_provider() {
1336 let mut test_block_builder: TestBlockBuilder = TestBlockBuilder::default();
1337 let block1 = test_block_builder.get_executed_block_with_number(1, B256::random());
1338 let block2 =
1339 test_block_builder.get_executed_block_with_number(2, block1.recovered_block().hash());
1340 let block3 =
1341 test_block_builder.get_executed_block_with_number(3, block2.recovered_block().hash());
1342
1343 let state1 = Arc::new(BlockState::new(block1.clone()));
1344 let state2 = Arc::new(BlockState::with_parent(block2.clone(), Some(state1.clone())));
1345 let state3 = Arc::new(BlockState::with_parent(block3.clone(), Some(state2.clone())));
1346
1347 let mut blocks = HashMap::default();
1348 blocks.insert(block1.recovered_block().hash(), state1);
1349 blocks.insert(block2.recovered_block().hash(), state2);
1350 blocks.insert(block3.recovered_block().hash(), state3);
1351
1352 let mut numbers = BTreeMap::new();
1353 numbers.insert(1, block1.recovered_block().hash());
1354 numbers.insert(2, block2.recovered_block().hash());
1355 numbers.insert(3, block3.recovered_block().hash());
1356
1357 let canonical_state = CanonicalInMemoryState::new(blocks, numbers, None, None, None);
1358
1359 let historical: StateProviderBox = Box::new(MockStateProvider);
1360
1361 let overlay_provider =
1362 canonical_state.state_provider(block3.recovered_block().hash(), historical);
1363
1364 assert_eq!(overlay_provider.in_memory.len(), 3);
1365 assert_eq!(overlay_provider.in_memory[0].recovered_block().number, 3);
1366 assert_eq!(overlay_provider.in_memory[1].recovered_block().number, 2);
1367 assert_eq!(overlay_provider.in_memory[2].recovered_block().number, 1);
1368
1369 assert_eq!(
1370 overlay_provider.in_memory[0].recovered_block().parent_hash,
1371 overlay_provider.in_memory[1].recovered_block().hash()
1372 );
1373 assert_eq!(
1374 overlay_provider.in_memory[1].recovered_block().parent_hash,
1375 overlay_provider.in_memory[2].recovered_block().hash()
1376 );
1377
1378 let unknown_hash = B256::random();
1379 let empty_overlay_provider =
1380 canonical_state.state_provider(unknown_hash, Box::new(MockStateProvider));
1381 assert_eq!(empty_overlay_provider.in_memory.len(), 0);
1382 }
1383
1384 #[test]
1385 fn test_canonical_in_memory_state_canonical_chain_empty() {
1386 let state: CanonicalInMemoryState = CanonicalInMemoryState::empty();
1387 assert!(state.canonical_chain().next().is_none());
1388 }
1389
1390 #[test]
1391 fn test_canonical_in_memory_state_canonical_chain_single_block() {
1392 let block = TestBlockBuilder::eth().get_executed_block_with_number(1, B256::random());
1393 let hash = block.recovered_block().hash();
1394 let mut blocks = HashMap::default();
1395 blocks.insert(hash, Arc::new(BlockState::new(block)));
1396 let mut numbers = BTreeMap::new();
1397 numbers.insert(1, hash);
1398
1399 let state = CanonicalInMemoryState::new(blocks, numbers, None, None, None);
1400 let chain: Vec<_> = state.canonical_chain().collect();
1401
1402 assert_eq!(chain.len(), 1);
1403 assert_eq!(chain[0].number(), 1);
1404 assert_eq!(chain[0].hash(), hash);
1405 }
1406
1407 #[test]
1408 fn test_canonical_in_memory_state_canonical_chain_multiple_blocks() {
1409 let mut parent_hash = B256::random();
1410 let mut block_builder = TestBlockBuilder::eth();
1411 let state: CanonicalInMemoryState = CanonicalInMemoryState::empty();
1412
1413 for i in 1..=3 {
1414 let block = block_builder.get_executed_block_with_number(i, parent_hash);
1415 let hash = block.recovered_block().hash();
1416 state.update_blocks(Some(block), None);
1417 parent_hash = hash;
1418 }
1419
1420 let chain: Vec<_> = state.canonical_chain().collect();
1421
1422 assert_eq!(chain.len(), 3);
1423 assert_eq!(chain[0].number(), 3);
1424 assert_eq!(chain[1].number(), 2);
1425 assert_eq!(chain[2].number(), 1);
1426 }
1427
1428 #[test]
1430 fn test_canonical_in_memory_state_canonical_chain_with_pending_block() {
1431 let mut parent_hash = B256::random();
1432 let mut block_builder = TestBlockBuilder::<EthPrimitives>::eth();
1433 let state: CanonicalInMemoryState = CanonicalInMemoryState::empty();
1434
1435 for i in 1..=2 {
1436 let block = block_builder.get_executed_block_with_number(i, parent_hash);
1437 let hash = block.recovered_block().hash();
1438 state.update_blocks(Some(block), None);
1439 parent_hash = hash;
1440 }
1441
1442 let pending_block = block_builder.get_executed_block_with_number(3, parent_hash);
1443 state.set_pending_block(pending_block);
1444 let chain: Vec<_> = state.canonical_chain().collect();
1445
1446 assert_eq!(chain.len(), 2);
1447 assert_eq!(chain[0].number(), 2);
1448 assert_eq!(chain[1].number(), 1);
1449 }
1450
1451 #[test]
1452 fn test_block_state_parent_blocks() {
1453 let mut test_block_builder: TestBlockBuilder = TestBlockBuilder::default();
1454 let chain = create_mock_state_chain(&mut test_block_builder, 4);
1455
1456 let parents = chain[3].parent_state_chain();
1457 assert_eq!(parents.len(), 3);
1458 assert_eq!(parents[0].block().recovered_block().number, 3);
1459 assert_eq!(parents[1].block().recovered_block().number, 2);
1460 assert_eq!(parents[2].block().recovered_block().number, 1);
1461
1462 let parents = chain[2].parent_state_chain();
1463 assert_eq!(parents.len(), 2);
1464 assert_eq!(parents[0].block().recovered_block().number, 2);
1465 assert_eq!(parents[1].block().recovered_block().number, 1);
1466
1467 let parents = chain[0].parent_state_chain();
1468 assert_eq!(parents.len(), 0);
1469 }
1470
1471 #[test]
1472 fn test_block_state_single_block_state_chain() {
1473 let single_block_number = 1;
1474 let mut test_block_builder: TestBlockBuilder = TestBlockBuilder::default();
1475 let single_block =
1476 create_mock_state(&mut test_block_builder, single_block_number, B256::random());
1477 let single_block_hash = single_block.block().recovered_block().hash();
1478
1479 let parents = single_block.parent_state_chain();
1480 assert_eq!(parents.len(), 0);
1481
1482 let block_state_chain = single_block.chain().collect::<Vec<_>>();
1483 assert_eq!(block_state_chain.len(), 1);
1484 assert_eq!(block_state_chain[0].block().recovered_block().number, single_block_number);
1485 assert_eq!(block_state_chain[0].block().recovered_block().hash(), single_block_hash);
1486 }
1487
1488 #[test]
1489 fn test_block_state_chain() {
1490 let mut test_block_builder: TestBlockBuilder = TestBlockBuilder::default();
1491 let chain = create_mock_state_chain(&mut test_block_builder, 3);
1492
1493 let block_state_chain = chain[2].chain().collect::<Vec<_>>();
1494 assert_eq!(block_state_chain.len(), 3);
1495 assert_eq!(block_state_chain[0].block().recovered_block().number, 3);
1496 assert_eq!(block_state_chain[1].block().recovered_block().number, 2);
1497 assert_eq!(block_state_chain[2].block().recovered_block().number, 1);
1498
1499 let block_state_chain = chain[1].chain().collect::<Vec<_>>();
1500 assert_eq!(block_state_chain.len(), 2);
1501 assert_eq!(block_state_chain[0].block().recovered_block().number, 2);
1502 assert_eq!(block_state_chain[1].block().recovered_block().number, 1);
1503
1504 let block_state_chain = chain[0].chain().collect::<Vec<_>>();
1505 assert_eq!(block_state_chain.len(), 1);
1506 assert_eq!(block_state_chain[0].block().recovered_block().number, 1);
1507 }
1508
1509 #[test]
1510 fn test_to_chain_notification() {
1511 let mut test_block_builder: TestBlockBuilder = TestBlockBuilder::default();
1513 let block0 = test_block_builder.get_executed_block_with_number(0, B256::random());
1514 let block1 =
1515 test_block_builder.get_executed_block_with_number(1, block0.recovered_block.hash());
1516 let block1a =
1517 test_block_builder.get_executed_block_with_number(1, block0.recovered_block.hash());
1518 let block2 =
1519 test_block_builder.get_executed_block_with_number(2, block1.recovered_block.hash());
1520 let block2a =
1521 test_block_builder.get_executed_block_with_number(2, block1.recovered_block.hash());
1522
1523 let sample_execution_outcome = ExecutionOutcome {
1524 receipts: vec![vec![], vec![]],
1525 requests: vec![Requests::default(), Requests::default()],
1526 ..Default::default()
1527 };
1528
1529 let chain_commit = NewCanonicalChain::Commit { new: vec![block0.clone(), block1.clone()] };
1531
1532 assert_eq!(
1533 chain_commit.to_chain_notification(),
1534 CanonStateNotification::Commit {
1535 new: Arc::new(Chain::new(
1536 vec![block0.recovered_block().clone(), block1.recovered_block().clone()],
1537 sample_execution_outcome.clone(),
1538 None
1539 ))
1540 }
1541 );
1542
1543 let chain_reorg = NewCanonicalChain::Reorg {
1545 new: vec![block1a.clone(), block2a.clone()],
1546 old: vec![block1.clone(), block2.clone()],
1547 };
1548
1549 assert_eq!(
1550 chain_reorg.to_chain_notification(),
1551 CanonStateNotification::Reorg {
1552 old: Arc::new(Chain::new(
1553 vec![block1.recovered_block().clone(), block2.recovered_block().clone()],
1554 sample_execution_outcome.clone(),
1555 None
1556 )),
1557 new: Arc::new(Chain::new(
1558 vec![block1a.recovered_block().clone(), block2a.recovered_block().clone()],
1559 sample_execution_outcome,
1560 None
1561 ))
1562 }
1563 );
1564 }
1565}