1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
// Copyright 2019-2024 ChainSafe Systems
// SPDX-License-Identifier: Apache-2.0, MIT

use std::fmt::{self, Display};

use jsonrpsee::{
    core::ClientError,
    types::error::{self, ErrorCode, ErrorObjectOwned},
};

/// An error returned _by the remote server_, not due to e.g serialization errors,
/// protocol errors, or the connection failing.
#[derive(derive_more::From, derive_more::Into, Debug, PartialEq)]
pub struct ServerError {
    inner: ErrorObjectOwned,
}

/// According to the [JSON-RPC 2.0 spec](https://www.jsonrpc.org/specification#response_object),
/// the error codes from -32000 to -32099 are reserved for implementation-defined server-errors.
/// We define them here.
pub(crate) mod implementation_defined_errors {
    /// This error indicates that the method is not supported by the current version of the Forest
    /// node. Note that it's not the same as not found, as we are explicitly not supporting it,
    /// e.g., because it's deprecated or Lotus is doing the same.
    pub(crate) const UNSUPPORTED_METHOD: i32 = -32001;
}

impl ServerError {
    pub fn new(
        code: i32,
        message: impl Display,
        data: impl Into<Option<serde_json::Value>>,
    ) -> Self {
        Self {
            inner: ErrorObjectOwned::owned(code, message.to_string(), data.into()),
        }
    }
    pub fn message(&self) -> &str {
        self.inner.message()
    }
    pub fn known_code(&self) -> ErrorCode {
        self.inner.code().into()
    }
    /// We are only including this method to get the JSON Schemas for our OpenRPC
    /// machinery
    pub fn stubbed_for_openrpc() -> Self {
        Self::new(
            4528,
            "unimplemented",
            Some(
                "This method is stubbed as part of https://github.com/ChainSafe/forest/issues/4528"
                    .into(),
            ),
        )
    }

    pub fn unsupported_method() -> Self {
        Self::new(
            implementation_defined_errors::UNSUPPORTED_METHOD,
            "unsupported method",
            Some("This method is not supported by the current version of the Forest node".into()),
        )
    }
}

impl Display for ServerError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str("JSON-RPC error:\n")?;
        f.write_fmt(format_args!("\tcode: {}\n", self.inner.code()))?;
        f.write_fmt(format_args!("\tmessage: {}\n", self.inner.message()))?;
        if let Some(data) = self.inner.data() {
            f.write_fmt(format_args!("\tdata: {}\n", data))?
        }
        Ok(())
    }
}

impl std::error::Error for ServerError {}

macro_rules! ctor {
    ($($ctor:ident { $code:expr })*) => {
        $(
            impl ServerError {
                pub fn $ctor(message: impl Display, data: impl Into<Option<serde_json::Value>>) -> Self {
                    Self::new($code, message, data)
                }
            }
        )*
    }
}

ctor! {
    parse_error { error::PARSE_ERROR_CODE }
    internal_error { error::INTERNAL_ERROR_CODE }
    invalid_params { error::INVALID_PARAMS_CODE }
    method_not_found { error::METHOD_NOT_FOUND_CODE }
}

macro_rules! from2internal {
    ($($ty:ty),* $(,)?) => {
        $(
            impl From<$ty> for ServerError {
                fn from(it: $ty) -> Self {
                    Self::internal_error(it, None)
                }
            }
        )*
    };
}

// TODO(forest): https://github.com/ChainSafe/forest/issues/3965
//               Just mapping everything to an internal error is not appropriate
from2internal! {
    anyhow::Error,
    base64::DecodeError,
    cid::multibase::Error,
    crate::chain::store::Error,
    crate::key_management::Error,
    crate::libp2p::ParseError,
    crate::message_pool::Error,
    crate::state_manager::Error,
    fil_actors_shared::fvm_ipld_amt::Error,
    futures::channel::oneshot::Canceled,
    fvm_ipld_encoding::Error,
    fvm_shared4::address::Error,
    jsonwebtoken::errors::Error,
    std::io::Error,
    std::time::SystemTimeError,
    tokio::task::JoinError,
    fil_actors_shared::fvm_ipld_hamt::Error,
    flume::RecvError,
    fil_actors_shared::v12::ActorError,
    fil_actors_shared::v13::ActorError,
    fil_actors_shared::v14::ActorError,
    serde_json::Error,
    jsonrpsee::core::client::error::Error,
}

impl From<ServerError> for ClientError {
    fn from(value: ServerError) -> Self {
        Self::Call(value.inner)
    }
}

impl<T> From<flume::SendError<T>> for ServerError {
    fn from(e: flume::SendError<T>) -> Self {
        Self::internal_error(e, None)
    }
}

impl<T> From<tokio::sync::mpsc::error::SendError<T>> for ServerError {
    fn from(e: tokio::sync::mpsc::error::SendError<T>) -> Self {
        Self::internal_error(e, None)
    }
}