bitcoind_async_client/
error.rs1use std::fmt;
3
4use bitcoin::Network;
5use bitreq::Error as BitreqError;
6use serde::{Deserialize, Serialize};
7use serde_json::Error as SerdeJsonError;
8use thiserror::Error;
9
10#[derive(Error, Debug, Clone, PartialEq, Serialize, Deserialize)]
12pub enum ClientError {
13 #[error("Missing username or password")]
15 MissingUserPassword,
16
17 #[error("RPC server returned error '{1}' (code {0})")]
26 Server(i32, String),
27
28 #[error("Error parsing rpc response: {0}")]
29 Parse(String),
30
31 #[error("Could not create RPC Param")]
33 Param(String),
34
35 #[error("{0}")]
37 Body(String),
38
39 #[error("Obtained failure status({0}): {1}")]
41 Status(u16, String),
42
43 #[error("Malformed Response: {0}")]
45 MalformedResponse(String),
46
47 #[error("Could not connect: {0}")]
49 Connection(String),
50
51 #[error("Timeout")]
53 Timeout,
54
55 #[error("HttpRedirect: {0}")]
57 HttpRedirect(String),
58
59 #[error("Could not build request: {0}")]
61 ReqBuilder(String),
62
63 #[error("Max retries {0} exceeded")]
65 MaxRetriesExceeded(u8),
66
67 #[error("Could not create request: {0}")]
69 Request(String),
70
71 #[error("Network address: {0}")]
73 WrongNetworkAddress(Network),
74
75 #[error(transparent)]
77 UnexpectedServerVersion(#[from] UnexpectedServerVersionError),
78
79 #[error(transparent)]
81 Sign(#[from] SignRawTransactionWithWalletError),
82
83 #[error("Could not get xpriv from wallet")]
85 Xpriv,
86
87 #[error("{0}")]
89 Other(String),
90}
91
92impl ClientError {
93 pub fn is_tx_not_found(&self) -> bool {
94 matches!(self, Self::Server(-5, _))
95 }
96
97 pub fn is_block_not_found(&self) -> bool {
98 matches!(self, Self::Server(-5, _))
99 }
100
101 pub fn is_missing_or_invalid_input(&self) -> bool {
102 matches!(self, Self::Server(-26, _)) || matches!(self, Self::Server(-25, _))
103 }
104}
105
106impl From<BitreqError> for ClientError {
107 fn from(value: BitreqError) -> Self {
108 match value {
109 BitreqError::AddressNotFound
111 | BitreqError::IoError(_)
112 | BitreqError::RustlsCreateConnection(_) => ClientError::Connection(value.to_string()),
113
114 BitreqError::RedirectLocationMissing
116 | BitreqError::InfiniteRedirectionLoop
117 | BitreqError::TooManyRedirections => ClientError::HttpRedirect(value.to_string()),
118
119 BitreqError::HeadersOverflow
121 | BitreqError::StatusLineOverflow
122 | BitreqError::BodyOverflow
123 | BitreqError::MalformedChunkLength
124 | BitreqError::MalformedChunkEnd
125 | BitreqError::MalformedContentLength
126 | BitreqError::InvalidUtf8InResponse
127 | BitreqError::InvalidUtf8InBody(_) => {
128 ClientError::MalformedResponse(value.to_string())
129 }
130
131 _ => ClientError::Other(value.to_string()),
133 }
134 }
135}
136
137impl From<SerdeJsonError> for ClientError {
138 fn from(value: SerdeJsonError) -> Self {
139 Self::Parse(format!("Could not parse {value}"))
140 }
141}
142
143#[derive(Error, Debug, Clone, PartialEq, Serialize, Deserialize)]
145pub struct BitcoinRpcError {
146 pub code: i32,
147 pub message: String,
148}
149
150impl fmt::Display for BitcoinRpcError {
151 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
152 write!(f, "RPC error {}: {}", self.code, self.message)
153 }
154}
155
156impl From<BitcoinRpcError> for ClientError {
157 fn from(value: BitcoinRpcError) -> Self {
158 Self::Server(value.code, value.message)
159 }
160}
161
162#[derive(Error, Debug, Clone, PartialEq, Serialize, Deserialize)]
164pub struct SignRawTransactionWithWalletError {
165 txid: String,
167 vout: u32,
169 #[serde(rename = "scriptSig")]
171 script_sig: String,
172 sequence: u32,
174 error: String,
176}
177
178impl fmt::Display for SignRawTransactionWithWalletError {
179 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
180 write!(
181 f,
182 "error signing raw transaction with wallet: {}",
183 self.error
184 )
185 }
186}
187
188#[derive(Error, Debug, Clone, PartialEq, Serialize, Deserialize)]
190pub struct UnexpectedServerVersionError {
191 pub got: usize,
193 pub expected: Vec<usize>,
195}
196
197impl fmt::Display for UnexpectedServerVersionError {
198 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
199 let mut expected = String::new();
200 for version in &self.expected {
201 let v = format!(" {version} ");
202 expected.push_str(&v);
203 }
204 write!(
205 f,
206 "unexpected bitcoind version, got: {} expected one of: {}",
207 self.got, expected
208 )
209 }
210}