reth_rpc_server_types/
result.rs1use std::fmt;
4
5use alloy_rpc_types_engine::PayloadError;
6use jsonrpsee_core::RpcResult;
7use reth_errors::ConsensusError;
8
9pub trait ToRpcResult<Ok, Err>: Sized {
11 fn to_rpc_result(self) -> RpcResult<Ok>
14 where
15 Err: fmt::Display,
16 {
17 self.map_internal_err(|err| err.to_string())
18 }
19
20 fn map_rpc_err<'a, F, M>(self, op: F) -> RpcResult<Ok>
22 where
23 F: FnOnce(Err) -> (i32, M, Option<&'a [u8]>),
24 M: Into<String>;
25
26 fn map_internal_err<F, M>(self, op: F) -> RpcResult<Ok>
29 where
30 F: FnOnce(Err) -> M,
31 M: Into<String>;
32
33 fn map_internal_err_with_data<'a, F, M>(self, op: F) -> RpcResult<Ok>
36 where
37 F: FnOnce(Err) -> (M, &'a [u8]),
38 M: Into<String>;
39
40 fn with_message(self, msg: &str) -> RpcResult<Ok>;
44}
45
46#[macro_export]
48macro_rules! impl_to_rpc_result {
49 ($err:ty) => {
50 impl<Ok> ToRpcResult<Ok, $err> for Result<Ok, $err> {
51 #[inline]
52 fn map_rpc_err<'a, F, M>(self, op: F) -> jsonrpsee_core::RpcResult<Ok>
53 where
54 F: FnOnce($err) -> (i32, M, Option<&'a [u8]>),
55 M: Into<String>,
56 {
57 match self {
58 Ok(t) => Ok(t),
59 Err(err) => {
60 let (code, msg, data) = op(err);
61 Err($crate::result::rpc_err(code, msg, data))
62 }
63 }
64 }
65
66 #[inline]
67 fn map_internal_err<F, M>(self, op: F) -> jsonrpsee_core::RpcResult<Ok>
68 where
69 F: FnOnce($err) -> M,
70 M: Into<String>,
71 {
72 self.map_err(|err| $crate::result::internal_rpc_err(op(err)))
73 }
74
75 #[inline]
76 fn map_internal_err_with_data<'a, F, M>(self, op: F) -> jsonrpsee_core::RpcResult<Ok>
77 where
78 F: FnOnce($err) -> (M, &'a [u8]),
79 M: Into<String>,
80 {
81 match self {
82 Ok(t) => Ok(t),
83 Err(err) => {
84 let (msg, data) = op(err);
85 Err($crate::result::internal_rpc_err_with_data(msg, data))
86 }
87 }
88 }
89
90 #[inline]
91 fn with_message(self, msg: &str) -> jsonrpsee_core::RpcResult<Ok> {
92 match self {
93 Ok(t) => Ok(t),
94 Err(err) => {
95 let msg = format!("{msg}: {err}");
96 Err($crate::result::internal_rpc_err(msg))
97 }
98 }
99 }
100 }
101 };
102}
103
104impl_to_rpc_result!(PayloadError);
105impl_to_rpc_result!(ConsensusError);
106impl_to_rpc_result!(reth_errors::RethError);
107impl_to_rpc_result!(reth_errors::ProviderError);
108impl_to_rpc_result!(reth_network_api::NetworkError);
109
110pub fn invalid_params_rpc_err(
112 msg: impl Into<String>,
113) -> jsonrpsee_types::error::ErrorObject<'static> {
114 rpc_err(jsonrpsee_types::error::INVALID_PARAMS_CODE, msg, None)
115}
116
117pub fn internal_rpc_err(msg: impl Into<String>) -> jsonrpsee_types::error::ErrorObject<'static> {
119 rpc_err(jsonrpsee_types::error::INTERNAL_ERROR_CODE, msg, None)
120}
121
122pub fn internal_rpc_err_with_data(
124 msg: impl Into<String>,
125 data: &[u8],
126) -> jsonrpsee_types::error::ErrorObject<'static> {
127 rpc_err(jsonrpsee_types::error::INTERNAL_ERROR_CODE, msg, Some(data))
128}
129
130pub fn rpc_error_with_code(
132 code: i32,
133 msg: impl Into<String>,
134) -> jsonrpsee_types::error::ErrorObject<'static> {
135 rpc_err(code, msg, None)
136}
137
138pub fn rpc_err(
140 code: i32,
141 msg: impl Into<String>,
142 data: Option<&[u8]>,
143) -> jsonrpsee_types::error::ErrorObject<'static> {
144 jsonrpsee_types::error::ErrorObject::owned(
145 code,
146 msg.into(),
147 data.map(|data| {
148 jsonrpsee_core::to_json_raw_value(&alloy_primitives::hex::encode_prefixed(data))
149 .expect("serializing String can't fail")
150 }),
151 )
152}
153
154#[cfg(test)]
155mod tests {
156 use super::*;
157 use reth_errors::{RethError, RethResult};
158
159 const fn assert_rpc_result<T, E, TRR: ToRpcResult<T, E>>() {}
160
161 #[test]
162 fn can_convert_rpc() {
163 assert_rpc_result::<(), RethError, RethResult<()>>();
164
165 let res = RethResult::Ok(100);
166 let rpc_res = res.map_internal_err(|_| "This is a message");
167 let val = rpc_res.unwrap();
168 assert_eq!(val, 100);
169 }
170}