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    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}