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/// Code is taken from https://github.com/filecoin-project/lotus/blob/release/v1.32.1/api/api_errors.go#L27
12pub const EXECUTION_REVERTED_CODE: i32 = 11;
13
14#[derive(Clone, Debug, Error, Serialize)]
15pub enum EthErrors {
16    #[error("{message}")]
17    ExecutionReverted {
18        message: String,
19        data: Option<String>,
20    },
21}
22
23impl EthErrors {
24    /// Create a new ExecutionReverted error with formatted message
25    pub fn execution_reverted(exit_code: ExitCode, reason: &str, error: &str, data: &[u8]) -> Self {
26        let revert_reason = if reason.is_empty() {
27            String::new()
28        } else {
29            format!(", revert reason=[{reason}]")
30        };
31
32        Self::ExecutionReverted {
33            message: format!(
34                "message execution failed (exit=[{exit_code}]{revert_reason}, vm error=[{error}])"
35            ),
36            data: (!data.is_empty()).then(|| format!("0x{}", hex::encode(data))),
37        }
38    }
39}
40
41impl RpcErrorData for EthErrors {
42    fn error_code(&self) -> Option<i32> {
43        match self {
44            EthErrors::ExecutionReverted { .. } => Some(EXECUTION_REVERTED_CODE),
45        }
46    }
47
48    fn error_message(&self) -> Option<String> {
49        match self {
50            EthErrors::ExecutionReverted { message, .. } => Some(message.clone()),
51        }
52    }
53
54    fn error_data(&self) -> Option<serde_json::Value> {
55        match self {
56            EthErrors::ExecutionReverted { data, .. } => {
57                data.clone().map(serde_json::Value::String)
58            }
59        }
60    }
61}