From ae07786c2710daa136c35e4be49eaa1106cf085d Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Thu, 18 May 2023 15:45:50 +1000 Subject: [PATCH] Add InvalidSighashTypeError As we do for `NonStandardSighashErrorType` add an error struct for invalid sighash type, used by the `taproot` module instead of returning a generic error enum with loads of unused variants. --- bitcoin/src/crypto/sighash.rs | 16 ++++++++++++++-- bitcoin/src/crypto/taproot.rs | 18 +++++++++++------- bitcoin/src/psbt/map/input.rs | 13 +++++++------ bitcoin/src/psbt/serialize.rs | 2 +- 4 files changed, 33 insertions(+), 16 deletions(-) diff --git a/bitcoin/src/crypto/sighash.rs b/bitcoin/src/crypto/sighash.rs index 7e5b1e11..e4b391d4 100644 --- a/bitcoin/src/crypto/sighash.rs +++ b/bitcoin/src/crypto/sighash.rs @@ -499,7 +499,7 @@ impl TapSighashType { } /// Constructs a [`TapSighashType`] from a raw `u8`. - pub fn from_consensus_u8(hash_ty: u8) -> Result { + pub fn from_consensus_u8(hash_ty: u8) -> Result { use TapSighashType::*; Ok(match hash_ty { @@ -510,11 +510,23 @@ impl TapSighashType { 0x81 => AllPlusAnyoneCanPay, 0x82 => NonePlusAnyoneCanPay, 0x83 => SinglePlusAnyoneCanPay, - x => return Err(Error::InvalidSighashType(x as u32)), + x => return Err(InvalidSighashTypeError(x.into())), }) } } +/// Integer is not a consensus valid sighash type. +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct InvalidSighashTypeError(pub u32); + +impl fmt::Display for InvalidSighashTypeError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "invalid sighash type {}", self.0) + } +} + +impl_std_error!(InvalidSighashTypeError); + /// This type is consensus valid but an input including it would prevent the transaction from /// being relayed on today's Bitcoin network. #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] diff --git a/bitcoin/src/crypto/taproot.rs b/bitcoin/src/crypto/taproot.rs index e6f20832..fa9bc1e1 100644 --- a/bitcoin/src/crypto/taproot.rs +++ b/bitcoin/src/crypto/taproot.rs @@ -11,7 +11,7 @@ use internals::write_err; pub use secp256k1::{self, constants, KeyPair, Parity, Secp256k1, Verification, XOnlyPublicKey}; use crate::prelude::*; -use crate::sighash::TapSighashType; +use crate::sighash::{InvalidSighashTypeError, TapSighashType}; /// A BIP340-341 serialized taproot signature with the corresponding hash type. #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] @@ -35,8 +35,7 @@ impl Signature { } 65 => { let (hash_ty, sig) = sl.split_last().expect("Slice len checked == 65"); - let hash_ty = TapSighashType::from_consensus_u8(*hash_ty) - .map_err(|_| SigFromSliceError::InvalidSighashType(*hash_ty))?; + let hash_ty = TapSighashType::from_consensus_u8(*hash_ty)?; let sig = secp256k1::schnorr::Signature::from_slice(sig)?; Ok(Signature { sig, hash_ty }) } @@ -64,7 +63,7 @@ impl Signature { #[non_exhaustive] pub enum SigFromSliceError { /// Invalid signature hash type. - InvalidSighashType(u8), + SighashType(InvalidSighashTypeError), /// Signature has valid size but does not parse correctly Secp256k1(secp256k1::Error), /// Invalid taproot signature size @@ -76,7 +75,7 @@ impl fmt::Display for SigFromSliceError { use SigFromSliceError::*; match *self { - InvalidSighashType(hash_ty) => write!(f, "invalid signature hash type {}", hash_ty), + SighashType(ref e) => write_err!(f, "invalid signature hash type"; e), Secp256k1(ref e) => write_err!(f, "taproot signature has correct len but is malformed"; e), InvalidSignatureSize(sz) => write!(f, "invalid taproot signature size: {}", sz), @@ -91,11 +90,16 @@ impl std::error::Error for SigFromSliceError { match self { Secp256k1(e) => Some(e), - InvalidSighashType(_) | InvalidSignatureSize(_) => None, + SighashType(e) => Some(e), + InvalidSignatureSize(_) => None, } } } impl From for SigFromSliceError { - fn from(e: secp256k1::Error) -> Self { SigFromSliceError::Secp256k1(e) } + fn from(e: secp256k1::Error) -> Self { Self::Secp256k1(e) } +} + +impl From for SigFromSliceError { + fn from(err: InvalidSighashTypeError) -> Self { Self::SighashType(err) } } diff --git a/bitcoin/src/psbt/map/input.rs b/bitcoin/src/psbt/map/input.rs index 91993e06..0be0d481 100644 --- a/bitcoin/src/psbt/map/input.rs +++ b/bitcoin/src/psbt/map/input.rs @@ -18,7 +18,8 @@ use crate::psbt::map::Map; use crate::psbt::serialize::Deserialize; use crate::psbt::{self, error, raw, Error}; use crate::sighash::{ - self, EcdsaSighashType, NonStandardSighashTypeError, SighashTypeParseError, TapSighashType, + EcdsaSighashType, InvalidSighashTypeError, NonStandardSighashTypeError, SighashTypeParseError, + TapSighashType, }; use crate::taproot::{ControlBlock, LeafVersion, TapLeafHash, TapNodeHash}; @@ -196,9 +197,9 @@ impl PsbtSighashType { /// Returns the [`TapSighashType`] if the [`PsbtSighashType`] can be /// converted to one. - pub fn taproot_hash_ty(self) -> Result { + pub fn taproot_hash_ty(self) -> Result { if self.inner > 0xffu32 { - Err(sighash::Error::InvalidSighashType(self.inner)) + Err(InvalidSighashTypeError(self.inner)) } else { TapSighashType::from_consensus_u8(self.inner as u8) } @@ -235,7 +236,7 @@ impl Input { /// # Errors /// /// If the `sighash_type` field is set to a invalid Taproot sighash value. - pub fn taproot_hash_ty(&self) -> Result { + pub fn taproot_hash_ty(&self) -> Result { self.sighash_type .map(|sighash_type| sighash_type.taproot_hash_ty()) .unwrap_or(Ok(TapSighashType::Default)) @@ -575,7 +576,7 @@ mod test { let back = PsbtSighashType::from_str(&s).unwrap(); assert_eq!(back, sighash); - assert_eq!(back.ecdsa_hash_ty(), Err(sighash::NonStandardSighashTypeError(nonstd))); - assert_eq!(back.taproot_hash_ty(), Err(sighash::Error::InvalidSighashType(nonstd))); + assert_eq!(back.ecdsa_hash_ty(), Err(NonStandardSighashTypeError(nonstd))); + assert_eq!(back.taproot_hash_ty(), Err(InvalidSighashTypeError(nonstd))); } } diff --git a/bitcoin/src/psbt/serialize.rs b/bitcoin/src/psbt/serialize.rs index 0d5deb61..3f9c57ad 100644 --- a/bitcoin/src/psbt/serialize.rs +++ b/bitcoin/src/psbt/serialize.rs @@ -258,7 +258,7 @@ impl Deserialize for taproot::Signature { use taproot::SigFromSliceError::*; taproot::Signature::from_slice(bytes).map_err(|e| match e { - InvalidSighashType(flag) => Error::NonStandardSighashType(flag as u32), + SighashType(err) => Error::NonStandardSighashType(err.0), InvalidSignatureSize(_) => Error::InvalidTaprootSignature(e), Secp256k1(..) => Error::InvalidTaprootSignature(e), })