1pub 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#[derive(Debug, Default, Clone, Copy)]
48#[non_exhaustive]
49pub struct EthereumNode;
50
51impl EthereumNode {
52 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 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#[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#[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#[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#[derive(Debug, Default, Clone, Copy)]
326#[non_exhaustive]
327pub struct EthereumPoolBuilder {
328 }
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 {
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 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#[derive(Debug, Default, Clone, Copy)]
396pub struct EthereumNetworkBuilder {
397 }
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#[derive(Debug, Default, Clone, Copy)]
424pub struct EthereumConsensusBuilder {
425 }
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#[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}