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}
28
29impl EthErrors {
30 pub fn execution_reverted(exit_code: ExitCode, reason: &str, error: &str, data: &[u8]) -> Self {
32 let revert_reason = if reason.is_empty() {
33 String::new()
34 } else {
35 format!(", revert reason=[{reason}]")
36 };
37
38 Self::ExecutionReverted {
39 message: format!(
40 "message execution failed (exit=[{exit_code}]{revert_reason}, vm error=[{error}])"
41 ),
42 data: format!("0x{}", hex::encode(data)),
43 }
44 }
45
46 pub fn limit_exceeded(max_block_range: i64, given: i64) -> Self {
47 Self::BlockRangeExceeded {
48 max: max_block_range,
49 given,
50 message: format!("block range exceeds maximum of {max_block_range} (got {given})"),
51 }
52 }
53}
54
55impl RpcErrorData for EthErrors {
56 fn error_code(&self) -> Option<i32> {
57 match self {
58 EthErrors::ExecutionReverted { .. } => Some(EXECUTION_REVERTED_CODE),
59 EthErrors::BlockRangeExceeded { .. } => Some(LIMIT_EXCEEDED_CODE),
60 }
61 }
62
63 fn error_message(&self) -> Option<String> {
64 match self {
65 EthErrors::ExecutionReverted { message, .. } => Some(message.clone()),
66 EthErrors::BlockRangeExceeded { message, .. } => Some(message.clone()),
67 }
68 }
69
70 fn error_data(&self) -> Option<serde_json::Value> {
71 match self {
72 EthErrors::ExecutionReverted { data, .. } => {
73 Some(serde_json::Value::String(data.clone()))
74 }
75 EthErrors::BlockRangeExceeded { .. } => None,
76 }
77 }
78}
79
80#[cfg(test)]
81mod tests {
82 use super::*;
83 use crate::rpc::error::ServerError;
84
85 #[test]
86 fn test_block_range_exceeded_converts_to_server_error_with_correct_code() {
87 let err = EthErrors::limit_exceeded(100, 500);
88 let server_err: ServerError = err.into();
89
90 assert_eq!(server_err.inner().code(), LIMIT_EXCEEDED_CODE);
91 assert_eq!(
92 server_err.message(),
93 "block range exceeds maximum of 100 (got 500)"
94 );
95 }
96
97 #[test]
98 fn test_block_range_exceeded_via_anyhow_preserves_code() {
99 let eth_err = EthErrors::limit_exceeded(2880, 5000);
100 let anyhow_err: anyhow::Error = eth_err.into();
101 let server_err: ServerError = anyhow_err.into();
102
103 assert_eq!(server_err.inner().code(), LIMIT_EXCEEDED_CODE);
104 assert_eq!(
105 server_err.message(),
106 "block range exceeds maximum of 2880 (got 5000)"
107 );
108 }
109}