1use crate::{
4 externals::TreeNodeTypes,
5 metrics::{MakeCanonicalAction, MakeCanonicalDurationsRecorder, TreeMetrics},
6 state::{SidechainId, TreeState},
7 AppendableChain, BlockIndices, BlockchainTreeConfig, ExecutionData, TreeExternals,
8};
9use alloy_eips::{BlockNumHash, ForkBlock};
10use alloy_primitives::{BlockHash, BlockNumber, B256, U256};
11use reth_blockchain_tree_api::{
12 error::{BlockchainTreeError, CanonicalError, InsertBlockError, InsertBlockErrorKind},
13 BlockAttachment, BlockStatus, BlockValidationKind, CanonicalOutcome, InsertPayloadOk,
14};
15use reth_consensus::{Consensus, ConsensusError};
16use reth_evm::execute::BlockExecutorProvider;
17use reth_execution_errors::{BlockExecutionError, BlockValidationError};
18use reth_execution_types::{Chain, ExecutionOutcome};
19use reth_node_types::NodeTypesWithDB;
20use reth_primitives::{
21 EthereumHardfork, GotExpected, Hardforks, Receipt, SealedBlock, SealedBlockWithSenders,
22 SealedHeader, StaticFileSegment,
23};
24use reth_provider::{
25 BlockExecutionWriter, BlockNumReader, BlockWriter, CanonStateNotification,
26 CanonStateNotificationSender, CanonStateNotifications, ChainSpecProvider, ChainSplit,
27 ChainSplitTarget, DBProvider, DisplayBlocksChain, HashedPostStateProvider, HeaderProvider,
28 ProviderError, StaticFileProviderFactory, StorageLocation,
29};
30use reth_stages_api::{MetricEvent, MetricEventsSender};
31use reth_storage_errors::provider::{ProviderResult, RootMismatch};
32use reth_trie::{hashed_cursor::HashedPostStateCursorFactory, StateRoot};
33use reth_trie_db::{DatabaseHashedCursorFactory, DatabaseStateRoot};
34use std::{
35 collections::{btree_map::Entry, BTreeMap, HashSet},
36 sync::Arc,
37};
38use tracing::{debug, error, info, instrument, trace, warn};
39
40#[cfg_attr(doc, aquamarine::aquamarine)]
41#[derive(Debug)]
64pub struct BlockchainTree<N: NodeTypesWithDB, E> {
65 state: TreeState,
69 externals: TreeExternals<N, E>,
71 config: BlockchainTreeConfig,
73 canon_state_notification_sender: CanonStateNotificationSender,
75 sync_metrics_tx: Option<MetricEventsSender>,
77 metrics: TreeMetrics,
79}
80
81impl<N: NodeTypesWithDB, E> BlockchainTree<N, E> {
82 pub fn subscribe_canon_state(&self) -> CanonStateNotifications {
86 self.canon_state_notification_sender.subscribe()
87 }
88
89 pub fn canon_state_notification_sender(&self) -> CanonStateNotificationSender {
91 self.canon_state_notification_sender.clone()
92 }
93}
94
95impl<N, E> BlockchainTree<N, E>
96where
97 N: TreeNodeTypes,
98 E: BlockExecutorProvider<Primitives = N::Primitives>,
99{
100 pub fn new(
118 externals: TreeExternals<N, E>,
119 config: BlockchainTreeConfig,
120 ) -> ProviderResult<Self> {
121 let max_reorg_depth = config.max_reorg_depth() as usize;
122 let (canon_state_notification_sender, _receiver) =
125 tokio::sync::broadcast::channel(max_reorg_depth * 2);
126
127 let last_canonical_hashes =
128 externals.fetch_latest_canonical_hashes(config.num_of_canonical_hashes() as usize)?;
129
130 let last_finalized_block_number =
132 externals.fetch_latest_finalized_block_number()?.unwrap_or_default();
133
134 Ok(Self {
135 externals,
136 state: TreeState::new(
137 last_finalized_block_number,
138 last_canonical_hashes,
139 config.max_unconnected_blocks(),
140 ),
141 config,
142 canon_state_notification_sender,
143 sync_metrics_tx: None,
144 metrics: Default::default(),
145 })
146 }
147
148 #[doc(hidden)]
152 pub fn with_canon_state_notification_sender(
153 mut self,
154 canon_state_notification_sender: CanonStateNotificationSender,
155 ) -> Self {
156 self.canon_state_notification_sender = canon_state_notification_sender;
157 self
158 }
159
160 pub fn with_sync_metrics_tx(mut self, metrics_tx: MetricEventsSender) -> Self {
165 self.sync_metrics_tx = Some(metrics_tx);
166 self
167 }
168
169 pub(crate) fn is_block_known(
180 &self,
181 block: BlockNumHash,
182 ) -> Result<Option<BlockStatus>, InsertBlockErrorKind> {
183 if self.is_block_hash_canonical(&block.hash)? {
185 return Ok(Some(BlockStatus::Valid(BlockAttachment::Canonical)));
186 }
187
188 let last_finalized_block = self.block_indices().last_finalized_block();
189 if block.number <= last_finalized_block {
191 if self.externals.provider_factory.provider()?.block_number(block.hash)?.is_some() {
193 return Ok(Some(BlockStatus::Valid(BlockAttachment::Canonical)));
194 }
195
196 return Err(BlockchainTreeError::PendingBlockIsFinalized {
197 last_finalized: last_finalized_block,
198 }
199 .into())
200 }
201
202 if let Some(attachment) = self.is_block_inside_sidechain(&block) {
204 return Ok(Some(BlockStatus::Valid(attachment)));
205 }
206
207 if let Some(block) = self.state.buffered_blocks.block(&block.hash) {
209 return Ok(Some(BlockStatus::Disconnected {
210 head: self.state.block_indices.canonical_tip(),
211 missing_ancestor: block.parent_num_hash(),
212 }))
213 }
214
215 Ok(None)
216 }
217
218 #[inline]
220 pub const fn block_indices(&self) -> &BlockIndices {
221 self.state.block_indices()
222 }
223
224 #[inline]
228 pub fn sidechain_block_by_hash(&self, block_hash: BlockHash) -> Option<&SealedBlock> {
229 self.state.block_by_hash(block_hash)
230 }
231
232 #[inline]
236 pub fn block_with_senders_by_hash(
237 &self,
238 block_hash: BlockHash,
239 ) -> Option<&SealedBlockWithSenders> {
240 self.state.block_with_senders_by_hash(block_hash)
241 }
242
243 pub fn receipts_by_block_hash(&self, block_hash: BlockHash) -> Option<Vec<&Receipt>> {
247 self.state.receipts_by_block_hash(block_hash)
248 }
249
250 pub fn pending_block(&self) -> Option<&SealedBlock> {
252 let b = self.block_indices().pending_block_num_hash()?;
253 self.sidechain_block_by_hash(b.hash)
254 }
255
256 pub fn post_state_data(&self, block_hash: BlockHash) -> Option<ExecutionData> {
268 trace!(target: "blockchain_tree", ?block_hash, "Searching for post state data");
269
270 let canonical_chain = self.state.block_indices.canonical_chain();
271
272 if let Some(chain_id) = self.block_indices().get_side_chain_id(&block_hash) {
274 trace!(target: "blockchain_tree", ?block_hash, "Constructing post state data based on non-canonical chain");
275 let Some(chain) = self.state.chains.get(&chain_id) else {
277 debug!(target: "blockchain_tree", ?chain_id, "Chain with ID not present");
278 return None;
279 };
280 let block_number = chain.block_number(block_hash)?;
281 let execution_outcome = chain.execution_outcome_at_block(block_number)?;
282
283 let mut parent_block_hashes = self.all_chain_hashes(chain_id);
285 let Some((first_pending_block_number, _)) = parent_block_hashes.first_key_value()
286 else {
287 debug!(target: "blockchain_tree", ?chain_id, "No block hashes stored");
288 return None;
289 };
290 let canonical_chain = canonical_chain
291 .iter()
292 .filter(|&(key, _)| &key < first_pending_block_number)
293 .collect::<Vec<_>>();
294 parent_block_hashes.extend(canonical_chain);
295
296 let canonical_fork = self.canonical_fork(chain_id)?;
298 return Some(ExecutionData { execution_outcome, parent_block_hashes, canonical_fork });
299 }
300
301 if let Some(canonical_number) = canonical_chain.canonical_number(&block_hash) {
303 trace!(target: "blockchain_tree", %block_hash, "Constructing post state data based on canonical chain");
304 return Some(ExecutionData {
305 canonical_fork: ForkBlock { number: canonical_number, hash: block_hash },
306 execution_outcome: ExecutionOutcome::default(),
307 parent_block_hashes: canonical_chain.inner().clone(),
308 });
309 }
310
311 None
312 }
313
314 #[instrument(level = "trace", skip_all, fields(block = ?block.num_hash()), target = "blockchain_tree", ret)]
319 fn try_insert_validated_block(
320 &mut self,
321 block: SealedBlockWithSenders,
322 block_validation_kind: BlockValidationKind,
323 ) -> Result<BlockStatus, InsertBlockErrorKind> {
324 debug_assert!(self.validate_block(&block).is_ok(), "Block must be validated");
325
326 let parent = block.parent_num_hash();
327
328 if let Some(chain_id) = self.block_indices().get_side_chain_id(&parent.hash) {
330 return self.try_insert_block_into_side_chain(block, chain_id, block_validation_kind);
332 }
333
334 if self.is_block_hash_canonical(&parent.hash)? {
336 return self.try_append_canonical_chain(block.clone(), block_validation_kind);
337 }
338
339 if let Some(canonical_parent_number) =
342 self.block_indices().canonical_number(&block.parent_hash)
343 {
344 if canonical_parent_number != parent.number {
346 return Err(ConsensusError::ParentBlockNumberMismatch {
347 parent_block_number: canonical_parent_number,
348 block_number: block.number,
349 }
350 .into())
351 }
352 }
353
354 if let Some(buffered_parent) = self.state.buffered_blocks.block(&parent.hash) {
356 self.externals.consensus.validate_header_against_parent(&block, buffered_parent)?;
357 }
358
359 self.state.buffered_blocks.insert_block(block.clone());
361
362 let block_hash = block.hash();
363 let lowest_ancestor = self
367 .state
368 .buffered_blocks
369 .lowest_ancestor(&block_hash)
370 .ok_or(BlockchainTreeError::BlockBufferingFailed { block_hash })?;
371
372 Ok(BlockStatus::Disconnected {
373 head: self.state.block_indices.canonical_tip(),
374 missing_ancestor: lowest_ancestor.parent_num_hash(),
375 })
376 }
377
378 #[instrument(level = "trace", skip_all, target = "blockchain_tree")]
384 fn try_append_canonical_chain(
385 &mut self,
386 block: SealedBlockWithSenders,
387 block_validation_kind: BlockValidationKind,
388 ) -> Result<BlockStatus, InsertBlockErrorKind> {
389 let parent = block.parent_num_hash();
390 let block_num_hash = block.num_hash();
391 debug!(target: "blockchain_tree", head = ?block_num_hash.hash, ?parent, "Appending block to canonical chain");
392
393 let provider = self.externals.provider_factory.provider()?;
394
395 let parent_td = provider
397 .header_td(&block.parent_hash)?
398 .ok_or_else(|| BlockchainTreeError::CanonicalChain { block_hash: block.parent_hash })?;
399
400 if !self
402 .externals
403 .provider_factory
404 .chain_spec()
405 .fork(EthereumHardfork::Paris)
406 .active_at_ttd(parent_td, U256::ZERO)
407 {
408 return Err(BlockExecutionError::Validation(BlockValidationError::BlockPreMerge {
409 hash: block.hash(),
410 })
411 .into())
412 }
413
414 let parent_header = provider
415 .header(&block.parent_hash)?
416 .ok_or_else(|| BlockchainTreeError::CanonicalChain { block_hash: block.parent_hash })?;
417
418 let parent_sealed_header = SealedHeader::new(parent_header, block.parent_hash);
419
420 let canonical_chain = self.state.block_indices.canonical_chain();
421
422 let block_attachment = if block.parent_hash == canonical_chain.tip().hash {
423 BlockAttachment::Canonical
424 } else {
425 BlockAttachment::HistoricalFork
426 };
427
428 let chain = AppendableChain::new_canonical_fork(
429 block,
430 &parent_sealed_header,
431 canonical_chain.inner(),
432 parent,
433 &self.externals,
434 block_attachment,
435 block_validation_kind,
436 )?;
437
438 self.insert_chain(chain);
439 self.try_connect_buffered_blocks(block_num_hash);
440
441 Ok(BlockStatus::Valid(block_attachment))
442 }
443
444 #[instrument(level = "trace", skip_all, target = "blockchain_tree")]
448 fn try_insert_block_into_side_chain(
449 &mut self,
450 block: SealedBlockWithSenders,
451 chain_id: SidechainId,
452 block_validation_kind: BlockValidationKind,
453 ) -> Result<BlockStatus, InsertBlockErrorKind> {
454 let block_num_hash = block.num_hash();
455 debug!(target: "blockchain_tree", ?block_num_hash, ?chain_id, "Inserting block into side chain");
456 let block_hashes = self.all_chain_hashes(chain_id);
459
460 let canonical_fork = self.canonical_fork(chain_id).ok_or_else(|| {
462 BlockchainTreeError::BlockSideChainIdConsistency { chain_id: chain_id.into() }
463 })?;
464
465 let parent_chain = self.state.chains.get_mut(&chain_id).ok_or_else(|| {
467 BlockchainTreeError::BlockSideChainIdConsistency { chain_id: chain_id.into() }
468 })?;
469
470 let chain_tip = parent_chain.tip().hash();
471 let canonical_chain = self.state.block_indices.canonical_chain();
472
473 let block_attachment = if chain_tip == block.parent_hash {
475 let block_attachment = if canonical_fork.hash == canonical_chain.tip().hash {
477 BlockAttachment::Canonical
478 } else {
479 BlockAttachment::HistoricalFork
480 };
481
482 let block_hash = block.hash();
483 let block_number = block.number;
484 debug!(target: "blockchain_tree", ?block_hash, ?block_number, "Appending block to side chain");
485 parent_chain.append_block(
486 block,
487 block_hashes,
488 canonical_chain.inner(),
489 &self.externals,
490 canonical_fork,
491 block_attachment,
492 block_validation_kind,
493 )?;
494
495 self.state.block_indices.insert_non_fork_block(block_number, block_hash, chain_id);
496 block_attachment
497 } else {
498 debug!(target: "blockchain_tree", ?canonical_fork, "Starting new fork from side chain");
499 let chain = parent_chain.new_chain_fork(
501 block,
502 block_hashes,
503 canonical_chain.inner(),
504 canonical_fork,
505 &self.externals,
506 block_validation_kind,
507 )?;
508 self.insert_chain(chain);
509 BlockAttachment::HistoricalFork
510 };
511
512 self.try_connect_buffered_blocks(block_num_hash);
514
515 Ok(BlockStatus::Valid(block_attachment))
516 }
517
518 fn all_chain_hashes(&self, chain_id: SidechainId) -> BTreeMap<BlockNumber, BlockHash> {
525 let mut chain_id = chain_id;
526 let mut hashes = BTreeMap::new();
527 loop {
528 let Some(chain) = self.state.chains.get(&chain_id) else { return hashes };
529
530 let latest_block_number = hashes
535 .last_key_value()
536 .map(|(number, _)| *number)
537 .unwrap_or_else(|| chain.tip().number);
538 for block in chain.blocks().values().filter(|b| b.number <= latest_block_number) {
539 if let Entry::Vacant(e) = hashes.entry(block.number) {
540 e.insert(block.hash());
541 }
542 }
543
544 let fork_block = chain.fork_block();
545 if let Some(next_chain_id) = self.block_indices().get_side_chain_id(&fork_block.hash) {
546 chain_id = next_chain_id;
547 } else {
548 break
551 }
552 }
553 hashes
554 }
555
556 fn canonical_fork(&self, chain_id: SidechainId) -> Option<ForkBlock> {
563 let mut chain_id = chain_id;
564 let mut fork;
565 loop {
566 fork = self.state.chains.get(&chain_id)?.fork_block();
568 if let Some(fork_chain_id) = self.block_indices().get_side_chain_id(&fork.hash) {
570 chain_id = fork_chain_id;
571 continue
572 }
573 break
574 }
575 (self.block_indices().canonical_hash(&fork.number) == Some(fork.hash)).then_some(fork)
576 }
577
578 fn insert_chain(&mut self, chain: AppendableChain) -> Option<SidechainId> {
582 self.state.insert_chain(chain)
583 }
584
585 fn find_all_dependent_chains(&self, block: &BlockHash) -> HashSet<SidechainId> {
588 let mut dependent_block =
590 self.block_indices().fork_to_child().get(block).cloned().unwrap_or_default();
591 let mut dependent_chains = HashSet::default();
592
593 while let Some(block) = dependent_block.pop_back() {
594 let Some(chain_id) = self.block_indices().get_side_chain_id(&block) else {
596 debug!(target: "blockchain_tree", ?block, "Block not in tree");
597 return Default::default();
598 };
599
600 let Some(chain) = self.state.chains.get(&chain_id) else {
602 debug!(target: "blockchain_tree", ?chain_id, "Chain not in tree");
603 return Default::default();
604 };
605 for chain_block in chain.blocks().values() {
606 if let Some(forks) = self.block_indices().fork_to_child().get(&chain_block.hash()) {
607 dependent_block.extend(forks);
609 }
610 }
611 dependent_chains.insert(chain_id);
613 }
614 dependent_chains
615 }
616
617 fn insert_unwound_chain(&mut self, chain: AppendableChain) -> Option<SidechainId> {
625 for (number, block) in chain.blocks() {
627 let hash = block.hash();
628
629 let chains_to_bump = self.find_all_dependent_chains(&hash);
631 if !chains_to_bump.is_empty() {
632 let mut cloned_execution_outcome = chain.execution_outcome().clone();
634 cloned_execution_outcome.revert_to(*number);
635
636 for chain_id in chains_to_bump {
638 let Some(chain) = self.state.chains.get_mut(&chain_id) else {
639 debug!(target: "blockchain_tree", ?chain_id, "Chain not in tree");
640 return None;
641 };
642
643 debug!(target: "blockchain_tree",
644 unwound_block= ?block.num_hash(),
645 chain_id = ?chain_id,
646 chain_tip = ?chain.tip().num_hash(),
647 "Prepend unwound block state to blockchain tree chain");
648
649 chain.prepend_state(cloned_execution_outcome.state().clone())
650 }
651 }
652 }
653 self.insert_chain(chain)
655 }
656
657 pub fn get_buffered_block(&self, hash: &BlockHash) -> Option<&SealedBlockWithSenders> {
659 self.state.get_buffered_block(hash)
660 }
661
662 pub fn lowest_buffered_ancestor(&self, hash: &BlockHash) -> Option<&SealedBlockWithSenders> {
664 self.state.lowest_buffered_ancestor(hash)
665 }
666
667 pub fn insert_block_without_senders(
673 &mut self,
674 block: SealedBlock,
675 ) -> Result<InsertPayloadOk, InsertBlockError> {
676 match block.try_seal_with_senders() {
677 Ok(block) => self.insert_block(block, BlockValidationKind::Exhaustive),
678 Err(block) => Err(InsertBlockError::sender_recovery_error(block)),
679 }
680 }
681
682 pub fn buffer_block(&mut self, block: SealedBlockWithSenders) -> Result<(), InsertBlockError> {
686 if let Err(err) = self.validate_block(&block) {
688 return Err(InsertBlockError::consensus_error(err, block.block));
689 }
690
691 self.state.buffered_blocks.insert_block(block);
692 Ok(())
693 }
694
695 fn validate_block(&self, block: &SealedBlockWithSenders) -> Result<(), ConsensusError> {
698 if let Err(e) =
699 self.externals.consensus.validate_header_with_total_difficulty(block, U256::MAX)
700 {
701 error!(
702 ?block,
703 "Failed to validate total difficulty for block {}: {e}",
704 block.header.hash()
705 );
706 return Err(e);
707 }
708
709 if let Err(e) = self.externals.consensus.validate_header(block) {
710 error!(?block, "Failed to validate header {}: {e}", block.header.hash());
711 return Err(e);
712 }
713
714 if let Err(e) = self.externals.consensus.validate_block_pre_execution(block) {
715 error!(?block, "Failed to validate block {}: {e}", block.header.hash());
716 return Err(e);
717 }
718
719 Ok(())
720 }
721
722 #[track_caller]
728 fn is_block_inside_sidechain(&self, block: &BlockNumHash) -> Option<BlockAttachment> {
729 if let Some(chain_id) = self.block_indices().get_side_chain_id(&block.hash) {
731 let Some(canonical_fork) = self.canonical_fork(chain_id) else {
733 debug!(target: "blockchain_tree", chain_id=?chain_id, block=?block.hash, "Chain id not valid");
734 return None;
735 };
736 return if canonical_fork == self.block_indices().canonical_tip() {
738 Some(BlockAttachment::Canonical)
739 } else {
740 Some(BlockAttachment::HistoricalFork)
741 };
742 }
743 None
744 }
745
746 pub fn insert_block(
769 &mut self,
770 block: SealedBlockWithSenders,
771 block_validation_kind: BlockValidationKind,
772 ) -> Result<InsertPayloadOk, InsertBlockError> {
773 match self.is_block_known(block.num_hash()) {
775 Ok(Some(status)) => return Ok(InsertPayloadOk::AlreadySeen(status)),
776 Err(err) => return Err(InsertBlockError::new(block.block, err)),
777 _ => {}
778 }
779
780 if let Err(err) = self.validate_block(&block) {
782 return Err(InsertBlockError::consensus_error(err, block.block));
783 }
784
785 let status = self
786 .try_insert_validated_block(block.clone(), block_validation_kind)
787 .map_err(|kind| InsertBlockError::new(block.block, kind))?;
788 Ok(InsertPayloadOk::Inserted(status))
789 }
790
791 pub fn remove_old_blocks(&mut self, block: BlockNumber) {
793 self.state.buffered_blocks.remove_old_blocks(block);
794 }
795
796 pub fn finalize_block(&mut self, finalized_block: BlockNumber) -> ProviderResult<()> {
798 let mut remove_chains = self.state.block_indices.finalize_canonical_blocks(
800 finalized_block,
801 self.config.num_of_additional_canonical_block_hashes(),
802 );
803 while let Some(chain_id) = remove_chains.pop_first() {
805 if let Some(chain) = self.state.chains.remove(&chain_id) {
806 remove_chains.extend(self.state.block_indices.remove_chain(&chain));
807 }
808 }
809 self.remove_old_blocks(finalized_block);
811
812 self.externals.save_finalized_block_number(finalized_block)?;
814
815 Ok(())
816 }
817
818 pub fn connect_buffered_blocks_to_canonical_hashes_and_finalize(
830 &mut self,
831 last_finalized_block: BlockNumber,
832 ) -> ProviderResult<()> {
833 self.finalize_block(last_finalized_block)?;
834
835 let last_canonical_hashes = self.update_block_hashes()?;
836
837 self.connect_buffered_blocks_to_hashes(last_canonical_hashes)?;
838
839 Ok(())
840 }
841
842 pub fn update_block_hashes(&mut self) -> ProviderResult<BTreeMap<BlockNumber, B256>> {
845 let last_canonical_hashes = self
846 .externals
847 .fetch_latest_canonical_hashes(self.config.num_of_canonical_hashes() as usize)?;
848
849 let (mut remove_chains, _) =
850 self.state.block_indices.update_block_hashes(last_canonical_hashes.clone());
851
852 while let Some(chain_id) = remove_chains.first() {
854 if let Some(chain) = self.state.chains.remove(chain_id) {
855 remove_chains.extend(self.state.block_indices.remove_chain(&chain));
856 }
857 }
858
859 Ok(last_canonical_hashes)
860 }
861
862 pub fn update_block_hashes_and_clear_buffered(
866 &mut self,
867 ) -> ProviderResult<BTreeMap<BlockNumber, BlockHash>> {
868 let chain = self.update_block_hashes()?;
869
870 if let Some((block, _)) = chain.last_key_value() {
871 self.remove_old_blocks(*block);
872 }
873
874 Ok(chain)
875 }
876
877 pub fn connect_buffered_blocks_to_canonical_hashes(&mut self) -> ProviderResult<()> {
883 let last_canonical_hashes = self
884 .externals
885 .fetch_latest_canonical_hashes(self.config.num_of_canonical_hashes() as usize)?;
886 self.connect_buffered_blocks_to_hashes(last_canonical_hashes)?;
887
888 Ok(())
889 }
890
891 fn connect_buffered_blocks_to_hashes(
892 &mut self,
893 hashes: impl IntoIterator<Item = impl Into<BlockNumHash>>,
894 ) -> ProviderResult<()> {
895 for added_block in hashes {
897 self.try_connect_buffered_blocks(added_block.into())
898 }
899
900 let mut all_chain_blocks = Vec::new();
902 for chain in self.state.chains.values() {
903 all_chain_blocks.reserve_exact(chain.blocks().len());
904 for (&number, block) in chain.blocks() {
905 all_chain_blocks.push(BlockNumHash { number, hash: block.hash() })
906 }
907 }
908 for block in all_chain_blocks {
909 self.try_connect_buffered_blocks(block)
910 }
911
912 Ok(())
913 }
914
915 fn try_connect_buffered_blocks(&mut self, new_block: BlockNumHash) {
922 trace!(target: "blockchain_tree", ?new_block, "try_connect_buffered_blocks");
923
924 let include_blocks = self.state.buffered_blocks.remove_block_with_children(&new_block.hash);
926 for block in include_blocks {
928 let _ = self
930 .try_insert_validated_block(block, BlockValidationKind::SkipStateRootValidation)
931 .map_err(|err| {
932 debug!(target: "blockchain_tree", %err, "Failed to insert buffered block");
933 err
934 });
935 }
936 }
937
938 fn remove_and_split_chain(
944 &mut self,
945 chain_id: SidechainId,
946 split_at: ChainSplitTarget,
947 ) -> Option<Chain> {
948 let chain = self.state.chains.remove(&chain_id)?;
949 match chain.into_inner().split(split_at) {
950 ChainSplit::Split { canonical, pending } => {
951 trace!(target: "blockchain_tree", ?canonical, ?pending, "Split chain");
952 self.state.block_indices.insert_chain(chain_id, &pending);
954 self.state.chains.insert(chain_id, AppendableChain::new(pending));
955 Some(canonical)
956 }
957 ChainSplit::NoSplitCanonical(canonical) => {
958 trace!(target: "blockchain_tree", "No split on canonical chain");
959 Some(canonical)
960 }
961 ChainSplit::NoSplitPending(_) => {
962 unreachable!("Should not happen as block indices guarantee structure of blocks")
963 }
964 }
965 }
966
967 pub fn find_canonical_header(
975 &self,
976 hash: &BlockHash,
977 ) -> Result<Option<SealedHeader>, ProviderError> {
978 let provider = self.externals.provider_factory.provider()?;
983
984 let mut header = None;
985 if let Some(num) = self.block_indices().canonical_number(hash) {
986 header = provider.header_by_number(num)?;
987 }
988
989 if header.is_none() && self.sidechain_block_by_hash(*hash).is_some() {
990 return Ok(None)
991 }
992
993 if header.is_none() {
994 header = provider.header(hash)?
995 }
996
997 Ok(header.map(|header| SealedHeader::new(header, *hash)))
998 }
999
1000 pub fn is_block_hash_canonical(&self, hash: &BlockHash) -> Result<bool, ProviderError> {
1005 self.find_canonical_header(hash).map(|header| header.is_some())
1006 }
1007
1008 #[track_caller]
1019 #[instrument(level = "trace", skip(self), target = "blockchain_tree")]
1020 pub fn make_canonical(
1021 &mut self,
1022 block_hash: BlockHash,
1023 ) -> Result<CanonicalOutcome, CanonicalError> {
1024 let mut durations_recorder = MakeCanonicalDurationsRecorder::default();
1025
1026 let old_block_indices = self.block_indices().clone();
1027 let old_buffered_blocks = self.state.buffered_blocks.parent_to_child.clone();
1028 durations_recorder.record_relative(MakeCanonicalAction::CloneOldBlocks);
1029
1030 let canonical_header = self.find_canonical_header(&block_hash)?;
1032 durations_recorder.record_relative(MakeCanonicalAction::FindCanonicalHeader);
1033 if let Some(header) = canonical_header {
1034 info!(target: "blockchain_tree", %block_hash, "Block is already canonical, ignoring.");
1035 let td =
1037 self.externals.provider_factory.provider()?.header_td(&block_hash)?.ok_or_else(
1038 || {
1039 CanonicalError::from(BlockValidationError::MissingTotalDifficulty {
1040 hash: block_hash,
1041 })
1042 },
1043 )?;
1044 if !self
1045 .externals
1046 .provider_factory
1047 .chain_spec()
1048 .fork(EthereumHardfork::Paris)
1049 .active_at_ttd(td, U256::ZERO)
1050 {
1051 return Err(CanonicalError::from(BlockValidationError::BlockPreMerge {
1052 hash: block_hash,
1053 }))
1054 }
1055
1056 let head = self.state.block_indices.canonical_tip();
1057 return Ok(CanonicalOutcome::AlreadyCanonical { header, head });
1058 }
1059
1060 let Some(chain_id) = self.block_indices().get_side_chain_id(&block_hash) else {
1061 debug!(target: "blockchain_tree", ?block_hash, "Block hash not found in block indices");
1062 return Err(CanonicalError::from(BlockchainTreeError::BlockHashNotFoundInChain {
1063 block_hash,
1064 }))
1065 };
1066
1067 let Some(canonical) = self.remove_and_split_chain(chain_id, block_hash.into()) else {
1069 debug!(target: "blockchain_tree", ?block_hash, ?chain_id, "Chain not present");
1070 return Err(CanonicalError::from(BlockchainTreeError::BlockSideChainIdConsistency {
1071 chain_id: chain_id.into(),
1072 }))
1073 };
1074 trace!(target: "blockchain_tree", chain = ?canonical, "Found chain to make canonical");
1075 durations_recorder.record_relative(MakeCanonicalAction::SplitChain);
1076
1077 let mut fork_block = canonical.fork_block();
1078 let mut chains_to_promote = vec![canonical];
1079
1080 while let Some(chain_id) = self.block_indices().get_side_chain_id(&fork_block.hash) {
1082 let Some(canonical) =
1084 self.remove_and_split_chain(chain_id, ChainSplitTarget::Number(fork_block.number))
1085 else {
1086 debug!(target: "blockchain_tree", ?fork_block, ?chain_id, "Fork not present");
1087 return Err(CanonicalError::from(
1088 BlockchainTreeError::BlockSideChainIdConsistency { chain_id: chain_id.into() },
1089 ));
1090 };
1091 fork_block = canonical.fork_block();
1092 chains_to_promote.push(canonical);
1093 }
1094 durations_recorder.record_relative(MakeCanonicalAction::SplitChainForks);
1095
1096 let old_tip = self.block_indices().canonical_tip();
1097 let Some(mut new_canon_chain) = chains_to_promote.pop() else {
1099 debug!(target: "blockchain_tree", "No blocks in the chain to make canonical");
1100 return Err(CanonicalError::from(BlockchainTreeError::BlockHashNotFoundInChain {
1101 block_hash: fork_block.hash,
1102 }))
1103 };
1104 trace!(target: "blockchain_tree", ?new_canon_chain, "Merging chains");
1105 let mut chain_appended = false;
1106 for chain in chains_to_promote.into_iter().rev() {
1107 trace!(target: "blockchain_tree", ?chain, "Appending chain");
1108 let block_hash = chain.fork_block().hash;
1109 new_canon_chain.append_chain(chain).map_err(|_| {
1110 CanonicalError::from(BlockchainTreeError::BlockHashNotFoundInChain { block_hash })
1111 })?;
1112 chain_appended = true;
1113 }
1114 durations_recorder.record_relative(MakeCanonicalAction::MergeAllChains);
1115
1116 if chain_appended {
1117 trace!(target: "blockchain_tree", ?new_canon_chain, "Canonical chain appended");
1118 }
1119 self.state.block_indices.canonicalize_blocks(new_canon_chain.blocks());
1121 durations_recorder.record_relative(MakeCanonicalAction::UpdateCanonicalIndex);
1122
1123 debug!(
1124 target: "blockchain_tree",
1125 "Committing new canonical chain: {}", DisplayBlocksChain(new_canon_chain.blocks())
1126 );
1127
1128 let chain_notification = if new_canon_chain.fork_block().hash == old_tip.hash {
1130 self.commit_canonical_to_database(new_canon_chain.clone(), &mut durations_recorder)?;
1132 CanonStateNotification::Commit { new: Arc::new(new_canon_chain) }
1133 } else {
1134 let canon_fork: BlockNumHash = new_canon_chain.fork_block();
1136 if self.block_indices().canonical_hash(&canon_fork.number) != Some(canon_fork.hash) {
1138 error!(
1139 target: "blockchain_tree",
1140 ?canon_fork,
1141 block_indices=?self.block_indices(),
1142 "All chains should point to canonical chain"
1143 );
1144 unreachable!("all chains should point to canonical chain.");
1145 }
1146
1147 let old_canon_chain =
1148 self.revert_canonical_from_database(canon_fork.number).inspect_err(|error| {
1149 error!(
1150 target: "blockchain_tree",
1151 "Reverting canonical chain failed with error: {:?}\n\
1152 Old BlockIndices are:{:?}\n\
1153 New BlockIndices are: {:?}\n\
1154 Old BufferedBlocks are:{:?}",
1155 error, old_block_indices, self.block_indices(), old_buffered_blocks
1156 );
1157 })?;
1158 durations_recorder
1159 .record_relative(MakeCanonicalAction::RevertCanonicalChainFromDatabase);
1160
1161 self.commit_canonical_to_database(new_canon_chain.clone(), &mut durations_recorder)?;
1163
1164 if let Some(old_canon_chain) = old_canon_chain {
1165 self.update_reorg_metrics(old_canon_chain.len() as f64);
1166
1167 self.insert_unwound_chain(AppendableChain::new(old_canon_chain.clone()));
1169 durations_recorder.record_relative(MakeCanonicalAction::InsertOldCanonicalChain);
1170
1171 CanonStateNotification::Reorg {
1172 old: Arc::new(old_canon_chain),
1173 new: Arc::new(new_canon_chain),
1174 }
1175 } else {
1176 error!(target: "blockchain_tree", %block_hash, "Nothing was removed from database");
1178 CanonStateNotification::Commit { new: Arc::new(new_canon_chain) }
1179 }
1180 };
1181
1182 debug!(
1183 target: "blockchain_tree",
1184 actions = ?durations_recorder.actions,
1185 "Canonicalization finished"
1186 );
1187
1188 self.block_indices()
1190 .fork_to_child()
1191 .get(&old_tip.hash)
1192 .cloned()
1193 .unwrap_or_default()
1194 .into_iter()
1195 .for_each(|child| {
1196 if let Some(chain_id) = self.block_indices().get_side_chain_id(&child) {
1197 if let Some(chain) = self.state.chains.get_mut(&chain_id) {
1198 chain.clear_trie_updates();
1199 }
1200 }
1201 });
1202
1203 durations_recorder.record_relative(MakeCanonicalAction::ClearTrieUpdatesForOtherChildren);
1204
1205 let outcome = CanonicalOutcome::Committed { head: chain_notification.tip().header.clone() };
1207 let _ = self.canon_state_notification_sender.send(chain_notification);
1208 Ok(outcome)
1209 }
1210
1211 fn commit_canonical_to_database(
1213 &self,
1214 chain: Chain,
1215 recorder: &mut MakeCanonicalDurationsRecorder,
1216 ) -> Result<(), CanonicalError> {
1217 let (blocks, state, chain_trie_updates) = chain.into_inner();
1218 let hashed_state = self.externals.provider_factory.hashed_post_state(state.state());
1219 let prefix_sets = hashed_state.construct_prefix_sets().freeze();
1220 let hashed_state_sorted = hashed_state.into_sorted();
1221
1222 let block_hash_numbers =
1224 blocks.iter().map(|(number, b)| (number, b.hash())).collect::<Vec<_>>();
1225 let trie_updates = match chain_trie_updates {
1226 Some(updates) => {
1227 debug!(target: "blockchain_tree", blocks = ?block_hash_numbers, "Using cached trie updates");
1228 self.metrics.trie_updates_insert_cached.increment(1);
1229 updates
1230 }
1231 None => {
1232 debug!(target: "blockchain_tree", blocks = ?block_hash_numbers, "Recomputing state root for insert");
1233 let provider = self
1234 .externals
1235 .provider_factory
1236 .provider()?
1237 .disable_long_read_transaction_safety();
1240 let (state_root, trie_updates) = StateRoot::from_tx(provider.tx_ref())
1241 .with_hashed_cursor_factory(HashedPostStateCursorFactory::new(
1242 DatabaseHashedCursorFactory::new(provider.tx_ref()),
1243 &hashed_state_sorted,
1244 ))
1245 .with_prefix_sets(prefix_sets)
1246 .root_with_updates()
1247 .map_err(BlockValidationError::from)?;
1248 let tip = blocks.tip();
1249 if state_root != tip.state_root {
1250 return Err(ProviderError::StateRootMismatch(Box::new(RootMismatch {
1251 root: GotExpected { got: state_root, expected: tip.state_root },
1252 block_number: tip.number,
1253 block_hash: tip.hash(),
1254 }))
1255 .into())
1256 }
1257 self.metrics.trie_updates_insert_recomputed.increment(1);
1258 trie_updates
1259 }
1260 };
1261 recorder.record_relative(MakeCanonicalAction::RetrieveStateTrieUpdates);
1262
1263 let provider_rw = self.externals.provider_factory.provider_rw()?;
1264 provider_rw
1265 .append_blocks_with_state(
1266 blocks.into_blocks().collect(),
1267 state,
1268 hashed_state_sorted,
1269 trie_updates,
1270 )
1271 .map_err(|e| CanonicalError::CanonicalCommit(e.to_string()))?;
1272
1273 provider_rw.commit()?;
1274 recorder.record_relative(MakeCanonicalAction::CommitCanonicalChainToDatabase);
1275
1276 Ok(())
1277 }
1278
1279 pub fn unwind(&mut self, unwind_to: BlockNumber) -> Result<(), CanonicalError> {
1281 if self.block_indices().canonical_tip().number <= unwind_to {
1283 return Ok(());
1284 }
1285 let old_canon_chain = self.revert_canonical_from_database(unwind_to)?;
1287
1288 if let Some(old_canon_chain) = old_canon_chain {
1290 self.state.block_indices.unwind_canonical_chain(unwind_to);
1291 self.insert_unwound_chain(AppendableChain::new(old_canon_chain));
1293 }
1294
1295 Ok(())
1296 }
1297
1298 fn revert_canonical_from_database(
1303 &self,
1304 revert_until: BlockNumber,
1305 ) -> Result<Option<Chain>, CanonicalError> {
1306 if self
1313 .externals
1314 .provider_factory
1315 .static_file_provider()
1316 .get_highest_static_file_block(StaticFileSegment::Headers)
1317 .unwrap_or_default() >
1318 revert_until
1319 {
1320 trace!(
1321 target: "blockchain_tree",
1322 "Reverting optimistic canonical chain to block {}",
1323 revert_until
1324 );
1325 return Err(CanonicalError::OptimisticTargetRevert(revert_until));
1326 }
1327
1328 let provider_rw = self.externals.provider_factory.provider_rw()?;
1330
1331 let tip = provider_rw.last_block_number()?;
1332 let revert_range = (revert_until + 1)..=tip;
1333 info!(target: "blockchain_tree", "REORG: revert canonical from database by unwinding chain blocks {:?}", revert_range);
1334 let blocks_and_execution = provider_rw
1336 .take_block_and_execution_above(revert_until, StorageLocation::Database)
1337 .map_err(|e| CanonicalError::CanonicalRevert(e.to_string()))?;
1338
1339 provider_rw.commit()?;
1340
1341 if blocks_and_execution.is_empty() {
1342 Ok(None)
1343 } else {
1344 Ok(Some(blocks_and_execution))
1345 }
1346 }
1347
1348 fn update_reorg_metrics(&self, reorg_depth: f64) {
1349 self.metrics.reorgs.increment(1);
1350 self.metrics.latest_reorg_depth.set(reorg_depth);
1351 }
1352
1353 pub(crate) fn update_chains_metrics(&mut self) {
1359 let height = self.state.block_indices.canonical_tip().number;
1360
1361 let longest_sidechain_height =
1362 self.state.chains.values().map(|chain| chain.tip().number).max();
1363 if let Some(longest_sidechain_height) = longest_sidechain_height {
1364 self.metrics.longest_sidechain_height.set(longest_sidechain_height as f64);
1365 }
1366
1367 self.metrics.sidechains.set(self.state.chains.len() as f64);
1368 self.metrics.canonical_chain_height.set(height as f64);
1369 if let Some(metrics_tx) = self.sync_metrics_tx.as_mut() {
1370 let _ = metrics_tx.send(MetricEvent::SyncHeight { height });
1371 }
1372 }
1373}
1374
1375#[cfg(test)]
1376mod tests {
1377 use super::*;
1378 use alloy_consensus::{Header, TxEip1559, EMPTY_ROOT_HASH};
1379 use alloy_eips::{
1380 eip1559::{ETHEREUM_BLOCK_GAS_LIMIT, INITIAL_BASE_FEE},
1381 eip4895::Withdrawals,
1382 };
1383 use alloy_genesis::{Genesis, GenesisAccount};
1384 use alloy_primitives::{keccak256, Address, PrimitiveSignature as Signature, B256};
1385 use assert_matches::assert_matches;
1386 use linked_hash_set::LinkedHashSet;
1387 use reth_chainspec::{ChainSpecBuilder, MAINNET, MIN_TRANSACTION_GAS};
1388 use reth_consensus::test_utils::TestConsensus;
1389 use reth_db::tables;
1390 use reth_db_api::transaction::DbTxMut;
1391 use reth_evm::test_utils::MockExecutorProvider;
1392 use reth_evm_ethereum::execute::EthExecutorProvider;
1393 use reth_node_types::FullNodePrimitives;
1394 use reth_primitives::{
1395 proofs::{calculate_receipt_root, calculate_transaction_root},
1396 Account, BlockBody, RecoveredTx, Transaction, TransactionSigned,
1397 };
1398 use reth_provider::{
1399 providers::ProviderNodeTypes,
1400 test_utils::{
1401 blocks::BlockchainTestData, create_test_provider_factory_with_chain_spec,
1402 MockNodeTypesWithDB,
1403 },
1404 ProviderFactory, StorageLocation,
1405 };
1406 use reth_revm::primitives::AccountInfo;
1407 use reth_stages_api::StageCheckpoint;
1408 use reth_trie::{root::state_root_unhashed, StateRoot};
1409 use std::collections::HashMap;
1410
1411 fn setup_externals(
1412 exec_res: Vec<ExecutionOutcome>,
1413 ) -> TreeExternals<MockNodeTypesWithDB, MockExecutorProvider> {
1414 let chain_spec = Arc::new(
1415 ChainSpecBuilder::default()
1416 .chain(MAINNET.chain)
1417 .genesis(MAINNET.genesis.clone())
1418 .shanghai_activated()
1419 .build(),
1420 );
1421 let provider_factory = create_test_provider_factory_with_chain_spec(chain_spec);
1422 let consensus = Arc::new(TestConsensus::default());
1423 let executor_factory = MockExecutorProvider::default();
1424 executor_factory.extend(exec_res);
1425
1426 TreeExternals::new(provider_factory, consensus, executor_factory)
1427 }
1428
1429 fn setup_genesis<
1430 N: ProviderNodeTypes<
1431 Primitives: FullNodePrimitives<
1432 BlockBody = reth_primitives::BlockBody,
1433 BlockHeader = reth_primitives::Header,
1434 >,
1435 >,
1436 >(
1437 factory: &ProviderFactory<N>,
1438 mut genesis: SealedBlock,
1439 ) {
1440 genesis.header.set_block_number(10);
1443 genesis.header.set_state_root(EMPTY_ROOT_HASH);
1444 let provider = factory.provider_rw().unwrap();
1445
1446 provider
1447 .insert_historical_block(
1448 genesis.try_seal_with_senders().expect("invalid tx signature in genesis"),
1449 )
1450 .unwrap();
1451
1452 for i in 0..10 {
1454 provider
1455 .tx_ref()
1456 .put::<tables::CanonicalHeaders>(i, B256::new([100 + i as u8; 32]))
1457 .unwrap();
1458 }
1459 provider
1460 .tx_ref()
1461 .put::<tables::StageCheckpoints>("Finish".to_string(), StageCheckpoint::new(10))
1462 .unwrap();
1463 provider.commit().unwrap();
1464 }
1465
1466 #[derive(Default, Debug)]
1468 struct TreeTester {
1469 chain_num: Option<usize>,
1471 block_to_chain: Option<HashMap<BlockHash, SidechainId>>,
1473 fork_to_child: Option<HashMap<BlockHash, HashSet<BlockHash>>>,
1475 pending_blocks: Option<(BlockNumber, HashSet<BlockHash>)>,
1477 buffered_blocks: Option<HashMap<BlockHash, SealedBlockWithSenders>>,
1479 }
1480
1481 impl TreeTester {
1482 const fn with_chain_num(mut self, chain_num: usize) -> Self {
1483 self.chain_num = Some(chain_num);
1484 self
1485 }
1486
1487 fn with_block_to_chain(mut self, block_to_chain: HashMap<BlockHash, SidechainId>) -> Self {
1488 self.block_to_chain = Some(block_to_chain);
1489 self
1490 }
1491
1492 fn with_fork_to_child(
1493 mut self,
1494 fork_to_child: HashMap<BlockHash, HashSet<BlockHash>>,
1495 ) -> Self {
1496 self.fork_to_child = Some(fork_to_child);
1497 self
1498 }
1499
1500 fn with_buffered_blocks(
1501 mut self,
1502 buffered_blocks: HashMap<BlockHash, SealedBlockWithSenders>,
1503 ) -> Self {
1504 self.buffered_blocks = Some(buffered_blocks);
1505 self
1506 }
1507
1508 fn with_pending_blocks(
1509 mut self,
1510 pending_blocks: (BlockNumber, HashSet<BlockHash>),
1511 ) -> Self {
1512 self.pending_blocks = Some(pending_blocks);
1513 self
1514 }
1515
1516 fn assert<N: NodeTypesWithDB, E: BlockExecutorProvider>(self, tree: &BlockchainTree<N, E>) {
1517 if let Some(chain_num) = self.chain_num {
1518 assert_eq!(tree.state.chains.len(), chain_num);
1519 }
1520 if let Some(block_to_chain) = self.block_to_chain {
1521 assert_eq!(*tree.state.block_indices.blocks_to_chain(), block_to_chain);
1522 }
1523 if let Some(fork_to_child) = self.fork_to_child {
1524 let mut x: HashMap<BlockHash, LinkedHashSet<BlockHash>> =
1525 HashMap::with_capacity(fork_to_child.len());
1526 for (key, hash_set) in fork_to_child {
1527 x.insert(key, hash_set.into_iter().collect());
1528 }
1529 assert_eq!(*tree.state.block_indices.fork_to_child(), x);
1530 }
1531 if let Some(pending_blocks) = self.pending_blocks {
1532 let (num, hashes) = tree.state.block_indices.pending_blocks();
1533 let hashes = hashes.into_iter().collect::<HashSet<_>>();
1534 assert_eq!((num, hashes), pending_blocks);
1535 }
1536 if let Some(buffered_blocks) = self.buffered_blocks {
1537 assert_eq!(*tree.state.buffered_blocks.blocks(), buffered_blocks);
1538 }
1539 }
1540 }
1541
1542 #[test]
1543 fn consecutive_reorgs() {
1544 let signer = Address::random();
1545 let initial_signer_balance = U256::from(10).pow(U256::from(18));
1546 let chain_spec = Arc::new(
1547 ChainSpecBuilder::default()
1548 .chain(MAINNET.chain)
1549 .genesis(Genesis {
1550 alloc: BTreeMap::from([(
1551 signer,
1552 GenesisAccount { balance: initial_signer_balance, ..Default::default() },
1553 )]),
1554 ..MAINNET.genesis.clone()
1555 })
1556 .shanghai_activated()
1557 .build(),
1558 );
1559 let provider_factory = create_test_provider_factory_with_chain_spec(chain_spec.clone());
1560 let consensus = Arc::new(TestConsensus::default());
1561 let executor_provider = EthExecutorProvider::ethereum(chain_spec.clone());
1562
1563 {
1564 let provider_rw = provider_factory.provider_rw().unwrap();
1565 provider_rw
1566 .insert_block(
1567 SealedBlock::new(chain_spec.sealed_genesis_header(), Default::default())
1568 .try_seal_with_senders()
1569 .unwrap(),
1570 StorageLocation::Database,
1571 )
1572 .unwrap();
1573 let account = Account { balance: initial_signer_balance, ..Default::default() };
1574 provider_rw.tx_ref().put::<tables::PlainAccountState>(signer, account).unwrap();
1575 provider_rw.tx_ref().put::<tables::HashedAccounts>(keccak256(signer), account).unwrap();
1576 provider_rw.commit().unwrap();
1577 }
1578
1579 let single_tx_cost = U256::from(INITIAL_BASE_FEE * MIN_TRANSACTION_GAS);
1580 let mock_tx = |nonce: u64| -> RecoveredTx {
1581 TransactionSigned::new_unhashed(
1582 Transaction::Eip1559(TxEip1559 {
1583 chain_id: chain_spec.chain.id(),
1584 nonce,
1585 gas_limit: MIN_TRANSACTION_GAS,
1586 to: Address::ZERO.into(),
1587 max_fee_per_gas: INITIAL_BASE_FEE as u128,
1588 ..Default::default()
1589 }),
1590 Signature::test_signature(),
1591 )
1592 .with_signer(signer)
1593 };
1594
1595 let mock_block = |number: u64,
1596 parent: Option<B256>,
1597 body: Vec<RecoveredTx>,
1598 num_of_signer_txs: u64|
1599 -> SealedBlockWithSenders {
1600 let signed_body =
1601 body.clone().into_iter().map(|tx| tx.into_signed()).collect::<Vec<_>>();
1602 let transactions_root = calculate_transaction_root(&signed_body);
1603 let receipts = body
1604 .iter()
1605 .enumerate()
1606 .map(|(idx, tx)| {
1607 Receipt {
1608 tx_type: tx.tx_type(),
1609 success: true,
1610 cumulative_gas_used: (idx as u64 + 1) * MIN_TRANSACTION_GAS,
1611 ..Default::default()
1612 }
1613 .with_bloom()
1614 })
1615 .collect::<Vec<_>>();
1616
1617 let receipts_root = calculate_receipt_root(&receipts);
1619
1620 let header = Header {
1621 number,
1622 parent_hash: parent.unwrap_or_default(),
1623 gas_used: body.len() as u64 * MIN_TRANSACTION_GAS,
1624 gas_limit: ETHEREUM_BLOCK_GAS_LIMIT,
1625 mix_hash: B256::random(),
1626 base_fee_per_gas: Some(INITIAL_BASE_FEE),
1627 transactions_root,
1628 receipts_root,
1629 state_root: state_root_unhashed(HashMap::from([(
1630 signer,
1631 (
1632 AccountInfo {
1633 balance: initial_signer_balance -
1634 (single_tx_cost * U256::from(num_of_signer_txs)),
1635 nonce: num_of_signer_txs,
1636 ..Default::default()
1637 },
1638 EMPTY_ROOT_HASH,
1639 ),
1640 )])),
1641 ..Default::default()
1642 };
1643
1644 SealedBlockWithSenders::new(
1645 SealedBlock {
1646 header: SealedHeader::seal(header),
1647 body: BlockBody {
1648 transactions: signed_body,
1649 ommers: Vec::new(),
1650 withdrawals: Some(Withdrawals::default()),
1651 },
1652 },
1653 body.iter().map(|tx| tx.signer()).collect(),
1654 )
1655 .unwrap()
1656 };
1657
1658 let fork_block = mock_block(1, Some(chain_spec.genesis_hash()), Vec::from([mock_tx(0)]), 1);
1659
1660 let canonical_block_1 =
1661 mock_block(2, Some(fork_block.hash()), Vec::from([mock_tx(1), mock_tx(2)]), 3);
1662 let canonical_block_2 = mock_block(3, Some(canonical_block_1.hash()), Vec::new(), 3);
1663 let canonical_block_3 =
1664 mock_block(4, Some(canonical_block_2.hash()), Vec::from([mock_tx(3)]), 4);
1665
1666 let sidechain_block_1 = mock_block(2, Some(fork_block.hash()), Vec::from([mock_tx(1)]), 2);
1667 let sidechain_block_2 =
1668 mock_block(3, Some(sidechain_block_1.hash()), Vec::from([mock_tx(2)]), 3);
1669
1670 let mut tree = BlockchainTree::new(
1671 TreeExternals::new(provider_factory, consensus, executor_provider),
1672 BlockchainTreeConfig::default(),
1673 )
1674 .expect("failed to create tree");
1675
1676 tree.insert_block(fork_block.clone(), BlockValidationKind::Exhaustive).unwrap();
1677
1678 assert_eq!(
1679 tree.make_canonical(fork_block.hash()).unwrap(),
1680 CanonicalOutcome::Committed { head: fork_block.header.clone() }
1681 );
1682
1683 assert_eq!(
1684 tree.insert_block(canonical_block_1.clone(), BlockValidationKind::Exhaustive).unwrap(),
1685 InsertPayloadOk::Inserted(BlockStatus::Valid(BlockAttachment::Canonical))
1686 );
1687
1688 assert_eq!(
1689 tree.make_canonical(canonical_block_1.hash()).unwrap(),
1690 CanonicalOutcome::Committed { head: canonical_block_1.header.clone() }
1691 );
1692
1693 assert_eq!(
1694 tree.insert_block(canonical_block_2, BlockValidationKind::Exhaustive).unwrap(),
1695 InsertPayloadOk::Inserted(BlockStatus::Valid(BlockAttachment::Canonical))
1696 );
1697
1698 assert_eq!(
1699 tree.insert_block(sidechain_block_1.clone(), BlockValidationKind::Exhaustive).unwrap(),
1700 InsertPayloadOk::Inserted(BlockStatus::Valid(BlockAttachment::HistoricalFork))
1701 );
1702
1703 assert_eq!(
1704 tree.make_canonical(sidechain_block_1.hash()).unwrap(),
1705 CanonicalOutcome::Committed { head: sidechain_block_1.header.clone() }
1706 );
1707
1708 assert_eq!(
1709 tree.make_canonical(canonical_block_1.hash()).unwrap(),
1710 CanonicalOutcome::Committed { head: canonical_block_1.header.clone() }
1711 );
1712
1713 assert_eq!(
1714 tree.insert_block(sidechain_block_2.clone(), BlockValidationKind::Exhaustive).unwrap(),
1715 InsertPayloadOk::Inserted(BlockStatus::Valid(BlockAttachment::HistoricalFork))
1716 );
1717
1718 assert_eq!(
1719 tree.make_canonical(sidechain_block_2.hash()).unwrap(),
1720 CanonicalOutcome::Committed { head: sidechain_block_2.header.clone() }
1721 );
1722
1723 assert_eq!(
1724 tree.insert_block(canonical_block_3.clone(), BlockValidationKind::Exhaustive).unwrap(),
1725 InsertPayloadOk::Inserted(BlockStatus::Valid(BlockAttachment::HistoricalFork))
1726 );
1727
1728 assert_eq!(
1729 tree.make_canonical(canonical_block_3.hash()).unwrap(),
1730 CanonicalOutcome::Committed { head: canonical_block_3.header.clone() }
1731 );
1732 }
1733
1734 #[test]
1735 fn sidechain_block_hashes() {
1736 let data = BlockchainTestData::default_from_number(11);
1737 let (block1, exec1) = data.blocks[0].clone();
1738 let (block2, exec2) = data.blocks[1].clone();
1739 let (block3, exec3) = data.blocks[2].clone();
1740 let (block4, exec4) = data.blocks[3].clone();
1741 let genesis = data.genesis;
1742
1743 let externals =
1745 setup_externals(vec![exec3.clone(), exec2.clone(), exec4, exec3, exec2, exec1]);
1746
1747 setup_genesis(&externals.provider_factory, genesis);
1749
1750 let config = BlockchainTreeConfig::new(1, 2, 3, 2);
1752 let mut tree = BlockchainTree::new(externals, config).expect("failed to create tree");
1753 tree.make_canonical(B256::ZERO).unwrap();
1755
1756 tree.finalize_block(10).unwrap();
1758
1759 assert_eq!(
1760 tree.insert_block(block1.clone(), BlockValidationKind::Exhaustive).unwrap(),
1761 InsertPayloadOk::Inserted(BlockStatus::Valid(BlockAttachment::Canonical))
1762 );
1763
1764 assert_eq!(
1765 tree.insert_block(block2.clone(), BlockValidationKind::Exhaustive).unwrap(),
1766 InsertPayloadOk::Inserted(BlockStatus::Valid(BlockAttachment::Canonical))
1767 );
1768
1769 assert_eq!(
1770 tree.insert_block(block3.clone(), BlockValidationKind::Exhaustive).unwrap(),
1771 InsertPayloadOk::Inserted(BlockStatus::Valid(BlockAttachment::Canonical))
1772 );
1773
1774 assert_eq!(
1775 tree.insert_block(block4, BlockValidationKind::Exhaustive).unwrap(),
1776 InsertPayloadOk::Inserted(BlockStatus::Valid(BlockAttachment::Canonical))
1777 );
1778
1779 let mut block2a = block2;
1780 let block2a_hash = B256::new([0x34; 32]);
1781 block2a.set_hash(block2a_hash);
1782
1783 assert_eq!(
1784 tree.insert_block(block2a.clone(), BlockValidationKind::Exhaustive).unwrap(),
1785 InsertPayloadOk::Inserted(BlockStatus::Valid(BlockAttachment::HistoricalFork))
1786 );
1787
1788 let mut block3a = block3;
1789 let block3a_hash = B256::new([0x35; 32]);
1790 block3a.set_hash(block3a_hash);
1791 block3a.set_parent_hash(block2a.hash());
1792
1793 assert_eq!(
1794 tree.insert_block(block3a.clone(), BlockValidationKind::Exhaustive).unwrap(),
1795 InsertPayloadOk::Inserted(BlockStatus::Valid(BlockAttachment::Canonical)) );
1797
1798 let block3a_chain_id = tree.state.block_indices.get_side_chain_id(&block3a.hash()).unwrap();
1799 assert_eq!(
1800 tree.all_chain_hashes(block3a_chain_id),
1801 BTreeMap::from([
1802 (block1.number, block1.hash()),
1803 (block2a.number, block2a.hash()),
1804 (block3a.number, block3a.hash()),
1805 ])
1806 );
1807 }
1808
1809 #[test]
1810 fn cached_trie_updates() {
1811 let data = BlockchainTestData::default_from_number(11);
1812 let (block1, exec1) = data.blocks[0].clone();
1813 let (block2, exec2) = data.blocks[1].clone();
1814 let (block3, exec3) = data.blocks[2].clone();
1815 let (block4, exec4) = data.blocks[3].clone();
1816 let (block5, exec5) = data.blocks[4].clone();
1817 let genesis = data.genesis;
1818
1819 let externals = setup_externals(vec![exec5.clone(), exec4, exec3, exec2, exec1]);
1821
1822 setup_genesis(&externals.provider_factory, genesis);
1824
1825 let config = BlockchainTreeConfig::new(1, 2, 3, 2);
1827 let mut tree = BlockchainTree::new(externals, config).expect("failed to create tree");
1828 tree.make_canonical(B256::ZERO).unwrap();
1830
1831 tree.finalize_block(10).unwrap();
1833
1834 assert_eq!(
1835 tree.insert_block(block1.clone(), BlockValidationKind::Exhaustive).unwrap(),
1836 InsertPayloadOk::Inserted(BlockStatus::Valid(BlockAttachment::Canonical))
1837 );
1838 let block1_chain_id = tree.state.block_indices.get_side_chain_id(&block1.hash()).unwrap();
1839 let block1_chain = tree.state.chains.get(&block1_chain_id).unwrap();
1840 assert!(block1_chain.trie_updates().is_some());
1841
1842 assert_eq!(
1843 tree.insert_block(block2.clone(), BlockValidationKind::Exhaustive).unwrap(),
1844 InsertPayloadOk::Inserted(BlockStatus::Valid(BlockAttachment::Canonical))
1845 );
1846 let block2_chain_id = tree.state.block_indices.get_side_chain_id(&block2.hash()).unwrap();
1847 let block2_chain = tree.state.chains.get(&block2_chain_id).unwrap();
1848 assert!(block2_chain.trie_updates().is_none());
1849
1850 assert_eq!(
1851 tree.make_canonical(block2.hash()).unwrap(),
1852 CanonicalOutcome::Committed { head: block2.header.clone() }
1853 );
1854
1855 assert_eq!(
1856 tree.insert_block(block3.clone(), BlockValidationKind::Exhaustive).unwrap(),
1857 InsertPayloadOk::Inserted(BlockStatus::Valid(BlockAttachment::Canonical))
1858 );
1859 let block3_chain_id = tree.state.block_indices.get_side_chain_id(&block3.hash()).unwrap();
1860 let block3_chain = tree.state.chains.get(&block3_chain_id).unwrap();
1861 assert!(block3_chain.trie_updates().is_some());
1862
1863 assert_eq!(
1864 tree.make_canonical(block3.hash()).unwrap(),
1865 CanonicalOutcome::Committed { head: block3.header.clone() }
1866 );
1867
1868 assert_eq!(
1869 tree.insert_block(block4.clone(), BlockValidationKind::Exhaustive).unwrap(),
1870 InsertPayloadOk::Inserted(BlockStatus::Valid(BlockAttachment::Canonical))
1871 );
1872 let block4_chain_id = tree.state.block_indices.get_side_chain_id(&block4.hash()).unwrap();
1873 let block4_chain = tree.state.chains.get(&block4_chain_id).unwrap();
1874 assert!(block4_chain.trie_updates().is_some());
1875
1876 assert_eq!(
1877 tree.insert_block(block5.clone(), BlockValidationKind::Exhaustive).unwrap(),
1878 InsertPayloadOk::Inserted(BlockStatus::Valid(BlockAttachment::Canonical))
1879 );
1880
1881 let block5_chain_id = tree.state.block_indices.get_side_chain_id(&block5.hash()).unwrap();
1882 let block5_chain = tree.state.chains.get(&block5_chain_id).unwrap();
1883 assert!(block5_chain.trie_updates().is_none());
1884
1885 assert_eq!(
1886 tree.make_canonical(block5.hash()).unwrap(),
1887 CanonicalOutcome::Committed { head: block5.header.clone() }
1888 );
1889
1890 let provider = tree.externals.provider_factory.provider().unwrap();
1891 let prefix_sets = tree
1892 .externals
1893 .provider_factory
1894 .hashed_post_state(exec5.state())
1895 .construct_prefix_sets()
1896 .freeze();
1897 let state_root =
1898 StateRoot::from_tx(provider.tx_ref()).with_prefix_sets(prefix_sets).root().unwrap();
1899 assert_eq!(state_root, block5.state_root);
1900 }
1901
1902 #[test]
1903 fn test_side_chain_fork() {
1904 let data = BlockchainTestData::default_from_number(11);
1905 let (block1, exec1) = data.blocks[0].clone();
1906 let (block2, exec2) = data.blocks[1].clone();
1907 let genesis = data.genesis;
1908
1909 let externals = setup_externals(vec![exec2.clone(), exec2, exec1]);
1911
1912 setup_genesis(&externals.provider_factory, genesis);
1914
1915 let config = BlockchainTreeConfig::new(1, 2, 3, 2);
1917 let mut tree = BlockchainTree::new(externals, config).expect("failed to create tree");
1918 tree.make_canonical(B256::ZERO).unwrap();
1920
1921 tree.finalize_block(10).unwrap();
1923
1924 assert_eq!(
1925 tree.insert_block(block1.clone(), BlockValidationKind::Exhaustive).unwrap(),
1926 InsertPayloadOk::Inserted(BlockStatus::Valid(BlockAttachment::Canonical))
1927 );
1928
1929 assert_eq!(
1930 tree.insert_block(block2.clone(), BlockValidationKind::Exhaustive).unwrap(),
1931 InsertPayloadOk::Inserted(BlockStatus::Valid(BlockAttachment::Canonical))
1932 );
1933
1934 TreeTester::default()
1945 .with_chain_num(1)
1946 .with_block_to_chain(HashMap::from([
1947 (block1.hash(), 0.into()),
1948 (block2.hash(), 0.into()),
1949 ]))
1950 .with_fork_to_child(HashMap::from([(
1951 block1.parent_hash,
1952 HashSet::from([block1.hash()]),
1953 )]))
1954 .assert(&tree);
1955
1956 let mut block2a = block2.clone();
1957 let block2a_hash = B256::new([0x34; 32]);
1958 block2a.set_hash(block2a_hash);
1959
1960 assert_eq!(
1961 tree.insert_block(block2a.clone(), BlockValidationKind::Exhaustive).unwrap(),
1962 InsertPayloadOk::Inserted(BlockStatus::Valid(BlockAttachment::HistoricalFork))
1963 );
1964
1965 TreeTester::default()
1977 .with_chain_num(2)
1978 .with_block_to_chain(HashMap::from([
1979 (block1.hash(), 0.into()),
1980 (block2.hash(), 0.into()),
1981 (block2a.hash(), 1.into()),
1982 ]))
1983 .with_fork_to_child(HashMap::from([
1984 (block1.parent_hash, HashSet::from([block1.hash()])),
1985 (block2a.parent_hash, HashSet::from([block2a.hash()])),
1986 ]))
1987 .assert(&tree);
1988 let chain0 = tree.state.chains.get(&0.into()).unwrap().execution_outcome();
1990 assert_eq!(chain0.receipts().len(), 2);
1991 assert_eq!(chain0.state().reverts.len(), 2);
1992 assert_eq!(chain0.first_block(), block1.number);
1993 let chain1 = tree.state.chains.get(&1.into()).unwrap().execution_outcome();
1995 assert_eq!(chain1.receipts().len(), 1);
1996 assert_eq!(chain1.state().reverts.len(), 1);
1997 assert_eq!(chain1.first_block(), block2.number);
1998 }
1999
2000 #[test]
2001 fn sanity_path() {
2002 let data = BlockchainTestData::default_from_number(11);
2003 let (block1, exec1) = data.blocks[0].clone();
2004 let (block2, exec2) = data.blocks[1].clone();
2005 let genesis = data.genesis;
2006
2007 let externals = setup_externals(vec![exec2.clone(), exec1.clone(), exec2, exec1]);
2009
2010 setup_genesis(&externals.provider_factory, genesis);
2012
2013 let config = BlockchainTreeConfig::new(1, 2, 3, 2);
2015 let mut tree = BlockchainTree::new(externals, config).expect("failed to create tree");
2016
2017 let mut canon_notif = tree.subscribe_canon_state();
2018 let head = BlockNumHash::new(10, B256::ZERO);
2020 tree.make_canonical(head.hash).unwrap();
2021
2022 tree.is_block_hash_canonical(&B256::ZERO).unwrap();
2024
2025 tree.finalize_block(head.number).unwrap();
2027
2028 assert_eq!(
2030 tree.insert_block(block2.clone(), BlockValidationKind::Exhaustive).unwrap(),
2031 InsertPayloadOk::Inserted(BlockStatus::Disconnected {
2032 head,
2033 missing_ancestor: block2.parent_num_hash()
2034 })
2035 );
2036
2037 TreeTester::default()
2044 .with_buffered_blocks(HashMap::from([(block2.hash(), block2.clone())]))
2045 .assert(&tree);
2046
2047 assert_eq!(
2048 tree.is_block_known(block2.num_hash()).unwrap(),
2049 Some(BlockStatus::Disconnected { head, missing_ancestor: block2.parent_num_hash() })
2050 );
2051
2052 let old_block = BlockNumHash::new(1, B256::new([32; 32]));
2054 let err = BlockchainTreeError::PendingBlockIsFinalized { last_finalized: 10 };
2055
2056 assert_eq!(tree.is_block_known(old_block).unwrap_err().as_tree_error(), Some(err));
2057
2058 assert_eq!(
2060 tree.insert_block(block1.clone(), BlockValidationKind::Exhaustive).unwrap(),
2061 InsertPayloadOk::Inserted(BlockStatus::Valid(BlockAttachment::Canonical))
2062 );
2063
2064 TreeTester::default()
2075 .with_chain_num(1)
2076 .with_block_to_chain(HashMap::from([
2077 (block1.hash(), 0.into()),
2078 (block2.hash(), 0.into()),
2079 ]))
2080 .with_fork_to_child(HashMap::from([(
2081 block1.parent_hash,
2082 HashSet::from([block1.hash()]),
2083 )]))
2084 .with_pending_blocks((block1.number, HashSet::from([block1.hash()])))
2085 .assert(&tree);
2086
2087 assert_eq!(
2089 tree.insert_block(block1.clone(), BlockValidationKind::Exhaustive).unwrap(),
2090 InsertPayloadOk::AlreadySeen(BlockStatus::Valid(BlockAttachment::Canonical))
2091 );
2092
2093 assert_eq!(
2095 tree.insert_block(block2.clone(), BlockValidationKind::Exhaustive).unwrap(),
2096 InsertPayloadOk::AlreadySeen(BlockStatus::Valid(BlockAttachment::Canonical))
2097 );
2098
2099 tree.make_canonical(block1.hash()).unwrap();
2101 assert_matches!(canon_notif.try_recv(), Ok(CanonStateNotification::Commit{ new}) if *new.blocks() == BTreeMap::from([(block1.number,block1.clone())]));
2103
2104 tree.make_canonical(block2.hash()).unwrap();
2106 assert_matches!(canon_notif.try_recv(), Ok(CanonStateNotification::Commit{ new}) if *new.blocks() == BTreeMap::from([(block2.number,block2.clone())]));
2108
2109 TreeTester::default()
2119 .with_chain_num(0)
2120 .with_block_to_chain(HashMap::from([]))
2121 .with_fork_to_child(HashMap::from([]))
2122 .assert(&tree);
2123
2124 let mut block1a = block1.clone();
2127 let block1a_hash = B256::new([0x33; 32]);
2128 block1a.set_hash(block1a_hash);
2129 let mut block2a = block2.clone();
2130 let block2a_hash = B256::new([0x34; 32]);
2131 block2a.set_hash(block2a_hash);
2132
2133 assert_eq!(
2135 tree.insert_block(block1a.clone(), BlockValidationKind::Exhaustive).unwrap(),
2136 InsertPayloadOk::Inserted(BlockStatus::Valid(BlockAttachment::HistoricalFork))
2137 );
2138
2139 TreeTester::default()
2140 .with_chain_num(1)
2141 .with_block_to_chain(HashMap::from([(block1a_hash, 1.into())]))
2142 .with_fork_to_child(HashMap::from([(
2143 block1.parent_hash,
2144 HashSet::from([block1a_hash]),
2145 )]))
2146 .with_pending_blocks((block2.number + 1, HashSet::from([])))
2147 .assert(&tree);
2148
2149 assert_eq!(
2150 tree.insert_block(block2a.clone(), BlockValidationKind::Exhaustive).unwrap(),
2151 InsertPayloadOk::Inserted(BlockStatus::Valid(BlockAttachment::HistoricalFork))
2152 );
2153 TreeTester::default()
2163 .with_chain_num(2)
2164 .with_block_to_chain(HashMap::from([
2165 (block1a_hash, 1.into()),
2166 (block2a_hash, 2.into()),
2167 ]))
2168 .with_fork_to_child(HashMap::from([
2169 (block1.parent_hash, HashSet::from([block1a_hash])),
2170 (block1.hash(), HashSet::from([block2a_hash])),
2171 ]))
2172 .with_pending_blocks((block2.number + 1, HashSet::from([])))
2173 .assert(&tree);
2174
2175 assert!(tree.make_canonical(block2a_hash).is_ok());
2177 assert_matches!(canon_notif.try_recv(),
2179 Ok(CanonStateNotification::Reorg{ old, new})
2180 if *old.blocks() == BTreeMap::from([(block2.number,block2.clone())])
2181 && *new.blocks() == BTreeMap::from([(block2a.number,block2a.clone())]));
2182
2183 TreeTester::default()
2193 .with_chain_num(2)
2194 .with_block_to_chain(HashMap::from([
2195 (block1a_hash, 1.into()),
2196 (block2.hash(), 3.into()),
2197 ]))
2198 .with_fork_to_child(HashMap::from([
2199 (block1.parent_hash, HashSet::from([block1a_hash])),
2200 (block1.hash(), HashSet::from([block2.hash()])),
2201 ]))
2202 .with_pending_blocks((block2.number + 1, HashSet::default()))
2203 .assert(&tree);
2204
2205 assert_matches!(tree.make_canonical(block1a_hash), Ok(_));
2206 TreeTester::default()
2216 .with_chain_num(2)
2217 .with_block_to_chain(HashMap::from([
2218 (block1.hash(), 4.into()),
2219 (block2a_hash, 4.into()),
2220 (block2.hash(), 3.into()),
2221 ]))
2222 .with_fork_to_child(HashMap::from([
2223 (block1.parent_hash, HashSet::from([block1.hash()])),
2224 (block1.hash(), HashSet::from([block2.hash()])),
2225 ]))
2226 .with_pending_blocks((block1a.number + 1, HashSet::default()))
2227 .assert(&tree);
2228
2229 assert_matches!(canon_notif.try_recv(),
2231 Ok(CanonStateNotification::Reorg{ old, new})
2232 if *old.blocks() == BTreeMap::from([(block1.number,block1.clone()),(block2a.number,block2a.clone())])
2233 && *new.blocks() == BTreeMap::from([(block1a.number,block1a.clone())]));
2234
2235 assert!(!tree.is_block_hash_canonical(&block2.hash()).unwrap());
2237 assert!(!tree.is_block_hash_canonical(&block1.hash()).unwrap());
2238
2239 assert!(tree.is_block_hash_canonical(&block1a.hash()).unwrap());
2241
2242 tree.make_canonical(block2.hash()).unwrap();
2244 TreeTester::default()
2254 .with_chain_num(2)
2255 .with_block_to_chain(HashMap::from([
2256 (block1a_hash, 5.into()),
2257 (block2a_hash, 4.into()),
2258 ]))
2259 .with_fork_to_child(HashMap::from([
2260 (block1.parent_hash, HashSet::from([block1a_hash])),
2261 (block1.hash(), HashSet::from([block2a_hash])),
2262 ]))
2263 .with_pending_blocks((block2.number + 1, HashSet::default()))
2264 .assert(&tree);
2265
2266 assert_matches!(canon_notif.try_recv(),
2268 Ok(CanonStateNotification::Reorg{ old, new})
2269 if *old.blocks() == BTreeMap::from([(block1a.number,block1a.clone())])
2270 && *new.blocks() == BTreeMap::from([(block1.number,block1.clone()),(block2.number,block2.clone())]));
2271
2272 assert!(tree.is_block_hash_canonical(&block2.hash()).unwrap());
2274
2275 tree.finalize_block(11).unwrap();
2277 TreeTester::default()
2286 .with_chain_num(1)
2287 .with_block_to_chain(HashMap::from([(block2a_hash, 4.into())]))
2288 .with_fork_to_child(HashMap::from([(block1.hash(), HashSet::from([block2a_hash]))]))
2289 .with_pending_blocks((block2.number + 1, HashSet::from([])))
2290 .assert(&tree);
2291
2292 assert!(tree.unwind(block1.number).is_ok());
2294 TreeTester::default()
2305 .with_chain_num(2)
2306 .with_block_to_chain(HashMap::from([
2307 (block2a_hash, 4.into()),
2308 (block2.hash(), 6.into()),
2309 ]))
2310 .with_fork_to_child(HashMap::from([(
2311 block1.hash(),
2312 HashSet::from([block2a_hash, block2.hash()]),
2313 )]))
2314 .with_pending_blocks((block2.number, HashSet::from([block2.hash(), block2a.hash()])))
2315 .assert(&tree);
2316
2317 tree.make_canonical(block2.hash()).unwrap();
2319
2320 TreeTester::default()
2329 .with_chain_num(1)
2330 .with_block_to_chain(HashMap::from([(block2a_hash, 4.into())]))
2331 .with_fork_to_child(HashMap::from([(block1.hash(), HashSet::from([block2a_hash]))]))
2332 .with_pending_blocks((block2.number + 1, HashSet::default()))
2333 .assert(&tree);
2334
2335 assert_matches!(canon_notif.try_recv(),
2337 Ok(CanonStateNotification::Commit{ new })
2338 if *new.blocks() == BTreeMap::from([(block2.number,block2.clone())]));
2339
2340 let mut block2b = block2a.clone();
2342 block2b.set_hash(B256::new([0x99; 32]));
2343 block2b.set_parent_hash(B256::new([0x88; 32]));
2344
2345 assert_eq!(
2346 tree.insert_block(block2b.clone(), BlockValidationKind::Exhaustive).unwrap(),
2347 InsertPayloadOk::Inserted(BlockStatus::Disconnected {
2348 head: block2.header.num_hash(),
2349 missing_ancestor: block2b.parent_num_hash()
2350 })
2351 );
2352
2353 TreeTester::default()
2354 .with_buffered_blocks(HashMap::from([(block2b.hash(), block2b.clone())]))
2355 .assert(&tree);
2356
2357 assert!(tree.connect_buffered_blocks_to_canonical_hashes_and_finalize(12).is_ok());
2359
2360 assert_eq!(
2361 tree.is_block_known(block2.num_hash()).unwrap(),
2362 Some(BlockStatus::Valid(BlockAttachment::Canonical))
2363 );
2364
2365 TreeTester::default()
2373 .with_chain_num(0)
2374 .with_block_to_chain(HashMap::default())
2375 .with_fork_to_child(HashMap::default())
2376 .with_pending_blocks((block2.number + 1, HashSet::default()))
2377 .with_buffered_blocks(HashMap::default())
2378 .assert(&tree);
2379 }
2380
2381 #[test]
2382 fn last_finalized_block_initialization() {
2383 let data = BlockchainTestData::default_from_number(11);
2384 let (block1, exec1) = data.blocks[0].clone();
2385 let (block2, exec2) = data.blocks[1].clone();
2386 let (block3, exec3) = data.blocks[2].clone();
2387 let genesis = data.genesis;
2388
2389 let externals =
2391 setup_externals(vec![exec3.clone(), exec2.clone(), exec1.clone(), exec3, exec2, exec1]);
2392 let cloned_externals_1 = TreeExternals {
2393 provider_factory: externals.provider_factory.clone(),
2394 executor_factory: externals.executor_factory.clone(),
2395 consensus: externals.consensus.clone(),
2396 };
2397 let cloned_externals_2 = TreeExternals {
2398 provider_factory: externals.provider_factory.clone(),
2399 executor_factory: externals.executor_factory.clone(),
2400 consensus: externals.consensus.clone(),
2401 };
2402
2403 setup_genesis(&externals.provider_factory, genesis);
2405
2406 let config = BlockchainTreeConfig::new(1, 2, 3, 2);
2408 let mut tree = BlockchainTree::new(externals, config).expect("failed to create tree");
2409
2410 assert_eq!(
2411 tree.insert_block(block1.clone(), BlockValidationKind::Exhaustive).unwrap(),
2412 InsertPayloadOk::Inserted(BlockStatus::Valid(BlockAttachment::Canonical))
2413 );
2414
2415 assert_eq!(
2416 tree.insert_block(block2.clone(), BlockValidationKind::Exhaustive).unwrap(),
2417 InsertPayloadOk::Inserted(BlockStatus::Valid(BlockAttachment::Canonical))
2418 );
2419
2420 assert_eq!(
2421 tree.insert_block(block3, BlockValidationKind::Exhaustive).unwrap(),
2422 InsertPayloadOk::Inserted(BlockStatus::Valid(BlockAttachment::Canonical))
2423 );
2424
2425 tree.make_canonical(block2.hash()).unwrap();
2426
2427 let mut tree =
2429 BlockchainTree::new(cloned_externals_1, config).expect("failed to create tree");
2430 assert_eq!(tree.block_indices().last_finalized_block(), 0);
2431
2432 let mut block1a = block1;
2433 let block1a_hash = B256::new([0x33; 32]);
2434 block1a.set_hash(block1a_hash);
2435
2436 assert_eq!(
2437 tree.insert_block(block1a.clone(), BlockValidationKind::Exhaustive).unwrap(),
2438 InsertPayloadOk::Inserted(BlockStatus::Valid(BlockAttachment::HistoricalFork))
2439 );
2440
2441 tree.make_canonical(block1a.hash()).unwrap();
2442 tree.finalize_block(block1a.number).unwrap();
2443
2444 let tree = BlockchainTree::new(cloned_externals_2, config).expect("failed to create tree");
2446
2447 assert_eq!(tree.block_indices().last_finalized_block(), block1a.number);
2448 }
2449}