miniscript/interpreter/
error.rs

1// Written in 2019 by Sanket Kanjular and Andrew Poelstra
2// SPDX-License-Identifier: CC0-1.0
3
4use core::fmt;
5#[cfg(feature = "std")]
6use std::error;
7
8use bitcoin::hashes::hash160;
9use bitcoin::hex::DisplayHex;
10#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/121684
11use bitcoin::secp256k1;
12use bitcoin::{absolute, relative, taproot};
13
14use super::BitcoinKey;
15use crate::prelude::*;
16
17/// Detailed Error type for Interpreter
18#[derive(Debug)]
19pub enum Error {
20    /// Could not satisfy, absolute locktime not met
21    AbsoluteLockTimeNotMet(absolute::LockTime),
22    /// Could not satisfy, lock time values are different units
23    AbsoluteLockTimeComparisonInvalid(absolute::LockTime, absolute::LockTime),
24    /// Cannot Infer a taproot descriptor
25    /// Key spends cannot infer the internal key of the descriptor
26    /// Inferring script spends is possible, but is hidden nodes are currently
27    /// not supported in descriptor spec
28    CannotInferTrDescriptors,
29    /// Error parsing taproot control block
30    ControlBlockParse(taproot::TaprootError),
31    /// Tap control block(merkle proofs + tweak) verification error
32    ControlBlockVerificationError,
33    /// General Interpreter error.
34    CouldNotEvaluate,
35    /// ECDSA Signature related error
36    EcdsaSig(bitcoin::ecdsa::Error),
37    /// We expected a push (including a `OP_1` but no other numeric pushes)
38    ExpectedPush,
39    /// The preimage to the hash function must be exactly 32 bytes.
40    HashPreimageLengthMismatch,
41    /// Incorrect scriptPubKey (pay-to-pubkeyhash) for the provided public key
42    IncorrectPubkeyHash,
43    /// Incorrect scriptPubKey for the provided redeem script
44    IncorrectScriptHash,
45    /// Incorrect scriptPubKey (pay-to-witness-pubkeyhash) for the provided public key
46    IncorrectWPubkeyHash,
47    /// Incorrect scriptPubKey for the provided witness script
48    IncorrectWScriptHash,
49    /// MultiSig missing at least `1` witness elements out of `k + 1` required
50    InsufficientSignaturesMultiSig,
51    /// Invalid Sighash type
52    InvalidSchnorrSighashType(Vec<u8>),
53    /// ecdsa Signature failed to verify
54    InvalidEcdsaSignature(bitcoin::PublicKey),
55    /// Signature failed to verify
56    InvalidSchnorrSignature(bitcoin::key::XOnlyPublicKey),
57    /// Last byte of this signature isn't a standard sighash type
58    NonStandardSighash(Vec<u8>),
59    /// Miniscript error
60    Miniscript(crate::Error),
61    /// MultiSig requires 1 extra zero element apart from the `k` signatures
62    MissingExtraZeroMultiSig,
63    /// Script abortion because of incorrect dissatisfaction for multisig.
64    /// Any input witness apart from sat(0 sig ...) or nsat(0 0 ..) leads to
65    /// this error. This is network standardness assumption and miniscript only
66    /// supports standard scripts
67    MultiSigEvaluationError,
68    ///Witness must be empty for pre-segwit transactions
69    NonEmptyWitness,
70    ///ScriptSig must be empty for pure segwit transactions
71    NonEmptyScriptSig,
72    /// Script abortion because of incorrect dissatisfaction for Checksig.
73    /// Any input witness apart from sat(sig) or nsat(0) leads to
74    /// this error. This is network standardness assumption and miniscript only
75    /// supports standard scripts
76    // note that BitcoinKey is not exported, create a data structure to convey the same
77    // information in error
78    PkEvaluationError(PkEvalErrInner),
79    /// The Public Key hash check for the given pubkey. This occurs in `PkH`
80    /// node when the given key does not match to Hash in script.
81    PkHashVerifyFail(hash160::Hash),
82    /// Parse Error while parsing a `stack::Element::Push` as a Pubkey. Both
83    /// 33 byte and 65 bytes are supported.
84    PubkeyParseError,
85    /// Parse Error while parsing a `stack::Element::Push` as a XOnlyPublicKey (32 bytes)
86    XOnlyPublicKeyParseError,
87    /// Could not satisfy, relative locktime not met
88    RelativeLockTimeNotMet(relative::LockTime),
89    /// Could not satisfy, the sequence number on the tx input had the disable flag set.
90    RelativeLockTimeDisabled(relative::LockTime),
91    /// Forward-secp related errors
92    Secp(secp256k1::Error),
93    /// Miniscript requires the entire top level script to be satisfied.
94    ScriptSatisfactionError,
95    /// Schnorr Signature error
96    SchnorrSig(bitcoin::taproot::SigFromSliceError),
97    /// Errors in signature hash calculations
98    SighashError(bitcoin::sighash::InvalidSighashTypeError),
99    /// Taproot Annex Unsupported
100    TapAnnexUnsupported,
101    /// An uncompressed public key was encountered in a context where it is
102    /// disallowed (e.g. in a Segwit script or p2wpkh output)
103    UncompressedPubkey,
104    /// Got `stack::Element::Satisfied` or `stack::Element::Dissatisfied` when the
105    /// interpreter was expecting `stack::Element::Push`
106    UnexpectedStackBoolean,
107    /// Unexpected Stack End, caused by popping extra elements from stack
108    UnexpectedStackEnd,
109    /// Unexpected Stack Push `stack::Element::Push` element when the interpreter
110    /// was expecting a stack boolean `stack::Element::Satisfied` or
111    /// `stack::Element::Dissatisfied`
112    UnexpectedStackElementPush,
113    /// Verify expects stack top element exactly to be `stack::Element::Satisfied`.
114    /// This error is raised even if the stack top is `stack::Element::Push`.
115    VerifyFailed,
116}
117
118impl fmt::Display for Error {
119    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
120        match *self {
121            Error::AbsoluteLockTimeNotMet(n) => {
122                write!(f, "required absolute locktime CLTV of {} blocks, not met", n)
123            }
124            Error::AbsoluteLockTimeComparisonInvalid(n, lock_time) => write!(
125                f,
126                "could not satisfy, lock time values are different units n: {} lock_time: {}",
127                n, lock_time
128            ),
129            Error::CannotInferTrDescriptors => write!(f, "Cannot infer taproot descriptors"),
130            Error::ControlBlockParse(ref e) => write!(f, "Control block parse error {}", e),
131            Error::ControlBlockVerificationError => {
132                f.write_str("Control block verification failed")
133            }
134            Error::EcdsaSig(ref s) => write!(f, "Ecdsa sig error: {}", s),
135            Error::ExpectedPush => f.write_str("expected push in script"),
136            Error::CouldNotEvaluate => f.write_str("Interpreter Error: Could not evaluate"),
137            Error::HashPreimageLengthMismatch => f.write_str("Hash preimage should be 32 bytes"),
138            Error::IncorrectPubkeyHash => f.write_str("public key did not match scriptpubkey"),
139            Error::IncorrectScriptHash => f.write_str("redeem script did not match scriptpubkey"),
140            Error::IncorrectWPubkeyHash => {
141                f.write_str("public key did not match scriptpubkey (segwit v0)")
142            }
143            Error::IncorrectWScriptHash => f.write_str("witness script did not match scriptpubkey"),
144            Error::InsufficientSignaturesMultiSig => f.write_str("Insufficient signatures for CMS"),
145            Error::InvalidSchnorrSighashType(ref sig) => {
146                write!(f, "Invalid sighash type for schnorr signature '{:x}'", sig.as_hex())
147            }
148            Error::InvalidEcdsaSignature(pk) => write!(f, "bad ecdsa signature with pk {}", pk),
149            Error::InvalidSchnorrSignature(pk) => write!(f, "bad schnorr signature with pk {}", pk),
150            Error::NonStandardSighash(ref sig) => {
151                write!(f, "Non standard sighash type for signature '{:x}'", sig.as_hex())
152            }
153            Error::NonEmptyWitness => f.write_str("legacy spend had nonempty witness"),
154            Error::NonEmptyScriptSig => f.write_str("segwit spend had nonempty scriptsig"),
155            Error::Miniscript(ref e) => write!(f, "parse error: {}", e),
156            Error::MissingExtraZeroMultiSig => f.write_str("CMS missing extra zero"),
157            Error::MultiSigEvaluationError => {
158                f.write_str("CMS script aborted, incorrect satisfaction/dissatisfaction")
159            }
160            Error::PkEvaluationError(ref key) => write!(f, "Incorrect Signature for pk {}", key),
161            Error::PkHashVerifyFail(ref hash) => write!(f, "Pubkey Hash check failed {}", hash),
162            Error::PubkeyParseError => f.write_str("could not parse pubkey"),
163            Error::XOnlyPublicKeyParseError => f.write_str("could not parse x-only pubkey"),
164            Error::RelativeLockTimeNotMet(n) => {
165                write!(f, "required relative locktime CSV of {} blocks, not met", n)
166            }
167            Error::RelativeLockTimeDisabled(n) => {
168                write!(f, "required relative locktime CSV of {} blocks, but tx sequence number has disable-flag set", n)
169            }
170            Error::ScriptSatisfactionError => f.write_str("Top level script must be satisfied"),
171            Error::Secp(ref e) => fmt::Display::fmt(e, f),
172            Error::SchnorrSig(ref s) => write!(f, "Schnorr sig error: {}", s),
173            Error::SighashError(ref e) => fmt::Display::fmt(e, f),
174            Error::TapAnnexUnsupported => f.write_str("Encountered annex element"),
175            Error::UncompressedPubkey => {
176                f.write_str("uncompressed pubkey in non-legacy descriptor")
177            }
178            Error::UnexpectedStackBoolean => {
179                f.write_str("Expected Stack Push operation, found stack bool")
180            }
181            Error::UnexpectedStackElementPush => write!(f, "Got {}, expected Stack Boolean", 1),
182            Error::UnexpectedStackEnd => f.write_str("unexpected end of stack"),
183            Error::VerifyFailed => {
184                f.write_str("Expected Satisfied Boolean at stack top for VERIFY")
185            }
186        }
187    }
188}
189
190#[cfg(feature = "std")]
191impl error::Error for Error {
192    fn cause(&self) -> Option<&dyn error::Error> {
193        use self::Error::*;
194
195        match self {
196            AbsoluteLockTimeNotMet(_)
197            | AbsoluteLockTimeComparisonInvalid(_, _)
198            | CannotInferTrDescriptors
199            | ControlBlockVerificationError
200            | CouldNotEvaluate
201            | ExpectedPush
202            | HashPreimageLengthMismatch
203            | IncorrectPubkeyHash
204            | IncorrectScriptHash
205            | IncorrectWPubkeyHash
206            | IncorrectWScriptHash
207            | InsufficientSignaturesMultiSig
208            | InvalidEcdsaSignature(_)
209            | InvalidSchnorrSignature(_)
210            | InvalidSchnorrSighashType(_)
211            | NonStandardSighash(_)
212            | MissingExtraZeroMultiSig
213            | MultiSigEvaluationError
214            | NonEmptyWitness
215            | NonEmptyScriptSig
216            | PubkeyParseError
217            | XOnlyPublicKeyParseError
218            | PkEvaluationError(_)
219            | PkHashVerifyFail(_)
220            | RelativeLockTimeNotMet(_)
221            | RelativeLockTimeDisabled(_)
222            | ScriptSatisfactionError
223            | TapAnnexUnsupported
224            | UncompressedPubkey
225            | UnexpectedStackBoolean
226            | UnexpectedStackEnd
227            | UnexpectedStackElementPush
228            | VerifyFailed => None,
229            ControlBlockParse(e) => Some(e),
230            EcdsaSig(e) => Some(e),
231            Miniscript(e) => Some(e),
232            Secp(e) => Some(e),
233            SchnorrSig(e) => Some(e),
234            SighashError(e) => Some(e),
235        }
236    }
237}
238
239#[doc(hidden)]
240impl From<secp256k1::Error> for Error {
241    fn from(e: secp256k1::Error) -> Error { Error::Secp(e) }
242}
243
244#[doc(hidden)]
245impl From<bitcoin::sighash::InvalidSighashTypeError> for Error {
246    fn from(e: bitcoin::sighash::InvalidSighashTypeError) -> Error { Error::SighashError(e) }
247}
248
249#[doc(hidden)]
250impl From<bitcoin::ecdsa::Error> for Error {
251    fn from(e: bitcoin::ecdsa::Error) -> Error { Error::EcdsaSig(e) }
252}
253
254#[doc(hidden)]
255impl From<bitcoin::taproot::SigFromSliceError> for Error {
256    fn from(e: bitcoin::taproot::SigFromSliceError) -> Error { Error::SchnorrSig(e) }
257}
258
259#[doc(hidden)]
260impl From<crate::Error> for Error {
261    fn from(e: crate::Error) -> Error { Error::Miniscript(e) }
262}
263
264/// A type of representing which keys errored during interpreter checksig evaluation
265// Note that we can't use BitcoinKey because it is not public
266#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
267pub enum PkEvalErrInner {
268    /// Full Key
269    FullKey(bitcoin::PublicKey),
270    /// XOnly Key
271    XOnlyKey(bitcoin::key::XOnlyPublicKey),
272}
273
274impl From<BitcoinKey> for PkEvalErrInner {
275    fn from(pk: BitcoinKey) -> Self {
276        match pk {
277            BitcoinKey::Fullkey(pk) => PkEvalErrInner::FullKey(pk),
278            BitcoinKey::XOnlyPublicKey(xpk) => PkEvalErrInner::XOnlyKey(xpk),
279        }
280    }
281}
282
283impl fmt::Display for PkEvalErrInner {
284    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
285        match self {
286            PkEvalErrInner::FullKey(pk) => pk.fmt(f),
287            PkEvalErrInner::XOnlyKey(xpk) => xpk.fmt(f),
288        }
289    }
290}