arb_node/
lib.rs

1//! Arbitrum node builder.
2//!
3//! Provides the node type definition and component builders
4//! needed to launch an Arbitrum reth node.
5
6pub mod addons;
7pub mod args;
8pub mod chainspec;
9pub mod coalesced_state;
10pub mod consensus;
11pub mod engine;
12pub mod error;
13pub mod genesis;
14pub mod launcher;
15pub mod network;
16pub mod payload;
17pub mod pool;
18pub mod producer;
19pub mod validator;
20
21use std::sync::Arc;
22
23use alloy_consensus::Header;
24use arb_evm::ArbEvmConfig;
25use arb_payload::ArbEngineTypes;
26use arb_primitives::{ArbPrimitives, ArbTransactionSigned};
27use arb_rpc::{
28    ArbApiHandler, ArbApiServer, ArbEthApiBuilder, NitroExecutionApiServer, NitroExecutionHandler,
29    stylus_debug::{StylusDebugHandler, StylusDebugServer},
30};
31pub use error::{GenesisError, LauncherError};
32use reth_chain_state::CanonicalInMemoryState;
33use reth_chainspec::ChainSpec;
34use reth_node_builder::{
35    BuilderContext, FullNodeComponents, FullNodeTypes, Node, NodeAdapter, NodeTypes,
36    components::{ComponentsBuilder, ConsensusBuilder, ExecutorBuilder},
37    rpc::{BasicEngineApiBuilder, BasicEngineValidatorBuilder, RpcAddOns, RpcContext},
38};
39use reth_provider::{BlockNumReader, BlockReaderIdExt, HeaderProvider, StateProviderFactory};
40use reth_storage_api::{CanonChainTracker, EthStorage};
41
42use crate::{
43    addons::ArbPayloadValidatorBuilder,
44    args::RollupArgs,
45    consensus::ArbConsensus,
46    network::ArbNetworkBuilder,
47    payload::ArbPayloadServiceBuilder,
48    pool::ArbPoolBuilder,
49    producer::{ArbBlockProducer, InMemoryStateAccess},
50};
51
52/// Arbitrum RPC add-ons type alias.
53pub type ArbAddOns<N> = RpcAddOns<
54    N,
55    ArbEthApiBuilder,
56    ArbPayloadValidatorBuilder,
57    BasicEngineApiBuilder<ArbPayloadValidatorBuilder>,
58    BasicEngineValidatorBuilder<ArbPayloadValidatorBuilder>,
59>;
60
61/// Arbitrum storage type.
62pub type ArbStorage = EthStorage<ArbTransactionSigned>;
63
64/// Arbitrum node configuration.
65#[derive(Debug, Clone, Default)]
66pub struct ArbNode {
67    /// Rollup CLI arguments.
68    pub args: RollupArgs,
69}
70
71impl ArbNode {
72    /// Create a new Arbitrum node configuration.
73    pub fn new(args: RollupArgs) -> Self {
74        Self { args }
75    }
76
77    /// Returns a [`ComponentsBuilder`] configured for Arbitrum.
78    pub fn components<N>() -> ComponentsBuilder<
79        N,
80        ArbPoolBuilder,
81        ArbPayloadServiceBuilder,
82        ArbNetworkBuilder,
83        ArbExecutorBuilder,
84        ArbConsensusBuilder,
85    >
86    where
87        N: FullNodeTypes<Types: NodeTypes<ChainSpec = ChainSpec, Primitives = ArbPrimitives>>,
88    {
89        ComponentsBuilder::default()
90            .node_types::<N>()
91            .pool(ArbPoolBuilder)
92            .executor(ArbExecutorBuilder)
93            .payload(ArbPayloadServiceBuilder)
94            .network(ArbNetworkBuilder)
95            .consensus(ArbConsensusBuilder)
96    }
97}
98
99impl NodeTypes for ArbNode {
100    type Primitives = ArbPrimitives;
101    type ChainSpec = ChainSpec;
102    type Storage = ArbStorage;
103    type Payload = ArbEngineTypes;
104}
105
106impl<N> Node<N> for ArbNode
107where
108    N: FullNodeTypes<Types = Self>,
109    N::Provider:
110        CanonChainTracker<Header = Header> + InMemoryStateAccess<Primitives = ArbPrimitives>,
111{
112    type ComponentsBuilder = ComponentsBuilder<
113        N,
114        ArbPoolBuilder,
115        ArbPayloadServiceBuilder,
116        ArbNetworkBuilder,
117        ArbExecutorBuilder,
118        ArbConsensusBuilder,
119    >;
120
121    type AddOns =
122        ArbAddOns<
123            NodeAdapter<
124                N,
125                <Self::ComponentsBuilder as reth_node_builder::components::NodeComponentsBuilder<
126                    N,
127                >>::Components,
128            >,
129        >;
130
131    fn components_builder(&self) -> Self::ComponentsBuilder {
132        Self::components()
133    }
134
135    fn add_ons(&self) -> Self::AddOns {
136        RpcAddOns::new(
137            ArbEthApiBuilder::default(),
138            ArbPayloadValidatorBuilder,
139            BasicEngineApiBuilder::default(),
140            BasicEngineValidatorBuilder::default(),
141            Default::default(),
142        )
143        .extend_rpc_modules(register_arb_rpc)
144    }
145}
146
147/// EVM config and consensus for reth's offline commands (`re-execute`,
148/// `import`, `stage`), so they run the node's ArbOS logic, not stock Ethereum.
149pub fn cli_components(chain_spec: Arc<ChainSpec>) -> (ArbEvmConfig, Arc<ArbConsensus<ChainSpec>>) {
150    let allow_debug = chainspec::allow_debug_precompiles(&chain_spec);
151    (
152        ArbEvmConfig::for_offline_execution(chain_spec.clone(), allow_debug),
153        Arc::new(ArbConsensus::new_verifying(chain_spec)),
154    )
155}
156
157/// Builder for the Arbitrum EVM executor component.
158#[derive(Debug, Default, Clone, Copy)]
159pub struct ArbExecutorBuilder;
160
161impl<N> ExecutorBuilder<N> for ArbExecutorBuilder
162where
163    N: FullNodeTypes<Types: NodeTypes<ChainSpec = ChainSpec, Primitives = ArbPrimitives>>,
164{
165    type EVM = ArbEvmConfig;
166
167    async fn build_evm(self, ctx: &BuilderContext<N>) -> eyre::Result<Self::EVM> {
168        let chain_spec = ctx.chain_spec();
169        let allow_debug = chainspec::allow_debug_precompiles(&chain_spec);
170        Ok(ArbEvmConfig::with_allow_debug_precompiles(
171            chain_spec,
172            allow_debug,
173        ))
174    }
175}
176
177/// Registers the `arb_` and `nitroexecution_` RPC namespaces.
178fn register_arb_rpc<N, EthApi>(ctx: RpcContext<'_, N, EthApi>) -> eyre::Result<()>
179where
180    N: FullNodeComponents<
181            Types: NodeTypes<ChainSpec = ChainSpec, Primitives = ArbPrimitives>,
182            Provider: BlockNumReader
183                          + BlockReaderIdExt
184                          + HeaderProvider
185                          + StateProviderFactory
186                          + InMemoryStateAccess<Primitives = ArbPrimitives>
187                          + CanonChainTracker<Header = Header>,
188        >,
189    EthApi: reth_rpc_eth_api::FullEthApiTypes
190        + reth_rpc_eth_api::helpers::TraceExt
191        + Clone
192        + Send
193        + Sync
194        + 'static,
195{
196    let arb_api = ArbApiHandler::new(ctx.provider().clone());
197    ctx.modules.merge_configured(arb_api.into_rpc())?;
198
199    // Override debug_traceTransaction so the `stylusTracer` named
200    // option returns the cached host-I/O records; everything else
201    // forwards to the standard handler.
202    {
203        let debug_api = ctx.registry.debug_api();
204        let forwarder: arb_rpc::stylus_debug::DebugForwarder =
205            std::sync::Arc::new(move |tx_hash, opts| {
206                let api = debug_api.clone();
207                Box::pin(async move {
208                    api.debug_trace_transaction(tx_hash, opts.unwrap_or_default())
209                        .await
210                        .map_err(Into::into)
211                })
212            });
213        let stylus_debug = StylusDebugHandler::new(forwarder);
214        ctx.modules
215            .add_or_replace_configured(stylus_debug.into_rpc())?;
216    }
217
218    let chain_spec: Arc<ChainSpec> = ctx.config().chain.clone();
219    let allow_debug = chainspec::allow_debug_precompiles(&chain_spec);
220    let evm_config = ArbEvmConfig::with_allow_debug_precompiles(chain_spec.clone(), allow_debug);
221
222    let in_memory_state: CanonicalInMemoryState<ArbPrimitives> =
223        ctx.provider().canonical_in_memory_state();
224
225    let genesis_block_num = chain_spec.genesis_header().number;
226
227    let flush_interval = std::env::var("ARB_FLUSH_INTERVAL")
228        .ok()
229        .and_then(|v| v.parse().ok())
230        .unwrap_or(producer::DEFAULT_FLUSH_INTERVAL);
231
232    let block_producer = Arc::new(ArbBlockProducer::new(
233        ctx.provider().clone(),
234        chain_spec,
235        evm_config,
236        in_memory_state,
237        flush_interval,
238    ));
239
240    let nitro_exec =
241        NitroExecutionHandler::new(ctx.provider().clone(), block_producer, genesis_block_num);
242    let nitro_rpc = nitro_exec.into_rpc();
243    ctx.modules.merge_configured(nitro_rpc.clone())?;
244    ctx.auth_module.merge_auth_methods(nitro_rpc)?;
245
246    Ok(())
247}
248
249/// Builder for the Arbitrum consensus component.
250#[derive(Debug, Default, Clone, Copy)]
251pub struct ArbConsensusBuilder;
252
253impl<N> ConsensusBuilder<N> for ArbConsensusBuilder
254where
255    N: FullNodeTypes<Types: NodeTypes<ChainSpec = ChainSpec, Primitives = ArbPrimitives>>,
256{
257    type Consensus = Arc<ArbConsensus<ChainSpec>>;
258
259    async fn build_consensus(self, ctx: &BuilderContext<N>) -> eyre::Result<Self::Consensus> {
260        Ok(Arc::new(ArbConsensus::new(ctx.chain_spec())))
261    }
262}