1use crate::{
4 args::RollupArgs,
5 engine::OpEngineValidator,
6 txpool::{OpTransactionPool, OpTransactionValidator},
7 OpEngineApiBuilder, OpEngineTypes,
8};
9use op_alloy_consensus::{interop::SafetyLevel, OpPooledTransaction};
10use reth_chainspec::{EthChainSpec, Hardforks};
11use reth_evm::{execute::BasicBlockExecutorProvider, ConfigureEvm, EvmFactory, EvmFactoryFor};
12use reth_network::{NetworkConfig, NetworkHandle, NetworkManager, NetworkPrimitives, PeersInfo};
13use reth_node_api::{
14 AddOnsContext, FullNodeComponents, KeyHasherTy, NodeAddOns, NodePrimitives, PrimitivesTy, TxTy,
15};
16use reth_node_builder::{
17 components::{
18 BasicPayloadServiceBuilder, ComponentsBuilder, ConsensusBuilder, ExecutorBuilder,
19 NetworkBuilder, PayloadBuilderBuilder, PoolBuilder, PoolBuilderConfigOverrides,
20 },
21 node::{FullNodeTypes, NodeTypes},
22 rpc::{
23 EngineValidatorAddOn, EngineValidatorBuilder, EthApiBuilder, RethRpcAddOns, RpcAddOns,
24 RpcHandle,
25 },
26 BuilderContext, DebugNode, Node, NodeAdapter, NodeComponentsBuilder,
27};
28use reth_optimism_chainspec::OpChainSpec;
29use reth_optimism_consensus::OpBeaconConsensus;
30use reth_optimism_evm::{OpEvmConfig, OpNextBlockEnvAttributes};
31use reth_optimism_forks::OpHardforks;
32use reth_optimism_payload_builder::{
33 builder::OpPayloadTransactions,
34 config::{OpBuilderConfig, OpDAConfig},
35};
36use reth_optimism_primitives::{DepositReceipt, OpPrimitives, OpReceipt, OpTransactionSigned};
37use reth_optimism_rpc::{
38 eth::{ext::OpEthExtApi, OpEthApiBuilder},
39 miner::{MinerApiExtServer, OpMinerExtApi},
40 witness::{DebugExecutionWitnessApiServer, OpDebugWitnessApi},
41 OpEthApi, OpEthApiError, SequencerClient,
42};
43use reth_optimism_txpool::{
44 conditional::MaybeConditionalTransaction,
45 interop::MaybeInteropTransaction,
46 supervisor::{SupervisorClient, DEFAULT_SUPERVISOR_URL},
47 OpPooledTx,
48};
49use reth_provider::{providers::ProviderFactoryBuilder, CanonStateSubscriptions, EthStorage};
50use reth_rpc_api::DebugApiServer;
51use reth_rpc_eth_api::ext::L2EthApiExtServer;
52use reth_rpc_eth_types::error::FromEvmError;
53use reth_rpc_server_types::RethRpcModule;
54use reth_tracing::tracing::{debug, info};
55use reth_transaction_pool::{
56 blobstore::DiskFileBlobStore, CoinbaseTipOrdering, EthPoolTransaction, PoolTransaction,
57 TransactionPool, TransactionValidationTaskExecutor,
58};
59use reth_trie_db::MerklePatriciaTrie;
60use revm::context::TxEnv;
61use std::sync::Arc;
62
63pub type OpStorage = EthStorage<OpTransactionSigned>;
65
66#[derive(Debug, Default, Clone)]
68#[non_exhaustive]
69pub struct OpNode {
70 pub args: RollupArgs,
72 pub da_config: OpDAConfig,
79}
80
81impl OpNode {
82 pub fn new(args: RollupArgs) -> Self {
84 Self { args, da_config: OpDAConfig::default() }
85 }
86
87 pub fn with_da_config(mut self, da_config: OpDAConfig) -> Self {
89 self.da_config = da_config;
90 self
91 }
92
93 pub fn components<Node>(
95 &self,
96 ) -> ComponentsBuilder<
97 Node,
98 OpPoolBuilder,
99 BasicPayloadServiceBuilder<OpPayloadBuilder>,
100 OpNetworkBuilder,
101 OpExecutorBuilder,
102 OpConsensusBuilder,
103 >
104 where
105 Node: FullNodeTypes<
106 Types: NodeTypes<
107 Payload = OpEngineTypes,
108 ChainSpec = OpChainSpec,
109 Primitives = OpPrimitives,
110 >,
111 >,
112 {
113 let RollupArgs { disable_txpool_gossip, compute_pending_block, discovery_v4, .. } =
114 self.args;
115 ComponentsBuilder::default()
116 .node_types::<Node>()
117 .pool(
118 OpPoolBuilder::default()
119 .with_enable_tx_conditional(self.args.enable_tx_conditional)
120 .with_supervisor(
121 self.args.supervisor_http.clone(),
122 self.args.supervisor_safety_level,
123 ),
124 )
125 .payload(BasicPayloadServiceBuilder::new(
126 OpPayloadBuilder::new(compute_pending_block).with_da_config(self.da_config.clone()),
127 ))
128 .network(OpNetworkBuilder {
129 disable_txpool_gossip,
130 disable_discovery_v4: !discovery_v4,
131 })
132 .executor(OpExecutorBuilder::default())
133 .consensus(OpConsensusBuilder::default())
134 }
135
136 pub fn provider_factory_builder() -> ProviderFactoryBuilder<Self> {
167 ProviderFactoryBuilder::default()
168 }
169}
170
171impl<N> Node<N> for OpNode
172where
173 N: FullNodeTypes<
174 Types: NodeTypes<
175 Payload = OpEngineTypes,
176 ChainSpec = OpChainSpec,
177 Primitives = OpPrimitives,
178 Storage = OpStorage,
179 >,
180 >,
181{
182 type ComponentsBuilder = ComponentsBuilder<
183 N,
184 OpPoolBuilder,
185 BasicPayloadServiceBuilder<OpPayloadBuilder>,
186 OpNetworkBuilder,
187 OpExecutorBuilder,
188 OpConsensusBuilder,
189 >;
190
191 type AddOns =
192 OpAddOns<NodeAdapter<N, <Self::ComponentsBuilder as NodeComponentsBuilder<N>>::Components>>;
193
194 fn components_builder(&self) -> Self::ComponentsBuilder {
195 Self::components(self)
196 }
197
198 fn add_ons(&self) -> Self::AddOns {
199 Self::AddOns::builder()
200 .with_sequencer(self.args.sequencer.clone())
201 .with_da_config(self.da_config.clone())
202 .with_enable_tx_conditional(self.args.enable_tx_conditional)
203 .build()
204 }
205}
206
207impl<N> DebugNode<N> for OpNode
208where
209 N: FullNodeComponents<Types = Self>,
210{
211 type RpcBlock = alloy_rpc_types_eth::Block<op_alloy_consensus::OpTxEnvelope>;
212
213 fn rpc_to_primitive_block(rpc_block: Self::RpcBlock) -> reth_node_api::BlockTy<Self> {
214 let alloy_rpc_types_eth::Block { header, transactions, .. } = rpc_block;
215 reth_optimism_primitives::OpBlock {
216 header: header.inner,
217 body: reth_optimism_primitives::OpBlockBody {
218 transactions: transactions.into_transactions().collect(),
219 ..Default::default()
220 },
221 }
222 }
223}
224
225impl NodeTypes for OpNode {
226 type Primitives = OpPrimitives;
227 type ChainSpec = OpChainSpec;
228 type StateCommitment = MerklePatriciaTrie;
229 type Storage = OpStorage;
230 type Payload = OpEngineTypes;
231}
232
233#[derive(Debug)]
235pub struct OpAddOns<N>
236where
237 N: FullNodeComponents,
238 OpEthApiBuilder: EthApiBuilder<N>,
239{
240 pub rpc_add_ons: RpcAddOns<
243 N,
244 OpEthApiBuilder,
245 OpEngineValidatorBuilder,
246 OpEngineApiBuilder<OpEngineValidatorBuilder>,
247 >,
248 pub da_config: OpDAConfig,
250 pub sequencer_url: Option<String>,
253 enable_tx_conditional: bool,
255}
256
257impl<N> Default for OpAddOns<N>
258where
259 N: FullNodeComponents<Types: NodeTypes<Primitives = OpPrimitives>>,
260 OpEthApiBuilder: EthApiBuilder<N>,
261{
262 fn default() -> Self {
263 Self::builder().build()
264 }
265}
266
267impl<N> OpAddOns<N>
268where
269 N: FullNodeComponents<Types: NodeTypes<Primitives = OpPrimitives>>,
270 OpEthApiBuilder: EthApiBuilder<N>,
271{
272 pub fn builder() -> OpAddOnsBuilder {
274 OpAddOnsBuilder::default()
275 }
276}
277
278impl<N> NodeAddOns<N> for OpAddOns<N>
279where
280 N: FullNodeComponents<
281 Types: NodeTypes<
282 ChainSpec = OpChainSpec,
283 Primitives = OpPrimitives,
284 Storage = OpStorage,
285 Payload = OpEngineTypes,
286 >,
287 Evm: ConfigureEvm<NextBlockEnvCtx = OpNextBlockEnvAttributes>,
288 >,
289 OpEthApiError: FromEvmError<N::Evm>,
290 <N::Pool as TransactionPool>::Transaction: OpPooledTx,
291 EvmFactoryFor<N::Evm>: EvmFactory<Tx = op_revm::OpTransaction<TxEnv>>,
292{
293 type Handle = RpcHandle<N, OpEthApi<N>>;
294
295 async fn launch_add_ons(
296 self,
297 ctx: reth_node_api::AddOnsContext<'_, N>,
298 ) -> eyre::Result<Self::Handle> {
299 let Self { rpc_add_ons, da_config, sequencer_url, enable_tx_conditional } = self;
300
301 let builder = reth_optimism_payload_builder::OpPayloadBuilder::new(
302 ctx.node.pool().clone(),
303 ctx.node.provider().clone(),
304 ctx.node.evm_config().clone(),
305 );
306 let debug_ext = OpDebugWitnessApi::new(
308 ctx.node.provider().clone(),
309 Box::new(ctx.node.task_executor().clone()),
310 builder,
311 );
312 let miner_ext = OpMinerExtApi::new(da_config);
313
314 let sequencer_client = if let Some(url) = sequencer_url {
315 Some(SequencerClient::new(url).await?)
316 } else {
317 None
318 };
319
320 let tx_conditional_ext: OpEthExtApi<N::Pool, N::Provider> = OpEthExtApi::new(
321 sequencer_client,
322 ctx.node.pool().clone(),
323 ctx.node.provider().clone(),
324 );
325
326 rpc_add_ons
327 .launch_add_ons_with(ctx, move |modules, auth_modules, registry| {
328 debug!(target: "reth::cli", "Installing debug payload witness rpc endpoint");
329 modules.merge_if_module_configured(RethRpcModule::Debug, debug_ext.into_rpc())?;
330
331 modules.merge_if_module_configured(
333 RethRpcModule::Miner,
334 miner_ext.clone().into_rpc(),
335 )?;
336
337 if modules.module_config().contains_any(&RethRpcModule::Miner) {
339 debug!(target: "reth::cli", "Installing miner DA rpc endpoint");
340 auth_modules.merge_auth_methods(miner_ext.into_rpc())?;
341 }
342
343 if modules.module_config().contains_any(&RethRpcModule::Debug) {
345 debug!(target: "reth::cli", "Installing debug rpc endpoint");
346 auth_modules.merge_auth_methods(registry.debug_api().into_rpc())?;
347 }
348
349 if enable_tx_conditional {
350 modules.merge_if_module_configured(
352 RethRpcModule::Eth,
353 tx_conditional_ext.into_rpc(),
354 )?;
355 }
356
357 Ok(())
358 })
359 .await
360 }
361}
362
363impl<N> RethRpcAddOns<N> for OpAddOns<N>
364where
365 N: FullNodeComponents<
366 Types: NodeTypes<
367 ChainSpec = OpChainSpec,
368 Primitives = OpPrimitives,
369 Storage = OpStorage,
370 Payload = OpEngineTypes,
371 >,
372 Evm: ConfigureEvm<NextBlockEnvCtx = OpNextBlockEnvAttributes>,
373 >,
374 OpEthApiError: FromEvmError<N::Evm>,
375 <<N as FullNodeComponents>::Pool as TransactionPool>::Transaction: OpPooledTx,
376 EvmFactoryFor<N::Evm>: EvmFactory<Tx = op_revm::OpTransaction<TxEnv>>,
377{
378 type EthApi = OpEthApi<N>;
379
380 fn hooks_mut(&mut self) -> &mut reth_node_builder::rpc::RpcHooks<N, Self::EthApi> {
381 self.rpc_add_ons.hooks_mut()
382 }
383}
384
385impl<N> EngineValidatorAddOn<N> for OpAddOns<N>
386where
387 N: FullNodeComponents<
388 Types: NodeTypes<
389 ChainSpec = OpChainSpec,
390 Primitives = OpPrimitives,
391 Payload = OpEngineTypes,
392 >,
393 >,
394 OpEthApiBuilder: EthApiBuilder<N>,
395{
396 type Validator = OpEngineValidator<N::Provider>;
397
398 async fn engine_validator(&self, ctx: &AddOnsContext<'_, N>) -> eyre::Result<Self::Validator> {
399 OpEngineValidatorBuilder::default().build(ctx).await
400 }
401}
402
403#[derive(Debug, Default, Clone)]
405#[non_exhaustive]
406pub struct OpAddOnsBuilder {
407 sequencer_url: Option<String>,
410 da_config: Option<OpDAConfig>,
412 enable_tx_conditional: bool,
414}
415
416impl OpAddOnsBuilder {
417 pub fn with_sequencer(mut self, sequencer_client: Option<String>) -> Self {
419 self.sequencer_url = sequencer_client;
420 self
421 }
422
423 pub fn with_da_config(mut self, da_config: OpDAConfig) -> Self {
425 self.da_config = Some(da_config);
426 self
427 }
428
429 pub const fn with_enable_tx_conditional(mut self, enable_tx_conditional: bool) -> Self {
431 self.enable_tx_conditional = enable_tx_conditional;
432 self
433 }
434}
435
436impl OpAddOnsBuilder {
437 pub fn build<N>(self) -> OpAddOns<N>
439 where
440 N: FullNodeComponents<Types: NodeTypes<Primitives = OpPrimitives>>,
441 OpEthApiBuilder: EthApiBuilder<N>,
442 {
443 let Self { sequencer_url, da_config, enable_tx_conditional } = self;
444
445 OpAddOns {
446 rpc_add_ons: RpcAddOns::new(
447 OpEthApiBuilder::default().with_sequencer(sequencer_url.clone()),
448 Default::default(),
449 Default::default(),
450 ),
451 da_config: da_config.unwrap_or_default(),
452 sequencer_url,
453 enable_tx_conditional,
454 }
455 }
456}
457
458#[derive(Debug, Default, Clone, Copy)]
460#[non_exhaustive]
461pub struct OpExecutorBuilder;
462
463impl<Node> ExecutorBuilder<Node> for OpExecutorBuilder
464where
465 Node: FullNodeTypes<Types: NodeTypes<ChainSpec = OpChainSpec, Primitives = OpPrimitives>>,
466{
467 type EVM = OpEvmConfig;
468 type Executor = BasicBlockExecutorProvider<Self::EVM>;
469
470 async fn build_evm(
471 self,
472 ctx: &BuilderContext<Node>,
473 ) -> eyre::Result<(Self::EVM, Self::Executor)> {
474 let evm_config = OpEvmConfig::optimism(ctx.chain_spec());
475 let executor = BasicBlockExecutorProvider::new(evm_config.clone());
476
477 Ok((evm_config, executor))
478 }
479}
480
481#[derive(Debug, Clone)]
486pub struct OpPoolBuilder<T = crate::txpool::OpPooledTransaction> {
487 pub pool_config_overrides: PoolBuilderConfigOverrides,
489 pub enable_tx_conditional: bool,
491 pub supervisor_http: String,
493 pub supervisor_safety_level: SafetyLevel,
495 _pd: core::marker::PhantomData<T>,
497}
498
499impl<T> Default for OpPoolBuilder<T> {
500 fn default() -> Self {
501 Self {
502 pool_config_overrides: Default::default(),
503 enable_tx_conditional: false,
504 supervisor_http: DEFAULT_SUPERVISOR_URL.to_string(),
505 supervisor_safety_level: SafetyLevel::CrossUnsafe,
506 _pd: Default::default(),
507 }
508 }
509}
510
511impl<T> OpPoolBuilder<T> {
512 pub const fn with_enable_tx_conditional(mut self, enable_tx_conditional: bool) -> Self {
514 self.enable_tx_conditional = enable_tx_conditional;
515 self
516 }
517
518 pub fn with_pool_config_overrides(
520 mut self,
521 pool_config_overrides: PoolBuilderConfigOverrides,
522 ) -> Self {
523 self.pool_config_overrides = pool_config_overrides;
524 self
525 }
526
527 pub fn with_supervisor(
529 mut self,
530 supervisor_client: String,
531 supervisor_safety_level: SafetyLevel,
532 ) -> Self {
533 self.supervisor_http = supervisor_client;
534 self.supervisor_safety_level = supervisor_safety_level;
535 self
536 }
537}
538
539impl<Node, T> PoolBuilder<Node> for OpPoolBuilder<T>
540where
541 Node: FullNodeTypes<Types: NodeTypes<ChainSpec: OpHardforks>>,
542 T: EthPoolTransaction<Consensus = TxTy<Node::Types>>
543 + MaybeConditionalTransaction
544 + MaybeInteropTransaction,
545{
546 type Pool = OpTransactionPool<Node::Provider, DiskFileBlobStore, T>;
547
548 async fn build_pool(self, ctx: &BuilderContext<Node>) -> eyre::Result<Self::Pool> {
549 let Self { pool_config_overrides, .. } = self;
550 let data_dir = ctx.config().datadir();
551 let blob_store = DiskFileBlobStore::open(data_dir.blobstore(), Default::default())?;
552 if ctx.chain_spec().is_interop_active_at_timestamp(ctx.head().timestamp) &&
554 self.supervisor_http == DEFAULT_SUPERVISOR_URL
555 {
556 info!(target: "reth::cli",
557 url=%DEFAULT_SUPERVISOR_URL,
558 "Default supervisor url is used, consider changing --rollup.supervisor-http."
559 );
560 }
561 let supervisor_client =
562 SupervisorClient::new(self.supervisor_http.clone(), self.supervisor_safety_level).await;
563
564 let validator = TransactionValidationTaskExecutor::eth_builder(ctx.provider().clone())
565 .no_eip4844()
566 .with_head_timestamp(ctx.head().timestamp)
567 .kzg_settings(ctx.kzg_settings()?)
568 .set_tx_fee_cap(ctx.config().rpc.rpc_tx_fee_cap)
569 .with_additional_tasks(
570 pool_config_overrides
571 .additional_validation_tasks
572 .unwrap_or_else(|| ctx.config().txpool.additional_validation_tasks),
573 )
574 .build_with_tasks(ctx.task_executor().clone(), blob_store.clone())
575 .map(|validator| {
576 OpTransactionValidator::new(validator)
577 .require_l1_data_gas_fee(!ctx.config().dev.dev)
580 .with_supervisor(supervisor_client.clone())
581 });
582
583 let transaction_pool = reth_transaction_pool::Pool::new(
584 validator,
585 CoinbaseTipOrdering::default(),
586 blob_store,
587 pool_config_overrides.apply(ctx.pool_config()),
588 );
589 info!(target: "reth::cli", "Transaction pool initialized");
590
591 {
593 let pool = transaction_pool.clone();
594 let chain_events = ctx.provider().canonical_state_stream();
595 let client = ctx.provider().clone();
596 if !ctx.config().txpool.disable_transactions_backup {
597 let transactions_path = ctx
599 .config()
600 .txpool
601 .transactions_backup_path
602 .clone()
603 .unwrap_or_else(|| data_dir.txpool_transactions());
604
605 let transactions_backup_config =
606 reth_transaction_pool::maintain::LocalTransactionBackupConfig::with_local_txs_backup(transactions_path);
607
608 ctx.task_executor().spawn_critical_with_graceful_shutdown_signal(
609 "local transactions backup task",
610 |shutdown| {
611 reth_transaction_pool::maintain::backup_local_transactions_task(
612 shutdown,
613 pool.clone(),
614 transactions_backup_config,
615 )
616 },
617 );
618 }
619
620 ctx.task_executor().spawn_critical(
622 "txpool maintenance task",
623 reth_transaction_pool::maintain::maintain_transaction_pool_future(
624 client,
625 pool.clone(),
626 chain_events,
627 ctx.task_executor().clone(),
628 reth_transaction_pool::maintain::MaintainPoolConfig {
629 max_tx_lifetime: pool.config().max_queued_lifetime,
630 no_local_exemptions: transaction_pool
631 .config()
632 .local_transactions_config
633 .no_exemptions,
634 ..Default::default()
635 },
636 ),
637 );
638 debug!(target: "reth::cli", "Spawned txpool maintenance task");
639
640 let chain_events = ctx.provider().canonical_state_stream();
642 ctx.task_executor().spawn_critical(
643 "Op txpool interop maintenance task",
644 reth_optimism_txpool::maintain::maintain_transaction_pool_interop_future(
645 pool.clone(),
646 chain_events,
647 supervisor_client,
648 ),
649 );
650 debug!(target: "reth::cli", "Spawned Op interop txpool maintenance task");
651
652 if self.enable_tx_conditional {
653 let chain_events = ctx.provider().canonical_state_stream();
655 ctx.task_executor().spawn_critical(
656 "Op txpool conditional maintenance task",
657 reth_optimism_txpool::maintain::maintain_transaction_pool_conditional_future(
658 pool,
659 chain_events,
660 ),
661 );
662 debug!(target: "reth::cli", "Spawned Op conditional txpool maintenance task");
663 }
664 }
665
666 Ok(transaction_pool)
667 }
668}
669
670#[derive(Debug, Default, Clone)]
672pub struct OpPayloadBuilder<Txs = ()> {
673 pub compute_pending_block: bool,
682 pub best_transactions: Txs,
685 pub da_config: OpDAConfig,
688}
689
690impl OpPayloadBuilder {
691 pub fn new(compute_pending_block: bool) -> Self {
694 Self { compute_pending_block, best_transactions: (), da_config: OpDAConfig::default() }
695 }
696
697 pub fn with_da_config(mut self, da_config: OpDAConfig) -> Self {
699 self.da_config = da_config;
700 self
701 }
702}
703
704impl<Txs> OpPayloadBuilder<Txs> {
705 pub fn with_transactions<T>(self, best_transactions: T) -> OpPayloadBuilder<T> {
708 let Self { compute_pending_block, da_config, .. } = self;
709 OpPayloadBuilder { compute_pending_block, best_transactions, da_config }
710 }
711
712 pub fn build<Node, Evm, Pool>(
715 self,
716 evm_config: Evm,
717 ctx: &BuilderContext<Node>,
718 pool: Pool,
719 ) -> eyre::Result<reth_optimism_payload_builder::OpPayloadBuilder<Pool, Node::Provider, Evm, Txs>>
720 where
721 Node: FullNodeTypes<
722 Types: NodeTypes<
723 Payload = OpEngineTypes,
724 ChainSpec = OpChainSpec,
725 Primitives = OpPrimitives,
726 >,
727 >,
728 Pool: TransactionPool<Transaction: PoolTransaction<Consensus = TxTy<Node::Types>>>
729 + Unpin
730 + 'static,
731 Evm: ConfigureEvm<Primitives = PrimitivesTy<Node::Types>>,
732 Txs: OpPayloadTransactions<Pool::Transaction>,
733 {
734 let payload_builder = reth_optimism_payload_builder::OpPayloadBuilder::with_builder_config(
735 pool,
736 ctx.provider().clone(),
737 evm_config,
738 OpBuilderConfig { da_config: self.da_config.clone() },
739 )
740 .with_transactions(self.best_transactions.clone())
741 .set_compute_pending_block(self.compute_pending_block);
742 Ok(payload_builder)
743 }
744}
745
746impl<Node, Pool, Txs> PayloadBuilderBuilder<Node, Pool> for OpPayloadBuilder<Txs>
747where
748 Node: FullNodeTypes<
749 Types: NodeTypes<
750 Payload = OpEngineTypes,
751 ChainSpec = OpChainSpec,
752 Primitives = OpPrimitives,
753 >,
754 >,
755 Pool: TransactionPool<Transaction: PoolTransaction<Consensus = TxTy<Node::Types>>>
756 + Unpin
757 + 'static,
758 Txs: OpPayloadTransactions<Pool::Transaction>,
759 <Pool as TransactionPool>::Transaction: OpPooledTx,
760{
761 type PayloadBuilder =
762 reth_optimism_payload_builder::OpPayloadBuilder<Pool, Node::Provider, OpEvmConfig, Txs>;
763
764 async fn build_payload_builder(
765 self,
766 ctx: &BuilderContext<Node>,
767 pool: Pool,
768 ) -> eyre::Result<Self::PayloadBuilder> {
769 self.build(OpEvmConfig::optimism(ctx.chain_spec()), ctx, pool)
770 }
771}
772
773#[derive(Debug, Default, Clone)]
775pub struct OpNetworkBuilder {
776 pub disable_txpool_gossip: bool,
778 pub disable_discovery_v4: bool,
780}
781
782impl OpNetworkBuilder {
783 pub fn network_config<Node>(
787 &self,
788 ctx: &BuilderContext<Node>,
789 ) -> eyre::Result<NetworkConfig<<Node as FullNodeTypes>::Provider, OpNetworkPrimitives>>
790 where
791 Node: FullNodeTypes<Types: NodeTypes<ChainSpec: Hardforks>>,
792 {
793 let Self { disable_txpool_gossip, disable_discovery_v4 } = self.clone();
794 let args = &ctx.config().network;
795 let network_builder = ctx
796 .network_config_builder()?
797 .apply(|mut builder| {
799 let rlpx_socket = (args.addr, args.port).into();
800 if disable_discovery_v4 || args.discovery.disable_discovery {
801 builder = builder.disable_discv4_discovery();
802 }
803 if !args.discovery.disable_discovery {
804 builder = builder.discovery_v5(
805 args.discovery.discovery_v5_builder(
806 rlpx_socket,
807 ctx.config()
808 .network
809 .resolved_bootnodes()
810 .or_else(|| ctx.chain_spec().bootnodes())
811 .unwrap_or_default(),
812 ),
813 );
814 }
815
816 builder
817 });
818
819 let mut network_config = ctx.build_network_config(network_builder);
820
821 network_config.tx_gossip_disabled = disable_txpool_gossip;
825
826 Ok(network_config)
827 }
828}
829
830impl<Node, Pool> NetworkBuilder<Node, Pool> for OpNetworkBuilder
831where
832 Node: FullNodeTypes<Types: NodeTypes<ChainSpec = OpChainSpec, Primitives = OpPrimitives>>,
833 Pool: TransactionPool<
834 Transaction: PoolTransaction<
835 Consensus = TxTy<Node::Types>,
836 Pooled = OpPooledTransaction,
837 >,
838 > + Unpin
839 + 'static,
840{
841 type Primitives = OpNetworkPrimitives;
842
843 async fn build_network(
844 self,
845 ctx: &BuilderContext<Node>,
846 pool: Pool,
847 ) -> eyre::Result<NetworkHandle<Self::Primitives>> {
848 let network_config = self.network_config(ctx)?;
849 let network = NetworkManager::builder(network_config).await?;
850 let handle = ctx.start_network(network, pool);
851 info!(target: "reth::cli", enode=%handle.local_node_record(), "P2P networking initialized");
852
853 Ok(handle)
854 }
855}
856
857#[derive(Debug, Default, Clone)]
859#[non_exhaustive]
860pub struct OpConsensusBuilder;
861
862impl<Node> ConsensusBuilder<Node> for OpConsensusBuilder
863where
864 Node: FullNodeTypes<
865 Types: NodeTypes<
866 ChainSpec: OpHardforks,
867 Primitives: NodePrimitives<Receipt: DepositReceipt>,
868 >,
869 >,
870{
871 type Consensus = Arc<OpBeaconConsensus<<Node::Types as NodeTypes>::ChainSpec>>;
872
873 async fn build_consensus(self, ctx: &BuilderContext<Node>) -> eyre::Result<Self::Consensus> {
874 Ok(Arc::new(OpBeaconConsensus::new(ctx.chain_spec())))
875 }
876}
877
878#[derive(Debug, Default, Clone)]
880#[non_exhaustive]
881pub struct OpEngineValidatorBuilder;
882
883impl<Node, Types> EngineValidatorBuilder<Node> for OpEngineValidatorBuilder
884where
885 Types: NodeTypes<ChainSpec = OpChainSpec, Primitives = OpPrimitives, Payload = OpEngineTypes>,
886 Node: FullNodeComponents<Types = Types>,
887{
888 type Validator = OpEngineValidator<Node::Provider>;
889
890 async fn build(self, ctx: &AddOnsContext<'_, Node>) -> eyre::Result<Self::Validator> {
891 Ok(OpEngineValidator::new::<KeyHasherTy<Types>>(
892 ctx.config.chain.clone(),
893 ctx.node.provider().clone(),
894 ))
895 }
896}
897
898#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
900#[non_exhaustive]
901pub struct OpNetworkPrimitives;
902
903impl NetworkPrimitives for OpNetworkPrimitives {
904 type BlockHeader = alloy_consensus::Header;
905 type BlockBody = alloy_consensus::BlockBody<OpTransactionSigned>;
906 type Block = alloy_consensus::Block<OpTransactionSigned>;
907 type BroadcastedTransaction = OpTransactionSigned;
908 type PooledTransaction = OpPooledTransaction;
909 type Receipt = OpReceipt;
910}