feat(rpc): impl rpc-builder types (#1203)

This commit is contained in:
Matthias Seitz
2023-02-07 20:03:05 +01:00
committed by GitHub
parent df6e3143c3
commit 10aa3d617a
15 changed files with 551 additions and 76 deletions

3
Cargo.lock generated
View File

@@ -4641,9 +4641,12 @@ dependencies = [
"reth-network-api",
"reth-provider",
"reth-rpc",
"reth-rpc-api",
"reth-tracing",
"reth-transaction-pool",
"serde",
"strum",
"tokio",
]
[[package]]

View File

@@ -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,
};
}

View File

@@ -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"] }

View File

@@ -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,
}
)
}
}

View 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();
}

View File

@@ -0,0 +1,4 @@
mod http;
pub mod utils;
fn main() {}

View 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())
}

View File

@@ -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> {

View File

@@ -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,
{

View File

@@ -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

View File

@@ -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,

View File

@@ -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,
{

View File

@@ -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,

View File

@@ -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(

View File

@@ -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()),