1use std::sync::Arc;
4
5use reth_basic_payload_builder::{BasicPayloadJobGenerator, BasicPayloadJobGeneratorConfig};
6use reth_beacon_consensus::EthBeaconConsensus;
7use reth_chainspec::ChainSpec;
8use reth_ethereum_engine_primitives::{
9 EthBuiltPayload, EthPayloadAttributes, EthPayloadBuilderAttributes,
10};
11use reth_ethereum_payload_builder::EthereumBuilderConfig;
12use reth_evm::execute::BasicBlockExecutorProvider;
13use reth_evm_ethereum::execute::EthExecutionStrategyFactory;
14use reth_network::{EthNetworkPrimitives, NetworkHandle, PeersInfo};
15use reth_node_api::{
16 AddOnsContext, ConfigureEvm, FullNodeComponents, HeaderTy, NodeTypesWithDB, TxTy,
17};
18use reth_node_builder::{
19 components::{
20 ComponentsBuilder, ConsensusBuilder, ExecutorBuilder, NetworkBuilder,
21 PayloadServiceBuilder, PoolBuilder,
22 },
23 node::{FullNodeTypes, NodeTypes, NodeTypesWithEngine},
24 rpc::{EngineValidatorBuilder, RpcAddOns},
25 BuilderContext, Node, NodeAdapter, NodeComponentsBuilder, PayloadBuilderConfig, PayloadTypes,
26};
27use reth_node_core::version::default_extra_data_bytes;
28use reth_payload_builder::{PayloadBuilderHandle, PayloadBuilderService};
29use reth_primitives::{EthPrimitives, PooledTransactionsElement};
30use reth_provider::{CanonStateSubscriptions, EthStorage};
31use reth_rpc::EthApi;
32use reth_tracing::tracing::{debug, info};
33use reth_transaction_pool::{
34 blobstore::DiskFileBlobStore, EthTransactionPool, PoolTransaction, TransactionPool,
35 TransactionValidationTaskExecutor,
36};
37use reth_trie_db::MerklePatriciaTrie;
38
39use crate::{EthEngineTypes, EthEvmConfig};
40
41pub use reth_ethereum_engine_primitives::EthereumEngineValidator;
42
43#[derive(Debug, Default, Clone, Copy)]
45#[non_exhaustive]
46pub struct EthereumNode;
47
48impl EthereumNode {
49 pub fn components<Node>() -> ComponentsBuilder<
51 Node,
52 EthereumPoolBuilder,
53 EthereumPayloadBuilder,
54 EthereumNetworkBuilder,
55 EthereumExecutorBuilder,
56 EthereumConsensusBuilder,
57 >
58 where
59 Node: FullNodeTypes<Types: NodeTypes<ChainSpec = ChainSpec, Primitives = EthPrimitives>>,
60 <Node::Types as NodeTypesWithEngine>::Engine: PayloadTypes<
61 BuiltPayload = EthBuiltPayload,
62 PayloadAttributes = EthPayloadAttributes,
63 PayloadBuilderAttributes = EthPayloadBuilderAttributes,
64 >,
65 {
66 ComponentsBuilder::default()
67 .node_types::<Node>()
68 .pool(EthereumPoolBuilder::default())
69 .payload(EthereumPayloadBuilder::default())
70 .network(EthereumNetworkBuilder::default())
71 .executor(EthereumExecutorBuilder::default())
72 .consensus(EthereumConsensusBuilder::default())
73 }
74}
75
76impl NodeTypes for EthereumNode {
77 type Primitives = EthPrimitives;
78 type ChainSpec = ChainSpec;
79 type StateCommitment = MerklePatriciaTrie;
80 type Storage = EthStorage;
81}
82
83impl NodeTypesWithEngine for EthereumNode {
84 type Engine = EthEngineTypes;
85}
86
87pub type EthereumAddOns<N> = RpcAddOns<
89 N,
90 EthApi<
91 <N as FullNodeTypes>::Provider,
92 <N as FullNodeComponents>::Pool,
93 NetworkHandle,
94 <N as FullNodeComponents>::Evm,
95 >,
96 EthereumEngineValidatorBuilder,
97>;
98
99impl<Types, N> Node<N> for EthereumNode
100where
101 Types: NodeTypesWithDB
102 + NodeTypesWithEngine<
103 Engine = EthEngineTypes,
104 ChainSpec = ChainSpec,
105 Primitives = EthPrimitives,
106 Storage = EthStorage,
107 >,
108 N: FullNodeTypes<Types = Types>,
109{
110 type ComponentsBuilder = ComponentsBuilder<
111 N,
112 EthereumPoolBuilder,
113 EthereumPayloadBuilder,
114 EthereumNetworkBuilder,
115 EthereumExecutorBuilder,
116 EthereumConsensusBuilder,
117 >;
118
119 type AddOns = EthereumAddOns<
120 NodeAdapter<N, <Self::ComponentsBuilder as NodeComponentsBuilder<N>>::Components>,
121 >;
122
123 fn components_builder(&self) -> Self::ComponentsBuilder {
124 Self::components()
125 }
126
127 fn add_ons(&self) -> Self::AddOns {
128 EthereumAddOns::default()
129 }
130}
131
132#[derive(Debug, Default, Clone, Copy)]
134#[non_exhaustive]
135pub struct EthereumExecutorBuilder;
136
137impl<Types, Node> ExecutorBuilder<Node> for EthereumExecutorBuilder
138where
139 Types: NodeTypesWithEngine<ChainSpec = ChainSpec, Primitives = EthPrimitives>,
140 Node: FullNodeTypes<Types = Types>,
141{
142 type EVM = EthEvmConfig;
143 type Executor = BasicBlockExecutorProvider<EthExecutionStrategyFactory>;
144
145 async fn build_evm(
146 self,
147 ctx: &BuilderContext<Node>,
148 ) -> eyre::Result<(Self::EVM, Self::Executor)> {
149 let chain_spec = ctx.chain_spec();
150 let enclave_args = ctx.config().enclave;
151 let evm_config = EthEvmConfig::new_with_enclave_addr_port(
152 ctx.chain_spec(),
153 enclave_args.enclave_server_addr,
154 enclave_args.enclave_server_port,
155 enclave_args.enclave_timeout,
156 );
157 let strategy_factory = EthExecutionStrategyFactory::new(chain_spec, evm_config.clone());
158 let executor = BasicBlockExecutorProvider::new(strategy_factory);
159
160 Ok((evm_config, executor))
161 }
162}
163
164#[derive(Debug, Default, Clone, Copy)]
169#[non_exhaustive]
170pub struct EthereumPoolBuilder {
171 }
173
174impl<Types, Node> PoolBuilder<Node> for EthereumPoolBuilder
175where
176 Types: NodeTypesWithEngine<ChainSpec = ChainSpec, Primitives = EthPrimitives>,
177 Node: FullNodeTypes<Types = Types>,
178{
179 type Pool = EthTransactionPool<Node::Provider, DiskFileBlobStore>;
180
181 async fn build_pool(self, ctx: &BuilderContext<Node>) -> eyre::Result<Self::Pool> {
182 let data_dir = ctx.config().datadir();
183 let pool_config = ctx.pool_config();
184 let blob_store = DiskFileBlobStore::open(data_dir.blobstore(), Default::default())?;
185 let validator = TransactionValidationTaskExecutor::eth_builder(ctx.chain_spec())
186 .with_head_timestamp(ctx.head().timestamp)
187 .kzg_settings(ctx.kzg_settings()?)
188 .with_local_transactions_config(pool_config.local_transactions_config.clone())
189 .with_additional_tasks(ctx.config().txpool.additional_validation_tasks)
190 .build_with_tasks(
191 ctx.provider().clone(),
192 ctx.task_executor().clone(),
193 blob_store.clone(),
194 );
195
196 let transaction_pool =
197 reth_transaction_pool::Pool::eth_pool(validator, blob_store, pool_config);
198 info!(target: "reth::cli", "Transaction pool initialized");
199 let transactions_path = data_dir.txpool_transactions();
200
201 {
203 let pool = transaction_pool.clone();
204 let chain_events = ctx.provider().canonical_state_stream();
205 let client = ctx.provider().clone();
206 let transactions_backup_config =
207 reth_transaction_pool::maintain::LocalTransactionBackupConfig::with_local_txs_backup(transactions_path);
208
209 ctx.task_executor().spawn_critical_with_graceful_shutdown_signal(
210 "local transactions backup task",
211 |shutdown| {
212 reth_transaction_pool::maintain::backup_local_transactions_task(
213 shutdown,
214 pool.clone(),
215 transactions_backup_config,
216 )
217 },
218 );
219
220 ctx.task_executor().spawn_critical(
222 "txpool maintenance task",
223 reth_transaction_pool::maintain::maintain_transaction_pool_future(
224 client,
225 pool,
226 chain_events,
227 ctx.task_executor().clone(),
228 Default::default(),
229 ),
230 );
231 debug!(target: "reth::cli", "Spawned txpool maintenance task");
232 }
233
234 Ok(transaction_pool)
235 }
236}
237
238#[derive(Clone, Debug)]
240pub struct EthereumPayloadBuilder {
241 config: EthereumBuilderConfig,
243}
244
245impl Default for EthereumPayloadBuilder {
246 fn default() -> Self {
247 Self { config: EthereumBuilderConfig::new(default_extra_data_bytes()) }
248 }
249}
250
251impl EthereumPayloadBuilder {
252 pub const fn new(config: EthereumBuilderConfig) -> Self {
254 Self { config }
255 }
256}
257
258impl EthereumPayloadBuilder {
259 pub fn spawn<Types, Node, Evm, Pool>(
261 self,
262 evm_config: Evm,
263 ctx: &BuilderContext<Node>,
264 pool: Pool,
265 ) -> eyre::Result<PayloadBuilderHandle<Types::Engine>>
266 where
267 Types: NodeTypesWithEngine<ChainSpec = ChainSpec, Primitives = EthPrimitives>,
268 Node: FullNodeTypes<Types = Types>,
269 Evm: ConfigureEvm<Header = HeaderTy<Types>, Transaction = TxTy<Node::Types>>,
270 Pool: TransactionPool<Transaction: PoolTransaction<Consensus = TxTy<Node::Types>>>
271 + Unpin
272 + 'static,
273 Types::Engine: PayloadTypes<
274 BuiltPayload = EthBuiltPayload,
275 PayloadAttributes = EthPayloadAttributes,
276 PayloadBuilderAttributes = EthPayloadBuilderAttributes,
277 >,
278 {
279 let payload_builder =
280 reth_ethereum_payload_builder::EthereumPayloadBuilder::new(evm_config, self.config);
281 let conf = ctx.payload_builder_config();
282
283 let payload_job_config = BasicPayloadJobGeneratorConfig::default()
284 .interval(conf.interval())
285 .deadline(conf.deadline())
286 .max_payload_tasks(conf.max_payload_tasks())
287 .extradata(conf.extradata_bytes());
288
289 let payload_generator = BasicPayloadJobGenerator::with_builder(
290 ctx.provider().clone(),
291 pool,
292 ctx.task_executor().clone(),
293 payload_job_config,
294 payload_builder,
295 );
296 let (payload_service, payload_builder) =
297 PayloadBuilderService::new(payload_generator, ctx.provider().canonical_state_stream());
298
299 ctx.task_executor().spawn_critical("payload builder service", Box::pin(payload_service));
300
301 Ok(payload_builder)
302 }
303}
304
305impl<Types, Node, Pool> PayloadServiceBuilder<Node, Pool> for EthereumPayloadBuilder
306where
307 Types: NodeTypesWithEngine<ChainSpec = ChainSpec, Primitives = EthPrimitives>,
308 Node: FullNodeTypes<Types = Types>,
309 Pool: TransactionPool<Transaction: PoolTransaction<Consensus = TxTy<Node::Types>>>
310 + Unpin
311 + 'static,
312 Types::Engine: PayloadTypes<
313 BuiltPayload = EthBuiltPayload,
314 PayloadAttributes = EthPayloadAttributes,
315 PayloadBuilderAttributes = EthPayloadBuilderAttributes,
316 >,
317{
318 async fn spawn_payload_service(
319 self,
320 ctx: &BuilderContext<Node>,
321 pool: Pool,
322 ) -> eyre::Result<PayloadBuilderHandle<Types::Engine>> {
323 let enclave_args = ctx.config().enclave;
324 self.spawn(
325 EthEvmConfig::new_with_enclave_addr_port(
326 ctx.chain_spec(),
327 enclave_args.enclave_server_addr,
328 enclave_args.enclave_server_port,
329 enclave_args.enclave_timeout,
330 ),
331 ctx,
332 pool,
333 )
334 }
335}
336
337#[derive(Debug, Default, Clone, Copy)]
339pub struct EthereumNetworkBuilder {
340 }
342
343impl<Node, Pool> NetworkBuilder<Node, Pool> for EthereumNetworkBuilder
344where
345 Node: FullNodeTypes<Types: NodeTypes<ChainSpec = ChainSpec, Primitives = EthPrimitives>>,
346 Pool: TransactionPool<
347 Transaction: PoolTransaction<
348 Consensus = TxTy<Node::Types>,
349 Pooled = PooledTransactionsElement,
350 >,
351 > + Unpin
352 + 'static,
353{
354 type Primitives = EthNetworkPrimitives;
355
356 async fn build_network(
357 self,
358 ctx: &BuilderContext<Node>,
359 pool: Pool,
360 ) -> eyre::Result<NetworkHandle> {
361 let network = ctx.network_builder().await?;
362 let handle = ctx.start_network(network, pool);
363 info!(target: "reth::cli", enode=%handle.local_node_record(), "P2P networking initialized");
364 Ok(handle)
365 }
366}
367
368#[derive(Debug, Default, Clone, Copy)]
370pub struct EthereumConsensusBuilder {
371 }
373
374impl<Node> ConsensusBuilder<Node> for EthereumConsensusBuilder
375where
376 Node: FullNodeTypes<Types: NodeTypes<ChainSpec = ChainSpec, Primitives = EthPrimitives>>,
377{
378 type Consensus = Arc<dyn reth_consensus::FullConsensus>;
379
380 async fn build_consensus(self, ctx: &BuilderContext<Node>) -> eyre::Result<Self::Consensus> {
381 Ok(Arc::new(EthBeaconConsensus::new(ctx.chain_spec())))
382 }
383}
384
385#[derive(Debug, Default, Clone)]
387#[non_exhaustive]
388pub struct EthereumEngineValidatorBuilder;
389
390impl<Node, Types> EngineValidatorBuilder<Node> for EthereumEngineValidatorBuilder
391where
392 Types: NodeTypesWithEngine<
393 ChainSpec = ChainSpec,
394 Engine = EthEngineTypes,
395 Primitives = EthPrimitives,
396 >,
397 Node: FullNodeComponents<Types = Types>,
398{
399 type Validator = EthereumEngineValidator;
400
401 async fn build(self, ctx: &AddOnsContext<'_, Node>) -> eyre::Result<Self::Validator> {
402 Ok(EthereumEngineValidator::new(ctx.config.chain.clone()))
403 }
404}