reth_blockchain_tree/
shareable.rs

1//! Wrapper around `BlockchainTree` that allows for it to be shared.
2
3use crate::externals::TreeNodeTypes;
4
5use super::BlockchainTree;
6use alloy_eips::BlockNumHash;
7use alloy_primitives::{BlockHash, BlockNumber};
8use parking_lot::RwLock;
9use reth_blockchain_tree_api::{
10    error::{CanonicalError, InsertBlockError},
11    BlockValidationKind, BlockchainTreeEngine, BlockchainTreeViewer, CanonicalOutcome,
12    InsertPayloadOk,
13};
14use reth_evm::execute::BlockExecutorProvider;
15use reth_node_types::NodeTypesWithDB;
16use reth_primitives::{Receipt, SealedBlock, SealedBlockWithSenders, SealedHeader};
17use reth_provider::{
18    providers::ProviderNodeTypes, BlockchainTreePendingStateProvider, CanonStateNotifications,
19    CanonStateSubscriptions, FullExecutionDataProvider, NodePrimitivesProvider, ProviderError,
20};
21use reth_storage_errors::provider::ProviderResult;
22use std::{collections::BTreeMap, sync::Arc};
23use tracing::trace;
24
25/// Shareable blockchain tree that is behind a `RwLock`
26#[derive(Clone, Debug)]
27pub struct ShareableBlockchainTree<N: NodeTypesWithDB, E> {
28    /// `BlockchainTree`
29    pub tree: Arc<RwLock<BlockchainTree<N, E>>>,
30}
31
32impl<N: NodeTypesWithDB, E> ShareableBlockchainTree<N, E> {
33    /// Create a new shareable database.
34    pub fn new(tree: BlockchainTree<N, E>) -> Self {
35        Self { tree: Arc::new(RwLock::new(tree)) }
36    }
37}
38
39impl<N, E> BlockchainTreeEngine for ShareableBlockchainTree<N, E>
40where
41    N: TreeNodeTypes,
42    E: BlockExecutorProvider<Primitives = N::Primitives>,
43{
44    fn buffer_block(&self, block: SealedBlockWithSenders) -> Result<(), InsertBlockError> {
45        let mut tree = self.tree.write();
46        // Blockchain tree metrics shouldn't be updated here, see
47        // `BlockchainTree::update_chains_metrics` documentation.
48        tree.buffer_block(block)
49    }
50
51    fn insert_block(
52        &self,
53        block: SealedBlockWithSenders,
54        validation_kind: BlockValidationKind,
55    ) -> Result<InsertPayloadOk, InsertBlockError> {
56        trace!(target: "blockchain_tree", hash = %block.hash(), number = block.number, parent_hash = %block.parent_hash, "Inserting block");
57        let mut tree = self.tree.write();
58        let res = tree.insert_block(block, validation_kind);
59        tree.update_chains_metrics();
60        res
61    }
62
63    fn finalize_block(&self, finalized_block: BlockNumber) -> ProviderResult<()> {
64        trace!(target: "blockchain_tree", finalized_block, "Finalizing block");
65        let mut tree = self.tree.write();
66        tree.finalize_block(finalized_block)?;
67        tree.update_chains_metrics();
68
69        Ok(())
70    }
71
72    fn connect_buffered_blocks_to_canonical_hashes_and_finalize(
73        &self,
74        last_finalized_block: BlockNumber,
75    ) -> Result<(), CanonicalError> {
76        trace!(target: "blockchain_tree", last_finalized_block, "Connecting buffered blocks to canonical hashes and finalizing the tree");
77        let mut tree = self.tree.write();
78        let res =
79            tree.connect_buffered_blocks_to_canonical_hashes_and_finalize(last_finalized_block);
80        tree.update_chains_metrics();
81        Ok(res?)
82    }
83
84    fn update_block_hashes_and_clear_buffered(
85        &self,
86    ) -> Result<BTreeMap<BlockNumber, BlockHash>, CanonicalError> {
87        let mut tree = self.tree.write();
88        let res = tree.update_block_hashes_and_clear_buffered();
89        tree.update_chains_metrics();
90        Ok(res?)
91    }
92
93    fn connect_buffered_blocks_to_canonical_hashes(&self) -> Result<(), CanonicalError> {
94        trace!(target: "blockchain_tree", "Connecting buffered blocks to canonical hashes");
95        let mut tree = self.tree.write();
96        let res = tree.connect_buffered_blocks_to_canonical_hashes();
97        tree.update_chains_metrics();
98        Ok(res?)
99    }
100
101    fn make_canonical(&self, block_hash: BlockHash) -> Result<CanonicalOutcome, CanonicalError> {
102        trace!(target: "blockchain_tree", %block_hash, "Making block canonical");
103        let mut tree = self.tree.write();
104        let res = tree.make_canonical(block_hash);
105        tree.update_chains_metrics();
106        res
107    }
108}
109
110impl<N, E> BlockchainTreeViewer for ShareableBlockchainTree<N, E>
111where
112    N: TreeNodeTypes,
113    E: BlockExecutorProvider<Primitives = N::Primitives>,
114{
115    fn header_by_hash(&self, hash: BlockHash) -> Option<SealedHeader> {
116        trace!(target: "blockchain_tree", ?hash, "Returning header by hash");
117        self.tree.read().sidechain_block_by_hash(hash).map(|b| b.header.clone())
118    }
119
120    fn block_by_hash(&self, block_hash: BlockHash) -> Option<SealedBlock> {
121        trace!(target: "blockchain_tree", ?block_hash, "Returning block by hash");
122        self.tree.read().sidechain_block_by_hash(block_hash).cloned()
123    }
124
125    fn block_with_senders_by_hash(&self, block_hash: BlockHash) -> Option<SealedBlockWithSenders> {
126        trace!(target: "blockchain_tree", ?block_hash, "Returning block by hash");
127        self.tree.read().block_with_senders_by_hash(block_hash).cloned()
128    }
129
130    fn buffered_header_by_hash(&self, block_hash: BlockHash) -> Option<SealedHeader> {
131        self.tree.read().get_buffered_block(&block_hash).map(|b| b.header.clone())
132    }
133
134    fn is_canonical(&self, hash: BlockHash) -> Result<bool, ProviderError> {
135        trace!(target: "blockchain_tree", ?hash, "Checking if block is canonical");
136        self.tree.read().is_block_hash_canonical(&hash)
137    }
138
139    fn lowest_buffered_ancestor(&self, hash: BlockHash) -> Option<SealedBlockWithSenders> {
140        trace!(target: "blockchain_tree", ?hash, "Returning lowest buffered ancestor");
141        self.tree.read().lowest_buffered_ancestor(&hash).cloned()
142    }
143
144    fn canonical_tip(&self) -> BlockNumHash {
145        trace!(target: "blockchain_tree", "Returning canonical tip");
146        self.tree.read().block_indices().canonical_tip()
147    }
148
149    fn pending_block_num_hash(&self) -> Option<BlockNumHash> {
150        trace!(target: "blockchain_tree", "Returning first pending block");
151        self.tree.read().block_indices().pending_block_num_hash()
152    }
153
154    fn pending_block(&self) -> Option<SealedBlock> {
155        trace!(target: "blockchain_tree", "Returning first pending block");
156        self.tree.read().pending_block().cloned()
157    }
158
159    fn pending_block_and_receipts(&self) -> Option<(SealedBlock, Vec<Receipt>)> {
160        let tree = self.tree.read();
161        let pending_block = tree.pending_block()?.clone();
162        let receipts =
163            tree.receipts_by_block_hash(pending_block.hash())?.into_iter().cloned().collect();
164        Some((pending_block, receipts))
165    }
166
167    fn receipts_by_block_hash(&self, block_hash: BlockHash) -> Option<Vec<Receipt>> {
168        let tree = self.tree.read();
169        Some(tree.receipts_by_block_hash(block_hash)?.into_iter().cloned().collect())
170    }
171}
172
173impl<N, E> BlockchainTreePendingStateProvider for ShareableBlockchainTree<N, E>
174where
175    N: TreeNodeTypes,
176    E: BlockExecutorProvider<Primitives = N::Primitives>,
177{
178    fn find_pending_state_provider(
179        &self,
180        block_hash: BlockHash,
181    ) -> Option<Box<dyn FullExecutionDataProvider>> {
182        trace!(target: "blockchain_tree", ?block_hash, "Finding pending state provider");
183        let provider = self.tree.read().post_state_data(block_hash)?;
184        Some(Box::new(provider))
185    }
186}
187
188impl<N, E> NodePrimitivesProvider for ShareableBlockchainTree<N, E>
189where
190    N: ProviderNodeTypes,
191    E: Send + Sync,
192{
193    type Primitives = N::Primitives;
194}
195
196impl<N, E> CanonStateSubscriptions for ShareableBlockchainTree<N, E>
197where
198    N: TreeNodeTypes,
199    E: Send + Sync,
200{
201    fn subscribe_to_canonical_state(&self) -> CanonStateNotifications {
202        trace!(target: "blockchain_tree", "Registered subscriber for canonical state");
203        self.tree.read().subscribe_canon_state()
204    }
205}