Skip to main content

dig_peer_protocol/
error.rs

1//! Errors a [`DigLink`](crate::DigLink) can produce.
2
3use thiserror::Error;
4use tokio::sync::oneshot::error::RecvError;
5
6/// Everything that can go wrong on a DIG peer link.
7///
8/// Opcodes appear as raw `u8` rather than `ProtocolMessageTypes` on purpose: a DIG opcode has no
9/// `ProtocolMessageTypes` representation, and an error type that could not name the opcode it
10/// rejected would be useless for exactly the messages this link exists to carry.
11#[derive(Debug, Error)]
12pub enum LinkError {
13    /// A body failed to encode or decode.
14    #[error("streamable error: {0}")]
15    Streamable(#[from] chia_traits::Error),
16
17    /// The websocket itself failed.
18    ///
19    /// Boxed because `tungstenite::Error` is by far the largest variant (~136 bytes) and would
20    /// otherwise set the size of every `Result` the link returns, on the success path too.
21    #[error("websocket error: {0}")]
22    WebSocket(Box<tungstenite::Error>),
23
24    /// The underlying socket failed, typically while reading the peer address.
25    #[error("io error: {0}")]
26    Io(#[from] std::io::Error),
27
28    /// The peer replied with an opcode none of the expected ones matched.
29    #[error("expected a response with opcode in {0:?}, found {1}")]
30    InvalidResponse(Vec<u8>, u8),
31
32    /// The link closed before the awaited reply arrived.
33    #[error("the link closed before a response arrived")]
34    Recv(#[from] RecvError),
35
36    /// The websocket is carried over a TLS backend this build does not support — enable the
37    /// `native-tls` or `rustls` feature.
38    #[error("the websocket's TLS backend is not supported by this build")]
39    UnsupportedTls,
40
41    /// The message exceeds a rate-limit bound no window will ever admit — typically the
42    /// per-message size cap. Retrying is futile; the body must be split.
43    #[error("a message with opcode {0} and a {1}-byte body exceeds the per-message limit")]
44    Unsendable(u8, usize),
45
46    /// Rate-limit budget did not free up within `LinkOptions::send_timeout`.
47    #[error("timed out waiting for rate-limit budget to send opcode {0}")]
48    SendTimeout(u8),
49
50    /// No correlated reply arrived within `LinkOptions::request_timeout`.
51    #[error("timed out waiting for a response to opcode {0}")]
52    RequestTimeout(u8),
53
54    /// A Chia message type did not encode to a single-byte opcode. Unreachable with any real
55    /// `ChiaProtocolMessage`; present so the encoding is never silently assumed.
56    #[error("message type did not encode to a single-byte opcode")]
57    MalformedOpcode,
58}
59
60// Hand-written rather than `#[from]`, because the variant boxes its payload: callers still get
61// the ergonomic `?` conversion from a bare `tungstenite::Error`.
62impl From<tungstenite::Error> for LinkError {
63    fn from(error: tungstenite::Error) -> Self {
64        Self::WebSocket(Box::new(error))
65    }
66}