reth_blockchain_tree/
blockchain_tree.rs

1//! Implementation of [`BlockchainTree`]
2
3use 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/// A Tree of chains.
42///
43/// The flowchart represents all the states a block can have inside the tree.
44///
45/// - Green blocks belong to the canonical chain and are saved inside the database.
46/// - Pending blocks and sidechains are found in-memory inside [`BlockchainTree`].
47///
48/// Both pending chains and sidechains have the same mechanisms, the only difference is when they
49/// get committed to the database.
50///
51/// For pending, it is an append operation, but for sidechains they need to move the current
52/// canonical blocks to the tree (by removing them from the database), and commit the sidechain
53/// blocks to the database to become the canonical chain (reorg).
54///
55/// `include_mmd!("docs/mermaid/tree.mmd`")
56///
57/// # Main functions
58/// * [`BlockchainTree::insert_block`]: Connect a block to a chain, execute it, and if valid, insert
59///   the block into the tree.
60/// * [`BlockchainTree::finalize_block`]: Remove chains that branch off of the now finalized block.
61/// * [`BlockchainTree::make_canonical`]: Check if we have the hash of a block that is the current
62///   canonical head and commit it to db.
63#[derive(Debug)]
64pub struct BlockchainTree<N: NodeTypesWithDB, E> {
65    /// The state of the tree
66    ///
67    /// Tracks all the chains, the block indices, and the block buffer.
68    state: TreeState,
69    /// External components (the database, consensus engine etc.)
70    externals: TreeExternals<N, E>,
71    /// Tree configuration
72    config: BlockchainTreeConfig,
73    /// Broadcast channel for canon state changes notifications.
74    canon_state_notification_sender: CanonStateNotificationSender,
75    /// Metrics for sync stages.
76    sync_metrics_tx: Option<MetricEventsSender>,
77    /// Metrics for the blockchain tree.
78    metrics: TreeMetrics,
79}
80
81impl<N: NodeTypesWithDB, E> BlockchainTree<N, E> {
82    /// Subscribe to new blocks events.
83    ///
84    /// Note: Only canonical blocks are emitted by the tree.
85    pub fn subscribe_canon_state(&self) -> CanonStateNotifications {
86        self.canon_state_notification_sender.subscribe()
87    }
88
89    /// Returns a clone of the sender for the canonical state notifications.
90    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    /// Builds the blockchain tree for the node.
101    ///
102    /// This method configures the blockchain tree, which is a critical component of the node,
103    /// responsible for managing the blockchain state, including blocks, transactions, and receipts.
104    /// It integrates with the consensus mechanism and the EVM for executing transactions.
105    ///
106    /// # Parameters
107    /// - `externals`: External components required by the blockchain tree:
108    ///     - `provider_factory`: A factory for creating various blockchain-related providers, such
109    ///       as for accessing the database or static files.
110    ///     - `consensus`: The consensus configuration, which defines how the node reaches agreement
111    ///       on the blockchain state with other nodes.
112    ///     - `evm_config`: The EVM (Ethereum Virtual Machine) configuration, which affects how
113    ///       smart contracts and transactions are executed. Proper validation of this configuration
114    ///       is crucial for the correct execution of transactions.
115    /// - `tree_config`: Configuration for the blockchain tree, including any parameters that affect
116    ///   its structure or performance.
117    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        // The size of the broadcast is twice the maximum reorg depth, because at maximum reorg
123        // depth at least N blocks must be sent at once.
124        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        // If we haven't written the finalized block, assume it's zero
131        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    /// Replaces the canon state notification sender.
149    ///
150    /// Caution: this will close any existing subscriptions to the previous sender.
151    #[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    /// Set the sync metric events sender.
161    ///
162    /// A transmitter for sending synchronization metrics. This is used for monitoring the node's
163    /// synchronization process with the blockchain network.
164    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    /// Check if the block is known to blockchain tree or database and return its status.
170    ///
171    /// Function will check:
172    /// * if block is inside database returns [`BlockStatus::Valid`].
173    /// * if block is inside buffer returns [`BlockStatus::Disconnected`].
174    /// * if block is part of the canonical returns [`BlockStatus::Valid`].
175    ///
176    /// Returns an error if
177    ///    - an error occurred while reading from the database.
178    ///    - the block is already finalized
179    pub(crate) fn is_block_known(
180        &self,
181        block: BlockNumHash,
182    ) -> Result<Option<BlockStatus>, InsertBlockErrorKind> {
183        // check if block is canonical
184        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        // check db if block is finalized.
190        if block.number <= last_finalized_block {
191            // check if block is inside database
192            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        // is block inside chain
203        if let Some(attachment) = self.is_block_inside_sidechain(&block) {
204            return Ok(Some(BlockStatus::Valid(attachment)));
205        }
206
207        // check if block is disconnected
208        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    /// Expose internal indices of the `BlockchainTree`.
219    #[inline]
220    pub const fn block_indices(&self) -> &BlockIndices {
221        self.state.block_indices()
222    }
223
224    /// Returns the block with matching hash from any side-chain.
225    ///
226    /// Caution: This will not return blocks from the canonical chain.
227    #[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    /// Returns the block with matching hash from any side-chain.
233    ///
234    /// Caution: This will not return blocks from the canonical chain.
235    #[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    /// Returns the block's receipts with matching hash from any side-chain.
244    ///
245    /// Caution: This will not return blocks from the canonical chain.
246    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    /// Returns the block that's considered the `Pending` block, if it exists.
251    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    /// Return items needed to execute on the pending state.
257    /// This includes:
258    ///     * `BlockHash` of canonical block that chain connects to. Needed for creating database
259    ///       provider for the rest of the state.
260    ///     * `BundleState` changes that happened at the asked `block_hash`
261    ///     * `BTreeMap<BlockNumber,BlockHash>` list of past pending and canonical hashes, That are
262    ///       needed for evm `BLOCKHASH` opcode.
263    /// Return none if:
264    ///     * block unknown.
265    ///     * `chain_id` not present in state.
266    ///     * there are no parent hashes stored.
267    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 it is part of the chain
273        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            // get block state
276            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            // get parent hashes
284            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            // get canonical fork.
297            let canonical_fork = self.canonical_fork(chain_id)?;
298            return Some(ExecutionData { execution_outcome, parent_block_hashes, canonical_fork });
299        }
300
301        // check if there is canonical block
302        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    /// Try inserting a validated [Self::validate_block] block inside the tree.
315    ///
316    /// If the block's parent block is unknown, this returns [`BlockStatus::Disconnected`] and the
317    /// block will be buffered until the parent block is inserted and then attached to sidechain
318    #[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        // check if block parent can be found in any side chain.
329        if let Some(chain_id) = self.block_indices().get_side_chain_id(&parent.hash) {
330            // found parent in side tree, try to insert there
331            return self.try_insert_block_into_side_chain(block, chain_id, block_validation_kind);
332        }
333
334        // if not found, check if the parent can be found inside canonical chain.
335        if self.is_block_hash_canonical(&parent.hash)? {
336            return self.try_append_canonical_chain(block.clone(), block_validation_kind);
337        }
338
339        // this is another check to ensure that if the block points to a canonical block its block
340        // is valid
341        if let Some(canonical_parent_number) =
342            self.block_indices().canonical_number(&block.parent_hash)
343        {
344            // we found the parent block in canonical chain
345            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 there is a parent inside the buffer, validate against it.
355        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        // insert block inside unconnected block buffer. Delaying its execution.
360        self.state.buffered_blocks.insert_block(block.clone());
361
362        let block_hash = block.hash();
363        // find the lowest ancestor of the block in the buffer to return as the missing parent
364        // this shouldn't return None because that only happens if the block was evicted, which
365        // shouldn't happen right after insertion
366        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    /// This tries to append the given block to the canonical chain.
379    ///
380    /// WARNING: this expects that the block extends the canonical chain: The block's parent is
381    /// part of the canonical chain (e.g. the block's parent is the latest canonical hash). See also
382    /// [Self::is_block_hash_canonical].
383    #[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        // Validate that the block is post merge
396        let parent_td = provider
397            .header_td(&block.parent_hash)?
398            .ok_or_else(|| BlockchainTreeError::CanonicalChain { block_hash: block.parent_hash })?;
399
400        // Pass the parent total difficulty to short-circuit unnecessary calculations.
401        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    /// Try inserting a block into the given side chain.
445    ///
446    /// WARNING: This expects a valid side chain id, see [BlockIndices::get_side_chain_id]
447    #[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        // Create a new sidechain by forking the given chain, or append the block if the parent
457        // block is the top of the given chain.
458        let block_hashes = self.all_chain_hashes(chain_id);
459
460        // get canonical fork.
461        let canonical_fork = self.canonical_fork(chain_id).ok_or_else(|| {
462            BlockchainTreeError::BlockSideChainIdConsistency { chain_id: chain_id.into() }
463        })?;
464
465        // get chain that block needs to join to.
466        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        // append the block if it is continuing the side chain.
474        let block_attachment = if chain_tip == block.parent_hash {
475            // check if the chain extends the currently tracked canonical head
476            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            // the block starts a new fork
500            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        // After we inserted the block, we try to connect any buffered blocks
513        self.try_connect_buffered_blocks(block_num_hash);
514
515        Ok(BlockStatus::Valid(block_attachment))
516    }
517
518    /// Get all block hashes from a sidechain that are not part of the canonical chain.
519    /// This is a one time operation per block.
520    ///
521    /// # Note
522    ///
523    /// This is not cached in order to save memory.
524    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            // The parent chains might contain blocks with overlapping numbers or numbers greater
531            // than original chain tip. Insert the block hash only if it's not present
532            // for the given block number and the block number does not exceed the
533            // original chain tip.
534            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                // if there is no fork block that point to other chains, break the loop.
549                // it means that this fork joins to canonical block.
550                break
551            }
552        }
553        hashes
554    }
555
556    /// Get the block at which the given chain forks off the current canonical chain.
557    ///
558    /// This is used to figure out what kind of state provider the executor should use to execute
559    /// the block on
560    ///
561    /// Returns `None` if the chain is unknown.
562    fn canonical_fork(&self, chain_id: SidechainId) -> Option<ForkBlock> {
563        let mut chain_id = chain_id;
564        let mut fork;
565        loop {
566            // chain fork block
567            fork = self.state.chains.get(&chain_id)?.fork_block();
568            // get fork block chain
569            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    /// Insert a chain into the tree.
579    ///
580    /// Inserts a chain into the tree and builds the block indices.
581    fn insert_chain(&mut self, chain: AppendableChain) -> Option<SidechainId> {
582        self.state.insert_chain(chain)
583    }
584
585    /// Iterate over all child chains that depend on this block and return
586    /// their ids.
587    fn find_all_dependent_chains(&self, block: &BlockHash) -> HashSet<SidechainId> {
588        // Find all forks of given block.
589        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            // Get chain of dependent block.
595            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            // Find all blocks that fork from this chain.
601            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                    // If there are sub forks append them for processing.
608                    dependent_block.extend(forks);
609                }
610            }
611            // Insert dependent chain id.
612            dependent_chains.insert(chain_id);
613        }
614        dependent_chains
615    }
616
617    /// Inserts unwound chain back into the tree and updates any dependent chains.
618    ///
619    /// This method searches for any chain that depended on this block being part of the canonical
620    /// chain. Each dependent chain's state is then updated with state entries removed from the
621    /// plain state during the unwind.
622    /// Returns the result of inserting the chain or None if any of the dependent chains is not
623    /// in the tree.
624    fn insert_unwound_chain(&mut self, chain: AppendableChain) -> Option<SidechainId> {
625        // iterate over all blocks in chain and find any fork blocks that are in tree.
626        for (number, block) in chain.blocks() {
627            let hash = block.hash();
628
629            // find all chains that fork from this block.
630            let chains_to_bump = self.find_all_dependent_chains(&hash);
631            if !chains_to_bump.is_empty() {
632                // if there is such chain, revert state to this block.
633                let mut cloned_execution_outcome = chain.execution_outcome().clone();
634                cloned_execution_outcome.revert_to(*number);
635
636                // prepend state to all chains that fork from this block.
637                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        // Insert unwound chain to the tree.
654        self.insert_chain(chain)
655    }
656
657    /// Checks the block buffer for the given block.
658    pub fn get_buffered_block(&self, hash: &BlockHash) -> Option<&SealedBlockWithSenders> {
659        self.state.get_buffered_block(hash)
660    }
661
662    /// Gets the lowest ancestor for the given block in the block buffer.
663    pub fn lowest_buffered_ancestor(&self, hash: &BlockHash) -> Option<&SealedBlockWithSenders> {
664        self.state.lowest_buffered_ancestor(hash)
665    }
666
667    /// Insert a new block into the tree.
668    ///
669    /// # Note
670    ///
671    /// This recovers transaction signers (unlike [`BlockchainTree::insert_block`]).
672    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    /// Insert block for future execution.
683    ///
684    /// Returns an error if the block is invalid.
685    pub fn buffer_block(&mut self, block: SealedBlockWithSenders) -> Result<(), InsertBlockError> {
686        // validate block consensus rules
687        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    /// Validate if block is correct and satisfies all the consensus rules that concern the header
696    /// and block body itself.
697    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    /// Check if block is found inside a sidechain and its attachment.
723    ///
724    /// if it is canonical or extends the canonical chain, return [`BlockAttachment::Canonical`]
725    /// if it does not extend the canonical chain, return [`BlockAttachment::HistoricalFork`]
726    /// if the block is not in the tree or its chain id is not valid, return None
727    #[track_caller]
728    fn is_block_inside_sidechain(&self, block: &BlockNumHash) -> Option<BlockAttachment> {
729        // check if block known and is already in the tree
730        if let Some(chain_id) = self.block_indices().get_side_chain_id(&block.hash) {
731            // find the canonical fork of this chain
732            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            // if the block's chain extends canonical chain
737            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    /// Insert a block (with recovered senders) into the tree.
747    ///
748    /// Returns the [`BlockStatus`] on success:
749    ///
750    /// - The block is already part of a sidechain in the tree, or
751    /// - The block is already part of the canonical chain, or
752    /// - The parent is part of a sidechain in the tree, and we can fork at this block, or
753    /// - The parent is part of the canonical chain, and we can fork at this block
754    ///
755    /// Otherwise, an error is returned, indicating that neither the block nor its parent are part
756    /// of the chain or any sidechains.
757    ///
758    /// This means that if the block becomes canonical, we need to fetch the missing blocks over
759    /// P2P.
760    ///
761    /// If the [`BlockValidationKind::SkipStateRootValidation`] variant is provided the state root
762    /// is not validated.
763    ///
764    /// # Note
765    ///
766    /// If the senders have not already been recovered, call
767    /// [`BlockchainTree::insert_block_without_senders`] instead.
768    pub fn insert_block(
769        &mut self,
770        block: SealedBlockWithSenders,
771        block_validation_kind: BlockValidationKind,
772    ) -> Result<InsertPayloadOk, InsertBlockError> {
773        // check if we already have this block
774        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        // validate block consensus rules
781        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    /// Discard all blocks that precede block number from the buffer.
792    pub fn remove_old_blocks(&mut self, block: BlockNumber) {
793        self.state.buffered_blocks.remove_old_blocks(block);
794    }
795
796    /// Finalize blocks up until and including `finalized_block`, and remove them from the tree.
797    pub fn finalize_block(&mut self, finalized_block: BlockNumber) -> ProviderResult<()> {
798        // remove blocks
799        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        // remove chains of removed blocks
804        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        // clean block buffer.
810        self.remove_old_blocks(finalized_block);
811
812        // save finalized block in db.
813        self.externals.save_finalized_block_number(finalized_block)?;
814
815        Ok(())
816    }
817
818    /// Reads the last `N` canonical hashes from the database and updates the block indices of the
819    /// tree by attempting to connect the buffered blocks to canonical hashes.
820    ///
821    ///
822    /// `N` is the maximum of `max_reorg_depth` and the number of block hashes needed to satisfy the
823    /// `BLOCKHASH` opcode in the EVM.
824    ///
825    /// # Note
826    ///
827    /// This finalizes `last_finalized_block` prior to reading the canonical hashes (using
828    /// [`BlockchainTree::finalize_block`]).
829    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    /// Update all block hashes. iterate over present and new list of canonical hashes and compare
843    /// them. Remove all mismatches, disconnect them and removes all chains.
844    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        // remove all chains that got discarded
853        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    /// Update all block hashes. iterate over present and new list of canonical hashes and compare
863    /// them. Remove all mismatches, disconnect them, removes all chains and clears all buffered
864    /// blocks before the tip.
865    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    /// Reads the last `N` canonical hashes from the database and updates the block indices of the
878    /// tree by attempting to connect the buffered blocks to canonical hashes.
879    ///
880    /// `N` is the maximum of `max_reorg_depth` and the number of block hashes needed to satisfy the
881    /// `BLOCKHASH` opcode in the EVM.
882    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        // check unconnected block buffer for children of the canonical hashes
896        for added_block in hashes {
897            self.try_connect_buffered_blocks(added_block.into())
898        }
899
900        // check unconnected block buffer for children of the chains
901        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    /// Connect unconnected (buffered) blocks if the new block closes a gap.
916    ///
917    /// This will try to insert all children of the new block, extending its chain.
918    ///
919    /// If all children are valid, then this essentially appends all child blocks to the
920    /// new block's chain.
921    fn try_connect_buffered_blocks(&mut self, new_block: BlockNumHash) {
922        trace!(target: "blockchain_tree", ?new_block, "try_connect_buffered_blocks");
923
924        // first remove all the children of the new block from the buffer
925        let include_blocks = self.state.buffered_blocks.remove_block_with_children(&new_block.hash);
926        // then try to reinsert them into the tree
927        for block in include_blocks {
928            // don't fail on error, just ignore the block.
929            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    /// Removes chain corresponding to provided chain id from block indices,
939    /// splits it at split target, and returns the canonical part of it.
940    /// Returns [None] if chain is missing.
941    ///
942    /// The pending part of the chain is reinserted back into the tree with the same `chain_id`.
943    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                // rest of split chain is inserted back with same chain_id.
953                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    /// Attempts to find the header for the given block hash if it is canonical.
968    ///
969    /// Returns `Ok(None)` if the block hash is not canonical (block hash does not exist, or is
970    /// included in a sidechain).
971    ///
972    /// Note: this does not distinguish between a block that is finalized and a block that is not
973    /// finalized yet, only whether it is part of the canonical chain or not.
974    pub fn find_canonical_header(
975        &self,
976        hash: &BlockHash,
977    ) -> Result<Option<SealedHeader>, ProviderError> {
978        // if the indices show that the block hash is not canonical, it's either in a sidechain or
979        // canonical, but in the db. If it is in a sidechain, it is not canonical. If it is missing
980        // in the db, then it is also not canonical.
981
982        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    /// Determines whether or not a block is canonical, checking the db if necessary.
1001    ///
1002    /// Note: this does not distinguish between a block that is finalized and a block that is not
1003    /// finalized yet, only whether it is part of the canonical chain or not.
1004    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    /// Make a block and its parent(s) part of the canonical chain and commit them to the database
1009    ///
1010    /// # Note
1011    ///
1012    /// This unwinds the database if necessary, i.e. if parts of the canonical chain have been
1013    /// reorged.
1014    ///
1015    /// # Returns
1016    ///
1017    /// Returns `Ok` if the blocks were canonicalized, or if the blocks were already canonical.
1018    #[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        // If block is already canonical don't return error.
1031        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            // TODO: this could be fetched from the chainspec first
1036            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        // we are splitting chain at the block hash that we want to make canonical
1068        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        // loop while fork blocks are found in Tree.
1081        while let Some(chain_id) = self.block_indices().get_side_chain_id(&fork_block.hash) {
1082            // canonical chain is lower part of the chain.
1083            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        // Merge all chains into one chain.
1098        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        // update canonical index
1120        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        // If chain extends the tip
1129        let chain_notification = if new_canon_chain.fork_block().hash == old_tip.hash {
1130            // Commit new canonical chain to database.
1131            self.commit_canonical_to_database(new_canon_chain.clone(), &mut durations_recorder)?;
1132            CanonStateNotification::Commit { new: Arc::new(new_canon_chain) }
1133        } else {
1134            // It forks to canonical block that is not the tip.
1135            let canon_fork: BlockNumHash = new_canon_chain.fork_block();
1136            // sanity check
1137            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            // Commit new canonical chain.
1162            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                // Insert old canonical chain back into tree.
1168                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 here to confirm that we are reverting nothing from db.
1177                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        // clear trie updates for other children
1189        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        // Send notification about new canonical chain and return outcome of canonicalization.
1206        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    /// Write the given chain to the database as canonical.
1212    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        // Compute state root or retrieve cached trie updates before opening write transaction.
1223        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                    // State root calculation can take a while, and we're sure no write transaction
1238                    // will be open in parallel. See https://github.com/paradigmxyz/reth/issues/6168.
1239                    .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    /// Unwind tables and put it inside state
1280    pub fn unwind(&mut self, unwind_to: BlockNumber) -> Result<(), CanonicalError> {
1281        // nothing to be done if unwind_to is higher then the tip
1282        if self.block_indices().canonical_tip().number <= unwind_to {
1283            return Ok(());
1284        }
1285        // revert `N` blocks from current canonical chain and put them inside BlockchainTree
1286        let old_canon_chain = self.revert_canonical_from_database(unwind_to)?;
1287
1288        // check if there is block in chain
1289        if let Some(old_canon_chain) = old_canon_chain {
1290            self.state.block_indices.unwind_canonical_chain(unwind_to);
1291            // insert old canonical chain to BlockchainTree.
1292            self.insert_unwound_chain(AppendableChain::new(old_canon_chain));
1293        }
1294
1295        Ok(())
1296    }
1297
1298    /// Reverts the canonical chain down to the given block from the database and returns the
1299    /// unwound chain.
1300    ///
1301    /// The block, `revert_until`, is __non-inclusive__, i.e. `revert_until` stays in the database.
1302    fn revert_canonical_from_database(
1303        &self,
1304        revert_until: BlockNumber,
1305    ) -> Result<Option<Chain>, CanonicalError> {
1306        // This should only happen when an optimistic sync target was re-orged.
1307        //
1308        // Static files generally contain finalized data. The blockchain tree only deals
1309        // with non-finalized data. The only scenario where canonical reverts go past the highest
1310        // static file is when an optimistic sync occurred and non-finalized data was written to
1311        // static files.
1312        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        // read data that is needed for new sidechain
1329        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        // read block and execution result from database. and remove traces of block from tables.
1335        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    /// Update blockchain tree chains (canonical and sidechains) and sync metrics.
1354    ///
1355    /// NOTE: this method should not be called during the pipeline sync, because otherwise the sync
1356    /// checkpoint metric will get overwritten. Buffered blocks metrics are updated in
1357    /// [`BlockBuffer`](crate::block_buffer::BlockBuffer) during the pipeline sync.
1358    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        // insert genesis to db.
1441
1442        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        // insert first 10 blocks
1453        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    /// Test data structure that will check tree internals
1467    #[derive(Default, Debug)]
1468    struct TreeTester {
1469        /// Number of chains
1470        chain_num: Option<usize>,
1471        /// Check block to chain index
1472        block_to_chain: Option<HashMap<BlockHash, SidechainId>>,
1473        /// Check fork to child index
1474        fork_to_child: Option<HashMap<BlockHash, HashSet<BlockHash>>>,
1475        /// Pending blocks
1476        pending_blocks: Option<(BlockNumber, HashSet<BlockHash>)>,
1477        /// Buffered blocks
1478        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            // receipts root computation is different for OP
1618            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        // test pops execution results from vector, so order is from last to first.
1744        let externals =
1745            setup_externals(vec![exec3.clone(), exec2.clone(), exec4, exec3, exec2, exec1]);
1746
1747        // last finalized block would be number 9.
1748        setup_genesis(&externals.provider_factory, genesis);
1749
1750        // make tree
1751        let config = BlockchainTreeConfig::new(1, 2, 3, 2);
1752        let mut tree = BlockchainTree::new(externals, config).expect("failed to create tree");
1753        // genesis block 10 is already canonical
1754        tree.make_canonical(B256::ZERO).unwrap();
1755
1756        // make genesis block 10 as finalized
1757        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)) /* TODO: this is incorrect, figure out why */
1796        );
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        // test pops execution results from vector, so order is from last to first.
1820        let externals = setup_externals(vec![exec5.clone(), exec4, exec3, exec2, exec1]);
1821
1822        // last finalized block would be number 9.
1823        setup_genesis(&externals.provider_factory, genesis);
1824
1825        // make tree
1826        let config = BlockchainTreeConfig::new(1, 2, 3, 2);
1827        let mut tree = BlockchainTree::new(externals, config).expect("failed to create tree");
1828        // genesis block 10 is already canonical
1829        tree.make_canonical(B256::ZERO).unwrap();
1830
1831        // make genesis block 10 as finalized
1832        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        // test pops execution results from vector, so order is from last to first.
1910        let externals = setup_externals(vec![exec2.clone(), exec2, exec1]);
1911
1912        // last finalized block would be number 9.
1913        setup_genesis(&externals.provider_factory, genesis);
1914
1915        // make tree
1916        let config = BlockchainTreeConfig::new(1, 2, 3, 2);
1917        let mut tree = BlockchainTree::new(externals, config).expect("failed to create tree");
1918        // genesis block 10 is already canonical
1919        tree.make_canonical(B256::ZERO).unwrap();
1920
1921        // make genesis block 10 as finalized
1922        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        // we have one chain that has two blocks.
1935        // Trie state:
1936        //      b2 (pending block)
1937        //      |
1938        //      |
1939        //      b1 (pending block)
1940        //    /
1941        //  /
1942        // g1 (canonical blocks)
1943        // |
1944        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        // fork chain.
1966        // Trie state:
1967        //      b2  b2a (pending blocks in tree)
1968        //      |   /
1969        //      | /
1970        //      b1
1971        //    /
1972        //  /
1973        // g1 (canonical blocks)
1974        // |
1975
1976        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        // chain 0 has two blocks so receipts and reverts len is 2
1989        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        // chain 1 has one block so receipts and reverts len is 1
1994        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        // test pops execution results from vector, so order is from last to first.
2008        let externals = setup_externals(vec![exec2.clone(), exec1.clone(), exec2, exec1]);
2009
2010        // last finalized block would be number 9.
2011        setup_genesis(&externals.provider_factory, genesis);
2012
2013        // make tree
2014        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        // genesis block 10 is already canonical
2019        let head = BlockNumHash::new(10, B256::ZERO);
2020        tree.make_canonical(head.hash).unwrap();
2021
2022        // make sure is_block_hash_canonical returns true for genesis block
2023        tree.is_block_hash_canonical(&B256::ZERO).unwrap();
2024
2025        // make genesis block 10 as finalized
2026        tree.finalize_block(head.number).unwrap();
2027
2028        // block 2 parent is not known, block2 is buffered.
2029        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        // Buffered block: [block2]
2038        // Trie state:
2039        // |
2040        // g1 (canonical blocks)
2041        // |
2042
2043        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        // check if random block is known
2053        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        // insert block1 and buffered block2 is inserted
2059        assert_eq!(
2060            tree.insert_block(block1.clone(), BlockValidationKind::Exhaustive).unwrap(),
2061            InsertPayloadOk::Inserted(BlockStatus::Valid(BlockAttachment::Canonical))
2062        );
2063
2064        // Buffered blocks: []
2065        // Trie state:
2066        //      b2 (pending block)
2067        //      |
2068        //      |
2069        //      b1 (pending block)
2070        //    /
2071        //  /
2072        // g1 (canonical blocks)
2073        // |
2074        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        // already inserted block will `InsertPayloadOk::AlreadySeen(_)`
2088        assert_eq!(
2089            tree.insert_block(block1.clone(), BlockValidationKind::Exhaustive).unwrap(),
2090            InsertPayloadOk::AlreadySeen(BlockStatus::Valid(BlockAttachment::Canonical))
2091        );
2092
2093        // block two is already inserted.
2094        assert_eq!(
2095            tree.insert_block(block2.clone(), BlockValidationKind::Exhaustive).unwrap(),
2096            InsertPayloadOk::AlreadySeen(BlockStatus::Valid(BlockAttachment::Canonical))
2097        );
2098
2099        // make block1 canonical
2100        tree.make_canonical(block1.hash()).unwrap();
2101        // check notification
2102        assert_matches!(canon_notif.try_recv(), Ok(CanonStateNotification::Commit{ new}) if *new.blocks() == BTreeMap::from([(block1.number,block1.clone())]));
2103
2104        // make block2 canonicals
2105        tree.make_canonical(block2.hash()).unwrap();
2106        // check notification.
2107        assert_matches!(canon_notif.try_recv(), Ok(CanonStateNotification::Commit{ new}) if *new.blocks() == BTreeMap::from([(block2.number,block2.clone())]));
2108
2109        // Trie state:
2110        // b2 (canonical block)
2111        // |
2112        // |
2113        // b1 (canonical block)
2114        // |
2115        // |
2116        // g1 (canonical blocks)
2117        // |
2118        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        /**** INSERT SIDE BLOCKS *** */
2125
2126        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        // reinsert two blocks that point to canonical chain
2134        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        // Trie state:
2154        // b2   b2a (side chain)
2155        // |   /
2156        // | /
2157        // b1  b1a (side chain)
2158        // |  /
2159        // |/
2160        // g1 (10)
2161        // |
2162        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        // make b2a canonical
2176        assert!(tree.make_canonical(block2a_hash).is_ok());
2177        // check notification.
2178        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        // Trie state:
2184        // b2a   b2 (side chain)
2185        // |   /
2186        // | /
2187        // b1  b1a (side chain)
2188        // |  /
2189        // |/
2190        // g1 (10)
2191        // |
2192        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        // Trie state:
2207        //       b2a   b2 (side chain)
2208        //       |   /
2209        //       | /
2210        // b1a  b1 (side chain)
2211        // |  /
2212        // |/
2213        // g1 (10)
2214        // |
2215        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        // check notification.
2230        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        // check that b2 and b1 are not canonical
2236        assert!(!tree.is_block_hash_canonical(&block2.hash()).unwrap());
2237        assert!(!tree.is_block_hash_canonical(&block1.hash()).unwrap());
2238
2239        // ensure that b1a is canonical
2240        assert!(tree.is_block_hash_canonical(&block1a.hash()).unwrap());
2241
2242        // make b2 canonical
2243        tree.make_canonical(block2.hash()).unwrap();
2244        // Trie state:
2245        // b2   b2a (side chain)
2246        // |   /
2247        // | /
2248        // b1  b1a (side chain)
2249        // |  /
2250        // |/
2251        // g1 (10)
2252        // |
2253        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        // check notification.
2267        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        // check that b2 is now canonical
2273        assert!(tree.is_block_hash_canonical(&block2.hash()).unwrap());
2274
2275        // finalize b1 that would make b1a removed from tree
2276        tree.finalize_block(11).unwrap();
2277        // Trie state:
2278        // b2   b2a (side chain)
2279        // |   /
2280        // | /
2281        // b1 (canon)
2282        // |
2283        // g1 (10)
2284        // |
2285        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        // unwind canonical
2293        assert!(tree.unwind(block1.number).is_ok());
2294        // Trie state:
2295        //    b2   b2a (pending block)
2296        //   /    /
2297        //  /   /
2298        // /  /
2299        // b1 (canonical block)
2300        // |
2301        // |
2302        // g1 (canonical blocks)
2303        // |
2304        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        // commit b2a
2318        tree.make_canonical(block2.hash()).unwrap();
2319
2320        // Trie state:
2321        // b2   b2a (side chain)
2322        // |   /
2323        // | /
2324        // b1 (finalized)
2325        // |
2326        // g1 (10)
2327        // |
2328        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        // check notification.
2336        assert_matches!(canon_notif.try_recv(),
2337            Ok(CanonStateNotification::Commit{ new })
2338            if *new.blocks() == BTreeMap::from([(block2.number,block2.clone())]));
2339
2340        // insert unconnected block2b
2341        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        // update canonical block to b2, this would make b2a be removed
2358        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        // Trie state:
2366        // b2 (finalized)
2367        // |
2368        // b1 (finalized)
2369        // |
2370        // g1 (10)
2371        // |
2372        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        // test pops execution results from vector, so order is from last to first.
2390        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        // last finalized block would be number 9.
2404        setup_genesis(&externals.provider_factory, genesis);
2405
2406        // make tree
2407        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        // restart
2428        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        // restart
2445        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}