zebra_rpc/server/error.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115
//! RPC error codes & their handling.
use jsonrpsee_types::{ErrorCode, ErrorObject, ErrorObjectOwned};
/// Bitcoin RPC error codes
///
/// Drawn from <https://github.com/zcash/zcash/blob/99ad6fdc3a549ab510422820eea5e5ce9f60a5fd/src/rpc/protocol.h#L32-L80>.
///
/// ## Notes
///
/// - All explicit discriminants fit within `i64`.
#[derive(Default)]
pub enum LegacyCode {
// General application defined errors
/// `std::exception` thrown in command handling
#[default]
Misc = -1,
/// Server is in safe mode, and command is not allowed in safe mode
ForbiddenBySafeMode = -2,
/// Unexpected type was passed as parameter
Type = -3,
/// Invalid address or key
InvalidAddressOrKey = -5,
/// Ran out of memory during operation
OutOfMemory = -7,
/// Invalid, missing or duplicate parameter
InvalidParameter = -8,
/// Database error
Database = -20,
/// Error parsing or validating structure in raw format
Deserialization = -22,
/// General error during transaction or block submission
Verify = -25,
/// Transaction or block was rejected by network rules
VerifyRejected = -26,
/// Transaction already in chain
VerifyAlreadyInChain = -27,
/// Client still warming up
InWarmup = -28,
// P2P client errors
/// Bitcoin is not connected
ClientNotConnected = -9,
/// Still downloading initial blocks
ClientInInitialDownload = -10,
/// Node is already added
ClientNodeAlreadyAdded = -23,
/// Node has not been added before
ClientNodeNotAdded = -24,
/// Node to disconnect not found in connected nodes
ClientNodeNotConnected = -29,
/// Invalid IP/Subnet
ClientInvalidIpOrSubnet = -30,
}
impl From<LegacyCode> for ErrorCode {
fn from(code: LegacyCode) -> Self {
Self::ServerError(code as i32)
}
}
impl From<LegacyCode> for i32 {
fn from(code: LegacyCode) -> Self {
code as i32
}
}
/// A trait for mapping errors to [`jsonrpsee_types::ErrorObjectOwned`].
pub(crate) trait MapError<T>: Sized {
/// Maps errors to [`jsonrpsee_types::ErrorObjectOwned`] with a specific error code.
fn map_error(self, code: impl Into<ErrorCode>) -> std::result::Result<T, ErrorObjectOwned>;
/// Maps errors to [`jsonrpsee_types::ErrorObjectOwned`] with a [`LegacyCode::Misc`] error code.
fn map_misc_error(self) -> std::result::Result<T, ErrorObjectOwned> {
self.map_error(LegacyCode::Misc)
}
}
/// A trait for conditionally converting a value into a `Result<T, jsonrpc_core::Error>`.
pub(crate) trait OkOrError<T>: Sized {
/// Converts the implementing type to `Result<T, jsonrpc_core::Error>`, using an error code and
/// message if conversion is to `Err`.
fn ok_or_error(
self,
code: impl Into<ErrorCode>,
message: impl ToString,
) -> std::result::Result<T, ErrorObjectOwned>;
/// Converts the implementing type to `Result<T, jsonrpc_core::Error>`, using a [`LegacyCode::Misc`] error code.
fn ok_or_misc_error(self, message: impl ToString) -> std::result::Result<T, ErrorObjectOwned> {
self.ok_or_error(LegacyCode::Misc, message)
}
}
impl<T, E> MapError<T> for Result<T, E>
where
E: ToString,
{
fn map_error(self, code: impl Into<ErrorCode>) -> Result<T, ErrorObjectOwned> {
self.map_err(|error| ErrorObject::owned(code.into().code(), error.to_string(), None::<()>))
}
}
impl<T> OkOrError<T> for Option<T> {
fn ok_or_error(
self,
code: impl Into<ErrorCode>,
message: impl ToString,
) -> Result<T, ErrorObjectOwned> {
self.ok_or(ErrorObject::owned(
code.into().code(),
message.to_string(),
None::<()>,
))
}
}