reth_node_ethereum/
node.rs

1//! Ethereum Node types config.
2
3pub use crate::{payload::EthereumPayloadBuilder, EthereumEngineValidator};
4use crate::{EthEngineTypes, EthEvmConfig};
5use reth_chainspec::ChainSpec;
6use reth_consensus::{ConsensusError, FullConsensus};
7use reth_ethereum_consensus::EthBeaconConsensus;
8use reth_ethereum_engine_primitives::{
9    EthBuiltPayload, EthPayloadAttributes, EthPayloadBuilderAttributes,
10};
11use reth_ethereum_primitives::{EthPrimitives, PooledTransaction};
12use reth_evm::{
13    execute::BasicBlockExecutorProvider, ConfigureEvm, EvmFactory, EvmFactoryFor,
14    NextBlockEnvAttributes,
15};
16use reth_network::{EthNetworkPrimitives, NetworkHandle, PeersInfo};
17use reth_node_api::{AddOnsContext, FullNodeComponents, NodeAddOns, TxTy};
18use reth_node_builder::{
19    components::{
20        BasicPayloadServiceBuilder, ComponentsBuilder, ConsensusBuilder, ExecutorBuilder,
21        NetworkBuilder, PoolBuilder,
22    },
23    node::{FullNodeTypes, NodeTypes, NodeTypesWithEngine},
24    rpc::{
25        EngineValidatorAddOn, EngineValidatorBuilder, EthApiBuilder, EthApiCtx, RethRpcAddOns,
26        RpcAddOns, RpcHandle,
27    },
28    BuilderContext, DebugNode, Node, NodeAdapter, NodeComponentsBuilder, PayloadBuilderConfig,
29    PayloadTypes,
30};
31use reth_provider::{providers::ProviderFactoryBuilder, CanonStateSubscriptions, EthStorage};
32use reth_rpc::{eth::core::EthApiFor, ValidationApi};
33use reth_rpc_api::{eth::FullEthApiServer, servers::BlockSubmissionValidationApiServer};
34use reth_rpc_builder::config::RethRpcServerConfig;
35use reth_rpc_eth_types::{error::FromEvmError, EthApiError};
36use reth_rpc_server_types::RethRpcModule;
37use reth_tracing::tracing::{debug, info};
38use reth_transaction_pool::{
39    blobstore::DiskFileBlobStore, EthTransactionPool, PoolTransaction, TransactionPool,
40    TransactionValidationTaskExecutor,
41};
42use reth_trie_db::MerklePatriciaTrie;
43use revm::context::TxEnv;
44use std::sync::Arc;
45
46/// Type configuration for a regular Ethereum node.
47#[derive(Debug, Default, Clone, Copy)]
48#[non_exhaustive]
49pub struct EthereumNode;
50
51impl EthereumNode {
52    /// Returns a [`ComponentsBuilder`] configured for a regular Ethereum node.
53    pub fn components<Node>() -> ComponentsBuilder<
54        Node,
55        EthereumPoolBuilder,
56        BasicPayloadServiceBuilder<EthereumPayloadBuilder>,
57        EthereumNetworkBuilder,
58        EthereumExecutorBuilder,
59        EthereumConsensusBuilder,
60    >
61    where
62        Node: FullNodeTypes<Types: NodeTypes<ChainSpec = ChainSpec, Primitives = EthPrimitives>>,
63        <Node::Types as NodeTypesWithEngine>::Engine: PayloadTypes<
64            BuiltPayload = EthBuiltPayload,
65            PayloadAttributes = EthPayloadAttributes,
66            PayloadBuilderAttributes = EthPayloadBuilderAttributes,
67        >,
68    {
69        ComponentsBuilder::default()
70            .node_types::<Node>()
71            .pool(EthereumPoolBuilder::default())
72            .payload(BasicPayloadServiceBuilder::default())
73            .network(EthereumNetworkBuilder::default())
74            .executor(EthereumExecutorBuilder::default())
75            .consensus(EthereumConsensusBuilder::default())
76    }
77
78    /// Instantiates the [`ProviderFactoryBuilder`] for an ethereum node.
79    ///
80    /// # Open a Providerfactory in read-only mode from a datadir
81    ///
82    /// See also: [`ProviderFactoryBuilder`] and
83    /// [`ReadOnlyConfig`](reth_provider::providers::ReadOnlyConfig).
84    ///
85    /// ```no_run
86    /// use reth_chainspec::MAINNET;
87    /// use reth_node_ethereum::EthereumNode;
88    ///
89    /// let factory = EthereumNode::provider_factory_builder()
90    ///     .open_read_only(MAINNET.clone(), "datadir")
91    ///     .unwrap();
92    /// ```
93    ///
94    /// # Open a Providerfactory manually with with all required components
95    ///
96    /// ```no_run
97    /// use reth_chainspec::ChainSpecBuilder;
98    /// use reth_db::open_db_read_only;
99    /// use reth_node_ethereum::EthereumNode;
100    /// use reth_provider::providers::StaticFileProvider;
101    /// use std::sync::Arc;
102    ///
103    /// let factory = EthereumNode::provider_factory_builder()
104    ///     .db(Arc::new(open_db_read_only("db", Default::default()).unwrap()))
105    ///     .chainspec(ChainSpecBuilder::mainnet().build().into())
106    ///     .static_file(StaticFileProvider::read_only("db/static_files", false).unwrap())
107    ///     .build_provider_factory();
108    /// ```
109    pub fn provider_factory_builder() -> ProviderFactoryBuilder<Self> {
110        ProviderFactoryBuilder::default()
111    }
112}
113
114impl NodeTypes for EthereumNode {
115    type Primitives = EthPrimitives;
116    type ChainSpec = ChainSpec;
117    type StateCommitment = MerklePatriciaTrie;
118    type Storage = EthStorage;
119}
120
121impl NodeTypesWithEngine for EthereumNode {
122    type Engine = EthEngineTypes;
123}
124
125/// Builds [`EthApi`](reth_rpc::EthApi) for Ethereum.
126#[derive(Debug, Default)]
127pub struct EthereumEthApiBuilder;
128
129impl<N> EthApiBuilder<N> for EthereumEthApiBuilder
130where
131    N: FullNodeComponents,
132    EthApiFor<N>: FullEthApiServer<Provider = N::Provider, Pool = N::Pool>,
133{
134    type EthApi = EthApiFor<N>;
135
136    fn build_eth_api(self, ctx: EthApiCtx<'_, N>) -> Self::EthApi {
137        reth_rpc::EthApiBuilder::new(
138            ctx.components.provider().clone(),
139            ctx.components.pool().clone(),
140            ctx.components.network().clone(),
141            ctx.components.evm_config().clone(),
142        )
143        .eth_cache(ctx.cache)
144        .task_spawner(ctx.components.task_executor().clone())
145        .gas_cap(ctx.config.rpc_gas_cap.into())
146        .max_simulate_blocks(ctx.config.rpc_max_simulate_blocks)
147        .eth_proof_window(ctx.config.eth_proof_window)
148        .fee_history_cache_config(ctx.config.fee_history_cache)
149        .proof_permits(ctx.config.proof_permits)
150        .build()
151    }
152}
153
154/// Add-ons w.r.t. l1 ethereum.
155#[derive(Debug)]
156pub struct EthereumAddOns<N: FullNodeComponents>
157where
158    EthApiFor<N>: FullEthApiServer<Provider = N::Provider, Pool = N::Pool>,
159{
160    inner: RpcAddOns<N, EthereumEthApiBuilder, EthereumEngineValidatorBuilder>,
161}
162
163impl<N: FullNodeComponents> Default for EthereumAddOns<N>
164where
165    EthApiFor<N>: FullEthApiServer<Provider = N::Provider, Pool = N::Pool>,
166{
167    fn default() -> Self {
168        Self { inner: Default::default() }
169    }
170}
171
172impl<N> NodeAddOns<N> for EthereumAddOns<N>
173where
174    N: FullNodeComponents<
175        Types: NodeTypesWithEngine<
176            ChainSpec = ChainSpec,
177            Primitives = EthPrimitives,
178            Engine = EthEngineTypes,
179        >,
180        Evm: ConfigureEvm<NextBlockEnvCtx = NextBlockEnvAttributes>,
181    >,
182    EthApiError: FromEvmError<N::Evm>,
183    EvmFactoryFor<N::Evm>: EvmFactory<Tx = TxEnv>,
184{
185    type Handle = RpcHandle<N, EthApiFor<N>>;
186
187    async fn launch_add_ons(
188        self,
189        ctx: reth_node_api::AddOnsContext<'_, N>,
190    ) -> eyre::Result<Self::Handle> {
191        let validation_api = ValidationApi::new(
192            ctx.node.provider().clone(),
193            Arc::new(ctx.node.consensus().clone()),
194            ctx.node.block_executor().clone(),
195            ctx.config.rpc.flashbots_config(),
196            Box::new(ctx.node.task_executor().clone()),
197            Arc::new(EthereumEngineValidator::new(ctx.config.chain.clone())),
198        );
199
200        self.inner
201            .launch_add_ons_with(ctx, move |modules, _| {
202                modules.merge_if_module_configured(
203                    RethRpcModule::Flashbots,
204                    validation_api.into_rpc(),
205                )?;
206
207                Ok(())
208            })
209            .await
210    }
211}
212
213impl<N> RethRpcAddOns<N> for EthereumAddOns<N>
214where
215    N: FullNodeComponents<
216        Types: NodeTypesWithEngine<
217            ChainSpec = ChainSpec,
218            Primitives = EthPrimitives,
219            Engine = EthEngineTypes,
220        >,
221        Evm: ConfigureEvm<NextBlockEnvCtx = NextBlockEnvAttributes>,
222    >,
223    EthApiError: FromEvmError<N::Evm>,
224    EvmFactoryFor<N::Evm>: EvmFactory<Tx = TxEnv>,
225{
226    type EthApi = EthApiFor<N>;
227
228    fn hooks_mut(&mut self) -> &mut reth_node_builder::rpc::RpcHooks<N, Self::EthApi> {
229        self.inner.hooks_mut()
230    }
231}
232
233impl<N> EngineValidatorAddOn<N> for EthereumAddOns<N>
234where
235    N: FullNodeComponents<
236        Types: NodeTypesWithEngine<
237            ChainSpec = ChainSpec,
238            Primitives = EthPrimitives,
239            Engine = EthEngineTypes,
240        >,
241    >,
242    EthApiFor<N>: FullEthApiServer<Provider = N::Provider, Pool = N::Pool>,
243{
244    type Validator = EthereumEngineValidator;
245
246    async fn engine_validator(&self, ctx: &AddOnsContext<'_, N>) -> eyre::Result<Self::Validator> {
247        EthereumEngineValidatorBuilder::default().build(ctx).await
248    }
249}
250
251impl<N> Node<N> for EthereumNode
252where
253    N: FullNodeTypes<Types = Self>,
254{
255    type ComponentsBuilder = ComponentsBuilder<
256        N,
257        EthereumPoolBuilder,
258        BasicPayloadServiceBuilder<EthereumPayloadBuilder>,
259        EthereumNetworkBuilder,
260        EthereumExecutorBuilder,
261        EthereumConsensusBuilder,
262    >;
263
264    type AddOns = EthereumAddOns<
265        NodeAdapter<N, <Self::ComponentsBuilder as NodeComponentsBuilder<N>>::Components>,
266    >;
267
268    fn components_builder(&self) -> Self::ComponentsBuilder {
269        Self::components()
270    }
271
272    fn add_ons(&self) -> Self::AddOns {
273        EthereumAddOns::default()
274    }
275}
276
277impl<N: FullNodeComponents<Types = Self>> DebugNode<N> for EthereumNode {
278    type RpcBlock = alloy_rpc_types_eth::Block;
279
280    fn rpc_to_primitive_block(rpc_block: Self::RpcBlock) -> reth_ethereum_primitives::Block {
281        let alloy_rpc_types_eth::Block { header, transactions, withdrawals, .. } = rpc_block;
282        reth_ethereum_primitives::Block {
283            header: header.inner,
284            body: reth_ethereum_primitives::BlockBody {
285                transactions: transactions
286                    .into_transactions()
287                    .map(|tx| tx.inner.into_inner().into())
288                    .collect(),
289                ommers: Default::default(),
290                withdrawals,
291            },
292        }
293    }
294}
295
296/// A regular ethereum evm and executor builder.
297#[derive(Debug, Default, Clone, Copy)]
298#[non_exhaustive]
299pub struct EthereumExecutorBuilder;
300
301impl<Types, Node> ExecutorBuilder<Node> for EthereumExecutorBuilder
302where
303    Types: NodeTypesWithEngine<ChainSpec = ChainSpec, Primitives = EthPrimitives>,
304    Node: FullNodeTypes<Types = Types>,
305{
306    type EVM = EthEvmConfig;
307    type Executor = BasicBlockExecutorProvider<EthEvmConfig>;
308
309    async fn build_evm(
310        self,
311        ctx: &BuilderContext<Node>,
312    ) -> eyre::Result<(Self::EVM, Self::Executor)> {
313        let evm_config = EthEvmConfig::new(ctx.chain_spec())
314            .with_extra_data(ctx.payload_builder_config().extra_data_bytes());
315        let executor = BasicBlockExecutorProvider::new(evm_config.clone());
316
317        Ok((evm_config, executor))
318    }
319}
320
321/// A basic ethereum transaction pool.
322///
323/// This contains various settings that can be configured and take precedence over the node's
324/// config.
325#[derive(Debug, Default, Clone, Copy)]
326#[non_exhaustive]
327pub struct EthereumPoolBuilder {
328    // TODO add options for txpool args
329}
330
331impl<Types, Node> PoolBuilder<Node> for EthereumPoolBuilder
332where
333    Types: NodeTypesWithEngine<ChainSpec = ChainSpec, Primitives = EthPrimitives>,
334    Node: FullNodeTypes<Types = Types>,
335{
336    type Pool = EthTransactionPool<Node::Provider, DiskFileBlobStore>;
337
338    async fn build_pool(self, ctx: &BuilderContext<Node>) -> eyre::Result<Self::Pool> {
339        let data_dir = ctx.config().datadir();
340        let pool_config = ctx.pool_config();
341        let blob_store = DiskFileBlobStore::open(data_dir.blobstore(), Default::default())?;
342        let validator = TransactionValidationTaskExecutor::eth_builder(ctx.provider().clone())
343            .with_head_timestamp(ctx.head().timestamp)
344            .kzg_settings(ctx.kzg_settings()?)
345            .with_local_transactions_config(pool_config.local_transactions_config.clone())
346            .with_additional_tasks(ctx.config().txpool.additional_validation_tasks)
347            .build_with_tasks(ctx.task_executor().clone(), blob_store.clone());
348
349        let transaction_pool =
350            reth_transaction_pool::Pool::eth_pool(validator, blob_store, pool_config);
351        info!(target: "reth::cli", "Transaction pool initialized");
352        let transactions_path = data_dir.txpool_transactions();
353
354        // spawn txpool maintenance task
355        {
356            let pool = transaction_pool.clone();
357            let chain_events = ctx.provider().canonical_state_stream();
358            let client = ctx.provider().clone();
359            let transactions_backup_config =
360                reth_transaction_pool::maintain::LocalTransactionBackupConfig::with_local_txs_backup(transactions_path);
361
362            ctx.task_executor().spawn_critical_with_graceful_shutdown_signal(
363                "local transactions backup task",
364                |shutdown| {
365                    reth_transaction_pool::maintain::backup_local_transactions_task(
366                        shutdown,
367                        pool.clone(),
368                        transactions_backup_config,
369                    )
370                },
371            );
372
373            // spawn the maintenance task
374            ctx.task_executor().spawn_critical(
375                "txpool maintenance task",
376                reth_transaction_pool::maintain::maintain_transaction_pool_future(
377                    client,
378                    pool,
379                    chain_events,
380                    ctx.task_executor().clone(),
381                    reth_transaction_pool::maintain::MaintainPoolConfig {
382                        max_tx_lifetime: transaction_pool.config().max_queued_lifetime,
383                        ..Default::default()
384                    },
385                ),
386            );
387            debug!(target: "reth::cli", "Spawned txpool maintenance task");
388        }
389
390        Ok(transaction_pool)
391    }
392}
393
394/// A basic ethereum payload service.
395#[derive(Debug, Default, Clone, Copy)]
396pub struct EthereumNetworkBuilder {
397    // TODO add closure to modify network
398}
399
400impl<Node, Pool> NetworkBuilder<Node, Pool> for EthereumNetworkBuilder
401where
402    Node: FullNodeTypes<Types: NodeTypes<ChainSpec = ChainSpec, Primitives = EthPrimitives>>,
403    Pool: TransactionPool<
404            Transaction: PoolTransaction<Consensus = TxTy<Node::Types>, Pooled = PooledTransaction>,
405        > + Unpin
406        + 'static,
407{
408    type Primitives = EthNetworkPrimitives;
409
410    async fn build_network(
411        self,
412        ctx: &BuilderContext<Node>,
413        pool: Pool,
414    ) -> eyre::Result<NetworkHandle> {
415        let network = ctx.network_builder().await?;
416        let handle = ctx.start_network(network, pool);
417        info!(target: "reth::cli", enode=%handle.local_node_record(), "P2P networking initialized");
418        Ok(handle)
419    }
420}
421
422/// A basic ethereum consensus builder.
423#[derive(Debug, Default, Clone, Copy)]
424pub struct EthereumConsensusBuilder {
425    // TODO add closure to modify consensus
426}
427
428impl<Node> ConsensusBuilder<Node> for EthereumConsensusBuilder
429where
430    Node: FullNodeTypes<Types: NodeTypes<ChainSpec = ChainSpec, Primitives = EthPrimitives>>,
431{
432    type Consensus = Arc<dyn FullConsensus<EthPrimitives, Error = ConsensusError>>;
433
434    async fn build_consensus(self, ctx: &BuilderContext<Node>) -> eyre::Result<Self::Consensus> {
435        Ok(Arc::new(EthBeaconConsensus::new(ctx.chain_spec())))
436    }
437}
438
439/// Builder for [`EthereumEngineValidator`].
440#[derive(Debug, Default, Clone)]
441#[non_exhaustive]
442pub struct EthereumEngineValidatorBuilder;
443
444impl<Node, Types> EngineValidatorBuilder<Node> for EthereumEngineValidatorBuilder
445where
446    Types: NodeTypesWithEngine<
447        ChainSpec = ChainSpec,
448        Engine = EthEngineTypes,
449        Primitives = EthPrimitives,
450    >,
451    Node: FullNodeComponents<Types = Types>,
452{
453    type Validator = EthereumEngineValidator;
454
455    async fn build(self, ctx: &AddOnsContext<'_, Node>) -> eyre::Result<Self::Validator> {
456        Ok(EthereumEngineValidator::new(ctx.config.chain.clone()))
457    }
458}