miden_client/rpc/errors/node/
mod.rs1mod account;
2mod block;
3mod note;
4mod sync;
5mod transaction;
6
7pub use account::{GetAccountError, RegisterAccountError};
8pub use block::{GetBlockByNumberError, GetBlockHeaderError};
9pub use note::{GetNoteScriptByRootError, GetNotesByIdError};
10pub use sync::{
11 NoteSyncError,
12 SyncAccountStorageMapsError,
13 SyncAccountVaultError,
14 SyncChainMmrError,
15 SyncNullifiersError,
16 SyncTransactionsError,
17};
18use thiserror::Error;
19pub use transaction::AddTransactionError;
20
21use crate::rpc::RpcEndpoint;
22use crate::rpc::errors::GrpcError;
23
24#[derive(Debug, Clone, PartialEq, Eq, Error)]
28pub enum EndpointError {
29 #[error(transparent)]
31 AddTransaction(#[from] AddTransactionError),
32 #[error(transparent)]
34 GetBlockHeader(#[from] GetBlockHeaderError),
35 #[error(transparent)]
37 GetBlockByNumber(#[from] GetBlockByNumberError),
38 #[error(transparent)]
40 NoteSync(#[from] NoteSyncError),
41 #[error(transparent)]
43 SyncNullifiers(#[from] SyncNullifiersError),
44 #[error(transparent)]
46 SyncAccountVault(#[from] SyncAccountVaultError),
47 #[error(transparent)]
49 SyncStorageMaps(#[from] SyncAccountStorageMapsError),
50 #[error(transparent)]
52 SyncTransactions(#[from] SyncTransactionsError),
53 #[error(transparent)]
55 SyncChainMmr(#[from] SyncChainMmrError),
56 #[error(transparent)]
58 GetNotesById(#[from] GetNotesByIdError),
59 #[error(transparent)]
61 GetNoteScriptByRoot(#[from] GetNoteScriptByRootError),
62 #[error(transparent)]
64 GetAccount(#[from] GetAccountError),
65 #[error(transparent)]
67 RegisterAccount(#[from] RegisterAccountError),
68}
69
70pub fn parse_node_error(
74 endpoint: &RpcEndpoint,
75 details: &[u8],
76 message: &str,
77) -> Option<EndpointError> {
78 let code = *details.first()?;
79
80 match endpoint {
81 RpcEndpoint::SubmitProvenTx | RpcEndpoint::SubmitProvenBatch => {
82 Some(EndpointError::AddTransaction(AddTransactionError::from_code(code, message)))
83 },
84 RpcEndpoint::GetBlockHeaderByNumber => {
85 Some(EndpointError::GetBlockHeader(GetBlockHeaderError::from_code(code, message)))
86 },
87 RpcEndpoint::GetBlockByNumber => {
88 Some(EndpointError::GetBlockByNumber(GetBlockByNumberError::from_code(code, message)))
89 },
90 RpcEndpoint::SyncNotes => {
91 Some(EndpointError::NoteSync(NoteSyncError::from_code(code, message)))
92 },
93 RpcEndpoint::SyncNullifiers => {
94 Some(EndpointError::SyncNullifiers(SyncNullifiersError::from_code(code, message)))
95 },
96 RpcEndpoint::SyncAccountVault => {
97 Some(EndpointError::SyncAccountVault(SyncAccountVaultError::from_code(code, message)))
98 },
99 RpcEndpoint::SyncStorageMaps => Some(EndpointError::SyncStorageMaps(
100 SyncAccountStorageMapsError::from_code(code, message),
101 )),
102 RpcEndpoint::SyncTransactions => {
103 Some(EndpointError::SyncTransactions(SyncTransactionsError::from_code(code, message)))
104 },
105 RpcEndpoint::GetNotesById => {
106 Some(EndpointError::GetNotesById(GetNotesByIdError::from_code(code, message)))
107 },
108 RpcEndpoint::GetNoteScriptByRoot => Some(EndpointError::GetNoteScriptByRoot(
109 GetNoteScriptByRootError::from_code(code, message),
110 )),
111 RpcEndpoint::GetAccount => {
112 Some(EndpointError::GetAccount(GetAccountError::from_code(code, message)))
113 },
114 RpcEndpoint::SyncChainMmr => {
115 Some(EndpointError::SyncChainMmr(SyncChainMmrError::from_code(code, message)))
116 },
117 RpcEndpoint::Status
119 | RpcEndpoint::GetLimits
120 | RpcEndpoint::GetNetworkNoteStatus
121 | RpcEndpoint::GetTransactionEncryptionKey
122 | RpcEndpoint::RegisterAccount
123 | RpcEndpoint::IsAccountAllowed
124 | RpcEndpoint::IsInvitationCodeValid => None,
125 }
126}
127
128pub fn parse_status_error(
130 endpoint: &RpcEndpoint,
131 error_kind: &GrpcError,
132 message: &str,
133) -> Option<EndpointError> {
134 match endpoint {
137 RpcEndpoint::RegisterAccount => RegisterAccountError::from_grpc_error(error_kind, message)
138 .map(EndpointError::RegisterAccount),
139 RpcEndpoint::SubmitProvenTx
140 | RpcEndpoint::GetBlockHeaderByNumber
141 | RpcEndpoint::GetBlockByNumber
142 | RpcEndpoint::SyncNotes
143 | RpcEndpoint::SyncNullifiers
144 | RpcEndpoint::SyncAccountVault
145 | RpcEndpoint::SyncStorageMaps
146 | RpcEndpoint::SyncTransactions
147 | RpcEndpoint::GetNotesById
148 | RpcEndpoint::GetNoteScriptByRoot
149 | RpcEndpoint::GetAccount
150 | RpcEndpoint::SyncChainMmr
151 | RpcEndpoint::Status
152 | RpcEndpoint::GetLimits
153 | RpcEndpoint::GetNetworkNoteStatus
154 | RpcEndpoint::GetTransactionEncryptionKey
155 | RpcEndpoint::IsAccountAllowed
156 | RpcEndpoint::IsInvitationCodeValid
157 | RpcEndpoint::SubmitProvenBatch => None,
158 }
159}
160
161#[cfg(test)]
165mod tests {
166 use super::*;
167
168 #[test]
172 fn only_the_register_account_endpoint_classifies_a_status_code() {
173 let registration =
174 parse_status_error(&RpcEndpoint::RegisterAccount, &GrpcError::NotFound, "unknown");
175
176 assert!(matches!(
177 registration,
178 Some(EndpointError::RegisterAccount(RegisterAccountError::InvitationNotFound))
179 ));
180
181 for endpoint in [
182 RpcEndpoint::GetAccount,
183 RpcEndpoint::SubmitProvenTx,
184 RpcEndpoint::GetNotesById,
185 RpcEndpoint::Status,
186 ] {
187 assert!(
188 parse_status_error(&endpoint, &GrpcError::NotFound, "unknown").is_none(),
189 "{endpoint:?} must not classify a status code"
190 );
191 }
192 }
193
194 #[test]
197 fn a_transport_failure_on_the_registration_endpoint_stays_unclassified() {
198 assert!(
199 parse_status_error(
200 &RpcEndpoint::RegisterAccount,
201 &GrpcError::Unavailable,
202 "node is down"
203 )
204 .is_none()
205 );
206 }
207
208 #[test]
211 fn a_block_after_the_chain_tip_parses_as_future_block() {
212 let message = "block_to (5) is greater than chain tip (4)";
213 assert_eq!(
214 parse_node_error(&RpcEndpoint::SyncNotes, &[2], message),
215 Some(EndpointError::NoteSync(NoteSyncError::FutureBlock))
216 );
217 assert_eq!(
218 parse_node_error(&RpcEndpoint::SyncChainMmr, &[2], message),
219 Some(EndpointError::SyncChainMmr(SyncChainMmrError::FutureBlock))
220 );
221 assert_eq!(
222 parse_node_error(&RpcEndpoint::SyncNullifiers, &[4], message),
223 Some(EndpointError::SyncNullifiers(SyncNullifiersError::FutureBlock))
224 );
225 assert_eq!(
226 parse_node_error(&RpcEndpoint::SyncAccountVault, &[4], message),
227 Some(EndpointError::SyncAccountVault(SyncAccountVaultError::FutureBlock))
228 );
229 assert_eq!(
230 parse_node_error(&RpcEndpoint::SyncStorageMaps, &[5], message),
231 Some(EndpointError::SyncStorageMaps(SyncAccountStorageMapsError::FutureBlock))
232 );
233 assert_eq!(
234 parse_node_error(&RpcEndpoint::SyncTransactions, &[5], message),
235 Some(EndpointError::SyncTransactions(SyncTransactionsError::FutureBlock))
236 );
237 }
238}