diff --git a/Cargo.lock b/Cargo.lock index 7bcb9c3c1..ea7226d3e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4241,6 +4241,7 @@ dependencies = [ "reth-codecs", "reth-db", "reth-eth-wire", + "reth-network-api", "reth-primitives", "reth-rpc-types", "secp256k1 0.24.2", @@ -4399,6 +4400,8 @@ dependencies = [ "async-trait", "reth-primitives", "serde", + "thiserror", + "tokio", ] [[package]] diff --git a/crates/interfaces/Cargo.toml b/crates/interfaces/Cargo.toml index 057df2919..aea3820bc 100644 --- a/crates/interfaces/Cargo.toml +++ b/crates/interfaces/Cargo.toml @@ -10,6 +10,7 @@ readme = "README.md" reth-codecs = { path = "../storage/codecs" } reth-primitives = { path = "../primitives" } reth-rpc-types = { path = "../net/rpc-types" } +reth-network-api = { path = "../net/network-api"} async-trait = "0.1.57" thiserror = "1.0.37" auto_impl = "1.0" diff --git a/crates/net/network-api/Cargo.toml b/crates/net/network-api/Cargo.toml index 37a90c6d7..90581bca7 100644 --- a/crates/net/network-api/Cargo.toml +++ b/crates/net/network-api/Cargo.toml @@ -11,8 +11,11 @@ description = "Network interfaces" # reth reth-primitives = { path = "../../primitives" } + # io serde = { version = "1.0", features = ["derive"] } # misc -async-trait = "0.1" \ No newline at end of file +async-trait = "0.1" +thiserror = "1.0.37" +tokio = { version = "1.21.2", features = ["sync"] } \ No newline at end of file diff --git a/crates/net/network-api/src/error.rs b/crates/net/network-api/src/error.rs new file mode 100644 index 000000000..71038cf4b --- /dev/null +++ b/crates/net/network-api/src/error.rs @@ -0,0 +1,22 @@ +use thiserror::Error; +use tokio::sync::{mpsc, oneshot}; + +/// Network Errors +#[allow(missing_docs)] +#[derive(Error, Debug, Clone, PartialEq, Eq)] +pub enum NetworkError { + #[error("Sender has been dropped")] + ChannelClosed, +} + +impl From> for NetworkError { + fn from(_: mpsc::error::SendError) -> Self { + NetworkError::ChannelClosed + } +} + +impl From for NetworkError { + fn from(_: oneshot::error::RecvError) -> Self { + NetworkError::ChannelClosed + } +} diff --git a/crates/net/network-api/src/lib.rs b/crates/net/network-api/src/lib.rs index 15bdee40a..54454f2be 100644 --- a/crates/net/network-api/src/lib.rs +++ b/crates/net/network-api/src/lib.rs @@ -12,19 +12,20 @@ use async_trait::async_trait; use reth_primitives::{NodeRecord, H256, U256}; use serde::{Deserialize, Serialize}; -use std::{error::Error, net::SocketAddr}; +use std::net::SocketAddr; + +/// Network Error +pub mod error; +pub use error::NetworkError; /// Provides general purpose information about the network. #[async_trait] pub trait NetworkInfo: Send + Sync { - /// Associated error type for the network implementation. - type Error: Send + Sync + Error; - /// Returns the [`SocketAddr`] that listens for incoming connections. fn local_addr(&self) -> SocketAddr; /// Returns the current status of the network being ran by the local node. - async fn network_status(&self) -> Result; + async fn network_status(&self) -> Result; } /// Provides general purpose information about Peers in the network. diff --git a/crates/net/network/src/network.rs b/crates/net/network/src/network.rs index bb920bb92..0d8e519b5 100644 --- a/crates/net/network/src/network.rs +++ b/crates/net/network/src/network.rs @@ -16,7 +16,7 @@ use reth_interfaces::{ sync::{SyncState, SyncStateProvider, SyncStateUpdater}, }; use reth_net_common::bandwidth_meter::BandwidthMeter; -use reth_network_api::{EthProtocolInfo, NetworkInfo, NetworkStatus, PeersInfo}; +use reth_network_api::{EthProtocolInfo, NetworkError, NetworkInfo, NetworkStatus, PeersInfo}; use reth_primitives::{NodeRecord, PeerId, TransactionSigned, TxHash, H256, U256}; use std::{ net::SocketAddr, @@ -227,13 +227,11 @@ impl PeersInfo for NetworkHandle { #[async_trait] impl NetworkInfo for NetworkHandle { - type Error = oneshot::error::RecvError; - fn local_addr(&self) -> SocketAddr { *self.inner.listener_address.lock() } - async fn network_status(&self) -> Result { + async fn network_status(&self) -> Result { let status = self.get_status().await?; Ok(NetworkStatus { diff --git a/crates/net/rpc/src/admin.rs b/crates/net/rpc/src/admin.rs index 29c52da62..830007fd6 100644 --- a/crates/net/rpc/src/admin.rs +++ b/crates/net/rpc/src/admin.rs @@ -1,11 +1,14 @@ use async_trait::async_trait; use jsonrpsee::core::RpcResult; + use reth_network::{peers::PeerKind, NetworkHandle}; use reth_network_api::{NetworkInfo, PeersInfo}; use reth_primitives::NodeRecord; use reth_rpc_api::AdminApiServer; use reth_rpc_types::NodeInfo; +use crate::result::ToRpcResult; + /// `admin` API implementation. /// /// This type provides the functionality for handling `admin` related requests. @@ -52,10 +55,7 @@ impl AdminApiServer for AdminApi { async fn node_info(&self) -> RpcResult { let enr = self.network.local_node_record(); - let status = match self.network.network_status().await { - Ok(status) => status, - Err(e) => return RpcResult::Err(jsonrpsee::core::Error::Custom(e.to_string())), - }; + let status = self.network.network_status().await.map_internal_err(|e| e.to_string())?; Ok(NodeInfo::new(enr, status)) } diff --git a/crates/net/rpc/src/result.rs b/crates/net/rpc/src/result.rs index aec3af029..b331bf358 100644 --- a/crates/net/rpc/src/result.rs +++ b/crates/net/rpc/src/result.rs @@ -1,6 +1,7 @@ //! Additional helpers for converting errors. use jsonrpsee::core::{Error as RpcError, RpcResult}; +use reth_network_api::NetworkError; /// Helper trait to easily convert various `Result` types into [`RpcResult`] pub(crate) trait ToRpcResult { @@ -85,6 +86,61 @@ impl ToRpcResult for reth_interfaces::Result } } +impl ToRpcResult for Result { + #[inline] + fn map_rpc_err<'a, F, M>(self, op: F) -> RpcResult + where + F: FnOnce(NetworkError) -> (i32, M, Option<&'a [u8]>), + M: Into, + { + match self { + Ok(t) => Ok(t), + Err(err) => { + let (code, msg, data) = op(err); + Err(rpc_err(code, msg, data)) + } + } + } + + #[inline] + fn map_internal_err<'a, F, M>(self, op: F) -> RpcResult + where + F: FnOnce(NetworkError) -> M, + M: Into, + { + match self { + Ok(t) => Ok(t), + Err(err) => Err(internal_rpc_err(op(err))), + } + } + + #[inline] + fn map_internal_err_with_data<'a, F, M>(self, op: F) -> RpcResult + where + F: FnOnce(NetworkError) -> (M, &'a [u8]), + M: Into, + { + match self { + Ok(t) => Ok(t), + Err(err) => { + let (msg, data) = op(err); + Err(internal_rpc_err_with_data(msg, data)) + } + } + } + + #[inline] + fn with_message(self, msg: &str) -> RpcResult { + match self { + Ok(t) => Ok(t), + Err(err) => { + let msg = format!("{msg}: {err:?}"); + Err(internal_rpc_err(msg)) + } + } + } +} + /// Constructs an internal JSON-RPC error. pub(crate) fn internal_rpc_err(msg: impl Into) -> jsonrpsee::core::Error { rpc_err(jsonrpsee::types::error::INTERNAL_ERROR_CODE, msg, None)