reth_optimism_node/
rpc.rs

1//! RPC component builder
2//!
3//! # Example
4//!
5//! Builds offline `TraceApi` with only EVM and database. This can be useful
6//! for example when downloading a state snapshot (pre-synced node) from some mirror.
7//!
8//! ```rust
9//! use alloy_rpc_types_eth::BlockId;
10//! use op_alloy_network::Optimism;
11//! use reth_db::test_utils::create_test_rw_db_with_path;
12//! use reth_node_builder::{
13//!     components::ComponentsBuilder,
14//!     hooks::OnComponentInitializedHook,
15//!     rpc::{EthApiBuilder, EthApiCtx},
16//!     LaunchContext, NodeConfig, RethFullAdapter,
17//! };
18//! use reth_optimism_chainspec::OP_SEPOLIA;
19//! use reth_optimism_evm::OpEvmConfig;
20//! use reth_optimism_node::{OpExecutorBuilder, OpNetworkPrimitives, OpNode};
21//! use reth_optimism_rpc::OpEthApiBuilder;
22//! use reth_optimism_txpool::OpPooledTransaction;
23//! use reth_provider::providers::BlockchainProvider;
24//! use reth_rpc::TraceApi;
25//! use reth_rpc_eth_types::{EthConfig, EthStateCache};
26//! use reth_tasks::{pool::BlockingTaskGuard, TaskManager};
27//! use std::sync::Arc;
28//!
29//! #[tokio::main]
30//! async fn main() {
31//!     // build core node with all components disabled except EVM and state
32//!     let sepolia = NodeConfig::new(OP_SEPOLIA.clone());
33//!     let db = create_test_rw_db_with_path(sepolia.datadir());
34//!     let tasks = TaskManager::current();
35//!     let launch_ctx = LaunchContext::new(tasks.executor(), sepolia.datadir());
36//!     let node = launch_ctx
37//!         .with_loaded_toml_config(sepolia)
38//!         .unwrap()
39//!         .attach(Arc::new(db))
40//!         .with_provider_factory::<_, OpEvmConfig>()
41//!         .await
42//!         .unwrap()
43//!         .with_genesis()
44//!         .unwrap()
45//!         .with_metrics_task() // todo: shouldn't be req to set up blockchain db
46//!         .with_blockchain_db::<RethFullAdapter<_, OpNode>, _>(move |provider_factory| {
47//!             Ok(BlockchainProvider::new(provider_factory).unwrap())
48//!         })
49//!         .unwrap()
50//!         .with_components(
51//!             ComponentsBuilder::default()
52//!                 .node_types::<RethFullAdapter<_, OpNode>>()
53//!                 .noop_pool::<OpPooledTransaction>()
54//!                 .noop_network::<OpNetworkPrimitives>()
55//!                 .noop_consensus()
56//!                 .executor(OpExecutorBuilder::default())
57//!                 .noop_payload(),
58//!             Box::new(()) as Box<dyn OnComponentInitializedHook<_>>,
59//!         )
60//!         .await
61//!         .unwrap();
62//!
63//!     // build `eth` namespace API
64//!     let config = EthConfig::default();
65//!     let cache = EthStateCache::spawn_with(
66//!         node.provider_factory().clone(),
67//!         config.cache,
68//!         node.task_executor().clone(),
69//!     );
70//!     let ctx = EthApiCtx { components: node.node_adapter(), config, cache };
71//!     let eth_api = OpEthApiBuilder::<Optimism>::default().build_eth_api(ctx).await.unwrap();
72//!
73//!     // build `trace` namespace API
74//!     let trace_api = TraceApi::new(eth_api, BlockingTaskGuard::new(10), EthConfig::default());
75//!
76//!     // fetch traces for latest block
77//!     let traces = trace_api.trace_block(BlockId::latest()).await.unwrap();
78//! }
79//! ```
80
81pub use reth_optimism_rpc::{OpEngineApi, OpEthApi, OpEthApiBuilder};
82
83use crate::OP_NAME_CLIENT;
84use alloy_rpc_types_engine::ClientVersionV1;
85use op_alloy_rpc_types_engine::OpExecutionData;
86use reth_chainspec::EthereumHardforks;
87use reth_node_api::{
88    AddOnsContext, EngineApiValidator, EngineTypes, FullNodeComponents, NodeTypes,
89};
90use reth_node_builder::rpc::{EngineApiBuilder, PayloadValidatorBuilder};
91use reth_node_core::version::{version_metadata, CLIENT_CODE};
92use reth_optimism_rpc::engine::OP_ENGINE_CAPABILITIES;
93use reth_payload_builder::PayloadStore;
94use reth_rpc_engine_api::{EngineApi, EngineCapabilities};
95
96/// Builder for basic [`OpEngineApi`] implementation.
97#[derive(Debug, Default, Clone)]
98pub struct OpEngineApiBuilder<EV> {
99    engine_validator_builder: EV,
100}
101
102impl<N, EV> EngineApiBuilder<N> for OpEngineApiBuilder<EV>
103where
104    N: FullNodeComponents<
105        Types: NodeTypes<
106            ChainSpec: EthereumHardforks,
107            Payload: EngineTypes<ExecutionData = OpExecutionData>,
108        >,
109    >,
110    EV: PayloadValidatorBuilder<N>,
111    EV::Validator: EngineApiValidator<<N::Types as NodeTypes>::Payload>,
112{
113    type EngineApi = OpEngineApi<
114        N::Provider,
115        <N::Types as NodeTypes>::Payload,
116        N::Pool,
117        EV::Validator,
118        <N::Types as NodeTypes>::ChainSpec,
119    >;
120
121    async fn build_engine_api(self, ctx: &AddOnsContext<'_, N>) -> eyre::Result<Self::EngineApi> {
122        let Self { engine_validator_builder } = self;
123
124        let engine_validator = engine_validator_builder.build(ctx).await?;
125        let client = ClientVersionV1 {
126            code: CLIENT_CODE,
127            name: OP_NAME_CLIENT.to_string(),
128            version: version_metadata().cargo_pkg_version.to_string(),
129            commit: version_metadata().vergen_git_sha.to_string(),
130        };
131        let inner = EngineApi::new(
132            ctx.node.provider().clone(),
133            ctx.config.chain.clone(),
134            ctx.beacon_engine_handle.clone(),
135            PayloadStore::new(ctx.node.payload_builder_handle().clone()),
136            ctx.node.pool().clone(),
137            Box::new(ctx.node.task_executor().clone()),
138            client,
139            EngineCapabilities::new(OP_ENGINE_CAPABILITIES.iter().copied()),
140            engine_validator,
141            ctx.config.engine.accept_execution_requests_hash,
142        );
143
144        Ok(OpEngineApi::new(inner))
145    }
146}