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