1use ethrex_common::U256;
10use ethrex_storage::error::StoreError;
11use ethrex_vm::EvmError;
12use serde::{Deserialize, Serialize};
13use serde_json::Value;
14
15use crate::{authentication::AuthenticationError, clients::EthClientError};
16use ethrex_blockchain::error::MempoolError;
17
18#[derive(Debug, thiserror::Error)]
28pub enum RpcErr {
29 #[error("Method not found: {0}")]
30 MethodNotFound(String),
31 #[error("Wrong parameter: {0}")]
32 WrongParam(String),
33 #[error("Invalid params: {0}")]
34 BadParams(String),
35 #[error("Missing parameter: {0}")]
36 MissingParam(String),
37 #[error("Too large request")]
38 TooLargeRequest,
39 #[error("Bad hex format: {0}")]
40 BadHexFormat(u64),
41 #[error("Unsupported fork: {0}")]
42 UnsupportedFork(String),
43 #[error("Internal Error: {0}")]
44 Internal(String),
45 #[error("Vm execution error: {0}")]
46 Vm(String),
47 #[error("execution reverted: data={data}")]
48 Revert { data: String },
49 #[error("execution halted: reason={reason}, gas_used={gas_used}")]
50 Halt { reason: String, gas_used: u64 },
51 #[error("Authentication error: {0:?}")]
52 AuthenticationError(AuthenticationError),
53 #[error("Invalid Request: {0}")]
58 InvalidRequest(String),
59 #[error("Invalid forkchoice state: {0}")]
60 InvalidForkChoiceState(String),
61 #[error("Invalid payload attributes: {0}")]
62 InvalidPayloadAttributes(String),
63 #[error("Too deep reorg: {0}")]
64 TooDeepReorg(String),
65 #[error("Unknown payload: {0}")]
66 UnknownPayload(String),
67 #[error("Invalid proof format: {0}")]
69 InvalidProofFormat(String),
70 #[error("Invalid header format: {0}")]
71 InvalidHeaderFormat(String),
72 #[error("Invalid payload: {0}")]
73 InvalidPayload(String),
74 #[error("Proof generation unavailable: {0}")]
75 ProofGenerationUnavailable(String),
76}
77
78impl From<RpcErr> for RpcErrorMetadata {
79 fn from(value: RpcErr) -> Self {
80 match value {
81 RpcErr::MethodNotFound(bad_method) => RpcErrorMetadata {
82 code: -32601,
83 data: None,
84 message: format!("Method not found: {bad_method}"),
85 },
86 RpcErr::WrongParam(field) => RpcErrorMetadata {
87 code: -32602,
88 data: None,
89 message: format!("Field '{field}' is incorrect or has an unknown format"),
90 },
91 RpcErr::BadParams(context) => RpcErrorMetadata {
92 code: -32000,
93 data: None,
94 message: format!("Invalid params: {context}"),
95 },
96 RpcErr::InvalidRequest(context) => RpcErrorMetadata {
97 code: -32600,
98 data: None,
99 message: format!("Invalid Request: {context}"),
100 },
101 RpcErr::MissingParam(parameter_name) => RpcErrorMetadata {
102 code: -32000,
103 data: None,
104 message: format!("Expected parameter: {parameter_name} is missing"),
105 },
106 RpcErr::TooLargeRequest => RpcErrorMetadata {
107 code: -38004,
108 data: None,
109 message: "Too large request".to_string(),
110 },
111 RpcErr::UnsupportedFork(context) => RpcErrorMetadata {
112 code: -38005,
113 data: None,
114 message: format!("Unsupported fork: {context}"),
115 },
116 RpcErr::BadHexFormat(arg_number) => RpcErrorMetadata {
117 code: -32602,
118 data: None,
119 message: format!("invalid argument {arg_number} : hex string without 0x prefix"),
120 },
121 RpcErr::Internal(context) => RpcErrorMetadata {
122 code: -32603,
123 data: None,
124 message: format!("Internal Error: {context}"),
125 },
126 RpcErr::Vm(context) => RpcErrorMetadata {
127 code: -32015,
128 data: None,
129 message: format!("Vm execution error: {context}"),
130 },
131 RpcErr::Revert { data } => RpcErrorMetadata {
132 code: 3,
135 data: Some(data.clone()),
136 message: format!(
137 "execution reverted: {}",
138 get_message_from_revert_data(&data).unwrap_or_else(|err| format!(
139 "tried to decode error from abi but failed: {err}"
140 ))
141 ),
142 },
143 RpcErr::Halt { reason, gas_used } => RpcErrorMetadata {
144 code: 3,
147 data: None,
148 message: format!("execution halted: reason={reason}, gas_used={gas_used}"),
149 },
150 RpcErr::AuthenticationError(auth_error) => match auth_error {
151 AuthenticationError::InvalidIssuedAtClaim => RpcErrorMetadata {
152 code: -32000,
153 data: None,
154 message: "Auth failed: Invalid iat claim".to_string(),
155 },
156 AuthenticationError::TokenDecodingError => RpcErrorMetadata {
157 code: -32000,
158 data: None,
159 message: "Auth failed: Invalid or missing token".to_string(),
160 },
161 AuthenticationError::MissingAuthentication => RpcErrorMetadata {
162 code: -32000,
163 data: None,
164 message: "Auth failed: Missing authentication header".to_string(),
165 },
166 },
167 RpcErr::InvalidForkChoiceState(data) => RpcErrorMetadata {
168 code: -38002,
169 data: Some(data),
170 message: "Invalid forkchoice state".to_string(),
171 },
172 RpcErr::InvalidPayloadAttributes(data) => RpcErrorMetadata {
173 code: -38003,
174 data: Some(data),
175 message: "Invalid payload attributes".to_string(),
176 },
177 RpcErr::TooDeepReorg(data) => RpcErrorMetadata {
178 code: -38006,
179 data: Some(data),
180 message: "Too deep reorg".to_string(),
181 },
182 RpcErr::UnknownPayload(context) => RpcErrorMetadata {
183 code: -38001,
184 data: None,
185 message: format!("Unknown payload: {context}"),
186 },
187 RpcErr::InvalidProofFormat(context) => RpcErrorMetadata {
189 code: -39001,
190 data: None,
191 message: format!("Invalid proof format: {context}"),
192 },
193 RpcErr::InvalidHeaderFormat(context) => RpcErrorMetadata {
194 code: -39002,
195 data: None,
196 message: format!("Invalid header format: {context}"),
197 },
198 RpcErr::InvalidPayload(context) => RpcErrorMetadata {
199 code: -39003,
200 data: None,
201 message: format!("Invalid payload: {context}"),
202 },
203 RpcErr::ProofGenerationUnavailable(context) => RpcErrorMetadata {
204 code: -39004,
205 data: None,
206 message: format!("Proof generation unavailable: {context}"),
207 },
208 }
209 }
210}
211
212impl From<serde_json::Error> for RpcErr {
213 fn from(error: serde_json::Error) -> Self {
214 Self::BadParams(error.to_string())
215 }
216}
217
218impl From<MempoolError> for RpcErr {
221 fn from(err: MempoolError) -> Self {
222 match err {
223 MempoolError::StoreError(err) => Self::Internal(err.to_string()),
224 other_err => Self::BadParams(other_err.to_string()),
225 }
226 }
227}
228
229impl From<ethrex_crypto::CryptoError> for RpcErr {
230 fn from(err: ethrex_crypto::CryptoError) -> Self {
231 Self::Internal(format!("Cryptography error: {err}"))
232 }
233}
234
235#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
240pub enum RpcNamespace {
241 Engine,
243 Eth,
245 Admin,
247 Debug,
249 Web3,
251 Net,
253 Mempool,
255}
256
257impl RpcNamespace {
258 pub fn from_prefix(s: &str) -> Option<Self> {
260 match s {
261 "engine" => Some(RpcNamespace::Engine),
262 "eth" => Some(RpcNamespace::Eth),
263 "admin" => Some(RpcNamespace::Admin),
264 "debug" => Some(RpcNamespace::Debug),
265 "web3" => Some(RpcNamespace::Web3),
266 "net" => Some(RpcNamespace::Net),
267 "txpool" => Some(RpcNamespace::Mempool),
268 _ => None,
269 }
270 }
271}
272
273#[derive(Debug, Clone, Serialize, Deserialize)]
278#[serde(untagged)]
279pub enum RpcRequestId {
280 Number(u64),
282 String(String),
284}
285
286#[derive(Serialize, Deserialize, Debug, Clone)]
299pub struct RpcRequest {
300 pub id: RpcRequestId,
302 pub jsonrpc: String,
304 pub method: String,
306 pub params: Option<Vec<Value>>,
308}
309
310impl RpcRequest {
311 pub fn namespace(&self) -> Result<RpcNamespace, RpcErr> {
312 let mut parts = self.method.split('_');
313 let Some(namespace) = parts.next() else {
314 return Err(RpcErr::MethodNotFound(self.method.clone()));
315 };
316 resolve_namespace(namespace, self.method.clone())
317 }
318
319 pub fn new(method: &str, params: Option<Vec<Value>>) -> Self {
320 RpcRequest {
321 id: RpcRequestId::Number(1),
322 jsonrpc: "2.0".to_string(),
323 method: method.to_string(),
324 params,
325 }
326 }
327}
328
329pub fn resolve_namespace(maybe_namespace: &str, method: String) -> Result<RpcNamespace, RpcErr> {
330 RpcNamespace::from_prefix(maybe_namespace).ok_or(RpcErr::MethodNotFound(method))
331}
332
333impl Default for RpcRequest {
334 fn default() -> Self {
335 RpcRequest {
336 id: RpcRequestId::Number(1),
337 jsonrpc: "2.0".to_string(),
338 method: "".to_string(),
339 params: None,
340 }
341 }
342}
343
344#[derive(Serialize, Deserialize, Debug, Clone)]
349pub struct RpcErrorMetadata {
350 pub code: i32,
352 #[serde(skip_serializing_if = "Option::is_none")]
354 pub data: Option<String>,
355 pub message: String,
357}
358
359#[derive(Serialize, Deserialize, Debug)]
361pub struct RpcSuccessResponse {
362 pub id: RpcRequestId,
364 pub jsonrpc: String,
366 pub result: Value,
368}
369
370#[derive(Serialize, Deserialize, Debug)]
372pub struct RpcErrorResponse {
373 pub id: RpcRequestId,
375 pub jsonrpc: String,
377 pub error: RpcErrorMetadata,
379}
380
381#[derive(Deserialize, Debug)]
383#[serde(untagged)]
384pub enum RpcResponse {
385 Success(RpcSuccessResponse),
386 Error(RpcErrorResponse),
387}
388
389impl From<StoreError> for RpcErr {
391 fn from(value: StoreError) -> Self {
392 RpcErr::Internal(value.to_string())
393 }
394}
395
396impl From<EvmError> for RpcErr {
397 fn from(value: EvmError) -> Self {
398 RpcErr::Vm(value.to_string())
399 }
400}
401
402pub fn get_message_from_revert_data(data: &str) -> Result<String, EthClientError> {
403 if data == "0x" {
404 Ok("Execution reverted without a reason string.".to_owned())
405 } else if data.len() == 10 {
407 Ok(data.to_owned())
408 } else {
409 let abi_decoded_error_data =
410 hex::decode(data.strip_prefix("0x").ok_or(EthClientError::Custom(
411 "Failed to strip_prefix when getting message from revert data".to_owned(),
412 ))?)
413 .map_err(|_| {
414 EthClientError::Custom(
415 "Failed to hex::decode when getting message from revert data".to_owned(),
416 )
417 })?;
418 let string_length = U256::from_big_endian(abi_decoded_error_data.get(36..68).ok_or(
419 EthClientError::Custom(
420 "Failed to slice index abi_decoded_error_data when getting message from revert data".to_owned(),
421 ),
422 )?);
423 let string_len = usize::try_from(string_length).map_err(|_| {
424 EthClientError::Custom(
425 "Failed to convert string_length to usize when getting message from revert data"
426 .to_owned(),
427 )
428 })?;
429 let string_data = abi_decoded_error_data
430 .get(68..68 + string_len)
431 .ok_or(EthClientError::Custom(
432 "Failed to slice index abi_decoded_error_data when getting message from revert data"
433 .to_owned(),
434 ))?;
435 String::from_utf8(string_data.to_vec()).map_err(|_| {
436 EthClientError::Custom(
437 "Failed to String::from_utf8 when getting message from revert data".to_owned(),
438 )
439 })
440 }
441}
442
443pub fn parse_json_hex(hex: &serde_json::Value) -> Result<u64, String> {
444 if let Value::String(maybe_hex) = hex {
445 let trimmed = maybe_hex.trim_start_matches("0x");
446 let maybe_parsed = u64::from_str_radix(trimmed, 16);
447 maybe_parsed.map_err(|_| format!("Could not parse given hex {maybe_hex}"))
448 } else {
449 Err(format!("Could not parse given hex {hex}"))
450 }
451}