From df3274892f041bf42f1ece4f3e57b212dd5bf7f7 Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Tue, 25 Apr 2023 20:11:55 +0200 Subject: [PATCH] feat: add StateProviderFactor::state_by_block_hash (#2390) --- crates/blockchain-tree/src/shareable.rs | 14 ++---- crates/storage/provider/src/providers/mod.rs | 16 +++++-- .../storage/provider/src/test_utils/mock.rs | 8 ++++ .../storage/provider/src/test_utils/noop.rs | 4 ++ crates/storage/provider/src/traits/state.rs | 44 ++++++++++++++++--- 5 files changed, 68 insertions(+), 18 deletions(-) diff --git a/crates/blockchain-tree/src/shareable.rs b/crates/blockchain-tree/src/shareable.rs index 4cf5c080c5..03157168c1 100644 --- a/crates/blockchain-tree/src/shareable.rs +++ b/crates/blockchain-tree/src/shareable.rs @@ -5,7 +5,6 @@ use reth_db::database::Database; use reth_interfaces::{ blockchain_tree::{BlockStatus, BlockchainTreeEngine, BlockchainTreeViewer}, consensus::Consensus, - provider::ProviderError, Error, }; use reth_primitives::{BlockHash, BlockNumHash, BlockNumber, SealedBlock, SealedBlockWithSenders}; @@ -101,17 +100,12 @@ impl BlockchainTreeViewer impl BlockchainTreePendingStateProvider for ShareableBlockchainTree { - fn pending_state_provider( + fn find_pending_state_provider( &self, block_hash: BlockHash, - ) -> Result, Error> { - let post_state = self - .tree - .read() - .post_state_data(block_hash) - .ok_or(ProviderError::UnknownBlockHash(block_hash)) - .map(Box::new)?; - Ok(Box::new(post_state)) + ) -> Option> { + let provider = self.tree.read().post_state_data(block_hash)?; + Some(Box::new(provider)) } } diff --git a/crates/storage/provider/src/providers/mod.rs b/crates/storage/provider/src/providers/mod.rs index c09faa1182..f619d81c6e 100644 --- a/crates/storage/provider/src/providers/mod.rs +++ b/crates/storage/provider/src/providers/mod.rs @@ -270,6 +270,16 @@ where self.database.history_by_block_hash(block_hash) } + fn state_by_block_hash(&self, block: BlockHash) -> Result> { + // check tree first + if let Some(pending) = self.tree.find_pending_state_provider(block) { + return self.pending_with_provider(pending) + } + + // not found in tree, check database + self.history_by_block_hash(block) + } + /// Storage provider for pending state. fn pending(&self) -> Result> { if let Some(block) = self.tree.pending_block() { @@ -351,11 +361,11 @@ where DB: Send + Sync, Tree: BlockchainTreePendingStateProvider, { - fn pending_state_provider( + fn find_pending_state_provider( &self, block_hash: BlockHash, - ) -> Result> { - self.tree.pending_state_provider(block_hash) + ) -> Option> { + self.tree.find_pending_state_provider(block_hash) } } diff --git a/crates/storage/provider/src/test_utils/mock.rs b/crates/storage/provider/src/test_utils/mock.rs index afdafbfdac..0fc632de68 100644 --- a/crates/storage/provider/src/test_utils/mock.rs +++ b/crates/storage/provider/src/test_utils/mock.rs @@ -353,6 +353,10 @@ impl StateProviderFactory for MockEthProvider { todo!() } + fn state_by_block_hash(&self, _block: BlockHash) -> Result> { + todo!() + } + fn pending(&self) -> Result> { todo!() } @@ -378,6 +382,10 @@ impl StateProviderFactory for Arc { todo!() } + fn state_by_block_hash(&self, _block: BlockHash) -> Result> { + todo!() + } + fn pending(&self) -> Result> { todo!() } diff --git a/crates/storage/provider/src/test_utils/noop.rs b/crates/storage/provider/src/test_utils/noop.rs index 44e2747f47..d243590330 100644 --- a/crates/storage/provider/src/test_utils/noop.rs +++ b/crates/storage/provider/src/test_utils/noop.rs @@ -203,6 +203,10 @@ impl StateProviderFactory for NoopProvider { Ok(Box::new(*self)) } + fn state_by_block_hash(&self, _block: BlockHash) -> Result> { + Ok(Box::new(*self)) + } + fn pending(&self) -> Result> { Ok(Box::new(*self)) } diff --git a/crates/storage/provider/src/traits/state.rs b/crates/storage/provider/src/traits/state.rs index dfdcd623b8..9f63909fa7 100644 --- a/crates/storage/provider/src/traits/state.rs +++ b/crates/storage/provider/src/traits/state.rs @@ -1,7 +1,7 @@ use super::AccountProvider; use crate::{post_state::PostState, BlockHashProvider}; use auto_impl::auto_impl; -use reth_interfaces::Result; +use reth_interfaces::{provider::ProviderError, Result}; use reth_primitives::{ Address, BlockHash, BlockId, BlockNumHash, BlockNumber, BlockNumberOrTag, Bytecode, Bytes, StorageKey, StorageValue, H256, KECCAK_EMPTY, U256, @@ -74,7 +74,18 @@ pub trait StateProvider: } /// Light wrapper that returns `StateProvider` implementations that correspond to the given -/// `BlockNumber` or the latest state. +/// `BlockNumber`, the latest state, or the pending state. +/// +/// This type differentiates states into `historical`, `latest` and `pending`, where the `latest` +/// block determines what is historical or pending: `[historical..latest..pending]`. +/// +/// The `latest` state represents the state after the most recent block has been committed to the +/// database, `historical` states are states that have been committed to the database before the +/// `latest` state, and `pending` states are states that have not yet been committed to the +/// database which may or may not become the `latest` state, depending on consensus. +/// +/// Note: the `pending` block is considered the block that extends the canonical chain but one and +/// has the `latest` block as its parent. pub trait StateProviderFactory: Send + Sync { /// Storage provider for latest block. fn latest(&self) -> Result>; @@ -106,13 +117,26 @@ pub trait StateProviderFactory: Send + Sync { } } - /// Returns a [StateProvider] indexed by the given block number. + /// Returns a historical [StateProvider] indexed by the given historic block number. + /// + /// + /// Note: this only looks at historical blocks, not pending blocks. fn history_by_block_number(&self, block: BlockNumber) -> Result>; - /// Returns a [StateProvider] indexed by the given block hash. + /// Returns a historical [StateProvider] indexed by the given block hash. + /// + /// Note: this only looks at historical blocks, not pending blocks. fn history_by_block_hash(&self, block: BlockHash) -> Result>; + /// Returns _any_[StateProvider] with matching block hash. + /// + /// This will return a [StateProvider] for either a historical or pending block. + fn state_by_block_hash(&self, block: BlockHash) -> Result>; + /// Storage provider for pending state. + /// + /// Represents the state at the block that extends the canonical chain by one. + /// If there's no `pending` block, then this is equal to [StateProviderFactory::latest] fn pending(&self) -> Result>; /// Return a [StateProvider] that contains post state data provider. @@ -133,7 +157,17 @@ pub trait BlockchainTreePendingStateProvider: Send + Sync { fn pending_state_provider( &self, block_hash: BlockHash, - ) -> Result>; + ) -> Result> { + Ok(self + .find_pending_state_provider(block_hash) + .ok_or(ProviderError::UnknownBlockHash(block_hash))?) + } + + /// Returns state provider if a matching block exists. + fn find_pending_state_provider( + &self, + block_hash: BlockHash, + ) -> Option>; } /// Post state data needs for execution on it.