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, StorageValue};
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
952 fn create_mock_state(
953 test_block_builder: &mut TestBlockBuilder<EthPrimitives>,
954 block_number: u64,
955 parent_hash: B256,
956 ) -> BlockState {
957 BlockState::new(
958 test_block_builder.get_executed_block_with_number(block_number, parent_hash),
959 )
960 }
961
962 fn create_mock_state_chain(
963 test_block_builder: &mut TestBlockBuilder<EthPrimitives>,
964 num_blocks: u64,
965 ) -> Vec<BlockState> {
966 let mut chain = Vec::with_capacity(num_blocks as usize);
967 let mut parent_hash = B256::random();
968 let mut parent_state: Option<BlockState> = None;
969
970 for i in 1..=num_blocks {
971 let mut state = create_mock_state(test_block_builder, i, parent_hash);
972 if let Some(parent) = parent_state {
973 state.parent = Some(Arc::new(parent));
974 }
975 parent_hash = state.hash();
976 parent_state = Some(state.clone());
977 chain.push(state);
978 }
979
980 chain
981 }
982
983 struct MockStateProvider;
984
985 impl StateProvider for MockStateProvider {
986 fn storage(
987 &self,
988 _address: Address,
989 _storage_key: StorageKey,
990 ) -> ProviderResult<Option<StorageValue>> {
991 Ok(None)
992 }
993
994 fn bytecode_by_hash(&self, _code_hash: &B256) -> ProviderResult<Option<Bytecode>> {
995 Ok(None)
996 }
997 }
998
999 impl BlockHashReader for MockStateProvider {
1000 fn block_hash(&self, _number: BlockNumber) -> ProviderResult<Option<B256>> {
1001 Ok(None)
1002 }
1003
1004 fn canonical_hashes_range(
1005 &self,
1006 _start: BlockNumber,
1007 _end: BlockNumber,
1008 ) -> ProviderResult<Vec<B256>> {
1009 Ok(vec![])
1010 }
1011 }
1012
1013 impl AccountReader for MockStateProvider {
1014 fn basic_account(&self, _address: &Address) -> ProviderResult<Option<Account>> {
1015 Ok(None)
1016 }
1017 }
1018
1019 impl StateRootProvider for MockStateProvider {
1020 fn state_root(&self, _hashed_state: HashedPostState) -> ProviderResult<B256> {
1021 Ok(B256::random())
1022 }
1023
1024 fn state_root_from_nodes(&self, _input: TrieInput) -> ProviderResult<B256> {
1025 Ok(B256::random())
1026 }
1027
1028 fn state_root_with_updates(
1029 &self,
1030 _hashed_state: HashedPostState,
1031 ) -> ProviderResult<(B256, TrieUpdates)> {
1032 Ok((B256::random(), TrieUpdates::default()))
1033 }
1034
1035 fn state_root_from_nodes_with_updates(
1036 &self,
1037 _input: TrieInput,
1038 ) -> ProviderResult<(B256, TrieUpdates)> {
1039 Ok((B256::random(), TrieUpdates::default()))
1040 }
1041 }
1042
1043 impl HashedPostStateProvider for MockStateProvider {
1044 fn hashed_post_state(&self, _bundle_state: &revm_database::BundleState) -> HashedPostState {
1045 HashedPostState::default()
1046 }
1047 }
1048
1049 impl StorageRootProvider for MockStateProvider {
1050 fn storage_root(
1051 &self,
1052 _address: Address,
1053 _hashed_storage: HashedStorage,
1054 ) -> ProviderResult<B256> {
1055 Ok(B256::random())
1056 }
1057
1058 fn storage_proof(
1059 &self,
1060 _address: Address,
1061 slot: B256,
1062 _hashed_storage: HashedStorage,
1063 ) -> ProviderResult<StorageProof> {
1064 Ok(StorageProof::new(slot))
1065 }
1066
1067 fn storage_multiproof(
1068 &self,
1069 _address: Address,
1070 _slots: &[B256],
1071 _hashed_storage: HashedStorage,
1072 ) -> ProviderResult<StorageMultiProof> {
1073 Ok(StorageMultiProof::empty())
1074 }
1075 }
1076
1077 impl StateProofProvider for MockStateProvider {
1078 fn proof(
1079 &self,
1080 _input: TrieInput,
1081 _address: Address,
1082 _slots: &[B256],
1083 ) -> ProviderResult<AccountProof> {
1084 Ok(AccountProof::new(Address::random()))
1085 }
1086
1087 fn multiproof(
1088 &self,
1089 _input: TrieInput,
1090 _targets: MultiProofTargets,
1091 ) -> ProviderResult<MultiProof> {
1092 Ok(MultiProof::default())
1093 }
1094
1095 fn witness(
1096 &self,
1097 _input: TrieInput,
1098 _target: HashedPostState,
1099 ) -> ProviderResult<Vec<Bytes>> {
1100 Ok(Vec::default())
1101 }
1102 }
1103
1104 #[test]
1105 fn test_in_memory_state_impl_state_by_hash() {
1106 let mut state_by_hash = HashMap::default();
1107 let number = rand::rng().random::<u64>();
1108 let mut test_block_builder: TestBlockBuilder = TestBlockBuilder::default();
1109 let state = Arc::new(create_mock_state(&mut test_block_builder, number, B256::random()));
1110 state_by_hash.insert(state.hash(), state.clone());
1111
1112 let in_memory_state = InMemoryState::new(state_by_hash, BTreeMap::new(), None);
1113
1114 assert_eq!(in_memory_state.state_by_hash(state.hash()), Some(state));
1115 assert_eq!(in_memory_state.state_by_hash(B256::random()), None);
1116 }
1117
1118 #[test]
1119 fn test_in_memory_state_impl_state_by_number() {
1120 let mut state_by_hash = HashMap::default();
1121 let mut hash_by_number = BTreeMap::new();
1122
1123 let number = rand::rng().random::<u64>();
1124 let mut test_block_builder: TestBlockBuilder = TestBlockBuilder::default();
1125 let state = Arc::new(create_mock_state(&mut test_block_builder, number, B256::random()));
1126 let hash = state.hash();
1127
1128 state_by_hash.insert(hash, state.clone());
1129 hash_by_number.insert(number, hash);
1130
1131 let in_memory_state = InMemoryState::new(state_by_hash, hash_by_number, None);
1132
1133 assert_eq!(in_memory_state.state_by_number(number), Some(state));
1134 assert_eq!(in_memory_state.state_by_number(number + 1), None);
1135 }
1136
1137 #[test]
1138 fn test_in_memory_state_impl_head_state() {
1139 let mut state_by_hash = HashMap::default();
1140 let mut hash_by_number = BTreeMap::new();
1141 let mut test_block_builder: TestBlockBuilder = TestBlockBuilder::default();
1142 let state1 = Arc::new(create_mock_state(&mut test_block_builder, 1, B256::random()));
1143 let hash1 = state1.hash();
1144 let state2 = Arc::new(create_mock_state(&mut test_block_builder, 2, hash1));
1145 let hash2 = state2.hash();
1146 hash_by_number.insert(1, hash1);
1147 hash_by_number.insert(2, hash2);
1148 state_by_hash.insert(hash1, state1);
1149 state_by_hash.insert(hash2, state2);
1150
1151 let in_memory_state = InMemoryState::new(state_by_hash, hash_by_number, None);
1152 let head_state = in_memory_state.head_state().unwrap();
1153
1154 assert_eq!(head_state.hash(), hash2);
1155 assert_eq!(head_state.number(), 2);
1156 }
1157
1158 #[test]
1159 fn test_in_memory_state_impl_pending_state() {
1160 let pending_number = rand::rng().random::<u64>();
1161 let mut test_block_builder: TestBlockBuilder = TestBlockBuilder::default();
1162 let pending_state =
1163 create_mock_state(&mut test_block_builder, pending_number, B256::random());
1164 let pending_hash = pending_state.hash();
1165
1166 let in_memory_state =
1167 InMemoryState::new(HashMap::default(), BTreeMap::new(), Some(pending_state));
1168
1169 let result = in_memory_state.pending_state();
1170 assert!(result.is_some());
1171 let actual_pending_state = result.unwrap();
1172 assert_eq!(actual_pending_state.block.recovered_block().hash(), pending_hash);
1173 assert_eq!(actual_pending_state.block.recovered_block().number, pending_number);
1174 }
1175
1176 #[test]
1177 fn test_in_memory_state_impl_no_pending_state() {
1178 let in_memory_state: InMemoryState =
1179 InMemoryState::new(HashMap::default(), BTreeMap::new(), None);
1180
1181 assert_eq!(in_memory_state.pending_state(), None);
1182 }
1183
1184 #[test]
1185 fn test_state() {
1186 let number = rand::rng().random::<u64>();
1187 let mut test_block_builder: TestBlockBuilder = TestBlockBuilder::default();
1188 let block = test_block_builder.get_executed_block_with_number(number, B256::random());
1189
1190 let state = BlockState::new(block.clone());
1191
1192 assert_eq!(state.block(), block);
1193 assert_eq!(state.hash(), block.recovered_block().hash());
1194 assert_eq!(state.number(), number);
1195 assert_eq!(state.state_root(), block.recovered_block().state_root);
1196 }
1197
1198 #[test]
1199 fn test_state_receipts() {
1200 let receipts = vec![vec![Receipt::default()]];
1201 let mut test_block_builder: TestBlockBuilder = TestBlockBuilder::default();
1202 let block =
1203 test_block_builder.get_executed_block_with_receipts(receipts.clone(), B256::random());
1204
1205 let state = BlockState::new(block);
1206
1207 assert_eq!(state.receipts(), &receipts);
1208 }
1209
1210 #[test]
1211 fn test_in_memory_state_chain_update() {
1212 let state: CanonicalInMemoryState = CanonicalInMemoryState::empty();
1213 let mut test_block_builder: TestBlockBuilder = TestBlockBuilder::default();
1214 let block1 = test_block_builder.get_executed_block_with_number(0, B256::random());
1215 let block2 = test_block_builder.get_executed_block_with_number(0, B256::random());
1216 let chain = NewCanonicalChain::Commit { new: vec![block1.clone()] };
1217 state.update_chain(chain);
1218 assert_eq!(
1219 state.head_state().unwrap().block_ref().recovered_block().hash(),
1220 block1.recovered_block().hash()
1221 );
1222 assert_eq!(
1223 state.state_by_number(0).unwrap().block_ref().recovered_block().hash(),
1224 block1.recovered_block().hash()
1225 );
1226
1227 let chain = NewCanonicalChain::Reorg { new: vec![block2.clone()], old: vec![block1.block] };
1228 state.update_chain(chain);
1229 assert_eq!(
1230 state.head_state().unwrap().block_ref().recovered_block().hash(),
1231 block2.recovered_block().hash()
1232 );
1233 assert_eq!(
1234 state.state_by_number(0).unwrap().block_ref().recovered_block().hash(),
1235 block2.recovered_block().hash()
1236 );
1237
1238 assert_eq!(state.inner.in_memory_state.block_count(), 1);
1239 }
1240
1241 #[test]
1242 fn test_in_memory_state_set_pending_block() {
1243 let state: CanonicalInMemoryState = CanonicalInMemoryState::empty();
1244 let mut test_block_builder: TestBlockBuilder = TestBlockBuilder::default();
1245
1246 let block1 = test_block_builder.get_executed_block_with_number(0, B256::random());
1248
1249 let block2 =
1251 test_block_builder.get_executed_block_with_number(1, block1.recovered_block().hash());
1252
1253 let chain = NewCanonicalChain::Commit { new: vec![block1.clone(), block2.clone()] };
1255 state.update_chain(chain);
1256
1257 assert!(state.pending_state().is_none());
1259
1260 state.set_pending_block(block2.clone());
1262
1263 assert_eq!(
1265 state.pending_state().unwrap(),
1266 BlockState::with_parent(block2.clone(), Some(Arc::new(BlockState::new(block1))))
1267 );
1268
1269 assert_eq!(state.pending_block().unwrap(), block2.recovered_block().sealed_block().clone());
1271
1272 assert_eq!(
1274 state.pending_block_num_hash().unwrap(),
1275 BlockNumHash { number: 1, hash: block2.recovered_block().hash() }
1276 );
1277
1278 assert_eq!(state.pending_header().unwrap(), block2.recovered_block().header().clone());
1280
1281 assert_eq!(
1283 state.pending_sealed_header().unwrap(),
1284 block2.recovered_block().clone_sealed_header()
1285 );
1286
1287 assert_eq!(state.pending_recovered_block().unwrap(), block2.recovered_block().clone());
1289
1290 assert_eq!(
1292 state.pending_block_and_receipts().unwrap(),
1293 (block2.recovered_block().sealed_block().clone(), vec![])
1294 );
1295 }
1296
1297 #[test]
1298 fn test_canonical_in_memory_state_state_provider() {
1299 let mut test_block_builder: TestBlockBuilder = TestBlockBuilder::default();
1300 let block1 = test_block_builder.get_executed_block_with_number(1, B256::random());
1301 let block2 =
1302 test_block_builder.get_executed_block_with_number(2, block1.recovered_block().hash());
1303 let block3 =
1304 test_block_builder.get_executed_block_with_number(3, block2.recovered_block().hash());
1305
1306 let state1 = Arc::new(BlockState::new(block1.clone()));
1307 let state2 = Arc::new(BlockState::with_parent(block2.clone(), Some(state1.clone())));
1308 let state3 = Arc::new(BlockState::with_parent(block3.clone(), Some(state2.clone())));
1309
1310 let mut blocks = HashMap::default();
1311 blocks.insert(block1.recovered_block().hash(), state1);
1312 blocks.insert(block2.recovered_block().hash(), state2);
1313 blocks.insert(block3.recovered_block().hash(), state3);
1314
1315 let mut numbers = BTreeMap::new();
1316 numbers.insert(1, block1.recovered_block().hash());
1317 numbers.insert(2, block2.recovered_block().hash());
1318 numbers.insert(3, block3.recovered_block().hash());
1319
1320 let canonical_state = CanonicalInMemoryState::new(blocks, numbers, None, None, None);
1321
1322 let historical: StateProviderBox = Box::new(MockStateProvider);
1323
1324 let overlay_provider =
1325 canonical_state.state_provider(block3.recovered_block().hash(), historical);
1326
1327 assert_eq!(overlay_provider.in_memory.len(), 3);
1328 assert_eq!(overlay_provider.in_memory[0].recovered_block().number, 3);
1329 assert_eq!(overlay_provider.in_memory[1].recovered_block().number, 2);
1330 assert_eq!(overlay_provider.in_memory[2].recovered_block().number, 1);
1331
1332 assert_eq!(
1333 overlay_provider.in_memory[0].recovered_block().parent_hash,
1334 overlay_provider.in_memory[1].recovered_block().hash()
1335 );
1336 assert_eq!(
1337 overlay_provider.in_memory[1].recovered_block().parent_hash,
1338 overlay_provider.in_memory[2].recovered_block().hash()
1339 );
1340
1341 let unknown_hash = B256::random();
1342 let empty_overlay_provider =
1343 canonical_state.state_provider(unknown_hash, Box::new(MockStateProvider));
1344 assert_eq!(empty_overlay_provider.in_memory.len(), 0);
1345 }
1346
1347 #[test]
1348 fn test_canonical_in_memory_state_canonical_chain_empty() {
1349 let state: CanonicalInMemoryState = CanonicalInMemoryState::empty();
1350 let chain: Vec<_> = state.canonical_chain().collect();
1351 assert!(chain.is_empty());
1352 }
1353
1354 #[test]
1355 fn test_canonical_in_memory_state_canonical_chain_single_block() {
1356 let block = TestBlockBuilder::eth().get_executed_block_with_number(1, B256::random());
1357 let hash = block.recovered_block().hash();
1358 let mut blocks = HashMap::default();
1359 blocks.insert(hash, Arc::new(BlockState::new(block)));
1360 let mut numbers = BTreeMap::new();
1361 numbers.insert(1, hash);
1362
1363 let state = CanonicalInMemoryState::new(blocks, numbers, None, None, None);
1364 let chain: Vec<_> = state.canonical_chain().collect();
1365
1366 assert_eq!(chain.len(), 1);
1367 assert_eq!(chain[0].number(), 1);
1368 assert_eq!(chain[0].hash(), hash);
1369 }
1370
1371 #[test]
1372 fn test_canonical_in_memory_state_canonical_chain_multiple_blocks() {
1373 let mut parent_hash = B256::random();
1374 let mut block_builder = TestBlockBuilder::eth();
1375 let state: CanonicalInMemoryState = CanonicalInMemoryState::empty();
1376
1377 for i in 1..=3 {
1378 let block = block_builder.get_executed_block_with_number(i, parent_hash);
1379 let hash = block.recovered_block().hash();
1380 state.update_blocks(Some(block), None);
1381 parent_hash = hash;
1382 }
1383
1384 let chain: Vec<_> = state.canonical_chain().collect();
1385
1386 assert_eq!(chain.len(), 3);
1387 assert_eq!(chain[0].number(), 3);
1388 assert_eq!(chain[1].number(), 2);
1389 assert_eq!(chain[2].number(), 1);
1390 }
1391
1392 #[test]
1394 fn test_canonical_in_memory_state_canonical_chain_with_pending_block() {
1395 let mut parent_hash = B256::random();
1396 let mut block_builder = TestBlockBuilder::<EthPrimitives>::eth();
1397 let state: CanonicalInMemoryState = CanonicalInMemoryState::empty();
1398
1399 for i in 1..=2 {
1400 let block = block_builder.get_executed_block_with_number(i, parent_hash);
1401 let hash = block.recovered_block().hash();
1402 state.update_blocks(Some(block), None);
1403 parent_hash = hash;
1404 }
1405
1406 let pending_block = block_builder.get_executed_block_with_number(3, parent_hash);
1407 state.set_pending_block(pending_block);
1408 let chain: Vec<_> = state.canonical_chain().collect();
1409
1410 assert_eq!(chain.len(), 2);
1411 assert_eq!(chain[0].number(), 2);
1412 assert_eq!(chain[1].number(), 1);
1413 }
1414
1415 #[test]
1416 fn test_block_state_parent_blocks() {
1417 let mut test_block_builder: TestBlockBuilder = TestBlockBuilder::default();
1418 let chain = create_mock_state_chain(&mut test_block_builder, 4);
1419
1420 let parents = chain[3].parent_state_chain();
1421 assert_eq!(parents.len(), 3);
1422 assert_eq!(parents[0].block().recovered_block().number, 3);
1423 assert_eq!(parents[1].block().recovered_block().number, 2);
1424 assert_eq!(parents[2].block().recovered_block().number, 1);
1425
1426 let parents = chain[2].parent_state_chain();
1427 assert_eq!(parents.len(), 2);
1428 assert_eq!(parents[0].block().recovered_block().number, 2);
1429 assert_eq!(parents[1].block().recovered_block().number, 1);
1430
1431 let parents = chain[0].parent_state_chain();
1432 assert_eq!(parents.len(), 0);
1433 }
1434
1435 #[test]
1436 fn test_block_state_single_block_state_chain() {
1437 let single_block_number = 1;
1438 let mut test_block_builder: TestBlockBuilder = TestBlockBuilder::default();
1439 let single_block =
1440 create_mock_state(&mut test_block_builder, single_block_number, B256::random());
1441 let single_block_hash = single_block.block().recovered_block().hash();
1442
1443 let parents = single_block.parent_state_chain();
1444 assert_eq!(parents.len(), 0);
1445
1446 let block_state_chain = single_block.chain().collect::<Vec<_>>();
1447 assert_eq!(block_state_chain.len(), 1);
1448 assert_eq!(block_state_chain[0].block().recovered_block().number, single_block_number);
1449 assert_eq!(block_state_chain[0].block().recovered_block().hash(), single_block_hash);
1450 }
1451
1452 #[test]
1453 fn test_block_state_chain() {
1454 let mut test_block_builder: TestBlockBuilder = TestBlockBuilder::default();
1455 let chain = create_mock_state_chain(&mut test_block_builder, 3);
1456
1457 let block_state_chain = chain[2].chain().collect::<Vec<_>>();
1458 assert_eq!(block_state_chain.len(), 3);
1459 assert_eq!(block_state_chain[0].block().recovered_block().number, 3);
1460 assert_eq!(block_state_chain[1].block().recovered_block().number, 2);
1461 assert_eq!(block_state_chain[2].block().recovered_block().number, 1);
1462
1463 let block_state_chain = chain[1].chain().collect::<Vec<_>>();
1464 assert_eq!(block_state_chain.len(), 2);
1465 assert_eq!(block_state_chain[0].block().recovered_block().number, 2);
1466 assert_eq!(block_state_chain[1].block().recovered_block().number, 1);
1467
1468 let block_state_chain = chain[0].chain().collect::<Vec<_>>();
1469 assert_eq!(block_state_chain.len(), 1);
1470 assert_eq!(block_state_chain[0].block().recovered_block().number, 1);
1471 }
1472
1473 #[test]
1474 fn test_to_chain_notification() {
1475 let mut test_block_builder: TestBlockBuilder = TestBlockBuilder::default();
1477 let block0 = test_block_builder.get_executed_block_with_number(0, B256::random());
1478 let block1 =
1479 test_block_builder.get_executed_block_with_number(1, block0.recovered_block.hash());
1480 let block1a =
1481 test_block_builder.get_executed_block_with_number(1, block0.recovered_block.hash());
1482 let block2 =
1483 test_block_builder.get_executed_block_with_number(2, block1.recovered_block.hash());
1484 let block2a =
1485 test_block_builder.get_executed_block_with_number(2, block1.recovered_block.hash());
1486
1487 let sample_execution_outcome = ExecutionOutcome {
1488 receipts: vec![vec![], vec![]],
1489 requests: vec![Requests::default(), Requests::default()],
1490 ..Default::default()
1491 };
1492
1493 let chain_commit = NewCanonicalChain::Commit { new: vec![block0.clone(), block1.clone()] };
1495
1496 assert_eq!(
1497 chain_commit.to_chain_notification(),
1498 CanonStateNotification::Commit {
1499 new: Arc::new(Chain::new(
1500 vec![block0.recovered_block().clone(), block1.recovered_block().clone()],
1501 sample_execution_outcome.clone(),
1502 None
1503 ))
1504 }
1505 );
1506
1507 let chain_reorg = NewCanonicalChain::Reorg {
1509 new: vec![block1a.clone(), block2a.clone()],
1510 old: vec![block1.block.clone(), block2.block.clone()],
1511 };
1512
1513 assert_eq!(
1514 chain_reorg.to_chain_notification(),
1515 CanonStateNotification::Reorg {
1516 old: Arc::new(Chain::new(
1517 vec![block1.recovered_block().clone(), block2.recovered_block().clone()],
1518 sample_execution_outcome.clone(),
1519 None
1520 )),
1521 new: Arc::new(Chain::new(
1522 vec![block1a.recovered_block().clone(), block2a.recovered_block().clone()],
1523 sample_execution_outcome,
1524 None
1525 ))
1526 }
1527 );
1528 }
1529}