mod account;
mod block;
mod note;
mod sync;
mod transaction;
pub use account::{GetAccountError, RegisterAccountError};
pub use block::{GetBlockByNumberError, GetBlockHeaderError};
pub use note::{GetNoteScriptByRootError, GetNotesByIdError};
pub use sync::{
NoteSyncError,
SyncAccountStorageMapsError,
SyncAccountVaultError,
SyncNullifiersError,
SyncTransactionsError,
};
use thiserror::Error;
pub use transaction::AddTransactionError;
use crate::rpc::RpcEndpoint;
use crate::rpc::errors::GrpcError;
#[derive(Debug, Clone, PartialEq, Eq, Error)]
pub enum EndpointError {
#[error(transparent)]
AddTransaction(#[from] AddTransactionError),
#[error(transparent)]
GetBlockHeader(#[from] GetBlockHeaderError),
#[error(transparent)]
GetBlockByNumber(#[from] GetBlockByNumberError),
#[error(transparent)]
NoteSync(#[from] NoteSyncError),
#[error(transparent)]
SyncNullifiers(#[from] SyncNullifiersError),
#[error(transparent)]
SyncAccountVault(#[from] SyncAccountVaultError),
#[error(transparent)]
SyncStorageMaps(#[from] SyncAccountStorageMapsError),
#[error(transparent)]
SyncTransactions(#[from] SyncTransactionsError),
#[error(transparent)]
GetNotesById(#[from] GetNotesByIdError),
#[error(transparent)]
GetNoteScriptByRoot(#[from] GetNoteScriptByRootError),
#[error(transparent)]
GetAccount(#[from] GetAccountError),
#[error(transparent)]
RegisterAccount(#[from] RegisterAccountError),
}
pub fn parse_node_error(
endpoint: &RpcEndpoint,
details: &[u8],
message: &str,
) -> Option<EndpointError> {
let code = *details.first()?;
match endpoint {
RpcEndpoint::SubmitProvenTx => {
Some(EndpointError::AddTransaction(AddTransactionError::from_code(code, message)))
},
RpcEndpoint::GetBlockHeaderByNumber => {
Some(EndpointError::GetBlockHeader(GetBlockHeaderError::from_code(code, message)))
},
RpcEndpoint::GetBlockByNumber => {
Some(EndpointError::GetBlockByNumber(GetBlockByNumberError::from_code(code, message)))
},
RpcEndpoint::SyncNotes => {
Some(EndpointError::NoteSync(NoteSyncError::from_code(code, message)))
},
RpcEndpoint::SyncNullifiers => {
Some(EndpointError::SyncNullifiers(SyncNullifiersError::from_code(code, message)))
},
RpcEndpoint::SyncAccountVault => {
Some(EndpointError::SyncAccountVault(SyncAccountVaultError::from_code(code, message)))
},
RpcEndpoint::SyncStorageMaps => Some(EndpointError::SyncStorageMaps(
SyncAccountStorageMapsError::from_code(code, message),
)),
RpcEndpoint::SyncTransactions => {
Some(EndpointError::SyncTransactions(SyncTransactionsError::from_code(code, message)))
},
RpcEndpoint::GetNotesById => {
Some(EndpointError::GetNotesById(GetNotesByIdError::from_code(code, message)))
},
RpcEndpoint::GetNoteScriptByRoot => Some(EndpointError::GetNoteScriptByRoot(
GetNoteScriptByRootError::from_code(code, message),
)),
RpcEndpoint::GetAccount => {
Some(EndpointError::GetAccount(GetAccountError::from_code(code, message)))
},
RpcEndpoint::SyncChainMmr
| RpcEndpoint::Status
| RpcEndpoint::GetLimits
| RpcEndpoint::GetNetworkNoteStatus
| RpcEndpoint::GetTransactionEncryptionKey
| RpcEndpoint::RegisterAccount
| RpcEndpoint::IsAccountAllowed
| RpcEndpoint::SubmitProvenBatch => None,
}
}
pub fn parse_status_error(
endpoint: &RpcEndpoint,
error_kind: &GrpcError,
message: &str,
) -> Option<EndpointError> {
match endpoint {
RpcEndpoint::RegisterAccount => RegisterAccountError::from_grpc_error(error_kind, message)
.map(EndpointError::RegisterAccount),
RpcEndpoint::SubmitProvenTx
| RpcEndpoint::GetBlockHeaderByNumber
| RpcEndpoint::GetBlockByNumber
| RpcEndpoint::SyncNotes
| RpcEndpoint::SyncNullifiers
| RpcEndpoint::SyncAccountVault
| RpcEndpoint::SyncStorageMaps
| RpcEndpoint::SyncTransactions
| RpcEndpoint::GetNotesById
| RpcEndpoint::GetNoteScriptByRoot
| RpcEndpoint::GetAccount
| RpcEndpoint::SyncChainMmr
| RpcEndpoint::Status
| RpcEndpoint::GetLimits
| RpcEndpoint::GetNetworkNoteStatus
| RpcEndpoint::GetTransactionEncryptionKey
| RpcEndpoint::IsAccountAllowed
| RpcEndpoint::SubmitProvenBatch => None,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn only_the_register_account_endpoint_classifies_a_status_code() {
let registration =
parse_status_error(&RpcEndpoint::RegisterAccount, &GrpcError::NotFound, "unknown");
assert!(matches!(
registration,
Some(EndpointError::RegisterAccount(RegisterAccountError::InvitationNotFound))
));
for endpoint in [
RpcEndpoint::GetAccount,
RpcEndpoint::SubmitProvenTx,
RpcEndpoint::GetNotesById,
RpcEndpoint::Status,
] {
assert!(
parse_status_error(&endpoint, &GrpcError::NotFound, "unknown").is_none(),
"{endpoint:?} must not classify a status code"
);
}
}
#[test]
fn a_transport_failure_on_the_registration_endpoint_stays_unclassified() {
assert!(
parse_status_error(
&RpcEndpoint::RegisterAccount,
&GrpcError::Unavailable,
"node is down"
)
.is_none()
);
}
}