forest/rpc/methods/eth/
errors.rs1use crate::rpc::error::RpcErrorData;
5use crate::shim::error::ExitCode;
6use serde::Serialize;
7use std::fmt::Debug;
8use thiserror::Error;
9
10pub const EXECUTION_REVERTED_CODE: i32 = 3;
13pub const LIMIT_EXCEEDED_CODE: i32 = -32005;
16
17#[derive(Clone, Debug, Error, Serialize)]
18pub enum EthErrors {
19 #[error("{message}")]
20 ExecutionReverted { message: String, data: String },
21 #[error("{message}")]
22 BlockRangeExceeded {
23 max: i64,
24 given: i64,
25 message: String,
26 },
27 #[error("events for the requested block are not yet available")]
28 EventsNotYetAvailable,
29}
30
31impl EthErrors {
32 pub fn execution_reverted(exit_code: ExitCode, reason: &str, error: &str, data: &[u8]) -> Self {
34 let revert_reason = if reason.is_empty() {
35 String::new()
36 } else {
37 format!(", revert reason=[{reason}]")
38 };
39
40 Self::ExecutionReverted {
41 message: format!(
42 "message execution failed (exit=[{exit_code}]{revert_reason}, vm error=[{error}])"
43 ),
44 data: format!("0x{}", hex::encode(data)),
45 }
46 }
47
48 pub fn limit_exceeded(max_block_range: i64, given: i64) -> Self {
49 Self::BlockRangeExceeded {
50 max: max_block_range,
51 given,
52 message: format!("block range exceeds maximum of {max_block_range} (got {given})"),
53 }
54 }
55}
56
57impl RpcErrorData for EthErrors {
58 fn error_code(&self) -> Option<i32> {
59 match self {
60 EthErrors::ExecutionReverted { .. } => Some(EXECUTION_REVERTED_CODE),
61 EthErrors::BlockRangeExceeded { .. } => Some(LIMIT_EXCEEDED_CODE),
62 EthErrors::EventsNotYetAvailable => None,
63 }
64 }
65
66 fn error_message(&self) -> Option<String> {
67 match self {
68 EthErrors::ExecutionReverted { message, .. } => Some(message.clone()),
69 EthErrors::BlockRangeExceeded { message, .. } => Some(message.clone()),
70 EthErrors::EventsNotYetAvailable => Some(self.to_string()),
71 }
72 }
73
74 fn error_data(&self) -> Option<serde_json::Value> {
75 match self {
76 EthErrors::ExecutionReverted { data, .. } => {
77 Some(serde_json::Value::String(data.clone()))
78 }
79 EthErrors::BlockRangeExceeded { .. } => None,
80 EthErrors::EventsNotYetAvailable => None,
81 }
82 }
83}
84
85#[cfg(test)]
86mod tests {
87 use super::*;
88 use crate::rpc::error::ServerError;
89
90 #[test]
91 fn test_block_range_exceeded_converts_to_server_error_with_correct_code() {
92 let err = EthErrors::limit_exceeded(100, 500);
93 let server_err: ServerError = err.into();
94
95 assert_eq!(server_err.inner().code(), LIMIT_EXCEEDED_CODE);
96 assert_eq!(
97 server_err.message(),
98 "block range exceeds maximum of 100 (got 500)"
99 );
100 }
101
102 #[test]
103 fn test_block_range_exceeded_via_anyhow_preserves_code() {
104 let eth_err = EthErrors::limit_exceeded(2880, 5000);
105 let anyhow_err: anyhow::Error = eth_err.into();
106 let server_err: ServerError = anyhow_err.into();
107
108 assert_eq!(server_err.inner().code(), LIMIT_EXCEEDED_CODE);
109 assert_eq!(
110 server_err.message(),
111 "block range exceeds maximum of 2880 (got 5000)"
112 );
113 }
114
115 #[test]
116 fn test_events_not_yet_available_converts_to_server_error() {
117 let err = EthErrors::EventsNotYetAvailable;
118 let server_err: ServerError = err.into();
119
120 assert_eq!(
122 server_err.message(),
123 "events for the requested block are not yet available"
124 );
125 }
126}