mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 19:09:54 +00:00
chore(rpc): improve rpc server launch error diagnostic (#1979)
This commit is contained in:
@ -2,15 +2,15 @@
|
||||
|
||||
use crate::dirs::{JwtSecretPath, PlatformPath};
|
||||
use clap::Args;
|
||||
use jsonrpsee::{core::Error as RpcError, server::ServerHandle};
|
||||
use jsonrpsee::server::ServerHandle;
|
||||
use reth_interfaces::events::ChainEventSubscriptions;
|
||||
use reth_network_api::{NetworkInfo, Peers};
|
||||
use reth_primitives::ChainSpec;
|
||||
use reth_provider::{BlockProvider, EvmEnvProvider, HeaderProvider, StateProviderFactory};
|
||||
use reth_rpc::{JwtError, JwtSecret};
|
||||
use reth_rpc_builder::{
|
||||
constants, IpcServerBuilder, RethRpcModule, RpcModuleSelection, RpcServerConfig,
|
||||
RpcServerHandle, ServerBuilder, TransportRpcModuleConfig,
|
||||
constants, error::RpcError, IpcServerBuilder, RethRpcModule, RpcModuleSelection,
|
||||
RpcServerConfig, RpcServerHandle, ServerBuilder, TransportRpcModuleConfig,
|
||||
};
|
||||
use reth_rpc_engine_api::EngineApiHandle;
|
||||
use reth_tasks::TaskSpawner;
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
use crate::error::{RpcError, ServerKind};
|
||||
pub use jsonrpsee::server::ServerBuilder;
|
||||
use jsonrpsee::{core::Error as RpcError, server::ServerHandle, RpcModule};
|
||||
use jsonrpsee::server::{RpcModule, ServerHandle};
|
||||
use reth_network_api::{NetworkInfo, Peers};
|
||||
use reth_primitives::ChainSpec;
|
||||
use reth_provider::{BlockProvider, EvmEnvProvider, HeaderProvider, StateProviderFactory};
|
||||
@ -74,7 +75,11 @@ where
|
||||
tower::ServiceBuilder::new().layer(AuthLayer::new(JwtAuthValidator::new(secret)));
|
||||
|
||||
// By default, both http and ws are enabled.
|
||||
let server = ServerBuilder::new().set_middleware(middleware).build(socket_addr).await?;
|
||||
let server = ServerBuilder::new()
|
||||
.set_middleware(middleware)
|
||||
.build(socket_addr)
|
||||
.await
|
||||
.map_err(|err| RpcError::from_jsonrpsee_error(err, ServerKind::Auth(socket_addr)))?;
|
||||
|
||||
server.start(module)
|
||||
Ok(server.start(module)?)
|
||||
}
|
||||
|
||||
64
crates/rpc/rpc-builder/src/error.rs
Normal file
64
crates/rpc/rpc-builder/src/error.rs
Normal file
@ -0,0 +1,64 @@
|
||||
use std::net::SocketAddr;
|
||||
|
||||
use jsonrpsee::core::Error as JsonRpseeError;
|
||||
use std::{io, io::ErrorKind};
|
||||
|
||||
/// Rpc server kind.
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum ServerKind {
|
||||
/// Http.
|
||||
Http(SocketAddr),
|
||||
/// Websocket.
|
||||
WS(SocketAddr),
|
||||
/// Auth.
|
||||
Auth(SocketAddr),
|
||||
}
|
||||
|
||||
impl std::fmt::Display for ServerKind {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
ServerKind::Http(addr) => write!(f, "{addr} (HTTP-RPC server)"),
|
||||
ServerKind::WS(addr) => write!(f, "{addr} (WS-RPC server)"),
|
||||
ServerKind::Auth(addr) => write!(f, "{addr} (AUTH server)"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Rpc Errors.
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum RpcError {
|
||||
/// Wrapper for `jsonrpsee::core::Error`.
|
||||
#[error(transparent)]
|
||||
RpcError(#[from] JsonRpseeError),
|
||||
/// Address already in use.
|
||||
#[error("Address {kind} is already in use (os error 98)")]
|
||||
AddressAlreadyInUse {
|
||||
/// Server kind.
|
||||
kind: ServerKind,
|
||||
/// IO error.
|
||||
error: io::Error,
|
||||
},
|
||||
/// Custom error.
|
||||
#[error("{0}")]
|
||||
Custom(String),
|
||||
}
|
||||
|
||||
impl RpcError {
|
||||
/// Converts a `jsonrpsee::core::Error` to a more descriptive `RpcError`.
|
||||
pub fn from_jsonrpsee_error(err: JsonRpseeError, kind: ServerKind) -> RpcError {
|
||||
match err {
|
||||
JsonRpseeError::Transport(err) => {
|
||||
if let Some(io_error) = err.downcast_ref::<io::Error>() {
|
||||
if io_error.kind() == ErrorKind::AddrInUse {
|
||||
return RpcError::AddressAlreadyInUse {
|
||||
kind,
|
||||
error: io::Error::from(io_error.kind()),
|
||||
}
|
||||
}
|
||||
}
|
||||
RpcError::RpcError(err.into())
|
||||
}
|
||||
_ => err.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -54,8 +54,9 @@
|
||||
//! ```
|
||||
|
||||
use constants::*;
|
||||
use error::{RpcError, ServerKind};
|
||||
use jsonrpsee::{
|
||||
core::{server::rpc_module::Methods, Error as RpcError},
|
||||
core::server::rpc_module::Methods,
|
||||
server::{IdProvider, Server, ServerHandle},
|
||||
RpcModule,
|
||||
};
|
||||
@ -89,6 +90,9 @@ pub mod auth;
|
||||
/// Cors utilities.
|
||||
mod cors;
|
||||
|
||||
/// Rpc error utilities.
|
||||
pub mod error;
|
||||
|
||||
/// Eth utils
|
||||
mod eth;
|
||||
|
||||
@ -865,11 +869,17 @@ impl RpcServerConfig {
|
||||
let cors = cors.map_err(|err| RpcError::Custom(err.to_string()))?;
|
||||
let middleware = tower::ServiceBuilder::new().layer(cors);
|
||||
let http_server =
|
||||
builder.set_middleware(middleware).build(http_socket_addr).await?;
|
||||
builder.set_middleware(middleware).build(http_socket_addr).await.map_err(
|
||||
|err| {
|
||||
RpcError::from_jsonrpsee_error(err, ServerKind::Http(http_socket_addr))
|
||||
},
|
||||
)?;
|
||||
server.http_local_addr = http_server.local_addr().ok();
|
||||
server.http = Some(WsHttpServer::WithCors(http_server));
|
||||
} else {
|
||||
let http_server = builder.build(http_socket_addr).await?;
|
||||
let http_server = builder.build(http_socket_addr).await.map_err(|err| {
|
||||
RpcError::from_jsonrpsee_error(err, ServerKind::Http(http_socket_addr))
|
||||
})?;
|
||||
server.http_local_addr = http_server.local_addr().ok();
|
||||
server.http = Some(WsHttpServer::Plain(http_server));
|
||||
}
|
||||
@ -884,11 +894,16 @@ impl RpcServerConfig {
|
||||
if let Some(cors) = self.ws_cors_domains.as_deref().map(cors::create_cors_layer) {
|
||||
let cors = cors.map_err(|err| RpcError::Custom(err.to_string()))?;
|
||||
let middleware = tower::ServiceBuilder::new().layer(cors);
|
||||
let ws_server = builder.set_middleware(middleware).build(ws_socket_addr).await?;
|
||||
let ws_server =
|
||||
builder.set_middleware(middleware).build(ws_socket_addr).await.map_err(
|
||||
|err| RpcError::from_jsonrpsee_error(err, ServerKind::WS(ws_socket_addr)),
|
||||
)?;
|
||||
server.http_local_addr = ws_server.local_addr().ok();
|
||||
server.ws = Some(WsHttpServer::WithCors(ws_server));
|
||||
} else {
|
||||
let ws_server = builder.build(ws_socket_addr).await?;
|
||||
let ws_server = builder.build(ws_socket_addr).await.map_err(|err| {
|
||||
RpcError::from_jsonrpsee_error(err, ServerKind::WS(ws_socket_addr))
|
||||
})?;
|
||||
server.ws_local_addr = ws_server.local_addr().ok();
|
||||
server.ws = Some(WsHttpServer::Plain(ws_server));
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
mod http;
|
||||
mod serde;
|
||||
mod startup;
|
||||
pub mod utils;
|
||||
|
||||
fn main() {}
|
||||
|
||||
39
crates/rpc/rpc-builder/tests/it/startup.rs
Normal file
39
crates/rpc/rpc-builder/tests/it/startup.rs
Normal file
@ -0,0 +1,39 @@
|
||||
//! Startup tests
|
||||
use crate::utils::{launch_http, launch_ws, test_rpc_builder};
|
||||
use reth_rpc_builder::{
|
||||
error::{RpcError, ServerKind},
|
||||
RethRpcModule, RpcServerConfig, TransportRpcModuleConfig,
|
||||
};
|
||||
use std::io;
|
||||
|
||||
fn is_addr_in_use_kind(err: RpcError, kind: ServerKind) -> bool {
|
||||
match err {
|
||||
RpcError::AddressAlreadyInUse { kind: k, error } => {
|
||||
k == kind && error.kind() == io::ErrorKind::AddrInUse
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn test_http_addr_in_use() {
|
||||
let handle = launch_http(vec![RethRpcModule::Admin]).await;
|
||||
let addr = handle.http_local_addr().unwrap();
|
||||
let builder = test_rpc_builder();
|
||||
let server = builder.build(TransportRpcModuleConfig::set_http(vec![RethRpcModule::Admin]));
|
||||
let result = server
|
||||
.start_server(RpcServerConfig::http(Default::default()).with_http_address(addr))
|
||||
.await;
|
||||
assert!(is_addr_in_use_kind(result.unwrap_err(), ServerKind::Http(addr)));
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn test_ws_addr_in_use() {
|
||||
let handle = launch_ws(vec![RethRpcModule::Admin]).await;
|
||||
let addr = handle.ws_local_addr().unwrap();
|
||||
let builder = test_rpc_builder();
|
||||
let server = builder.build(TransportRpcModuleConfig::set_ws(vec![RethRpcModule::Admin]));
|
||||
let result =
|
||||
server.start_server(RpcServerConfig::ws(Default::default()).with_ws_address(addr)).await;
|
||||
assert!(is_addr_in_use_kind(result.unwrap_err(), ServerKind::WS(addr)));
|
||||
}
|
||||
Reference in New Issue
Block a user