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