Преглед изворни кода

explorerd/error: enhance error module with parameterized errors and conversions

Enhanced the `explorerd` error module by introducing parameterized errors, improving error propagation through conversions, renaming for clarity, and refining JSON-RPC error handling.

Updates include:
- Renamed `RpcError` to `ExplorerdError` for use across all application layers (rpc, service, store)
- Updated `ExplorerdError` to support parameterized error variants for more detailed and flexible error messages
- Added conversions from `ExplorerdError` to `RpcError` and `Error` to aid with error propagation from individual RPC handlers to the `handle_request` method
- Renamed `to_tuple` to `to_error_code_message` for improved readability and updated it to support parameterized errors
- Revised the `server_error` function to construct `JsonError` responses using `ExplorerdError`
- Updated Cargo.toml to include thiserror support
- Updated `mod/ping_darkfid` function to use the updated `ExplorerdError`, including error details for additional context
kalm пре 1 година
родитељ
комит
83478ad50d

+ 1 - 0
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"

+ 55 - 22
bin/explorer/explorerd/src/error.rs

@@ -16,44 +16,77 @@
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
 
+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),
 
-fn to_tuple(e: RpcError) -> (i32, String) {
-    let msg = match e {
-        // Misc errors
-        RpcError::PingFailed => "Darkfid daemon ping error",
-    };
+    #[error("Invalid contract ID: {0}")]
+    InvalidContractId(String),
+
+    #[error("Invalid header hash: {0}")]
+    InvalidHeaderHash(String),
+
+    #[error("Invalid tx hash: {0}")]
+    InvalidTxHash(String),
+}
 
-    (e as i32, msg.to_string())
+/// Provides a conversion from [`ExplorerdError`] to darkfi [`Error`] type.
+impl From<ExplorerdError> for Error {
+    fn from(err: ExplorerdError) -> Self {
+        let error: RpcError = err.into();
+        error.into()
+    }
 }
 
-pub fn server_error(e: RpcError, id: u16, msg: Option<&str>) -> JsonResult {
-    let (code, default_msg) = to_tuple(e);
+/// Conversion from [`ExplorerdRpcError`] to [`RpcError`]
+impl From<ExplorerdError> for RpcError {
+    fn from(err: ExplorerdError) -> Self {
+        RpcError::ServerError(Arc::new(err))
+    }
+}
 
-    if let Some(message) = msg {
-        return JsonError::new(ServerError(code), Some(message.to_string()), id).into()
+/// 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(ServerError(code), Some(default_msg), id).into()
+    JsonError::new(ErrorCode::ServerError(code), Some(message), id)
 }
 
-/// 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 {
+/// 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)
 }

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