diff --git a/src/blockdata/transaction.rs b/src/blockdata/transaction.rs index ea2cd2b7..f837ad63 100644 --- a/src/blockdata/transaction.rs +++ b/src/blockdata/transaction.rs @@ -29,7 +29,7 @@ use crate::blockdata::locktime::{LockTime, PackedLockTime, Height, Time}; use crate::consensus::{encode, Decodable, Encodable}; use crate::hash_types::{Sighash, Txid, Wtxid}; use crate::VarInt; -use crate::internal_macros::{impl_consensus_encoding, serde_string_impl, serde_struct_human_string_impl, write_err}; +use crate::internal_macros::{impl_consensus_encoding, serde_struct_human_string_impl, write_err}; use crate::parse::impl_parse_str_through_int; #[cfg(doc)] @@ -1014,183 +1014,16 @@ impl Decodable for Transaction { } } -/// 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)] -pub struct NonStandardSighashType(pub u32); - -impl fmt::Display for NonStandardSighashType { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Non standard sighash type {}", self.0) - } -} - -#[cfg(feature = "std")] -#[cfg_attr(docsrs, doc(cfg(feature = "std")))] -impl std::error::Error for NonStandardSighashType { - fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - None - } -} - /// Legacy Hashtype of an input's signature #[deprecated(since = "0.28.0", note = "Please use [`EcdsaSighashType`] instead")] pub type SigHashType = EcdsaSighashType; -/// Hashtype of an input's signature, encoded in the last byte of the signature. -/// -/// Fixed values so they can be cast as integer types for encoding (see also -/// [`SchnorrSighashType`]). -#[derive(PartialEq, Eq, Debug, Copy, Clone, Hash)] -pub enum EcdsaSighashType { - /// 0x1: Sign all outputs. - All = 0x01, - /// 0x2: Sign no outputs --- anyone can choose the destination. - None = 0x02, - /// 0x3: Sign the output whose index matches this input's index. If none exists, - /// sign the hash `0000000000000000000000000000000000000000000000000000000000000001`. - /// (This rule is probably an unintentional C++ism, but it's consensus so we have - /// to follow it.) - Single = 0x03, - /// 0x81: Sign all outputs but only this input. - AllPlusAnyoneCanPay = 0x81, - /// 0x82: Sign no outputs and only this input. - NonePlusAnyoneCanPay = 0x82, - /// 0x83: Sign one output and only this input (see `Single` for what "one output" means). - SinglePlusAnyoneCanPay = 0x83 -} -serde_string_impl!(EcdsaSighashType, "a EcdsaSighashType data"); - -impl fmt::Display for EcdsaSighashType { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let s = match self { - EcdsaSighashType::All => "SIGHASH_ALL", - EcdsaSighashType::None => "SIGHASH_NONE", - EcdsaSighashType::Single => "SIGHASH_SINGLE", - EcdsaSighashType::AllPlusAnyoneCanPay => "SIGHASH_ALL|SIGHASH_ANYONECANPAY", - EcdsaSighashType::NonePlusAnyoneCanPay => "SIGHASH_NONE|SIGHASH_ANYONECANPAY", - EcdsaSighashType::SinglePlusAnyoneCanPay => "SIGHASH_SINGLE|SIGHASH_ANYONECANPAY", - }; - f.write_str(s) - } -} - -impl str::FromStr for EcdsaSighashType { - type Err = SighashTypeParseError; - - fn from_str(s: &str) -> Result { - match s { - "SIGHASH_ALL" => Ok(EcdsaSighashType::All), - "SIGHASH_NONE" => Ok(EcdsaSighashType::None), - "SIGHASH_SINGLE" => Ok(EcdsaSighashType::Single), - "SIGHASH_ALL|SIGHASH_ANYONECANPAY" => Ok(EcdsaSighashType::AllPlusAnyoneCanPay), - "SIGHASH_NONE|SIGHASH_ANYONECANPAY" => Ok(EcdsaSighashType::NonePlusAnyoneCanPay), - "SIGHASH_SINGLE|SIGHASH_ANYONECANPAY" => Ok(EcdsaSighashType::SinglePlusAnyoneCanPay), - _ => Err(SighashTypeParseError { unrecognized: s.to_owned() }), - } - } -} - -impl EcdsaSighashType { - /// Splits the sighash flag into the "real" sighash flag and the ANYONECANPAY boolean. - pub(crate) fn split_anyonecanpay_flag(self) -> (EcdsaSighashType, bool) { - match self { - EcdsaSighashType::All => (EcdsaSighashType::All, false), - EcdsaSighashType::None => (EcdsaSighashType::None, false), - EcdsaSighashType::Single => (EcdsaSighashType::Single, false), - EcdsaSighashType::AllPlusAnyoneCanPay => (EcdsaSighashType::All, true), - EcdsaSighashType::NonePlusAnyoneCanPay => (EcdsaSighashType::None, true), - EcdsaSighashType::SinglePlusAnyoneCanPay => (EcdsaSighashType::Single, true) - } - } - - /// Creates a [`EcdsaSighashType`] from a raw `u32`. - #[deprecated(since="0.28.0", note="please use `from_consensus`")] - pub fn from_u32_consensus(n: u32) -> EcdsaSighashType { - EcdsaSighashType::from_consensus(n) - } - - /// Creates a [`EcdsaSighashType`] from a raw `u32`. - /// - /// **Note**: this replicates consensus behaviour, for current standardness rules correctness - /// you probably want [`Self::from_standard`]. - /// - /// This might cause unexpected behavior because it does not roundtrip. That is, - /// `EcdsaSighashType::from_consensus(n) as u32 != n` for non-standard values of `n`. While - /// verifying signatures, the user should retain the `n` and use it compute the signature hash - /// message. - pub fn from_consensus(n: u32) -> EcdsaSighashType { - // In Bitcoin Core, the SignatureHash function will mask the (int32) value with - // 0x1f to (apparently) deactivate ACP when checking for SINGLE and NONE bits. - // We however want to be matching also against on ACP-masked ALL, SINGLE, and NONE. - // So here we re-activate ACP. - let mask = 0x1f | 0x80; - match n & mask { - // "real" sighashes - 0x01 => EcdsaSighashType::All, - 0x02 => EcdsaSighashType::None, - 0x03 => EcdsaSighashType::Single, - 0x81 => EcdsaSighashType::AllPlusAnyoneCanPay, - 0x82 => EcdsaSighashType::NonePlusAnyoneCanPay, - 0x83 => EcdsaSighashType::SinglePlusAnyoneCanPay, - // catchalls - x if x & 0x80 == 0x80 => EcdsaSighashType::AllPlusAnyoneCanPay, - _ => EcdsaSighashType::All - } - } - - /// Creates a [`EcdsaSighashType`] from a raw `u32`. - #[deprecated(since="0.28.0", note="please use `from_standard`")] - pub fn from_u32_standard(n: u32) -> Result { - EcdsaSighashType::from_standard(n) - } - - /// Creates a [`EcdsaSighashType`] from a raw `u32`. - /// - /// # Errors - /// - /// If `n` is a non-standard sighash value. - pub fn from_standard(n: u32) -> Result { - match n { - // Standard sighashes, see https://github.com/bitcoin/bitcoin/blob/b805dbb0b9c90dadef0424e5b3bf86ac308e103e/src/script/interpreter.cpp#L189-L198 - 0x01 => Ok(EcdsaSighashType::All), - 0x02 => Ok(EcdsaSighashType::None), - 0x03 => Ok(EcdsaSighashType::Single), - 0x81 => Ok(EcdsaSighashType::AllPlusAnyoneCanPay), - 0x82 => Ok(EcdsaSighashType::NonePlusAnyoneCanPay), - 0x83 => Ok(EcdsaSighashType::SinglePlusAnyoneCanPay), - non_standard => Err(NonStandardSighashType(non_standard)) - } - } - - /// Converts [`EcdsaSighashType`] to a `u32` sighash flag. - /// - /// The returned value is guaranteed to be a valid according to standardness rules. - pub fn to_u32(self) -> u32 { self as u32 } -} - -/// Error returned for failure during parsing one of the sighash types. -/// -/// This is currently returned for unrecognized sighash strings. -#[derive(Debug, Clone)] -pub struct SighashTypeParseError { - /// The unrecognized string we attempted to parse. - pub unrecognized: String, -} - -impl fmt::Display for SighashTypeParseError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Unrecognized SIGHASH string '{}'", self.unrecognized) - } -} - -#[cfg(feature = "std")] -#[cfg_attr(docsrs, doc(cfg(feature = "std")))] -impl std::error::Error for SighashTypeParseError { - fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - None - } -} +#[deprecated(since = "0.30.0", note = "use crate::NonStandardSighashType instead")] +pub use crate::util::sighash::NonStandardSighashType; +#[deprecated(since = "0.30.0", note = "use crate::EcdsaSighashType instead")] +pub use crate::util::sighash::EcdsaSighashType; +#[deprecated(since = "0.30.0", note = "use crate::SighashTypeParseError instead")] +pub use crate::util::sighash::SighashTypeParseError; #[cfg(test)] mod tests { @@ -1207,7 +1040,7 @@ mod tests { use crate::hashes::hex::FromHex; use crate::hash_types::*; - use super::EcdsaSighashType; + use crate::util::sighash::NonStandardSighashType; const SOME_TX: &str = "0100000001a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff0100e1f505000000001976a9140389035a9225b3839e2bbf32d826a1e222031fd888ac00000000"; diff --git a/src/blockdata/witness.rs b/src/blockdata/witness.rs index 9b16e647..6f2ff7f5 100644 --- a/src/blockdata/witness.rs +++ b/src/blockdata/witness.rs @@ -7,9 +7,9 @@ use secp256k1::ecdsa; -use crate::blockdata::transaction::EcdsaSighashType; use crate::consensus::encode::{Error, MAX_VEC_SIZE}; use crate::consensus::{Decodable, Encodable, WriteExt}; +use crate::util::sighash::EcdsaSighashType; use crate::io::{self, Read, Write}; use crate::prelude::*; use crate::VarInt; diff --git a/src/lib.rs b/src/lib.rs index c962da7a..1d3280f7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -100,10 +100,7 @@ pub use crate::blockdata::locktime::{self, LockTime, PackedLockTime}; pub use crate::blockdata::script::Script; #[allow(deprecated)] pub use crate::blockdata::transaction::SigHashType; -pub use crate::blockdata::transaction::{ - EcdsaSighashType, NonStandardSighashType, OutPoint, Sequence, SighashTypeParseError, - Transaction, TxIn, TxOut, -}; +pub use crate::blockdata::transaction::{OutPoint, Sequence, Transaction, TxIn, TxOut}; pub use crate::blockdata::witness::Witness; pub use crate::consensus::encode::VarInt; pub use crate::hash_types::*; @@ -114,7 +111,10 @@ pub use crate::util::ecdsa::{self, EcdsaSig, EcdsaSigError}; pub use crate::util::key::{KeyPair, PrivateKey, PublicKey, XOnlyPublicKey}; pub use crate::util::merkleblock::MerkleBlock; pub use crate::util::schnorr::{self, SchnorrSig, SchnorrSigError}; -pub use crate::util::sighash::{SchnorrSighashType, SighashCache}; +pub use crate::util::sighash::{ + EcdsaSighashType, NonStandardSighashType, SchnorrSighashType, SighashCache, + SighashTypeParseError, +}; pub use crate::util::{psbt, Error}; #[cfg(not(feature = "std"))] diff --git a/src/util/bip143.rs b/src/util/bip143.rs index c4b35e34..34c739d2 100644 --- a/src/util/bip143.rs +++ b/src/util/bip143.rs @@ -16,10 +16,10 @@ use crate::io; use crate::hashes::Hash; use crate::hash_types::Sighash; use crate::blockdata::script::Script; -use crate::blockdata::transaction::{Transaction, EcdsaSighashType}; +use crate::blockdata::transaction::Transaction; use crate::blockdata::witness::Witness; use crate::consensus::encode; -use crate::util::sighash; +use crate::util::sighash::{self, EcdsaSighashType}; /// A replacement for SigHashComponents which supports all sighash modes #[deprecated(since = "0.28.0", note = "please use [sighash::SighashCache] instead")] @@ -78,9 +78,8 @@ impl> SigHashCache { /// panics if `input_index` is out of bounds with respect of the number of inputs /// /// ``` - /// use bitcoin::blockdata::transaction::{Transaction, EcdsaSighashType}; /// use bitcoin::util::bip143::SigHashCache; - /// use bitcoin::{PackedLockTime, Script}; + /// use bitcoin::{EcdsaSighashType, Script, Transaction, PackedLockTime}; /// /// let mut tx_to_sign = Transaction { version: 2, lock_time: PackedLockTime::ZERO, input: Vec::new(), output: Vec::new() }; /// let input_count = tx_to_sign.input.len(); diff --git a/src/util/ecdsa.rs b/src/util/ecdsa.rs index 7ae9cff3..50116723 100644 --- a/src/util/ecdsa.rs +++ b/src/util/ecdsa.rs @@ -12,9 +12,8 @@ use secp256k1; use crate::prelude::*; use crate::hashes::hex::{self, FromHex}; -use crate::blockdata::transaction::NonStandardSighashType; -use crate::EcdsaSighashType; use crate::internal_macros::write_err; +use crate::util::sighash::{EcdsaSighashType, NonStandardSighashType}; /// An ECDSA signature with the corresponding hash type. #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] diff --git a/src/util/psbt/map/input.rs b/src/util/psbt/map/input.rs index e6f0d30b..1e9186f6 100644 --- a/src/util/psbt/map/input.rs +++ b/src/util/psbt/map/input.rs @@ -11,7 +11,7 @@ use secp256k1::XOnlyPublicKey; use crate::blockdata::script::Script; use crate::blockdata::witness::Witness; -use crate::blockdata::transaction::{Transaction, TxOut, NonStandardSighashType, SighashTypeParseError}; +use crate::blockdata::transaction::{Transaction, TxOut}; use crate::consensus::encode; use crate::hashes::{self, hash160, ripemd160, sha256, sha256d}; use crate::util::bip32::KeySource; @@ -21,9 +21,10 @@ use crate::util::psbt::raw; use crate::util::psbt::serialize::Deserialize; use crate::util::psbt::{Error, error}; use crate::util::key::PublicKey; +use crate::util::sighash::{NonStandardSighashType, SighashTypeParseError, EcdsaSighashType, SchnorrSighashType}; use crate::util::taproot::{ControlBlock, LeafVersion, TapLeafHash, TapBranchHash}; use crate::util::sighash; -use crate::{EcdsaSighashType, SchnorrSighashType, EcdsaSig, SchnorrSig}; +use crate::{EcdsaSig, SchnorrSig}; /// Type: Non-Witness UTXO PSBT_IN_NON_WITNESS_UTXO = 0x00 const PSBT_IN_NON_WITNESS_UTXO: u8 = 0x00; diff --git a/src/util/psbt/mod.rs b/src/util/psbt/mod.rs index 2cb7e6e7..6ee66e82 100644 --- a/src/util/psbt/mod.rs +++ b/src/util/psbt/mod.rs @@ -598,12 +598,13 @@ mod tests { use crate::hash_types::Txid; use crate::blockdata::script::Script; - use crate::blockdata::transaction::{EcdsaSighashType, Transaction, TxIn, TxOut, OutPoint, Sequence}; + use crate::blockdata::transaction::{Transaction, TxIn, TxOut, OutPoint, Sequence}; use crate::consensus::encode::serialize_hex; use crate::blockdata::locktime::PackedLockTime; use crate::util::psbt::map::{Map, Input, Output}; use crate::util::psbt::raw; use crate::util::psbt::{PartiallySignedTransaction, Error}; + use crate::util::sighash::EcdsaSighashType; use std::collections::BTreeMap; use crate::blockdata::witness::Witness; use crate::internal_macros::hex_script; diff --git a/src/util/sighash.rs b/src/util/sighash.rs index 62e9c9ef..90287d57 100644 --- a/src/util/sighash.rs +++ b/src/util/sighash.rs @@ -22,8 +22,6 @@ use crate::internal_macros::serde_string_impl; use crate::prelude::*; use crate::util::taproot::{TapLeafHash, TAPROOT_ANNEX_PREFIX, TapSighashHash, LeafVersion}; -pub use crate::blockdata::transaction::{EcdsaSighashType, SighashTypeParseError}; - /// Used for signature hash for invalid use of SIGHASH_SINGLE. pub(crate) const UINT256_ONE: [u8; 32] = [ 1, 0, 0, 0, 0, 0, 0, 0, @@ -297,6 +295,138 @@ impl<'s> From> for TapLeafHash { } } +/// Hashtype of an input's signature, encoded in the last byte of the signature. +/// +/// Fixed values so they can be cast as integer types for encoding (see also +/// [`SchnorrSighashType`]). +#[derive(PartialEq, Eq, Debug, Copy, Clone, Hash)] +pub enum EcdsaSighashType { + /// 0x1: Sign all outputs. + All = 0x01, + /// 0x2: Sign no outputs --- anyone can choose the destination. + None = 0x02, + /// 0x3: Sign the output whose index matches this input's index. If none exists, + /// sign the hash `0000000000000000000000000000000000000000000000000000000000000001`. + /// (This rule is probably an unintentional C++ism, but it's consensus so we have + /// to follow it.) + Single = 0x03, + /// 0x81: Sign all outputs but only this input. + AllPlusAnyoneCanPay = 0x81, + /// 0x82: Sign no outputs and only this input. + NonePlusAnyoneCanPay = 0x82, + /// 0x83: Sign one output and only this input (see `Single` for what "one output" means). + SinglePlusAnyoneCanPay = 0x83 +} +serde_string_impl!(EcdsaSighashType, "a EcdsaSighashType data"); + +impl fmt::Display for EcdsaSighashType { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let s = match self { + EcdsaSighashType::All => "SIGHASH_ALL", + EcdsaSighashType::None => "SIGHASH_NONE", + EcdsaSighashType::Single => "SIGHASH_SINGLE", + EcdsaSighashType::AllPlusAnyoneCanPay => "SIGHASH_ALL|SIGHASH_ANYONECANPAY", + EcdsaSighashType::NonePlusAnyoneCanPay => "SIGHASH_NONE|SIGHASH_ANYONECANPAY", + EcdsaSighashType::SinglePlusAnyoneCanPay => "SIGHASH_SINGLE|SIGHASH_ANYONECANPAY", + }; + f.write_str(s) + } +} + +impl str::FromStr for EcdsaSighashType { + type Err = SighashTypeParseError; + + fn from_str(s: &str) -> Result { + match s { + "SIGHASH_ALL" => Ok(EcdsaSighashType::All), + "SIGHASH_NONE" => Ok(EcdsaSighashType::None), + "SIGHASH_SINGLE" => Ok(EcdsaSighashType::Single), + "SIGHASH_ALL|SIGHASH_ANYONECANPAY" => Ok(EcdsaSighashType::AllPlusAnyoneCanPay), + "SIGHASH_NONE|SIGHASH_ANYONECANPAY" => Ok(EcdsaSighashType::NonePlusAnyoneCanPay), + "SIGHASH_SINGLE|SIGHASH_ANYONECANPAY" => Ok(EcdsaSighashType::SinglePlusAnyoneCanPay), + _ => Err(SighashTypeParseError { unrecognized: s.to_owned() }), + } + } +} + +impl EcdsaSighashType { + /// Splits the sighash flag into the "real" sighash flag and the ANYONECANPAY boolean. + pub(crate) fn split_anyonecanpay_flag(self) -> (EcdsaSighashType, bool) { + match self { + EcdsaSighashType::All => (EcdsaSighashType::All, false), + EcdsaSighashType::None => (EcdsaSighashType::None, false), + EcdsaSighashType::Single => (EcdsaSighashType::Single, false), + EcdsaSighashType::AllPlusAnyoneCanPay => (EcdsaSighashType::All, true), + EcdsaSighashType::NonePlusAnyoneCanPay => (EcdsaSighashType::None, true), + EcdsaSighashType::SinglePlusAnyoneCanPay => (EcdsaSighashType::Single, true) + } + } + + /// Creates a [`EcdsaSighashType`] from a raw `u32`. + #[deprecated(since="0.28.0", note="please use `from_consensus`")] + pub fn from_u32_consensus(n: u32) -> EcdsaSighashType { + EcdsaSighashType::from_consensus(n) + } + + /// Creates a [`EcdsaSighashType`] from a raw `u32`. + /// + /// **Note**: this replicates consensus behaviour, for current standardness rules correctness + /// you probably want [`Self::from_standard`]. + /// + /// This might cause unexpected behavior because it does not roundtrip. That is, + /// `EcdsaSighashType::from_consensus(n) as u32 != n` for non-standard values of `n`. While + /// verifying signatures, the user should retain the `n` and use it compute the signature hash + /// message. + pub fn from_consensus(n: u32) -> EcdsaSighashType { + // In Bitcoin Core, the SignatureHash function will mask the (int32) value with + // 0x1f to (apparently) deactivate ACP when checking for SINGLE and NONE bits. + // We however want to be matching also against on ACP-masked ALL, SINGLE, and NONE. + // So here we re-activate ACP. + let mask = 0x1f | 0x80; + match n & mask { + // "real" sighashes + 0x01 => EcdsaSighashType::All, + 0x02 => EcdsaSighashType::None, + 0x03 => EcdsaSighashType::Single, + 0x81 => EcdsaSighashType::AllPlusAnyoneCanPay, + 0x82 => EcdsaSighashType::NonePlusAnyoneCanPay, + 0x83 => EcdsaSighashType::SinglePlusAnyoneCanPay, + // catchalls + x if x & 0x80 == 0x80 => EcdsaSighashType::AllPlusAnyoneCanPay, + _ => EcdsaSighashType::All + } + } + + /// Creates a [`EcdsaSighashType`] from a raw `u32`. + #[deprecated(since="0.28.0", note="please use `from_standard`")] + pub fn from_u32_standard(n: u32) -> Result { + EcdsaSighashType::from_standard(n) + } + + /// Creates a [`EcdsaSighashType`] from a raw `u32`. + /// + /// # Errors + /// + /// If `n` is a non-standard sighash value. + pub fn from_standard(n: u32) -> Result { + match n { + // Standard sighashes, see https://github.com/bitcoin/bitcoin/blob/b805dbb0b9c90dadef0424e5b3bf86ac308e103e/src/script/interpreter.cpp#L189-L198 + 0x01 => Ok(EcdsaSighashType::All), + 0x02 => Ok(EcdsaSighashType::None), + 0x03 => Ok(EcdsaSighashType::Single), + 0x81 => Ok(EcdsaSighashType::AllPlusAnyoneCanPay), + 0x82 => Ok(EcdsaSighashType::NonePlusAnyoneCanPay), + 0x83 => Ok(EcdsaSighashType::SinglePlusAnyoneCanPay), + non_standard => Err(NonStandardSighashType(non_standard)) + } + } + + /// Converts [`EcdsaSighashType`] to a `u32` sighash flag. + /// + /// The returned value is guaranteed to be a valid according to standardness rules. + pub fn to_u32(self) -> u32 { self as u32 } +} + impl From for SchnorrSighashType { fn from(s: EcdsaSighashType) -> Self { match s { @@ -347,6 +477,48 @@ impl SchnorrSighashType { } } +/// 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)] +pub struct NonStandardSighashType(pub u32); + +impl fmt::Display for NonStandardSighashType { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Non standard sighash type {}", self.0) + } +} + +#[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] +impl std::error::Error for NonStandardSighashType { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + None + } +} + +/// Error returned for failure during parsing one of the sighash types. +/// +/// This is currently returned for unrecognized sighash strings. +#[derive(Debug, Clone)] +pub struct SighashTypeParseError { + /// The unrecognized string we attempted to parse. + pub unrecognized: String, +} + +impl fmt::Display for SighashTypeParseError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Unrecognized SIGHASH string '{}'", self.unrecognized) + } +} + +#[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] +impl std::error::Error for SighashTypeParseError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + None + } +} + impl> SighashCache { /// Constructs a new `SighashCache` from an unsigned transaction. /// @@ -863,8 +1035,8 @@ impl> SighashCache { /// /// This allows in-line signing such as /// ``` - /// use bitcoin::blockdata::transaction::{Transaction, EcdsaSighashType}; - /// use bitcoin::util::sighash::SighashCache; + /// use bitcoin::blockdata::transaction::Transaction; + /// use bitcoin::util::sighash::{EcdsaSighashType, SighashCache}; /// use bitcoin::{PackedLockTime, Script}; /// /// let mut tx_to_sign = Transaction { version: 2, lock_time: PackedLockTime::ZERO, input: Vec::new(), output: Vec::new() };