use jsonrpsee::types::ErrorObjectOwned;
pub mod error_codes {
pub const PARSE_ERROR: i32 = -32700;
pub const INVALID_REQUEST: i32 = -32600;
pub const METHOD_NOT_FOUND: i32 = -32601;
pub const INVALID_PARAMS: i32 = -32602;
pub const INTERNAL_ERROR: i32 = -32603;
pub const TOO_MANY_SUBSCRIPTIONS: i32 = -32800;
pub const INVALID_BLOCK: i32 = -32801;
pub const OPERATION_LIMIT: i32 = -32802;
pub const OPERATION_NOT_FOUND: i32 = -32803;
pub const INVALID_TRANSACTION: i32 = 1010;
pub const UNKNOWN_TRANSACTION: i32 = 1011;
}
#[derive(Debug, thiserror::Error)]
pub enum RpcServerError {
#[error("Failed to start RPC server: {0}")]
ServerStart(String),
#[error("Too many active subscriptions (limit: {limit})")]
TooManySubscriptions {
limit: usize,
},
#[error("Block {hash} is not pinned or unknown")]
BlockNotPinned {
hash: String,
},
#[error("Invalid subscription ID: {id}")]
InvalidSubscription {
id: String,
},
#[error("Operation {id} not found")]
OperationNotFound {
id: String,
},
#[error("Storage error: {0}")]
Storage(String),
#[error("Runtime call failed: {0}")]
RuntimeCall(String),
#[error("Invalid parameter: {0}")]
InvalidParam(String),
#[error("Internal error: {0}")]
Internal(String),
#[error("Block not found: {0}")]
BlockNotFound(String),
#[error("Transaction is invalid: {reason}")]
InvalidTransaction {
reason: String,
data: Option<String>,
},
#[error("Transaction validity unknown: {reason}")]
UnknownTransaction {
reason: String,
data: Option<String>,
},
}
impl From<RpcServerError> for ErrorObjectOwned {
fn from(err: RpcServerError) -> Self {
match err {
RpcServerError::ServerStart(msg) =>
ErrorObjectOwned::owned(error_codes::INTERNAL_ERROR, msg, None::<()>),
RpcServerError::TooManySubscriptions { limit } => ErrorObjectOwned::owned(
error_codes::TOO_MANY_SUBSCRIPTIONS,
format!("Too many subscriptions (limit: {limit})"),
None::<()>,
),
RpcServerError::BlockNotPinned { hash } => ErrorObjectOwned::owned(
error_codes::INVALID_BLOCK,
format!("Block {hash} is not pinned or unknown"),
None::<()>,
),
RpcServerError::InvalidSubscription { id } => ErrorObjectOwned::owned(
error_codes::INVALID_PARAMS,
format!("Invalid subscription ID: {id}"),
None::<()>,
),
RpcServerError::OperationNotFound { id } => ErrorObjectOwned::owned(
error_codes::OPERATION_NOT_FOUND,
format!("Operation {id} not found"),
None::<()>,
),
RpcServerError::Storage(msg) =>
ErrorObjectOwned::owned(error_codes::INTERNAL_ERROR, msg, None::<()>),
RpcServerError::RuntimeCall(msg) =>
ErrorObjectOwned::owned(error_codes::INTERNAL_ERROR, msg, None::<()>),
RpcServerError::InvalidParam(msg) =>
ErrorObjectOwned::owned(error_codes::INVALID_PARAMS, msg, None::<()>),
RpcServerError::Internal(msg) =>
ErrorObjectOwned::owned(error_codes::INTERNAL_ERROR, msg, None::<()>),
RpcServerError::BlockNotFound(msg) =>
ErrorObjectOwned::owned(error_codes::INVALID_BLOCK, msg, None::<()>),
RpcServerError::InvalidTransaction { reason, data } => ErrorObjectOwned::owned(
error_codes::INVALID_TRANSACTION,
format!("Transaction is invalid: {reason}"),
data,
),
RpcServerError::UnknownTransaction { reason, data } => ErrorObjectOwned::owned(
error_codes::UNKNOWN_TRANSACTION,
format!("Transaction validity unknown: {reason}"),
data,
),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn invalid_transaction_error_has_correct_code() {
let error = RpcServerError::InvalidTransaction {
reason: "Nonce too low".to_string(),
data: Some("0x1234".to_string()),
};
let error_object: ErrorObjectOwned = error.into();
assert_eq!(error_object.code(), error_codes::INVALID_TRANSACTION);
assert_eq!(error_object.code(), 1010);
assert!(error_object.message().contains("Transaction is invalid"));
assert!(error_object.message().contains("Nonce too low"));
}
#[test]
fn unknown_transaction_error_has_correct_code() {
let error =
RpcServerError::UnknownTransaction { reason: "Nonce too high".to_string(), data: None };
let error_object: ErrorObjectOwned = error.into();
assert_eq!(error_object.code(), error_codes::UNKNOWN_TRANSACTION);
assert_eq!(error_object.code(), 1011);
assert!(error_object.message().contains("Transaction validity unknown"));
assert!(error_object.message().contains("Nonce too high"));
}
}