1use crate::{
4 CanonStateNotification, CanonStateNotificationSender, CanonStateNotifications,
5 ChainInfoTracker, 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::TrieUpdates, HashedPostState};
21use std::{collections::BTreeMap, 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: ExecutedBlockWithTrieUpdates<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 = ExecutedBlockWithTrieUpdates<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, PartialEq, Eq, Clone)]
569pub struct BlockState<N: NodePrimitives = EthPrimitives> {
570 block: ExecutedBlockWithTrieUpdates<N>,
572 parent: Option<Arc<BlockState<N>>>,
574}
575
576impl<N: NodePrimitives> BlockState<N> {
577 pub const fn new(block: ExecutedBlockWithTrieUpdates<N>) -> Self {
579 Self { block, parent: None }
580 }
581
582 pub const fn with_parent(
584 block: ExecutedBlockWithTrieUpdates<N>,
585 parent: Option<Arc<Self>>,
586 ) -> Self {
587 Self { block, parent }
588 }
589
590 pub fn anchor(&self) -> BlockNumHash {
592 let mut current = self;
593 while let Some(parent) = ¤t.parent {
594 current = parent;
595 }
596 current.block.recovered_block().parent_num_hash()
597 }
598
599 pub fn block(&self) -> ExecutedBlockWithTrieUpdates<N> {
601 self.block.clone()
602 }
603
604 pub const fn block_ref(&self) -> &ExecutedBlockWithTrieUpdates<N> {
606 &self.block
607 }
608
609 pub fn hash(&self) -> B256 {
611 self.block.recovered_block().hash()
612 }
613
614 pub fn number(&self) -> u64 {
616 self.block.recovered_block().number()
617 }
618
619 pub fn state_root(&self) -> B256 {
622 self.block.recovered_block().state_root()
623 }
624
625 pub fn receipts(&self) -> &Vec<Vec<N::Receipt>> {
627 &self.block.execution_outcome().receipts
628 }
629
630 pub fn executed_block_receipts(&self) -> Vec<N::Receipt> {
635 let receipts = self.receipts();
636
637 debug_assert!(
638 receipts.len() <= 1,
639 "Expected at most one block's worth of receipts, found {}",
640 receipts.len()
641 );
642
643 receipts.first().cloned().unwrap_or_default()
644 }
645
646 pub fn parent_state_chain(&self) -> Vec<&Self> {
653 let mut parents = Vec::new();
654 let mut current = self.parent.as_deref();
655
656 while let Some(parent) = current {
657 parents.push(parent);
658 current = parent.parent.as_deref();
659 }
660
661 parents
662 }
663
664 pub fn chain(&self) -> impl Iterator<Item = &Self> {
668 std::iter::successors(Some(self), |state| state.parent.as_deref())
669 }
670
671 pub fn append_parent_chain<'a>(&'a self, chain: &mut Vec<&'a Self>) {
673 chain.extend(self.parent_state_chain());
674 }
675
676 pub fn iter(self: Arc<Self>) -> impl Iterator<Item = Arc<Self>> {
680 std::iter::successors(Some(self), |state| state.parent.clone())
681 }
682
683 pub fn state_provider(&self, historical: StateProviderBox) -> MemoryOverlayStateProvider<N> {
688 let in_memory = self.chain().map(|block_state| block_state.block()).collect();
689
690 MemoryOverlayStateProvider::new(historical, in_memory)
691 }
692
693 pub fn block_on_chain(&self, hash_or_num: BlockHashOrNumber) -> Option<&Self> {
695 self.chain().find(|block| match hash_or_num {
696 BlockHashOrNumber::Hash(hash) => block.hash() == hash,
697 BlockHashOrNumber::Number(number) => block.number() == number,
698 })
699 }
700
701 pub fn transaction_on_chain(&self, hash: TxHash) -> Option<N::SignedTx> {
703 self.chain().find_map(|block_state| {
704 block_state.block_ref().recovered_block().body().transaction_by_hash(&hash).cloned()
705 })
706 }
707
708 pub fn transaction_meta_on_chain(
710 &self,
711 tx_hash: TxHash,
712 ) -> Option<(N::SignedTx, TransactionMeta)> {
713 self.chain().find_map(|block_state| {
714 block_state.find_indexed(tx_hash).map(|indexed| (indexed.tx().clone(), indexed.meta()))
715 })
716 }
717
718 pub fn find_indexed(&self, tx_hash: TxHash) -> Option<IndexedTx<'_, N::Block>> {
720 self.block_ref().recovered_block().find_indexed(tx_hash)
721 }
722}
723
724#[derive(Clone, Debug, PartialEq, Eq)]
726pub struct ExecutedBlock<N: NodePrimitives = EthPrimitives> {
727 pub recovered_block: Arc<RecoveredBlock<N::Block>>,
729 pub execution_output: Arc<ExecutionOutcome<N::Receipt>>,
731 pub hashed_state: Arc<HashedPostState>,
733}
734
735impl<N: NodePrimitives> Default for ExecutedBlock<N> {
736 fn default() -> Self {
737 Self {
738 recovered_block: Default::default(),
739 execution_output: Default::default(),
740 hashed_state: Default::default(),
741 }
742 }
743}
744
745impl<N: NodePrimitives> ExecutedBlock<N> {
746 #[inline]
748 pub fn sealed_block(&self) -> &SealedBlock<N::Block> {
749 self.recovered_block.sealed_block()
750 }
751
752 #[inline]
754 pub fn recovered_block(&self) -> &RecoveredBlock<N::Block> {
755 &self.recovered_block
756 }
757
758 #[inline]
760 pub fn execution_outcome(&self) -> &ExecutionOutcome<N::Receipt> {
761 &self.execution_output
762 }
763
764 #[inline]
766 pub fn hashed_state(&self) -> &HashedPostState {
767 &self.hashed_state
768 }
769
770 #[inline]
772 pub fn block_number(&self) -> BlockNumber {
773 self.recovered_block.header().number()
774 }
775}
776
777#[derive(Debug, Clone, PartialEq, Eq)]
779pub enum ExecutedTrieUpdates {
780 Present(Arc<TrieUpdates>),
783 Missing,
791}
792
793impl ExecutedTrieUpdates {
794 pub fn empty() -> Self {
796 Self::Present(Arc::default())
797 }
798
799 pub fn set_present(&mut self, updates: Arc<TrieUpdates>) {
801 *self = Self::Present(updates);
802 }
803
804 pub fn take_present(&mut self) -> Option<Arc<TrieUpdates>> {
806 match self {
807 Self::Present(updates) => {
808 let updates = core::mem::take(updates);
809 *self = Self::Missing;
810 Some(updates)
811 }
812 Self::Missing => None,
813 }
814 }
815
816 #[allow(clippy::missing_const_for_fn)] pub fn as_ref(&self) -> Option<&TrieUpdates> {
819 match self {
820 Self::Present(updates) => Some(updates),
821 Self::Missing => None,
822 }
823 }
824
825 pub const fn is_present(&self) -> bool {
827 matches!(self, Self::Present(_))
828 }
829
830 pub const fn is_missing(&self) -> bool {
832 matches!(self, Self::Missing)
833 }
834}
835
836#[derive(
841 Clone, Debug, PartialEq, Eq, derive_more::Deref, derive_more::DerefMut, derive_more::Into,
842)]
843pub struct ExecutedBlockWithTrieUpdates<N: NodePrimitives = EthPrimitives> {
844 #[deref]
846 #[deref_mut]
847 #[into]
848 pub block: ExecutedBlock<N>,
849 pub trie: ExecutedTrieUpdates,
854}
855
856impl<N: NodePrimitives> ExecutedBlockWithTrieUpdates<N> {
857 pub const fn new(
859 recovered_block: Arc<RecoveredBlock<N::Block>>,
860 execution_output: Arc<ExecutionOutcome<N::Receipt>>,
861 hashed_state: Arc<HashedPostState>,
862 trie: ExecutedTrieUpdates,
863 ) -> Self {
864 Self { block: ExecutedBlock { recovered_block, execution_output, hashed_state }, trie }
865 }
866
867 #[inline]
869 pub fn trie_updates(&self) -> Option<&TrieUpdates> {
870 self.trie.as_ref()
871 }
872
873 pub fn into_sealed_block(self) -> SealedBlock<N::Block> {
875 let block = Arc::unwrap_or_clone(self.block.recovered_block);
876 block.into_sealed_block()
877 }
878}
879
880#[derive(Debug)]
882pub enum NewCanonicalChain<N: NodePrimitives = EthPrimitives> {
883 Commit {
885 new: Vec<ExecutedBlockWithTrieUpdates<N>>,
887 },
888 Reorg {
891 new: Vec<ExecutedBlockWithTrieUpdates<N>>,
893 old: Vec<ExecutedBlock<N>>,
899 },
900}
901
902impl<N: NodePrimitives<SignedTx: SignedTransaction>> NewCanonicalChain<N> {
903 pub const fn new_block_count(&self) -> usize {
905 match self {
906 Self::Commit { new } | Self::Reorg { new, .. } => new.len(),
907 }
908 }
909
910 pub const fn reorged_block_count(&self) -> usize {
912 match self {
913 Self::Commit { .. } => 0,
914 Self::Reorg { old, .. } => old.len(),
915 }
916 }
917
918 pub fn to_chain_notification(&self) -> CanonStateNotification<N> {
920 match self {
921 Self::Commit { new } => {
922 let new = Arc::new(new.iter().fold(Chain::default(), |mut chain, exec| {
923 chain.append_block(
924 exec.recovered_block().clone(),
925 exec.execution_outcome().clone(),
926 );
927 chain
928 }));
929 CanonStateNotification::Commit { new }
930 }
931 Self::Reorg { new, old } => {
932 let new = Arc::new(new.iter().fold(Chain::default(), |mut chain, exec| {
933 chain.append_block(
934 exec.recovered_block().clone(),
935 exec.execution_outcome().clone(),
936 );
937 chain
938 }));
939 let old = Arc::new(old.iter().fold(Chain::default(), |mut chain, exec| {
940 chain.append_block(
941 exec.recovered_block().clone(),
942 exec.execution_outcome().clone(),
943 );
944 chain
945 }));
946 CanonStateNotification::Reorg { new, old }
947 }
948 }
949 }
950
951 pub fn tip(&self) -> &SealedBlock<N::Block> {
956 match self {
957 Self::Commit { new } | Self::Reorg { new, .. } => {
958 new.last().expect("non empty blocks").recovered_block()
959 }
960 }
961 }
962}
963
964#[cfg(test)]
965mod tests {
966 use super::*;
967 use crate::test_utils::TestBlockBuilder;
968 use alloy_eips::eip7685::Requests;
969 use alloy_primitives::{Address, BlockNumber, Bytes, StorageKey, StorageValue};
970 use rand::Rng;
971 use reth_errors::ProviderResult;
972 use reth_ethereum_primitives::{EthPrimitives, Receipt};
973 use reth_primitives_traits::{Account, Bytecode};
974 use reth_storage_api::{
975 AccountReader, BlockHashReader, BytecodeReader, HashedPostStateProvider,
976 StateProofProvider, StateProvider, StateRootProvider, StorageRootProvider,
977 };
978 use reth_trie::{
979 AccountProof, HashedStorage, MultiProof, MultiProofTargets, StorageMultiProof,
980 StorageProof, TrieInput,
981 };
982
983 fn create_mock_state(
984 test_block_builder: &mut TestBlockBuilder<EthPrimitives>,
985 block_number: u64,
986 parent_hash: B256,
987 ) -> BlockState {
988 BlockState::new(
989 test_block_builder.get_executed_block_with_number(block_number, parent_hash),
990 )
991 }
992
993 fn create_mock_state_chain(
994 test_block_builder: &mut TestBlockBuilder<EthPrimitives>,
995 num_blocks: u64,
996 ) -> Vec<BlockState> {
997 let mut chain = Vec::with_capacity(num_blocks as usize);
998 let mut parent_hash = B256::random();
999 let mut parent_state: Option<BlockState> = None;
1000
1001 for i in 1..=num_blocks {
1002 let mut state = create_mock_state(test_block_builder, i, parent_hash);
1003 if let Some(parent) = parent_state {
1004 state.parent = Some(Arc::new(parent));
1005 }
1006 parent_hash = state.hash();
1007 parent_state = Some(state.clone());
1008 chain.push(state);
1009 }
1010
1011 chain
1012 }
1013
1014 struct MockStateProvider;
1015
1016 impl StateProvider for MockStateProvider {
1017 fn storage(
1018 &self,
1019 _address: Address,
1020 _storage_key: StorageKey,
1021 ) -> ProviderResult<Option<StorageValue>> {
1022 Ok(None)
1023 }
1024 }
1025
1026 impl BytecodeReader for MockStateProvider {
1027 fn bytecode_by_hash(&self, _code_hash: &B256) -> ProviderResult<Option<Bytecode>> {
1028 Ok(None)
1029 }
1030 }
1031
1032 impl BlockHashReader for MockStateProvider {
1033 fn block_hash(&self, _number: BlockNumber) -> ProviderResult<Option<B256>> {
1034 Ok(None)
1035 }
1036
1037 fn canonical_hashes_range(
1038 &self,
1039 _start: BlockNumber,
1040 _end: BlockNumber,
1041 ) -> ProviderResult<Vec<B256>> {
1042 Ok(vec![])
1043 }
1044 }
1045
1046 impl AccountReader for MockStateProvider {
1047 fn basic_account(&self, _address: &Address) -> ProviderResult<Option<Account>> {
1048 Ok(None)
1049 }
1050 }
1051
1052 impl StateRootProvider for MockStateProvider {
1053 fn state_root(&self, _hashed_state: HashedPostState) -> ProviderResult<B256> {
1054 Ok(B256::random())
1055 }
1056
1057 fn state_root_from_nodes(&self, _input: TrieInput) -> ProviderResult<B256> {
1058 Ok(B256::random())
1059 }
1060
1061 fn state_root_with_updates(
1062 &self,
1063 _hashed_state: HashedPostState,
1064 ) -> ProviderResult<(B256, TrieUpdates)> {
1065 Ok((B256::random(), TrieUpdates::default()))
1066 }
1067
1068 fn state_root_from_nodes_with_updates(
1069 &self,
1070 _input: TrieInput,
1071 ) -> ProviderResult<(B256, TrieUpdates)> {
1072 Ok((B256::random(), TrieUpdates::default()))
1073 }
1074 }
1075
1076 impl HashedPostStateProvider for MockStateProvider {
1077 fn hashed_post_state(&self, _bundle_state: &revm_database::BundleState) -> HashedPostState {
1078 HashedPostState::default()
1079 }
1080 }
1081
1082 impl StorageRootProvider for MockStateProvider {
1083 fn storage_root(
1084 &self,
1085 _address: Address,
1086 _hashed_storage: HashedStorage,
1087 ) -> ProviderResult<B256> {
1088 Ok(B256::random())
1089 }
1090
1091 fn storage_proof(
1092 &self,
1093 _address: Address,
1094 slot: B256,
1095 _hashed_storage: HashedStorage,
1096 ) -> ProviderResult<StorageProof> {
1097 Ok(StorageProof::new(slot))
1098 }
1099
1100 fn storage_multiproof(
1101 &self,
1102 _address: Address,
1103 _slots: &[B256],
1104 _hashed_storage: HashedStorage,
1105 ) -> ProviderResult<StorageMultiProof> {
1106 Ok(StorageMultiProof::empty())
1107 }
1108 }
1109
1110 impl StateProofProvider for MockStateProvider {
1111 fn proof(
1112 &self,
1113 _input: TrieInput,
1114 _address: Address,
1115 _slots: &[B256],
1116 ) -> ProviderResult<AccountProof> {
1117 Ok(AccountProof::new(Address::random()))
1118 }
1119
1120 fn multiproof(
1121 &self,
1122 _input: TrieInput,
1123 _targets: MultiProofTargets,
1124 ) -> ProviderResult<MultiProof> {
1125 Ok(MultiProof::default())
1126 }
1127
1128 fn witness(
1129 &self,
1130 _input: TrieInput,
1131 _target: HashedPostState,
1132 ) -> ProviderResult<Vec<Bytes>> {
1133 Ok(Vec::default())
1134 }
1135 }
1136
1137 #[test]
1138 fn test_in_memory_state_impl_state_by_hash() {
1139 let mut state_by_hash = HashMap::default();
1140 let number = rand::rng().random::<u64>();
1141 let mut test_block_builder: TestBlockBuilder = TestBlockBuilder::default();
1142 let state = Arc::new(create_mock_state(&mut test_block_builder, number, B256::random()));
1143 state_by_hash.insert(state.hash(), state.clone());
1144
1145 let in_memory_state = InMemoryState::new(state_by_hash, BTreeMap::new(), None);
1146
1147 assert_eq!(in_memory_state.state_by_hash(state.hash()), Some(state));
1148 assert_eq!(in_memory_state.state_by_hash(B256::random()), None);
1149 }
1150
1151 #[test]
1152 fn test_in_memory_state_impl_state_by_number() {
1153 let mut state_by_hash = HashMap::default();
1154 let mut hash_by_number = BTreeMap::new();
1155
1156 let number = rand::rng().random::<u64>();
1157 let mut test_block_builder: TestBlockBuilder = TestBlockBuilder::default();
1158 let state = Arc::new(create_mock_state(&mut test_block_builder, number, B256::random()));
1159 let hash = state.hash();
1160
1161 state_by_hash.insert(hash, state.clone());
1162 hash_by_number.insert(number, hash);
1163
1164 let in_memory_state = InMemoryState::new(state_by_hash, hash_by_number, None);
1165
1166 assert_eq!(in_memory_state.state_by_number(number), Some(state));
1167 assert_eq!(in_memory_state.state_by_number(number + 1), None);
1168 }
1169
1170 #[test]
1171 fn test_in_memory_state_impl_head_state() {
1172 let mut state_by_hash = HashMap::default();
1173 let mut hash_by_number = BTreeMap::new();
1174 let mut test_block_builder: TestBlockBuilder = TestBlockBuilder::default();
1175 let state1 = Arc::new(create_mock_state(&mut test_block_builder, 1, B256::random()));
1176 let hash1 = state1.hash();
1177 let state2 = Arc::new(create_mock_state(&mut test_block_builder, 2, hash1));
1178 let hash2 = state2.hash();
1179 hash_by_number.insert(1, hash1);
1180 hash_by_number.insert(2, hash2);
1181 state_by_hash.insert(hash1, state1);
1182 state_by_hash.insert(hash2, state2);
1183
1184 let in_memory_state = InMemoryState::new(state_by_hash, hash_by_number, None);
1185 let head_state = in_memory_state.head_state().unwrap();
1186
1187 assert_eq!(head_state.hash(), hash2);
1188 assert_eq!(head_state.number(), 2);
1189 }
1190
1191 #[test]
1192 fn test_in_memory_state_impl_pending_state() {
1193 let pending_number = rand::rng().random::<u64>();
1194 let mut test_block_builder: TestBlockBuilder = TestBlockBuilder::default();
1195 let pending_state =
1196 create_mock_state(&mut test_block_builder, pending_number, B256::random());
1197 let pending_hash = pending_state.hash();
1198
1199 let in_memory_state =
1200 InMemoryState::new(HashMap::default(), BTreeMap::new(), Some(pending_state));
1201
1202 let result = in_memory_state.pending_state();
1203 assert!(result.is_some());
1204 let actual_pending_state = result.unwrap();
1205 assert_eq!(actual_pending_state.block.recovered_block().hash(), pending_hash);
1206 assert_eq!(actual_pending_state.block.recovered_block().number, pending_number);
1207 }
1208
1209 #[test]
1210 fn test_in_memory_state_impl_no_pending_state() {
1211 let in_memory_state: InMemoryState =
1212 InMemoryState::new(HashMap::default(), BTreeMap::new(), None);
1213
1214 assert_eq!(in_memory_state.pending_state(), None);
1215 }
1216
1217 #[test]
1218 fn test_state() {
1219 let number = rand::rng().random::<u64>();
1220 let mut test_block_builder: TestBlockBuilder = TestBlockBuilder::default();
1221 let block = test_block_builder.get_executed_block_with_number(number, B256::random());
1222
1223 let state = BlockState::new(block.clone());
1224
1225 assert_eq!(state.block(), block);
1226 assert_eq!(state.hash(), block.recovered_block().hash());
1227 assert_eq!(state.number(), number);
1228 assert_eq!(state.state_root(), block.recovered_block().state_root);
1229 }
1230
1231 #[test]
1232 fn test_state_receipts() {
1233 let receipts = vec![vec![Receipt::default()]];
1234 let mut test_block_builder: TestBlockBuilder = TestBlockBuilder::default();
1235 let block =
1236 test_block_builder.get_executed_block_with_receipts(receipts.clone(), B256::random());
1237
1238 let state = BlockState::new(block);
1239
1240 assert_eq!(state.receipts(), &receipts);
1241 }
1242
1243 #[test]
1244 fn test_in_memory_state_chain_update() {
1245 let state: CanonicalInMemoryState = CanonicalInMemoryState::empty();
1246 let mut test_block_builder: TestBlockBuilder = TestBlockBuilder::default();
1247 let block1 = test_block_builder.get_executed_block_with_number(0, B256::random());
1248 let block2 = test_block_builder.get_executed_block_with_number(0, B256::random());
1249 let chain = NewCanonicalChain::Commit { new: vec![block1.clone()] };
1250 state.update_chain(chain);
1251 assert_eq!(
1252 state.head_state().unwrap().block_ref().recovered_block().hash(),
1253 block1.recovered_block().hash()
1254 );
1255 assert_eq!(
1256 state.state_by_number(0).unwrap().block_ref().recovered_block().hash(),
1257 block1.recovered_block().hash()
1258 );
1259
1260 let chain = NewCanonicalChain::Reorg { new: vec![block2.clone()], old: vec![block1.block] };
1261 state.update_chain(chain);
1262 assert_eq!(
1263 state.head_state().unwrap().block_ref().recovered_block().hash(),
1264 block2.recovered_block().hash()
1265 );
1266 assert_eq!(
1267 state.state_by_number(0).unwrap().block_ref().recovered_block().hash(),
1268 block2.recovered_block().hash()
1269 );
1270
1271 assert_eq!(state.inner.in_memory_state.block_count(), 1);
1272 }
1273
1274 #[test]
1275 fn test_in_memory_state_set_pending_block() {
1276 let state: CanonicalInMemoryState = CanonicalInMemoryState::empty();
1277 let mut test_block_builder: TestBlockBuilder = TestBlockBuilder::default();
1278
1279 let block1 = test_block_builder.get_executed_block_with_number(0, B256::random());
1281
1282 let block2 =
1284 test_block_builder.get_executed_block_with_number(1, block1.recovered_block().hash());
1285
1286 let chain = NewCanonicalChain::Commit { new: vec![block1.clone(), block2.clone()] };
1288 state.update_chain(chain);
1289
1290 assert!(state.pending_state().is_none());
1292
1293 state.set_pending_block(block2.clone());
1295
1296 assert_eq!(
1298 state.pending_state().unwrap(),
1299 BlockState::with_parent(block2.clone(), Some(Arc::new(BlockState::new(block1))))
1300 );
1301
1302 assert_eq!(state.pending_block().unwrap(), block2.recovered_block().sealed_block().clone());
1304
1305 assert_eq!(
1307 state.pending_block_num_hash().unwrap(),
1308 BlockNumHash { number: 1, hash: block2.recovered_block().hash() }
1309 );
1310
1311 assert_eq!(state.pending_header().unwrap(), block2.recovered_block().header().clone());
1313
1314 assert_eq!(
1316 state.pending_sealed_header().unwrap(),
1317 block2.recovered_block().clone_sealed_header()
1318 );
1319
1320 assert_eq!(state.pending_recovered_block().unwrap(), block2.recovered_block().clone());
1322
1323 assert_eq!(
1325 state.pending_block_and_receipts().unwrap(),
1326 (block2.recovered_block().clone(), vec![])
1327 );
1328 }
1329
1330 #[test]
1331 fn test_canonical_in_memory_state_state_provider() {
1332 let mut test_block_builder: TestBlockBuilder = TestBlockBuilder::default();
1333 let block1 = test_block_builder.get_executed_block_with_number(1, B256::random());
1334 let block2 =
1335 test_block_builder.get_executed_block_with_number(2, block1.recovered_block().hash());
1336 let block3 =
1337 test_block_builder.get_executed_block_with_number(3, block2.recovered_block().hash());
1338
1339 let state1 = Arc::new(BlockState::new(block1.clone()));
1340 let state2 = Arc::new(BlockState::with_parent(block2.clone(), Some(state1.clone())));
1341 let state3 = Arc::new(BlockState::with_parent(block3.clone(), Some(state2.clone())));
1342
1343 let mut blocks = HashMap::default();
1344 blocks.insert(block1.recovered_block().hash(), state1);
1345 blocks.insert(block2.recovered_block().hash(), state2);
1346 blocks.insert(block3.recovered_block().hash(), state3);
1347
1348 let mut numbers = BTreeMap::new();
1349 numbers.insert(1, block1.recovered_block().hash());
1350 numbers.insert(2, block2.recovered_block().hash());
1351 numbers.insert(3, block3.recovered_block().hash());
1352
1353 let canonical_state = CanonicalInMemoryState::new(blocks, numbers, None, None, None);
1354
1355 let historical: StateProviderBox = Box::new(MockStateProvider);
1356
1357 let overlay_provider =
1358 canonical_state.state_provider(block3.recovered_block().hash(), historical);
1359
1360 assert_eq!(overlay_provider.in_memory.len(), 3);
1361 assert_eq!(overlay_provider.in_memory[0].recovered_block().number, 3);
1362 assert_eq!(overlay_provider.in_memory[1].recovered_block().number, 2);
1363 assert_eq!(overlay_provider.in_memory[2].recovered_block().number, 1);
1364
1365 assert_eq!(
1366 overlay_provider.in_memory[0].recovered_block().parent_hash,
1367 overlay_provider.in_memory[1].recovered_block().hash()
1368 );
1369 assert_eq!(
1370 overlay_provider.in_memory[1].recovered_block().parent_hash,
1371 overlay_provider.in_memory[2].recovered_block().hash()
1372 );
1373
1374 let unknown_hash = B256::random();
1375 let empty_overlay_provider =
1376 canonical_state.state_provider(unknown_hash, Box::new(MockStateProvider));
1377 assert_eq!(empty_overlay_provider.in_memory.len(), 0);
1378 }
1379
1380 #[test]
1381 fn test_canonical_in_memory_state_canonical_chain_empty() {
1382 let state: CanonicalInMemoryState = CanonicalInMemoryState::empty();
1383 let chain: Vec<_> = state.canonical_chain().collect();
1384 assert!(chain.is_empty());
1385 }
1386
1387 #[test]
1388 fn test_canonical_in_memory_state_canonical_chain_single_block() {
1389 let block = TestBlockBuilder::eth().get_executed_block_with_number(1, B256::random());
1390 let hash = block.recovered_block().hash();
1391 let mut blocks = HashMap::default();
1392 blocks.insert(hash, Arc::new(BlockState::new(block)));
1393 let mut numbers = BTreeMap::new();
1394 numbers.insert(1, hash);
1395
1396 let state = CanonicalInMemoryState::new(blocks, numbers, None, None, None);
1397 let chain: Vec<_> = state.canonical_chain().collect();
1398
1399 assert_eq!(chain.len(), 1);
1400 assert_eq!(chain[0].number(), 1);
1401 assert_eq!(chain[0].hash(), hash);
1402 }
1403
1404 #[test]
1405 fn test_canonical_in_memory_state_canonical_chain_multiple_blocks() {
1406 let mut parent_hash = B256::random();
1407 let mut block_builder = TestBlockBuilder::eth();
1408 let state: CanonicalInMemoryState = CanonicalInMemoryState::empty();
1409
1410 for i in 1..=3 {
1411 let block = block_builder.get_executed_block_with_number(i, parent_hash);
1412 let hash = block.recovered_block().hash();
1413 state.update_blocks(Some(block), None);
1414 parent_hash = hash;
1415 }
1416
1417 let chain: Vec<_> = state.canonical_chain().collect();
1418
1419 assert_eq!(chain.len(), 3);
1420 assert_eq!(chain[0].number(), 3);
1421 assert_eq!(chain[1].number(), 2);
1422 assert_eq!(chain[2].number(), 1);
1423 }
1424
1425 #[test]
1427 fn test_canonical_in_memory_state_canonical_chain_with_pending_block() {
1428 let mut parent_hash = B256::random();
1429 let mut block_builder = TestBlockBuilder::<EthPrimitives>::eth();
1430 let state: CanonicalInMemoryState = CanonicalInMemoryState::empty();
1431
1432 for i in 1..=2 {
1433 let block = block_builder.get_executed_block_with_number(i, parent_hash);
1434 let hash = block.recovered_block().hash();
1435 state.update_blocks(Some(block), None);
1436 parent_hash = hash;
1437 }
1438
1439 let pending_block = block_builder.get_executed_block_with_number(3, parent_hash);
1440 state.set_pending_block(pending_block);
1441 let chain: Vec<_> = state.canonical_chain().collect();
1442
1443 assert_eq!(chain.len(), 2);
1444 assert_eq!(chain[0].number(), 2);
1445 assert_eq!(chain[1].number(), 1);
1446 }
1447
1448 #[test]
1449 fn test_block_state_parent_blocks() {
1450 let mut test_block_builder: TestBlockBuilder = TestBlockBuilder::default();
1451 let chain = create_mock_state_chain(&mut test_block_builder, 4);
1452
1453 let parents = chain[3].parent_state_chain();
1454 assert_eq!(parents.len(), 3);
1455 assert_eq!(parents[0].block().recovered_block().number, 3);
1456 assert_eq!(parents[1].block().recovered_block().number, 2);
1457 assert_eq!(parents[2].block().recovered_block().number, 1);
1458
1459 let parents = chain[2].parent_state_chain();
1460 assert_eq!(parents.len(), 2);
1461 assert_eq!(parents[0].block().recovered_block().number, 2);
1462 assert_eq!(parents[1].block().recovered_block().number, 1);
1463
1464 let parents = chain[0].parent_state_chain();
1465 assert_eq!(parents.len(), 0);
1466 }
1467
1468 #[test]
1469 fn test_block_state_single_block_state_chain() {
1470 let single_block_number = 1;
1471 let mut test_block_builder: TestBlockBuilder = TestBlockBuilder::default();
1472 let single_block =
1473 create_mock_state(&mut test_block_builder, single_block_number, B256::random());
1474 let single_block_hash = single_block.block().recovered_block().hash();
1475
1476 let parents = single_block.parent_state_chain();
1477 assert_eq!(parents.len(), 0);
1478
1479 let block_state_chain = single_block.chain().collect::<Vec<_>>();
1480 assert_eq!(block_state_chain.len(), 1);
1481 assert_eq!(block_state_chain[0].block().recovered_block().number, single_block_number);
1482 assert_eq!(block_state_chain[0].block().recovered_block().hash(), single_block_hash);
1483 }
1484
1485 #[test]
1486 fn test_block_state_chain() {
1487 let mut test_block_builder: TestBlockBuilder = TestBlockBuilder::default();
1488 let chain = create_mock_state_chain(&mut test_block_builder, 3);
1489
1490 let block_state_chain = chain[2].chain().collect::<Vec<_>>();
1491 assert_eq!(block_state_chain.len(), 3);
1492 assert_eq!(block_state_chain[0].block().recovered_block().number, 3);
1493 assert_eq!(block_state_chain[1].block().recovered_block().number, 2);
1494 assert_eq!(block_state_chain[2].block().recovered_block().number, 1);
1495
1496 let block_state_chain = chain[1].chain().collect::<Vec<_>>();
1497 assert_eq!(block_state_chain.len(), 2);
1498 assert_eq!(block_state_chain[0].block().recovered_block().number, 2);
1499 assert_eq!(block_state_chain[1].block().recovered_block().number, 1);
1500
1501 let block_state_chain = chain[0].chain().collect::<Vec<_>>();
1502 assert_eq!(block_state_chain.len(), 1);
1503 assert_eq!(block_state_chain[0].block().recovered_block().number, 1);
1504 }
1505
1506 #[test]
1507 fn test_to_chain_notification() {
1508 let mut test_block_builder: TestBlockBuilder = TestBlockBuilder::default();
1510 let block0 = test_block_builder.get_executed_block_with_number(0, B256::random());
1511 let block1 =
1512 test_block_builder.get_executed_block_with_number(1, block0.recovered_block.hash());
1513 let block1a =
1514 test_block_builder.get_executed_block_with_number(1, block0.recovered_block.hash());
1515 let block2 =
1516 test_block_builder.get_executed_block_with_number(2, block1.recovered_block.hash());
1517 let block2a =
1518 test_block_builder.get_executed_block_with_number(2, block1.recovered_block.hash());
1519
1520 let sample_execution_outcome = ExecutionOutcome {
1521 receipts: vec![vec![], vec![]],
1522 requests: vec![Requests::default(), Requests::default()],
1523 ..Default::default()
1524 };
1525
1526 let chain_commit = NewCanonicalChain::Commit { new: vec![block0.clone(), block1.clone()] };
1528
1529 assert_eq!(
1530 chain_commit.to_chain_notification(),
1531 CanonStateNotification::Commit {
1532 new: Arc::new(Chain::new(
1533 vec![block0.recovered_block().clone(), block1.recovered_block().clone()],
1534 sample_execution_outcome.clone(),
1535 None
1536 ))
1537 }
1538 );
1539
1540 let chain_reorg = NewCanonicalChain::Reorg {
1542 new: vec![block1a.clone(), block2a.clone()],
1543 old: vec![block1.block.clone(), block2.block.clone()],
1544 };
1545
1546 assert_eq!(
1547 chain_reorg.to_chain_notification(),
1548 CanonStateNotification::Reorg {
1549 old: Arc::new(Chain::new(
1550 vec![block1.recovered_block().clone(), block2.recovered_block().clone()],
1551 sample_execution_outcome.clone(),
1552 None
1553 )),
1554 new: Arc::new(Chain::new(
1555 vec![block1a.recovered_block().clone(), block2a.recovered_block().clone()],
1556 sample_execution_outcome,
1557 None
1558 ))
1559 }
1560 );
1561 }
1562}