bitcoin_bosd/
error.rs

1//! Error types for the Bitcoin BOSD library.
2
3use core::fmt;
4
5use hex::error::HexToBytesError;
6
7use crate::DescriptorType;
8
9#[cfg(feature = "address")]
10use bitcoin::script::witness_program::Error as WitnessProgramError;
11#[cfg(feature = "address")]
12use bitcoin::secp256k1::Error as Secp256k1Error;
13
14/// Errors related to [`Descriptor`](crate::Descriptor).
15#[derive(Debug, PartialEq, Eq)]
16pub enum DescriptorError {
17    /// Missing type tag.
18    MissingTypeTag,
19
20    /// Invalid descriptor type tag.
21    InvalidDescriptorType(u8),
22
23    /// Invalid payload length.
24    InvalidPayloadLength(usize),
25
26    /// Invalid X-only public key.
27    #[cfg(feature = "address")]
28    InvalidXOnlyPublicKey,
29
30    /// Hex decoding error.
31    HexDecodingError(HexToBytesError),
32
33    /// Invalid [`Address`](bitcoin::Address) conversion.
34    ///
35    /// Currently only susceptible for `OP_RETURN` descriptors
36    /// being converted to a bitcoin address.
37    #[cfg(feature = "address")]
38    InvalidAddressConversion(DescriptorType),
39
40    /// [`secp256k1`](bitcoin::secp256k1) errors.
41    #[cfg(feature = "address")]
42    Secp256k1Error(Secp256k1Error),
43
44    /// [`WitnessProgram`](bitcoin::WitnessProgram) errors.
45    #[cfg(feature = "address")]
46    WitnessProgramError(WitnessProgramError),
47}
48
49impl core::fmt::Display for DescriptorError {
50    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
51        match self {
52            Self::MissingTypeTag => write!(f, "missing type tag"),
53            Self::InvalidDescriptorType(tag) => write!(f, "invalid descriptor type tag: {tag}"),
54            Self::InvalidPayloadLength(len) => write!(f, "invalid payload length: {len}"),
55            #[cfg(feature = "address")]
56            Self::InvalidXOnlyPublicKey => write!(f, "invalid X-only public key"),
57            Self::HexDecodingError(err) => write!(f, "hex decoding error: {err}"),
58            #[cfg(feature = "address")]
59            Self::InvalidAddressConversion(desc_type) => write!(
60                f,
61                "{desc_type} locking script cannot be converted into a bitcoin address"
62            ),
63            #[cfg(feature = "address")]
64            Self::Secp256k1Error(err) => write!(f, "secp256k1 error: {err}"),
65            #[cfg(feature = "address")]
66            Self::WitnessProgramError(err) => write!(f, "witness program error: {err}"),
67        }
68    }
69}
70
71// TODO: uncomment feature flag when no-std is supported
72//#[cfg(feature = "std")]
73impl std::error::Error for DescriptorError {
74    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
75        match self {
76            Self::HexDecodingError(err) => Some(err),
77            #[cfg(feature = "address")]
78            Self::Secp256k1Error(err) => Some(err),
79            #[cfg(feature = "address")]
80            Self::WitnessProgramError(err) => Some(err),
81            _ => None,
82        }
83    }
84}
85
86impl From<HexToBytesError> for DescriptorError {
87    fn from(err: HexToBytesError) -> Self {
88        Self::HexDecodingError(err)
89    }
90}
91
92#[cfg(feature = "address")]
93impl From<Secp256k1Error> for DescriptorError {
94    fn from(err: Secp256k1Error) -> Self {
95        Self::Secp256k1Error(err)
96    }
97}
98
99#[cfg(feature = "address")]
100impl From<WitnessProgramError> for DescriptorError {
101    fn from(err: WitnessProgramError) -> Self {
102        Self::WitnessProgramError(err)
103    }
104}