Skip to content
4 changes: 2 additions & 2 deletions crates/storage/provider/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ pub use revm_database::states::OriginalValuesKnown;
// reexport traits to avoid breaking changes
pub use reth_static_file_types as static_file;
pub use reth_storage_api::{
HistoryWriter, MetadataProvider, MetadataWriter, StateWriteConfig, StatsReader,
StorageSettings, StorageSettingsCache,
BalProvider, BalStore, BalStoreHandle, HistoryWriter, MetadataProvider, MetadataWriter,
NoopBalStore, StateWriteConfig, StatsReader, StorageSettings, StorageSettingsCache,
};
/// Re-export provider error.
pub use reth_storage_errors::provider::{ProviderError, ProviderResult};
Expand Down
24 changes: 17 additions & 7 deletions crates/storage/provider/src/providers/blockchain_provider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ use crate::{
ConsistentProvider, ProviderNodeTypes, RocksDBProvider, StaticFileProvider,
StaticFileProviderRWRefMut,
},
AccountReader, BlockHashReader, BlockIdReader, BlockNumReader, BlockReader, BlockReaderIdExt,
BlockSource, CanonChainTracker, CanonStateNotifications, CanonStateSubscriptions,
ChainSpecProvider, ChainStateBlockReader, ChangeSetReader, DatabaseProviderFactory,
HashedPostStateProvider, HeaderProvider, ProviderError, ProviderFactory, PruneCheckpointReader,
ReceiptProvider, ReceiptProviderIdExt, RocksDBProviderFactory, StageCheckpointReader,
StateProviderBox, StateProviderFactory, StateReader, StaticFileProviderFactory,
TransactionVariant, TransactionsProvider,
AccountReader, BalProvider, BalStoreHandle, BlockHashReader, BlockIdReader, BlockNumReader,
BlockReader, BlockReaderIdExt, BlockSource, CanonChainTracker, CanonStateNotifications,
CanonStateSubscriptions, ChainSpecProvider, ChainStateBlockReader, ChangeSetReader,
DatabaseProviderFactory, HashedPostStateProvider, HeaderProvider, ProviderError,
ProviderFactory, PruneCheckpointReader, ReceiptProvider, ReceiptProviderIdExt,
RocksDBProviderFactory, StageCheckpointReader, StateProviderBox, StateProviderFactory,
StateReader, StaticFileProviderFactory, TransactionVariant, TransactionsProvider,
};
use alloy_consensus::transaction::TransactionMeta;
use alloy_eips::{BlockHashOrNumber, BlockId, BlockNumHash, BlockNumberOrTag};
Expand Down Expand Up @@ -50,13 +50,16 @@ pub struct BlockchainProvider<N: NodeTypesWithDB> {
/// Tracks the chain info wrt forkchoice updates and in memory canonical
/// state.
pub(crate) canonical_in_memory_state: CanonicalInMemoryState<N::Primitives>,
/// Store for BALs associated with this provider view.
pub(crate) bal_store: BalStoreHandle,
}

impl<N: NodeTypesWithDB> Clone for BlockchainProvider<N> {
fn clone(&self) -> Self {
Self {
database: self.database.clone(),
canonical_in_memory_state: self.canonical_in_memory_state.clone(),
bal_store: self.bal_store.clone(),
}
}
}
Expand Down Expand Up @@ -108,6 +111,7 @@ impl<N: ProviderNodeTypes> BlockchainProvider<N> {
finalized_header,
safe_header,
),
bal_store: BalStoreHandle::default(),
})
}

Expand Down Expand Up @@ -149,6 +153,12 @@ impl<N: NodeTypesWithDB> NodePrimitivesProvider for BlockchainProvider<N> {
type Primitives = N::Primitives;
}

impl<N: NodeTypesWithDB> BalProvider for BlockchainProvider<N> {
fn bal_store(&self) -> &BalStoreHandle {
&self.bal_store
}
}

impl<N: ProviderNodeTypes> DatabaseProviderFactory for BlockchainProvider<N> {
type DB = N::DB;
type Provider = <ProviderFactory<N> as DatabaseProviderFactory>::Provider;
Expand Down
19 changes: 15 additions & 4 deletions crates/storage/provider/src/test_utils/mock.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use crate::{
traits::{BlockSource, ReceiptProvider},
AccountReader, BlockHashReader, BlockIdReader, BlockNumReader, BlockReader, BlockReaderIdExt,
ChainSpecProvider, ChangeSetReader, HeaderProvider, PruneCheckpointReader,
ReceiptProviderIdExt, StateProvider, StateProviderBox, StateProviderFactory, StateReader,
StateRootProvider, TransactionVariant, TransactionsProvider,
AccountReader, BalProvider, BalStoreHandle, BlockHashReader, BlockIdReader, BlockNumReader,
BlockReader, BlockReaderIdExt, ChainSpecProvider, ChangeSetReader, HeaderProvider,
PruneCheckpointReader, ReceiptProviderIdExt, StateProvider, StateProviderBox,
StateProviderFactory, StateReader, StateRootProvider, TransactionVariant, TransactionsProvider,
};
use alloy_consensus::{
constants::EMPTY_ROOT_HASH,
Expand Down Expand Up @@ -68,6 +68,8 @@ pub struct MockEthProvider<T: NodePrimitives = EthPrimitives, ChainSpec = reth_c
pub state_roots: Arc<Mutex<Vec<B256>>>,
/// Local block body indices store
pub block_body_indices: Arc<Mutex<HashMap<BlockNumber, StoredBlockBodyIndices>>>,
/// Local BAL store handle
pub bal_store: BalStoreHandle,
tx: TxMock,
prune_modes: Arc<PruneModes>,
}
Expand All @@ -85,6 +87,7 @@ where
chain_spec: self.chain_spec.clone(),
state_roots: self.state_roots.clone(),
block_body_indices: self.block_body_indices.clone(),
bal_store: self.bal_store.clone(),
tx: self.tx.clone(),
prune_modes: self.prune_modes.clone(),
}
Expand All @@ -102,6 +105,7 @@ impl<T: NodePrimitives> MockEthProvider<T, reth_chainspec::ChainSpec> {
chain_spec: Arc::new(reth_chainspec::ChainSpecBuilder::mainnet().build()),
state_roots: Default::default(),
block_body_indices: Default::default(),
bal_store: Default::default(),
tx: Default::default(),
prune_modes: Default::default(),
}
Expand Down Expand Up @@ -185,6 +189,7 @@ impl<T: NodePrimitives, ChainSpec> MockEthProvider<T, ChainSpec> {
chain_spec: Arc::new(chain_spec),
state_roots: self.state_roots,
block_body_indices: self.block_body_indices,
bal_store: self.bal_store,
tx: self.tx,
prune_modes: self.prune_modes,
}
Expand Down Expand Up @@ -212,6 +217,12 @@ impl Default for MockEthProvider {
}
}

impl<T: NodePrimitives, ChainSpec> BalProvider for MockEthProvider<T, ChainSpec> {
fn bal_store(&self) -> &BalStoreHandle {
&self.bal_store
}
}

/// An extended account for local store
#[derive(Debug, Clone)]
pub struct ExtendedAccount {
Expand Down
4 changes: 3 additions & 1 deletion crates/storage/provider/src/traits/full.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Helper provider traits to encapsulate all provider traits for simplicity.

use crate::{
AccountReader, BlockReader, BlockReaderIdExt, ChainSpecProvider, ChangeSetReader,
AccountReader, BalProvider, BlockReader, BlockReaderIdExt, ChainSpecProvider, ChangeSetReader,
DatabaseProviderFactory, HashedPostStateProvider, PruneCheckpointReader,
RocksDBProviderFactory, StageCheckpointReader, StateProviderFactory, StateReader,
StaticFileProviderFactory,
Expand Down Expand Up @@ -32,6 +32,7 @@ pub trait FullProvider<N: NodeTypesWithDB>:
Receipt = ReceiptTy<N>,
Header = HeaderTy<N>,
> + AccountReader
+ BalProvider
+ StateProviderFactory
+ StateReader
+ HashedPostStateProvider
Expand Down Expand Up @@ -67,6 +68,7 @@ impl<T, N: NodeTypesWithDB> FullProvider<N> for T where
Receipt = ReceiptTy<N>,
Header = HeaderTy<N>,
> + AccountReader
+ BalProvider
+ StateProviderFactory
+ StateReader
+ HashedPostStateProvider
Expand Down
130 changes: 130 additions & 0 deletions crates/storage/storage-api/src/bal.rs
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this, this is a good start

Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
use alloc::{sync::Arc, vec::Vec};
use alloy_primitives::{BlockHash, BlockNumber, Bytes};
use reth_storage_errors::provider::ProviderResult;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I addition, can we introduce a config type:

struct BalStoreConfig {
  pub prune_mode: PruneMode
}

/// Store for Block Access Lists (BALs).
///
/// This abstraction intentionally does not prescribe where BALs live. Implementations may keep
/// recent BALs in memory, read canonical BALs from static files, or compose multiple tiers behind
/// a single interface.
#[auto_impl::auto_impl(&, Arc, Box)]
pub trait BalStore: Send + Sync + 'static {
/// Insert the BAL for the given block.
fn insert(
&self,
block_hash: BlockHash,
block_number: BlockNumber,
bal: Bytes,
) -> ProviderResult<()>;

/// Fetch BALs for the given block hashes.
///
/// The returned vector must align with `block_hashes`.
fn get_by_hashes(&self, block_hashes: &[BlockHash]) -> ProviderResult<Vec<Option<Bytes>>>;

/// Fetch BALs for the requested range.
///
/// Implementations may stop at the first gap and return the contiguous prefix.
fn get_by_range(&self, start: BlockNumber, count: u64) -> ProviderResult<Vec<Bytes>>;
}

/// Clone-friendly façade around a BAL store implementation.
#[derive(Clone)]
pub struct BalStoreHandle {
inner: Arc<dyn BalStore>,
}

impl BalStoreHandle {
/// Creates a new [`BalStoreHandle`] from the given implementation.
pub fn new(inner: impl BalStore) -> Self {
Self { inner: Arc::new(inner) }
}

/// Creates a [`BalStoreHandle`] backed by [`NoopBalStore`].
pub fn noop() -> Self {
Self::new(NoopBalStore)
}

/// Insert the BAL for the given block.
#[inline]
pub fn insert(
&self,
block_hash: BlockHash,
block_number: BlockNumber,
bal: Bytes,
) -> ProviderResult<()> {
self.inner.insert(block_hash, block_number, bal)
}

/// Fetch BALs for the given block hashes.
#[inline]
pub fn get_by_hashes(&self, block_hashes: &[BlockHash]) -> ProviderResult<Vec<Option<Bytes>>> {
self.inner.get_by_hashes(block_hashes)
}

/// Fetch BALs for the requested range.
#[inline]
pub fn get_by_range(&self, start: BlockNumber, count: u64) -> ProviderResult<Vec<Bytes>> {
self.inner.get_by_range(start, count)
}
}

impl Default for BalStoreHandle {
fn default() -> Self {
Self::noop()
}
}

impl core::fmt::Debug for BalStoreHandle {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("BalStoreHandle").finish_non_exhaustive()
}
}

/// Provider-side access to BAL storage.
#[auto_impl::auto_impl(&, Arc)]
pub trait BalProvider {
/// Returns the configured BAL store handle.
fn bal_store(&self) -> &BalStoreHandle;
}

/// No-op BAL store used as the default wiring target until a concrete implementation is injected.
#[derive(Debug, Default, Clone, Copy)]
pub struct NoopBalStore;

impl BalStore for NoopBalStore {
fn insert(
&self,
_block_hash: BlockHash,
_block_number: BlockNumber,
_bal: Bytes,
) -> ProviderResult<()> {
Ok(())
}

fn get_by_hashes(&self, block_hashes: &[BlockHash]) -> ProviderResult<Vec<Option<Bytes>>> {
Ok(block_hashes.iter().map(|_| None).collect())
}

fn get_by_range(&self, _start: BlockNumber, _count: u64) -> ProviderResult<Vec<Bytes>> {
Ok(Vec::new())
}
}

#[cfg(test)]
mod tests {
use super::*;
use alloy_primitives::B256;

#[test]
fn noop_store_returns_empty_results() {
let store = BalStoreHandle::default();
let hashes = [B256::random(), B256::random()];

let by_hash = store.get_by_hashes(&hashes).unwrap();
let by_range = store.get_by_range(1, 10).unwrap();

assert_eq!(by_hash, vec![None, None]);
assert!(by_range.is_empty());
}
}
3 changes: 3 additions & 0 deletions crates/storage/storage-api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ extern crate alloc;

// Re-export used error types.
pub use reth_storage_errors as errors;
mod bal;
pub use bal::*;

mod account;
pub use account::*;

Expand Down
24 changes: 18 additions & 6 deletions crates/storage/storage-api/src/noop.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
//! Various noop implementations for traits.

pub use crate::bal::NoopBalStore;

use crate::{
AccountReader, BlockBodyIndicesProvider, BlockHashReader, BlockIdReader, BlockNumReader,
BlockReader, BlockReaderIdExt, BlockSource, BytecodeReader, ChangeSetReader,
HashedPostStateProvider, HeaderProvider, NodePrimitivesProvider, PruneCheckpointReader,
ReceiptProvider, ReceiptProviderIdExt, StageCheckpointReader, StateProofProvider,
StateProvider, StateProviderBox, StateProviderFactory, StateReader, StateRootProvider,
StorageRootProvider, TransactionVariant, TransactionsProvider,
AccountReader, BalProvider, BalStoreHandle, BlockBodyIndicesProvider, BlockHashReader,
BlockIdReader, BlockNumReader, BlockReader, BlockReaderIdExt, BlockSource, BytecodeReader,
ChangeSetReader, HashedPostStateProvider, HeaderProvider, NodePrimitivesProvider,
PruneCheckpointReader, ReceiptProvider, ReceiptProviderIdExt, StageCheckpointReader,
StateProofProvider, StateProvider, StateProviderBox, StateProviderFactory, StateReader,
StateRootProvider, StorageRootProvider, TransactionVariant, TransactionsProvider,
};

#[cfg(feature = "db-api")]
Expand Down Expand Up @@ -44,6 +46,7 @@ use reth_trie_common::{
#[non_exhaustive]
pub struct NoopProvider<ChainSpec = reth_chainspec::ChainSpec, N = EthPrimitives> {
chain_spec: Arc<ChainSpec>,
bal_store: BalStoreHandle,
#[cfg(feature = "db-api")]
tx: TxMock,
#[cfg(feature = "db-api")]
Expand All @@ -56,6 +59,7 @@ impl<ChainSpec, N> NoopProvider<ChainSpec, N> {
pub fn new(chain_spec: Arc<ChainSpec>) -> Self {
Self {
chain_spec,
bal_store: BalStoreHandle::default(),
#[cfg(feature = "db-api")]
tx: TxMock::default(),
#[cfg(feature = "db-api")]
Expand All @@ -70,6 +74,7 @@ impl<ChainSpec> NoopProvider<ChainSpec> {
pub fn eth(chain_spec: Arc<ChainSpec>) -> Self {
Self {
chain_spec,
bal_store: BalStoreHandle::default(),
#[cfg(feature = "db-api")]
tx: TxMock::default(),
#[cfg(feature = "db-api")]
Expand All @@ -96,6 +101,7 @@ impl<ChainSpec, N> Clone for NoopProvider<ChainSpec, N> {
fn clone(&self) -> Self {
Self {
chain_spec: Arc::clone(&self.chain_spec),
bal_store: self.bal_store.clone(),
#[cfg(feature = "db-api")]
tx: self.tx.clone(),
#[cfg(feature = "db-api")]
Expand All @@ -105,6 +111,12 @@ impl<ChainSpec, N> Clone for NoopProvider<ChainSpec, N> {
}
}

impl<ChainSpec, N> BalProvider for NoopProvider<ChainSpec, N> {
fn bal_store(&self) -> &BalStoreHandle {
&self.bal_store
}
}

/// Noop implementation for testing purposes
impl<ChainSpec: Send + Sync, N: Send + Sync> BlockHashReader for NoopProvider<ChainSpec, N> {
fn block_hash(&self, _number: u64) -> ProviderResult<Option<B256>> {
Expand Down
Loading