From 0678137a0d2d77791c43fe96fb075e93f8c04d27 Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Wed, 26 Apr 2023 14:58:18 +0200 Subject: [PATCH] chore: add find_block_by_hash and more docs (#2405) --- crates/storage/provider/src/lib.rs | 2 +- .../provider/src/providers/database.rs | 10 +++- crates/storage/provider/src/providers/mod.rs | 20 +++++++ .../storage/provider/src/test_utils/mock.rs | 11 +++- .../storage/provider/src/test_utils/noop.rs | 11 +++- crates/storage/provider/src/traits/block.rs | 57 +++++++++++++++++-- crates/storage/provider/src/traits/mod.rs | 2 +- 7 files changed, 99 insertions(+), 14 deletions(-) diff --git a/crates/storage/provider/src/lib.rs b/crates/storage/provider/src/lib.rs index 71cbd755fc..32895c2b67 100644 --- a/crates/storage/provider/src/lib.rs +++ b/crates/storage/provider/src/lib.rs @@ -11,7 +11,7 @@ /// Various provider traits. mod traits; pub use traits::{ - AccountProvider, BlockExecutor, BlockHashProvider, BlockIdProvider, BlockProvider, + AccountProvider, BlockExecutor, BlockHashProvider, BlockIdProvider, BlockProvider, BlockSource, BlockchainTreePendingStateProvider, CanonStateNotification, CanonStateNotificationSender, CanonStateNotifications, CanonStateSubscriptions, EvmEnvProvider, ExecutorFactory, HeaderProvider, PostStateDataProvider, ReceiptProvider, StateProvider, StateProviderBox, diff --git a/crates/storage/provider/src/providers/database.rs b/crates/storage/provider/src/providers/database.rs index f7cdccda61..42a1d3d04f 100644 --- a/crates/storage/provider/src/providers/database.rs +++ b/crates/storage/provider/src/providers/database.rs @@ -1,6 +1,6 @@ use crate::{ providers::state::{historical::HistoricalStateProvider, latest::LatestStateProvider}, - traits::ReceiptProvider, + traits::{BlockSource, ReceiptProvider}, BlockHashProvider, BlockIdProvider, BlockProvider, EvmEnvProvider, HeaderProvider, ProviderError, StateProviderBox, TransactionsProvider, WithdrawalsProvider, }; @@ -158,6 +158,14 @@ impl BlockIdProvider for ShareableDatabase { } impl BlockProvider for ShareableDatabase { + fn find_block_by_hash(&self, hash: H256, source: BlockSource) -> Result> { + if source.is_database() { + self.block(hash.into()) + } else { + Ok(None) + } + } + fn block(&self, id: BlockId) -> Result> { if let Some(number) = self.block_number_for_id(id)? { if let Some(header) = self.header_by_number(number)? { diff --git a/crates/storage/provider/src/providers/mod.rs b/crates/storage/provider/src/providers/mod.rs index 072238e6c5..2a2e68c7d3 100644 --- a/crates/storage/provider/src/providers/mod.rs +++ b/crates/storage/provider/src/providers/mod.rs @@ -27,6 +27,7 @@ use std::{ mod database; mod post_state_provider; mod state; +use crate::traits::BlockSource; pub use database::*; pub use post_state_provider::PostStateProvider; @@ -140,6 +141,25 @@ where DB: Database, Tree: BlockchainTreeViewer + Send + Sync, { + fn find_block_by_hash(&self, hash: H256, source: BlockSource) -> Result> { + let block = match source { + BlockSource::Any => { + // check pending source first + // Note: it's fine to return the unsealed block because the caller already has the + // hash + let mut block = self.tree.block_by_hash(hash).map(|block| block.unseal()); + if block.is_none() { + block = self.database.block_by_hash(hash)?; + } + block + } + BlockSource::Pending => self.tree.block_by_hash(hash).map(|block| block.unseal()), + BlockSource::Database => self.database.block_by_hash(hash)?, + }; + + Ok(block) + } + fn block(&self, id: BlockId) -> Result> { self.database.block(id) } diff --git a/crates/storage/provider/src/test_utils/mock.rs b/crates/storage/provider/src/test_utils/mock.rs index 9135271fbe..72a4ddb205 100644 --- a/crates/storage/provider/src/test_utils/mock.rs +++ b/crates/storage/provider/src/test_utils/mock.rs @@ -1,7 +1,8 @@ use crate::{ - traits::ReceiptProvider, AccountProvider, BlockHashProvider, BlockIdProvider, BlockProvider, - EvmEnvProvider, HeaderProvider, PostState, PostStateDataProvider, StateProvider, - StateProviderBox, StateProviderFactory, StateRootProvider, TransactionsProvider, + traits::{BlockSource, ReceiptProvider}, + AccountProvider, BlockHashProvider, BlockIdProvider, BlockProvider, EvmEnvProvider, + HeaderProvider, PostState, PostStateDataProvider, StateProvider, StateProviderBox, + StateProviderFactory, StateRootProvider, TransactionsProvider, }; use parking_lot::Mutex; use reth_interfaces::Result; @@ -254,6 +255,10 @@ impl BlockIdProvider for MockEthProvider { } impl BlockProvider for MockEthProvider { + fn find_block_by_hash(&self, hash: H256, _source: BlockSource) -> Result> { + self.block(hash.into()) + } + fn block(&self, id: BlockId) -> Result> { let lock = self.blocks.lock(); match id { diff --git a/crates/storage/provider/src/test_utils/noop.rs b/crates/storage/provider/src/test_utils/noop.rs index 2fb397847b..955c19e400 100644 --- a/crates/storage/provider/src/test_utils/noop.rs +++ b/crates/storage/provider/src/test_utils/noop.rs @@ -1,7 +1,8 @@ use crate::{ - traits::ReceiptProvider, AccountProvider, BlockHashProvider, BlockIdProvider, BlockProvider, - EvmEnvProvider, HeaderProvider, PostState, StateProvider, StateProviderBox, - StateProviderFactory, StateRootProvider, TransactionsProvider, + traits::{BlockSource, ReceiptProvider}, + AccountProvider, BlockHashProvider, BlockIdProvider, BlockProvider, EvmEnvProvider, + HeaderProvider, PostState, StateProvider, StateProviderBox, StateProviderFactory, + StateRootProvider, TransactionsProvider, }; use reth_interfaces::Result; use reth_primitives::{ @@ -43,6 +44,10 @@ impl BlockIdProvider for NoopProvider { } impl BlockProvider for NoopProvider { + fn find_block_by_hash(&self, hash: H256, _source: BlockSource) -> Result> { + self.block(hash.into()) + } + fn block(&self, _id: BlockId) -> Result> { Ok(None) } diff --git a/crates/storage/provider/src/traits/block.rs b/crates/storage/provider/src/traits/block.rs index 044bb5fce7..02136113c7 100644 --- a/crates/storage/provider/src/traits/block.rs +++ b/crates/storage/provider/src/traits/block.rs @@ -2,32 +2,79 @@ use crate::{BlockIdProvider, HeaderProvider, ReceiptProvider, TransactionsProvid use reth_interfaces::Result; use reth_primitives::{Block, BlockId, BlockNumberOrTag, Header, H256}; +/// A helper enum that represents the origin of the requested block. +/// +/// This helper type's sole purpose is to give the caller more control over from where blocks can be +/// fetched. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] +pub enum BlockSource { + /// Check all available sources. + /// + /// Note: it's expected that looking up pending blocks is faster than looking up blocks in the + /// database so this prioritizes Pending > Database. + #[default] + Any, + /// The block was fetched from the pending block source, the blockchain tree that buffers + /// blocks that are not yet finalized. + Pending, + /// The block was fetched from the database. + Database, +} + +impl BlockSource { + /// Returns `true` if the block source is `Pending` or `Any`. + pub fn is_pending(&self) -> bool { + matches!(self, BlockSource::Pending | BlockSource::Any) + } + + /// Returns `true` if the block source is `Database` or `Any`. + pub fn is_database(&self) -> bool { + matches!(self, BlockSource::Database | BlockSource::Any) + } +} + /// Api trait for fetching `Block` related data. +/// +/// If not requested otherwise, implementers of this trait should prioritize fetching blocks from +/// the database. #[auto_impl::auto_impl(&, Arc)] pub trait BlockProvider: BlockIdProvider + HeaderProvider + TransactionsProvider + ReceiptProvider + Send + Sync { - /// Returns the block. + /// Tries to find in the given block source. + /// + /// Note: this only operates on the hash because the number might be ambiguous. + /// + /// Returns `None` if block is not found. + fn find_block_by_hash(&self, hash: H256, source: BlockSource) -> Result>; + + /// Returns the block with given id from the database. /// /// Returns `None` if block is not found. fn block(&self, id: BlockId) -> Result>; - /// Returns the ommers/uncle headers of the given block. + /// Returns the ommers/uncle headers of the given block from the database. /// /// Returns `None` if block is not found. fn ommers(&self, id: BlockId) -> Result>>; - /// Returns the block. Returns `None` if block is not found. + /// Returns the block with matching hash from the database. + /// + /// Returns `None` if block is not found. fn block_by_hash(&self, hash: H256) -> Result> { self.block(hash.into()) } - /// Returns the block. Returns `None` if block is not found. + /// Returns the block with matching tag from the database + /// + /// Returns `None` if block is not found. fn block_by_number_or_tag(&self, num: BlockNumberOrTag) -> Result> { self.block(num.into()) } - /// Returns the block. Returns `None` if block is not found. + /// Returns the block with matching number from database. + /// + /// Returns `None` if block is not found. fn block_by_number(&self, num: u64) -> Result> { self.block(num.into()) } diff --git a/crates/storage/provider/src/traits/mod.rs b/crates/storage/provider/src/traits/mod.rs index 7cbc55adea..f0adfdd2ec 100644 --- a/crates/storage/provider/src/traits/mod.rs +++ b/crates/storage/provider/src/traits/mod.rs @@ -4,7 +4,7 @@ mod account; pub use account::AccountProvider; mod block; -pub use block::BlockProvider; +pub use block::{BlockProvider, BlockSource}; mod block_hash; pub use block_hash::BlockHashProvider;