Skip to main content

urma_core/
error.rs

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}