feat: add StateProviderFactor::state_by_block_hash (#2390)

This commit is contained in:
Matthias Seitz
2023-04-25 20:11:55 +02:00
committed by GitHub
parent 420a65a206
commit df3274892f
5 changed files with 68 additions and 18 deletions

View File

@ -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<DB: Database, C: Consensus, EF: ExecutorFactory> BlockchainTreeViewer
impl<DB: Database, C: Consensus, EF: ExecutorFactory> BlockchainTreePendingStateProvider
for ShareableBlockchainTree<DB, C, EF>
{
fn pending_state_provider(
fn find_pending_state_provider(
&self,
block_hash: BlockHash,
) -> Result<Box<dyn PostStateDataProvider>, 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<Box<dyn PostStateDataProvider>> {
let provider = self.tree.read().post_state_data(block_hash)?;
Some(Box::new(provider))
}
}

View File

@ -270,6 +270,16 @@ where
self.database.history_by_block_hash(block_hash)
}
fn state_by_block_hash(&self, block: BlockHash) -> Result<StateProviderBox<'_>> {
// 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<StateProviderBox<'_>> {
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<Box<dyn PostStateDataProvider>> {
self.tree.pending_state_provider(block_hash)
) -> Option<Box<dyn PostStateDataProvider>> {
self.tree.find_pending_state_provider(block_hash)
}
}

View File

@ -353,6 +353,10 @@ impl StateProviderFactory for MockEthProvider {
todo!()
}
fn state_by_block_hash(&self, _block: BlockHash) -> Result<StateProviderBox<'_>> {
todo!()
}
fn pending(&self) -> Result<StateProviderBox<'_>> {
todo!()
}
@ -378,6 +382,10 @@ impl StateProviderFactory for Arc<MockEthProvider> {
todo!()
}
fn state_by_block_hash(&self, _block: BlockHash) -> Result<StateProviderBox<'_>> {
todo!()
}
fn pending(&self) -> Result<StateProviderBox<'_>> {
todo!()
}

View File

@ -203,6 +203,10 @@ impl StateProviderFactory for NoopProvider {
Ok(Box::new(*self))
}
fn state_by_block_hash(&self, _block: BlockHash) -> Result<StateProviderBox<'_>> {
Ok(Box::new(*self))
}
fn pending(&self) -> Result<StateProviderBox<'_>> {
Ok(Box::new(*self))
}

View File

@ -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<StateProviderBox<'_>>;
@ -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<StateProviderBox<'_>>;
/// 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<StateProviderBox<'_>>;
/// 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<StateProviderBox<'_>>;
/// 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<StateProviderBox<'_>>;
/// 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<Box<dyn PostStateDataProvider>>;
) -> Result<Box<dyn PostStateDataProvider>> {
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<Box<dyn PostStateDataProvider>>;
}
/// Post state data needs for execution on it.