Skip to content

Commit

Permalink
feat(provider): add *StateProviderRef creation methods to `Database…
Browse files Browse the repository at this point in the history
…Provider` (paradigmxyz#11776)
  • Loading branch information
joshieDo authored Oct 16, 2024
1 parent 183cea4 commit a6358d2
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 8 deletions.
74 changes: 66 additions & 8 deletions crates/storage/provider/src/providers/database/provider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ use crate::{
AccountReader, BlockExecutionReader, BlockExecutionWriter, BlockHashReader, BlockNumReader,
BlockReader, BlockWriter, BundleStateInit, ChainStateBlockReader, ChainStateBlockWriter,
DBProvider, EvmEnvProvider, HashingWriter, HeaderProvider, HeaderSyncGap,
HeaderSyncGapProvider, HistoricalStateProvider, HistoryWriter, LatestStateProvider,
OriginalValuesKnown, ProviderError, PruneCheckpointReader, PruneCheckpointWriter,
RequestsProvider, RevertsInit, StageCheckpointReader, StateChangeWriter, StateProviderBox,
StateReader, StateWriter, StaticFileProviderFactory, StatsReader, StorageReader,
StorageTrieWriter, TransactionVariant, TransactionsProvider, TransactionsProviderExt,
TrieWriter, WithdrawalsProvider,
HeaderSyncGapProvider, HistoricalStateProvider, HistoricalStateProviderRef, HistoryWriter,
LatestStateProvider, LatestStateProviderRef, OriginalValuesKnown, ProviderError,
PruneCheckpointReader, PruneCheckpointWriter, RequestsProvider, RevertsInit,
StageCheckpointReader, StateChangeWriter, StateProviderBox, StateReader, StateWriter,
StaticFileProviderFactory, StatsReader, StorageReader, StorageTrieWriter, TransactionVariant,
TransactionsProvider, TransactionsProviderExt, TrieWriter, WithdrawalsProvider,
};
use alloy_eips::BlockHashOrNumber;
use alloy_primitives::{keccak256, Address, BlockHash, BlockNumber, TxHash, TxNumber, B256, U256};
Expand Down Expand Up @@ -47,7 +47,7 @@ use reth_primitives::{
};
use reth_prune_types::{PruneCheckpoint, PruneModes, PruneSegment};
use reth_stages_types::{StageCheckpoint, StageId};
use reth_storage_api::{StorageChangeSetReader, TryIntoHistoricalStateProvider};
use reth_storage_api::{StateProvider, StorageChangeSetReader, TryIntoHistoricalStateProvider};
use reth_storage_errors::provider::{ProviderResult, RootMismatch};
use reth_trie::{
prefix_set::{PrefixSet, PrefixSetMut, TriePrefixSets},
Expand All @@ -68,7 +68,7 @@ use std::{
time::{Duration, Instant},
};
use tokio::sync::watch;
use tracing::{debug, error, warn};
use tracing::{debug, error, trace, warn};

/// A [`DatabaseProvider`] that holds a read-only database transaction.
pub type DatabaseProviderRO<DB, Spec> = DatabaseProvider<<DB as Database>::TX, Spec>;
Expand Down Expand Up @@ -145,6 +145,64 @@ impl<TX, Spec> DatabaseProvider<TX, Spec> {
}
}

impl<TX: DbTx, Spec: Send + Sync> DatabaseProvider<TX, Spec> {
/// State provider for latest block
pub fn latest<'a>(&'a self) -> ProviderResult<Box<dyn StateProvider + 'a>> {
trace!(target: "providers::db", "Returning latest state provider");
Ok(Box::new(LatestStateProviderRef::new(&self.tx, self.static_file_provider.clone())))
}

/// Storage provider for state at that given block hash
pub fn history_by_block_hash<'a>(
&'a self,
block_hash: BlockHash,
) -> ProviderResult<Box<dyn StateProvider + 'a>> {
let mut block_number =
self.block_number(block_hash)?.ok_or(ProviderError::BlockHashNotFound(block_hash))?;
if block_number == self.best_block_number().unwrap_or_default() &&
block_number == self.last_block_number().unwrap_or_default()
{
return Ok(Box::new(LatestStateProviderRef::new(
&self.tx,
self.static_file_provider.clone(),
)))
}

// +1 as the changeset that we want is the one that was applied after this block.
block_number += 1;

let account_history_prune_checkpoint =
self.get_prune_checkpoint(PruneSegment::AccountHistory)?;
let storage_history_prune_checkpoint =
self.get_prune_checkpoint(PruneSegment::StorageHistory)?;

let mut state_provider = HistoricalStateProviderRef::new(
&self.tx,
block_number,
self.static_file_provider.clone(),
);

// If we pruned account or storage history, we can't return state on every historical block.
// Instead, we should cap it at the latest prune checkpoint for corresponding prune segment.
if let Some(prune_checkpoint_block_number) =
account_history_prune_checkpoint.and_then(|checkpoint| checkpoint.block_number)
{
state_provider = state_provider.with_lowest_available_account_history_block_number(
prune_checkpoint_block_number + 1,
);
}
if let Some(prune_checkpoint_block_number) =
storage_history_prune_checkpoint.and_then(|checkpoint| checkpoint.block_number)
{
state_provider = state_provider.with_lowest_available_storage_history_block_number(
prune_checkpoint_block_number + 1,
);
}

Ok(Box::new(state_provider))
}
}

impl<TX, Spec> StaticFileProviderFactory for DatabaseProvider<TX, Spec> {
/// Returns a static file provider
fn static_file_provider(&self) -> StaticFileProvider {
Expand Down
18 changes: 18 additions & 0 deletions crates/storage/provider/src/providers/state/historical.rs
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,24 @@ impl<'b, TX: DbTx> HistoricalStateProviderRef<'b, TX> {
Ok(HistoryInfo::NotYetWritten)
}
}

/// Set the lowest block number at which the account history is available.
pub const fn with_lowest_available_account_history_block_number(
mut self,
block_number: BlockNumber,
) -> Self {
self.lowest_available_blocks.account_history_block_number = Some(block_number);
self
}

/// Set the lowest block number at which the storage history is available.
pub const fn with_lowest_available_storage_history_block_number(
mut self,
block_number: BlockNumber,
) -> Self {
self.lowest_available_blocks.storage_history_block_number = Some(block_number);
self
}
}

impl<TX: DbTx> AccountReader for HistoricalStateProviderRef<'_, TX> {
Expand Down

0 comments on commit a6358d2

Please sign in to comment.