Skip to main content

forest/rpc/methods/eth/
errors.rs

1// Copyright 2019-2026 ChainSafe Systems
2// SPDX-License-Identifier: Apache-2.0, MIT
3
4use crate::rpc::error::RpcErrorData;
5use crate::shim::error::ExitCode;
6use serde::Serialize;
7use std::fmt::Debug;
8use thiserror::Error;
9
10/// This error indicates that the execution reverted while executing the message.
11/// Error code 3 was introduced in geth v1.9.15 and is now expected by most Ethereum ecosystem tooling for automatic ABI decoding of revert reasons from the error data field.
12pub const EXECUTION_REVERTED_CODE: i32 = 3;
13
14#[derive(Clone, Debug, Error, Serialize)]
15pub enum EthErrors {
16    #[error("{message}")]
17    ExecutionReverted { message: String, data: String },
18}
19
20impl EthErrors {
21    /// Create a new ExecutionReverted error with formatted message
22    pub fn execution_reverted(exit_code: ExitCode, reason: &str, error: &str, data: &[u8]) -> Self {
23        let revert_reason = if reason.is_empty() {
24            String::new()
25        } else {
26            format!(", revert reason=[{reason}]")
27        };
28
29        Self::ExecutionReverted {
30            message: format!(
31                "message execution failed (exit=[{exit_code}]{revert_reason}, vm error=[{error}])"
32            ),
33            data: format!("0x{}", hex::encode(data)),
34        }
35    }
36}
37
38impl RpcErrorData for EthErrors {
39    fn error_code(&self) -> Option<i32> {
40        match self {
41            EthErrors::ExecutionReverted { .. } => Some(EXECUTION_REVERTED_CODE),
42        }
43    }
44
45    fn error_message(&self) -> Option<String> {
46        match self {
47            EthErrors::ExecutionReverted { message, .. } => Some(message.clone()),
48        }
49    }
50
51    fn error_data(&self) -> Option<serde_json::Value> {
52        match self {
53            EthErrors::ExecutionReverted { data, .. } => {
54                Some(serde_json::Value::String(data.clone()))
55            }
56        }
57    }
58}