use core::fmt;
#[cfg(feature = "std")]
use std::error;
use bitcoin::hashes::hash160;
use bitcoin::hex::DisplayHex;
#[cfg(not(test))] use bitcoin::secp256k1;
use bitcoin::{absolute, relative, taproot};
use super::BitcoinKey;
use crate::prelude::*;
#[derive(Debug)]
pub enum Error {
AbsoluteLockTimeNotMet(absolute::LockTime),
AbsoluteLockTimeComparisonInvalid(absolute::LockTime, absolute::LockTime),
CannotInferTrDescriptors,
ControlBlockParse(taproot::TaprootError),
ControlBlockVerificationError,
CouldNotEvaluate,
EcdsaSig(bitcoin::ecdsa::Error),
ExpectedPush,
HashPreimageLengthMismatch,
IncorrectPubkeyHash,
IncorrectScriptHash,
IncorrectWPubkeyHash,
IncorrectWScriptHash,
InsufficientSignaturesMultiSig,
InvalidSchnorrSighashType(Vec<u8>),
InvalidEcdsaSignature(bitcoin::PublicKey),
InvalidSchnorrSignature(bitcoin::key::XOnlyPublicKey),
NonStandardSighash(Vec<u8>),
Miniscript(crate::Error),
MissingExtraZeroMultiSig,
MultiSigEvaluationError,
NonEmptyWitness,
NonEmptyScriptSig,
PkEvaluationError(PkEvalErrInner),
PkHashVerifyFail(hash160::Hash),
PubkeyParseError,
XOnlyPublicKeyParseError,
RelativeLockTimeNotMet(relative::LockTime),
RelativeLockTimeDisabled(relative::LockTime),
Secp(secp256k1::Error),
ScriptSatisfactionError,
SchnorrSig(bitcoin::taproot::SigFromSliceError),
SighashError(bitcoin::sighash::InvalidSighashTypeError),
TapAnnexUnsupported,
UncompressedPubkey,
UnexpectedStackBoolean,
UnexpectedStackEnd,
UnexpectedStackElementPush,
VerifyFailed,
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Error::AbsoluteLockTimeNotMet(n) => {
write!(f, "required absolute locktime CLTV of {} blocks, not met", n)
}
Error::AbsoluteLockTimeComparisonInvalid(n, lock_time) => write!(
f,
"could not satisfy, lock time values are different units n: {} lock_time: {}",
n, lock_time
),
Error::CannotInferTrDescriptors => write!(f, "Cannot infer taproot descriptors"),
Error::ControlBlockParse(ref e) => write!(f, "Control block parse error {}", e),
Error::ControlBlockVerificationError => {
f.write_str("Control block verification failed")
}
Error::EcdsaSig(ref s) => write!(f, "Ecdsa sig error: {}", s),
Error::ExpectedPush => f.write_str("expected push in script"),
Error::CouldNotEvaluate => f.write_str("Interpreter Error: Could not evaluate"),
Error::HashPreimageLengthMismatch => f.write_str("Hash preimage should be 32 bytes"),
Error::IncorrectPubkeyHash => f.write_str("public key did not match scriptpubkey"),
Error::IncorrectScriptHash => f.write_str("redeem script did not match scriptpubkey"),
Error::IncorrectWPubkeyHash => {
f.write_str("public key did not match scriptpubkey (segwit v0)")
}
Error::IncorrectWScriptHash => f.write_str("witness script did not match scriptpubkey"),
Error::InsufficientSignaturesMultiSig => f.write_str("Insufficient signatures for CMS"),
Error::InvalidSchnorrSighashType(ref sig) => {
write!(f, "Invalid sighash type for schnorr signature '{:x}'", sig.as_hex())
}
Error::InvalidEcdsaSignature(pk) => write!(f, "bad ecdsa signature with pk {}", pk),
Error::InvalidSchnorrSignature(pk) => write!(f, "bad schnorr signature with pk {}", pk),
Error::NonStandardSighash(ref sig) => {
write!(f, "Non standard sighash type for signature '{:x}'", sig.as_hex())
}
Error::NonEmptyWitness => f.write_str("legacy spend had nonempty witness"),
Error::NonEmptyScriptSig => f.write_str("segwit spend had nonempty scriptsig"),
Error::Miniscript(ref e) => write!(f, "parse error: {}", e),
Error::MissingExtraZeroMultiSig => f.write_str("CMS missing extra zero"),
Error::MultiSigEvaluationError => {
f.write_str("CMS script aborted, incorrect satisfaction/dissatisfaction")
}
Error::PkEvaluationError(ref key) => write!(f, "Incorrect Signature for pk {}", key),
Error::PkHashVerifyFail(ref hash) => write!(f, "Pubkey Hash check failed {}", hash),
Error::PubkeyParseError => f.write_str("could not parse pubkey"),
Error::XOnlyPublicKeyParseError => f.write_str("could not parse x-only pubkey"),
Error::RelativeLockTimeNotMet(n) => {
write!(f, "required relative locktime CSV of {} blocks, not met", n)
}
Error::RelativeLockTimeDisabled(n) => {
write!(f, "required relative locktime CSV of {} blocks, but tx sequence number has disable-flag set", n)
}
Error::ScriptSatisfactionError => f.write_str("Top level script must be satisfied"),
Error::Secp(ref e) => fmt::Display::fmt(e, f),
Error::SchnorrSig(ref s) => write!(f, "Schnorr sig error: {}", s),
Error::SighashError(ref e) => fmt::Display::fmt(e, f),
Error::TapAnnexUnsupported => f.write_str("Encountered annex element"),
Error::UncompressedPubkey => {
f.write_str("uncompressed pubkey in non-legacy descriptor")
}
Error::UnexpectedStackBoolean => {
f.write_str("Expected Stack Push operation, found stack bool")
}
Error::UnexpectedStackElementPush => write!(f, "Got {}, expected Stack Boolean", 1),
Error::UnexpectedStackEnd => f.write_str("unexpected end of stack"),
Error::VerifyFailed => {
f.write_str("Expected Satisfied Boolean at stack top for VERIFY")
}
}
}
}
#[cfg(feature = "std")]
impl error::Error for Error {
fn cause(&self) -> Option<&dyn error::Error> {
use self::Error::*;
match self {
AbsoluteLockTimeNotMet(_)
| AbsoluteLockTimeComparisonInvalid(_, _)
| CannotInferTrDescriptors
| ControlBlockVerificationError
| CouldNotEvaluate
| ExpectedPush
| HashPreimageLengthMismatch
| IncorrectPubkeyHash
| IncorrectScriptHash
| IncorrectWPubkeyHash
| IncorrectWScriptHash
| InsufficientSignaturesMultiSig
| InvalidEcdsaSignature(_)
| InvalidSchnorrSignature(_)
| InvalidSchnorrSighashType(_)
| NonStandardSighash(_)
| MissingExtraZeroMultiSig
| MultiSigEvaluationError
| NonEmptyWitness
| NonEmptyScriptSig
| PubkeyParseError
| XOnlyPublicKeyParseError
| PkEvaluationError(_)
| PkHashVerifyFail(_)
| RelativeLockTimeNotMet(_)
| RelativeLockTimeDisabled(_)
| ScriptSatisfactionError
| TapAnnexUnsupported
| UncompressedPubkey
| UnexpectedStackBoolean
| UnexpectedStackEnd
| UnexpectedStackElementPush
| VerifyFailed => None,
ControlBlockParse(e) => Some(e),
EcdsaSig(e) => Some(e),
Miniscript(e) => Some(e),
Secp(e) => Some(e),
SchnorrSig(e) => Some(e),
SighashError(e) => Some(e),
}
}
}
#[doc(hidden)]
impl From<secp256k1::Error> for Error {
fn from(e: secp256k1::Error) -> Error { Error::Secp(e) }
}
#[doc(hidden)]
impl From<bitcoin::sighash::InvalidSighashTypeError> for Error {
fn from(e: bitcoin::sighash::InvalidSighashTypeError) -> Error { Error::SighashError(e) }
}
#[doc(hidden)]
impl From<bitcoin::ecdsa::Error> for Error {
fn from(e: bitcoin::ecdsa::Error) -> Error { Error::EcdsaSig(e) }
}
#[doc(hidden)]
impl From<bitcoin::taproot::SigFromSliceError> for Error {
fn from(e: bitcoin::taproot::SigFromSliceError) -> Error { Error::SchnorrSig(e) }
}
#[doc(hidden)]
impl From<crate::Error> for Error {
fn from(e: crate::Error) -> Error { Error::Miniscript(e) }
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum PkEvalErrInner {
FullKey(bitcoin::PublicKey),
XOnlyKey(bitcoin::key::XOnlyPublicKey),
}
impl From<BitcoinKey> for PkEvalErrInner {
fn from(pk: BitcoinKey) -> Self {
match pk {
BitcoinKey::Fullkey(pk) => PkEvalErrInner::FullKey(pk),
BitcoinKey::XOnlyPublicKey(xpk) => PkEvalErrInner::XOnlyKey(xpk),
}
}
}
impl fmt::Display for PkEvalErrInner {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
PkEvalErrInner::FullKey(pk) => pk.fmt(f),
PkEvalErrInner::XOnlyKey(xpk) => xpk.fmt(f),
}
}
}