From 3c681fa45ef82609656827e0f9a19d32a1d47c08 Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Fri, 29 Sep 2023 14:16:27 +0200 Subject: [PATCH] feat: add NoopBlockchainTree (#4852) --- crates/blockchain-tree/src/lib.rs | 3 + crates/blockchain-tree/src/noop.rs | 133 ++++++++++++++++++++++++ crates/blockchain-tree/src/shareable.rs | 10 +- examples/rpc-db/src/main.rs | 43 ++------ 4 files changed, 150 insertions(+), 39 deletions(-) create mode 100644 crates/blockchain-tree/src/noop.rs diff --git a/crates/blockchain-tree/src/lib.rs b/crates/blockchain-tree/src/lib.rs index 946055cac..919a69f42 100644 --- a/crates/blockchain-tree/src/lib.rs +++ b/crates/blockchain-tree/src/lib.rs @@ -48,3 +48,6 @@ mod canonical_chain; pub mod metrics; pub use block_buffer::BlockBuffer; + +/// Implementation of Tree traits that does nothing. +pub mod noop; diff --git a/crates/blockchain-tree/src/noop.rs b/crates/blockchain-tree/src/noop.rs new file mode 100644 index 000000000..d9c87e6d7 --- /dev/null +++ b/crates/blockchain-tree/src/noop.rs @@ -0,0 +1,133 @@ +use reth_interfaces::{ + blockchain_tree::{ + error::{BlockchainTreeError, InsertBlockError}, + BlockchainTreeEngine, BlockchainTreeViewer, CanonicalOutcome, InsertPayloadOk, + }, + RethResult, +}; +use reth_primitives::{ + BlockHash, BlockNumHash, BlockNumber, Receipt, SealedBlock, SealedBlockWithSenders, + SealedHeader, +}; +use reth_provider::{ + BlockchainTreePendingStateProvider, BundleStateDataProvider, CanonStateNotificationSender, + CanonStateNotifications, CanonStateSubscriptions, +}; +use std::collections::{BTreeMap, HashSet}; + +/// A BlockchainTree that does nothing. +/// +/// Caution: this is only intended for testing purposes, or for wiring components together. +#[derive(Debug, Clone, Default)] +#[non_exhaustive] +pub struct NoopBlockchainTree {} + +impl BlockchainTreeEngine for NoopBlockchainTree { + fn buffer_block(&self, _block: SealedBlockWithSenders) -> Result<(), InsertBlockError> { + Ok(()) + } + + fn insert_block( + &self, + block: SealedBlockWithSenders, + ) -> Result { + Err(InsertBlockError::tree_error( + BlockchainTreeError::BlockHashNotFoundInChain { block_hash: block.hash }, + block.block, + )) + } + + fn finalize_block(&self, _finalized_block: BlockNumber) {} + + fn connect_buffered_blocks_to_canonical_hashes_and_finalize( + &self, + _last_finalized_block: BlockNumber, + ) -> RethResult<()> { + Ok(()) + } + + fn connect_buffered_blocks_to_canonical_hashes(&self) -> RethResult<()> { + Ok(()) + } + + fn make_canonical(&self, block_hash: &BlockHash) -> RethResult { + Err(BlockchainTreeError::BlockHashNotFoundInChain { block_hash: *block_hash }.into()) + } + + fn unwind(&self, _unwind_to: BlockNumber) -> RethResult<()> { + Ok(()) + } +} + +impl BlockchainTreeViewer for NoopBlockchainTree { + fn blocks(&self) -> BTreeMap> { + Default::default() + } + + fn header_by_hash(&self, _hash: BlockHash) -> Option { + None + } + + fn block_by_hash(&self, _hash: BlockHash) -> Option { + None + } + + fn buffered_block_by_hash(&self, _block_hash: BlockHash) -> Option { + None + } + + fn buffered_header_by_hash(&self, _block_hash: BlockHash) -> Option { + None + } + + fn canonical_blocks(&self) -> BTreeMap { + Default::default() + } + + fn find_canonical_ancestor(&self, _parent_hash: BlockHash) -> Option { + None + } + + fn is_canonical(&self, block_hash: BlockHash) -> RethResult { + Err(BlockchainTreeError::BlockHashNotFoundInChain { block_hash }.into()) + } + + fn lowest_buffered_ancestor(&self, _hash: BlockHash) -> Option { + None + } + + fn canonical_tip(&self) -> BlockNumHash { + Default::default() + } + + fn pending_blocks(&self) -> (BlockNumber, Vec) { + (0, vec![]) + } + + fn pending_block_num_hash(&self) -> Option { + None + } + + fn pending_block_and_receipts(&self) -> Option<(SealedBlock, Vec)> { + None + } + + fn receipts_by_block_hash(&self, _block_hash: BlockHash) -> Option> { + None + } +} + +impl BlockchainTreePendingStateProvider for NoopBlockchainTree { + fn find_pending_state_provider( + &self, + _block_hash: BlockHash, + ) -> Option> { + None + } +} + +impl CanonStateSubscriptions for NoopBlockchainTree { + fn subscribe_to_canonical_state(&self) -> CanonStateNotifications { + CanonStateNotificationSender::new(1).subscribe() + } +} diff --git a/crates/blockchain-tree/src/shareable.rs b/crates/blockchain-tree/src/shareable.rs index a3f7505d9..d1b777464 100644 --- a/crates/blockchain-tree/src/shareable.rs +++ b/crates/blockchain-tree/src/shareable.rs @@ -149,6 +149,11 @@ impl BlockchainTreeViewer None } + fn is_canonical(&self, hash: BlockHash) -> RethResult { + trace!(target: "blockchain_tree", ?hash, "Checking if block is canonical"); + self.tree.read().is_block_hash_canonical(&hash) + } + fn lowest_buffered_ancestor(&self, hash: BlockHash) -> Option { trace!(target: "blockchain_tree", ?hash, "Returning lowest buffered ancestor"); self.tree.read().lowest_buffered_ancestor(&hash).cloned() @@ -159,11 +164,6 @@ impl BlockchainTreeViewer self.tree.read().block_indices().canonical_tip() } - fn is_canonical(&self, hash: BlockHash) -> RethResult { - trace!(target: "blockchain_tree", ?hash, "Checking if block is canonical"); - self.tree.read().is_block_hash_canonical(&hash) - } - fn pending_blocks(&self) -> (BlockNumber, Vec) { trace!(target: "blockchain_tree", "Returning all pending blocks"); self.tree.read().block_indices().pending_blocks() diff --git a/examples/rpc-db/src/main.rs b/examples/rpc-db/src/main.rs index 54aa243ac..aa97f82b6 100644 --- a/examples/rpc-db/src/main.rs +++ b/examples/rpc-db/src/main.rs @@ -20,23 +20,14 @@ use reth::{ use reth::rpc::builder::{ RethRpcModule, RpcModuleBuilder, RpcServerConfig, TransportRpcModuleConfig, }; - -// Code which we'd ideally like to not need to import if you're only spinning up -// read-only parts of the API and do not require access to pending state or to -// EVM sims -use reth::{ - beacon_consensus::BeaconConsensus, - blockchain_tree::{ - BlockchainTree, BlockchainTreeConfig, ShareableBlockchainTree, TreeExternals, - }, - revm::Factory as ExecutionFactory, -}; - // Configuring the network parts, ideally also wouldn't ned to think about this. -use reth::{providers::test_utils::TestCanonStateSubscriptions, tasks::TokioTaskExecutor}; +use myrpc_ext::{MyRpcExt, MyRpcExtApiServer}; +use reth::{ + blockchain_tree::noop::NoopBlockchainTree, providers::test_utils::TestCanonStateSubscriptions, + tasks::TokioTaskExecutor, +}; use std::{path::Path, sync::Arc}; -use myrpc_ext::{MyRpcExt, MyRpcExtApiServer}; // Custom rpc extension pub mod myrpc_ext; @@ -47,26 +38,10 @@ async fn main() -> eyre::Result<()> { let spec = Arc::new(ChainSpecBuilder::mainnet().build()); let factory = ProviderFactory::new(db.clone(), spec.clone()); - // 2. Setup blcokchain tree to be able to receive live notifs - // TODO: Make this easier to configure - let provider = { - let consensus = Arc::new(BeaconConsensus::new(spec.clone())); - let exec_factory = ExecutionFactory::new(spec.clone()); - - let externals = TreeExternals::new(db.clone(), consensus, exec_factory, spec.clone()); - let tree_config = BlockchainTreeConfig::default(); - let (canon_state_notification_sender, _receiver) = - tokio::sync::broadcast::channel(tree_config.max_reorg_depth() as usize * 2); - - let tree = ShareableBlockchainTree::new(BlockchainTree::new( - externals, - canon_state_notification_sender, - tree_config, - None, - )?); - - BlockchainProvider::new(factory, tree)? - }; + // 2. Setup the blockchain provider using only the database provider and a noop for the tree to + // satisfy trait bounds. Tree is not used in this example since we are only operating on the + // disk and don't handle new blocks/live sync etc, which is done by the blockchain tree. + let provider = BlockchainProvider::new(factory, NoopBlockchainTree::default())?; let rpc_builder = RpcModuleBuilder::default() .with_provider(provider.clone())