1use std::fmt::{Display, Formatter};
2
3#[derive(Debug)]
4pub enum Error {
5 Amount(bitcoin::amount::ParseAmountError),
6 Script(bitcoin::script::Error),
7 Invalid(String),
8 Unsupported(String),
9 Capacity(String),
10 Missing(String),
11 Context { message: String, cause: Box<Error> },
12 Hex(hex::FromHexError),
13 Integer(std::num::TryFromIntError),
14 IntegerText(std::num::ParseIntError),
15 Slice(std::array::TryFromSliceError),
16 Utf8(std::str::Utf8Error),
17 Text(std::string::FromUtf8Error),
18 Allocation(std::collections::TryReserveError),
19 Random(rand::Error),
20 CipherKey(hmac::digest::InvalidLength),
21 Kdf(hkdf::InvalidLength),
22 Mac(hmac::digest::MacError),
23 Secp256k1(bitcoin::secp256k1::Error),
24 Transaction(bitcoin::consensus::encode::Error),
25 Push(bitcoin::script::PushBytesError),
26 TaprootBuilder(bitcoin::taproot::TaprootBuilderError),
27 Taproot(bitcoin::taproot::TaprootError),
28 TaprootSighash(bitcoin::sighash::TaprootError),
29 SegwitSighash(bitcoin::sighash::P2wpkhError),
30 AddressScript(bitcoin::address::FromScriptError),
31 AddressParse(bitcoin::address::ParseError),
32 AddressNetwork(bitcoin::address::NetworkValidationError),
33 PublicKey(bitcoin::key::FromSliceError),
34 UncompressedKey(bitcoin::key::UncompressedPublicKeyError),
35 Ecdsa(bitcoin::ecdsa::Error),
36 Hash(bitcoin::hex::HexToArrayError),
37 ProofOfWork(bitcoin::block::ValidationError),
38}
39impl Display for Error {
40 fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
41 match self {
42 Self::Amount(cause) => Display::fmt(cause, formatter),
43 Self::Script(cause) => Display::fmt(cause, formatter),
44 Self::Invalid(message)
45 | Self::Missing(message)
46 | Self::Unsupported(message)
47 | Self::Capacity(message) => formatter.write_str(message),
48 Self::Context { message, cause } => write!(formatter, "{message}: {cause}"),
49 Self::Hex(cause) => Display::fmt(cause, formatter),
50 Self::Integer(cause) => Display::fmt(cause, formatter),
51 Self::IntegerText(cause) => Display::fmt(cause, formatter),
52 Self::Slice(cause) => Display::fmt(cause, formatter),
53 Self::Utf8(cause) => Display::fmt(cause, formatter),
54 Self::Text(cause) => Display::fmt(cause, formatter),
55 Self::Allocation(cause) => Display::fmt(cause, formatter),
56 Self::Random(cause) => Display::fmt(cause, formatter),
57 Self::CipherKey(cause) => Display::fmt(cause, formatter),
58 Self::Kdf(cause) => Display::fmt(cause, formatter),
59 Self::Mac(cause) => Display::fmt(cause, formatter),
60 Self::Secp256k1(cause) => Display::fmt(cause, formatter),
61 Self::Transaction(cause) => Display::fmt(cause, formatter),
62 Self::Push(cause) => Display::fmt(cause, formatter),
63 Self::TaprootBuilder(cause) => Display::fmt(cause, formatter),
64 Self::Taproot(cause) => Display::fmt(cause, formatter),
65 Self::TaprootSighash(cause) => Display::fmt(cause, formatter),
66 Self::SegwitSighash(cause) => Display::fmt(cause, formatter),
67 Self::AddressScript(cause) => Display::fmt(cause, formatter),
68 Self::AddressParse(cause) => Display::fmt(cause, formatter),
69 Self::AddressNetwork(cause) => Display::fmt(cause, formatter),
70 Self::PublicKey(cause) => Display::fmt(cause, formatter),
71 Self::UncompressedKey(cause) => Display::fmt(cause, formatter),
72 Self::Ecdsa(cause) => Display::fmt(cause, formatter),
73 Self::Hash(cause) => Display::fmt(cause, formatter),
74 Self::ProofOfWork(cause) => Display::fmt(cause, formatter),
75 }
76 }
77}
78impl std::error::Error for Error {
79 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
80 match self {
81 Self::Amount(cause) => Some(cause),
82 Self::Script(cause) => Some(cause),
83 Self::Hex(cause) => Some(cause),
84 Self::Integer(cause) => Some(cause),
85 Self::IntegerText(cause) => Some(cause),
86 Self::Slice(cause) => Some(cause),
87 Self::Utf8(cause) => Some(cause),
88 Self::Text(cause) => Some(cause),
89 Self::Allocation(cause) => Some(cause),
90 Self::Random(cause) => Some(cause),
91 Self::CipherKey(cause) => Some(cause),
92 Self::Kdf(cause) => Some(cause),
93 Self::Mac(cause) => Some(cause),
94 Self::Secp256k1(cause) => Some(cause),
95 Self::Transaction(cause) => Some(cause),
96 Self::Push(cause) => Some(cause),
97 Self::TaprootBuilder(cause) => Some(cause),
98 Self::Taproot(cause) => Some(cause),
99 Self::TaprootSighash(cause) => Some(cause),
100 Self::SegwitSighash(cause) => Some(cause),
101 Self::AddressScript(cause) => Some(cause),
102 Self::AddressParse(cause) => Some(cause),
103 Self::AddressNetwork(cause) => Some(cause),
104 Self::PublicKey(cause) => Some(cause),
105 Self::UncompressedKey(cause) => Some(cause),
106 Self::Ecdsa(cause) => Some(cause),
107 Self::Hash(cause) => Some(cause),
108 Self::ProofOfWork(cause) => Some(cause),
109 Self::Context { cause, .. } => Some(cause.as_ref()),
110 _ => None,
111 }
112 }
113}
114impl From<hex::FromHexError> for Error {
115 fn from(error: hex::FromHexError) -> Self {
116 Self::Hex(error)
117 }
118}
119impl From<std::num::TryFromIntError> for Error {
120 fn from(error: std::num::TryFromIntError) -> Self {
121 Self::Integer(error)
122 }
123}
124impl From<std::num::ParseIntError> for Error {
125 fn from(error: std::num::ParseIntError) -> Self {
126 Self::IntegerText(error)
127 }
128}
129impl From<std::array::TryFromSliceError> for Error {
130 fn from(error: std::array::TryFromSliceError) -> Self {
131 Self::Slice(error)
132 }
133}
134impl From<std::str::Utf8Error> for Error {
135 fn from(error: std::str::Utf8Error) -> Self {
136 Self::Utf8(error)
137 }
138}
139impl From<std::string::FromUtf8Error> for Error {
140 fn from(error: std::string::FromUtf8Error) -> Self {
141 Self::Text(error)
142 }
143}
144impl From<std::collections::TryReserveError> for Error {
145 fn from(error: std::collections::TryReserveError) -> Self {
146 Self::Allocation(error)
147 }
148}
149impl From<rand::Error> for Error {
150 fn from(error: rand::Error) -> Self {
151 Self::Random(error)
152 }
153}
154impl From<hmac::digest::InvalidLength> for Error {
155 fn from(error: hmac::digest::InvalidLength) -> Self {
156 Self::CipherKey(error)
157 }
158}
159impl From<hkdf::InvalidLength> for Error {
160 fn from(error: hkdf::InvalidLength) -> Self {
161 Self::Kdf(error)
162 }
163}
164impl From<hmac::digest::MacError> for Error {
165 fn from(error: hmac::digest::MacError) -> Self {
166 Self::Mac(error)
167 }
168}
169impl From<bitcoin::secp256k1::Error> for Error {
170 fn from(error: bitcoin::secp256k1::Error) -> Self {
171 Self::Secp256k1(error)
172 }
173}
174impl From<bitcoin::consensus::encode::Error> for Error {
175 fn from(error: bitcoin::consensus::encode::Error) -> Self {
176 Self::Transaction(error)
177 }
178}
179impl From<bitcoin::script::PushBytesError> for Error {
180 fn from(error: bitcoin::script::PushBytesError) -> Self {
181 Self::Push(error)
182 }
183}
184impl From<bitcoin::taproot::TaprootBuilderError> for Error {
185 fn from(error: bitcoin::taproot::TaprootBuilderError) -> Self {
186 Self::TaprootBuilder(error)
187 }
188}
189impl From<bitcoin::taproot::TaprootError> for Error {
190 fn from(error: bitcoin::taproot::TaprootError) -> Self {
191 Self::Taproot(error)
192 }
193}
194impl From<bitcoin::sighash::TaprootError> for Error {
195 fn from(error: bitcoin::sighash::TaprootError) -> Self {
196 Self::TaprootSighash(error)
197 }
198}
199impl From<bitcoin::sighash::P2wpkhError> for Error {
200 fn from(error: bitcoin::sighash::P2wpkhError) -> Self {
201 Self::SegwitSighash(error)
202 }
203}
204impl From<bitcoin::address::FromScriptError> for Error {
205 fn from(error: bitcoin::address::FromScriptError) -> Self {
206 Self::AddressScript(error)
207 }
208}
209impl From<bitcoin::address::ParseError> for Error {
210 fn from(error: bitcoin::address::ParseError) -> Self {
211 Self::AddressParse(error)
212 }
213}
214impl From<bitcoin::address::NetworkValidationError> for Error {
215 fn from(error: bitcoin::address::NetworkValidationError) -> Self {
216 Self::AddressNetwork(error)
217 }
218}
219impl From<bitcoin::key::FromSliceError> for Error {
220 fn from(error: bitcoin::key::FromSliceError) -> Self {
221 Self::PublicKey(error)
222 }
223}
224impl From<bitcoin::key::UncompressedPublicKeyError> for Error {
225 fn from(error: bitcoin::key::UncompressedPublicKeyError) -> Self {
226 Self::UncompressedKey(error)
227 }
228}
229impl From<bitcoin::ecdsa::Error> for Error {
230 fn from(error: bitcoin::ecdsa::Error) -> Self {
231 Self::Ecdsa(error)
232 }
233}
234impl From<bitcoin::hex::HexToArrayError> for Error {
235 fn from(error: bitcoin::hex::HexToArrayError) -> Self {
236 Self::Hash(error)
237 }
238}
239impl From<bitcoin::block::ValidationError> for Error {
240 fn from(error: bitcoin::block::ValidationError) -> Self {
241 Self::ProofOfWork(error)
242 }
243}
244
245pub trait Context<T> {
246 fn context(self, message: impl Into<String>) -> Result<T, Error>;
247 fn with_context(self, message: impl FnOnce() -> String) -> Result<T, Error>;
248}
249impl<T> Context<T> for Option<T> {
250 fn context(self, message: impl Into<String>) -> Result<T, Error> {
251 match self {
252 Some(value) => Ok(value),
253 None => Err(Error::Missing(message.into())),
254 }
255 }
256 fn with_context(self, message: impl FnOnce() -> String) -> Result<T, Error> {
257 match self {
258 Some(value) => Ok(value),
259 None => Err(Error::Missing(message())),
260 }
261 }
262}
263impl<T, E: Into<Error>> Context<T> for Result<T, E> {
264 fn context(self, message: impl Into<String>) -> Result<T, Error> {
265 self.map_err(|cause| Error::Context {
266 message: message.into(),
267 cause: Box::new(cause.into()),
268 })
269 }
270 fn with_context(self, message: impl FnOnce() -> String) -> Result<T, Error> {
271 self.map_err(|cause| Error::Context {
272 message: message(),
273 cause: Box::new(cause.into()),
274 })
275 }
276}
277#[macro_export]
278macro_rules! ensure {
279 ($condition:expr, $($message:tt)*) => {
280 if !$condition { return Err($crate::error::Error::Invalid(format!($($message)*))); }
281 };
282}
283#[macro_export]
284macro_rules! bail {
285 ($($message:tt)*) => { return Err($crate::error::Error::Invalid(format!($($message)*))) };
286}
287pub use {bail, ensure};
288impl From<bitcoin::script::Error> for Error {
289 fn from(error: bitcoin::script::Error) -> Self {
290 Self::Script(error)
291 }
292}
293impl From<bitcoin::amount::ParseAmountError> for Error {
294 fn from(error: bitcoin::amount::ParseAmountError) -> Self {
295 Self::Amount(error)
296 }
297}