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}