Skip to content

Commit

Permalink
Moving from BitcoinHash to Wtxid for Transactions
Browse files Browse the repository at this point in the history
  • Loading branch information
dr-orlovsky committed Jan 1, 2020
1 parent f5a8087 commit 0abe15b
Show file tree
Hide file tree
Showing 6 changed files with 32 additions and 26 deletions.
8 changes: 4 additions & 4 deletions src/blockdata/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -103,16 +103,16 @@ 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()
}
}

impl MerkleRooted for Block {
fn merkle_root(&self) -> TxMerkleRoot {
bitcoin_merkle_root(self.txdata.iter().map(|obj| obj.txid().into()).collect())
bitcoin_merkle_root::<Txid>(self.txdata.iter().map(|obj| obj.txid().into()).collect())
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/blockdata/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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());
}

Expand Down
33 changes: 17 additions & 16 deletions src/blockdata/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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();
Expand All @@ -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
Expand Down Expand Up @@ -438,14 +446,6 @@ impl Transaction {
}
}

impl BitcoinHash<Txid> 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 {
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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);

Expand All @@ -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");
}

Expand Down
6 changes: 6 additions & 0 deletions src/hash_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Inner = [u8; 32]> + Encodable + Decodable { }
impl TxidType for Txid { }
impl TxidType for Wtxid { }
5 changes: 2 additions & 3 deletions src/util/hash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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<Txid>) -> TxMerkleRoot {
pub fn bitcoin_merkle_root<T: TxidType>(data: Vec<T>) -> TxMerkleRoot {
// Base case
if data.len() < 1 {
return Default::default();
Expand Down
4 changes: 2 additions & 2 deletions src/util/merkleblock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};

Expand Down Expand Up @@ -445,7 +445,7 @@ impl MerkleBlock {
let mut matches: Vec<bool> = Vec::with_capacity(block.txdata.len());
let mut hashes: Vec<Txid> = 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);
}
Expand Down

0 comments on commit 0abe15b

Please sign in to comment.