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