Merge rust-bitcoin/rust-bitcoin#3288: priority: Move txid hash types to `primitives`
0403e52ce3
Move the transaction hash types over to primitives (Tobin C. Harding)7e454d756d
Define extension traits for txid types (Tobin C. Harding)832b726d03
Stop using all_zeros (Tobin C. Harding)d69c241b5c
Improve docs on associated consts (Tobin C. Harding)68c9e28165
Do not use private constructor for txid hash types (Tobin C. Harding)98328b5a7b
Use as_byte_array to encode hash type (Tobin C. Harding) Pull request description: Move the `Txid` and `Wtxid` hash wrapper types over to `primitives`. This introduces to `primitves` an unconditional dependency on `hashes`. ACKs for top commit: Kixunil: ACK0403e52ce3
apoelstra: ACK0403e52ce3
successfully ran local tests Tree-SHA512: d14fa95bc12c2399d30d4d640b5a3fce625d51adf587a8037158f7d7e7b6288170b2d4418ca2cb68f612086ea0bdd0fae3b577f84f0d60627072fdb2217a6531
This commit is contained in:
commit
0c2737f25a
|
@ -113,6 +113,7 @@ dependencies = [
|
||||||
"bitcoin-internals",
|
"bitcoin-internals",
|
||||||
"bitcoin-io",
|
"bitcoin-io",
|
||||||
"bitcoin-units",
|
"bitcoin-units",
|
||||||
|
"bitcoin_hashes",
|
||||||
"mutagen",
|
"mutagen",
|
||||||
"ordered",
|
"ordered",
|
||||||
"serde",
|
"serde",
|
||||||
|
|
|
@ -112,6 +112,7 @@ dependencies = [
|
||||||
"bitcoin-internals",
|
"bitcoin-internals",
|
||||||
"bitcoin-io",
|
"bitcoin-io",
|
||||||
"bitcoin-units",
|
"bitcoin-units",
|
||||||
|
"bitcoin_hashes",
|
||||||
"mutagen",
|
"mutagen",
|
||||||
"ordered",
|
"ordered",
|
||||||
"serde",
|
"serde",
|
||||||
|
|
|
@ -101,7 +101,7 @@ fn dummy_unspent_transaction_outputs() -> Vec<(OutPoint, TxOut)> {
|
||||||
.script_pubkey();
|
.script_pubkey();
|
||||||
|
|
||||||
let out_point_1 = OutPoint {
|
let out_point_1 = OutPoint {
|
||||||
txid: Txid::all_zeros(), // Obviously invalid.
|
txid: Txid::from_byte_array([0xFF; 32]), // Arbitrary invalid dummy value.
|
||||||
vout: 0,
|
vout: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -115,7 +115,7 @@ fn dummy_unspent_transaction_outputs() -> Vec<(OutPoint, TxOut)> {
|
||||||
.script_pubkey();
|
.script_pubkey();
|
||||||
|
|
||||||
let out_point_2 = OutPoint {
|
let out_point_2 = OutPoint {
|
||||||
txid: Txid::all_zeros(), // Obviously invalid.
|
txid: Txid::from_byte_array([0xFF; 32]), // Arbitrary invalid dummy value.
|
||||||
vout: 1,
|
vout: 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -119,7 +119,7 @@ fn dummy_unspent_transaction_output(wpkh: WPubkeyHash) -> (OutPoint, TxOut) {
|
||||||
let script_pubkey = ScriptBuf::new_p2wpkh(wpkh);
|
let script_pubkey = ScriptBuf::new_p2wpkh(wpkh);
|
||||||
|
|
||||||
let out_point = OutPoint {
|
let out_point = OutPoint {
|
||||||
txid: Txid::all_zeros(), // Obviously invalid.
|
txid: Txid::from_byte_array([0xFF; 32]), // Arbitrary invalid dummy value.
|
||||||
vout: 0,
|
vout: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -119,7 +119,7 @@ fn dummy_unspent_transaction_output<C: Verification>(
|
||||||
let script_pubkey = ScriptBuf::new_p2tr(secp, internal_key, None);
|
let script_pubkey = ScriptBuf::new_p2tr(secp, internal_key, None);
|
||||||
|
|
||||||
let out_point = OutPoint {
|
let out_point = OutPoint {
|
||||||
txid: Txid::all_zeros(), // Obviously invalid.
|
txid: Txid::from_byte_array([0xFF; 32]), // Arbitrary invalid dummy value.
|
||||||
vout: 0,
|
vout: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -111,7 +111,7 @@ fn dummy_unspent_transaction_outputs() -> Vec<(OutPoint, TxOut)> {
|
||||||
.script_pubkey();
|
.script_pubkey();
|
||||||
|
|
||||||
let out_point_1 = OutPoint {
|
let out_point_1 = OutPoint {
|
||||||
txid: Txid::all_zeros(), // Obviously invalid.
|
txid: Txid::from_byte_array([0xFF; 32]), // Arbitrary invalid dummy value.
|
||||||
vout: 0,
|
vout: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -125,7 +125,7 @@ fn dummy_unspent_transaction_outputs() -> Vec<(OutPoint, TxOut)> {
|
||||||
.script_pubkey();
|
.script_pubkey();
|
||||||
|
|
||||||
let out_point_2 = OutPoint {
|
let out_point_2 = OutPoint {
|
||||||
txid: Txid::all_zeros(), // Obviously invalid.
|
txid: Txid::from_byte_array([0xFF; 32]), // Arbitrary invalid dummy value.
|
||||||
vout: 1,
|
vout: 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -305,7 +305,7 @@ impl Block {
|
||||||
let hashes = self.txdata.iter().enumerate().map(|(i, t)| {
|
let hashes = self.txdata.iter().enumerate().map(|(i, t)| {
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
// Replace the first hash with zeroes.
|
// Replace the first hash with zeroes.
|
||||||
Wtxid::all_zeros()
|
Wtxid::COINBASE
|
||||||
} else {
|
} else {
|
||||||
t.compute_wtxid()
|
t.compute_wtxid()
|
||||||
}
|
}
|
||||||
|
|
|
@ -226,7 +226,7 @@ mod test {
|
||||||
|
|
||||||
assert_eq!(gen.version, transaction::Version::ONE);
|
assert_eq!(gen.version, transaction::Version::ONE);
|
||||||
assert_eq!(gen.input.len(), 1);
|
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!(gen.input[0].previous_output.vout, 0xFFFFFFFF);
|
||||||
assert_eq!(serialize(&gen.input[0].script_sig),
|
assert_eq!(serialize(&gen.input[0].script_sig),
|
||||||
hex!("4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73"));
|
hex!("4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73"));
|
||||||
|
|
|
@ -35,47 +35,25 @@ use crate::{Amount, FeeRate, SignedAmount, VarInt};
|
||||||
#[doc(inline)]
|
#[doc(inline)]
|
||||||
pub use primitives::transaction::*;
|
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!(Txid);
|
||||||
impl_hashencode!(Wtxid);
|
impl_hashencode!(Wtxid);
|
||||||
|
|
||||||
impl Txid {
|
crate::internal_macros::define_extension_trait! {
|
||||||
/// The `Txid` used in a coinbase prevout.
|
/// Extension functionality for the [`Txid`] type.
|
||||||
///
|
pub trait TxidExt impl for Txid {
|
||||||
/// This is used as the "txid" of the dummy input of a coinbase transaction. This is not a real
|
/// The "all zeros" TXID.
|
||||||
/// TXID and should not be used in any other contexts. See [`OutPoint::COINBASE_PREVOUT`].
|
#[deprecated(since = "TBD", note = "use Txid::COINBASE_PREVOUT instead")]
|
||||||
pub const COINBASE_PREVOUT: Self = Self::from_byte_array([0; 32]);
|
fn all_zeros() -> Self { Self::COINBASE_PREVOUT }
|
||||||
|
}
|
||||||
/// The "all zeros" TXID.
|
|
||||||
#[deprecated(since = "TBD", note = "use Txid::COINBASE_PREVOUT instead")]
|
|
||||||
pub fn all_zeros() -> Self { Self::COINBASE_PREVOUT }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Wtxid {
|
crate::internal_macros::define_extension_trait! {
|
||||||
/// The `Wtxid` of a coinbase transaction.
|
/// Extension functionality for the [`Wtxid`] type.
|
||||||
///
|
pub trait WtxidExt impl for Wtxid {
|
||||||
/// This is used as the wTXID for the coinbase transaction when constructing blocks,
|
/// The "all zeros" wTXID.
|
||||||
/// since the coinbase transaction contains a commitment to all transactions' wTXIDs
|
#[deprecated(since = "TBD", note = "use Wtxid::COINBASE instead")]
|
||||||
/// but naturally cannot commit to its own. It is not a real wTXID and should not be
|
fn all_zeros() -> Self { Self::COINBASE }
|
||||||
/// 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 }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Trait that abstracts over a transaction identifier i.e., `Txid` and `Wtxid`.
|
/// 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.
|
/// The `OutPoint` used in a coinbase prevout.
|
||||||
///
|
///
|
||||||
/// This is used as the dummy input for coinbase transactions because they don't have any
|
/// 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 };
|
pub const COINBASE_PREVOUT: Self = Self { txid: Txid::COINBASE_PREVOUT, vout: u32::MAX };
|
||||||
|
|
||||||
/// Creates a new [`OutPoint`].
|
/// Creates a new [`OutPoint`].
|
||||||
|
@ -583,7 +561,7 @@ impl Transaction {
|
||||||
self.input.consensus_encode(&mut enc).expect("engines don't error");
|
self.input.consensus_encode(&mut enc).expect("engines don't error");
|
||||||
self.output.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");
|
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.
|
/// Computes the segwit version of the transaction id.
|
||||||
|
@ -604,7 +582,7 @@ impl Transaction {
|
||||||
pub fn compute_wtxid(&self) -> Wtxid {
|
pub fn compute_wtxid(&self) -> Wtxid {
|
||||||
let mut enc = sha256d::Hash::engine();
|
let mut enc = sha256d::Hash::engine();
|
||||||
self.consensus_encode(&mut enc).expect("engines don't error");
|
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.
|
/// Returns the weight of this transaction, as defined by BIP-141.
|
||||||
|
|
|
@ -181,7 +181,7 @@ macro_rules! impl_hashencode {
|
||||||
($hashtype:ident) => {
|
($hashtype:ident) => {
|
||||||
impl $crate::consensus::Encodable for $hashtype {
|
impl $crate::consensus::Encodable for $hashtype {
|
||||||
fn consensus_encode<W: $crate::io::Write + ?Sized>(&self, w: &mut W) -> core::result::Result<usize, $crate::io::Error> {
|
fn consensus_encode<W: $crate::io::Write + ?Sized>(&self, w: &mut W) -> core::result::Result<usize, $crate::io::Error> {
|
||||||
self.0.consensus_encode(w)
|
self.as_byte_array().consensus_encode(w)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,8 @@
|
||||||
//! # use bitcoin::Txid;
|
//! # use bitcoin::Txid;
|
||||||
//! # use bitcoin::merkle_tree::{MerkleNode as _, TxMerkleNode};
|
//! # use bitcoin::merkle_tree::{MerkleNode as _, TxMerkleNode};
|
||||||
//! # use bitcoin::hashes::Hash;
|
//! # use bitcoin::hashes::Hash;
|
||||||
//! # let tx1 = Txid::all_zeros(); // Dummy hash values.
|
//! # let tx1 = Txid::from_byte_array([0xAA; 32]); // Arbitrary dummy hash values.
|
||||||
//! # let tx2 = Txid::all_zeros();
|
//! # let tx2 = Txid::from_byte_array([0xFF; 32]);
|
||||||
//! let tx_hashes = vec![tx1, tx2]; // All the hashes we wish to merkelize.
|
//! let tx_hashes = vec![tx1, tx2]; // All the hashes we wish to merkelize.
|
||||||
//! let root = TxMerkleNode::calculate_root(tx_hashes.into_iter());
|
//! let root = TxMerkleNode::calculate_root(tx_hashes.into_iter());
|
||||||
//! ```
|
//! ```
|
||||||
|
|
|
@ -16,11 +16,12 @@ exclude = ["tests", "contrib"]
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["std"]
|
default = ["std"]
|
||||||
std = ["alloc", "internals/std", "io/std", "units/std"]
|
std = ["alloc", "hashes/std", "internals/std", "io/std", "units/std"]
|
||||||
alloc = ["internals/alloc", "io/alloc", "units/alloc"]
|
alloc = ["hashes/alloc", "internals/alloc", "io/alloc", "units/alloc"]
|
||||||
serde = ["dep:serde", "internals/serde", "units/serde", "alloc"]
|
serde = ["dep:serde", "hashes/serde", "internals/serde", "units/serde", "alloc"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
hashes = { package = "bitcoin_hashes", version = "0.14.0", default-features = false, features = ["bitcoin-io"] }
|
||||||
internals = { package = "bitcoin-internals", version = "0.3.0" }
|
internals = { package = "bitcoin-internals", version = "0.3.0" }
|
||||||
io = { package = "bitcoin-io", version = "0.1.1", default-features = false }
|
io = { package = "bitcoin-io", version = "0.1.1", default-features = false }
|
||||||
units = { package = "bitcoin-units", version = "0.1.0", default-features = false }
|
units = { package = "bitcoin-units", version = "0.1.0", default-features = false }
|
||||||
|
|
|
@ -42,7 +42,11 @@ pub use units::*;
|
||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
pub use self::locktime::{absolute, relative};
|
pub use self::locktime::{absolute, relative};
|
||||||
#[doc(inline)]
|
#[doc(inline)]
|
||||||
pub use self::{pow::CompactTarget, sequence::Sequence};
|
pub use self::{
|
||||||
|
pow::CompactTarget,
|
||||||
|
sequence::Sequence,
|
||||||
|
transaction::{Txid, Wtxid},
|
||||||
|
};
|
||||||
|
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
|
|
|
@ -12,6 +12,40 @@
|
||||||
|
|
||||||
use core::fmt;
|
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.
|
/// The transaction version.
|
||||||
///
|
///
|
||||||
/// Currently, as specified by [BIP-68], only version 1 and 2 are considered standard.
|
/// Currently, as specified by [BIP-68], only version 1 and 2 are considered standard.
|
||||||
|
|
Loading…
Reference in New Issue