mirror of
https://github.com/paradigmxyz/reth.git
synced 2026-01-29 09:08:05 -05:00
feat(rpc): impl rpc-builder types (#1203)
This commit is contained in:
3
Cargo.lock
generated
3
Cargo.lock
generated
@@ -4641,9 +4641,12 @@ dependencies = [
|
||||
"reth-network-api",
|
||||
"reth-provider",
|
||||
"reth-rpc",
|
||||
"reth-rpc-api",
|
||||
"reth-tracing",
|
||||
"reth-transaction-pool",
|
||||
"serde",
|
||||
"strum",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
@@ -19,8 +19,14 @@ mod net;
|
||||
mod trace;
|
||||
mod web3;
|
||||
|
||||
pub use self::{
|
||||
admin::AdminApiServer, debug::DebugApiServer, engine::EngineApiServer, eth::EthApiServer,
|
||||
eth_filter::EthFilterApiServer, eth_pubsub::EthPubSubApiServer, net::NetApiServer,
|
||||
trace::TraceApiServer, web3::Web3ApiServer,
|
||||
};
|
||||
/// re-export of all server traits
|
||||
pub use servers::*;
|
||||
|
||||
/// Aggregates all server traits.
|
||||
pub mod servers {
|
||||
pub use crate::{
|
||||
admin::AdminApiServer, debug::DebugApiServer, engine::EngineApiServer, eth::EthApiServer,
|
||||
eth_filter::EthFilterApiServer, eth_pubsub::EthPubSubApiServer, net::NetApiServer,
|
||||
trace::TraceApiServer, web3::Web3ApiServer,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -12,9 +12,18 @@ reth-ipc = { path = "../ipc" }
|
||||
reth-network-api = { path = "../../net/network-api" }
|
||||
reth-provider = { path = "../../storage/provider" }
|
||||
reth-rpc = { path = "../rpc" }
|
||||
reth-rpc-api = { path = "../rpc-api" }
|
||||
reth-transaction-pool = { path = "../../transaction-pool" }
|
||||
|
||||
jsonrpsee = { version = "0.16", features = ["server"] }
|
||||
|
||||
strum = { version = "0.24", features = ["derive"] }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
|
||||
[dev-dependencies]
|
||||
reth-tracing = { path = "../../tracing" }
|
||||
reth-rpc-api = { path = "../rpc-api", features = ["client"] }
|
||||
reth-transaction-pool = { path = "../../transaction-pool", features = ["test-utils"] }
|
||||
reth-provider = { path = "../../storage/provider", features = ["test-utils"] }
|
||||
|
||||
tokio = { version = "1", features = ["rt", "rt-multi-thread"] }
|
||||
|
||||
@@ -7,29 +7,106 @@
|
||||
#![allow(unused)]
|
||||
|
||||
//! Configure reth RPC
|
||||
//!
|
||||
//! This crate contains several builder and config types that allow to configure the selection of
|
||||
//! [RethRpcModule] specific to transports (ws, http, ipc).
|
||||
//!
|
||||
//! The [RpcModuleBuilder] is the main entrypoint for configuring all reth modules. It takes
|
||||
//! instances of components required to start the servers, such as provider impls, network and
|
||||
//! transaction pool. [RpcModuleBuilder::build] returns a [TransportRpcModules] which contains the
|
||||
//! transport specific config (what APIs are available via this transport).
|
||||
//!
|
||||
//! The [RpcServerConfig] is used to configure the [RpcServer] type which contains all transport
|
||||
//! implementations (http server, ws server, ipc server). [RpcServer::start] requires the
|
||||
//! [TransportRpcModules] so it can start the servers with the configured modules.
|
||||
//!
|
||||
//! # Examples
|
||||
//!
|
||||
//! Configure only a http server with a selection of [RethRpcModule]s
|
||||
//!
|
||||
//! ```
|
||||
//! use reth_network_api::{NetworkInfo, Peers};
|
||||
//! use reth_provider::{BlockProvider, StateProviderFactory};
|
||||
//! use reth_rpc_builder::{RethRpcModule, RpcModuleBuilder, RpcServerConfig, ServerBuilder, TransportRpcModuleConfig};
|
||||
//! use reth_transaction_pool::TransactionPool;
|
||||
//! pub async fn launch<Client, Pool, Network>(client: Client, pool: Pool, network: Network)
|
||||
//! where
|
||||
//! Client: BlockProvider + StateProviderFactory + Clone + 'static,
|
||||
//! Pool: TransactionPool + Clone + 'static,
|
||||
//! Network: NetworkInfo + Peers + Clone + 'static,
|
||||
//! {
|
||||
//! // configure the rpc module per transport
|
||||
//! let transports = TransportRpcModuleConfig::default().with_http(vec![
|
||||
//! RethRpcModule::Admin,
|
||||
//! RethRpcModule::Debug,
|
||||
//! RethRpcModule::Eth,
|
||||
//! RethRpcModule::Web3,
|
||||
//! ]);
|
||||
//! let transport_modules = RpcModuleBuilder::new(client, pool, network).build(transports);
|
||||
//! let handle = RpcServerConfig::default()
|
||||
//! .with_http(ServerBuilder::default())
|
||||
//! .start(transport_modules)
|
||||
//! .await
|
||||
//! .unwrap();
|
||||
//! }
|
||||
//! ```
|
||||
|
||||
pub use jsonrpsee::server::ServerBuilder;
|
||||
use jsonrpsee::{
|
||||
core::{server::rpc_module::Methods, Error as RpcError},
|
||||
server::{Server, ServerBuilder, ServerHandle},
|
||||
server::{Server, ServerHandle},
|
||||
RpcModule,
|
||||
};
|
||||
use reth_ipc::server::{Builder as IpcServerBuilder, Endpoint, IpcServer};
|
||||
use reth_network_api::{NetworkInfo, PeersInfo};
|
||||
use reth_ipc::server::IpcServer;
|
||||
pub use reth_ipc::server::{Builder as IpcServerBuilder, Endpoint};
|
||||
use reth_network_api::{NetworkInfo, Peers};
|
||||
use reth_provider::{BlockProvider, StateProviderFactory};
|
||||
use reth_rpc::{AdminApi, DebugApi, EthApi, NetApi, TraceApi, Web3Api};
|
||||
use reth_rpc_api::servers::*;
|
||||
use reth_transaction_pool::TransactionPool;
|
||||
use serde::{Deserialize, Serialize, Serializer};
|
||||
use std::{fmt, net::SocketAddr};
|
||||
use strum::{AsRefStr, EnumString, EnumVariantNames};
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
fmt,
|
||||
net::{Ipv4Addr, SocketAddr, SocketAddrV4},
|
||||
};
|
||||
use strum::{AsRefStr, EnumString, EnumVariantNames, VariantNames};
|
||||
|
||||
/// The default port for the http/ws server
|
||||
pub const DEFAULT_RPC_PORT: u16 = 8545;
|
||||
|
||||
/// The default IPC endpoint
|
||||
#[cfg(windows)]
|
||||
pub const DEFAULT_IPC_ENDPOINT: &str = r"\\.\pipe\reth.ipc";
|
||||
|
||||
/// The default IPC endpoint
|
||||
#[cfg(not(windows))]
|
||||
pub const DEFAULT_IPC_ENDPOINT: &str = "/tmp/reth.ipc";
|
||||
|
||||
/// Convenience function for starting a server in one step.
|
||||
pub async fn launch<Client, Pool, Network>(
|
||||
client: Client,
|
||||
pool: Pool,
|
||||
network: Network,
|
||||
module_config: impl Into<TransportRpcModuleConfig>,
|
||||
server_config: impl Into<RpcServerConfig>,
|
||||
) -> Result<RpcServerHandle, RpcError>
|
||||
where
|
||||
Client: BlockProvider + StateProviderFactory + Clone + 'static,
|
||||
Pool: TransactionPool + Clone + 'static,
|
||||
Network: NetworkInfo + Peers + Clone + 'static,
|
||||
{
|
||||
let module_config = module_config.into();
|
||||
let server_config = server_config.into();
|
||||
RpcModuleBuilder::new(client, pool, network)
|
||||
.build(module_config)
|
||||
.start_server(server_config)
|
||||
.await
|
||||
}
|
||||
|
||||
/// A builder type to configure the RPC module: See [RpcModule]
|
||||
///
|
||||
/// This is the main entrypoint for up RPC servers.
|
||||
///
|
||||
/// ```
|
||||
/// use reth_rpc_builder::{RethRpcModule, RpcModuleBuilder, RpcModuleConfig};
|
||||
/// let builder = RpcModuleBuilder::default()
|
||||
/// .with_config(RpcModuleConfig::Selection(vec![RethRpcModule::Eth]));
|
||||
/// ```
|
||||
#[derive(Debug)]
|
||||
pub struct RpcModuleBuilder<Client, Pool, Network> {
|
||||
/// The Client type to when creating all rpc handlers
|
||||
@@ -38,8 +115,6 @@ pub struct RpcModuleBuilder<Client, Pool, Network> {
|
||||
pool: Pool,
|
||||
/// The Network type to when creating all rpc handlers
|
||||
network: Network,
|
||||
/// What modules to configure
|
||||
config: RpcModuleConfig,
|
||||
}
|
||||
|
||||
// === impl RpcBuilder ===
|
||||
@@ -47,13 +122,7 @@ pub struct RpcModuleBuilder<Client, Pool, Network> {
|
||||
impl<Client, Pool, Network> RpcModuleBuilder<Client, Pool, Network> {
|
||||
/// Create a new instance of the builder
|
||||
pub fn new(client: Client, pool: Pool, network: Network) -> Self {
|
||||
Self { client, pool, network, config: Default::default() }
|
||||
}
|
||||
|
||||
/// Configures what RPC modules should be installed
|
||||
pub fn with_config(mut self, config: RpcModuleConfig) -> Self {
|
||||
self.config = config;
|
||||
self
|
||||
Self { client, pool, network }
|
||||
}
|
||||
|
||||
/// Configure the client instance.
|
||||
@@ -61,8 +130,8 @@ impl<Client, Pool, Network> RpcModuleBuilder<Client, Pool, Network> {
|
||||
where
|
||||
C: BlockProvider + StateProviderFactory + 'static,
|
||||
{
|
||||
let Self { pool, config, network, .. } = self;
|
||||
RpcModuleBuilder { client, config, network, pool }
|
||||
let Self { pool, network, .. } = self;
|
||||
RpcModuleBuilder { client, network, pool }
|
||||
}
|
||||
|
||||
/// Configure the transaction pool instance.
|
||||
@@ -70,33 +139,45 @@ impl<Client, Pool, Network> RpcModuleBuilder<Client, Pool, Network> {
|
||||
where
|
||||
P: TransactionPool + 'static,
|
||||
{
|
||||
let Self { client, config, network, .. } = self;
|
||||
RpcModuleBuilder { client, config, network, pool }
|
||||
let Self { client, network, .. } = self;
|
||||
RpcModuleBuilder { client, network, pool }
|
||||
}
|
||||
|
||||
/// Configure the network instance.
|
||||
pub fn with_network<N>(self, network: N) -> RpcModuleBuilder<Client, Pool, N>
|
||||
where
|
||||
N: NetworkInfo + PeersInfo + 'static,
|
||||
N: NetworkInfo + Peers + 'static,
|
||||
{
|
||||
let Self { client, config, pool, .. } = self;
|
||||
RpcModuleBuilder { client, config, network, pool }
|
||||
let Self { client, pool, .. } = self;
|
||||
RpcModuleBuilder { client, network, pool }
|
||||
}
|
||||
}
|
||||
|
||||
impl<Client, Pool, Network> RpcModuleBuilder<Client, Pool, Network>
|
||||
where
|
||||
Client: BlockProvider + StateProviderFactory + 'static,
|
||||
Pool: TransactionPool + 'static,
|
||||
Network: NetworkInfo + PeersInfo + 'static,
|
||||
Client: BlockProvider + StateProviderFactory + Clone + 'static,
|
||||
Pool: TransactionPool + Clone + 'static,
|
||||
Network: NetworkInfo + Peers + Clone + 'static,
|
||||
{
|
||||
/// Configures the [RpcModule] which can be used to start the server(s).
|
||||
/// Configures all [RpcModule]s specific to the given [TransportRpcModuleConfig] which can be
|
||||
/// used to start the transport server(s).
|
||||
///
|
||||
/// See also [RpcServer::start]
|
||||
pub fn build(self, _servers: TransportRpcModuleConfig) -> TransportRpcModules<()> {
|
||||
let Self { client: _, pool: _, network: _, config: _ } = self;
|
||||
pub fn build(self, module_config: TransportRpcModuleConfig) -> TransportRpcModules<()> {
|
||||
let mut modules = TransportRpcModules::default();
|
||||
|
||||
todo!("merge all handlers")
|
||||
let Self { client, pool, network } = self;
|
||||
|
||||
let mut registry = RethModuleRegistry::new(client, pool, network);
|
||||
|
||||
if !module_config.is_empty() {
|
||||
let TransportRpcModuleConfig { http, ws, ipc } = module_config;
|
||||
modules.http = registry.maybe_module(http.as_ref());
|
||||
modules.ws = registry.maybe_module(ws.as_ref());
|
||||
modules.ipc = registry.maybe_module(ipc.as_ref());
|
||||
}
|
||||
|
||||
modules
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,7 +188,16 @@ impl Default for RpcModuleBuilder<(), (), ()> {
|
||||
}
|
||||
|
||||
/// Describes the modules that should be installed
|
||||
#[derive(Debug, Default)]
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// Create a [RpcModuleConfig] from a selection.
|
||||
///
|
||||
/// ```
|
||||
/// use reth_rpc_builder::{RethRpcModule, RpcModuleConfig};
|
||||
/// let config: RpcModuleConfig = vec![RethRpcModule::Eth].into();
|
||||
/// ```
|
||||
#[derive(Debug, Default, Clone, Eq, PartialEq)]
|
||||
pub enum RpcModuleConfig {
|
||||
/// Use all available modules.
|
||||
#[default]
|
||||
@@ -116,9 +206,88 @@ pub enum RpcModuleConfig {
|
||||
Selection(Vec<RethRpcModule>),
|
||||
}
|
||||
|
||||
// === impl RpcModuleConfig ===
|
||||
|
||||
impl RpcModuleConfig {
|
||||
/// Returns a selection of [RethRpcModule] with all [RethRpcModule::VARIANTS].
|
||||
pub fn all_modules() -> Vec<RethRpcModule> {
|
||||
RpcModuleConfig::try_from_selection(RethRpcModule::VARIANTS.iter().copied())
|
||||
.expect("valid selection")
|
||||
.into_selection()
|
||||
}
|
||||
|
||||
/// Creates a new [RpcModuleConfig::Selection] from the given items.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// Create a selection from the [RethRpcModule] string identifiers
|
||||
///
|
||||
/// ```
|
||||
/// use reth_rpc_builder::{RethRpcModule, RpcModuleConfig};
|
||||
/// let selection = vec!["eth", "admin"];
|
||||
/// let config = RpcModuleConfig::try_from_selection(selection).unwrap();
|
||||
/// assert_eq!(config, RpcModuleConfig::Selection(vec![RethRpcModule::Eth, RethRpcModule::Admin]));
|
||||
/// ```
|
||||
pub fn try_from_selection<I, T>(selection: I) -> Result<Self, T::Error>
|
||||
where
|
||||
I: IntoIterator<Item = T>,
|
||||
T: TryInto<RethRpcModule>,
|
||||
{
|
||||
let selection =
|
||||
selection.into_iter().map(TryInto::try_into).collect::<Result<Vec<_>, _>>()?;
|
||||
Ok(RpcModuleConfig::Selection(selection))
|
||||
}
|
||||
|
||||
/// Creates a new [RpcModule] based on the configured reth modules.
|
||||
///
|
||||
/// Note: This will always create new instance of the module handlers and is therefor only
|
||||
/// recommended for launching standalone transports. If multiple transports need to be
|
||||
/// configured it's recommended to use the [RpcModuleBuilder].
|
||||
pub fn standalone_module<Client, Pool, Network>(
|
||||
&self,
|
||||
client: Client,
|
||||
pool: Pool,
|
||||
network: Network,
|
||||
) -> RpcModule<()>
|
||||
where
|
||||
Client: BlockProvider + StateProviderFactory + Clone + 'static,
|
||||
Pool: TransactionPool + Clone + 'static,
|
||||
Network: NetworkInfo + Peers + Clone + 'static,
|
||||
{
|
||||
let mut registry = RethModuleRegistry::new(client, pool, network);
|
||||
registry.module(self)
|
||||
}
|
||||
|
||||
/// Returns an iterator over all configured [RethRpcModule]
|
||||
pub fn iter_selection(&self) -> Box<dyn Iterator<Item = RethRpcModule> + '_> {
|
||||
match self {
|
||||
RpcModuleConfig::All => Box::new(Self::all_modules().into_iter()),
|
||||
RpcModuleConfig::Selection(s) => Box::new(s.iter().copied()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the list of configured [RethRpcModule]
|
||||
pub fn into_selection(self) -> Vec<RethRpcModule> {
|
||||
match self {
|
||||
RpcModuleConfig::All => Self::all_modules(),
|
||||
RpcModuleConfig::Selection(s) => s,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, T> From<I> for RpcModuleConfig
|
||||
where
|
||||
I: IntoIterator<Item = T>,
|
||||
T: Into<RethRpcModule>,
|
||||
{
|
||||
fn from(value: I) -> Self {
|
||||
RpcModuleConfig::Selection(value.into_iter().map(Into::into).collect())
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents RPC modules that are supported by reth
|
||||
#[derive(
|
||||
Debug, Clone, Copy, Eq, PartialEq, AsRefStr, EnumVariantNames, EnumString, Deserialize,
|
||||
Debug, Clone, Copy, Eq, PartialEq, Hash, AsRefStr, EnumVariantNames, EnumString, Deserialize,
|
||||
)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
#[strum(serialize_all = "kebab-case")]
|
||||
@@ -152,6 +321,83 @@ impl Serialize for RethRpcModule {
|
||||
}
|
||||
}
|
||||
|
||||
/// A Helper type the holds instances of the configured modules.
|
||||
pub struct RethModuleRegistry<Client, Pool, Network> {
|
||||
client: Client,
|
||||
pool: Pool,
|
||||
network: Network,
|
||||
/// Holds a clone of the actual [EthApi] namespace impl since this can be required by other
|
||||
/// namespaces
|
||||
eth_api: Option<EthApi<Client, Pool, Network>>,
|
||||
/// Contains the [Methods] of a module
|
||||
modules: HashMap<RethRpcModule, Methods>,
|
||||
}
|
||||
|
||||
// === impl RethModuleRegistry ===
|
||||
|
||||
impl<Client, Pool, Network> RethModuleRegistry<Client, Pool, Network>
|
||||
where
|
||||
Client: BlockProvider + StateProviderFactory + Clone + 'static,
|
||||
Pool: TransactionPool + Clone + 'static,
|
||||
Network: NetworkInfo + Peers + Clone + 'static,
|
||||
{
|
||||
/// Creates a new, empty instance
|
||||
pub fn new(client: Client, pool: Pool, network: Network) -> Self {
|
||||
Self { client, pool, network, eth_api: None, modules: Default::default() }
|
||||
}
|
||||
|
||||
/// Helper function to create a [RpcModule] if it's not `None`
|
||||
fn maybe_module(&mut self, config: Option<&RpcModuleConfig>) -> Option<RpcModule<()>> {
|
||||
let config = config?;
|
||||
let module = self.module(config);
|
||||
Some(module)
|
||||
}
|
||||
|
||||
/// Populates a new [RpcModule] based on the selected [RethRpcModule]s in the given
|
||||
/// [RpcModuleConfig]
|
||||
pub fn module(&mut self, config: &RpcModuleConfig) -> RpcModule<()> {
|
||||
let mut module = RpcModule::new(());
|
||||
for reth_module in config.iter_selection() {
|
||||
let methods = self.reth_methods(reth_module);
|
||||
module.merge(methods).expect("No conflicts");
|
||||
}
|
||||
module
|
||||
}
|
||||
|
||||
/// Returns the [Methods] for the given [RethRpcModule]
|
||||
///
|
||||
/// If this is the first time the namespace is requested, a new instance of API implementation
|
||||
/// will be created.
|
||||
pub fn reth_methods(&mut self, namespace: RethRpcModule) -> Methods {
|
||||
if let Some(methods) = self.modules.get(&namespace).cloned() {
|
||||
return methods
|
||||
}
|
||||
let methods: Methods = match namespace {
|
||||
RethRpcModule::Admin => AdminApi::new(self.network.clone()).into_rpc().into(),
|
||||
RethRpcModule::Debug => DebugApi::new().into_rpc().into(),
|
||||
RethRpcModule::Eth => self.eth_api().into_rpc().into(),
|
||||
RethRpcModule::Net => {
|
||||
let eth_api = self.eth_api();
|
||||
NetApi::new(self.network.clone(), eth_api).into_rpc().into()
|
||||
}
|
||||
RethRpcModule::Trace => TraceApi::new().into_rpc().into(),
|
||||
RethRpcModule::Web3 => Web3Api::new(self.network.clone()).into_rpc().into(),
|
||||
};
|
||||
self.modules.insert(namespace, methods.clone());
|
||||
|
||||
methods
|
||||
}
|
||||
|
||||
/// Returns the configured [EthApi] or creates it if it does not exist yet
|
||||
fn eth_api(&mut self) -> EthApi<Client, Pool, Network> {
|
||||
self.eth_api
|
||||
.get_or_insert_with(|| {
|
||||
EthApi::new(self.client.clone(), self.pool.clone(), self.network.clone())
|
||||
})
|
||||
.clone()
|
||||
}
|
||||
}
|
||||
|
||||
/// A builder type for configuring and launching the servers that will handle RPC requests.
|
||||
///
|
||||
/// Supported server transports are:
|
||||
@@ -163,31 +409,74 @@ impl Serialize for RethRpcModule {
|
||||
///
|
||||
/// Once the [RpcModule] is built via [RpcModuleBuilder] the servers can be started, See also
|
||||
/// [ServerBuilder::build] and [Server::start](jsonrpsee::server::Server::start).
|
||||
pub struct RpcServerBuilder {
|
||||
#[derive(Default)]
|
||||
pub struct RpcServerConfig {
|
||||
/// Configs for JSON-RPC Http.
|
||||
pub http_server_config: Option<ServerBuilder>,
|
||||
http_server_config: Option<ServerBuilder>,
|
||||
/// Configs for WS server
|
||||
pub ws_server_config: Option<ServerBuilder>,
|
||||
ws_server_config: Option<ServerBuilder>,
|
||||
/// Address where to bind the http and ws server to
|
||||
pub http_ws_addr: Option<SocketAddr>,
|
||||
http_ws_addr: Option<SocketAddr>,
|
||||
/// Configs for JSON-RPC IPC server
|
||||
pub ipc_server_config: Option<IpcServerBuilder>,
|
||||
ipc_server_config: Option<IpcServerBuilder>,
|
||||
/// The Endpoint where to launch the ipc server
|
||||
pub ipc_server_path: Option<Endpoint>,
|
||||
ipc_endpoint: Option<Endpoint>,
|
||||
}
|
||||
|
||||
/// === impl RpcServerBuilder ===
|
||||
/// === impl RpcServerConfig ===
|
||||
|
||||
impl RpcServerConfig {
|
||||
/// Configures the http server
|
||||
pub fn with_http(mut self, config: ServerBuilder) -> Self {
|
||||
self.http_server_config = Some(config.http_only());
|
||||
self
|
||||
}
|
||||
|
||||
/// Configures the ws server
|
||||
pub fn with_ws(mut self, config: ServerBuilder) -> Self {
|
||||
self.ws_server_config = Some(config.ws_only());
|
||||
self
|
||||
}
|
||||
|
||||
/// Configures the [SocketAddr] of the http/ws server
|
||||
///
|
||||
/// Default is [Ipv4Addr::UNSPECIFIED] and [DEFAULT_RPC_PORT]
|
||||
pub fn with_address(mut self, addr: SocketAddr) -> Self {
|
||||
self.http_ws_addr = Some(addr);
|
||||
self
|
||||
}
|
||||
|
||||
/// Configures the ipc server
|
||||
pub fn with_ipc(mut self, mut config: IpcServerBuilder) -> Self {
|
||||
self.ipc_server_config = Some(config);
|
||||
self
|
||||
}
|
||||
|
||||
/// Configures the endpoint of the ipc server
|
||||
///
|
||||
/// Default is [DEFAULT_IPC_ENDPOINT]
|
||||
pub fn with_ipc_endpoint(mut self, path: impl Into<String>) -> Self {
|
||||
self.ipc_endpoint = Some(Endpoint::new(path.into()));
|
||||
self
|
||||
}
|
||||
|
||||
/// Convenience function to do [RpcServerConfig::build] and [RpcServer::start] in one step
|
||||
pub async fn start(
|
||||
self,
|
||||
modules: TransportRpcModules<()>,
|
||||
) -> Result<RpcServerHandle, RpcError> {
|
||||
self.build().await?.start(modules).await
|
||||
}
|
||||
|
||||
impl RpcServerBuilder {
|
||||
/// Finalize the configuration of the server(s).
|
||||
///
|
||||
/// This consumes the builder and returns a server.
|
||||
///
|
||||
/// Note: The server ist not started and does nothing unless polled, See also
|
||||
/// Note: The server ist not started and does nothing unless polled, See also [RpcServer::start]
|
||||
pub async fn build(self) -> Result<RpcServer, RpcError> {
|
||||
let socket_addr = self.http_ws_addr.unwrap_or("127.0.0.1:8545".parse().unwrap());
|
||||
/// Todo: default path for ipc
|
||||
let ips_path = self.ipc_server_path.unwrap(); // default path undecided
|
||||
let socket_addr = self
|
||||
.http_ws_addr
|
||||
.unwrap_or(SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, DEFAULT_RPC_PORT)));
|
||||
|
||||
let http_server = if let Some(builder) = self.http_server_config {
|
||||
let server = builder.build(socket_addr).await?;
|
||||
@@ -204,7 +493,10 @@ impl RpcServerBuilder {
|
||||
};
|
||||
|
||||
let ipc_server = if let Some(builder) = self.ipc_server_config {
|
||||
let server = builder.build(ips_path.path())?;
|
||||
let ipc_path = self
|
||||
.ipc_endpoint
|
||||
.unwrap_or_else(|| Endpoint::new(DEFAULT_IPC_ENDPOINT.to_string()));
|
||||
let server = builder.build(ipc_path.path())?;
|
||||
Some(server)
|
||||
} else {
|
||||
None
|
||||
@@ -215,6 +507,17 @@ impl RpcServerBuilder {
|
||||
}
|
||||
|
||||
/// Holds modules to be installed per transport type
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// Configure an http transport only
|
||||
///
|
||||
/// ```
|
||||
/// use reth_rpc_builder::{RethRpcModule, TransportRpcModuleConfig};
|
||||
/// let config = TransportRpcModuleConfig::default()
|
||||
/// .with_http([RethRpcModule::Eth, RethRpcModule::Admin]);
|
||||
/// ```
|
||||
#[derive(Debug, Clone, Default, Eq, PartialEq)]
|
||||
pub struct TransportRpcModuleConfig {
|
||||
/// http module configuration
|
||||
http: Option<RpcModuleConfig>,
|
||||
@@ -224,7 +527,35 @@ pub struct TransportRpcModuleConfig {
|
||||
ipc: Option<RpcModuleConfig>,
|
||||
}
|
||||
|
||||
/// Holds installed modules per transport type
|
||||
// === impl TransportRpcModuleConfig ===
|
||||
|
||||
impl TransportRpcModuleConfig {
|
||||
/// Sets the [RpcModuleConfig] for the http transport.
|
||||
pub fn with_http(mut self, http: impl Into<RpcModuleConfig>) -> Self {
|
||||
self.http = Some(http.into());
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the [RpcModuleConfig] for the ws transport.
|
||||
pub fn with_ws(mut self, ws: impl Into<RpcModuleConfig>) -> Self {
|
||||
self.ws = Some(ws.into());
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the [RpcModuleConfig] for the http transport.
|
||||
pub fn with_ipc(mut self, ipc: impl Into<RpcModuleConfig>) -> Self {
|
||||
self.ipc = Some(ipc.into());
|
||||
self
|
||||
}
|
||||
|
||||
/// Returns true if no transports are configured
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.http.is_none() && self.ws.is_none() && self.ipc.is_none()
|
||||
}
|
||||
}
|
||||
|
||||
/// Holds installed modules per transport type.
|
||||
#[derive(Debug, Default)]
|
||||
pub struct TransportRpcModules<Context> {
|
||||
/// rpcs module for http
|
||||
http: Option<RpcModule<Context>>,
|
||||
@@ -234,7 +565,16 @@ pub struct TransportRpcModules<Context> {
|
||||
ipc: Option<RpcModule<Context>>,
|
||||
}
|
||||
|
||||
/// Container type for each trandport ie. http, ws, and ipc server
|
||||
// === impl TransportRpcModules ===
|
||||
|
||||
impl TransportRpcModules<()> {
|
||||
/// Convenience function for starting a server
|
||||
pub async fn start_server(self, builder: RpcServerConfig) -> Result<RpcServerHandle, RpcError> {
|
||||
builder.start(self).await
|
||||
}
|
||||
}
|
||||
|
||||
/// Container type for each transport ie. http, ws, and ipc server
|
||||
pub struct RpcServer {
|
||||
/// http server
|
||||
http: Option<Server>,
|
||||
@@ -251,15 +591,50 @@ impl RpcServer {
|
||||
///
|
||||
/// This returns an [RpcServerHandle] that's connected to the server task(s) until the server is
|
||||
/// stopped or the [RpcServerHandle] is dropped.
|
||||
pub async fn start(self, _methods: impl Into<Methods>) -> Result<RpcServerHandle, RpcError> {
|
||||
todo!()
|
||||
pub async fn start(
|
||||
self,
|
||||
modules: TransportRpcModules<()>,
|
||||
) -> Result<RpcServerHandle, RpcError> {
|
||||
let TransportRpcModules { http, ws, ipc } = modules;
|
||||
let mut handle = RpcServerHandle { http: None, ws: None, ipc: None };
|
||||
|
||||
// Start all servers
|
||||
if let Some((server, module)) =
|
||||
self.http.and_then(|server| http.map(|module| (server, module)))
|
||||
{
|
||||
handle.http = Some(server.start(module)?);
|
||||
}
|
||||
|
||||
if let Some((server, module)) = self.ws.and_then(|server| ws.map(|module| (server, module)))
|
||||
{
|
||||
handle.ws = Some(server.start(module)?);
|
||||
}
|
||||
|
||||
if let Some((server, module)) =
|
||||
self.ipc.and_then(|server| ipc.map(|module| (server, module)))
|
||||
{
|
||||
handle.ipc = Some(server.start(module).await?);
|
||||
}
|
||||
|
||||
Ok(handle)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for RpcServer {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("RpcServer")
|
||||
.field("http", &self.http.is_some())
|
||||
.field("ws", &self.ws.is_some())
|
||||
.field("ipc", &self.ipc.is_some())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
/// A handle to the spawned servers.
|
||||
///
|
||||
/// When stop has been called the server will be stopped.
|
||||
#[derive(Debug, Clone)]
|
||||
/// When this type is dropped or [RpcServerHandle::stop] has been called the server will be stopped.
|
||||
#[derive(Clone)]
|
||||
#[must_use = "Server stop if dropped"]
|
||||
pub struct RpcServerHandle {
|
||||
http: Option<ServerHandle>,
|
||||
ws: Option<ServerHandle>,
|
||||
@@ -287,6 +662,16 @@ impl RpcServerHandle {
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for RpcServerHandle {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("RpcServerHandle")
|
||||
.field("http", &self.http.is_some())
|
||||
.field("ws", &self.ws.is_some())
|
||||
.field("ipc", &self.ipc.is_some())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@@ -312,4 +697,31 @@ mod tests {
|
||||
"web3" => RethRpcModule::Web3,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_create_rpc_module_config() {
|
||||
let selection = vec!["eth", "admin"];
|
||||
let config = RpcModuleConfig::try_from_selection(selection).unwrap();
|
||||
assert_eq!(
|
||||
config,
|
||||
RpcModuleConfig::Selection(vec![RethRpcModule::Eth, RethRpcModule::Admin])
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_configure_transport_config() {
|
||||
let config = TransportRpcModuleConfig::default()
|
||||
.with_http([RethRpcModule::Eth, RethRpcModule::Admin]);
|
||||
assert_eq!(
|
||||
config,
|
||||
TransportRpcModuleConfig {
|
||||
http: Some(RpcModuleConfig::Selection(vec![
|
||||
RethRpcModule::Eth,
|
||||
RethRpcModule::Admin
|
||||
])),
|
||||
ws: None,
|
||||
ipc: None,
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
8
crates/rpc/rpc-builder/tests/it/http.rs
Normal file
8
crates/rpc/rpc-builder/tests/it/http.rs
Normal file
@@ -0,0 +1,8 @@
|
||||
//! Standalone http tests
|
||||
|
||||
use crate::utils::test_rpc_builder;
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn test_launch_http() {
|
||||
let _builder = test_rpc_builder();
|
||||
}
|
||||
4
crates/rpc/rpc-builder/tests/it/main.rs
Normal file
4
crates/rpc/rpc-builder/tests/it/main.rs
Normal file
@@ -0,0 +1,4 @@
|
||||
mod http;
|
||||
pub mod utils;
|
||||
|
||||
fn main() {}
|
||||
8
crates/rpc/rpc-builder/tests/it/utils.rs
Normal file
8
crates/rpc/rpc-builder/tests/it/utils.rs
Normal file
@@ -0,0 +1,8 @@
|
||||
use reth_provider::test_utils::NoopProvider;
|
||||
use reth_rpc_builder::RpcModuleBuilder;
|
||||
use reth_transaction_pool::test_utils::{testing_pool, TestPool};
|
||||
|
||||
/// Returns an [RpcModuleBuilder] with testing components.
|
||||
pub fn test_rpc_builder() -> RpcModuleBuilder<NoopProvider, TestPool, ()> {
|
||||
RpcModuleBuilder::default().with_client(NoopProvider::default()).with_pool(testing_pool())
|
||||
}
|
||||
@@ -8,10 +8,22 @@ use reth_rpc_types::RichBlock;
|
||||
/// `debug` API implementation.
|
||||
///
|
||||
/// This type provides the functionality for handling `debug` related requests.
|
||||
#[non_exhaustive]
|
||||
pub struct DebugApi {
|
||||
// TODO: add proper handler when implementing functions
|
||||
}
|
||||
|
||||
// === impl DebugApi ===
|
||||
|
||||
impl DebugApi {
|
||||
/// Create a new instance of the [DebugApi]
|
||||
#[allow(clippy::new_without_default)]
|
||||
// TODO add necessary types
|
||||
pub fn new() -> Self {
|
||||
Self {}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl DebugApiServer for DebugApi {
|
||||
async fn raw_header(&self, _block_id: BlockId) -> Result<Bytes> {
|
||||
|
||||
@@ -5,7 +5,7 @@ use reth_primitives::H256;
|
||||
use reth_provider::{BlockProvider, StateProviderFactory};
|
||||
use reth_rpc_types::RichBlock;
|
||||
|
||||
impl<Pool, Client, Network> EthApi<Pool, Client, Network>
|
||||
impl<Client, Pool, Network> EthApi<Client, Pool, Network>
|
||||
where
|
||||
Client: BlockProvider + StateProviderFactory + 'static,
|
||||
{
|
||||
|
||||
@@ -12,7 +12,6 @@ use reth_primitives::{
|
||||
Address, ChainInfo, H256, U64,
|
||||
};
|
||||
use reth_provider::{BlockProvider, StateProviderFactory};
|
||||
use reth_rpc_types::Transaction;
|
||||
use reth_transaction_pool::TransactionPool;
|
||||
use std::sync::Arc;
|
||||
|
||||
@@ -49,20 +48,20 @@ pub trait EthApiSpec: Send + Sync {
|
||||
/// or in other network handlers (for example ipc).
|
||||
#[derive(Clone)]
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub struct EthApi<Pool, Client, Network> {
|
||||
pub struct EthApi<Client, Pool, Network> {
|
||||
/// All nested fields bundled together.
|
||||
inner: Arc<EthApiInner<Pool, Client, Network>>,
|
||||
inner: Arc<EthApiInner<Client, Pool, Network>>,
|
||||
}
|
||||
|
||||
impl<Pool, Client, Network> EthApi<Pool, Client, Network> {
|
||||
impl<Client, Pool, Network> EthApi<Client, Pool, Network> {
|
||||
/// Creates a new, shareable instance.
|
||||
pub fn new(client: Arc<Client>, pool: Pool, network: Network) -> Self {
|
||||
pub fn new(client: Client, pool: Pool, network: Network) -> Self {
|
||||
let inner = EthApiInner { client, pool, network, signers: Default::default() };
|
||||
Self { inner: Arc::new(inner) }
|
||||
}
|
||||
|
||||
/// Returns the inner `Client`
|
||||
pub(crate) fn client(&self) -> &Arc<Client> {
|
||||
pub(crate) fn client(&self) -> &Client {
|
||||
&self.inner.client
|
||||
}
|
||||
|
||||
@@ -79,7 +78,7 @@ impl<Pool, Client, Network> EthApi<Pool, Client, Network> {
|
||||
|
||||
// === State access helpers ===
|
||||
|
||||
impl<Pool, Client, Network> EthApi<Pool, Client, Network>
|
||||
impl<Client, Pool, Network> EthApi<Client, Pool, Network>
|
||||
where
|
||||
Client: BlockProvider + StateProviderFactory + 'static,
|
||||
{
|
||||
@@ -130,9 +129,9 @@ where
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<Pool, Client, Network> EthApiSpec for EthApi<Pool, Client, Network>
|
||||
impl<Client, Pool, Network> EthApiSpec for EthApi<Client, Pool, Network>
|
||||
where
|
||||
Pool: TransactionPool<Transaction = Transaction> + Clone + 'static,
|
||||
Pool: TransactionPool + Clone + 'static,
|
||||
Client: BlockProvider + StateProviderFactory + 'static,
|
||||
Network: NetworkInfo + 'static,
|
||||
{
|
||||
@@ -160,11 +159,11 @@ where
|
||||
}
|
||||
|
||||
/// Container type `EthApi`
|
||||
struct EthApiInner<Pool, Client, Network> {
|
||||
struct EthApiInner<Client, Pool, Network> {
|
||||
/// The transaction pool.
|
||||
pool: Pool,
|
||||
/// The client that can interact with the chain.
|
||||
client: Arc<Client>,
|
||||
client: Client,
|
||||
/// An interface to interact with the network
|
||||
network: Network,
|
||||
/// All configured Signers
|
||||
|
||||
@@ -22,7 +22,7 @@ use serde_json::Value;
|
||||
use super::EthApiSpec;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl<Pool, Client, Network> EthApiServer for EthApi<Pool, Client, Network>
|
||||
impl<Client, Pool, Network> EthApiServer for EthApi<Client, Pool, Network>
|
||||
where
|
||||
Self: EthApiSpec,
|
||||
Pool: TransactionPool + 'static,
|
||||
|
||||
@@ -5,7 +5,7 @@ use reth_interfaces::Result;
|
||||
use reth_primitives::{rpc::BlockId, Address, H256, U256};
|
||||
use reth_provider::{BlockProvider, StateProviderFactory};
|
||||
|
||||
impl<Pool, Client, Network> EthApi<Pool, Client, Network>
|
||||
impl<Client, Pool, Network> EthApi<Client, Pool, Network>
|
||||
where
|
||||
Client: BlockProvider + StateProviderFactory + 'static,
|
||||
{
|
||||
|
||||
@@ -10,7 +10,7 @@ use reth_rlp::Decodable;
|
||||
use reth_rpc_types::TransactionRequest;
|
||||
use reth_transaction_pool::{TransactionOrigin, TransactionPool};
|
||||
|
||||
impl<Pool, Client, Network> EthApi<Pool, Client, Network>
|
||||
impl<Client, Pool, Network> EthApi<Client, Pool, Network>
|
||||
where
|
||||
Pool: TransactionPool + 'static,
|
||||
Client: BlockProvider + StateProviderFactory + 'static,
|
||||
|
||||
@@ -15,6 +15,17 @@ use std::collections::HashSet;
|
||||
#[non_exhaustive]
|
||||
pub struct TraceApi {}
|
||||
|
||||
// === impl TraceApi ===
|
||||
|
||||
impl TraceApi {
|
||||
/// Create a new instance of the [TraceApi]
|
||||
#[allow(clippy::new_without_default)]
|
||||
// TODO add necessary types
|
||||
pub fn new() -> Self {
|
||||
Self {}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl TraceApiServer for TraceApi {
|
||||
async fn call(
|
||||
|
||||
@@ -11,8 +11,11 @@ use async_trait::async_trait;
|
||||
pub use mock::*;
|
||||
use std::{marker::PhantomData, sync::Arc};
|
||||
|
||||
/// A [Pool] used for testing
|
||||
pub type TestPool = Pool<NoopTransactionValidator<MockTransaction>, MockOrdering>;
|
||||
|
||||
/// Returns a new [Pool] used for testing purposes
|
||||
pub fn testing_pool() -> Pool<NoopTransactionValidator<MockTransaction>, MockOrdering> {
|
||||
pub fn testing_pool() -> TestPool {
|
||||
Pool::new(
|
||||
Arc::new(NoopTransactionValidator::default()),
|
||||
Arc::new(MockOrdering::default()),
|
||||
|
||||
Reference in New Issue
Block a user