Skip to content

Commit

Permalink
storage api
Browse files Browse the repository at this point in the history
  • Loading branch information
joshieDo committed Oct 29, 2024
1 parent 0c51609 commit 0444fe0
Show file tree
Hide file tree
Showing 10 changed files with 171 additions and 30 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion crates/ethereum/node/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ reth-node-api.workspace = true
reth-chainspec.workspace = true
reth-primitives.workspace = true
reth-revm = { workspace = true, features = ["std"] }

reth-db.workspace = true
alloy-eips.workspace = true
# revm with required ethereum features
revm = { workspace = true, features = ["secp256k1", "blst", "c-kzg"] }

Expand Down
48 changes: 46 additions & 2 deletions crates/ethereum/node/src/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,11 @@ use reth_node_builder::{
BuilderContext, Node, NodeAdapter, NodeComponentsBuilder, PayloadBuilderConfig, PayloadTypes,
};
use reth_payload_builder::{PayloadBuilderHandle, PayloadBuilderService};
use reth_primitives::{Block, Header};
use reth_provider::CanonStateSubscriptions;
use reth_primitives::{Block, BlockBody, Header};
use reth_provider::{
BlockNumReader, BlockReader, CanonStateSubscriptions, ChainStorageReader, HeaderProvider,
TransactionsProvider, WithdrawalsProvider,
};
use reth_rpc::EthApi;
use reth_tracing::tracing::{debug, info};
use reth_transaction_pool::{
Expand Down Expand Up @@ -81,6 +84,47 @@ impl EthereumNode {
impl NodeTypes for EthereumNode {
type Primitives = EthPrimitives;
type ChainSpec = ChainSpec;
type Storage = EthStorage;
}

#[derive(Debug, Default)]
pub struct EthStorage;

impl ChainStorageReader for EthStorage {
fn block<
P: reth_provider::DBProvider<Tx: reth_db::transaction::DbTx>
+ TransactionsProvider
+ BlockReader
+ WithdrawalsProvider
+ HeaderProvider
+ BlockNumReader,
>(
&self,
provider: &P,
id: alloy_eips::BlockHashOrNumber,
) -> reth_provider::ProviderResult<Option<Block>> {
if let Some(number) = provider.convert_hash_or_number(id)? {
if let Some(header) = provider.header_by_number(number)? {
let withdrawals = provider.withdrawals_by_block(number.into(), header.timestamp)?;
let ommers = provider.ommers(number.into())?.unwrap_or_default();
// If the body indices are not found, this means that the transactions either do not
// exist in the database yet, or they do exit but are not indexed.
// If they exist but are not indexed, we don't have enough
// information to return the block anyways, so we return `None`.
let transactions = match provider.transactions_by_block(number.into())? {
Some(transactions) => transactions,
None => return Ok(None),
};

return Ok(Some(Block {
header,
body: BlockBody { transactions, ommers, withdrawals },
}))
}
}

Ok(None)
}
}

impl NodeTypesWithEngine for EthereumNode {
Expand Down
2 changes: 2 additions & 0 deletions crates/node/builder/src/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ where
type Primitives = <N::Types as NodeTypes>::Primitives;

type ChainSpec = <N::Types as NodeTypes>::ChainSpec;

type Storage = <N::Types as NodeTypes>::Storage;
}

impl<N, C, AO> NodeTypesWithEngine for AnyNode<N, C, AO>
Expand Down
1 change: 1 addition & 0 deletions crates/node/types/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@ reth-db-api.workspace = true
reth-engine-primitives.workspace = true
reth-primitives.workspace = true
reth-primitives-traits.workspace = true
reth-storage-api.workspace =true
41 changes: 30 additions & 11 deletions crates/node/types/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]

pub use reth_primitives_traits::{Block, BlockBody};
use reth_storage_api::ChainStorageReader;

use std::marker::PhantomData;

Expand Down Expand Up @@ -39,6 +40,8 @@ pub trait NodeTypes: Send + Sync + Unpin + 'static {
type Primitives: NodePrimitives;
/// The type used for configuration of the EVM.
type ChainSpec: EthChainSpec;
/// The type used for reading chain specific types from storage.
type Storage: ChainStorageReader;
}

/// The type that configures an Ethereum-like node with an engine for consensus.
Expand Down Expand Up @@ -89,6 +92,7 @@ where
{
type Primitives = Types::Primitives;
type ChainSpec = Types::ChainSpec;
type Storage = Types::Storage;
}

impl<Types, DB> NodeTypesWithEngine for NodeTypesWithDBAdapter<Types, DB>
Expand All @@ -109,34 +113,41 @@ where

/// A [`NodeTypes`] type builder.
#[derive(Default, Debug)]
pub struct AnyNodeTypes<P = (), C = ()>(PhantomData<P>, PhantomData<C>);
pub struct AnyNodeTypes<P = (), C = (), S = ()>(PhantomData<P>, PhantomData<C>, PhantomData<S>);

impl<P, C> AnyNodeTypes<P, C> {
impl<P, C, S> AnyNodeTypes<P, C, S> {
/// Sets the `Primitives` associated type.
pub const fn primitives<T>(self) -> AnyNodeTypes<T, C> {
AnyNodeTypes::<T, C>(PhantomData::<T>, PhantomData::<C>)
pub const fn primitives<T>(self) -> AnyNodeTypes<T, C, S> {
AnyNodeTypes::<T, C, S>(PhantomData::<T>, PhantomData::<C>, PhantomData::<S>)
}

/// Sets the `ChainSpec` associated type.
pub const fn chain_spec<T>(self) -> AnyNodeTypes<P, T> {
AnyNodeTypes::<P, T>(PhantomData::<P>, PhantomData::<T>)
pub const fn chain_spec<T>(self) -> AnyNodeTypes<P, T, S> {
AnyNodeTypes::<P, T, S>(PhantomData::<P>, PhantomData::<T>, PhantomData::<S>)
}

/// Sets the `Storage` associated type.
pub const fn storage<T>(self) -> AnyNodeTypes<P, C, T> {
AnyNodeTypes::<P, C, T>(PhantomData::<P>, PhantomData::<C>, PhantomData::<T>)
}
}

impl<P, C> NodeTypes for AnyNodeTypes<P, C>
impl<P, C, S> NodeTypes for AnyNodeTypes<P, C, S>
where
P: NodePrimitives + Send + Sync + Unpin + 'static,
C: EthChainSpec + 'static,
S: ChainStorageReader + 'static,
{
type Primitives = P;
type ChainSpec = C;
type Storage = S;
}

/// A [`NodeTypesWithEngine`] type builder.
#[derive(Default, Debug)]
pub struct AnyNodeTypesWithEngine<P = (), E = (), C = ()> {
pub struct AnyNodeTypesWithEngine<P = (), E = (), C = (), S = ()> {
/// Embedding the basic node types.
base: AnyNodeTypes<P, C>,
base: AnyNodeTypes<P, C, S>,
/// Phantom data for the engine.
_engine: PhantomData<E>,
}
Expand All @@ -156,23 +167,31 @@ impl<P, E, C> AnyNodeTypesWithEngine<P, E, C> {
pub const fn chain_spec<T>(self) -> AnyNodeTypesWithEngine<P, E, T> {
AnyNodeTypesWithEngine { base: self.base.chain_spec::<T>(), _engine: PhantomData }
}

/// Sets the `Storage` associated type.
pub const fn storage<T>(self) -> AnyNodeTypesWithEngine<P, E, C, T> {
AnyNodeTypesWithEngine { base: self.base.storage::<T>(), _engine: PhantomData }
}
}

impl<P, E, C> NodeTypes for AnyNodeTypesWithEngine<P, E, C>
impl<P, E, C, S> NodeTypes for AnyNodeTypesWithEngine<P, E, C, S>
where
P: NodePrimitives + Send + Sync + Unpin + 'static,
E: EngineTypes + Send + Sync + Unpin,
C: EthChainSpec + 'static,
S: ChainStorageReader + 'static,
{
type Primitives = P;
type ChainSpec = C;
type Storage = S;
}

impl<P, E, C> NodeTypesWithEngine for AnyNodeTypesWithEngine<P, E, C>
impl<P, E, C, S> NodeTypesWithEngine for AnyNodeTypesWithEngine<P, E, C, S>
where
P: NodePrimitives + Send + Sync + Unpin + 'static,
E: EngineTypes + Send + Sync + Unpin,
C: EthChainSpec + 'static,
S: ChainStorageReader + 'static,
{
type Engine = E;
}
5 changes: 3 additions & 2 deletions crates/stages/stages/src/stages/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,9 @@ mod tests {
use reth_provider::{
providers::{StaticFileProvider, StaticFileWriter},
test_utils::MockNodeTypesWithDB,
AccountExtReader, BlockReader, DatabaseProviderFactory, ProviderFactory, ProviderResult,
ReceiptProvider, StageCheckpointWriter, StaticFileProviderFactory, StorageReader,
AccountExtReader, BlockReader, ChainStorageReader, DatabaseProviderFactory,
ProviderFactory, ProviderResult, ReceiptProvider, StageCheckpointWriter,
StaticFileProviderFactory,
};
use reth_prune_types::{PruneMode, PruneModes};
use reth_stages_api::{
Expand Down
38 changes: 27 additions & 11 deletions crates/storage/provider/src/providers/database/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,21 @@ use crate::{
use alloy_eips::BlockHashOrNumber;
use alloy_primitives::{Address, BlockHash, BlockNumber, TxHash, TxNumber, B256, U256};
use core::fmt;
use provider::DatabaseProvider2;
use reth_chainspec::{ChainInfo, EthereumHardforks};
use reth_db::{init_db, mdbx::DatabaseArguments, DatabaseEnv};
use reth_db_api::{database::Database, models::StoredBlockBodyIndices};
use reth_errors::{RethError, RethResult};
use reth_evm::ConfigureEvmEnv;
use reth_node_types::NodeTypesWithDB;
use reth_node_types::{NodeTypes, NodeTypesWithDB};
use reth_primitives::{
Block, BlockWithSenders, Header, Receipt, SealedBlock, SealedBlockWithSenders, SealedHeader,
StaticFileSegment, TransactionMeta, TransactionSigned, TransactionSignedNoHash, Withdrawal,
Withdrawals,
};
use reth_prune_types::{PruneCheckpoint, PruneModes, PruneSegment};
use reth_stages_types::{StageCheckpoint, StageId};
use reth_storage_api::TryIntoHistoricalStateProvider;
use reth_storage_api::{ChainStorageReader, TryIntoHistoricalStateProvider};
use reth_storage_errors::provider::ProviderResult;
use revm::primitives::{BlockEnv, CfgEnvWithHandlerCfg};
use std::{
Expand Down Expand Up @@ -53,19 +54,22 @@ pub struct ProviderFactory<N: NodeTypesWithDB> {
static_file_provider: StaticFileProvider,
/// Optional pruning configuration
prune_modes: PruneModes,
/// Chain storage reader
chain_storage: Arc<N::Storage>,
}

impl<N> fmt::Debug for ProviderFactory<N>
where
N: NodeTypesWithDB<DB: fmt::Debug, ChainSpec: fmt::Debug>,
N: NodeTypesWithDB<DB: fmt::Debug, ChainSpec: fmt::Debug, Storage: fmt::Debug>,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let Self { db, chain_spec, static_file_provider, prune_modes } = self;
let Self { db, chain_spec, static_file_provider, prune_modes, chain_storage } = self;
f.debug_struct("ProviderFactory")
.field("db", &db)
.field("chain_spec", &chain_spec)
.field("static_file_provider", &static_file_provider)
.field("prune_modes", &prune_modes)
.field("chain_storage", &chain_storage)
.finish()
}
}
Expand All @@ -77,7 +81,13 @@ impl<N: NodeTypesWithDB> ProviderFactory<N> {
chain_spec: Arc<N::ChainSpec>,
static_file_provider: StaticFileProvider,
) -> Self {
Self { db, chain_spec, static_file_provider, prune_modes: PruneModes::none() }
Self {
db,
chain_spec,
static_file_provider,
prune_modes: PruneModes::none(),
chain_storage: Default::default(),
}
}

/// Enables metrics on the static file provider.
Expand Down Expand Up @@ -118,6 +128,7 @@ impl<N: NodeTypesWithDB<DB = Arc<DatabaseEnv>>> ProviderFactory<N> {
chain_spec,
static_file_provider,
prune_modes: PruneModes::none(),
chain_storage: Default::default(),
})
}
}
Expand All @@ -131,12 +142,15 @@ impl<N: ProviderNodeTypes> ProviderFactory<N> {
/// data.
#[track_caller]
pub fn provider(&self) -> ProviderResult<DatabaseProviderRO<N::DB, N::ChainSpec>> {
Ok(DatabaseProvider::new(
self.db.tx()?,
self.chain_spec.clone(),
self.static_file_provider.clone(),
self.prune_modes.clone(),
))
let provider2: DatabaseProvider2<<<N as NodeTypesWithDB>::DB as Database>::TX, N> =
DatabaseProvider2::new(
self.db.tx()?,
self.chain_spec.clone(),
self.static_file_provider.clone(),
self.prune_modes.clone(),
self.chain_storage.clone(),
);
Ok(provider2.into_provider())
}

/// Returns a provider with a created `DbTxMut` inside, which allows fetching and updating
Expand Down Expand Up @@ -339,6 +353,7 @@ impl<N: ProviderNodeTypes> BlockReader for ProviderFactory<N> {

fn block(&self, id: BlockHashOrNumber) -> ProviderResult<Option<Block>> {
self.provider()?.block(id)
// self.chain_storage.block(&self.provider()?, id)
}

fn pending_block(&self) -> ProviderResult<Option<SealedBlock>> {
Expand Down Expand Up @@ -612,6 +627,7 @@ impl<N: NodeTypesWithDB> Clone for ProviderFactory<N> {
chain_spec: self.chain_spec.clone(),
static_file_provider: self.static_file_provider.clone(),
prune_modes: self.prune_modes.clone(),
chain_storage: self.chain_storage.clone(),
}
}
}
Expand Down
37 changes: 37 additions & 0 deletions crates/storage/provider/src/providers/database/provider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ use reth_db_api::{
use reth_evm::ConfigureEvmEnv;
use reth_execution_types::{Chain, ExecutionOutcome};
use reth_network_p2p::headers::downloader::SyncTarget;
use reth_node_types::NodeTypes;
use reth_primitives::{
Account, Block, BlockBody, BlockWithSenders, Bytecode, GotExpected, Header, Receipt,
SealedBlock, SealedBlockWithSenders, SealedHeader, StaticFileSegment, StorageEntry,
Expand Down Expand Up @@ -124,6 +125,42 @@ impl<DB: Database, Spec> From<DatabaseProviderRW<DB, Spec>>
}
}

/// A provider struct that fetches data from the database.
/// Wrapper around [`DbTx`] and [`DbTxMut`]. Example: [`HeaderProvider`] [`BlockHashReader`]
#[derive(Debug)]
pub struct DatabaseProvider2<TX, N: NodeTypes> {
/// Database transaction.
tx: TX,
/// Chain spec
chain_spec: Arc<N::ChainSpec>,
/// Static File provider
static_file_provider: StaticFileProvider,
/// Pruning configuration
prune_modes: PruneModes,
chain_storage: Arc<N::Storage>,
}

impl<TX, N: NodeTypes> DatabaseProvider2<TX, N> {
pub const fn new(
tx: TX,
chain_spec: Arc<N::ChainSpec>,
static_file_provider: StaticFileProvider,
prune_modes: PruneModes,
chain_storage: Arc<N::Storage>,
) -> Self {
Self { tx, chain_spec, static_file_provider, prune_modes, chain_storage }
}

pub fn into_provider(self) -> DatabaseProvider<TX, N::ChainSpec> {
DatabaseProvider {
tx: self.tx,
chain_spec: self.chain_spec,
static_file_provider: self.static_file_provider,
prune_modes: self.prune_modes,
}
}
}

/// A provider struct that fetches data from the database.
/// Wrapper around [`DbTx`] and [`DbTxMut`]. Example: [`HeaderProvider`] [`BlockHashReader`]
#[derive(Debug)]
Expand Down
Loading

0 comments on commit 0444fe0

Please sign in to comment.