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 crate::dirs::{JwtSecretPath, PlatformPath};
|
||||||
use clap::Args;
|
use clap::Args;
|
||||||
use jsonrpsee::{core::Error as RpcError, server::ServerHandle};
|
use jsonrpsee::server::ServerHandle;
|
||||||
use reth_interfaces::events::ChainEventSubscriptions;
|
use reth_interfaces::events::ChainEventSubscriptions;
|
||||||
use reth_network_api::{NetworkInfo, Peers};
|
use reth_network_api::{NetworkInfo, Peers};
|
||||||
use reth_primitives::ChainSpec;
|
use reth_primitives::ChainSpec;
|
||||||
use reth_provider::{BlockProvider, EvmEnvProvider, HeaderProvider, StateProviderFactory};
|
use reth_provider::{BlockProvider, EvmEnvProvider, HeaderProvider, StateProviderFactory};
|
||||||
use reth_rpc::{JwtError, JwtSecret};
|
use reth_rpc::{JwtError, JwtSecret};
|
||||||
use reth_rpc_builder::{
|
use reth_rpc_builder::{
|
||||||
constants, IpcServerBuilder, RethRpcModule, RpcModuleSelection, RpcServerConfig,
|
constants, error::RpcError, IpcServerBuilder, RethRpcModule, RpcModuleSelection,
|
||||||
RpcServerHandle, ServerBuilder, TransportRpcModuleConfig,
|
RpcServerConfig, RpcServerHandle, ServerBuilder, TransportRpcModuleConfig,
|
||||||
};
|
};
|
||||||
use reth_rpc_engine_api::EngineApiHandle;
|
use reth_rpc_engine_api::EngineApiHandle;
|
||||||
use reth_tasks::TaskSpawner;
|
use reth_tasks::TaskSpawner;
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
|
use crate::error::{RpcError, ServerKind};
|
||||||
pub use jsonrpsee::server::ServerBuilder;
|
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_network_api::{NetworkInfo, Peers};
|
||||||
use reth_primitives::ChainSpec;
|
use reth_primitives::ChainSpec;
|
||||||
use reth_provider::{BlockProvider, EvmEnvProvider, HeaderProvider, StateProviderFactory};
|
use reth_provider::{BlockProvider, EvmEnvProvider, HeaderProvider, StateProviderFactory};
|
||||||
@ -74,7 +75,11 @@ where
|
|||||||
tower::ServiceBuilder::new().layer(AuthLayer::new(JwtAuthValidator::new(secret)));
|
tower::ServiceBuilder::new().layer(AuthLayer::new(JwtAuthValidator::new(secret)));
|
||||||
|
|
||||||
// By default, both http and ws are enabled.
|
// 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 constants::*;
|
||||||
|
use error::{RpcError, ServerKind};
|
||||||
use jsonrpsee::{
|
use jsonrpsee::{
|
||||||
core::{server::rpc_module::Methods, Error as RpcError},
|
core::server::rpc_module::Methods,
|
||||||
server::{IdProvider, Server, ServerHandle},
|
server::{IdProvider, Server, ServerHandle},
|
||||||
RpcModule,
|
RpcModule,
|
||||||
};
|
};
|
||||||
@ -89,6 +90,9 @@ pub mod auth;
|
|||||||
/// Cors utilities.
|
/// Cors utilities.
|
||||||
mod cors;
|
mod cors;
|
||||||
|
|
||||||
|
/// Rpc error utilities.
|
||||||
|
pub mod error;
|
||||||
|
|
||||||
/// Eth utils
|
/// Eth utils
|
||||||
mod eth;
|
mod eth;
|
||||||
|
|
||||||
@ -865,11 +869,17 @@ impl RpcServerConfig {
|
|||||||
let cors = cors.map_err(|err| RpcError::Custom(err.to_string()))?;
|
let cors = cors.map_err(|err| RpcError::Custom(err.to_string()))?;
|
||||||
let middleware = tower::ServiceBuilder::new().layer(cors);
|
let middleware = tower::ServiceBuilder::new().layer(cors);
|
||||||
let http_server =
|
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_local_addr = http_server.local_addr().ok();
|
||||||
server.http = Some(WsHttpServer::WithCors(http_server));
|
server.http = Some(WsHttpServer::WithCors(http_server));
|
||||||
} else {
|
} 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_local_addr = http_server.local_addr().ok();
|
||||||
server.http = Some(WsHttpServer::Plain(http_server));
|
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) {
|
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 cors = cors.map_err(|err| RpcError::Custom(err.to_string()))?;
|
||||||
let middleware = tower::ServiceBuilder::new().layer(cors);
|
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.http_local_addr = ws_server.local_addr().ok();
|
||||||
server.ws = Some(WsHttpServer::WithCors(ws_server));
|
server.ws = Some(WsHttpServer::WithCors(ws_server));
|
||||||
} else {
|
} 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_local_addr = ws_server.local_addr().ok();
|
||||||
server.ws = Some(WsHttpServer::Plain(ws_server));
|
server.ws = Some(WsHttpServer::Plain(ws_server));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
mod http;
|
mod http;
|
||||||
mod serde;
|
mod serde;
|
||||||
|
mod startup;
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
|
|
||||||
fn main() {}
|
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