diff --git a/bin/explorer/explorerd/Cargo.toml b/bin/explorer/explorerd/Cargo.toml index e8358fdeb..1c1cbc62a 100644 --- a/bin/explorer/explorerd/Cargo.toml +++ b/bin/explorer/explorerd/Cargo.toml @@ -38,6 +38,7 @@ log = "0.4.26" lazy_static = "1.5.0" tar = "0.4.44" toml = "0.8.20" +thiserror = "2.0.11" # Testing tempdir = "0.3.7" diff --git a/bin/explorer/explorerd/src/error.rs b/bin/explorer/explorerd/src/error.rs index 7b845cd97..790420a95 100644 --- a/bin/explorer/explorerd/src/error.rs +++ b/bin/explorer/explorerd/src/error.rs @@ -16,44 +16,77 @@ * along with this program. If not, see . */ +use std::{fmt, sync::Arc}; + use log::error; use darkfi::{ - rpc::jsonrpc::{ErrorCode::ServerError, JsonError, JsonResult}, - Error, + rpc::jsonrpc::{ErrorCode, JsonError}, + Error, RpcError, }; +// Constant for the error code +pub const ERROR_CODE_PING_DARKFID_FAILED: i32 = -32300; + /// Custom RPC errors available for blockchain explorer. -/// Please sort them sensefully. -pub enum RpcError { - // Misc errors - PingFailed = -32300, +/// These represent specific RPC-related failures. +#[derive(Debug, thiserror::Error)] +pub enum ExplorerdError { + #[error("Ping darkfid failed: {0}")] + PingDarkfidFailed(String), + + #[error("Invalid contract ID: {0}")] + InvalidContractId(String), + + #[error("Invalid header hash: {0}")] + InvalidHeaderHash(String), + + #[error("Invalid tx hash: {0}")] + InvalidTxHash(String), } -fn to_tuple(e: RpcError) -> (i32, String) { - let msg = match e { - // Misc errors - RpcError::PingFailed => "Darkfid daemon ping error", - }; - - (e as i32, msg.to_string()) -} - -pub fn server_error(e: RpcError, id: u16, msg: Option<&str>) -> JsonResult { - let (code, default_msg) = to_tuple(e); - - if let Some(message) = msg { - return JsonError::new(ServerError(code), Some(message.to_string()), id).into() +/// Provides a conversion from [`ExplorerdError`] to darkfi [`Error`] type. +impl From for Error { + fn from(err: ExplorerdError) -> Self { + let error: RpcError = err.into(); + error.into() } - - JsonError::new(ServerError(code), Some(default_msg), id).into() } -/// Handles a database error by formatting the output, logging it with target-specific context, -/// and returning a [`DatabaseError`]. -pub fn handle_database_error(target: &str, message: &str, error: impl std::fmt::Debug) -> Error { +/// Conversion from [`ExplorerdRpcError`] to [`RpcError`] +impl From for RpcError { + fn from(err: ExplorerdError) -> Self { + RpcError::ServerError(Arc::new(err)) + } +} + +/// Helper function to convert `ExplorerdRpcError` into error code with corresponding error message. +pub fn to_error_code_message(e: &ExplorerdError) -> (i32, String) { + match e { + ExplorerdError::PingDarkfidFailed(_) => (ERROR_CODE_PING_DARKFID_FAILED, e.to_string()), + ExplorerdError::InvalidContractId(_) | + ExplorerdError::InvalidHeaderHash(_) | + ExplorerdError::InvalidTxHash(_) => (ErrorCode::InvalidParams.code(), e.to_string()), + } +} + +/// Constructs a [`JsonError`] representing a server error using the provided +/// [`ExplorerdError`] , request ID, and optional custom message, returning a [`JsonError`] +/// with a corresponding server error code and message. +pub fn server_error(e: &ExplorerdError, id: u16, msg: Option<&str>) -> JsonError { + let (code, default_msg) = to_error_code_message(e); + + // Use the provided custom message if available; otherwise, use the default. + let message = msg.unwrap_or(&default_msg).to_string(); + + JsonError::new(ErrorCode::ServerError(code), Some(message), id) +} + +/// Logs and converts a database error into a [`DatabaseError`]. +/// This function ensures the error is logged contextually before being returned. +pub fn handle_database_error(target: &str, message: &str, error: impl fmt::Debug) -> Error { let error_message = format!("{}: {:?}", message, error); - let formatted_target = format!("explorerd:: {target}"); + let formatted_target = format!("explorerd::{}", target); error!(target: &formatted_target, "{}", error_message); Error::DatabaseError(error_message) } diff --git a/bin/explorer/explorerd/src/rpc/mod.rs b/bin/explorer/explorerd/src/rpc/mod.rs index 4e472ba22..5477c3a7d 100644 --- a/bin/explorer/explorerd/src/rpc/mod.rs +++ b/bin/explorer/explorerd/src/rpc/mod.rs @@ -35,7 +35,7 @@ use darkfi::{ }; use crate::{ - error::{server_error, RpcError}, + error::{server_error, ExplorerdError}, Explorerd, }; @@ -221,7 +221,7 @@ impl Explorerd { debug!(target: "explorerd::rpc::ping_darkfid", "Pinging darkfid daemon..."); if let Err(e) = self.darkfid_client.ping().await { error!(target: "explorerd::rpc::ping_darkfid", "Failed to ping darkfid daemon: {}", e); - return server_error(RpcError::PingFailed, id, None) + return server_error(&ExplorerdError::PingDarkfidFailed(e.to_string()), id, None).into() } JsonResponse::new(JsonValue::Boolean(true), id).into() }