diff --git a/Cargo.lock b/Cargo.lock index a5344b812e..b174a1c7f3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4245,6 +4245,7 @@ dependencies = [ "eyre", "fdlimit", "futures", + "jsonrpsee", "metrics", "metrics-exporter-prometheus", "metrics-util", diff --git a/bin/reth/Cargo.toml b/bin/reth/Cargo.toml index d4a91404d4..84bca20202 100644 --- a/bin/reth/Cargo.toml +++ b/bin/reth/Cargo.toml @@ -61,4 +61,5 @@ tempfile = { version = "3.3.0" } backon = "0.2.0" comfy-table = "6.1.4" crossterm = "0.25.0" -tui = "0.19.0" \ No newline at end of file +tui = "0.19.0" +jsonrpsee = { version = "0.16", features = ["server"] } \ No newline at end of file diff --git a/bin/reth/src/args/rpc_server_args.rs b/bin/reth/src/args/rpc_server_args.rs index 9017b82569..2d19f3f3b5 100644 --- a/bin/reth/src/args/rpc_server_args.rs +++ b/bin/reth/src/args/rpc_server_args.rs @@ -2,9 +2,19 @@ use crate::dirs::{JwtSecretPath, PlatformPath}; use clap::Args; +use jsonrpsee::core::Error as RpcError; +use reth_network_api::{NetworkInfo, Peers}; +use reth_provider::{BlockProvider, HeaderProvider, StateProviderFactory}; use reth_rpc::{JwtError, JwtSecret}; -use reth_rpc_builder::RpcModuleSelection; -use std::{net::IpAddr, path::Path}; +use reth_rpc_builder::{ + IpcServerBuilder, RethRpcModule, RpcModuleSelection, RpcServerConfig, RpcServerHandle, + ServerBuilder, TransportRpcModuleConfig, DEFAULT_HTTP_RPC_PORT, DEFAULT_IPC_ENDPOINT, +}; +use reth_transaction_pool::TransactionPool; +use std::{ + net::{IpAddr, Ipv4Addr, SocketAddr}, + path::Path, +}; /// Parameters for configuring the rpc more granularity via CLI #[derive(Debug, Args, PartialEq, Default)] @@ -78,10 +88,80 @@ impl RpcServerArgs { } } } + + /// Convenience function for starting a rpc server with configs which extracted from cli args. + pub(crate) async fn start_server( + &self, + client: Client, + pool: Pool, + network: Network, + ) -> Result + where + Client: BlockProvider + HeaderProvider + StateProviderFactory + Clone + 'static, + Pool: TransactionPool + Clone + 'static, + Network: NetworkInfo + Peers + Clone + 'static, + { + reth_rpc_builder::launch( + client, + pool, + network, + self.transport_rpc_module_config(), + self.rpc_server_config(), + ) + .await + } + + /// Creates the [TransportRpcModuleConfig] from cli args. + fn transport_rpc_module_config(&self) -> TransportRpcModuleConfig { + let mut config = TransportRpcModuleConfig::default(); + let rpc_modules = + RpcModuleSelection::Selection(vec![RethRpcModule::Admin, RethRpcModule::Eth]); + if self.http { + config = config.with_http(self.http_api.as_ref().unwrap_or(&rpc_modules).clone()); + } + + if self.ws { + config = config.with_ws(self.ws_api.as_ref().unwrap_or(&rpc_modules).clone()); + } + + config + } + + /// Creates the [RpcServerConfig] from cli args. + fn rpc_server_config(&self) -> RpcServerConfig { + let mut config = RpcServerConfig::default(); + + if self.http { + let socket_address = SocketAddr::new( + self.http_addr.unwrap_or(IpAddr::V4(Ipv4Addr::UNSPECIFIED)), + self.http_port.unwrap_or(DEFAULT_HTTP_RPC_PORT), + ); + config = config.with_http_address(socket_address).with_http(ServerBuilder::new()); + } + + if self.ws { + let socket_address = SocketAddr::new( + self.ws_addr.unwrap_or(IpAddr::V4(Ipv4Addr::UNSPECIFIED)), + self.ws_port.unwrap_or(DEFAULT_HTTP_RPC_PORT), + ); + config = config.with_ws_address(socket_address).with_http(ServerBuilder::new()); + } + + if !self.ipcdisable { + let ipc_builder = IpcServerBuilder::default(); + config = config.with_ipc(ipc_builder).with_ipc_endpoint( + self.ipcpath.as_ref().unwrap_or(&DEFAULT_IPC_ENDPOINT.to_string()), + ); + } + + config + } } #[cfg(test)] mod tests { + use std::net::SocketAddrV4; + use super::*; use clap::Parser; @@ -103,4 +183,49 @@ mod tests { assert_eq!(apis, expected); } + + #[test] + fn test_transport_rpc_module_config() { + let args = CommandParser::::parse_from([ + "reth", + "--http.api", + "eth,admin,debug", + "--http", + "--ws", + ]) + .args; + let config = args.transport_rpc_module_config(); + let expected = vec![RethRpcModule::Eth, RethRpcModule::Admin, RethRpcModule::Debug]; + assert_eq!(config.http().cloned().unwrap().into_selection(), expected); + assert_eq!( + config.ws().unwrap().cloned().into_selection(), + vec![RethRpcModule::Admin, RethRpcModule::Eth] + ); + } + + #[test] + fn test_rpc_server_config() { + let args = CommandParser::::parse_from([ + "reth", + "--http.api", + "eth,admin,debug", + "--http", + "--ws", + "--ws.addr", + "127.0.0.1", + "--ws.port", + "8888", + ]) + .args; + let config = args.rpc_server_config(); + assert_eq!( + config.http_address().unwrap(), + SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, DEFAULT_HTTP_RPC_PORT)) + ); + assert_eq!( + config.ws_address().unwrap(), + SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8888)) + ); + assert_eq!(config.ipc_endpoint().unwrap().path(), DEFAULT_IPC_ENDPOINT); + } } diff --git a/bin/reth/src/node/mod.rs b/bin/reth/src/node/mod.rs index 831219e799..2b0e22b3f7 100644 --- a/bin/reth/src/node/mod.rs +++ b/bin/reth/src/node/mod.rs @@ -36,7 +36,7 @@ use reth_network::{ use reth_network_api::NetworkInfo; use reth_primitives::{BlockNumber, ChainSpec, Head, H256}; use reth_provider::{BlockProvider, HeaderProvider, ShareableDatabase}; -use reth_rpc_builder::{RethRpcModule, RpcServerConfig, TransportRpcModuleConfig}; + use reth_staged_sync::{ utils::{ chainspec::genesis_value_parser, @@ -148,16 +148,14 @@ impl Command { // Look at `reth_rpc::AuthLayer` for integration hints let _secret = self.rpc.jwt_secret(); - // TODO(mattsse): cleanup, add cli args - let _rpc_server = reth_rpc_builder::launch( - ShareableDatabase::new(db.clone(), self.chain.clone()), - reth_transaction_pool::test_utils::testing_pool(), - network.clone(), - TransportRpcModuleConfig::default() - .with_http(vec![RethRpcModule::Admin, RethRpcModule::Eth]), - RpcServerConfig::default().with_http(Default::default()), - ) - .await?; + let _rpc_server = self + .rpc + .start_server( + ShareableDatabase::new(db.clone(), self.chain.clone()), + reth_transaction_pool::test_utils::testing_pool(), + network.clone(), + ) + .await?; info!(target: "reth::cli", "Started RPC server"); let (mut pipeline, events) = self diff --git a/crates/rpc/rpc-builder/src/lib.rs b/crates/rpc/rpc-builder/src/lib.rs index 1c5f270154..3c88d94a86 100644 --- a/crates/rpc/rpc-builder/src/lib.rs +++ b/crates/rpc/rpc-builder/src/lib.rs @@ -572,6 +572,21 @@ impl RpcServerConfig { self } + /// Returns the [SocketAddr] of the http server + pub fn http_address(&self) -> Option { + self.http_addr + } + + /// Returns the [SocketAddr] of the ws server + pub fn ws_address(&self) -> Option { + self.ws_addr + } + + /// Returns the [Endpoint] of the ipc server + pub fn ipc_endpoint(&self) -> Option<&Endpoint> { + self.ipc_endpoint.as_ref() + } + /// Convenience function to do [RpcServerConfig::build] and [RpcServer::start] in one step pub async fn start( self, @@ -647,17 +662,17 @@ pub struct TransportRpcModuleConfig { impl TransportRpcModuleConfig { /// Creates a new config with only http set - pub fn http(http: impl Into) -> Self { + pub fn set_http(http: impl Into) -> Self { Self::default().with_http(http) } /// Creates a new config with only ws set - pub fn ws(ws: impl Into) -> Self { + pub fn set_ws(ws: impl Into) -> Self { Self::default().with_ws(ws) } /// Creates a new config with only ipc set - pub fn ipc(ipc: impl Into) -> Self { + pub fn set_ipc(ipc: impl Into) -> Self { Self::default().with_ipc(ipc) } @@ -683,6 +698,21 @@ impl TransportRpcModuleConfig { pub fn is_empty(&self) -> bool { self.http.is_none() && self.ws.is_none() && self.ipc.is_none() } + + /// Returns the [RpcModuleSelection] for the http transport + pub fn http(&self) -> Option<&RpcModuleSelection> { + self.http.as_ref() + } + + /// Returns the [RpcModuleSelection] for the ws transport + pub fn ws(&self) -> Option<&RpcModuleSelection> { + self.ws.as_ref() + } + + /// Returns the [RpcModuleSelection] for the ipc transport + pub fn ipc(&self) -> Option<&RpcModuleSelection> { + self.ipc.as_ref() + } } /// Holds installed modules per transport type. diff --git a/crates/rpc/rpc-builder/tests/it/utils.rs b/crates/rpc/rpc-builder/tests/it/utils.rs index 108ea5e17b..bc9f696591 100644 --- a/crates/rpc/rpc-builder/tests/it/utils.rs +++ b/crates/rpc/rpc-builder/tests/it/utils.rs @@ -15,7 +15,7 @@ pub fn test_address() -> SocketAddr { /// Launches a new server with http only with the given modules pub async fn launch_http(modules: impl Into) -> RpcServerHandle { let builder = test_rpc_builder(); - let server = builder.build(TransportRpcModuleConfig::http(modules)); + let server = builder.build(TransportRpcModuleConfig::set_http(modules)); server .start_server(RpcServerConfig::http(Default::default()).with_http_address(test_address())) .await @@ -25,7 +25,7 @@ pub async fn launch_http(modules: impl Into) -> RpcServerHan /// Launches a new server with ws only with the given modules pub async fn launch_ws(modules: impl Into) -> RpcServerHandle { let builder = test_rpc_builder(); - let server = builder.build(TransportRpcModuleConfig::ws(modules)); + let server = builder.build(TransportRpcModuleConfig::set_ws(modules)); server .start_server(RpcServerConfig::ws(Default::default()).with_ws_address(test_address())) .await @@ -36,7 +36,8 @@ pub async fn launch_ws(modules: impl Into) -> RpcServerHandl pub async fn launch_http_ws(modules: impl Into) -> RpcServerHandle { let builder = test_rpc_builder(); let modules = modules.into(); - let server = builder.build(TransportRpcModuleConfig::ws(modules.clone()).with_http(modules)); + let server = + builder.build(TransportRpcModuleConfig::set_ws(modules.clone()).with_http(modules)); server .start_server( RpcServerConfig::ws(Default::default())