Skip to main content

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    /// Unsupported witness program.
49    ///
50    /// The witness program is consensus-valid but not representable
51    /// as a standard descriptor (e.g., non-standard v0/v1 lengths,
52    /// future witness versions v2+, or non-P2A 2-byte v1 programs).
53    #[cfg(feature = "address")]
54    UnsupportedWitnessProgram(String),
55}
56
57impl core::fmt::Display for DescriptorError {
58    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
59        match self {
60            Self::MissingTypeTag => write!(f, "missing type tag"),
61            Self::InvalidDescriptorType(tag) => write!(f, "invalid descriptor type tag: {tag}"),
62            Self::InvalidPayloadLength(len) => write!(f, "invalid payload length: {len}"),
63            #[cfg(feature = "address")]
64            Self::InvalidXOnlyPublicKey => write!(f, "invalid X-only public key"),
65            Self::HexDecodingError(err) => write!(f, "hex decoding error: {err}"),
66            #[cfg(feature = "address")]
67            Self::InvalidAddressConversion(desc_type) => write!(
68                f,
69                "{desc_type} locking script cannot be converted into a bitcoin address"
70            ),
71            #[cfg(feature = "address")]
72            Self::Secp256k1Error(err) => write!(f, "secp256k1 error: {err}"),
73            #[cfg(feature = "address")]
74            Self::WitnessProgramError(err) => write!(f, "witness program error: {err}"),
75            #[cfg(feature = "address")]
76            Self::UnsupportedWitnessProgram(msg) => write!(f, "unsupported witness program: {msg}"),
77        }
78    }
79}
80
81// TODO: uncomment feature flag when no-std is supported
82//#[cfg(feature = "std")]
83impl std::error::Error for DescriptorError {
84    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
85        match self {
86            Self::HexDecodingError(err) => Some(err),
87            #[cfg(feature = "address")]
88            Self::Secp256k1Error(err) => Some(err),
89            #[cfg(feature = "address")]
90            Self::WitnessProgramError(err) => Some(err),
91            #[cfg(feature = "address")]
92            Self::UnsupportedWitnessProgram(_) => None,
93            _ => None,
94        }
95    }
96}
97
98impl From<HexToBytesError> for DescriptorError {
99    fn from(err: HexToBytesError) -> Self {
100        Self::HexDecodingError(err)
101    }
102}
103
104#[cfg(feature = "address")]
105impl From<Secp256k1Error> for DescriptorError {
106    fn from(err: Secp256k1Error) -> Self {
107        Self::Secp256k1Error(err)
108    }
109}
110
111#[cfg(feature = "address")]
112impl From<WitnessProgramError> for DescriptorError {
113    fn from(err: WitnessProgramError) -> Self {
114        Self::WitnessProgramError(err)
115    }
116}