1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
// Copyright (c) 2023 MASSA LABS <info@massa.net>

use std::error::Error;

use displaydoc::Display;

use massa_consensus_exports::error::ConsensusError;
use massa_execution_exports::ExecutionError;
use massa_hash::MassaHashError;
use massa_models::error::ModelsError;
use massa_protocol_exports::ProtocolError;
use massa_signature::MassaSignatureError;
use massa_time::TimeError;
use massa_versioning::versioning_factory::FactoryError;
use massa_wallet::WalletError;
use tracing::error;

/// Errors of the gRPC component.
#[non_exhaustive]
#[derive(Display, thiserror::Error, Debug)]
pub enum GrpcError {
    /// `massa_hash` error: {0}
    MassaHashError(#[from] MassaHashError),
    /// `massa_hash` error: {0}
    MassaSignatureError(#[from] MassaSignatureError),
    /// consensus error: {0}
    ConsensusError(#[from] ConsensusError),
    /// execution error: {0}
    ExecutionError(#[from] ExecutionError),
    /// Protocol error: {0}
    ProtocolError(#[from] ProtocolError),
    /// Reflection error : {0}
    ReflectionError(#[from] tonic_reflection::server::Error),
    /// Models error: {0}
    ModelsError(#[from] ModelsError),
    /// Time error: {0}
    TimeError(#[from] TimeError),
    /// Versioning factory error: {0}
    FactoryError(#[from] FactoryError),
    /// Wallet error: {0}
    WalletError(#[from] WalletError),
    /// Internal server error: {0}
    InternalServerError(String),
    /// Invalid argument error: {0}
    InvalidArgument(String),
    /// Not implemented error: {0}
    Unimplemented(String),
}

impl From<GrpcError> for tonic::Status {
    fn from(error: GrpcError) -> Self {
        error!("{}", error);
        match error {
            GrpcError::MassaHashError(e) => tonic::Status::internal(e.to_string()),
            GrpcError::MassaSignatureError(e) => tonic::Status::internal(e.to_string()),
            GrpcError::ConsensusError(e) => tonic::Status::internal(e.to_string()),
            GrpcError::ExecutionError(e) => tonic::Status::internal(e.to_string()),
            GrpcError::ProtocolError(e) => tonic::Status::internal(e.to_string()),
            GrpcError::ModelsError(e) => tonic::Status::internal(e.to_string()),
            GrpcError::TimeError(e) => tonic::Status::internal(e.to_string()),
            GrpcError::FactoryError(e) => tonic::Status::internal(e.to_string()),
            GrpcError::WalletError(e) => tonic::Status::internal(e.to_string()),
            GrpcError::InternalServerError(e) => tonic::Status::internal(e),
            GrpcError::ReflectionError(e) => tonic::Status::internal(e.to_string()),
            GrpcError::InvalidArgument(e) => tonic::Status::invalid_argument(e),
            GrpcError::Unimplemented(e) => tonic::Status::unimplemented(e),
        }
    }
}

/// returns the first IO error found
pub fn match_for_io_error(err_status: &tonic::Status) -> Option<&std::io::Error> {
    let mut err: &(dyn Error + 'static) = err_status;

    loop {
        if let Some(io_err) = err.downcast_ref::<std::io::Error>() {
            return Some(io_err);
        }

        // h2::Error do not expose std::io::Error with `source()`
        // https://github.com/hyperium/h2/pull/462
        if let Some(h2_err) = err.downcast_ref::<h2::Error>() {
            if let Some(io_err) = h2_err.get_io() {
                return Some(io_err);
            }
        }

        err = match err.source() {
            Some(err) => err,
            None => return None,
        };
    }
}