miden_client/rpc/
errors.rs1use alloc::boxed::Box;
2use alloc::string::{String, ToString};
3use core::error::Error;
4use core::num::TryFromIntError;
5
6use miden_objects::NoteError;
7use miden_objects::account::AccountId;
8use miden_objects::crypto::merkle::MerkleError;
9use miden_objects::note::NoteId;
10use miden_objects::utils::DeserializationError;
11use thiserror::Error;
12
13use super::NodeRpcClientEndpoint;
14
15#[derive(Debug, Error)]
19pub enum RpcError {
20 #[error("accept header validation failed: {0}")]
21 AcceptHeaderError(#[from] AcceptHeaderError),
22 #[error("rpc api response contained an update for a private account: {0}")]
23 AccountUpdateForPrivateAccountReceived(AccountId),
24 #[error("failed to connect to the api server: {0}")]
25 ConnectionError(#[source] Box<dyn Error + Send + Sync + 'static>),
26 #[error("failed to deserialize rpc data: {0}")]
27 DeserializationError(String),
28 #[error("rpc api response missing an expected field: {0}")]
29 ExpectedDataMissing(String),
30 #[error("rpc api response is invalid: {0}")]
31 InvalidResponse(String),
32 #[error("grpc request failed for {endpoint}: {error_kind}")]
33 GrpcError {
34 endpoint: NodeRpcClientEndpoint,
35 error_kind: GrpcError,
36 #[source]
37 source: Option<Box<dyn Error + Send + Sync + 'static>>,
38 },
39 #[error("note with id {0} was not found")]
40 NoteNotFound(NoteId),
41 #[error("invalid node endpoint: {0}")]
42 InvalidNodeEndpoint(String),
43}
44
45impl From<DeserializationError> for RpcError {
46 fn from(err: DeserializationError) -> Self {
47 Self::DeserializationError(err.to_string())
48 }
49}
50
51impl From<NoteError> for RpcError {
52 fn from(err: NoteError) -> Self {
53 Self::DeserializationError(err.to_string())
54 }
55}
56
57impl From<RpcConversionError> for RpcError {
58 fn from(err: RpcConversionError) -> Self {
59 Self::DeserializationError(err.to_string())
60 }
61}
62
63#[derive(Debug, Error)]
67pub enum RpcConversionError {
68 #[error("failed to deserialize: {0}")]
69 DeserializationError(#[from] DeserializationError),
70 #[error("value is not in the range 0..modulus")]
71 NotAValidFelt,
72 #[error("note error")]
73 NoteTypeError(#[from] NoteError),
74 #[error("merkle error")]
75 MerkleError(#[from] MerkleError),
76 #[error("failed to convert rpc data: {0}")]
77 InvalidField(String),
78 #[error("failed to convert int")]
79 InvalidInt(#[from] TryFromIntError),
80 #[error("field `{field_name}` expected to be present in protobuf representation of {entity}")]
81 MissingFieldInProtobufRepresentation {
82 entity: &'static str,
83 field_name: &'static str,
84 },
85}
86
87#[derive(Debug, Error)]
92pub enum GrpcError {
93 #[error("resource not found")]
94 NotFound,
95 #[error("invalid request parameters")]
96 InvalidArgument,
97 #[error("permission denied")]
98 PermissionDenied,
99 #[error("resource already exists")]
100 AlreadyExists,
101 #[error("resource exhausted or rate limited")]
102 ResourceExhausted,
103 #[error("precondition failed")]
104 FailedPrecondition,
105 #[error("operation was cancelled")]
106 Cancelled,
107 #[error("deadline exceeded")]
108 DeadlineExceeded,
109 #[error("service unavailable")]
110 Unavailable,
111 #[error("internal server error")]
112 Internal,
113 #[error("unimplemented method")]
114 Unimplemented,
115 #[error("unauthenticated request")]
116 Unauthenticated,
117 #[error("operation was aborted")]
118 Aborted,
119 #[error("operation was attempted past the valid range")]
120 OutOfRange,
121 #[error("unrecoverable data loss or corruption")]
122 DataLoss,
123 #[error("unknown error: {0}")]
124 Unknown(String),
125}
126
127impl GrpcError {
128 pub fn from_code(code: i32, message: Option<String>) -> Self {
131 match code {
132 1 => Self::Cancelled,
133 2 => Self::Unknown(message.unwrap_or_default()),
134 3 => Self::InvalidArgument,
135 4 => Self::DeadlineExceeded,
136 5 => Self::NotFound,
137 6 => Self::AlreadyExists,
138 7 => Self::PermissionDenied,
139 8 => Self::ResourceExhausted,
140 9 => Self::FailedPrecondition,
141 10 => Self::Aborted,
142 11 => Self::OutOfRange,
143 12 => Self::Unimplemented,
144 13 => Self::Internal,
145 14 => Self::Unavailable,
146 15 => Self::DataLoss,
147 16 => Self::Unauthenticated,
148 _ => Self::Unknown(
149 message.unwrap_or_else(|| format!("Unknown gRPC status code: {code}")),
150 ),
151 }
152 }
153}
154
155#[derive(Debug, Error)]
163pub enum AcceptHeaderError {
164 #[error("server rejected request - please check your version and network settings")]
165 NoSupportedMediaRange,
166 #[error("server rejected request - parsing error: {0}")]
167 ParsingError(String),
168}
169
170impl AcceptHeaderError {
171 pub fn try_from_message(message: &str) -> Option<Self> {
173 if message.contains(
175 "server does not support any of the specified application/vnd.miden content types",
176 ) {
177 return Some(Self::NoSupportedMediaRange);
178 }
179 if message.contains("genesis value failed to parse")
180 || message.contains("version value failed to parse")
181 {
182 return Some(Self::ParsingError(message.to_string()));
183 }
184 None
185 }
186}