diff --git a/Cargo.lock b/Cargo.lock index b483fd6641db9..9e5455bd6f1d8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8085,6 +8085,7 @@ dependencies = [ "reth-engine-primitives", "reth-primitives", "reth-primitives-traits", + "reth-storage-api", ] [[package]] @@ -9057,6 +9058,7 @@ dependencies = [ "reth-db-models", "reth-execution-types", "reth-primitives", + "reth-primitives-traits", "reth-prune-types", "reth-stages-types", "reth-storage-errors", diff --git a/crates/ethereum/node/Cargo.toml b/crates/ethereum/node/Cargo.toml index 98224b99e26b2..a41265b72319a 100644 --- a/crates/ethereum/node/Cargo.toml +++ b/crates/ethereum/node/Cargo.toml @@ -31,11 +31,12 @@ reth-node-api.workspace = true reth-chainspec.workspace = true reth-primitives.workspace = true reth-revm = { workspace = true, features = ["std"] } - +reth-db.workspace = true # revm with required ethereum features revm = { workspace = true, features = ["secp256k1", "blst", "c-kzg"] } # misc +alloy-eips.workspace = true eyre.workspace = true [dev-dependencies] diff --git a/crates/ethereum/node/src/node.rs b/crates/ethereum/node/src/node.rs index dbd6ce0a134a4..60da28ad01dcc 100644 --- a/crates/ethereum/node/src/node.rs +++ b/crates/ethereum/node/src/node.rs @@ -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::{ @@ -81,6 +84,53 @@ 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 { + type Primitives = EthPrimitives; + + fn block< + P: reth_provider::DBProvider + + TransactionsProvider + + BlockReader + + WithdrawalsProvider + + HeaderProvider + + BlockNumReader, + >( + &self, + provider: &P, + id: alloy_eips::BlockHashOrNumber, + ) -> reth_provider::ProviderResult::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) + } + + fn dummy

(&self, provider: &P) { + todo!() + } } impl NodeTypesWithEngine for EthereumNode { diff --git a/crates/node/builder/src/node.rs b/crates/node/builder/src/node.rs index 3b2f467d61c0e..0111b4138d59d 100644 --- a/crates/node/builder/src/node.rs +++ b/crates/node/builder/src/node.rs @@ -69,6 +69,8 @@ where type Primitives = ::Primitives; type ChainSpec = ::ChainSpec; + + type Storage = ::Storage; } impl NodeTypesWithEngine for AnyNode diff --git a/crates/node/types/Cargo.toml b/crates/node/types/Cargo.toml index 5747abe9c34b3..30b50b568bab4 100644 --- a/crates/node/types/Cargo.toml +++ b/crates/node/types/Cargo.toml @@ -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 diff --git a/crates/node/types/src/lib.rs b/crates/node/types/src/lib.rs index 5ba03e6795aba..436560547afea 100644 --- a/crates/node/types/src/lib.rs +++ b/crates/node/types/src/lib.rs @@ -8,7 +8,8 @@ #![cfg_attr(not(test), warn(unused_crate_dependencies))] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] -pub use reth_primitives_traits::{Block, BlockBody}; +pub use reth_primitives_traits::{Block, BlockBody, NodePrimitives}; +use reth_storage_api::ChainStorageReader; use std::marker::PhantomData; @@ -19,16 +20,6 @@ use reth_db_api::{ }; use reth_engine_primitives::EngineTypes; -/// Configures all the primitive types of the node. -pub trait NodePrimitives { - /// Block primitive. - type Block; -} - -impl NodePrimitives for () { - type Block = reth_primitives::Block; -} - /// The type that configures the essential types of an Ethereum-like node. /// /// This includes the primitive types of a node and chain specification. @@ -39,6 +30,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. @@ -89,6 +82,7 @@ where { type Primitives = Types::Primitives; type ChainSpec = Types::ChainSpec; + type Storage = Types::Storage; } impl NodeTypesWithEngine for NodeTypesWithDBAdapter @@ -109,34 +103,41 @@ where /// A [`NodeTypes`] type builder. #[derive(Default, Debug)] -pub struct AnyNodeTypes

(PhantomData

, PhantomData); +pub struct AnyNodeTypes

(PhantomData

, PhantomData, PhantomData); -impl AnyNodeTypes { +impl AnyNodeTypes { /// Sets the `Primitives` associated type. - pub const fn primitives(self) -> AnyNodeTypes { - AnyNodeTypes::(PhantomData::, PhantomData::) + pub const fn primitives(self) -> AnyNodeTypes { + AnyNodeTypes::(PhantomData::, PhantomData::, PhantomData::) } /// Sets the `ChainSpec` associated type. - pub const fn chain_spec(self) -> AnyNodeTypes { - AnyNodeTypes::(PhantomData::

, PhantomData::) + pub const fn chain_spec(self) -> AnyNodeTypes { + AnyNodeTypes::(PhantomData::

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

, PhantomData::, PhantomData::) } } -impl NodeTypes for AnyNodeTypes +impl NodeTypes for AnyNodeTypes 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

{ +pub struct AnyNodeTypesWithEngine

{ /// Embedding the basic node types. - base: AnyNodeTypes, + base: AnyNodeTypes, /// Phantom data for the engine. _engine: PhantomData, } @@ -156,23 +157,31 @@ impl AnyNodeTypesWithEngine { pub const fn chain_spec(self) -> AnyNodeTypesWithEngine { AnyNodeTypesWithEngine { base: self.base.chain_spec::(), _engine: PhantomData } } + + /// Sets the `Storage` associated type. + pub const fn storage(self) -> AnyNodeTypesWithEngine { + AnyNodeTypesWithEngine { base: self.base.storage::(), _engine: PhantomData } + } } -impl NodeTypes for AnyNodeTypesWithEngine +impl NodeTypes for AnyNodeTypesWithEngine 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 NodeTypesWithEngine for AnyNodeTypesWithEngine +impl NodeTypesWithEngine for AnyNodeTypesWithEngine where P: NodePrimitives + Send + Sync + Unpin + 'static, E: EngineTypes + Send + Sync + Unpin, C: EthChainSpec + 'static, + S: ChainStorageReader + 'static, { type Engine = E; } diff --git a/crates/primitives-traits/src/lib.rs b/crates/primitives-traits/src/lib.rs index 57d1119b03515..23cd63d4a4270 100644 --- a/crates/primitives-traits/src/lib.rs +++ b/crates/primitives-traits/src/lib.rs @@ -44,6 +44,9 @@ pub use alloy_primitives::{logs_bloom, Log, LogData}; mod storage; pub use storage::StorageEntry; +mod node; +pub use node::NodePrimitives; + /// Common header types pub mod header; #[cfg(any(test, feature = "arbitrary", feature = "test-utils"))] diff --git a/crates/primitives-traits/src/node.rs b/crates/primitives-traits/src/node.rs new file mode 100644 index 0000000000000..ffb96690653ac --- /dev/null +++ b/crates/primitives-traits/src/node.rs @@ -0,0 +1,5 @@ +/// Configures all the primitive types of the node. +pub trait NodePrimitives { + /// Block primitive. + type Block; +} diff --git a/crates/storage/provider/src/providers/database/mod.rs b/crates/storage/provider/src/providers/database/mod.rs index 54186dca6f695..0842b91f0bde7 100644 --- a/crates/storage/provider/src/providers/database/mod.rs +++ b/crates/storage/provider/src/providers/database/mod.rs @@ -10,12 +10,13 @@ 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, @@ -23,7 +24,7 @@ use reth_primitives::{ }; 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::{ @@ -53,19 +54,22 @@ pub struct ProviderFactory { static_file_provider: StaticFileProvider, /// Optional pruning configuration prune_modes: PruneModes, + /// Chain storage reader + chain_storage: Arc, } impl fmt::Debug for ProviderFactory where - N: NodeTypesWithDB, + N: NodeTypesWithDB, { 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() } } @@ -77,7 +81,13 @@ impl ProviderFactory { chain_spec: Arc, 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. @@ -118,6 +128,7 @@ impl>> ProviderFactory { chain_spec, static_file_provider, prune_modes: PruneModes::none(), + chain_storage: Default::default(), }) } } @@ -131,12 +142,15 @@ impl ProviderFactory { /// data. #[track_caller] pub fn provider(&self) -> ProviderResult> { - Ok(DatabaseProvider::new( - self.db.tx()?, - self.chain_spec.clone(), - self.static_file_provider.clone(), - self.prune_modes.clone(), - )) + let provider2: DatabaseProvider2<<::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 @@ -339,6 +353,7 @@ impl BlockReader for ProviderFactory { fn block(&self, id: BlockHashOrNumber) -> ProviderResult> { self.provider()?.block(id) + // self.chain_storage.block(&self.provider()?, id) } fn pending_block(&self) -> ProviderResult> { @@ -612,6 +627,7 @@ impl Clone for ProviderFactory { 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(), } } } diff --git a/crates/storage/provider/src/providers/database/provider.rs b/crates/storage/provider/src/providers/database/provider.rs index 308fa364a3d3c..443a6d4cb0188 100644 --- a/crates/storage/provider/src/providers/database/provider.rs +++ b/crates/storage/provider/src/providers/database/provider.rs @@ -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, @@ -47,7 +48,9 @@ use reth_primitives::{ }; use reth_prune_types::{PruneCheckpoint, PruneModes, PruneSegment}; use reth_stages_types::{StageCheckpoint, StageId}; -use reth_storage_api::{StateProvider, StorageChangeSetReader, TryIntoHistoricalStateProvider}; +use reth_storage_api::{ + ChainStorageReader, StateProvider, StorageChangeSetReader, TryIntoHistoricalStateProvider, +}; use reth_storage_errors::provider::{ProviderResult, RootMismatch}; use reth_trie::{ prefix_set::{PrefixSet, PrefixSetMut, TriePrefixSets}, @@ -124,6 +127,47 @@ impl From> } } +/// A provider struct that fetches data from the database. +/// Wrapper around [`DbTx`] and [`DbTxMut`]. Example: [`HeaderProvider`] [`BlockHashReader`] +#[derive(Debug)] +pub struct DatabaseProvider2 { + /// Database transaction. + tx: TX, + /// Chain spec + chain_spec: Arc, + /// Static File provider + static_file_provider: StaticFileProvider, + /// Pruning configuration + prune_modes: PruneModes, + chain_storage: Arc, +} + +impl DatabaseProvider2 { + pub const fn new( + tx: TX, + chain_spec: Arc, + static_file_provider: StaticFileProvider, + prune_modes: PruneModes, + chain_storage: Arc, + ) -> Self { + Self { tx, chain_spec, static_file_provider, prune_modes, chain_storage } + } + + pub fn into_provider(self) -> DatabaseProvider { + DatabaseProvider { + tx: self.tx, + chain_spec: self.chain_spec, + static_file_provider: self.static_file_provider, + prune_modes: self.prune_modes, + } + } + + /// Example + fn block(&self) { + self.chain_storage.dummy(&self); + } +} + /// A provider struct that fetches data from the database. /// Wrapper around [`DbTx`] and [`DbTxMut`]. Example: [`HeaderProvider`] [`BlockHashReader`] #[derive(Debug)] diff --git a/crates/storage/storage-api/Cargo.toml b/crates/storage/storage-api/Cargo.toml index 0ae8b284588e4..2da202cae8515 100644 --- a/crates/storage/storage-api/Cargo.toml +++ b/crates/storage/storage-api/Cargo.toml @@ -18,6 +18,7 @@ reth-db-models.workspace = true reth-db-api.workspace = true reth-execution-types.workspace = true reth-primitives.workspace = true +reth-primitives-traits.workspace = true reth-prune-types.workspace = true reth-stages-types.workspace = true reth-storage-errors.workspace = true diff --git a/crates/storage/storage-api/src/block.rs b/crates/storage/storage-api/src/block.rs index 01238be745e28..40e0388a5899d 100644 --- a/crates/storage/storage-api/src/block.rs +++ b/crates/storage/storage-api/src/block.rs @@ -1,15 +1,17 @@ use crate::{ - BlockNumReader, HeaderProvider, ReceiptProvider, ReceiptProviderIdExt, TransactionVariant, - TransactionsProvider, WithdrawalsProvider, + BlockNumReader, DBProvider, HeaderProvider, ReceiptProvider, ReceiptProviderIdExt, + TransactionVariant, TransactionsProvider, WithdrawalsProvider, }; use alloy_eips::{BlockHashOrNumber, BlockId, BlockNumberOrTag}; use alloy_primitives::{BlockNumber, Sealable, B256}; +use reth_db_api::transaction::DbTx; use reth_db_models::StoredBlockBodyIndices; use reth_primitives::{ Block, BlockWithSenders, Header, Receipt, SealedBlock, SealedBlockWithSenders, SealedHeader, }; +use reth_primitives_traits::NodePrimitives; use reth_storage_errors::provider::ProviderResult; -use std::ops::RangeInclusive; +use std::{fmt::Debug, ops::RangeInclusive}; /// A helper enum that represents the origin of the requested block. /// @@ -42,6 +44,28 @@ impl BlockSource { } } +pub trait ChainStorageReader: Send + Sync + Unpin + Default + Debug { + type Primitives: NodePrimitives; + + /// Returns the block with given id from the database. + /// + /// Returns `None` if block is not found. + fn block< + P: DBProvider + + TransactionsProvider + + BlockReader + + WithdrawalsProvider + + HeaderProvider + + BlockNumReader, + >( + &self, + provider: &P, + id: BlockHashOrNumber, + ) -> ProviderResult::Block>>; + + fn dummy

(&self, provider: &P); +} + /// Api trait for fetching `Block` related data. /// /// If not requested otherwise, implementers of this trait should prioritize fetching blocks from