feat: trait-based storage API (#12616)

Co-authored-by: joshie <93316087+joshieDo@users.noreply.github.com>
This commit is contained in:
Arsenii Kulikov
2024-11-19 19:39:28 +04:00
committed by GitHub
parent 66a9d3e424
commit 1e7189d3e4
36 changed files with 486 additions and 149 deletions

5
Cargo.lock generated
View File

@ -6683,6 +6683,7 @@ dependencies = [
"reth-network",
"reth-network-p2p",
"reth-network-peers",
"reth-node-api",
"reth-node-builder",
"reth-node-core",
"reth-node-events",
@ -7089,10 +7090,12 @@ dependencies = [
"reth-db",
"reth-engine-local",
"reth-network-peers",
"reth-node-api",
"reth-node-builder",
"reth-payload-builder",
"reth-payload-builder-primitives",
"reth-payload-primitives",
"reth-primitives",
"reth-provider",
"reth-rpc-layer",
"reth-stages-types",
@ -8626,6 +8629,7 @@ dependencies = [
"reth-node-types",
"reth-optimism-primitives",
"reth-primitives",
"reth-primitives-traits",
"reth-prune-types",
"reth-stages-types",
"reth-storage-api",
@ -9189,6 +9193,7 @@ dependencies = [
"reth-db-models",
"reth-execution-types",
"reth-primitives",
"reth-primitives-traits",
"reth-prune-types",
"reth-stages-types",
"reth-storage-errors",

View File

@ -59,7 +59,7 @@ pub struct Command<C: ChainSpecParser> {
}
impl<C: ChainSpecParser<ChainSpec = ChainSpec>> Command<C> {
fn build_pipeline<N: ProviderNodeTypes<ChainSpec = C::ChainSpec>, Client>(
fn build_pipeline<N: ProviderNodeTypes<ChainSpec = C::ChainSpec> + CliNodeTypes, Client>(
&self,
config: &Config,
client: Client,

View File

@ -32,6 +32,7 @@ reth-fs-util.workspace = true
reth-network = { workspace = true, features = ["serde"] }
reth-network-p2p.workspace = true
reth-network-peers = { workspace = true, features = ["secp256k1"] }
reth-node-api.workspace = true
reth-node-builder.workspace = true
reth-node-core.workspace = true
reth-node-events.workspace = true

View File

@ -10,12 +10,16 @@ use reth_db::{init_db, open_db_read_only, DatabaseEnv};
use reth_db_common::init::init_genesis;
use reth_downloaders::{bodies::noop::NoopBodiesDownloader, headers::noop::NoopHeaderDownloader};
use reth_evm::noop::NoopBlockExecutorProvider;
use reth_node_api::FullNodePrimitives;
use reth_node_builder::{NodeTypesWithDBAdapter, NodeTypesWithEngine};
use reth_node_core::{
args::{DatabaseArgs, DatadirArgs},
dirs::{ChainPath, DataDirPath},
};
use reth_provider::{providers::StaticFileProvider, ProviderFactory, StaticFileProviderFactory};
use reth_provider::{
providers::{NodeTypesForProvider, StaticFileProvider},
ProviderFactory, StaticFileProviderFactory,
};
use reth_stages::{sets::DefaultStages, Pipeline, PipelineTarget};
use reth_static_file::StaticFileProducer;
use std::{path::PathBuf, sync::Arc};
@ -191,5 +195,21 @@ impl AccessRights {
/// Helper trait with a common set of requirements for the
/// [`NodeTypes`](reth_node_builder::NodeTypes) in CLI.
pub trait CliNodeTypes: NodeTypesWithEngine<ChainSpec: EthereumHardforks> {}
impl<N> CliNodeTypes for N where N: NodeTypesWithEngine<ChainSpec: EthereumHardforks> {}
pub trait CliNodeTypes:
NodeTypesWithEngine
+ NodeTypesForProvider<
Primitives: FullNodePrimitives<
Block: reth_node_api::Block<Body = reth_primitives::BlockBody>,
>,
>
{
}
impl<N> CliNodeTypes for N where
N: NodeTypesWithEngine
+ NodeTypesForProvider<
Primitives: FullNodePrimitives<
Block: reth_node_api::Block<Body = reth_primitives::BlockBody>,
>,
>
{
}

View File

@ -167,7 +167,7 @@ pub fn build_import_pipeline<N, C, E>(
executor: E,
) -> eyre::Result<(Pipeline<N>, impl Stream<Item = NodeEvent>)>
where
N: ProviderNodeTypes,
N: ProviderNodeTypes + CliNodeTypes,
C: Consensus + 'static,
E: BlockExecutorProvider,
{

View File

@ -113,7 +113,7 @@ impl<C: ChainSpecParser<ChainSpec: EthChainSpec + EthereumHardforks>> Command<C>
Ok(())
}
fn build_pipeline<N: ProviderNodeTypes<ChainSpec = C::ChainSpec>>(
fn build_pipeline<N: ProviderNodeTypes<ChainSpec = C::ChainSpec> + CliNodeTypes>(
self,
config: Config,
provider_factory: ProviderFactory<N>,

View File

@ -19,7 +19,9 @@ reth-rpc-layer.workspace = true
reth-payload-builder = { workspace = true, features = ["test-utils"] }
reth-payload-builder-primitives.workspace = true
reth-payload-primitives.workspace = true
reth-primitives.workspace = true
reth-provider.workspace = true
reth-node-api.workspace = true
reth-node-builder = { workspace = true, features = ["test-utils"] }
reth-tokio-util.workspace = true
reth-stages-types.workspace = true

View File

@ -5,12 +5,12 @@ use std::sync::Arc;
use node::NodeTestContext;
use reth::{
args::{DiscoveryArgs, NetworkArgs, RpcServerArgs},
builder::{NodeBuilder, NodeConfig, NodeHandle},
builder::{FullNodePrimitives, NodeBuilder, NodeConfig, NodeHandle},
network::PeersHandleProvider,
rpc::server_types::RpcModuleSelection,
tasks::TaskManager,
};
use reth_chainspec::{EthChainSpec, EthereumHardforks};
use reth_chainspec::EthChainSpec;
use reth_db::{test_utils::TempDatabase, DatabaseEnv};
use reth_engine_local::LocalPayloadAttributesBuilder;
use reth_node_builder::{
@ -18,7 +18,7 @@ use reth_node_builder::{
FullNodeTypesAdapter, Node, NodeAdapter, NodeComponents, NodeTypesWithDBAdapter,
NodeTypesWithEngine, PayloadAttributesBuilder, PayloadTypes,
};
use reth_provider::providers::{BlockchainProvider, BlockchainProvider2};
use reth_provider::providers::{BlockchainProvider, BlockchainProvider2, NodeTypesForProvider};
use tracing::{span, Level};
use wallet::Wallet;
@ -53,12 +53,14 @@ pub async fn setup<N>(
attributes_generator: impl Fn(u64) -> <<N as NodeTypesWithEngine>::Engine as PayloadTypes>::PayloadBuilderAttributes + Copy + 'static,
) -> eyre::Result<(Vec<NodeHelperType<N, N::AddOns>>, TaskManager, Wallet)>
where
N: Default + Node<TmpNodeAdapter<N>> + NodeTypesWithEngine<ChainSpec: EthereumHardforks>,
N: Default + Node<TmpNodeAdapter<N>> + NodeTypesForProvider + NodeTypesWithEngine,
N::ComponentsBuilder: NodeComponentsBuilder<
TmpNodeAdapter<N>,
Components: NodeComponents<TmpNodeAdapter<N>, Network: PeersHandleProvider>,
>,
N::AddOns: RethRpcAddOns<Adapter<N>>,
N::Primitives:
FullNodePrimitives<Block: reth_node_api::Block<Body = reth_primitives::BlockBody>>,
{
let tasks = TaskManager::current();
let exec = tasks.executor();
@ -120,7 +122,8 @@ pub async fn setup_engine<N>(
where
N: Default
+ Node<TmpNodeAdapter<N, BlockchainProvider2<NodeTypesWithDBAdapter<N, TmpDB>>>>
+ NodeTypesWithEngine<ChainSpec: EthereumHardforks>,
+ NodeTypesWithEngine
+ NodeTypesForProvider,
N::ComponentsBuilder: NodeComponentsBuilder<
TmpNodeAdapter<N, BlockchainProvider2<NodeTypesWithDBAdapter<N, TmpDB>>>,
Components: NodeComponents<
@ -132,6 +135,8 @@ where
LocalPayloadAttributesBuilder<N::ChainSpec>: PayloadAttributesBuilder<
<<N as NodeTypesWithEngine>::Engine as PayloadTypes>::PayloadAttributes,
>,
N::Primitives:
FullNodePrimitives<Block: reth_node_api::Block<Body = reth_primitives::BlockBody>>,
{
let tasks = TaskManager::current();
let exec = tasks.executor();

View File

@ -26,7 +26,7 @@ use reth_node_builder::{
};
use reth_payload_builder::{PayloadBuilderHandle, PayloadBuilderService};
use reth_primitives::EthPrimitives;
use reth_provider::CanonStateSubscriptions;
use reth_provider::{CanonStateSubscriptions, EthStorage};
use reth_rpc::EthApi;
use reth_tracing::tracing::{debug, info};
use reth_transaction_pool::{
@ -74,6 +74,7 @@ impl NodeTypes for EthereumNode {
type Primitives = EthPrimitives;
type ChainSpec = ChainSpec;
type StateCommitment = MerklePatriciaTrie;
type Storage = EthStorage;
}
impl NodeTypesWithEngine for EthereumNode {
@ -94,7 +95,13 @@ pub type EthereumAddOns<N> = RpcAddOns<
impl<Types, N> Node<N> for EthereumNode
where
Types: NodeTypesWithDB + NodeTypesWithEngine<Engine = EthEngineTypes, ChainSpec = ChainSpec>,
Types: NodeTypesWithDB
+ NodeTypesWithEngine<
Engine = EthEngineTypes,
ChainSpec = ChainSpec,
Primitives = EthPrimitives,
Storage = EthStorage,
>,
N: FullNodeTypes<Types = Types>,
{
type ComponentsBuilder = ComponentsBuilder<

View File

@ -45,10 +45,10 @@ use reth_node_ethereum::{
EthEngineTypes, EthEvmConfig,
};
use reth_payload_builder::noop::NoopPayloadBuilderService;
use reth_primitives::{Head, SealedBlockWithSenders};
use reth_primitives::{EthPrimitives, Head, SealedBlockWithSenders};
use reth_provider::{
providers::{BlockchainProvider, StaticFileProvider},
BlockReader, ProviderFactory,
BlockReader, EthStorage, ProviderFactory,
};
use reth_tasks::TaskManager;
use reth_transaction_pool::test_utils::{testing_pool, TestPool};
@ -118,9 +118,10 @@ where
pub struct TestNode;
impl NodeTypes for TestNode {
type Primitives = ();
type Primitives = EthPrimitives;
type ChainSpec = ChainSpec;
type StateCommitment = reth_trie_db::MerklePatriciaTrie;
type Storage = EthStorage;
}
impl NodeTypesWithEngine for TestNode {
@ -129,7 +130,14 @@ impl NodeTypesWithEngine for TestNode {
impl<N> Node<N> for TestNode
where
N: FullNodeTypes<Types: NodeTypesWithEngine<Engine = EthEngineTypes, ChainSpec = ChainSpec>>,
N: FullNodeTypes<
Types: NodeTypesWithEngine<
Engine = EthEngineTypes,
ChainSpec = ChainSpec,
Primitives = EthPrimitives,
Storage = EthStorage,
>,
>,
{
type ComponentsBuilder = ComponentsBuilder<
N,

View File

@ -22,8 +22,8 @@ use reth_network::{
NetworkHandle, NetworkManager,
};
use reth_node_api::{
FullNodeTypes, FullNodeTypesAdapter, NodeAddOns, NodeTypes, NodeTypesWithDBAdapter,
NodeTypesWithEngine,
FullNodePrimitives, FullNodeTypes, FullNodeTypesAdapter, NodeAddOns, NodeTypes,
NodeTypesWithDBAdapter, NodeTypesWithEngine,
};
use reth_node_core::{
cli::config::{PayloadBuilderConfig, RethTransactionPoolConfig},
@ -31,7 +31,10 @@ use reth_node_core::{
node_config::NodeConfig,
primitives::Head,
};
use reth_provider::{providers::BlockchainProvider, ChainSpecProvider, FullProvider};
use reth_provider::{
providers::{BlockchainProvider, NodeTypesForProvider},
ChainSpecProvider, FullProvider,
};
use reth_tasks::TaskExecutor;
use reth_transaction_pool::{PoolConfig, TransactionPool};
use revm_primitives::EnvKzgSettings;
@ -240,7 +243,7 @@ where
/// Configures the types of the node.
pub fn with_types<T>(self) -> NodeBuilderWithTypes<RethFullAdapter<DB, T>>
where
T: NodeTypesWithEngine<ChainSpec = ChainSpec>,
T: NodeTypesWithEngine<ChainSpec = ChainSpec> + NodeTypesForProvider,
{
self.with_types_and_provider()
}
@ -250,7 +253,7 @@ where
self,
) -> NodeBuilderWithTypes<FullNodeTypesAdapter<NodeTypesWithDBAdapter<T, DB>, P>>
where
T: NodeTypesWithEngine<ChainSpec = ChainSpec>,
T: NodeTypesWithEngine<ChainSpec = ChainSpec> + NodeTypesForProvider,
P: FullProvider<NodeTypesWithDBAdapter<T, DB>>,
{
NodeBuilderWithTypes::new(self.config, self.database)
@ -264,7 +267,7 @@ where
node: N,
) -> NodeBuilderWithComponents<RethFullAdapter<DB, N>, N::ComponentsBuilder, N::AddOns>
where
N: Node<RethFullAdapter<DB, N>, ChainSpec = ChainSpec>,
N: Node<RethFullAdapter<DB, N>, ChainSpec = ChainSpec> + NodeTypesForProvider,
{
self.with_types().with_components(node.components_builder()).with_add_ons(node.add_ons())
}
@ -301,7 +304,7 @@ where
/// Configures the types of the node.
pub fn with_types<T>(self) -> WithLaunchContext<NodeBuilderWithTypes<RethFullAdapter<DB, T>>>
where
T: NodeTypesWithEngine<ChainSpec = ChainSpec>,
T: NodeTypesWithEngine<ChainSpec = ChainSpec> + NodeTypesForProvider,
{
WithLaunchContext { builder: self.builder.with_types(), task_executor: self.task_executor }
}
@ -313,7 +316,7 @@ where
NodeBuilderWithTypes<FullNodeTypesAdapter<NodeTypesWithDBAdapter<T, DB>, P>>,
>
where
T: NodeTypesWithEngine<ChainSpec = ChainSpec>,
T: NodeTypesWithEngine<ChainSpec = ChainSpec> + NodeTypesForProvider,
P: FullProvider<NodeTypesWithDBAdapter<T, DB>>,
{
WithLaunchContext {
@ -332,7 +335,7 @@ where
NodeBuilderWithComponents<RethFullAdapter<DB, N>, N::ComponentsBuilder, N::AddOns>,
>
where
N: Node<RethFullAdapter<DB, N>, ChainSpec = ChainSpec>,
N: Node<RethFullAdapter<DB, N>, ChainSpec = ChainSpec> + NodeTypesForProvider,
{
self.with_types().with_components(node.components_builder()).with_add_ons(node.add_ons())
}
@ -355,13 +358,15 @@ where
>,
>
where
N: Node<RethFullAdapter<DB, N>, ChainSpec = ChainSpec>,
N: Node<RethFullAdapter<DB, N>, ChainSpec = ChainSpec> + NodeTypesForProvider,
N::AddOns: RethRpcAddOns<
NodeAdapter<
RethFullAdapter<DB, N>,
<N::ComponentsBuilder as NodeComponentsBuilder<RethFullAdapter<DB, N>>>::Components,
>,
>,
N::Primitives:
FullNodePrimitives<Block: reth_node_api::Block<Body = reth_primitives::BlockBody>>,
{
self.node(node).launch().await
}
@ -549,9 +554,11 @@ where
impl<T, DB, CB, AO> WithLaunchContext<NodeBuilderWithComponents<RethFullAdapter<DB, T>, CB, AO>>
where
DB: Database + DatabaseMetrics + DatabaseMetadata + Clone + Unpin + 'static,
T: NodeTypesWithEngine<ChainSpec: EthereumHardforks + EthChainSpec>,
T: NodeTypesWithEngine + NodeTypesForProvider,
CB: NodeComponentsBuilder<RethFullAdapter<DB, T>>,
AO: RethRpcAddOns<NodeAdapter<RethFullAdapter<DB, T>, CB::Components>>,
T::Primitives:
FullNodePrimitives<Block: reth_node_api::Block<Body = reth_primitives::BlockBody>>,
{
/// Launches the node with the [`DefaultNodeLauncher`] that sets up engine API consensus and rpc
pub async fn launch(

View File

@ -26,7 +26,7 @@ use reth_evm::noop::NoopBlockExecutorProvider;
use reth_fs_util as fs;
use reth_invalid_block_hooks::InvalidBlockWitnessHook;
use reth_network_p2p::headers::client::HeadersClient;
use reth_node_api::{FullNodeTypes, NodeTypes, NodeTypesWithDB};
use reth_node_api::{FullNodePrimitives, FullNodeTypes, NodeTypes, NodeTypesWithDB};
use reth_node_core::{
args::InvalidBlockHookType,
dirs::{ChainPath, DataDirPath},
@ -404,9 +404,12 @@ where
/// Returns the [`ProviderFactory`] for the attached storage after executing a consistent check
/// between the database and static files. **It may execute a pipeline unwind if it fails this
/// check.**
pub async fn create_provider_factory<N: NodeTypesWithDB<DB = DB, ChainSpec = ChainSpec>>(
&self,
) -> eyre::Result<ProviderFactory<N>> {
pub async fn create_provider_factory<N>(&self) -> eyre::Result<ProviderFactory<N>>
where
N: ProviderNodeTypes<DB = DB, ChainSpec = ChainSpec>,
N::Primitives:
FullNodePrimitives<Block: reth_node_api::Block<Body = reth_primitives::BlockBody>>,
{
let factory = ProviderFactory::new(
self.right().clone(),
self.chain_spec(),
@ -467,9 +470,14 @@ where
}
/// Creates a new [`ProviderFactory`] and attaches it to the launch context.
pub async fn with_provider_factory<N: NodeTypesWithDB<DB = DB, ChainSpec = ChainSpec>>(
pub async fn with_provider_factory<N>(
self,
) -> eyre::Result<LaunchContextWith<Attached<WithConfigs<ChainSpec>, ProviderFactory<N>>>> {
) -> eyre::Result<LaunchContextWith<Attached<WithConfigs<ChainSpec>, ProviderFactory<N>>>>
where
N: ProviderNodeTypes<DB = DB, ChainSpec = ChainSpec>,
N::Primitives:
FullNodePrimitives<Block: reth_node_api::Block<Body = reth_primitives::BlockBody>>,
{
let factory = self.create_provider_factory().await?;
let ctx = LaunchContextWith {
inner: self.inner,
@ -482,7 +490,7 @@ where
impl<T> LaunchContextWith<Attached<WithConfigs<T::ChainSpec>, ProviderFactory<T>>>
where
T: NodeTypesWithDB<ChainSpec: EthereumHardforks + EthChainSpec>,
T: ProviderNodeTypes,
{
/// Returns access to the underlying database.
pub const fn database(&self) -> &T::DB {
@ -748,10 +756,7 @@ impl<T, CB>
Attached<WithConfigs<<T::Types as NodeTypes>::ChainSpec>, WithComponents<T, CB>>,
>
where
T: FullNodeTypes<
Provider: WithTree,
Types: NodeTypes<ChainSpec: EthChainSpec + EthereumHardforks>,
>,
T: FullNodeTypes<Provider: WithTree, Types: ProviderNodeTypes>,
CB: NodeComponentsBuilder<T>,
{
/// Returns the configured `ProviderFactory`.
@ -913,7 +918,7 @@ impl<T, CB>
where
T: FullNodeTypes<
Provider: WithTree + StateProviderFactory + ChainSpecProvider,
Types: NodeTypes<ChainSpec: EthereumHardforks>,
Types: ProviderNodeTypes,
>,
CB: NodeComponentsBuilder<T>,
{

View File

@ -19,8 +19,8 @@ use reth_exex::ExExManagerHandle;
use reth_network::{NetworkSyncUpdater, SyncState};
use reth_network_api::{BlockDownloaderProvider, NetworkEventListenerProvider};
use reth_node_api::{
BuiltPayload, FullNodeTypes, NodeTypesWithEngine, PayloadAttributesBuilder, PayloadBuilder,
PayloadTypes,
BuiltPayload, FullNodePrimitives, FullNodeTypes, NodeTypesWithEngine, PayloadAttributesBuilder,
PayloadBuilder, PayloadTypes,
};
use reth_node_core::{
dirs::{ChainPath, DataDirPath},
@ -77,6 +77,8 @@ where
LocalPayloadAttributesBuilder<Types::ChainSpec>: PayloadAttributesBuilder<
<<Types as NodeTypesWithEngine>::Engine as PayloadTypes>::PayloadAttributes,
>,
Types::Primitives:
FullNodePrimitives<Block: reth_node_api::Block<Body = reth_primitives::BlockBody>>,
{
type Node = NodeHandle<NodeAdapter<T, CB::Components>, AO>;

View File

@ -17,18 +17,18 @@ use reth_beacon_consensus::{
BeaconConsensusEngine,
};
use reth_blockchain_tree::{noop::NoopBlockchainTree, BlockchainTreeConfig};
use reth_chainspec::{EthChainSpec, EthereumHardforks};
use reth_chainspec::EthChainSpec;
use reth_consensus_debug_client::{DebugConsensusClient, EtherscanBlockProvider, RpcBlockProvider};
use reth_engine_util::EngineMessageStreamExt;
use reth_exex::ExExManagerHandle;
use reth_network::{BlockDownloaderProvider, NetworkEventListenerProvider};
use reth_node_api::{AddOnsContext, FullNodeTypes, NodeTypesWithDB, NodeTypesWithEngine};
use reth_node_api::{AddOnsContext, FullNodePrimitives, FullNodeTypes, NodeTypesWithEngine};
use reth_node_core::{
dirs::{ChainPath, DataDirPath},
exit::NodeExitFuture,
};
use reth_node_events::{cl::ConsensusLayerHealthEvents, node};
use reth_provider::providers::BlockchainProvider;
use reth_provider::providers::{BlockchainProvider, ProviderNodeTypes};
use reth_rpc::eth::RpcNodeCore;
use reth_tasks::TaskExecutor;
use reth_tracing::tracing::{debug, info};
@ -98,10 +98,12 @@ impl DefaultNodeLauncher {
impl<Types, T, CB, AO> LaunchNode<NodeBuilderWithComponents<T, CB, AO>> for DefaultNodeLauncher
where
Types: NodeTypesWithDB<ChainSpec: EthereumHardforks + EthChainSpec> + NodeTypesWithEngine,
Types: ProviderNodeTypes + NodeTypesWithEngine,
T: FullNodeTypes<Provider = BlockchainProvider<Types>, Types = Types>,
CB: NodeComponentsBuilder<T>,
AO: RethRpcAddOns<NodeAdapter<T, CB::Components>>,
Types::Primitives:
FullNodePrimitives<Block: reth_node_api::Block<Body = reth_primitives::BlockBody>>,
{
type Node = NodeHandle<NodeAdapter<T, CB::Components>, AO>;

View File

@ -71,6 +71,8 @@ where
type ChainSpec = <N::Types as NodeTypes>::ChainSpec;
type StateCommitment = <N::Types as NodeTypes>::StateCommitment;
type Storage = <N::Types as NodeTypes>::Storage;
}
impl<N, C, AO> NodeTypesWithEngine for AnyNode<N, C, AO>

View File

@ -14,6 +14,7 @@ use reth_exex::ExExManagerHandle;
use reth_network_p2p::{
bodies::downloader::BodyDownloader, headers::downloader::HeaderDownloader, EthBlockClient,
};
use reth_node_api::FullNodePrimitives;
use reth_provider::{providers::ProviderNodeTypes, ProviderFactory};
use reth_stages::{prelude::DefaultStages, stages::ExecutionStage, Pipeline, StageSet};
use reth_static_file::StaticFileProducer;
@ -40,6 +41,8 @@ where
N: ProviderNodeTypes,
Client: EthBlockClient + 'static,
Executor: BlockExecutorProvider,
N::Primitives:
FullNodePrimitives<Block: reth_node_api::Block<Body = reth_primitives::BlockBody>>,
{
// building network downloaders using the fetch client
let header_downloader = ReverseHeadersDownloaderBuilder::new(config.headers)
@ -85,8 +88,12 @@ pub fn build_pipeline<N, H, B, Executor>(
where
N: ProviderNodeTypes,
H: HeaderDownloader<Header = alloy_consensus::Header> + 'static,
B: BodyDownloader<Body = reth_primitives::BlockBody> + 'static,
B: BodyDownloader<
Body = <<N::Primitives as FullNodePrimitives>::Block as reth_node_api::Block>::Body,
> + 'static,
Executor: BlockExecutorProvider,
N::Primitives:
FullNodePrimitives<Block: reth_node_api::Block<Body = reth_primitives::BlockBody>>,
{
let mut builder = Pipeline::<N>::builder();

View File

@ -9,12 +9,11 @@
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
#![cfg_attr(not(feature = "std"), no_std)]
use core::{fmt::Debug, marker::PhantomData};
pub use reth_primitives_traits::{
Block, BlockBody, FullBlock, FullNodePrimitives, FullReceipt, FullSignedTx, NodePrimitives,
};
use core::marker::PhantomData;
use reth_chainspec::EthChainSpec;
use reth_db_api::{
database_metrics::{DatabaseMetadata, DatabaseMetrics},
@ -35,6 +34,8 @@ pub trait NodeTypes: Send + Sync + Unpin + 'static {
type ChainSpec: EthChainSpec;
/// The type used to perform state commitment operations.
type StateCommitment: StateCommitment;
/// The type responsible for writing chain primitives to storage.
type Storage: Default + Send + Sync + Unpin + Debug + 'static;
}
/// The type that configures an Ethereum-like node with an engine for consensus.
@ -86,6 +87,7 @@ where
type Primitives = Types::Primitives;
type ChainSpec = Types::ChainSpec;
type StateCommitment = Types::StateCommitment;
type Storage = Types::Storage;
}
impl<Types, DB> NodeTypesWithEngine for NodeTypesWithDBAdapter<Types, DB>
@ -105,86 +107,128 @@ where
}
/// A [`NodeTypes`] type builder.
#[derive(Default, Debug)]
pub struct AnyNodeTypes<P = (), C = (), S = ()>(PhantomData<P>, PhantomData<C>, PhantomData<S>);
#[derive(Debug)]
pub struct AnyNodeTypes<P = (), C = (), SC = (), S = ()>(
PhantomData<P>,
PhantomData<C>,
PhantomData<SC>,
PhantomData<S>,
);
impl<P, C, SC, S> Default for AnyNodeTypes<P, C, SC, S> {
fn default() -> Self {
Self::new()
}
}
impl<P, C, SC, S> AnyNodeTypes<P, C, SC, S> {
/// Creates a new instance of [`AnyNodeTypes`].
pub const fn new() -> Self {
Self(PhantomData, PhantomData, PhantomData, PhantomData)
}
impl<P, C, S> AnyNodeTypes<P, C, S> {
/// Sets the `Primitives` associated type.
pub const fn primitives<T>(self) -> AnyNodeTypes<T, C, S> {
AnyNodeTypes::<T, C, S>(PhantomData::<T>, PhantomData::<C>, PhantomData::<S>)
pub const fn primitives<T>(self) -> AnyNodeTypes<T, C, SC, S> {
AnyNodeTypes::new()
}
/// Sets the `ChainSpec` associated type.
pub const fn chain_spec<T>(self) -> AnyNodeTypes<P, T, S> {
AnyNodeTypes::<P, T, S>(PhantomData::<P>, PhantomData::<T>, PhantomData::<S>)
pub const fn chain_spec<T>(self) -> AnyNodeTypes<P, T, SC, S> {
AnyNodeTypes::new()
}
/// Sets the `StateCommitment` associated type.
pub const fn state_commitment<T>(self) -> AnyNodeTypes<P, C, T> {
AnyNodeTypes::<P, C, T>(PhantomData::<P>, PhantomData::<C>, PhantomData::<T>)
pub const fn state_commitment<T>(self) -> AnyNodeTypes<P, C, T, S> {
AnyNodeTypes::new()
}
/// Sets the `Storage` associated type.
pub const fn storage<T>(self) -> AnyNodeTypes<P, C, SC, T> {
AnyNodeTypes::new()
}
}
impl<P, C, S> NodeTypes for AnyNodeTypes<P, C, S>
impl<P, C, SC, S> NodeTypes for AnyNodeTypes<P, C, SC, S>
where
P: NodePrimitives + Send + Sync + Unpin + 'static,
C: EthChainSpec + 'static,
S: StateCommitment,
SC: StateCommitment,
S: Default + Send + Sync + Unpin + Debug + 'static,
{
type Primitives = P;
type ChainSpec = C;
type StateCommitment = S;
type StateCommitment = SC;
type Storage = S;
}
/// A [`NodeTypesWithEngine`] type builder.
#[derive(Default, Debug)]
pub struct AnyNodeTypesWithEngine<P = (), E = (), C = (), S = ()> {
#[derive(Debug)]
pub struct AnyNodeTypesWithEngine<P = (), E = (), C = (), SC = (), S = ()> {
/// Embedding the basic node types.
base: AnyNodeTypes<P, C, S>,
_base: AnyNodeTypes<P, C, SC, S>,
/// Phantom data for the engine.
_engine: PhantomData<E>,
}
impl<P, E, C, S> AnyNodeTypesWithEngine<P, E, C, S> {
impl<P, E, C, SC, S> Default for AnyNodeTypesWithEngine<P, E, C, SC, S> {
fn default() -> Self {
Self::new()
}
}
impl<P, E, C, SC, S> AnyNodeTypesWithEngine<P, E, C, SC, S> {
/// Creates a new instance of [`AnyNodeTypesWithEngine`].
pub const fn new() -> Self {
Self { _base: AnyNodeTypes::new(), _engine: PhantomData }
}
/// Sets the `Primitives` associated type.
pub const fn primitives<T>(self) -> AnyNodeTypesWithEngine<T, E, C, S> {
AnyNodeTypesWithEngine { base: self.base.primitives::<T>(), _engine: PhantomData }
pub const fn primitives<T>(self) -> AnyNodeTypesWithEngine<T, E, C, SC, S> {
AnyNodeTypesWithEngine::new()
}
/// Sets the `Engine` associated type.
pub const fn engine<T>(self) -> AnyNodeTypesWithEngine<P, T, C, S> {
AnyNodeTypesWithEngine { base: self.base, _engine: PhantomData::<T> }
pub const fn engine<T>(self) -> AnyNodeTypesWithEngine<P, T, C, SC, S> {
AnyNodeTypesWithEngine::new()
}
/// Sets the `ChainSpec` associated type.
pub const fn chain_spec<T>(self) -> AnyNodeTypesWithEngine<P, E, T, S> {
AnyNodeTypesWithEngine { base: self.base.chain_spec::<T>(), _engine: PhantomData }
pub const fn chain_spec<T>(self) -> AnyNodeTypesWithEngine<P, E, T, SC, S> {
AnyNodeTypesWithEngine::new()
}
/// Sets the `StateCommitment` associated type.
pub const fn state_commitment<T>(self) -> AnyNodeTypesWithEngine<P, E, C, T> {
AnyNodeTypesWithEngine { base: self.base.state_commitment::<T>(), _engine: PhantomData }
pub const fn state_commitment<T>(self) -> AnyNodeTypesWithEngine<P, E, C, T, S> {
AnyNodeTypesWithEngine::new()
}
/// Sets the `Storage` associated type.
pub const fn storage<T>(self) -> AnyNodeTypesWithEngine<P, E, C, SC, T> {
AnyNodeTypesWithEngine::new()
}
}
impl<P, E, C, S> NodeTypes for AnyNodeTypesWithEngine<P, E, C, S>
impl<P, E, C, SC, S> NodeTypes for AnyNodeTypesWithEngine<P, E, C, SC, S>
where
P: NodePrimitives + Send + Sync + Unpin + 'static,
E: EngineTypes + Send + Sync + Unpin,
C: EthChainSpec + 'static,
S: StateCommitment,
SC: StateCommitment,
S: Default + Send + Sync + Unpin + Debug + 'static,
{
type Primitives = P;
type ChainSpec = C;
type StateCommitment = S;
type StateCommitment = SC;
type Storage = S;
}
impl<P, E, C, S> NodeTypesWithEngine for AnyNodeTypesWithEngine<P, E, C, S>
impl<P, E, C, SC, S> NodeTypesWithEngine for AnyNodeTypesWithEngine<P, E, C, SC, S>
where
P: NodePrimitives + Send + Sync + Unpin + 'static,
E: EngineTypes + Send + Sync + Unpin,
C: EthChainSpec + 'static,
S: StateCommitment,
SC: StateCommitment,
S: Default + Send + Sync + Unpin + Debug + 'static,
{
type Engine = E;
}

View File

@ -1,5 +1,6 @@
use alloy_primitives::B256;
use futures_util::{Stream, StreamExt};
use reth_cli_commands::common::CliNodeTypes;
use reth_config::Config;
use reth_consensus::Consensus;
use reth_downloaders::{
@ -38,7 +39,7 @@ pub(crate) async fn build_import_pipeline<N, C>(
disable_exec: bool,
) -> eyre::Result<(Pipeline<N>, impl Stream<Item = NodeEvent>)>
where
N: ProviderNodeTypes<ChainSpec = OpChainSpec>,
N: CliNodeTypes + ProviderNodeTypes<ChainSpec = OpChainSpec>,
C: Consensus + 'static,
{
if !file_client.has_canonical_blocks() {

View File

@ -13,6 +13,7 @@ workspace = true
[dependencies]
# reth
reth-chainspec.workspace = true
reth-db.workspace = true
reth-engine-local.workspace = true
reth-primitives.workspace = true
reth-payload-builder.workspace = true

View File

@ -5,10 +5,12 @@ use std::sync::Arc;
use alloy_consensus::Header;
use reth_basic_payload_builder::{BasicPayloadJobGenerator, BasicPayloadJobGeneratorConfig};
use reth_chainspec::{EthChainSpec, Hardforks};
use reth_db::transaction::{DbTx, DbTxMut};
use reth_evm::{execute::BasicBlockExecutorProvider, ConfigureEvm};
use reth_network::{NetworkConfig, NetworkHandle, NetworkManager, PeersInfo};
use reth_node_api::{
AddOnsContext, EngineValidator, FullNodeComponents, NodeAddOns, PayloadBuilder,
AddOnsContext, EngineValidator, FullNodeComponents, FullNodePrimitives, NodeAddOns,
PayloadBuilder,
};
use reth_node_builder::{
components::{
@ -28,7 +30,11 @@ use reth_optimism_rpc::{
OpEthApi,
};
use reth_payload_builder::{PayloadBuilderHandle, PayloadBuilderService};
use reth_provider::CanonStateSubscriptions;
use reth_primitives::{Block, BlockBody, Receipt, TransactionSigned, TxType};
use reth_provider::{
providers::ChainStorage, BlockBodyWriter, CanonStateSubscriptions, DBProvider, EthStorage,
ProviderResult,
};
use reth_rpc_server_types::RethRpcModule;
use reth_tracing::tracing::{debug, info};
use reth_transaction_pool::{
@ -43,7 +49,42 @@ use crate::{
txpool::{OpTransactionPool, OpTransactionValidator},
OpEngineTypes,
};
/// Optimism primitive types.
#[derive(Debug, Default, Clone, PartialEq, Eq)]
pub struct OpPrimitives;
impl FullNodePrimitives for OpPrimitives {
type Block = Block;
type SignedTx = TransactionSigned;
type TxType = TxType;
type Receipt = Receipt;
}
/// Storage implementation for Optimism.
#[derive(Debug, Default, Clone)]
pub struct OpStorage(EthStorage);
impl<Provider: DBProvider<Tx: DbTxMut>> BlockBodyWriter<Provider, BlockBody> for OpStorage {
fn write_block_bodies(
&self,
provider: &Provider,
bodies: Vec<(u64, Option<BlockBody>)>,
) -> ProviderResult<()> {
self.0.write_block_bodies(provider, bodies)
}
}
impl ChainStorage<OpPrimitives> for OpStorage {
fn writer<TX, Types>(
&self,
) -> impl reth_provider::ChainStorageWriter<reth_provider::DatabaseProvider<TX, Types>, OpPrimitives>
where
TX: DbTxMut + DbTx + 'static,
Types: NodeTypes<Primitives = OpPrimitives>,
{
self
}
}
/// Type configuration for a regular Optimism node.
#[derive(Debug, Default, Clone)]
#[non_exhaustive]
@ -90,7 +131,14 @@ impl OpNode {
impl<N> Node<N> for OpNode
where
N: FullNodeTypes<Types: NodeTypesWithEngine<Engine = OpEngineTypes, ChainSpec = OpChainSpec>>,
N: FullNodeTypes<
Types: NodeTypesWithEngine<
Engine = OpEngineTypes,
ChainSpec = OpChainSpec,
Primitives = OpPrimitives,
Storage = OpStorage,
>,
>,
{
type ComponentsBuilder = ComponentsBuilder<
N,
@ -115,9 +163,10 @@ where
}
impl NodeTypes for OpNode {
type Primitives = reth_primitives::EthPrimitives; // todo: replace with OpPrimitives when EthPrimitives is only used in reth-ethereum-* crates
type Primitives = OpPrimitives;
type ChainSpec = OpChainSpec;
type StateCommitment = MerklePatriciaTrie;
type Storage = OpStorage;
}
impl NodeTypesWithEngine for OpNode {
@ -144,7 +193,7 @@ impl<N: FullNodeComponents> OpAddOns<N> {
impl<N> NodeAddOns<N> for OpAddOns<N>
where
N: FullNodeComponents<
Types: NodeTypes<ChainSpec = OpChainSpec>,
Types: NodeTypes<ChainSpec = OpChainSpec, Primitives = OpPrimitives, Storage = OpStorage>,
PayloadBuilder: PayloadBuilder<PayloadType = <N::Types as NodeTypesWithEngine>::Engine>,
>,
OpEngineValidator: EngineValidator<<N::Types as NodeTypesWithEngine>::Engine>,
@ -172,7 +221,7 @@ where
impl<N> RethRpcAddOns<N> for OpAddOns<N>
where
N: FullNodeComponents<
Types: NodeTypes<ChainSpec = OpChainSpec>,
Types: NodeTypes<ChainSpec = OpChainSpec, Primitives = OpPrimitives, Storage = OpStorage>,
PayloadBuilder: PayloadBuilder<PayloadType = <N::Types as NodeTypesWithEngine>::Engine>,
>,
OpEngineValidator: EngineValidator<<N::Types as NodeTypesWithEngine>::Engine>,

View File

@ -10,9 +10,9 @@ use reth_codecs::Compact;
use crate::{BlockHeader, FullBlockHeader, InMemorySize, MaybeSerde};
/// Helper trait that unifies all behaviour required by block to support full node operations.
pub trait FullBlock: Block<Header: Compact> + Compact {}
pub trait FullBlock: Block<Header: Compact> {}
impl<T> FullBlock for T where T: Block<Header: FullBlockHeader> + Compact {}
impl<T> FullBlock for T where T: Block<Header: FullBlockHeader> {}
/// Abstraction of block data type.
// todo: make sealable super-trait, depends on <https://github.com/paradigmxyz/reth/issues/11449>

View File

@ -79,6 +79,15 @@ pub mod serde_bincode_compat {
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct EthPrimitives;
#[cfg(feature = "reth-codec")]
impl reth_primitives_traits::FullNodePrimitives for EthPrimitives {
type Block = crate::Block;
type SignedTx = crate::TransactionSigned;
type TxType = crate::TxType;
type Receipt = crate::Receipt;
}
#[cfg(not(feature = "reth-codec"))]
impl NodePrimitives for EthPrimitives {
type Block = crate::Block;
type SignedTx = crate::TransactionSigned;

View File

@ -198,7 +198,10 @@ where
// Write bodies to database. This will NOT write transactions to database as we've already
// written them directly to static files.
provider.append_block_bodies(
buffer.into_iter().map(|response| (response.block_number(), response.into_body())),
buffer
.into_iter()
.map(|response| (response.block_number(), response.into_body()))
.collect(),
)?;
// The stage is "done" if:

View File

@ -15,7 +15,7 @@ use reth_db_api::{
DatabaseError as DbError,
};
use reth_primitives::{
Account, Receipt, SealedBlock, SealedHeader, StaticFileSegment, StorageEntry,
Account, EthPrimitives, Receipt, SealedBlock, SealedHeader, StaticFileSegment, StorageEntry,
};
use reth_provider::{
providers::{StaticFileProvider, StaticFileProviderRWRefMut, StaticFileWriter},
@ -142,7 +142,7 @@ impl TestStageDB {
/// Insert header to static file if `writer` exists, otherwise to DB.
pub fn insert_header<TX: DbTx + DbTxMut>(
writer: Option<&mut StaticFileProviderRWRefMut<'_, ()>>,
writer: Option<&mut StaticFileProviderRWRefMut<'_, EthPrimitives>>,
tx: &TX,
header: &SealedHeader,
td: U256,

View File

@ -17,6 +17,7 @@ reth-chainspec.workspace = true
reth-blockchain-tree-api.workspace = true
reth-execution-types.workspace = true
reth-primitives = { workspace = true, features = ["reth-codec", "secp256k1"] }
reth-primitives-traits.workspace = true
reth-fs-util.workspace = true
reth-errors.workspace = true
reth-storage-errors.workspace = true
@ -111,6 +112,7 @@ serde = [
"revm/serde",
"reth-codecs/serde",
"reth-optimism-primitives?/serde",
"reth-primitives-traits/serde",
]
test-utils = [
"reth-db/test-utils",
@ -122,6 +124,7 @@ test-utils = [
"reth-evm/test-utils",
"reth-network-p2p/test-utils",
"reth-primitives/test-utils",
"reth-primitives-traits/test-utils",
"reth-codecs/test-utils",
"reth-db-api/test-utils",
"reth-trie-db/test-utils",

View File

@ -0,0 +1,26 @@
use crate::{providers::NodeTypes, DatabaseProvider};
use reth_db::transaction::{DbTx, DbTxMut};
use reth_node_types::FullNodePrimitives;
use reth_primitives::EthPrimitives;
use reth_storage_api::{ChainStorageWriter, EthStorage};
/// Trait that provides access to implementations of [`ChainStorage`]
pub trait ChainStorage<Primitives: FullNodePrimitives>: Send + Sync {
/// Provides access to the chain writer.
fn writer<TX, Types>(&self) -> impl ChainStorageWriter<DatabaseProvider<TX, Types>, Primitives>
where
TX: DbTxMut + DbTx + 'static,
Types: NodeTypes<Primitives = Primitives>;
}
impl ChainStorage<EthPrimitives> for EthStorage {
fn writer<TX, Types>(
&self,
) -> impl ChainStorageWriter<DatabaseProvider<TX, Types>, EthPrimitives>
where
TX: DbTxMut + DbTx + 'static,
Types: NodeTypes<Primitives = EthPrimitives>,
{
self
}
}

View File

@ -44,6 +44,9 @@ use super::ProviderNodeTypes;
mod metrics;
mod chain;
pub use chain::*;
/// A common provider that fetches data from a database or static file.
///
/// This provider implements most provider or provider factory traits.
@ -56,19 +59,22 @@ pub struct ProviderFactory<N: NodeTypesWithDB> {
static_file_provider: StaticFileProvider<N::Primitives>,
/// Optional pruning configuration
prune_modes: PruneModes,
/// The node storage handler.
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, 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("storage", &storage)
.finish()
}
}
@ -80,7 +86,13 @@ impl<N: NodeTypesWithDB> ProviderFactory<N> {
chain_spec: Arc<N::ChainSpec>,
static_file_provider: StaticFileProvider<N::Primitives>,
) -> Self {
Self { db, chain_spec, static_file_provider, prune_modes: PruneModes::none() }
Self {
db,
chain_spec,
static_file_provider,
prune_modes: PruneModes::none(),
storage: Default::default(),
}
}
/// Enables metrics on the static file provider.
@ -121,6 +133,7 @@ impl<N: NodeTypesWithDB<DB = Arc<DatabaseEnv>>> ProviderFactory<N> {
chain_spec,
static_file_provider,
prune_modes: PruneModes::none(),
storage: Default::default(),
})
}
}
@ -139,6 +152,7 @@ impl<N: ProviderNodeTypes> ProviderFactory<N> {
self.chain_spec.clone(),
self.static_file_provider.clone(),
self.prune_modes.clone(),
self.storage.clone(),
))
}
@ -153,6 +167,7 @@ impl<N: ProviderNodeTypes> ProviderFactory<N> {
self.chain_spec.clone(),
self.static_file_provider.clone(),
self.prune_modes.clone(),
self.storage.clone(),
)))
}
@ -617,6 +632,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(),
storage: self.storage.clone(),
}
}
}

View File

@ -1,19 +1,24 @@
use crate::{
bundle_state::StorageRevertsIter,
providers::{database::metrics, static_file::StaticFileWriter, StaticFileProvider},
providers::{
database::{chain::ChainStorage, metrics},
static_file::StaticFileWriter,
ProviderNodeTypes, StaticFileProvider,
},
to_range,
traits::{
AccountExtReader, BlockSource, ChangeSetReader, ReceiptProvider, StageCheckpointWriter,
},
writer::UnifiedStorageWriter,
AccountReader, BlockExecutionWriter, BlockHashReader, BlockNumReader, BlockReader, BlockWriter,
BundleStateInit, ChainStateBlockReader, ChainStateBlockWriter, DBProvider, EvmEnvProvider,
HashingWriter, HeaderProvider, HeaderSyncGap, HeaderSyncGapProvider, HistoricalStateProvider,
HistoricalStateProviderRef, HistoryWriter, LatestStateProvider, LatestStateProviderRef,
OriginalValuesKnown, ProviderError, PruneCheckpointReader, PruneCheckpointWriter, RevertsInit,
StageCheckpointReader, StateChangeWriter, StateProviderBox, StateReader, StateWriter,
StaticFileProviderFactory, StatsReader, StorageReader, StorageTrieWriter, TransactionVariant,
TransactionsProvider, TransactionsProviderExt, TrieWriter, WithdrawalsProvider,
AccountReader, BlockBodyWriter, BlockExecutionWriter, BlockHashReader, BlockNumReader,
BlockReader, BlockWriter, BundleStateInit, ChainStateBlockReader, ChainStateBlockWriter,
DBProvider, EvmEnvProvider, HashingWriter, HeaderProvider, HeaderSyncGap,
HeaderSyncGapProvider, HistoricalStateProvider, HistoricalStateProviderRef, HistoryWriter,
LatestStateProvider, LatestStateProviderRef, OriginalValuesKnown, ProviderError,
PruneCheckpointReader, PruneCheckpointWriter, RevertsInit, StageCheckpointReader,
StateChangeWriter, StateProviderBox, StateReader, StateWriter, StaticFileProviderFactory,
StatsReader, StorageReader, StorageTrieWriter, TransactionVariant, TransactionsProvider,
TransactionsProviderExt, TrieWriter, WithdrawalsProvider,
};
use alloy_consensus::Header;
use alloy_eips::{
@ -47,6 +52,7 @@ use reth_primitives::{
SealedBlockWithSenders, SealedHeader, StaticFileSegment, StorageEntry, TransactionMeta,
TransactionSigned, TransactionSignedEcRecovered, TransactionSignedNoHash,
};
use reth_primitives_traits::{BlockBody as _, FullNodePrimitives};
use reth_prune_types::{PruneCheckpoint, PruneModes, PruneSegment};
use reth_stages_types::{StageCheckpoint, StageId};
use reth_storage_api::{StateProvider, StorageChangeSetReader, TryIntoHistoricalStateProvider};
@ -138,6 +144,8 @@ pub struct DatabaseProvider<TX, N: NodeTypes> {
static_file_provider: StaticFileProvider<N::Primitives>,
/// Pruning configuration
prune_modes: PruneModes,
/// Node storage handler.
storage: Arc<N::Storage>,
}
impl<TX, N: NodeTypes> DatabaseProvider<TX, N> {
@ -224,8 +232,9 @@ impl<TX: DbTxMut, N: NodeTypes> DatabaseProvider<TX, N> {
chain_spec: Arc<N::ChainSpec>,
static_file_provider: StaticFileProvider<N::Primitives>,
prune_modes: PruneModes,
storage: Arc<N::Storage>,
) -> Self {
Self { tx, chain_spec, static_file_provider, prune_modes }
Self { tx, chain_spec, static_file_provider, prune_modes, storage }
}
}
@ -277,9 +286,7 @@ impl<TX: DbTx + 'static, N: NodeTypes> TryIntoHistoricalStateProvider for Databa
}
}
impl<Tx: DbTx + DbTxMut + 'static, N: NodeTypes<ChainSpec: EthereumHardforks> + 'static>
DatabaseProvider<Tx, N>
{
impl<Tx: DbTx + DbTxMut + 'static, N: ProviderNodeTypes + 'static> DatabaseProvider<Tx, N> {
// TODO: uncomment below, once `reth debug_cmd` has been feature gated with dev.
// #[cfg(any(test, feature = "test-utils"))]
/// Inserts an historical block. **Used for setting up test environments**
@ -367,8 +374,9 @@ impl<TX: DbTx + 'static, N: NodeTypes> DatabaseProvider<TX, N> {
chain_spec: Arc<N::ChainSpec>,
static_file_provider: StaticFileProvider<N::Primitives>,
prune_modes: PruneModes,
storage: Arc<N::Storage>,
) -> Self {
Self { tx, chain_spec, static_file_provider, prune_modes }
Self { tx, chain_spec, static_file_provider, prune_modes, storage }
}
/// Consume `DbTx` or `DbTxMut`.
@ -2899,8 +2907,8 @@ impl<TX: DbTx + 'static, N: NodeTypes> StateReader for DatabaseProvider<TX, N> {
}
}
impl<TX: DbTxMut + DbTx + 'static, N: NodeTypes<ChainSpec: EthereumHardforks> + 'static>
BlockExecutionWriter for DatabaseProvider<TX, N>
impl<TX: DbTxMut + DbTx + 'static, N: ProviderNodeTypes + 'static> BlockExecutionWriter
for DatabaseProvider<TX, N>
{
fn take_block_and_execution_range(
&self,
@ -3101,10 +3109,11 @@ impl<TX: DbTxMut + DbTx + 'static, N: NodeTypes<ChainSpec: EthereumHardforks> +
}
}
impl<TX: DbTxMut + DbTx + 'static, N: NodeTypes<ChainSpec: EthereumHardforks> + 'static> BlockWriter
impl<TX: DbTxMut + DbTx + 'static, N: ProviderNodeTypes + 'static> BlockWriter
for DatabaseProvider<TX, N>
{
type Body = BlockBody;
type Body =
<<N::Primitives as FullNodePrimitives>::Block as reth_primitives_traits::Block>::Body;
/// Inserts the block into the database, always modifying the following tables:
/// * [`CanonicalHeaders`](tables::CanonicalHeaders)
@ -3266,44 +3275,31 @@ impl<TX: DbTxMut + DbTx + 'static, N: NodeTypes<ChainSpec: EthereumHardforks> +
fn append_block_bodies(
&self,
bodies: impl Iterator<Item = (BlockNumber, Option<BlockBody>)>,
bodies: Vec<(BlockNumber, Option<Self::Body>)>,
) -> ProviderResult<()> {
let mut block_indices_cursor = self.tx.cursor_write::<tables::BlockBodyIndices>()?;
let mut tx_block_cursor = self.tx.cursor_write::<tables::TransactionBlocks>()?;
let mut ommers_cursor = self.tx.cursor_write::<tables::BlockOmmers>()?;
let mut withdrawals_cursor = self.tx.cursor_write::<tables::BlockWithdrawals>()?;
// Get id for the next tx_num of zero if there are no transactions.
let mut next_tx_num = tx_block_cursor.last()?.map(|(id, _)| id + 1).unwrap_or_default();
for (block_number, body) in bodies {
let tx_count = body.as_ref().map(|b| b.transactions.len() as u64).unwrap_or_default();
for (block_number, body) in &bodies {
let tx_count = body.as_ref().map(|b| b.transactions().len() as u64).unwrap_or_default();
let block_indices = StoredBlockBodyIndices { first_tx_num: next_tx_num, tx_count };
// insert block meta
block_indices_cursor.append(block_number, block_indices)?;
block_indices_cursor.append(*block_number, block_indices)?;
next_tx_num += tx_count;
let Some(body) = body else { continue };
// write transaction block index
if !body.transactions.is_empty() {
tx_block_cursor.append(block_indices.last_tx_num(), block_number)?;
if !body.transactions().is_empty() {
tx_block_cursor.append(block_indices.last_tx_num(), *block_number)?;
}
}
// Write ommers if any
if !body.ommers.is_empty() {
ommers_cursor.append(block_number, StoredBlockOmmers { ommers: body.ommers })?;
}
// Write withdrawals if any
if let Some(withdrawals) = body.withdrawals {
if !withdrawals.is_empty() {
withdrawals_cursor
.append(block_number, StoredBlockWithdrawals { withdrawals })?;
}
}
}
self.storage.writer().write_block_bodies(self, bodies)?;
Ok(())
}

View File

@ -22,7 +22,7 @@ use reth_chain_state::{ChainInfoTracker, ForkChoiceNotifications, ForkChoiceSubs
use reth_chainspec::{ChainInfo, EthereumHardforks};
use reth_db_api::models::{AccountBeforeTx, StoredBlockBodyIndices};
use reth_evm::ConfigureEvmEnv;
use reth_node_types::NodeTypesWithDB;
use reth_node_types::{FullNodePrimitives, NodeTypes, NodeTypesWithDB};
use reth_primitives::{
Account, Block, BlockWithSenders, Receipt, SealedBlock, SealedBlockWithSenders, SealedHeader,
TransactionMeta, TransactionSigned, TransactionSignedNoHash,
@ -37,6 +37,7 @@ use std::{
sync::Arc,
time::Instant,
};
use tracing::trace;
mod database;
@ -67,10 +68,35 @@ pub use blockchain_provider::BlockchainProvider2;
mod consistent;
pub use consistent::ConsistentProvider;
/// Helper trait keeping common requirements of providers for [`NodeTypesWithDB`].
pub trait ProviderNodeTypes: NodeTypesWithDB<ChainSpec: EthereumHardforks> {}
/// Helper trait to bound [`NodeTypes`] so that combined with database they satisfy
/// [`ProviderNodeTypes`].
pub trait NodeTypesForProvider
where
Self: NodeTypes<
ChainSpec: EthereumHardforks,
Storage: ChainStorage<Self::Primitives>,
Primitives: FullNodePrimitives,
>,
{
}
impl<T> ProviderNodeTypes for T where T: NodeTypesWithDB<ChainSpec: EthereumHardforks> {}
impl<T> NodeTypesForProvider for T where
T: NodeTypes<
ChainSpec: EthereumHardforks,
Storage: ChainStorage<T::Primitives>,
Primitives: FullNodePrimitives,
>
{
}
/// Helper trait keeping common requirements of providers for [`NodeTypesWithDB`].
pub trait ProviderNodeTypes
where
Self: NodeTypesForProvider + NodeTypesWithDB,
{
}
impl<T> ProviderNodeTypes for T where T: NodeTypesForProvider + NodeTypesWithDB {}
/// The main type for interacting with the blockchain.
///

View File

@ -1,9 +1,9 @@
use crate::{
traits::{BlockSource, ReceiptProvider},
AccountReader, BlockHashReader, BlockIdReader, BlockNumReader, BlockReader, BlockReaderIdExt,
ChainSpecProvider, ChangeSetReader, DatabaseProvider, EvmEnvProvider, HeaderProvider,
ReceiptProviderIdExt, StateProvider, StateProviderBox, StateProviderFactory, StateReader,
StateRootProvider, TransactionVariant, TransactionsProvider, WithdrawalsProvider,
ChainSpecProvider, ChangeSetReader, DatabaseProvider, EthStorage, EvmEnvProvider,
HeaderProvider, ReceiptProviderIdExt, StateProvider, StateProviderBox, StateProviderFactory,
StateReader, StateRootProvider, TransactionVariant, TransactionsProvider, WithdrawalsProvider,
};
use alloy_consensus::{constants::EMPTY_ROOT_HASH, Header};
use alloy_eips::{
@ -23,7 +23,7 @@ use reth_evm::ConfigureEvmEnv;
use reth_execution_types::ExecutionOutcome;
use reth_node_types::NodeTypes;
use reth_primitives::{
Account, Block, BlockWithSenders, Bytecode, GotExpected, Receipt, SealedBlock,
Account, Block, BlockWithSenders, Bytecode, EthPrimitives, GotExpected, Receipt, SealedBlock,
SealedBlockWithSenders, SealedHeader, TransactionMeta, TransactionSigned,
TransactionSignedNoHash,
};
@ -158,9 +158,10 @@ impl MockEthProvider {
pub struct MockNode;
impl NodeTypes for MockNode {
type Primitives = ();
type Primitives = EthPrimitives;
type ChainSpec = ChainSpec;
type StateCommitment = MerklePatriciaTrie;
type Storage = EthStorage;
}
impl DatabaseProviderFactory for MockEthProvider {

View File

@ -1,4 +1,7 @@
use crate::{providers::StaticFileProvider, HashingWriter, ProviderFactory, TrieWriter};
use crate::{
providers::{ProviderNodeTypes, StaticFileProvider},
HashingWriter, ProviderFactory, TrieWriter,
};
use alloy_primitives::B256;
use reth_chainspec::{ChainSpec, MAINNET};
use reth_db::{
@ -6,7 +9,7 @@ use reth_db::{
DatabaseEnv,
};
use reth_errors::ProviderResult;
use reth_node_types::{NodeTypesWithDB, NodeTypesWithDBAdapter};
use reth_node_types::NodeTypesWithDBAdapter;
use reth_primitives::{Account, StorageEntry};
use reth_trie::StateRoot;
use reth_trie_db::DatabaseStateRoot;
@ -22,10 +25,11 @@ pub use reth_chain_state::test_utils::TestCanonStateSubscriptions;
/// Mock [`reth_node_types::NodeTypes`] for testing.
pub type MockNodeTypes = reth_node_types::AnyNodeTypesWithEngine<
(),
reth_primitives::EthPrimitives,
reth_ethereum_engine_primitives::EthEngineTypes,
reth_chainspec::ChainSpec,
reth_trie_db::MerklePatriciaTrie,
crate::EthStorage,
>;
/// Mock [`reth_node_types::NodeTypesWithDB`] for testing.
@ -51,7 +55,7 @@ pub fn create_test_provider_factory_with_chain_spec(
}
/// Inserts the genesis alloc from the provided chain spec into the trie.
pub fn insert_genesis<N: NodeTypesWithDB<ChainSpec = ChainSpec>>(
pub fn insert_genesis<N: ProviderNodeTypes<ChainSpec = ChainSpec>>(
provider_factory: &ProviderFactory<N>,
chain_spec: Arc<N::ChainSpec>,
) -> ProviderResult<B256> {

View File

@ -50,7 +50,7 @@ pub trait BlockWriter: Send + Sync {
/// Bodies are passed as [`Option`]s, if body is `None` the corresponding block is empty.
fn append_block_bodies(
&self,
bodies: impl Iterator<Item = (BlockNumber, Option<Self::Body>)>,
bodies: Vec<(BlockNumber, Option<Self::Body>)>,
) -> ProviderResult<()>;
/// Appends a batch of sealed blocks to the blockchain, including sender information, and

View File

@ -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

View File

@ -0,0 +1,72 @@
use crate::DBProvider;
use alloy_primitives::BlockNumber;
use reth_db::{
cursor::DbCursorRW,
models::{StoredBlockOmmers, StoredBlockWithdrawals},
tables,
transaction::DbTxMut,
};
use reth_primitives_traits::{Block, BlockBody, FullNodePrimitives};
use reth_storage_errors::provider::ProviderResult;
/// Trait that implements how block bodies are written to the storage.
///
/// Note: Within the current abstraction, this should only write to tables unrelated to
/// transactions. Writing of transactions is handled separately.
#[auto_impl::auto_impl(&, Arc)]
pub trait BlockBodyWriter<Provider, Body: BlockBody> {
/// Writes a set of block bodies to the storage.
fn write_block_bodies(
&self,
provider: &Provider,
bodies: Vec<(BlockNumber, Option<Body>)>,
) -> ProviderResult<()>;
}
/// Trait that implements how chain-specific types are written to the storage.
pub trait ChainStorageWriter<Provider, Primitives: FullNodePrimitives>:
BlockBodyWriter<Provider, <Primitives::Block as Block>::Body>
{
}
impl<T, Provider, Primitives: FullNodePrimitives> ChainStorageWriter<Provider, Primitives> for T where
T: BlockBodyWriter<Provider, <Primitives::Block as Block>::Body>
{
}
/// Ethereum storage implementation.
#[derive(Debug, Default, Clone, Copy)]
pub struct EthStorage;
impl<Provider> BlockBodyWriter<Provider, reth_primitives::BlockBody> for EthStorage
where
Provider: DBProvider<Tx: DbTxMut>,
{
fn write_block_bodies(
&self,
provider: &Provider,
bodies: Vec<(u64, Option<reth_primitives::BlockBody>)>,
) -> ProviderResult<()> {
let mut ommers_cursor = provider.tx_ref().cursor_write::<tables::BlockOmmers>()?;
let mut withdrawals_cursor =
provider.tx_ref().cursor_write::<tables::BlockWithdrawals>()?;
for (block_number, body) in bodies {
let Some(body) = body else { continue };
// Write ommers if any
if !body.ommers.is_empty() {
ommers_cursor.append(block_number, StoredBlockOmmers { ommers: body.ommers })?;
}
// Write withdrawals if any
if let Some(withdrawals) = body.withdrawals {
if !withdrawals.is_empty() {
withdrawals_cursor
.append(block_number, StoredBlockWithdrawals { withdrawals })?;
}
}
}
Ok(())
}
}

View File

@ -22,6 +22,9 @@ pub use block_id::*;
mod block_hash;
pub use block_hash::*;
mod chain;
pub use chain::*;
mod header;
pub use header::*;

View File

@ -42,7 +42,8 @@ use reth::{
PayloadBuilderConfig,
},
network::NetworkHandle,
providers::{CanonStateSubscriptions, StateProviderFactory},
primitives::EthPrimitives,
providers::{CanonStateSubscriptions, EthStorage, StateProviderFactory},
rpc::eth::EthApi,
tasks::TaskManager,
transaction_pool::TransactionPool,
@ -227,9 +228,10 @@ struct MyCustomNode;
/// Configure the node types
impl NodeTypes for MyCustomNode {
type Primitives = ();
type Primitives = EthPrimitives;
type ChainSpec = ChainSpec;
type StateCommitment = MerklePatriciaTrie;
type Storage = EthStorage;
}
/// Configure the node types with the custom engine types
@ -254,7 +256,14 @@ pub type MyNodeAddOns<N> = RpcAddOns<
/// This provides a preset configuration for the node
impl<N> Node<N> for MyCustomNode
where
N: FullNodeTypes<Types: NodeTypesWithEngine<Engine = CustomEngineTypes, ChainSpec = ChainSpec>>,
N: FullNodeTypes<
Types: NodeTypesWithEngine<
Engine = CustomEngineTypes,
ChainSpec = ChainSpec,
Primitives = EthPrimitives,
Storage = EthStorage,
>,
>,
{
type ComponentsBuilder = ComponentsBuilder<
N,