bitcoin/psbt/
error.rs

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