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