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