explorerd/
error.rs

1/* This file is part of DarkFi (https://dark.fi)
2 *
3 * Copyright (C) 2020-2025 Dyne.org foundation
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU Affero General Public License as
7 * published by the Free Software Foundation, either version 3 of the
8 * License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
17 */
18
19use std::{fmt, sync::Arc};
20
21use log::error;
22
23use darkfi::{
24    error::RpcError,
25    rpc::jsonrpc::{ErrorCode, JsonError},
26    Error,
27};
28
29// Constant for the error code
30pub const ERROR_CODE_PING_DARKFID_FAILED: i32 = -32300;
31
32/// Custom RPC errors available for blockchain explorer.
33/// These represent specific RPC-related failures.
34#[derive(Debug, thiserror::Error)]
35pub enum ExplorerdError {
36    #[error("Ping darkfid failed: {0}")]
37    PingDarkfidFailed(String),
38
39    #[error("Invalid contract ID: {0}")]
40    InvalidContractId(String),
41
42    #[error("Invalid header hash: {0}")]
43    InvalidHeaderHash(String),
44
45    #[error("Invalid tx hash: {0}")]
46    InvalidTxHash(String),
47}
48
49/// Provides a conversion from [`ExplorerdError`] to darkfi [`Error`] type.
50impl From<ExplorerdError> for Error {
51    fn from(err: ExplorerdError) -> Self {
52        let error: RpcError = err.into();
53        error.into()
54    }
55}
56
57/// Conversion from [`ExplorerdRpcError`] to [`RpcError`]
58impl From<ExplorerdError> for RpcError {
59    fn from(err: ExplorerdError) -> Self {
60        RpcError::ServerError(Arc::new(err))
61    }
62}
63
64/// Helper function to convert `ExplorerdRpcError` into error code with corresponding error message.
65pub fn to_error_code_message(e: &ExplorerdError) -> (i32, String) {
66    match e {
67        ExplorerdError::PingDarkfidFailed(_) => (ERROR_CODE_PING_DARKFID_FAILED, e.to_string()),
68        ExplorerdError::InvalidContractId(_) |
69        ExplorerdError::InvalidHeaderHash(_) |
70        ExplorerdError::InvalidTxHash(_) => (ErrorCode::InvalidParams.code(), e.to_string()),
71    }
72}
73
74/// Constructs a [`JsonError`] representing a server error using the provided
75/// [`ExplorerdError`] , request ID, and optional custom message, returning a [`JsonError`]
76/// with a corresponding server error code and message.
77pub fn server_error(e: &ExplorerdError, id: u16, msg: Option<&str>) -> JsonError {
78    let (code, default_msg) = to_error_code_message(e);
79
80    // Use the provided custom message if available; otherwise, use the default.
81    let message = msg.unwrap_or(&default_msg).to_string();
82
83    JsonError::new(ErrorCode::ServerError(code), Some(message), id)
84}
85
86/// Logs and converts a database error into a [`DatabaseError`].
87/// This function ensures the error is logged contextually before being returned.
88pub fn handle_database_error(target: &str, message: &str, error: impl fmt::Debug) -> Error {
89    let error_message = format!("{}: {:?}", message, error);
90    let formatted_target = format!("explorerd::{}", target);
91    error!(target: &formatted_target, "{}", error_message);
92    Error::DatabaseError(error_message)
93}