1use thiserror::Error;
3use {
4 crate::rpc_response::RpcSimulateTransactionResult,
5 jsonrpc_core::{Error, ErrorCode},
6 gemachain_sdk::clock::Slot,
7};
8
9pub const JSON_RPC_SERVER_ERROR_BLOCK_CLEANED_UP: i64 = -32001;
10pub const JSON_RPC_SERVER_ERROR_SEND_TRANSACTION_PREFLIGHT_FAILURE: i64 = -32002;
11pub const JSON_RPC_SERVER_ERROR_TRANSACTION_SIGNATURE_VERIFICATION_FAILURE: i64 = -32003;
12pub const JSON_RPC_SERVER_ERROR_BLOCK_NOT_AVAILABLE: i64 = -32004;
13pub const JSON_RPC_SERVER_ERROR_NODE_UNHEALTHY: i64 = -32005;
14pub const JSON_RPC_SERVER_ERROR_TRANSACTION_PRECOMPILE_VERIFICATION_FAILURE: i64 = -32006;
15pub const JSON_RPC_SERVER_ERROR_SLOT_SKIPPED: i64 = -32007;
16pub const JSON_RPC_SERVER_ERROR_NO_SNAPSHOT: i64 = -32008;
17pub const JSON_RPC_SERVER_ERROR_LONG_TERM_STORAGE_SLOT_SKIPPED: i64 = -32009;
18pub const JSON_RPC_SERVER_ERROR_KEY_EXCLUDED_FROM_SECONDARY_INDEX: i64 = -32010;
19pub const JSON_RPC_SERVER_ERROR_TRANSACTION_HISTORY_NOT_AVAILABLE: i64 = -32011;
20pub const JSON_RPC_SCAN_ERROR: i64 = -32012;
21pub const JSON_RPC_SERVER_ERROR_TRANSACTION_SIGNATURE_LEN_MISMATCH: i64 = -32013;
22
23#[derive(Error, Debug)]
24pub enum RpcCustomError {
25 #[error("BlockCleanedUp")]
26 BlockCleanedUp {
27 slot: Slot,
28 first_available_block: Slot,
29 },
30 #[error("SendTransactionPreflightFailure")]
31 SendTransactionPreflightFailure {
32 message: String,
33 result: RpcSimulateTransactionResult,
34 },
35 #[error("TransactionSignatureVerificationFailure")]
36 TransactionSignatureVerificationFailure,
37 #[error("BlockNotAvailable")]
38 BlockNotAvailable { slot: Slot },
39 #[error("NodeUnhealthy")]
40 NodeUnhealthy { num_slots_behind: Option<Slot> },
41 #[error("TransactionPrecompileVerificationFailure")]
42 TransactionPrecompileVerificationFailure(gemachain_sdk::transaction::TransactionError),
43 #[error("SlotSkipped")]
44 SlotSkipped { slot: Slot },
45 #[error("NoSnapshot")]
46 NoSnapshot,
47 #[error("LongTermStorageSlotSkipped")]
48 LongTermStorageSlotSkipped { slot: Slot },
49 #[error("KeyExcludedFromSecondaryIndex")]
50 KeyExcludedFromSecondaryIndex { index_key: String },
51 #[error("TransactionHistoryNotAvailable")]
52 TransactionHistoryNotAvailable,
53 #[error("ScanError")]
54 ScanError { message: String },
55 #[error("TransactionSignatureLenMismatch")]
56 TransactionSignatureLenMismatch,
57}
58
59#[derive(Debug, Serialize, Deserialize)]
60#[serde(rename_all = "camelCase")]
61pub struct NodeUnhealthyErrorData {
62 pub num_slots_behind: Option<Slot>,
63}
64
65impl From<RpcCustomError> for Error {
66 fn from(e: RpcCustomError) -> Self {
67 match e {
68 RpcCustomError::BlockCleanedUp {
69 slot,
70 first_available_block,
71 } => Self {
72 code: ErrorCode::ServerError(JSON_RPC_SERVER_ERROR_BLOCK_CLEANED_UP),
73 message: format!(
74 "Block {} cleaned up, does not exist on node. First available block: {}",
75 slot, first_available_block,
76 ),
77 data: None,
78 },
79 RpcCustomError::SendTransactionPreflightFailure { message, result } => Self {
80 code: ErrorCode::ServerError(
81 JSON_RPC_SERVER_ERROR_SEND_TRANSACTION_PREFLIGHT_FAILURE,
82 ),
83 message,
84 data: Some(serde_json::json!(result)),
85 },
86 RpcCustomError::TransactionSignatureVerificationFailure => Self {
87 code: ErrorCode::ServerError(
88 JSON_RPC_SERVER_ERROR_TRANSACTION_SIGNATURE_VERIFICATION_FAILURE,
89 ),
90 message: "Transaction signature verification failure".to_string(),
91 data: None,
92 },
93 RpcCustomError::BlockNotAvailable { slot } => Self {
94 code: ErrorCode::ServerError(JSON_RPC_SERVER_ERROR_BLOCK_NOT_AVAILABLE),
95 message: format!("Block not available for slot {}", slot),
96 data: None,
97 },
98 RpcCustomError::NodeUnhealthy { num_slots_behind } => Self {
99 code: ErrorCode::ServerError(JSON_RPC_SERVER_ERROR_NODE_UNHEALTHY),
100 message: if let Some(num_slots_behind) = num_slots_behind {
101 format!("Node is behind by {} slots", num_slots_behind)
102 } else {
103 "Node is unhealthy".to_string()
104 },
105 data: Some(serde_json::json!(NodeUnhealthyErrorData {
106 num_slots_behind
107 })),
108 },
109 RpcCustomError::TransactionPrecompileVerificationFailure(e) => Self {
110 code: ErrorCode::ServerError(
111 JSON_RPC_SERVER_ERROR_TRANSACTION_SIGNATURE_VERIFICATION_FAILURE,
112 ),
113 message: format!("Transaction precompile verification failure {:?}", e),
114 data: None,
115 },
116 RpcCustomError::SlotSkipped { slot } => Self {
117 code: ErrorCode::ServerError(JSON_RPC_SERVER_ERROR_SLOT_SKIPPED),
118 message: format!(
119 "Slot {} was skipped, or missing due to ledger jump to recent snapshot",
120 slot
121 ),
122 data: None,
123 },
124 RpcCustomError::NoSnapshot => Self {
125 code: ErrorCode::ServerError(JSON_RPC_SERVER_ERROR_NO_SNAPSHOT),
126 message: "No snapshot".to_string(),
127 data: None,
128 },
129 RpcCustomError::LongTermStorageSlotSkipped { slot } => Self {
130 code: ErrorCode::ServerError(JSON_RPC_SERVER_ERROR_LONG_TERM_STORAGE_SLOT_SKIPPED),
131 message: format!("Slot {} was skipped, or missing in long-term storage", slot),
132 data: None,
133 },
134 RpcCustomError::KeyExcludedFromSecondaryIndex { index_key } => Self {
135 code: ErrorCode::ServerError(
136 JSON_RPC_SERVER_ERROR_KEY_EXCLUDED_FROM_SECONDARY_INDEX,
137 ),
138 message: format!(
139 "{} excluded from account secondary indexes; \
140 this RPC method unavailable for key",
141 index_key
142 ),
143 data: None,
144 },
145 RpcCustomError::TransactionHistoryNotAvailable => Self {
146 code: ErrorCode::ServerError(
147 JSON_RPC_SERVER_ERROR_TRANSACTION_HISTORY_NOT_AVAILABLE,
148 ),
149 message: "Transaction history is not available from this node".to_string(),
150 data: None,
151 },
152 RpcCustomError::ScanError { message } => Self {
153 code: ErrorCode::ServerError(JSON_RPC_SCAN_ERROR),
154 message,
155 data: None,
156 },
157 RpcCustomError::TransactionSignatureLenMismatch => Self {
158 code: ErrorCode::ServerError(
159 JSON_RPC_SERVER_ERROR_TRANSACTION_SIGNATURE_LEN_MISMATCH,
160 ),
161 message: "Transaction signature length mismatch".to_string(),
162 data: None,
163 },
164 }
165 }
166}