Skip to main content

psbt_v2/v0/bitcoin/
error.rs

1// SPDX-License-Identifier: CC0-1.0
2
3use core::fmt;
4
5use bitcoin::bip32::Xpub;
6use bitcoin::blockdata::transaction::Transaction;
7use bitcoin::consensus::encode;
8use bitcoin::{hashes, secp256k1};
9
10use crate::error::write_err;
11use crate::io;
12use crate::prelude::*;
13use crate::v0::bitcoin::raw;
14
15/// Enum for marking psbt hash error.
16#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
17pub enum PsbtHash {
18    Ripemd,
19    Sha256,
20    Hash160,
21    Hash256,
22}
23/// Ways that a Partially Signed Transaction might fail.
24#[derive(Debug)]
25#[non_exhaustive]
26pub enum Error {
27    /// Magic bytes for a PSBT must be the ASCII for "psbt" serialized in most
28    /// significant byte order.
29    InvalidMagic,
30    /// Missing both the witness and non-witness utxo.
31    MissingUtxo,
32    /// The separator for a PSBT must be `0xff`.
33    InvalidSeparator,
34    /// Returned when output index is out of bounds in relation to the output in non-witness UTXO.
35    PsbtUtxoOutOfbounds,
36    /// Known keys must be according to spec.
37    InvalidKey(raw::Key),
38    /// Non-proprietary key type found when proprietary key was expected
39    InvalidProprietaryKey,
40    /// Keys within key-value map should never be duplicated.
41    DuplicateKey(raw::Key),
42    /// The scriptSigs for the unsigned transaction must be empty.
43    UnsignedTxHasScriptSigs,
44    /// The scriptWitnesses for the unsigned transaction must be empty.
45    UnsignedTxHasScriptWitnesses,
46    /// A PSBT must have an unsigned transaction.
47    MustHaveUnsignedTx,
48    /// Signals that there are no more key-value pairs in a key-value map.
49    NoMorePairs,
50    /// Attempting to combine with a PSBT describing a different unsigned
51    /// transaction.
52    UnexpectedUnsignedTx {
53        /// Expected
54        expected: Box<Transaction>,
55        /// Actual
56        actual: Box<Transaction>,
57    },
58    /// Unable to parse as a standard sighash type.
59    NonStandardSighashType(u32),
60    /// Invalid hash when parsing slice.
61    InvalidHash(hashes::FromSliceError),
62    /// The pre-image must hash to the correponding psbt hash
63    InvalidPreimageHashPair {
64        /// Hash-type
65        hash_type: PsbtHash,
66        /// Pre-image
67        preimage: Box<[u8]>,
68        /// Hash value
69        hash: Box<[u8]>,
70    },
71    /// Conflicting data during combine procedure:
72    /// global extended public key has inconsistent key sources
73    CombineInconsistentKeySources(Box<Xpub>),
74    /// Serialization error in bitcoin consensus-encoded structures
75    ConsensusEncoding(encode::Error),
76    /// Negative fee
77    NegativeFee,
78    /// Integer overflow in fee calculation
79    FeeOverflow,
80    /// Parsing error indicating invalid public keys
81    InvalidPublicKey(bitcoin::key::FromSliceError),
82    /// Parsing error indicating invalid secp256k1 public keys
83    InvalidSecp256k1PublicKey(secp256k1::Error),
84    /// Parsing error indicating invalid xonly public keys
85    InvalidXOnlyPublicKey,
86    /// Parsing error indicating invalid ECDSA signatures
87    InvalidEcdsaSignature(bitcoin::ecdsa::Error),
88    /// Parsing error indicating invalid taproot signatures
89    InvalidTaprootSignature(bitcoin::taproot::SigFromSliceError),
90    /// Parsing error indicating invalid control block
91    InvalidControlBlock,
92    /// Parsing error indicating invalid leaf version
93    InvalidLeafVersion,
94    /// Parsing error indicating a taproot error
95    Taproot(&'static str),
96    /// Taproot tree deserilaization error
97    TapTree(bitcoin::taproot::IncompleteBuilderError),
98    /// Error related to an xpub key
99    XPubKey(&'static str),
100    /// Error related to PSBT version
101    Version(&'static str),
102    /// PSBT data is not consumed entirely
103    PartialDataConsumption,
104    /// I/O error.
105    Io(io::Error),
106    /// Key must be excluded from this version of PSBT (see consts.rs for u8 values).
107    ExcludedKey {
108        /// The disallowed valued.
109        key_type_value: u8,
110    },
111}
112
113impl fmt::Display for Error {
114    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
115        use Error::*;
116
117        match *self {
118            InvalidMagic => f.write_str("invalid magic"),
119            MissingUtxo => f.write_str("UTXO information is not present in PSBT"),
120            InvalidSeparator => f.write_str("invalid separator"),
121            PsbtUtxoOutOfbounds =>
122                f.write_str("output index is out of bounds of non witness script output array"),
123            InvalidKey(ref rkey) => write!(f, "invalid key: {}", rkey),
124            InvalidProprietaryKey =>
125                write!(f, "non-proprietary key type found when proprietary key was expected"),
126            DuplicateKey(ref rkey) => write!(f, "duplicate key: {}", rkey),
127            UnsignedTxHasScriptSigs => f.write_str("the unsigned transaction has script sigs"),
128            UnsignedTxHasScriptWitnesses =>
129                f.write_str("the unsigned transaction has script witnesses"),
130            MustHaveUnsignedTx =>
131                f.write_str("partially signed transactions must have an unsigned transaction"),
132            NoMorePairs => f.write_str("no more key-value pairs for this psbt map"),
133            UnexpectedUnsignedTx { expected: ref e, actual: ref a } => write!(
134                f,
135                "different unsigned transaction: expected {}, actual {}",
136                e.compute_txid(),
137                a.compute_txid()
138            ),
139            NonStandardSighashType(ref sht) => write!(f, "non-standard sighash type: {}", sht),
140            InvalidHash(ref e) => write_err!(f, "invalid hash when parsing slice"; e),
141            InvalidPreimageHashPair { ref preimage, ref hash, ref hash_type } => {
142                // directly using debug forms of psbthash enums
143                write!(f, "Preimage {:?} does not match {:?} hash {:?}", preimage, hash_type, hash)
144            }
145            CombineInconsistentKeySources(ref s) => {
146                write!(f, "combine conflict: {}", s)
147            }
148            ConsensusEncoding(ref e) => write_err!(f, "bitcoin consensus encoding error"; e),
149            NegativeFee => f.write_str("PSBT has a negative fee which is not allowed"),
150            FeeOverflow => f.write_str("integer overflow in fee calculation"),
151            InvalidPublicKey(ref e) => write_err!(f, "invalid public key"; e),
152            InvalidSecp256k1PublicKey(ref e) => write_err!(f, "invalid secp256k1 public key"; e),
153            InvalidXOnlyPublicKey => f.write_str("invalid xonly public key"),
154            InvalidEcdsaSignature(ref e) => write_err!(f, "invalid ECDSA signature"; e),
155            InvalidTaprootSignature(ref e) => write_err!(f, "invalid taproot signature"; e),
156            InvalidControlBlock => f.write_str("invalid control block"),
157            InvalidLeafVersion => f.write_str("invalid leaf version"),
158            Taproot(s) => write!(f, "taproot error -  {}", s),
159            TapTree(ref e) => write_err!(f, "taproot tree error"; e),
160            XPubKey(s) => write!(f, "xpub key error -  {}", s),
161            Version(s) => write!(f, "version error {}", s),
162            PartialDataConsumption =>
163                f.write_str("data not consumed entirely when explicitly deserializing"),
164            Io(ref e) => write_err!(f, "I/O error"; e),
165            ExcludedKey { key_type_value } => write!(
166                f,
167                "found a keypair type that is explicitly excluded: {}",
168                crate::consts::psbt_in_key_type_value_to_str(key_type_value)
169            ),
170        }
171    }
172}
173
174#[cfg(feature = "std")]
175impl std::error::Error for Error {
176    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
177        use Error::*;
178
179        match *self {
180            InvalidHash(ref e) => Some(e),
181            ConsensusEncoding(ref e) => Some(e),
182            Io(ref e) => Some(e),
183            InvalidMagic
184            | MissingUtxo
185            | InvalidSeparator
186            | PsbtUtxoOutOfbounds
187            | InvalidKey(_)
188            | InvalidProprietaryKey
189            | DuplicateKey(_)
190            | UnsignedTxHasScriptSigs
191            | UnsignedTxHasScriptWitnesses
192            | MustHaveUnsignedTx
193            | NoMorePairs
194            | UnexpectedUnsignedTx { .. }
195            | NonStandardSighashType(_)
196            | InvalidPreimageHashPair { .. }
197            | CombineInconsistentKeySources(_)
198            | NegativeFee
199            | FeeOverflow
200            | InvalidPublicKey(_)
201            | InvalidSecp256k1PublicKey(_)
202            | InvalidXOnlyPublicKey
203            | InvalidEcdsaSignature(_)
204            | InvalidTaprootSignature(_)
205            | InvalidControlBlock
206            | InvalidLeafVersion
207            | Taproot(_)
208            | TapTree(_)
209            | XPubKey(_)
210            | Version(_)
211            | PartialDataConsumption
212            | ExcludedKey { .. } => None,
213        }
214    }
215}
216
217impl From<hashes::FromSliceError> for Error {
218    fn from(e: hashes::FromSliceError) -> Error { Error::InvalidHash(e) }
219}
220
221impl From<encode::Error> for Error {
222    fn from(e: encode::Error) -> Self { Error::ConsensusEncoding(e) }
223}
224
225impl From<io::Error> for Error {
226    fn from(e: io::Error) -> Self { Error::Io(e) }
227}