• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

tari-project / tari / 16123384529

07 Jul 2025 05:11PM UTC coverage: 64.327% (-7.6%) from 71.89%
16123384529

push

github

web-flow
chore: new release v4.9.0-pre.0 (#7289)

Description
---
new release esmeralda

77151 of 119935 relevant lines covered (64.33%)

227108.34 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

43.9
/comms/core/src/protocol/rpc/error.rs
1
//  Copyright 2020, The Tari Project
2
//
3
//  Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
4
//  following conditions are met:
5
//
6
//  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
7
//  disclaimer.
8
//
9
//  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
10
//  following disclaimer in the documentation and/or other materials provided with the distribution.
11
//
12
//  3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
13
//  products derived from this software without specific prior written permission.
14
//
15
//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
16
//  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17
//  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
18
//  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19
//  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
20
//  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
21
//  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22

23
use std::io;
24

25
use prost::DecodeError;
26
use thiserror::Error;
27

28
use super::{handshake::RpcHandshakeError, server::RpcServerError, RpcStatus};
29
use crate::{
30
    connectivity::ConnectivityError,
31
    peer_manager::PeerManagerError,
32
    proto::rpc as rpc_proto,
33
    traits::OrOptional,
34
    PeerConnectionError,
35
};
36

37
#[derive(Debug, Error)]
38
pub enum RpcError {
39
    #[error("Failed to decode message: {0}")]
40
    DecodeError(#[from] DecodeError),
41
    #[error("IO Error: {0}")]
42
    Io(#[from] io::Error),
43
    #[error("The client connection is closed")]
44
    ClientClosed,
45
    #[error("Request failed: {0}")]
46
    RequestFailed(#[from] RpcStatus),
47
    #[error("Remote peer unexpectedly closed the RPC connection")]
48
    ServerClosedRequest,
49
    #[error("Request cancelled")]
50
    RequestCancelled,
51
    #[error("Response did not match the request ID (expected {expected} actual {actual})")]
52
    ResponseIdDidNotMatchRequest { expected: u16, actual: u16 },
53
    #[error("Client internal error: {0}")]
54
    ClientInternalError(String),
55
    #[error("Handshake error: {0}")]
56
    HandshakeError(#[from] RpcHandshakeError),
57
    #[error("Server error: {0}")]
58
    ServerError(#[from] RpcServerError),
59
    #[error("Peer connection error: {0}")]
60
    PeerConnectionError(#[from] PeerConnectionError),
61
    #[error("Peer manager error: {0}")]
62
    PeerManagerError(#[from] PeerManagerError),
63
    #[error("Connectivity error: {0}")]
64
    ConnectivityError(#[from] ConnectivityError),
65
    #[error("Reply from peer timed out")]
66
    ReplyTimeout,
67
    #[error("Received an invalid ping response")]
68
    InvalidPingResponse,
69
    #[error("Unexpected ACK response. This is likely because of a previous ACK timeout")]
70
    UnexpectedAckResponse,
71
    #[error("Remote peer attempted to send more than {expected} payload chunks")]
72
    RemotePeerExceededMaxChunkCount { expected: usize },
73
    #[error("Request body was too large. Expected <= {expected} but got {got}")]
74
    MaxRequestSizeExceeded { got: usize, expected: usize },
75
    #[error(transparent)]
76
    UnknownError(#[from] anyhow::Error),
77
}
78

79
impl RpcError {
80
    pub fn client_internal_error<T: ToString>(err: &T) -> Self {
×
81
        RpcError::ClientInternalError(err.to_string())
×
82
    }
×
83

84
    /// Returns true if the server directly caused the error, otherwise false
85
    pub fn is_caused_by_server(&self) -> bool {
×
86
        match self {
×
87
            RpcError::ReplyTimeout |
88
            RpcError::DecodeError(_) |
89
            RpcError::RemotePeerExceededMaxChunkCount { .. } |
90
            RpcError::HandshakeError(RpcHandshakeError::DecodeError(_)) |
91
            RpcError::HandshakeError(RpcHandshakeError::ServerClosedRequest) |
92
            RpcError::HandshakeError(RpcHandshakeError::Rejected(_)) |
93
            RpcError::HandshakeError(RpcHandshakeError::TimedOut) |
94
            RpcError::ServerClosedRequest |
95
            RpcError::UnexpectedAckResponse |
96
            RpcError::ResponseIdDidNotMatchRequest { .. } => true,
×
97

98
            // Some of these may be caused by the server, but not with 100% certainty
99
            RpcError::RequestFailed(_) |
100
            RpcError::Io(_) |
101
            RpcError::ClientClosed |
102
            RpcError::RequestCancelled |
103
            RpcError::ClientInternalError(_) |
104
            RpcError::ServerError(_) |
105
            RpcError::PeerConnectionError(_) |
106
            RpcError::PeerManagerError(_) |
107
            RpcError::ConnectivityError(_) |
108
            RpcError::InvalidPingResponse |
109
            RpcError::MaxRequestSizeExceeded { .. } |
110
            RpcError::HandshakeError(RpcHandshakeError::Io(_)) |
111
            RpcError::HandshakeError(RpcHandshakeError::ClientNoSupportedVersion) |
112
            RpcError::HandshakeError(RpcHandshakeError::ClientClosed) |
113
            RpcError::UnknownError(_) => false,
×
114
        }
115
    }
×
116
}
117

118
#[derive(Debug, Error, Clone, Copy)]
119
pub enum HandshakeRejectReason {
120
    #[error("protocol version not supported")]
121
    UnsupportedVersion,
122
    #[error("no more RPC server sessions available: {0}")]
123
    NoServerSessionsAvailable(&'static str),
124
    #[error("no more RPC client sessions available: {0}")]
125
    NoClientSessionsAvailable(&'static str),
126
    #[error("protocol not supported")]
127
    ProtocolNotSupported,
128
    #[error("unknown protocol error: {0}")]
129
    Unknown(&'static str),
130
}
131

132
impl HandshakeRejectReason {
133
    pub fn as_i32(&self) -> i32 {
7✔
134
        rpc_proto::rpc_session_reply::HandshakeRejectReason::from(*self) as i32
7✔
135
    }
7✔
136

137
    pub fn from_i32(v: i32) -> Option<Self> {
7✔
138
        rpc_proto::rpc_session_reply::HandshakeRejectReason::try_from(v)
7✔
139
            .map(Into::into)
7✔
140
            .ok()
7✔
141
    }
7✔
142
}
143

144
impl From<rpc_proto::rpc_session_reply::HandshakeRejectReason> for HandshakeRejectReason {
145
    fn from(reason: rpc_proto::rpc_session_reply::HandshakeRejectReason) -> Self {
7✔
146
        #[allow(clippy::enum_glob_use)]
147
        use rpc_proto::rpc_session_reply::HandshakeRejectReason::*;
148
        match reason {
7✔
149
            UnsupportedVersion => HandshakeRejectReason::UnsupportedVersion,
×
150
            NoServerSessionsAvailable => HandshakeRejectReason::NoServerSessionsAvailable("session limit reached"),
6✔
151
            NoClientSessionsAvailable => HandshakeRejectReason::NoClientSessionsAvailable("session limit reached"),
×
152
            ProtocolNotSupported => HandshakeRejectReason::ProtocolNotSupported,
1✔
153
            Unknown => HandshakeRejectReason::Unknown("reject reason is not known"),
×
154
        }
155
    }
7✔
156
}
157

158
impl From<HandshakeRejectReason> for rpc_proto::rpc_session_reply::HandshakeRejectReason {
159
    fn from(reason: HandshakeRejectReason) -> Self {
7✔
160
        #[allow(clippy::enum_glob_use)]
161
        use rpc_proto::rpc_session_reply::HandshakeRejectReason::*;
162
        match reason {
7✔
163
            HandshakeRejectReason::UnsupportedVersion => UnsupportedVersion,
×
164
            HandshakeRejectReason::NoServerSessionsAvailable(_) => NoServerSessionsAvailable,
6✔
165
            HandshakeRejectReason::NoClientSessionsAvailable(_) => NoClientSessionsAvailable,
×
166
            HandshakeRejectReason::ProtocolNotSupported => ProtocolNotSupported,
1✔
167
            HandshakeRejectReason::Unknown(_) => Unknown,
×
168
        }
169
    }
7✔
170
}
171

172
impl<T> OrOptional<T> for Result<T, RpcError> {
173
    type Error = RpcError;
174

175
    fn or_optional(self) -> Result<Option<T>, Self::Error> {
×
176
        self.map(Some).or_else(|err| {
×
177
            if let RpcError::RequestFailed(ref status) = err {
×
178
                if status.is_not_found() {
×
179
                    Ok(None)
×
180
                } else {
181
                    Err(err)
×
182
                }
183
            } else {
184
                Err(err)
×
185
            }
186
        })
×
187
    }
×
188
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc