From 0abe15b1f6010991e33acacdb69fcb1935234bc3 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Wed, 18 Dec 2019 12:00:18 +0100 Subject: [PATCH] Moving from BitcoinHash to Wtxid for Transactions --- src/blockdata/block.rs | 8 ++++---- src/blockdata/constants.rs | 2 +- src/blockdata/transaction.rs | 33 +++++++++++++++++---------------- src/hash_types.rs | 6 ++++++ src/util/hash.rs | 5 ++--- src/util/merkleblock.rs | 4 ++-- 6 files changed, 32 insertions(+), 26 deletions(-) diff --git a/src/blockdata/block.rs b/src/blockdata/block.rs index cef92a5a..044494c8 100644 --- a/src/blockdata/block.rs +++ b/src/blockdata/block.rs @@ -24,7 +24,7 @@ use util; use util::Error::{BlockBadTarget, BlockBadProofOfWork}; use util::hash::{BitcoinHash, MerkleRooted, bitcoin_merkle_root}; use hashes::{Hash, sha256d, HashEngine}; -use hash_types::{Txid, BlockHash, TxMerkleRoot, WitnessMerkleRoot, WitnessCommitment}; +use hash_types::{Txid, Wtxid, BlockHash, TxMerkleRoot, WitnessMerkleRoot, WitnessCommitment}; use util::uint::Uint256; use consensus::encode::Encodable; use network::constants::Network; @@ -103,8 +103,8 @@ impl Block { /// Merkle root of transactions hashed for witness pub fn witness_root(&self) -> WitnessMerkleRoot { - let mut txhashes = vec!(Txid::default()); - txhashes.extend(self.txdata.iter().skip(1).map(|t|t.bitcoin_hash())); + let mut txhashes = vec!(Wtxid::default()); + txhashes.extend(self.txdata.iter().skip(1).map(|t|t.wtxid())); let hash_value: sha256d::Hash = bitcoin_merkle_root(txhashes).into(); hash_value.into() } @@ -112,7 +112,7 @@ impl Block { impl MerkleRooted for Block { fn merkle_root(&self) -> TxMerkleRoot { - bitcoin_merkle_root(self.txdata.iter().map(|obj| obj.txid().into()).collect()) + bitcoin_merkle_root::(self.txdata.iter().map(|obj| obj.txid().into()).collect()) } } diff --git a/src/blockdata/constants.rs b/src/blockdata/constants.rs index c2e2a0f9..23622918 100644 --- a/src/blockdata/constants.rs +++ b/src/blockdata/constants.rs @@ -171,7 +171,7 @@ mod test { assert_eq!(gen.output[0].value, 50 * COIN_VALUE); assert_eq!(gen.lock_time, 0); - assert_eq!(format!("{:x}", gen.bitcoin_hash()), + assert_eq!(format!("{:x}", gen.wtxid()), "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b".to_string()); } diff --git a/src/blockdata/transaction.rs b/src/blockdata/transaction.rs index 41ca9051..356853dc 100644 --- a/src/blockdata/transaction.rs +++ b/src/blockdata/transaction.rs @@ -30,7 +30,6 @@ use hashes::{self, Hash, sha256d}; use hashes::hex::FromHex; use util::endian; -use util::hash::BitcoinHash; #[cfg(feature="bitcoinconsensus")] use blockdata::script; use blockdata::script::Script; use consensus::{encode, serialize, Decodable, Encodable}; @@ -287,12 +286,12 @@ impl Transaction { input: self.input.iter().map(|txin| TxIn { script_sig: Script::new(), witness: vec![], .. *txin }).collect(), output: self.output.clone(), }; - cloned_tx.bitcoin_hash().into() + cloned_tx.txid().into() } /// Computes the txid. For non-segwit transactions this will be identical - /// to the output of `BitcoinHash::bitcoin_hash()`, but for segwit transactions, - /// this will give the correct txid (not including witnesses) while `bitcoin_hash` + /// to the output of `wtxid()`, but for segwit transactions, + /// this will give the correct txid (not including witnesses) while `wtxid` /// will also hash witnesses. pub fn txid(&self) -> Txid { let mut enc = Txid::engine(); @@ -303,6 +302,15 @@ impl Transaction { Txid::from_engine(enc) } + /// Computes SegWit-version of the transaction id (wtxid). For transaction with the witness + /// data this hash includes witness, for pre-witness transaction it is equal to the normal + /// value returned by txid() function. + pub fn wtxid(&self) -> Wtxid { + let mut enc = Wtxid::engine(); + self.consensus_encode(&mut enc).unwrap(); + Wtxid::from_engine(enc) + } + /// Computes a signature hash for a given input index with a given sighash flag. /// To actually produce a scriptSig, this hash needs to be run through an /// ECDSA signer, the SigHashType appended to the resulting sig, and a @@ -438,14 +446,6 @@ impl Transaction { } } -impl BitcoinHash for Transaction { - fn bitcoin_hash(&self) -> Txid { - let mut enc = Txid::engine(); - self.consensus_encode(&mut enc).unwrap(); - Txid::from_engine(enc) - } -} - impl_consensus_encoding!(TxOut, value, script_pubkey); impl Encodable for OutPoint { @@ -626,7 +626,6 @@ mod tests { use blockdata::script::Script; use consensus::encode::serialize; use consensus::encode::deserialize; - use util::hash::BitcoinHash; use hashes::Hash; use hashes::hex::FromHex; @@ -712,7 +711,9 @@ mod tests { assert_eq!(realtx.output.len(), 1); assert_eq!(realtx.lock_time, 0); - assert_eq!(format!("{:x}", realtx.bitcoin_hash()), + assert_eq!(format!("{:x}", realtx.txid()), + "a6eab3c14ab5272a58a5ba91505ba1a4b6d7a3a9fcbd187b6cd99a7b6d548cb7".to_string()); + assert_eq!(format!("{:x}", realtx.wtxid()), "a6eab3c14ab5272a58a5ba91505ba1a4b6d7a3a9fcbd187b6cd99a7b6d548cb7".to_string()); assert_eq!(realtx.get_weight(), 193*4); } @@ -781,7 +782,7 @@ mod tests { ).unwrap(); let tx: Transaction = deserialize(&hex_tx).unwrap(); - assert_eq!(format!("{:x}", tx.bitcoin_hash()), "d6ac4a5e61657c4c604dcde855a1db74ec6b3e54f32695d72c5e11c7761ea1b4"); + assert_eq!(format!("{:x}", tx.wtxid()), "d6ac4a5e61657c4c604dcde855a1db74ec6b3e54f32695d72c5e11c7761ea1b4"); assert_eq!(format!("{:x}", tx.txid()), "9652aa62b0e748caeec40c4cb7bc17c6792435cc3dfe447dd1ca24f912a1c6ec"); assert_eq!(tx.get_weight(), 2718); @@ -796,7 +797,7 @@ mod tests { ).unwrap(); let tx: Transaction = deserialize(&hex_tx).unwrap(); - assert_eq!(format!("{:x}", tx.bitcoin_hash()), "971ed48a62c143bbd9c87f4bafa2ef213cfa106c6e140f111931d0be307468dd"); + assert_eq!(format!("{:x}", tx.wtxid()), "971ed48a62c143bbd9c87f4bafa2ef213cfa106c6e140f111931d0be307468dd"); assert_eq!(format!("{:x}", tx.txid()), "971ed48a62c143bbd9c87f4bafa2ef213cfa106c6e140f111931d0be307468dd"); } diff --git a/src/hash_types.rs b/src/hash_types.rs index 0b9d543d..54c51e5e 100644 --- a/src/hash_types.rs +++ b/src/hash_types.rs @@ -66,3 +66,9 @@ impl_hashencode!(TxMerkleRoot); impl_hashencode!(TxMerkleBranch); impl_hashencode!(WitnessMerkleRoot); impl_hashencode!(FilterHash); + +/// Generic trait for functions which may either take a Txid type of Wtxid type as an imput. +/// For instance, used for Merklization procedure +pub trait TxidType: Hash + Encodable + Decodable { } +impl TxidType for Txid { } +impl TxidType for Wtxid { } diff --git a/src/util/hash.rs b/src/util/hash.rs index 54d2c4bb..1aac8fbf 100644 --- a/src/util/hash.rs +++ b/src/util/hash.rs @@ -19,9 +19,8 @@ use std::cmp::min; use std::default::Default; use hashes::Hash; -use hash_types::{Txid, TxMerkleRoot}; +use hash_types::{Txid, TxidType, TxMerkleRoot}; -use consensus::encode::Encodable; /// Any collection of objects for which a merkle root makes sense to calculate pub trait MerkleRooted { @@ -31,7 +30,7 @@ pub trait MerkleRooted { } /// Calculates the merkle root of a list of txids hashes directly -pub fn bitcoin_merkle_root(data: Vec) -> TxMerkleRoot { +pub fn bitcoin_merkle_root(data: Vec) -> TxMerkleRoot { // Base case if data.len() < 1 { return Default::default(); diff --git a/src/util/merkleblock.rs b/src/util/merkleblock.rs index 4c4c7cd0..974a9623 100644 --- a/src/util/merkleblock.rs +++ b/src/util/merkleblock.rs @@ -61,9 +61,9 @@ use std::io; use hashes::Hash; use hash_types::{Txid, TxMerkleRoot, TxMerkleBranch}; +use blockdata::transaction::Transaction; use blockdata::constants::{MAX_BLOCK_WEIGHT, MIN_TRANSACTION_WEIGHT}; use consensus::encode::{self, Decodable, Encodable}; -use util::hash::BitcoinHash; use util::merkleblock::MerkleBlockError::*; use {Block, BlockHeader}; @@ -445,7 +445,7 @@ impl MerkleBlock { let mut matches: Vec = Vec::with_capacity(block.txdata.len()); let mut hashes: Vec = Vec::with_capacity(block.txdata.len()); - for hash in block.txdata.iter().map(BitcoinHash::bitcoin_hash) { + for hash in block.txdata.iter().map(Transaction::txid) { matches.push(match_txids.contains(&hash)); hashes.push(hash); }