massa_grpc/
error.rs

1// Copyright (c) 2023 MASSA LABS <info@massa.net>
2
3use std::error::Error;
4
5use displaydoc::Display;
6
7use massa_consensus_exports::error::ConsensusError;
8use massa_execution_exports::ExecutionError;
9use massa_hash::MassaHashError;
10use massa_models::error::ModelsError;
11use massa_protocol_exports::ProtocolError;
12use massa_signature::MassaSignatureError;
13use massa_time::TimeError;
14use massa_versioning::versioning_factory::FactoryError;
15use massa_wallet::WalletError;
16use tracing::error;
17
18/// Errors of the gRPC component.
19#[non_exhaustive]
20#[derive(Display, thiserror::Error, Debug)]
21pub enum GrpcError {
22    /// `massa_hash` error: {0}
23    MassaHashError(#[from] MassaHashError),
24    /// `massa_hash` error: {0}
25    MassaSignatureError(#[from] MassaSignatureError),
26    /// consensus error: {0}
27    ConsensusError(#[from] ConsensusError),
28    /// execution error: {0}
29    ExecutionError(#[from] ExecutionError),
30    /// Protocol error: {0}
31    ProtocolError(#[from] ProtocolError),
32    /// Reflection error : {0}
33    ReflectionError(#[from] tonic_reflection::server::Error),
34    /// Models error: {0}
35    ModelsError(#[from] ModelsError),
36    /// Time error: {0}
37    TimeError(#[from] TimeError),
38    /// Versioning factory error: {0}
39    FactoryError(#[from] FactoryError),
40    /// Wallet error: {0}
41    WalletError(#[from] WalletError),
42    /// Internal server error: {0}
43    InternalServerError(String),
44    /// Invalid argument error: {0}
45    InvalidArgument(String),
46    /// Invalid configuration error: {0}
47    ConfigError(String),
48    /// Not implemented error: {0}
49    Unimplemented(String),
50}
51
52impl From<GrpcError> for tonic::Status {
53    fn from(error: GrpcError) -> Self {
54        error!("{}", error);
55        match error {
56            GrpcError::MassaHashError(e) => tonic::Status::internal(e.to_string()),
57            GrpcError::MassaSignatureError(e) => tonic::Status::internal(e.to_string()),
58            GrpcError::ConsensusError(e) => tonic::Status::internal(e.to_string()),
59            GrpcError::ExecutionError(e) => tonic::Status::internal(e.to_string()),
60            GrpcError::ProtocolError(e) => tonic::Status::internal(e.to_string()),
61            GrpcError::ModelsError(e) => tonic::Status::internal(e.to_string()),
62            GrpcError::TimeError(e) => tonic::Status::internal(e.to_string()),
63            GrpcError::FactoryError(e) => tonic::Status::internal(e.to_string()),
64            GrpcError::WalletError(e) => tonic::Status::internal(e.to_string()),
65            GrpcError::InternalServerError(e) => tonic::Status::internal(e),
66            GrpcError::ReflectionError(e) => tonic::Status::internal(e.to_string()),
67            GrpcError::InvalidArgument(e) => tonic::Status::invalid_argument(e),
68            GrpcError::ConfigError(e) => tonic::Status::internal(e),
69            GrpcError::Unimplemented(e) => tonic::Status::unimplemented(e),
70        }
71    }
72}
73
74/// returns the first IO error found
75pub fn match_for_io_error(err_status: &tonic::Status) -> Option<&std::io::Error> {
76    let mut err: &(dyn Error + 'static) = err_status;
77
78    loop {
79        if let Some(io_err) = err.downcast_ref::<std::io::Error>() {
80            return Some(io_err);
81        }
82
83        // h2::Error do not expose std::io::Error with `source()`
84        // https://github.com/hyperium/h2/pull/462
85        if let Some(h2_err) = err.downcast_ref::<h2::Error>() {
86            if let Some(io_err) = h2_err.get_io() {
87                return Some(io_err);
88            }
89        }
90
91        err = err.source()?;
92    }
93}