From 5744ad1fa00a19a894827ed323efd6b456ea09b1 Mon Sep 17 00:00:00 2001 From: Dan Cline <6798349+Rjected@users.noreply.github.com> Date: Tue, 3 Sep 2024 11:24:02 -0400 Subject: [PATCH] feat: impl StateReader for BlockchainProvider2 (#10618) --- .../src/providers/blockchain_provider.rs | 17 +++++++++- .../provider/src/providers/database/mod.rs | 1 + .../src/providers/database/provider.rs | 34 +++++++++++++------ crates/storage/provider/src/traits/block.rs | 9 ++++- 4 files changed, 48 insertions(+), 13 deletions(-) diff --git a/crates/storage/provider/src/providers/blockchain_provider.rs b/crates/storage/provider/src/providers/blockchain_provider.rs index 6e5c7ee6bcaf..190e5c44efd7 100644 --- a/crates/storage/provider/src/providers/blockchain_provider.rs +++ b/crates/storage/provider/src/providers/blockchain_provider.rs @@ -4,7 +4,7 @@ use crate::{ CanonStateSubscriptions, ChainSpecProvider, ChangeSetReader, DatabaseProviderFactory, DatabaseProviderRO, EvmEnvProvider, FinalizedBlockReader, HeaderProvider, ProviderError, ProviderFactory, PruneCheckpointReader, ReceiptProvider, ReceiptProviderIdExt, - RequestsProvider, StageCheckpointReader, StateProviderBox, StateProviderFactory, + RequestsProvider, StageCheckpointReader, StateProviderBox, StateProviderFactory, StateReader, StaticFileProviderFactory, TransactionVariant, TransactionsProvider, WithdrawalsProvider, }; use alloy_rpc_types_engine::ForkchoiceState; @@ -18,6 +18,7 @@ use reth_db_api::{ models::{AccountBeforeTx, StoredBlockBodyIndices}, }; use reth_evm::ConfigureEvmEnv; +use reth_execution_types::ExecutionOutcome; use reth_primitives::{ Account, Address, Block, BlockHash, BlockHashOrNumber, BlockId, BlockNumHash, BlockNumber, BlockNumberOrTag, BlockWithSenders, EthereumHardforks, Header, Receipt, SealedBlock, @@ -1433,6 +1434,20 @@ where } } +impl StateReader for BlockchainProvider2 +where + DB: Database + Sync + Send, +{ + fn get_state(&self, block: BlockNumber) -> ProviderResult> { + if let Some(state) = self.canonical_in_memory_state.state_by_number(block) { + let state = state.block().execution_outcome().clone(); + Ok(Some(state)) + } else { + self.database.provider()?.get_state(block..=block) + } + } +} + #[cfg(test)] mod tests { use std::{ diff --git a/crates/storage/provider/src/providers/database/mod.rs b/crates/storage/provider/src/providers/database/mod.rs index 46b282ea3886..40287c962ea9 100644 --- a/crates/storage/provider/src/providers/database/mod.rs +++ b/crates/storage/provider/src/providers/database/mod.rs @@ -603,6 +603,7 @@ impl Clone for ProviderFactory { } } } + #[cfg(test)] mod tests { use super::*; diff --git a/crates/storage/provider/src/providers/database/provider.rs b/crates/storage/provider/src/providers/database/provider.rs index 15e920178ac3..312cf7deb2a3 100644 --- a/crates/storage/provider/src/providers/database/provider.rs +++ b/crates/storage/provider/src/providers/database/provider.rs @@ -11,8 +11,8 @@ use crate::{ FinalizedBlockWriter, HashingWriter, HeaderProvider, HeaderSyncGap, HeaderSyncGapProvider, HistoricalStateProvider, HistoryWriter, LatestStateProvider, OriginalValuesKnown, ProviderError, PruneCheckpointReader, PruneCheckpointWriter, RequestsProvider, RevertsInit, - StageCheckpointReader, StateChangeWriter, StateProviderBox, StateWriter, StatsReader, - StorageReader, StorageTrieWriter, TransactionVariant, TransactionsProvider, + StageCheckpointReader, StateChangeWriter, StateProviderBox, StateReader, StateWriter, + StatsReader, StorageReader, StorageTrieWriter, TransactionVariant, TransactionsProvider, TransactionsProviderExt, TrieWriter, WithdrawalsProvider, }; use itertools::{izip, Itertools}; @@ -777,12 +777,14 @@ impl DatabaseProvider { /// 1. Take the old value from the changeset /// 2. Take the new value from the local state /// 3. Set the local state to the value in the changeset + /// + /// If the range is empty, or there are no blocks for the given range, then this returns `None`. pub fn get_state( &self, range: RangeInclusive, - ) -> ProviderResult { + ) -> ProviderResult> { if range.is_empty() { - return Ok(ExecutionOutcome::default()) + return Ok(None) } let start_block_number = *range.start(); @@ -790,10 +792,14 @@ impl DatabaseProvider { let block_bodies = self.get::(range.clone())?; // get transaction receipts - let from_transaction_num = - block_bodies.first().expect("already checked if there are blocks").1.first_tx_num(); - let to_transaction_num = - block_bodies.last().expect("already checked if there are blocks").1.last_tx_num(); + let Some(from_transaction_num) = block_bodies.first().map(|bodies| bodies.1.first_tx_num()) + else { + return Ok(None) + }; + let Some(to_transaction_num) = block_bodies.last().map(|bodies| bodies.1.last_tx_num()) + else { + return Ok(None) + }; let storage_range = BlockNumberAddress::range(range.clone()); @@ -830,14 +836,14 @@ impl DatabaseProvider { receipts.push(block_receipts); } - Ok(ExecutionOutcome::new_init( + Ok(Some(ExecutionOutcome::new_init( state, reverts, Vec::new(), receipts.into(), start_block_number, Vec::new(), - )) + ))) } /// Populate a [`BundleStateInit`] and [`RevertsInit`] using cursors over the @@ -3223,12 +3229,18 @@ impl BlockExecutionReader for DatabaseProvider { let blocks = self.get_block_range(range.clone())?; // get execution res - let execution_state = self.get_state(range)?; + let execution_state = self.get_state(range)?.unwrap_or_default(); Ok(Chain::new(blocks, execution_state, None)) } } +impl StateReader for DatabaseProvider { + fn get_state(&self, block: BlockNumber) -> ProviderResult> { + self.get_state(block..=block) + } +} + impl BlockExecutionWriter for DatabaseProvider { fn take_block_and_execution_range( &self, diff --git a/crates/storage/provider/src/traits/block.rs b/crates/storage/provider/src/traits/block.rs index c5623fa01aac..cbdafbbce6dc 100644 --- a/crates/storage/provider/src/traits/block.rs +++ b/crates/storage/provider/src/traits/block.rs @@ -22,7 +22,7 @@ pub trait BlockExecutionWriter: BlockWriter + Send + Sync { ) -> ProviderResult<()>; } -/// BlockExecution Writer +/// BlockExecution Reader #[auto_impl::auto_impl(&, Arc, Box)] pub trait BlockExecutionReader: BlockReader + Send + Sync { /// Get range of blocks and its execution result @@ -32,6 +32,13 @@ pub trait BlockExecutionReader: BlockReader + Send + Sync { ) -> ProviderResult; } +/// This just receives state, or [`ExecutionOutcome`], from the provider +#[auto_impl::auto_impl(&, Arc, Box)] +pub trait StateReader: Send + Sync { + /// Get the [`ExecutionOutcome`] for the given block + fn get_state(&self, block: BlockNumber) -> ProviderResult>; +} + /// Block Writer #[auto_impl::auto_impl(&, Arc, Box)] pub trait BlockWriter: Send + Sync {