1use crate::{
4 CanonStateNotification, CanonStateNotificationSender, CanonStateNotifications,
5 ChainInfoTracker, MemoryOverlayStateProvider,
6};
7use alloy_consensus::{transaction::TransactionMeta, BlockHeader};
8use alloy_eips::{eip2718::Encodable2718, BlockHashOrNumber, BlockNumHash};
9use alloy_primitives::{map::HashMap, 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 _, NodePrimitives, RecoveredBlock, SealedBlock, SealedHeader, SignedTransaction,
17};
18use reth_storage_api::StateProviderBox;
19use reth_trie::{updates::TrieUpdates, HashedPostState};
20use std::{collections::BTreeMap, sync::Arc, time::Instant};
21use tokio::sync::{broadcast, watch};
22
23const CANON_STATE_NOTIFICATION_CHANNEL_SIZE: usize = 256;
25
26#[derive(Metrics)]
28#[metrics(scope = "blockchain_tree.in_mem_state")]
29pub(crate) struct InMemoryStateMetrics {
30 pub(crate) earliest_block: Gauge,
32 pub(crate) latest_block: Gauge,
34 pub(crate) num_blocks: Gauge,
36}
37
38#[derive(Debug, Default)]
53pub(crate) struct InMemoryState<N: NodePrimitives = EthPrimitives> {
54 blocks: RwLock<HashMap<B256, Arc<BlockState<N>>>>,
56 numbers: RwLock<BTreeMap<u64, B256>>,
58 pending: watch::Sender<Option<BlockState<N>>>,
60 metrics: InMemoryStateMetrics,
62}
63
64impl<N: NodePrimitives> InMemoryState<N> {
65 pub(crate) fn new(
66 blocks: HashMap<B256, Arc<BlockState<N>>>,
67 numbers: BTreeMap<u64, B256>,
68 pending: Option<BlockState<N>>,
69 ) -> Self {
70 let (pending, _) = watch::channel(pending);
71 let this = Self {
72 blocks: RwLock::new(blocks),
73 numbers: RwLock::new(numbers),
74 pending,
75 metrics: Default::default(),
76 };
77 this.update_metrics();
78 this
79 }
80
81 pub(crate) fn update_metrics(&self) {
87 let numbers = self.numbers.read();
88 if let Some((earliest_block_number, _)) = numbers.first_key_value() {
89 self.metrics.earliest_block.set(*earliest_block_number as f64);
90 }
91 if let Some((latest_block_number, _)) = numbers.last_key_value() {
92 self.metrics.latest_block.set(*latest_block_number as f64);
93 }
94 self.metrics.num_blocks.set(numbers.len() as f64);
95 }
96
97 pub(crate) fn state_by_hash(&self, hash: B256) -> Option<Arc<BlockState<N>>> {
99 self.blocks.read().get(&hash).cloned()
100 }
101
102 pub(crate) fn state_by_number(&self, number: u64) -> Option<Arc<BlockState<N>>> {
104 let hash = self.hash_by_number(number)?;
105 self.state_by_hash(hash)
106 }
107
108 pub(crate) fn hash_by_number(&self, number: u64) -> Option<B256> {
110 self.numbers.read().get(&number).copied()
111 }
112
113 pub(crate) fn head_state(&self) -> Option<Arc<BlockState<N>>> {
115 let hash = *self.numbers.read().last_key_value()?.1;
116 self.state_by_hash(hash)
117 }
118
119 pub(crate) fn pending_state(&self) -> Option<BlockState<N>> {
122 self.pending.borrow().clone()
123 }
124
125 #[cfg(test)]
126 fn block_count(&self) -> usize {
127 self.blocks.read().len()
128 }
129}
130
131#[derive(Debug)]
134pub(crate) struct CanonicalInMemoryStateInner<N: NodePrimitives> {
135 pub(crate) chain_info_tracker: ChainInfoTracker<N>,
138 pub(crate) in_memory_state: InMemoryState<N>,
140 pub(crate) canon_state_notification_sender: CanonStateNotificationSender<N>,
142}
143
144impl<N: NodePrimitives> CanonicalInMemoryStateInner<N> {
145 fn clear(&self) {
147 {
148 let mut numbers = self.in_memory_state.numbers.write();
150 let mut blocks = self.in_memory_state.blocks.write();
151 numbers.clear();
152 blocks.clear();
153 self.in_memory_state.pending.send_modify(|p| {
154 p.take();
155 });
156 }
157 self.in_memory_state.update_metrics();
158 }
159}
160
161type PendingBlockAndReceipts<N> =
162 (SealedBlock<<N as NodePrimitives>::Block>, Vec<reth_primitives_traits::ReceiptTy<N>>);
163
164#[derive(Debug, Clone)]
168pub struct CanonicalInMemoryState<N: NodePrimitives = EthPrimitives> {
169 pub(crate) inner: Arc<CanonicalInMemoryStateInner<N>>,
170}
171
172impl<N: NodePrimitives> CanonicalInMemoryState<N> {
173 pub fn new(
176 blocks: HashMap<B256, Arc<BlockState<N>>>,
177 numbers: BTreeMap<u64, B256>,
178 pending: Option<BlockState<N>>,
179 finalized: Option<SealedHeader<N::BlockHeader>>,
180 safe: Option<SealedHeader<N::BlockHeader>>,
181 ) -> Self {
182 let in_memory_state = InMemoryState::new(blocks, numbers, pending);
183 let header = in_memory_state.head_state().map_or_else(SealedHeader::default, |state| {
184 state.block_ref().recovered_block().clone_sealed_header()
185 });
186 let chain_info_tracker = ChainInfoTracker::new(header, finalized, safe);
187 let (canon_state_notification_sender, _) =
188 broadcast::channel(CANON_STATE_NOTIFICATION_CHANNEL_SIZE);
189
190 Self {
191 inner: Arc::new(CanonicalInMemoryStateInner {
192 chain_info_tracker,
193 in_memory_state,
194 canon_state_notification_sender,
195 }),
196 }
197 }
198
199 pub fn empty() -> Self {
201 Self::new(HashMap::default(), BTreeMap::new(), None, None, None)
202 }
203
204 pub fn with_head(
207 head: SealedHeader<N::BlockHeader>,
208 finalized: Option<SealedHeader<N::BlockHeader>>,
209 safe: Option<SealedHeader<N::BlockHeader>>,
210 ) -> Self {
211 let chain_info_tracker = ChainInfoTracker::new(head, finalized, safe);
212 let in_memory_state = InMemoryState::default();
213 let (canon_state_notification_sender, _) =
214 broadcast::channel(CANON_STATE_NOTIFICATION_CHANNEL_SIZE);
215 let inner = CanonicalInMemoryStateInner {
216 chain_info_tracker,
217 in_memory_state,
218 canon_state_notification_sender,
219 };
220
221 Self { inner: Arc::new(inner) }
222 }
223
224 pub fn hash_by_number(&self, number: u64) -> Option<B256> {
226 self.inner.in_memory_state.hash_by_number(number)
227 }
228
229 pub fn header_by_hash(&self, hash: B256) -> Option<SealedHeader<N::BlockHeader>> {
231 self.state_by_hash(hash)
232 .map(|block| block.block_ref().recovered_block().clone_sealed_header())
233 }
234
235 pub fn clear_state(&self) {
237 self.inner.clear()
238 }
239
240 pub fn set_pending_block(&self, pending: ExecutedBlockWithTrieUpdates<N>) {
244 let parent = self.state_by_hash(pending.recovered_block().parent_hash());
246 let pending = BlockState::with_parent(pending, parent);
247 self.inner.in_memory_state.pending.send_modify(|p| {
248 p.replace(pending);
249 });
250 self.inner.in_memory_state.update_metrics();
251 }
252
253 fn update_blocks<I, R>(&self, new_blocks: I, reorged: R)
258 where
259 I: IntoIterator<Item = ExecutedBlockWithTrieUpdates<N>>,
260 R: IntoIterator<Item = ExecutedBlock<N>>,
261 {
262 {
263 let mut numbers = self.inner.in_memory_state.numbers.write();
265 let mut blocks = self.inner.in_memory_state.blocks.write();
266
267 for block in reorged {
269 let hash = block.recovered_block().hash();
270 let number = block.recovered_block().number();
271 blocks.remove(&hash);
272 numbers.remove(&number);
273 }
274
275 for block in new_blocks {
277 let parent = blocks.get(&block.recovered_block().parent_hash()).cloned();
278 let block_state = BlockState::with_parent(block, parent);
279 let hash = block_state.hash();
280 let number = block_state.number();
281
282 blocks.insert(hash, Arc::new(block_state));
284 numbers.insert(number, hash);
285 }
286
287 self.inner.in_memory_state.pending.send_modify(|p| {
289 p.take();
290 });
291 }
292 self.inner.in_memory_state.update_metrics();
293 }
294
295 pub fn update_chain(&self, new_chain: NewCanonicalChain<N>) {
297 match new_chain {
298 NewCanonicalChain::Commit { new } => {
299 self.update_blocks(new, vec![]);
300 }
301 NewCanonicalChain::Reorg { new, old } => {
302 self.update_blocks(new, old);
303 }
304 }
305 }
306
307 pub fn remove_persisted_blocks(&self, persisted_num_hash: BlockNumHash) {
312 {
317 if self.inner.in_memory_state.blocks.read().get(&persisted_num_hash.hash).is_none() {
318 return
320 }
321 }
322
323 {
324 let mut numbers = self.inner.in_memory_state.numbers.write();
326 let mut blocks = self.inner.in_memory_state.blocks.write();
327
328 let BlockNumHash { number: persisted_height, hash: _ } = persisted_num_hash;
329
330 numbers.clear();
332
333 let mut old_blocks = blocks
336 .drain()
337 .filter(|(_, b)| b.block_ref().recovered_block().number() > persisted_height)
338 .map(|(_, b)| b.block.clone())
339 .collect::<Vec<_>>();
340
341 old_blocks.sort_unstable_by_key(|block| block.recovered_block().number());
343
344 for block in old_blocks {
346 let parent = blocks.get(&block.recovered_block().parent_hash()).cloned();
347 let block_state = BlockState::with_parent(block, parent);
348 let hash = block_state.hash();
349 let number = block_state.number();
350
351 blocks.insert(hash, Arc::new(block_state));
353 numbers.insert(number, hash);
354 }
355
356 self.inner.in_memory_state.pending.send_modify(|p| {
358 if let Some(p) = p.as_mut() {
359 p.parent = blocks.get(&p.block_ref().recovered_block().parent_hash()).cloned();
360 }
361 });
362 }
363 self.inner.in_memory_state.update_metrics();
364 }
365
366 pub fn state_by_hash(&self, hash: B256) -> Option<Arc<BlockState<N>>> {
368 self.inner.in_memory_state.state_by_hash(hash)
369 }
370
371 pub fn state_by_number(&self, number: u64) -> Option<Arc<BlockState<N>>> {
373 self.inner.in_memory_state.state_by_number(number)
374 }
375
376 pub fn head_state(&self) -> Option<Arc<BlockState<N>>> {
378 self.inner.in_memory_state.head_state()
379 }
380
381 pub fn pending_state(&self) -> Option<BlockState<N>> {
383 self.inner.in_memory_state.pending_state()
384 }
385
386 pub fn pending_block_num_hash(&self) -> Option<BlockNumHash> {
388 self.inner
389 .in_memory_state
390 .pending_state()
391 .map(|state| BlockNumHash { number: state.number(), hash: state.hash() })
392 }
393
394 pub fn chain_info(&self) -> ChainInfo {
396 self.inner.chain_info_tracker.chain_info()
397 }
398
399 pub fn get_canonical_block_number(&self) -> u64 {
401 self.inner.chain_info_tracker.get_canonical_block_number()
402 }
403
404 pub fn get_safe_num_hash(&self) -> Option<BlockNumHash> {
406 self.inner.chain_info_tracker.get_safe_num_hash()
407 }
408
409 pub fn get_finalized_num_hash(&self) -> Option<BlockNumHash> {
411 self.inner.chain_info_tracker.get_finalized_num_hash()
412 }
413
414 pub fn on_forkchoice_update_received(&self) {
416 self.inner.chain_info_tracker.on_forkchoice_update_received();
417 }
418
419 pub fn last_received_update_timestamp(&self) -> Option<Instant> {
421 self.inner.chain_info_tracker.last_forkchoice_update_received_at()
422 }
423
424 pub fn set_canonical_head(&self, header: SealedHeader<N::BlockHeader>) {
426 self.inner.chain_info_tracker.set_canonical_head(header);
427 }
428
429 pub fn set_safe(&self, header: SealedHeader<N::BlockHeader>) {
431 self.inner.chain_info_tracker.set_safe(header);
432 }
433
434 pub fn set_finalized(&self, header: SealedHeader<N::BlockHeader>) {
436 self.inner.chain_info_tracker.set_finalized(header);
437 }
438
439 pub fn get_canonical_head(&self) -> SealedHeader<N::BlockHeader> {
441 self.inner.chain_info_tracker.get_canonical_head()
442 }
443
444 pub fn get_finalized_header(&self) -> Option<SealedHeader<N::BlockHeader>> {
446 self.inner.chain_info_tracker.get_finalized_header()
447 }
448
449 pub fn get_safe_header(&self) -> Option<SealedHeader<N::BlockHeader>> {
451 self.inner.chain_info_tracker.get_safe_header()
452 }
453
454 pub fn pending_sealed_header(&self) -> Option<SealedHeader<N::BlockHeader>> {
456 self.pending_state().map(|h| h.block_ref().recovered_block().clone_sealed_header())
457 }
458
459 pub fn pending_header(&self) -> Option<N::BlockHeader> {
461 self.pending_sealed_header().map(|sealed_header| sealed_header.unseal())
462 }
463
464 pub fn pending_block(&self) -> Option<SealedBlock<N::Block>> {
466 self.pending_state()
467 .map(|block_state| block_state.block_ref().recovered_block().sealed_block().clone())
468 }
469
470 pub fn pending_recovered_block(&self) -> Option<RecoveredBlock<N::Block>>
472 where
473 N::SignedTx: SignedTransaction,
474 {
475 self.pending_state().map(|block_state| block_state.block_ref().recovered_block().clone())
476 }
477
478 pub fn pending_block_and_receipts(&self) -> Option<PendingBlockAndReceipts<N>> {
481 self.pending_state().map(|block_state| {
482 (
483 block_state.block_ref().recovered_block().sealed_block().clone(),
484 block_state.executed_block_receipts(),
485 )
486 })
487 }
488
489 pub fn subscribe_canon_state(&self) -> CanonStateNotifications<N> {
491 self.inner.canon_state_notification_sender.subscribe()
492 }
493
494 pub fn subscribe_safe_block(&self) -> watch::Receiver<Option<SealedHeader<N::BlockHeader>>> {
496 self.inner.chain_info_tracker.subscribe_safe_block()
497 }
498
499 pub fn subscribe_finalized_block(
501 &self,
502 ) -> watch::Receiver<Option<SealedHeader<N::BlockHeader>>> {
503 self.inner.chain_info_tracker.subscribe_finalized_block()
504 }
505
506 pub fn notify_canon_state(&self, event: CanonStateNotification<N>) {
508 self.inner.canon_state_notification_sender.send(event).ok();
509 }
510
511 pub fn state_provider(
516 &self,
517 hash: B256,
518 historical: StateProviderBox,
519 ) -> MemoryOverlayStateProvider<N> {
520 let in_memory = if let Some(state) = self.state_by_hash(hash) {
521 state.chain().map(|block_state| block_state.block()).collect()
522 } else {
523 Vec::new()
524 };
525
526 MemoryOverlayStateProvider::new(historical, in_memory)
527 }
528
529 pub fn canonical_chain(&self) -> impl Iterator<Item = Arc<BlockState<N>>> {
534 self.inner.in_memory_state.head_state().into_iter().flat_map(|head| head.iter())
535 }
536
537 pub fn transaction_by_hash(&self, hash: TxHash) -> Option<N::SignedTx> {
539 for block_state in self.canonical_chain() {
540 if let Some(tx) =
541 block_state.block_ref().recovered_block().body().transaction_by_hash(&hash)
542 {
543 return Some(tx.clone())
544 }
545 }
546 None
547 }
548
549 pub fn transaction_by_hash_with_meta(
552 &self,
553 tx_hash: TxHash,
554 ) -> Option<(N::SignedTx, TransactionMeta)> {
555 for block_state in self.canonical_chain() {
556 if let Some((index, tx)) = block_state
557 .block_ref()
558 .recovered_block()
559 .body()
560 .transactions_iter()
561 .enumerate()
562 .find(|(_, tx)| tx.trie_hash() == tx_hash)
563 {
564 let meta = TransactionMeta {
565 tx_hash,
566 index: index as u64,
567 block_hash: block_state.hash(),
568 block_number: block_state.block_ref().recovered_block().number(),
569 base_fee: block_state.block_ref().recovered_block().base_fee_per_gas(),
570 timestamp: block_state.block_ref().recovered_block().timestamp(),
571 excess_blob_gas: block_state.block_ref().recovered_block().excess_blob_gas(),
572 };
573 return Some((tx.clone(), meta))
574 }
575 }
576 None
577 }
578}
579
580#[derive(Debug, PartialEq, Eq, Clone)]
583pub struct BlockState<N: NodePrimitives = EthPrimitives> {
584 block: ExecutedBlockWithTrieUpdates<N>,
586 parent: Option<Arc<BlockState<N>>>,
588}
589
590impl<N: NodePrimitives> BlockState<N> {
591 pub const fn new(block: ExecutedBlockWithTrieUpdates<N>) -> Self {
593 Self { block, parent: None }
594 }
595
596 pub const fn with_parent(
598 block: ExecutedBlockWithTrieUpdates<N>,
599 parent: Option<Arc<Self>>,
600 ) -> Self {
601 Self { block, parent }
602 }
603
604 pub fn anchor(&self) -> BlockNumHash {
606 if let Some(parent) = &self.parent {
607 parent.anchor()
608 } else {
609 self.block.recovered_block().parent_num_hash()
610 }
611 }
612
613 pub fn block(&self) -> ExecutedBlockWithTrieUpdates<N> {
615 self.block.clone()
616 }
617
618 pub const fn block_ref(&self) -> &ExecutedBlockWithTrieUpdates<N> {
620 &self.block
621 }
622
623 pub fn hash(&self) -> B256 {
625 self.block.recovered_block().hash()
626 }
627
628 pub fn number(&self) -> u64 {
630 self.block.recovered_block().number()
631 }
632
633 pub fn state_root(&self) -> B256 {
636 self.block.recovered_block().state_root()
637 }
638
639 pub fn receipts(&self) -> &Vec<Vec<N::Receipt>> {
641 &self.block.execution_outcome().receipts
642 }
643
644 pub fn executed_block_receipts(&self) -> Vec<N::Receipt> {
649 let receipts = self.receipts();
650
651 debug_assert!(
652 receipts.len() <= 1,
653 "Expected at most one block's worth of receipts, found {}",
654 receipts.len()
655 );
656
657 receipts.first().cloned().unwrap_or_default()
658 }
659
660 pub fn parent_state_chain(&self) -> Vec<&Self> {
667 let mut parents = Vec::new();
668 let mut current = self.parent.as_deref();
669
670 while let Some(parent) = current {
671 parents.push(parent);
672 current = parent.parent.as_deref();
673 }
674
675 parents
676 }
677
678 pub fn chain(&self) -> impl Iterator<Item = &Self> {
682 std::iter::successors(Some(self), |state| state.parent.as_deref())
683 }
684
685 pub fn append_parent_chain<'a>(&'a self, chain: &mut Vec<&'a Self>) {
687 chain.extend(self.parent_state_chain());
688 }
689
690 pub fn iter(self: Arc<Self>) -> impl Iterator<Item = Arc<Self>> {
694 std::iter::successors(Some(self), |state| state.parent.clone())
695 }
696
697 pub fn state_provider(&self, historical: StateProviderBox) -> MemoryOverlayStateProvider<N> {
702 let in_memory = self.chain().map(|block_state| block_state.block()).collect();
703
704 MemoryOverlayStateProvider::new(historical, in_memory)
705 }
706
707 pub fn block_on_chain(&self, hash_or_num: BlockHashOrNumber) -> Option<&Self> {
709 self.chain().find(|block| match hash_or_num {
710 BlockHashOrNumber::Hash(hash) => block.hash() == hash,
711 BlockHashOrNumber::Number(number) => block.number() == number,
712 })
713 }
714
715 pub fn transaction_on_chain(&self, hash: TxHash) -> Option<N::SignedTx> {
717 self.chain().find_map(|block_state| {
718 block_state.block_ref().recovered_block().body().transaction_by_hash(&hash).cloned()
719 })
720 }
721
722 pub fn transaction_meta_on_chain(
724 &self,
725 tx_hash: TxHash,
726 ) -> Option<(N::SignedTx, TransactionMeta)> {
727 self.chain().find_map(|block_state| {
728 block_state
729 .block_ref()
730 .recovered_block()
731 .body()
732 .transactions_iter()
733 .enumerate()
734 .find(|(_, tx)| tx.trie_hash() == tx_hash)
735 .map(|(index, tx)| {
736 let meta = TransactionMeta {
737 tx_hash,
738 index: index as u64,
739 block_hash: block_state.hash(),
740 block_number: block_state.block_ref().recovered_block().number(),
741 base_fee: block_state.block_ref().recovered_block().base_fee_per_gas(),
742 timestamp: block_state.block_ref().recovered_block().timestamp(),
743 excess_blob_gas: block_state
744 .block_ref()
745 .recovered_block()
746 .excess_blob_gas(),
747 };
748 (tx.clone(), meta)
749 })
750 })
751 }
752}
753
754#[derive(Clone, Debug, PartialEq, Eq)]
756pub struct ExecutedBlock<N: NodePrimitives = EthPrimitives> {
757 pub recovered_block: Arc<RecoveredBlock<N::Block>>,
759 pub execution_output: Arc<ExecutionOutcome<N::Receipt>>,
761 pub hashed_state: Arc<HashedPostState>,
763}
764
765impl<N: NodePrimitives> Default for ExecutedBlock<N> {
766 fn default() -> Self {
767 Self {
768 recovered_block: Default::default(),
769 execution_output: Default::default(),
770 hashed_state: Default::default(),
771 }
772 }
773}
774
775impl<N: NodePrimitives> ExecutedBlock<N> {
776 #[inline]
778 pub fn sealed_block(&self) -> &SealedBlock<N::Block> {
779 self.recovered_block.sealed_block()
780 }
781
782 #[inline]
784 pub fn recovered_block(&self) -> &RecoveredBlock<N::Block> {
785 &self.recovered_block
786 }
787
788 #[inline]
790 pub fn execution_outcome(&self) -> &ExecutionOutcome<N::Receipt> {
791 &self.execution_output
792 }
793
794 #[inline]
796 pub fn hashed_state(&self) -> &HashedPostState {
797 &self.hashed_state
798 }
799}
800
801#[derive(
806 Clone,
807 Debug,
808 PartialEq,
809 Eq,
810 Default,
811 derive_more::Deref,
812 derive_more::DerefMut,
813 derive_more::Into,
814)]
815pub struct ExecutedBlockWithTrieUpdates<N: NodePrimitives = EthPrimitives> {
816 #[deref]
818 #[deref_mut]
819 #[into]
820 pub block: ExecutedBlock<N>,
821 pub trie: Arc<TrieUpdates>,
823}
824
825impl<N: NodePrimitives> ExecutedBlockWithTrieUpdates<N> {
826 pub const fn new(
828 recovered_block: Arc<RecoveredBlock<N::Block>>,
829 execution_output: Arc<ExecutionOutcome<N::Receipt>>,
830 hashed_state: Arc<HashedPostState>,
831 trie: Arc<TrieUpdates>,
832 ) -> Self {
833 Self { block: ExecutedBlock { recovered_block, execution_output, hashed_state }, trie }
834 }
835
836 #[inline]
838 pub fn trie_updates(&self) -> &TrieUpdates {
839 &self.trie
840 }
841
842 pub fn into_sealed_block(self) -> SealedBlock<N::Block> {
844 let block = Arc::unwrap_or_clone(self.block.recovered_block);
845 block.into_sealed_block()
846 }
847}
848
849#[derive(Debug)]
851pub enum NewCanonicalChain<N: NodePrimitives = EthPrimitives> {
852 Commit {
854 new: Vec<ExecutedBlockWithTrieUpdates<N>>,
856 },
857 Reorg {
860 new: Vec<ExecutedBlockWithTrieUpdates<N>>,
862 old: Vec<ExecutedBlock<N>>,
868 },
869}
870
871impl<N: NodePrimitives<SignedTx: SignedTransaction>> NewCanonicalChain<N> {
872 pub fn new_block_count(&self) -> usize {
874 match self {
875 Self::Commit { new } | Self::Reorg { new, .. } => new.len(),
876 }
877 }
878
879 pub fn reorged_block_count(&self) -> usize {
881 match self {
882 Self::Commit { .. } => 0,
883 Self::Reorg { old, .. } => old.len(),
884 }
885 }
886
887 pub fn to_chain_notification(&self) -> CanonStateNotification<N> {
889 match self {
890 Self::Commit { new } => {
891 let new = Arc::new(new.iter().fold(Chain::default(), |mut chain, exec| {
892 chain.append_block(
893 exec.recovered_block().clone(),
894 exec.execution_outcome().clone(),
895 );
896 chain
897 }));
898 CanonStateNotification::Commit { new }
899 }
900 Self::Reorg { new, old } => {
901 let new = Arc::new(new.iter().fold(Chain::default(), |mut chain, exec| {
902 chain.append_block(
903 exec.recovered_block().clone(),
904 exec.execution_outcome().clone(),
905 );
906 chain
907 }));
908 let old = Arc::new(old.iter().fold(Chain::default(), |mut chain, exec| {
909 chain.append_block(
910 exec.recovered_block().clone(),
911 exec.execution_outcome().clone(),
912 );
913 chain
914 }));
915 CanonStateNotification::Reorg { new, old }
916 }
917 }
918 }
919
920 pub fn tip(&self) -> &SealedBlock<N::Block> {
925 match self {
926 Self::Commit { new } | Self::Reorg { new, .. } => {
927 new.last().expect("non empty blocks").recovered_block()
928 }
929 }
930 }
931}
932
933#[cfg(test)]
934mod tests {
935 use super::*;
936 use crate::test_utils::TestBlockBuilder;
937 use alloy_eips::eip7685::Requests;
938 use alloy_primitives::{Address, BlockNumber, Bytes, StorageKey};
939 use rand::Rng;
940 use reth_errors::ProviderResult;
941 use reth_ethereum_primitives::{EthPrimitives, Receipt};
942 use reth_primitives_traits::{Account, Bytecode};
943 use reth_storage_api::{
944 AccountReader, BlockHashReader, HashedPostStateProvider, StateProofProvider, StateProvider,
945 StateRootProvider, StorageRootProvider,
946 };
947 use reth_trie::{
948 AccountProof, HashedStorage, MultiProof, MultiProofTargets, StorageMultiProof,
949 StorageProof, TrieInput,
950 };
951 use revm_state::FlaggedStorage;
952
953 fn create_mock_state(
954 test_block_builder: &mut TestBlockBuilder<EthPrimitives>,
955 block_number: u64,
956 parent_hash: B256,
957 ) -> BlockState {
958 BlockState::new(
959 test_block_builder.get_executed_block_with_number(block_number, parent_hash),
960 )
961 }
962
963 fn create_mock_state_chain(
964 test_block_builder: &mut TestBlockBuilder<EthPrimitives>,
965 num_blocks: u64,
966 ) -> Vec<BlockState> {
967 let mut chain = Vec::with_capacity(num_blocks as usize);
968 let mut parent_hash = B256::random();
969 let mut parent_state: Option<BlockState> = None;
970
971 for i in 1..=num_blocks {
972 let mut state = create_mock_state(test_block_builder, i, parent_hash);
973 if let Some(parent) = parent_state {
974 state.parent = Some(Arc::new(parent));
975 }
976 parent_hash = state.hash();
977 parent_state = Some(state.clone());
978 chain.push(state);
979 }
980
981 chain
982 }
983
984 struct MockStateProvider;
985
986 impl StateProvider for MockStateProvider {
987 fn storage(
988 &self,
989 _address: Address,
990 _storage_key: StorageKey,
991 ) -> ProviderResult<Option<FlaggedStorage>> {
992 Ok(None)
993 }
994
995 fn bytecode_by_hash(&self, _code_hash: &B256) -> ProviderResult<Option<Bytecode>> {
996 Ok(None)
997 }
998 }
999
1000 impl BlockHashReader for MockStateProvider {
1001 fn block_hash(&self, _number: BlockNumber) -> ProviderResult<Option<B256>> {
1002 Ok(None)
1003 }
1004
1005 fn canonical_hashes_range(
1006 &self,
1007 _start: BlockNumber,
1008 _end: BlockNumber,
1009 ) -> ProviderResult<Vec<B256>> {
1010 Ok(vec![])
1011 }
1012 }
1013
1014 impl AccountReader for MockStateProvider {
1015 fn basic_account(&self, _address: &Address) -> ProviderResult<Option<Account>> {
1016 Ok(None)
1017 }
1018 }
1019
1020 impl StateRootProvider for MockStateProvider {
1021 fn state_root(&self, _hashed_state: HashedPostState) -> ProviderResult<B256> {
1022 Ok(B256::random())
1023 }
1024
1025 fn state_root_from_nodes(&self, _input: TrieInput) -> ProviderResult<B256> {
1026 Ok(B256::random())
1027 }
1028
1029 fn state_root_with_updates(
1030 &self,
1031 _hashed_state: HashedPostState,
1032 ) -> ProviderResult<(B256, TrieUpdates)> {
1033 Ok((B256::random(), TrieUpdates::default()))
1034 }
1035
1036 fn state_root_from_nodes_with_updates(
1037 &self,
1038 _input: TrieInput,
1039 ) -> ProviderResult<(B256, TrieUpdates)> {
1040 Ok((B256::random(), TrieUpdates::default()))
1041 }
1042 }
1043
1044 impl HashedPostStateProvider for MockStateProvider {
1045 fn hashed_post_state(&self, _bundle_state: &revm_database::BundleState) -> HashedPostState {
1046 HashedPostState::default()
1047 }
1048 }
1049
1050 impl StorageRootProvider for MockStateProvider {
1051 fn storage_root(
1052 &self,
1053 _address: Address,
1054 _hashed_storage: HashedStorage,
1055 ) -> ProviderResult<B256> {
1056 Ok(B256::random())
1057 }
1058
1059 fn storage_proof(
1060 &self,
1061 _address: Address,
1062 slot: B256,
1063 _hashed_storage: HashedStorage,
1064 ) -> ProviderResult<StorageProof> {
1065 Ok(StorageProof::new(slot))
1066 }
1067
1068 fn storage_multiproof(
1069 &self,
1070 _address: Address,
1071 _slots: &[B256],
1072 _hashed_storage: HashedStorage,
1073 ) -> ProviderResult<StorageMultiProof> {
1074 Ok(StorageMultiProof::empty())
1075 }
1076 }
1077
1078 impl StateProofProvider for MockStateProvider {
1079 fn proof(
1080 &self,
1081 _input: TrieInput,
1082 _address: Address,
1083 _slots: &[B256],
1084 ) -> ProviderResult<AccountProof> {
1085 Ok(AccountProof::new(Address::random()))
1086 }
1087
1088 fn multiproof(
1089 &self,
1090 _input: TrieInput,
1091 _targets: MultiProofTargets,
1092 ) -> ProviderResult<MultiProof> {
1093 Ok(MultiProof::default())
1094 }
1095
1096 fn witness(
1097 &self,
1098 _input: TrieInput,
1099 _target: HashedPostState,
1100 ) -> ProviderResult<Vec<Bytes>> {
1101 Ok(Vec::default())
1102 }
1103 }
1104
1105 #[test]
1106 fn test_in_memory_state_impl_state_by_hash() {
1107 let mut state_by_hash = HashMap::default();
1108 let number = rand::rng().random::<u64>();
1109 let mut test_block_builder: TestBlockBuilder = TestBlockBuilder::default();
1110 let state = Arc::new(create_mock_state(&mut test_block_builder, number, B256::random()));
1111 state_by_hash.insert(state.hash(), state.clone());
1112
1113 let in_memory_state = InMemoryState::new(state_by_hash, BTreeMap::new(), None);
1114
1115 assert_eq!(in_memory_state.state_by_hash(state.hash()), Some(state));
1116 assert_eq!(in_memory_state.state_by_hash(B256::random()), None);
1117 }
1118
1119 #[test]
1120 fn test_in_memory_state_impl_state_by_number() {
1121 let mut state_by_hash = HashMap::default();
1122 let mut hash_by_number = BTreeMap::new();
1123
1124 let number = rand::rng().random::<u64>();
1125 let mut test_block_builder: TestBlockBuilder = TestBlockBuilder::default();
1126 let state = Arc::new(create_mock_state(&mut test_block_builder, number, B256::random()));
1127 let hash = state.hash();
1128
1129 state_by_hash.insert(hash, state.clone());
1130 hash_by_number.insert(number, hash);
1131
1132 let in_memory_state = InMemoryState::new(state_by_hash, hash_by_number, None);
1133
1134 assert_eq!(in_memory_state.state_by_number(number), Some(state));
1135 assert_eq!(in_memory_state.state_by_number(number + 1), None);
1136 }
1137
1138 #[test]
1139 fn test_in_memory_state_impl_head_state() {
1140 let mut state_by_hash = HashMap::default();
1141 let mut hash_by_number = BTreeMap::new();
1142 let mut test_block_builder: TestBlockBuilder = TestBlockBuilder::default();
1143 let state1 = Arc::new(create_mock_state(&mut test_block_builder, 1, B256::random()));
1144 let hash1 = state1.hash();
1145 let state2 = Arc::new(create_mock_state(&mut test_block_builder, 2, hash1));
1146 let hash2 = state2.hash();
1147 hash_by_number.insert(1, hash1);
1148 hash_by_number.insert(2, hash2);
1149 state_by_hash.insert(hash1, state1);
1150 state_by_hash.insert(hash2, state2);
1151
1152 let in_memory_state = InMemoryState::new(state_by_hash, hash_by_number, None);
1153 let head_state = in_memory_state.head_state().unwrap();
1154
1155 assert_eq!(head_state.hash(), hash2);
1156 assert_eq!(head_state.number(), 2);
1157 }
1158
1159 #[test]
1160 fn test_in_memory_state_impl_pending_state() {
1161 let pending_number = rand::rng().random::<u64>();
1162 let mut test_block_builder: TestBlockBuilder = TestBlockBuilder::default();
1163 let pending_state =
1164 create_mock_state(&mut test_block_builder, pending_number, B256::random());
1165 let pending_hash = pending_state.hash();
1166
1167 let in_memory_state =
1168 InMemoryState::new(HashMap::default(), BTreeMap::new(), Some(pending_state));
1169
1170 let result = in_memory_state.pending_state();
1171 assert!(result.is_some());
1172 let actual_pending_state = result.unwrap();
1173 assert_eq!(actual_pending_state.block.recovered_block().hash(), pending_hash);
1174 assert_eq!(actual_pending_state.block.recovered_block().number, pending_number);
1175 }
1176
1177 #[test]
1178 fn test_in_memory_state_impl_no_pending_state() {
1179 let in_memory_state: InMemoryState =
1180 InMemoryState::new(HashMap::default(), BTreeMap::new(), None);
1181
1182 assert_eq!(in_memory_state.pending_state(), None);
1183 }
1184
1185 #[test]
1186 fn test_state() {
1187 let number = rand::rng().random::<u64>();
1188 let mut test_block_builder: TestBlockBuilder = TestBlockBuilder::default();
1189 let block = test_block_builder.get_executed_block_with_number(number, B256::random());
1190
1191 let state = BlockState::new(block.clone());
1192
1193 assert_eq!(state.block(), block);
1194 assert_eq!(state.hash(), block.recovered_block().hash());
1195 assert_eq!(state.number(), number);
1196 assert_eq!(state.state_root(), block.recovered_block().state_root);
1197 }
1198
1199 #[test]
1200 fn test_state_receipts() {
1201 let receipts = vec![vec![Receipt::default()]];
1202 let mut test_block_builder: TestBlockBuilder = TestBlockBuilder::default();
1203 let block =
1204 test_block_builder.get_executed_block_with_receipts(receipts.clone(), B256::random());
1205
1206 let state = BlockState::new(block);
1207
1208 assert_eq!(state.receipts(), &receipts);
1209 }
1210
1211 #[test]
1212 fn test_in_memory_state_chain_update() {
1213 let state: CanonicalInMemoryState = CanonicalInMemoryState::empty();
1214 let mut test_block_builder: TestBlockBuilder = TestBlockBuilder::default();
1215 let block1 = test_block_builder.get_executed_block_with_number(0, B256::random());
1216 let block2 = test_block_builder.get_executed_block_with_number(0, B256::random());
1217 let chain = NewCanonicalChain::Commit { new: vec![block1.clone()] };
1218 state.update_chain(chain);
1219 assert_eq!(
1220 state.head_state().unwrap().block_ref().recovered_block().hash(),
1221 block1.recovered_block().hash()
1222 );
1223 assert_eq!(
1224 state.state_by_number(0).unwrap().block_ref().recovered_block().hash(),
1225 block1.recovered_block().hash()
1226 );
1227
1228 let chain = NewCanonicalChain::Reorg { new: vec![block2.clone()], old: vec![block1.block] };
1229 state.update_chain(chain);
1230 assert_eq!(
1231 state.head_state().unwrap().block_ref().recovered_block().hash(),
1232 block2.recovered_block().hash()
1233 );
1234 assert_eq!(
1235 state.state_by_number(0).unwrap().block_ref().recovered_block().hash(),
1236 block2.recovered_block().hash()
1237 );
1238
1239 assert_eq!(state.inner.in_memory_state.block_count(), 1);
1240 }
1241
1242 #[test]
1243 fn test_in_memory_state_set_pending_block() {
1244 let state: CanonicalInMemoryState = CanonicalInMemoryState::empty();
1245 let mut test_block_builder: TestBlockBuilder = TestBlockBuilder::default();
1246
1247 let block1 = test_block_builder.get_executed_block_with_number(0, B256::random());
1249
1250 let block2 =
1252 test_block_builder.get_executed_block_with_number(1, block1.recovered_block().hash());
1253
1254 let chain = NewCanonicalChain::Commit { new: vec![block1.clone(), block2.clone()] };
1256 state.update_chain(chain);
1257
1258 assert!(state.pending_state().is_none());
1260
1261 state.set_pending_block(block2.clone());
1263
1264 assert_eq!(
1266 state.pending_state().unwrap(),
1267 BlockState::with_parent(block2.clone(), Some(Arc::new(BlockState::new(block1))))
1268 );
1269
1270 assert_eq!(state.pending_block().unwrap(), block2.recovered_block().sealed_block().clone());
1272
1273 assert_eq!(
1275 state.pending_block_num_hash().unwrap(),
1276 BlockNumHash { number: 1, hash: block2.recovered_block().hash() }
1277 );
1278
1279 assert_eq!(state.pending_header().unwrap(), block2.recovered_block().header().clone());
1281
1282 assert_eq!(
1284 state.pending_sealed_header().unwrap(),
1285 block2.recovered_block().clone_sealed_header()
1286 );
1287
1288 assert_eq!(state.pending_recovered_block().unwrap(), block2.recovered_block().clone());
1290
1291 assert_eq!(
1293 state.pending_block_and_receipts().unwrap(),
1294 (block2.recovered_block().sealed_block().clone(), vec![])
1295 );
1296 }
1297
1298 #[test]
1299 fn test_canonical_in_memory_state_state_provider() {
1300 let mut test_block_builder: TestBlockBuilder = TestBlockBuilder::default();
1301 let block1 = test_block_builder.get_executed_block_with_number(1, B256::random());
1302 let block2 =
1303 test_block_builder.get_executed_block_with_number(2, block1.recovered_block().hash());
1304 let block3 =
1305 test_block_builder.get_executed_block_with_number(3, block2.recovered_block().hash());
1306
1307 let state1 = Arc::new(BlockState::new(block1.clone()));
1308 let state2 = Arc::new(BlockState::with_parent(block2.clone(), Some(state1.clone())));
1309 let state3 = Arc::new(BlockState::with_parent(block3.clone(), Some(state2.clone())));
1310
1311 let mut blocks = HashMap::default();
1312 blocks.insert(block1.recovered_block().hash(), state1);
1313 blocks.insert(block2.recovered_block().hash(), state2);
1314 blocks.insert(block3.recovered_block().hash(), state3);
1315
1316 let mut numbers = BTreeMap::new();
1317 numbers.insert(1, block1.recovered_block().hash());
1318 numbers.insert(2, block2.recovered_block().hash());
1319 numbers.insert(3, block3.recovered_block().hash());
1320
1321 let canonical_state = CanonicalInMemoryState::new(blocks, numbers, None, None, None);
1322
1323 let historical: StateProviderBox = Box::new(MockStateProvider);
1324
1325 let overlay_provider =
1326 canonical_state.state_provider(block3.recovered_block().hash(), historical);
1327
1328 assert_eq!(overlay_provider.in_memory.len(), 3);
1329 assert_eq!(overlay_provider.in_memory[0].recovered_block().number, 3);
1330 assert_eq!(overlay_provider.in_memory[1].recovered_block().number, 2);
1331 assert_eq!(overlay_provider.in_memory[2].recovered_block().number, 1);
1332
1333 assert_eq!(
1334 overlay_provider.in_memory[0].recovered_block().parent_hash,
1335 overlay_provider.in_memory[1].recovered_block().hash()
1336 );
1337 assert_eq!(
1338 overlay_provider.in_memory[1].recovered_block().parent_hash,
1339 overlay_provider.in_memory[2].recovered_block().hash()
1340 );
1341
1342 let unknown_hash = B256::random();
1343 let empty_overlay_provider =
1344 canonical_state.state_provider(unknown_hash, Box::new(MockStateProvider));
1345 assert_eq!(empty_overlay_provider.in_memory.len(), 0);
1346 }
1347
1348 #[test]
1349 fn test_canonical_in_memory_state_canonical_chain_empty() {
1350 let state: CanonicalInMemoryState = CanonicalInMemoryState::empty();
1351 let chain: Vec<_> = state.canonical_chain().collect();
1352 assert!(chain.is_empty());
1353 }
1354
1355 #[test]
1356 fn test_canonical_in_memory_state_canonical_chain_single_block() {
1357 let block = TestBlockBuilder::eth().get_executed_block_with_number(1, B256::random());
1358 let hash = block.recovered_block().hash();
1359 let mut blocks = HashMap::default();
1360 blocks.insert(hash, Arc::new(BlockState::new(block)));
1361 let mut numbers = BTreeMap::new();
1362 numbers.insert(1, hash);
1363
1364 let state = CanonicalInMemoryState::new(blocks, numbers, None, None, None);
1365 let chain: Vec<_> = state.canonical_chain().collect();
1366
1367 assert_eq!(chain.len(), 1);
1368 assert_eq!(chain[0].number(), 1);
1369 assert_eq!(chain[0].hash(), hash);
1370 }
1371
1372 #[test]
1373 fn test_canonical_in_memory_state_canonical_chain_multiple_blocks() {
1374 let mut parent_hash = B256::random();
1375 let mut block_builder = TestBlockBuilder::eth();
1376 let state: CanonicalInMemoryState = CanonicalInMemoryState::empty();
1377
1378 for i in 1..=3 {
1379 let block = block_builder.get_executed_block_with_number(i, parent_hash);
1380 let hash = block.recovered_block().hash();
1381 state.update_blocks(Some(block), None);
1382 parent_hash = hash;
1383 }
1384
1385 let chain: Vec<_> = state.canonical_chain().collect();
1386
1387 assert_eq!(chain.len(), 3);
1388 assert_eq!(chain[0].number(), 3);
1389 assert_eq!(chain[1].number(), 2);
1390 assert_eq!(chain[2].number(), 1);
1391 }
1392
1393 #[test]
1395 fn test_canonical_in_memory_state_canonical_chain_with_pending_block() {
1396 let mut parent_hash = B256::random();
1397 let mut block_builder = TestBlockBuilder::<EthPrimitives>::eth();
1398 let state: CanonicalInMemoryState = CanonicalInMemoryState::empty();
1399
1400 for i in 1..=2 {
1401 let block = block_builder.get_executed_block_with_number(i, parent_hash);
1402 let hash = block.recovered_block().hash();
1403 state.update_blocks(Some(block), None);
1404 parent_hash = hash;
1405 }
1406
1407 let pending_block = block_builder.get_executed_block_with_number(3, parent_hash);
1408 state.set_pending_block(pending_block);
1409 let chain: Vec<_> = state.canonical_chain().collect();
1410
1411 assert_eq!(chain.len(), 2);
1412 assert_eq!(chain[0].number(), 2);
1413 assert_eq!(chain[1].number(), 1);
1414 }
1415
1416 #[test]
1417 fn test_block_state_parent_blocks() {
1418 let mut test_block_builder: TestBlockBuilder = TestBlockBuilder::default();
1419 let chain = create_mock_state_chain(&mut test_block_builder, 4);
1420
1421 let parents = chain[3].parent_state_chain();
1422 assert_eq!(parents.len(), 3);
1423 assert_eq!(parents[0].block().recovered_block().number, 3);
1424 assert_eq!(parents[1].block().recovered_block().number, 2);
1425 assert_eq!(parents[2].block().recovered_block().number, 1);
1426
1427 let parents = chain[2].parent_state_chain();
1428 assert_eq!(parents.len(), 2);
1429 assert_eq!(parents[0].block().recovered_block().number, 2);
1430 assert_eq!(parents[1].block().recovered_block().number, 1);
1431
1432 let parents = chain[0].parent_state_chain();
1433 assert_eq!(parents.len(), 0);
1434 }
1435
1436 #[test]
1437 fn test_block_state_single_block_state_chain() {
1438 let single_block_number = 1;
1439 let mut test_block_builder: TestBlockBuilder = TestBlockBuilder::default();
1440 let single_block =
1441 create_mock_state(&mut test_block_builder, single_block_number, B256::random());
1442 let single_block_hash = single_block.block().recovered_block().hash();
1443
1444 let parents = single_block.parent_state_chain();
1445 assert_eq!(parents.len(), 0);
1446
1447 let block_state_chain = single_block.chain().collect::<Vec<_>>();
1448 assert_eq!(block_state_chain.len(), 1);
1449 assert_eq!(block_state_chain[0].block().recovered_block().number, single_block_number);
1450 assert_eq!(block_state_chain[0].block().recovered_block().hash(), single_block_hash);
1451 }
1452
1453 #[test]
1454 fn test_block_state_chain() {
1455 let mut test_block_builder: TestBlockBuilder = TestBlockBuilder::default();
1456 let chain = create_mock_state_chain(&mut test_block_builder, 3);
1457
1458 let block_state_chain = chain[2].chain().collect::<Vec<_>>();
1459 assert_eq!(block_state_chain.len(), 3);
1460 assert_eq!(block_state_chain[0].block().recovered_block().number, 3);
1461 assert_eq!(block_state_chain[1].block().recovered_block().number, 2);
1462 assert_eq!(block_state_chain[2].block().recovered_block().number, 1);
1463
1464 let block_state_chain = chain[1].chain().collect::<Vec<_>>();
1465 assert_eq!(block_state_chain.len(), 2);
1466 assert_eq!(block_state_chain[0].block().recovered_block().number, 2);
1467 assert_eq!(block_state_chain[1].block().recovered_block().number, 1);
1468
1469 let block_state_chain = chain[0].chain().collect::<Vec<_>>();
1470 assert_eq!(block_state_chain.len(), 1);
1471 assert_eq!(block_state_chain[0].block().recovered_block().number, 1);
1472 }
1473
1474 #[test]
1475 fn test_to_chain_notification() {
1476 let mut test_block_builder: TestBlockBuilder = TestBlockBuilder::default();
1478 let block0 = test_block_builder.get_executed_block_with_number(0, B256::random());
1479 let block1 =
1480 test_block_builder.get_executed_block_with_number(1, block0.recovered_block.hash());
1481 let block1a =
1482 test_block_builder.get_executed_block_with_number(1, block0.recovered_block.hash());
1483 let block2 =
1484 test_block_builder.get_executed_block_with_number(2, block1.recovered_block.hash());
1485 let block2a =
1486 test_block_builder.get_executed_block_with_number(2, block1.recovered_block.hash());
1487
1488 let sample_execution_outcome = ExecutionOutcome {
1489 receipts: vec![vec![], vec![]],
1490 requests: vec![Requests::default(), Requests::default()],
1491 ..Default::default()
1492 };
1493
1494 let chain_commit = NewCanonicalChain::Commit { new: vec![block0.clone(), block1.clone()] };
1496
1497 assert_eq!(
1498 chain_commit.to_chain_notification(),
1499 CanonStateNotification::Commit {
1500 new: Arc::new(Chain::new(
1501 vec![block0.recovered_block().clone(), block1.recovered_block().clone()],
1502 sample_execution_outcome.clone(),
1503 None
1504 ))
1505 }
1506 );
1507
1508 let chain_reorg = NewCanonicalChain::Reorg {
1510 new: vec![block1a.clone(), block2a.clone()],
1511 old: vec![block1.block.clone(), block2.block.clone()],
1512 };
1513
1514 assert_eq!(
1515 chain_reorg.to_chain_notification(),
1516 CanonStateNotification::Reorg {
1517 old: Arc::new(Chain::new(
1518 vec![block1.recovered_block().clone(), block2.recovered_block().clone()],
1519 sample_execution_outcome.clone(),
1520 None
1521 )),
1522 new: Arc::new(Chain::new(
1523 vec![block1a.recovered_block().clone(), block2a.recovered_block().clone()],
1524 sample_execution_outcome,
1525 None
1526 ))
1527 }
1528 );
1529 }
1530}