kyoto/
error.rs

1use std::fmt::{Debug, Display};
2
3use crate::impl_sourceless_error;
4
5/// Errors that prevent the node from running.
6#[derive(Debug)]
7pub enum NodeError<H: Debug + Display, P: Debug + Display> {
8    /// The persistence layer experienced a critical error.
9    HeaderDatabase(HeaderPersistenceError<H>),
10    /// The persistence layer experienced a critical error.
11    PeerDatabase(PeerManagerError<P>),
12}
13
14impl<H: Debug + Display, P: Debug + Display> core::fmt::Display for NodeError<H, P> {
15    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
16        match self {
17            NodeError::HeaderDatabase(e) => write!(f, "block headers: {e}"),
18            NodeError::PeerDatabase(e) => write!(f, "peer manager: {e}"),
19        }
20    }
21}
22
23impl<H: Debug + Display, P: Debug + Display> std::error::Error for NodeError<H, P> {
24    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
25        None
26    }
27}
28
29impl<H: Debug + Display, P: Debug + Display> From<HeaderPersistenceError<H>> for NodeError<H, P> {
30    fn from(value: HeaderPersistenceError<H>) -> Self {
31        NodeError::HeaderDatabase(value)
32    }
33}
34
35impl<H: Debug + Display, P: Debug + Display> From<PeerManagerError<P>> for NodeError<H, P> {
36    fn from(value: PeerManagerError<P>) -> Self {
37        NodeError::PeerDatabase(value)
38    }
39}
40
41/// Errors when managing persisted peers.
42#[derive(Debug)]
43pub enum PeerManagerError<P: Debug + Display> {
44    /// Reading or writing from the database failed.
45    Database(P),
46}
47
48impl<P: Debug + Display> core::fmt::Display for PeerManagerError<P> {
49    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
50        match self {
51            PeerManagerError::Database(e) => {
52                write!(f, "database: {e}")
53            }
54        }
55    }
56}
57
58impl<P: Debug + Display> std::error::Error for PeerManagerError<P> {
59    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
60        None
61    }
62}
63
64impl<P: Debug + Display> From<P> for PeerManagerError<P> {
65    fn from(value: P) -> Self {
66        PeerManagerError::Database(value)
67    }
68}
69
70/// Errors with the block header representation that prevent the node from operating.
71#[derive(Debug)]
72pub enum HeaderPersistenceError<H: Debug + Display> {
73    /// The block headers do not point to each other in a list.
74    HeadersDoNotLink,
75    /// Some predefined checkpoint does not match.
76    MismatchedCheckpoints,
77    /// A user tried to retrieve headers too far in the past for what is in their database.
78    CannotLocateHistory,
79    /// A database error.
80    Database(H),
81}
82
83impl<H: Debug + Display> core::fmt::Display for HeaderPersistenceError<H> {
84    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
85        match self {
86            HeaderPersistenceError::HeadersDoNotLink => write!(f, "the headers loaded from persistence do not link together."),
87            HeaderPersistenceError::MismatchedCheckpoints => write!(f, "the headers loaded do not match a known checkpoint."),
88            HeaderPersistenceError::CannotLocateHistory => write!(f, "the configured checkpoint is too far in the past compared to previous syncs. The database cannot reconstruct the chain."),
89            HeaderPersistenceError::Database(e) => write!(f, "database: {e}"),
90        }
91    }
92}
93
94impl<H: Debug + Display> std::error::Error for HeaderPersistenceError<H> {
95    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
96        None
97    }
98}
99
100/// Errors occuring when the client is talking to the node.
101#[derive(Debug)]
102pub enum ClientError {
103    /// The channel to the node was likely closed and dropped from memory.
104    SendError,
105}
106
107impl core::fmt::Display for ClientError {
108    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
109        match self {
110            ClientError::SendError => {
111                write!(f, "the receiver of this message was dropped from memory.")
112            }
113        }
114    }
115}
116
117impl_sourceless_error!(ClientError);
118
119/// Errors occuring when the client is fetching headers from the node.
120#[derive(Debug)]
121pub enum FetchHeaderError {
122    /// The channel to the node was likely closed and dropped from memory.
123    /// This implies the node is not running.
124    SendError,
125    /// The database operation failed while attempting to find the header.
126    DatabaseOptFailed {
127        /// The message from the backend describing the failure.
128        error: String,
129    },
130    /// The channel to the client was likely closed by the node and dropped from memory.
131    RecvError,
132    /// The header at the requested height does not yet exist.
133    UnknownHeight,
134}
135
136impl core::fmt::Display for FetchHeaderError {
137    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
138        match self {
139            FetchHeaderError::SendError => {
140                write!(f, "the receiver of this message was dropped from memory.")
141            }
142            FetchHeaderError::DatabaseOptFailed { error } => {
143                write!(
144                    f,
145                    "the database operation failed while attempting to find the header: {error}"
146                )
147            }
148            FetchHeaderError::RecvError => write!(
149                f,
150                "the channel to the client was likely closed by the node and dropped from memory."
151            ),
152            FetchHeaderError::UnknownHeight => {
153                write!(f, "the header at the requested height does not yet exist.")
154            }
155        }
156    }
157}
158
159impl_sourceless_error!(FetchHeaderError);
160
161/// Errors occuring when the client is fetching blocks from the node.
162#[derive(Debug)]
163pub enum FetchBlockError {
164    /// The channel to the node was likely closed and dropped from memory.
165    /// This implies the node is not running.
166    SendError,
167    /// The database operation failed while attempting to find the header.
168    DatabaseOptFailed {
169        /// The message from the backend describing the failure.
170        error: String,
171    },
172    /// The channel to the client was likely closed by the node and dropped from memory.
173    RecvError,
174    /// The hash is not a member of the chain of most work.
175    UnknownHash,
176}
177
178impl core::fmt::Display for FetchBlockError {
179    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
180        match self {
181            FetchBlockError::SendError => {
182                write!(f, "the receiver of this message was dropped from memory.")
183            }
184            FetchBlockError::DatabaseOptFailed { error } => {
185                write!(
186                    f,
187                    "the database operation failed while attempting to find the header: {error}"
188                )
189            }
190            FetchBlockError::RecvError => write!(
191                f,
192                "the channel to the client was likely closed by the node and dropped from memory."
193            ),
194            FetchBlockError::UnknownHash => {
195                write!(f, "the hash is not a member of the chain of most work.")
196            }
197        }
198    }
199}
200
201impl_sourceless_error!(FetchBlockError);
202
203/// Errors that occur when fetching the minimum fee rate to broadcast a transaction.
204#[derive(Debug)]
205pub enum FetchFeeRateError {
206    /// The channel to the node was likely closed and dropped from memory.
207    /// This implies the node is not running.
208    SendError,
209    /// The channel to the client was likely closed by the node and dropped from memory.
210    RecvError,
211}
212
213impl core::fmt::Display for FetchFeeRateError {
214    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
215        match self {
216            FetchFeeRateError::SendError => {
217                write!(f, "the receiver of this message was dropped from memory.")
218            }
219            FetchFeeRateError::RecvError => write!(
220                f,
221                "the channel to the client was likely closed by the node and dropped from memory."
222            ),
223        }
224    }
225}
226
227impl_sourceless_error!(FetchFeeRateError);