diff --git a/Cargo-minimal.lock b/Cargo-minimal.lock index 8646c016f..a6dd5ab4a 100644 --- a/Cargo-minimal.lock +++ b/Cargo-minimal.lock @@ -113,6 +113,7 @@ dependencies = [ "bitcoin-internals", "bitcoin-io", "bitcoin-units", + "bitcoin_hashes", "mutagen", "ordered", "serde", diff --git a/Cargo-recent.lock b/Cargo-recent.lock index af67f9316..2be0c9915 100644 --- a/Cargo-recent.lock +++ b/Cargo-recent.lock @@ -112,6 +112,7 @@ dependencies = [ "bitcoin-internals", "bitcoin-io", "bitcoin-units", + "bitcoin_hashes", "mutagen", "ordered", "serde", diff --git a/bitcoin/examples/ecdsa-psbt-simple.rs b/bitcoin/examples/ecdsa-psbt-simple.rs index b96cb7367..1acfab8e9 100644 --- a/bitcoin/examples/ecdsa-psbt-simple.rs +++ b/bitcoin/examples/ecdsa-psbt-simple.rs @@ -101,7 +101,7 @@ fn dummy_unspent_transaction_outputs() -> Vec<(OutPoint, TxOut)> { .script_pubkey(); let out_point_1 = OutPoint { - txid: Txid::all_zeros(), // Obviously invalid. + txid: Txid::from_byte_array([0xFF; 32]), // Arbitrary invalid dummy value. vout: 0, }; @@ -115,7 +115,7 @@ fn dummy_unspent_transaction_outputs() -> Vec<(OutPoint, TxOut)> { .script_pubkey(); let out_point_2 = OutPoint { - txid: Txid::all_zeros(), // Obviously invalid. + txid: Txid::from_byte_array([0xFF; 32]), // Arbitrary invalid dummy value. vout: 1, }; diff --git a/bitcoin/examples/sign-tx-segwit-v0.rs b/bitcoin/examples/sign-tx-segwit-v0.rs index 932663c94..997104d66 100644 --- a/bitcoin/examples/sign-tx-segwit-v0.rs +++ b/bitcoin/examples/sign-tx-segwit-v0.rs @@ -119,7 +119,7 @@ fn dummy_unspent_transaction_output(wpkh: WPubkeyHash) -> (OutPoint, TxOut) { let script_pubkey = ScriptBuf::new_p2wpkh(wpkh); let out_point = OutPoint { - txid: Txid::all_zeros(), // Obviously invalid. + txid: Txid::from_byte_array([0xFF; 32]), // Arbitrary invalid dummy value. vout: 0, }; diff --git a/bitcoin/examples/sign-tx-taproot.rs b/bitcoin/examples/sign-tx-taproot.rs index 23b8b2923..c56f5e912 100644 --- a/bitcoin/examples/sign-tx-taproot.rs +++ b/bitcoin/examples/sign-tx-taproot.rs @@ -119,7 +119,7 @@ fn dummy_unspent_transaction_output( let script_pubkey = ScriptBuf::new_p2tr(secp, internal_key, None); let out_point = OutPoint { - txid: Txid::all_zeros(), // Obviously invalid. + txid: Txid::from_byte_array([0xFF; 32]), // Arbitrary invalid dummy value. vout: 0, }; diff --git a/bitcoin/examples/taproot-psbt-simple.rs b/bitcoin/examples/taproot-psbt-simple.rs index edd375ec6..90fc3a602 100644 --- a/bitcoin/examples/taproot-psbt-simple.rs +++ b/bitcoin/examples/taproot-psbt-simple.rs @@ -111,7 +111,7 @@ fn dummy_unspent_transaction_outputs() -> Vec<(OutPoint, TxOut)> { .script_pubkey(); let out_point_1 = OutPoint { - txid: Txid::all_zeros(), // Obviously invalid. + txid: Txid::from_byte_array([0xFF; 32]), // Arbitrary invalid dummy value. vout: 0, }; @@ -125,7 +125,7 @@ fn dummy_unspent_transaction_outputs() -> Vec<(OutPoint, TxOut)> { .script_pubkey(); let out_point_2 = OutPoint { - txid: Txid::all_zeros(), // Obviously invalid. + txid: Txid::from_byte_array([0xFF; 32]), // Arbitrary invalid dummy value. vout: 1, }; diff --git a/bitcoin/src/blockdata/block.rs b/bitcoin/src/blockdata/block.rs index 2578e3f8d..1670389d4 100644 --- a/bitcoin/src/blockdata/block.rs +++ b/bitcoin/src/blockdata/block.rs @@ -305,7 +305,7 @@ impl Block { let hashes = self.txdata.iter().enumerate().map(|(i, t)| { if i == 0 { // Replace the first hash with zeroes. - Wtxid::all_zeros() + Wtxid::COINBASE } else { t.compute_wtxid() } diff --git a/bitcoin/src/blockdata/constants.rs b/bitcoin/src/blockdata/constants.rs index d55133916..e1d49833c 100644 --- a/bitcoin/src/blockdata/constants.rs +++ b/bitcoin/src/blockdata/constants.rs @@ -226,7 +226,7 @@ mod test { assert_eq!(gen.version, transaction::Version::ONE); assert_eq!(gen.input.len(), 1); - assert_eq!(gen.input[0].previous_output.txid, Txid::all_zeros()); + assert_eq!(gen.input[0].previous_output.txid, Txid::COINBASE_PREVOUT); assert_eq!(gen.input[0].previous_output.vout, 0xFFFFFFFF); assert_eq!(serialize(&gen.input[0].script_sig), hex!("4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73")); diff --git a/bitcoin/src/blockdata/transaction.rs b/bitcoin/src/blockdata/transaction.rs index bcbd3525d..174afff09 100644 --- a/bitcoin/src/blockdata/transaction.rs +++ b/bitcoin/src/blockdata/transaction.rs @@ -35,47 +35,25 @@ use crate::{Amount, FeeRate, SignedAmount, VarInt}; #[doc(inline)] pub use primitives::transaction::*; -hashes::hash_newtype! { - /// A bitcoin transaction hash/transaction ID. - /// - /// For compatibility with the existing Bitcoin infrastructure and historical and current - /// versions of the Bitcoin Core software itself, this and other [`sha256d::Hash`] types, are - /// serialized in reverse byte order when converted to a hex string via [`std::fmt::Display`] - /// trait operations. - /// - /// See [`hashes::Hash::DISPLAY_BACKWARD`] for more details. - pub struct Txid(sha256d::Hash); - - /// A bitcoin witness transaction ID. - pub struct Wtxid(sha256d::Hash); -} impl_hashencode!(Txid); impl_hashencode!(Wtxid); -impl Txid { - /// The `Txid` used in a coinbase prevout. - /// - /// This is used as the "txid" of the dummy input of a coinbase transaction. This is not a real - /// TXID and should not be used in any other contexts. See [`OutPoint::COINBASE_PREVOUT`]. - pub const COINBASE_PREVOUT: Self = Self::from_byte_array([0; 32]); - - /// The "all zeros" TXID. - #[deprecated(since = "TBD", note = "use Txid::COINBASE_PREVOUT instead")] - pub fn all_zeros() -> Self { Self::COINBASE_PREVOUT } +crate::internal_macros::define_extension_trait! { + /// Extension functionality for the [`Txid`] type. + pub trait TxidExt impl for Txid { + /// The "all zeros" TXID. + #[deprecated(since = "TBD", note = "use Txid::COINBASE_PREVOUT instead")] + fn all_zeros() -> Self { Self::COINBASE_PREVOUT } + } } -impl Wtxid { - /// The `Wtxid` of a coinbase transaction. - /// - /// This is used as the wTXID for the coinbase transaction when constructing blocks, - /// since the coinbase transaction contains a commitment to all transactions' wTXIDs - /// but naturally cannot commit to its own. It is not a real wTXID and should not be - /// used in other contexts. - pub const COINBASE: Self = Self::from_byte_array([0; 32]); - - /// The "all zeros" wTXID. - #[deprecated(since = "TBD", note = "use Wtxid::COINBASE instead")] - pub fn all_zeros() -> Self { Self::COINBASE } +crate::internal_macros::define_extension_trait! { + /// Extension functionality for the [`Wtxid`] type. + pub trait WtxidExt impl for Wtxid { + /// The "all zeros" wTXID. + #[deprecated(since = "TBD", note = "use Wtxid::COINBASE instead")] + fn all_zeros() -> Self { Self::COINBASE } + } } /// Trait that abstracts over a transaction identifier i.e., `Txid` and `Wtxid`. @@ -117,7 +95,7 @@ impl OutPoint { /// The `OutPoint` used in a coinbase prevout. /// /// This is used as the dummy input for coinbase transactions because they don't have any - /// previous outputs. This is not a real outpoint and should not be used in any other contexts. + /// previous outputs. In other words, does not point to a real transaction. pub const COINBASE_PREVOUT: Self = Self { txid: Txid::COINBASE_PREVOUT, vout: u32::MAX }; /// Creates a new [`OutPoint`]. @@ -583,7 +561,7 @@ impl Transaction { self.input.consensus_encode(&mut enc).expect("engines don't error"); self.output.consensus_encode(&mut enc).expect("engines don't error"); self.lock_time.consensus_encode(&mut enc).expect("engines don't error"); - Txid(sha256d::Hash::from_engine(enc)) + Txid::from_byte_array(sha256d::Hash::from_engine(enc).to_byte_array()) } /// Computes the segwit version of the transaction id. @@ -604,7 +582,7 @@ impl Transaction { pub fn compute_wtxid(&self) -> Wtxid { let mut enc = sha256d::Hash::engine(); self.consensus_encode(&mut enc).expect("engines don't error"); - Wtxid(sha256d::Hash::from_engine(enc)) + Wtxid::from_byte_array(sha256d::Hash::from_engine(enc).to_byte_array()) } /// Returns the weight of this transaction, as defined by BIP-141. diff --git a/bitcoin/src/internal_macros.rs b/bitcoin/src/internal_macros.rs index e59f2f4e1..208dbb688 100644 --- a/bitcoin/src/internal_macros.rs +++ b/bitcoin/src/internal_macros.rs @@ -181,7 +181,7 @@ macro_rules! impl_hashencode { ($hashtype:ident) => { impl $crate::consensus::Encodable for $hashtype { fn consensus_encode(&self, w: &mut W) -> core::result::Result { - self.0.consensus_encode(w) + self.as_byte_array().consensus_encode(w) } } diff --git a/bitcoin/src/merkle_tree/mod.rs b/bitcoin/src/merkle_tree/mod.rs index f024482b0..39c9310b3 100644 --- a/bitcoin/src/merkle_tree/mod.rs +++ b/bitcoin/src/merkle_tree/mod.rs @@ -8,8 +8,8 @@ //! # use bitcoin::Txid; //! # use bitcoin::merkle_tree::{MerkleNode as _, TxMerkleNode}; //! # use bitcoin::hashes::Hash; -//! # let tx1 = Txid::all_zeros(); // Dummy hash values. -//! # let tx2 = Txid::all_zeros(); +//! # let tx1 = Txid::from_byte_array([0xAA; 32]); // Arbitrary dummy hash values. +//! # let tx2 = Txid::from_byte_array([0xFF; 32]); //! let tx_hashes = vec![tx1, tx2]; // All the hashes we wish to merkelize. //! let root = TxMerkleNode::calculate_root(tx_hashes.into_iter()); //! ``` diff --git a/primitives/Cargo.toml b/primitives/Cargo.toml index 9a293fdaf..64329f9d1 100644 --- a/primitives/Cargo.toml +++ b/primitives/Cargo.toml @@ -16,11 +16,12 @@ exclude = ["tests", "contrib"] [features] default = ["std"] -std = ["alloc", "internals/std", "io/std", "units/std"] -alloc = ["internals/alloc", "io/alloc", "units/alloc"] -serde = ["dep:serde", "internals/serde", "units/serde", "alloc"] +std = ["alloc", "hashes/std", "internals/std", "io/std", "units/std"] +alloc = ["hashes/alloc", "internals/alloc", "io/alloc", "units/alloc"] +serde = ["dep:serde", "hashes/serde", "internals/serde", "units/serde", "alloc"] [dependencies] +hashes = { package = "bitcoin_hashes", version = "0.14.0", default-features = false, features = ["bitcoin-io"] } internals = { package = "bitcoin-internals", version = "0.3.0" } io = { package = "bitcoin-io", version = "0.1.1", default-features = false } units = { package = "bitcoin-units", version = "0.1.0", default-features = false } diff --git a/primitives/src/lib.rs b/primitives/src/lib.rs index 0383ffca9..e6743bc1e 100644 --- a/primitives/src/lib.rs +++ b/primitives/src/lib.rs @@ -42,7 +42,11 @@ pub use units::*; #[cfg(feature = "alloc")] pub use self::locktime::{absolute, relative}; #[doc(inline)] -pub use self::{pow::CompactTarget, sequence::Sequence}; +pub use self::{ + pow::CompactTarget, + sequence::Sequence, + transaction::{Txid, Wtxid}, +}; #[rustfmt::skip] #[allow(unused_imports)] diff --git a/primitives/src/transaction.rs b/primitives/src/transaction.rs index 7b0701002..6d705e724 100644 --- a/primitives/src/transaction.rs +++ b/primitives/src/transaction.rs @@ -12,6 +12,40 @@ use core::fmt; +use hashes::sha256d; + +hashes::hash_newtype! { + /// A bitcoin transaction hash/transaction ID. + /// + /// For compatibility with the existing Bitcoin infrastructure and historical and current + /// versions of the Bitcoin Core software itself, this and other [`sha256d::Hash`] types, are + /// serialized in reverse byte order when converted to a hex string via [`std::fmt::Display`] + /// trait operations. + /// + /// See [`hashes::Hash::DISPLAY_BACKWARD`] for more details. + pub struct Txid(sha256d::Hash); + + /// A bitcoin witness transaction ID. + pub struct Wtxid(sha256d::Hash); +} + +impl Txid { + /// The `Txid` used in a coinbase prevout. + /// + /// This is used as the "txid" of the dummy input of a coinbase transaction. This is not a real + /// TXID and should not be used in any other contexts. See `OutPoint::COINBASE_PREVOUT`. + pub const COINBASE_PREVOUT: Self = Self::from_byte_array([0; 32]); +} + +impl Wtxid { + /// The `Wtxid` of a coinbase transaction. + /// + /// This is used as the wTXID for the coinbase transaction when constructing blocks (in the + /// witness commitment tree) since the coinbase transaction contains a commitment to all + /// transactions' wTXIDs but naturally cannot commit to its own. + pub const COINBASE: Self = Self::from_byte_array([0; 32]); +} + /// The transaction version. /// /// Currently, as specified by [BIP-68], only version 1 and 2 are considered standard.