New hash types: MerkleRoot/Branch, WitnessCommit, SigHash, FilterHash

This commit is contained in:
Dr Maxim Orlovsky 2019-12-06 10:01:15 +01:00
parent 4746ccb88e
commit f5a8087105
14 changed files with 126 additions and 111 deletions

View File

@ -20,18 +20,16 @@
//! these blocks and the blockchain.
//!
use hashes::{sha256d, Hash};
use util;
use util::Error::{BlockBadTarget, BlockBadProofOfWork};
use util::hash::{BitcoinHash, MerkleRoot, bitcoin_merkle_root};
use util::hash::{BitcoinHash, MerkleRooted, bitcoin_merkle_root};
use hashes::{Hash, sha256d, HashEngine};
use hash_types::{Txid, BlockHash, TxMerkleRoot, WitnessMerkleRoot, WitnessCommitment};
use util::uint::Uint256;
use hash_types::{Txid, BlockHash};
use consensus::encode::Encodable;
use network::constants::Network;
use blockdata::transaction::Transaction;
use blockdata::constants::max_target;
use hashes::HashEngine;
/// A block header, which contains all the block's information except
/// the actual transactions
@ -42,7 +40,7 @@ pub struct BlockHeader {
/// Reference to the previous block in the chain
pub prev_blockhash: BlockHash,
/// The root hash of the merkle tree of transactions in the block
pub merkle_root: sha256d::Hash,
pub merkle_root: TxMerkleRoot,
/// The timestamp of the block, as claimed by the miner
pub time: u32,
/// The target value below which the blockhash must lie, encoded as a
@ -83,7 +81,7 @@ impl Block {
.rposition(|o| {
o.script_pubkey.len () >= 38 &&
o.script_pubkey[0..6] == [0x6a, 0x24, 0xaa, 0x21, 0xa9, 0xed] }) {
let commitment = sha256d::Hash::from_slice(&coinbase.output[pos].script_pubkey.as_bytes()[6..38]).unwrap();
let commitment = WitnessCommitment::from_slice(&coinbase.output[pos].script_pubkey.as_bytes()[6..38]).unwrap();
// witness reserved value is in coinbase input witness
if coinbase.input[0].witness.len() == 1 && coinbase.input[0].witness[0].len() == 32 {
let witness_root = self.witness_root();
@ -96,23 +94,24 @@ impl Block {
}
/// compute witness commitment for the transaction list
pub fn compute_witness_commitment (witness_root: &sha256d::Hash, witness_reserved_value: &[u8]) -> sha256d::Hash {
let mut encoder = sha256d::Hash::engine();
pub fn compute_witness_commitment (witness_root: &WitnessMerkleRoot, witness_reserved_value: &[u8]) -> WitnessCommitment {
let mut encoder = WitnessCommitment::engine();
witness_root.consensus_encode(&mut encoder).unwrap();
encoder.input(witness_reserved_value);
sha256d::Hash::from_engine(encoder)
WitnessCommitment::from_engine(encoder)
}
/// Merkle root of transactions hashed for witness
pub fn witness_root(&self) -> sha256d::Hash {
pub fn witness_root(&self) -> WitnessMerkleRoot {
let mut txhashes = vec!(Txid::default());
txhashes.extend(self.txdata.iter().skip(1).map(|t|t.bitcoin_hash()));
bitcoin_merkle_root(txhashes)
let hash_value: sha256d::Hash = bitcoin_merkle_root(txhashes).into();
hash_value.into()
}
}
impl MerkleRoot for Block {
fn merkle_root(&self) -> sha256d::Hash {
impl MerkleRooted for Block {
fn merkle_root(&self) -> TxMerkleRoot {
bitcoin_merkle_root(self.txdata.iter().map(|obj| obj.txid().into()).collect())
}
}
@ -213,7 +212,7 @@ mod tests {
use blockdata::block::{Block, BlockHeader};
use consensus::encode::{deserialize, serialize};
use util::hash::MerkleRoot;
use util::hash::MerkleRooted;
#[test]
fn block_test() {

View File

@ -22,7 +22,7 @@
use std::default::Default;
use hashes::hex::FromHex;
use hashes::sha256d;
use blockdata::opcodes;
use blockdata::script;
use blockdata::transaction::{OutPoint, Transaction, TxOut, TxIn};
@ -97,7 +97,8 @@ fn bitcoin_genesis_tx() -> Transaction {
/// Constructs and returns the genesis block
pub fn genesis_block(network: Network) -> Block {
let txdata = vec![bitcoin_genesis_tx()];
let merkle_root = txdata[0].txid().into();
let hash: sha256d::Hash = txdata[0].txid().into();
let merkle_root = hash.into();
match network {
Network::Bitcoin => {
Block {

View File

@ -26,7 +26,7 @@
use std::default::Default;
use std::{fmt, io};
use hashes::{self, sha256d, Hash};
use hashes::{self, Hash, sha256d};
use hashes::hex::FromHex;
use util::endian;
@ -316,14 +316,14 @@ impl Transaction {
/// # Panics
/// Panics if `input_index` is greater than or equal to `self.input.len()`
///
pub fn signature_hash(&self, input_index: usize, script_pubkey: &Script, sighash_u32: u32) -> sha256d::Hash {
pub fn signature_hash(&self, input_index: usize, script_pubkey: &Script, sighash_u32: u32) -> SigHash {
assert!(input_index < self.input.len()); // Panic on OOB
let (sighash, anyone_can_pay) = SigHashType::from_u32(sighash_u32).split_anyonecanpay_flag();
// Special-case sighash_single bug because this is easy enough.
if sighash == SigHashType::Single && input_index >= self.output.len() {
return sha256d::Hash::from_slice(&[1, 0, 0, 0, 0, 0, 0, 0,
return SigHash::from_slice(&[1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0]).unwrap();
@ -371,7 +371,7 @@ impl Transaction {
// hash the result
let mut raw_vec = serialize(&tx);
raw_vec.extend_from_slice(&endian::u32_to_array_le(sighash_u32));
sha256d::Hash::hash(&raw_vec)
SigHash::hash(&raw_vec)
}
/// Gets the "weight" of this transaction, as defined by BIP141. For transactions with an empty
@ -628,7 +628,7 @@ mod tests {
use consensus::encode::deserialize;
use util::hash::BitcoinHash;
use hashes::{sha256d, Hash};
use hashes::Hash;
use hashes::hex::FromHex;
use hash_types::*;
@ -813,7 +813,7 @@ mod tests {
let script = Script::from(Vec::<u8>::from_hex(script).unwrap());
let mut raw_expected = Vec::<u8>::from_hex(expected_result).unwrap();
raw_expected.reverse();
let expected_result = sha256d::Hash::from_slice(&raw_expected[..]).unwrap();
let expected_result = SigHash::from_slice(&raw_expected[..]).unwrap();
let actual_result = tx.signature_hash(input_index, &script, hash_type as u32);
assert_eq!(actual_result, expected_result);

View File

@ -35,6 +35,7 @@ use std::io::{Cursor, Read, Write};
use hashes::hex::ToHex;
use hashes::{sha256d, Hash as HashTrait};
use hash_types::{FilterHash, TxMerkleBranch};
use util::endian;
use util::psbt;
@ -590,7 +591,8 @@ macro_rules! impl_vec {
}
}
}
impl_vec!(sha256d::Hash);
impl_vec!(FilterHash);
impl_vec!(TxMerkleBranch);
impl_vec!(Transaction);
impl_vec!(TxOut);
impl_vec!(TxIn);

View File

@ -20,9 +20,6 @@ use std::io;
use consensus::encode::{Encodable, Decodable, Error};
use hashes::{sha256, sha256d, hash160, Hash};
// Do not remove: required in order to get hash types implementation macros to work correctly
#[allow(unused_imports)]
use hashes::hex::{ToHex, FromHex};
macro_rules! impl_hashencode {
@ -45,12 +42,27 @@ macro_rules! impl_hashencode {
hash_newtype!(Txid, sha256d::Hash, 32, doc="A bitcoin transaction hash/transaction ID.");
hash_newtype!(Wtxid, sha256d::Hash, 32, doc="A bitcoin witness transaction ID.");
hash_newtype!(BlockHash, sha256d::Hash, 32, doc="A bitcoin block hash.");
hash_newtype!(SigHash, sha256d::Hash, 32, doc="Hash of the transaction according to the signature algorithm");
hash_newtype!(PubkeyHash, hash160::Hash, 20, doc="A hash of a public key.");
hash_newtype!(ScriptHash, hash160::Hash, 20, doc="A hash of Bitcoin Script bytecode.");
hash_newtype!(WPubkeyHash, hash160::Hash, 20, doc="SegWit version of a public key hash.");
hash_newtype!(WScriptHash, sha256::Hash, 32, doc="SegWit version of a Bitcoin Script bytecode hash.");
hash_newtype!(TxMerkleRoot, sha256d::Hash, 32, doc="A hash corresponding to the Merkle tree root for transactions");
hash_newtype!(TxMerkleBranch, sha256d::Hash, 32, doc="A hash of the Merkle tree branch for transactions");
hash_newtype!(WitnessMerkleRoot, sha256d::Hash, 32, doc="A hash corresponding to the Merkle tree root for witness data");
hash_newtype!(WitnessCommitment, sha256d::Hash, 32, doc="A hash corresponding to the witness structure commitment in the coinbase transaction");
hash_newtype!(XpubIdentifier, hash160::Hash, 20, doc="XpubIdentifier as defined in BIP-32.");
hash_newtype!(FilterHash, sha256d::Hash, 32, doc="Bloom filter souble-SHA256 locator hash, as defined in BIP-168");
impl_hashencode!(Txid);
impl_hashencode!(Wtxid);
impl_hashencode!(SigHash);
impl_hashencode!(BlockHash);
impl_hashencode!(TxMerkleRoot);
impl_hashencode!(TxMerkleBranch);
impl_hashencode!(WitnessMerkleRoot);
impl_hashencode!(FilterHash);

View File

@ -227,7 +227,7 @@ macro_rules! display_from_debug {
macro_rules! hex_script (($s:expr) => (::blockdata::script::Script::from(::hex::decode($s).unwrap())));
#[cfg(test)]
macro_rules! hex_hash (($s:expr) => (::hashes::sha256d::Hash::from_slice(&::hex::decode($s).unwrap()).unwrap()));
macro_rules! hex_hash (($h:ident, $s:expr) => ($h::from_slice(&::hex::decode($s).unwrap()).unwrap()));
macro_rules! serde_struct_impl {
($name:ident, $($fe:ident),*) => (

View File

@ -77,6 +77,7 @@ pub mod network;
pub mod blockdata;
pub mod util;
pub mod consensus;
// Do not remove: required in order to get hash types implementation macros to work correctly
#[allow(unused_imports)]
pub mod hash_types;

View File

@ -362,11 +362,11 @@ mod test {
NetworkMessage::Version(version_msg),
NetworkMessage::Verack,
NetworkMessage::Addr(vec![(45, Address::new(&([123,255,000,100], 833).into(), ServiceFlags::NETWORK))]),
NetworkMessage::Inv(vec![Inventory{inv_type: InvType::Block, hash: hash([8u8; 32])}]),
NetworkMessage::GetData(vec![Inventory{inv_type: InvType::Transaction, hash: hash([45u8; 32])}]),
NetworkMessage::NotFound(vec![Inventory{inv_type: InvType::Error, hash: hash([45u8; 32])}]),
NetworkMessage::GetBlocks(GetBlocksMessage::new(vec![hash([1u8; 32]), hash([4u8; 32])], hash([5u8; 32]))),
NetworkMessage::GetHeaders(GetHeadersMessage::new(vec![hash([10u8; 32]), hash([40u8; 32])], hash([50u8; 32]))),
NetworkMessage::Inv(vec![Inventory{inv_type: InvType::Block, hash: hash([8u8; 32]).into()}]),
NetworkMessage::GetData(vec![Inventory{inv_type: InvType::Transaction, hash: hash([45u8; 32]).into()}]),
NetworkMessage::NotFound(vec![Inventory{inv_type: InvType::Error, hash: hash([45u8; 32]).into()}]),
NetworkMessage::GetBlocks(GetBlocksMessage::new(vec![hash([1u8; 32]).into(), hash([4u8; 32]).into()], hash([5u8; 32]).into())),
NetworkMessage::GetHeaders(GetHeadersMessage::new(vec![hash([10u8; 32]).into(), hash([40u8; 32]).into()], hash([50u8; 32]).into())),
NetworkMessage::MemPool,
NetworkMessage::Tx(tx),
NetworkMessage::Block(block),
@ -377,10 +377,10 @@ mod test {
NetworkMessage::Pong(23),
NetworkMessage::GetCFilters(GetCFilters{filter_type: 2, start_height: 52, stop_hash: hash([42u8; 32]).into()}),
NetworkMessage::CFilter(CFilter{filter_type: 7, block_hash: hash([25u8; 32]).into(), filter: vec![1,2,3]}),
NetworkMessage::GetCFHeaders(GetCFHeaders{filter_type: 4, start_height: 102, stop_hash: hash([47u8; 32])}),
NetworkMessage::CFHeaders(CFHeaders{filter_type: 13, stop_hash: hash([53u8; 32]), previous_filter: hash([12u8; 32]), filter_hashes: vec![hash([4u8; 32]), hash([12u8; 32])]}),
NetworkMessage::GetCFCheckpt(GetCFCheckpt{filter_type: 17, stop_hash: hash([25u8; 32])}),
NetworkMessage::CFCheckpt(CFCheckpt{filter_type: 27, stop_hash: hash([77u8; 32]), filter_headers: vec![hash([3u8; 32]), hash([99u8; 32])]}),
NetworkMessage::GetCFHeaders(GetCFHeaders{filter_type: 4, start_height: 102, stop_hash: hash([47u8; 32]).into()}),
NetworkMessage::CFHeaders(CFHeaders{filter_type: 13, stop_hash: hash([53u8; 32]).into(), previous_filter: hash([12u8; 32]).into(), filter_hashes: vec![hash([4u8; 32]).into(), hash([12u8; 32]).into()]}),
NetworkMessage::GetCFCheckpt(GetCFCheckpt{filter_type: 17, stop_hash: hash([25u8; 32]).into()}),
NetworkMessage::CFCheckpt(CFCheckpt{filter_type: 27, stop_hash: hash([77u8; 32]).into(), filter_headers: vec![hash([3u8; 32]).into(), hash([99u8; 32]).into()]}),
NetworkMessage::Alert(vec![45,66,3,2,6,8,9,12,3,130]),
NetworkMessage::Reject(Reject{message: "Test reject".into(), ccode: RejectReason::Duplicate, reason: "Cause".into(), hash: hash([255u8; 32])}),
];

View File

@ -20,7 +20,7 @@
use network::constants;
use consensus::encode::{self, Decodable, Encodable};
use hashes::sha256d;
use hash_types::FilterHash;
use std::io;
@ -49,9 +49,9 @@ pub struct GetBlocksMessage {
/// Locator hashes --- ordered newest to oldest. The remote peer will
/// reply with its longest known chain, starting from a locator hash
/// if possible and block 1 otherwise.
pub locator_hashes: Vec<sha256d::Hash>,
pub locator_hashes: Vec<FilterHash>,
/// References the block to stop at, or zero to just fetch the maximum 500 blocks
pub stop_hash: sha256d::Hash,
pub stop_hash: FilterHash,
}
/// The `getheaders` message
@ -62,9 +62,9 @@ pub struct GetHeadersMessage {
/// Locator hashes --- ordered newest to oldest. The remote peer will
/// reply with its longest known chain, starting from a locator hash
/// if possible and block 1 otherwise.
pub locator_hashes: Vec<sha256d::Hash>,
pub locator_hashes: Vec<FilterHash>,
/// References the header to stop at, or zero to just fetch the maximum 2000 headers
pub stop_hash: sha256d::Hash
pub stop_hash: FilterHash
}
/// An inventory object --- a reference to a Bitcoin object
@ -73,7 +73,7 @@ pub struct Inventory {
/// The type of object that is referenced
pub inv_type: InvType,
/// The object's hash
pub hash: sha256d::Hash
pub hash: FilterHash
}
impl ::std::hash::Hash for Inventory {
@ -84,7 +84,7 @@ impl ::std::hash::Hash for Inventory {
impl GetBlocksMessage {
/// Construct a new `getblocks` message
pub fn new(locator_hashes: Vec<sha256d::Hash>, stop_hash: sha256d::Hash) -> GetBlocksMessage {
pub fn new(locator_hashes: Vec<FilterHash>, stop_hash: FilterHash) -> GetBlocksMessage {
GetBlocksMessage {
version: constants::PROTOCOL_VERSION,
locator_hashes: locator_hashes.clone(),
@ -97,7 +97,7 @@ impl_consensus_encoding!(GetBlocksMessage, version, locator_hashes, stop_hash);
impl GetHeadersMessage {
/// Construct a new `getheaders` message
pub fn new(locator_hashes: Vec<sha256d::Hash>, stop_hash: sha256d::Hash) -> GetHeadersMessage {
pub fn new(locator_hashes: Vec<FilterHash>, stop_hash: FilterHash) -> GetHeadersMessage {
GetHeadersMessage {
version: constants::PROTOCOL_VERSION,
locator_hashes: locator_hashes,

View File

@ -2,8 +2,7 @@
//! BIP157 Client Side Block Filtering network messages
//!
use hash_types::BlockHash;
use hashes::sha256d;
use hash_types::{BlockHash, FilterHash};
#[derive(PartialEq, Eq, Clone, Debug)]
/// getcfilters message
@ -37,7 +36,7 @@ pub struct GetCFHeaders {
/// The height of the first block in the requested range
pub start_height: u32,
/// The hash of the last block in the requested range
pub stop_hash: sha256d::Hash,
pub stop_hash: FilterHash,
}
impl_consensus_encoding!(GetCFHeaders, filter_type, start_height, stop_hash);
@ -47,11 +46,11 @@ pub struct CFHeaders {
/// Filter type for which headers are requested
pub filter_type: u8,
/// The hash of the last block in the requested range
pub stop_hash: sha256d::Hash,
pub stop_hash: FilterHash,
/// The filter header preceding the first block in the requested range
pub previous_filter: sha256d::Hash,
pub previous_filter: FilterHash,
/// The filter hashes for each block in the requested range
pub filter_hashes: Vec<sha256d::Hash>,
pub filter_hashes: Vec<FilterHash>,
}
impl_consensus_encoding!(CFHeaders, filter_type, stop_hash, previous_filter, filter_hashes);
@ -61,7 +60,7 @@ pub struct GetCFCheckpt {
/// Filter type for which headers are requested
pub filter_type: u8,
/// The hash of the last block in the requested range
pub stop_hash: sha256d::Hash,
pub stop_hash: FilterHash,
}
impl_consensus_encoding!(GetCFCheckpt, filter_type, stop_hash);
@ -71,8 +70,8 @@ pub struct CFCheckpt {
/// Filter type for which headers are requested
pub filter_type: u8,
/// The hash of the last block in the requested range
pub stop_hash: sha256d::Hash,
pub stop_hash: FilterHash,
/// The filter headers at intervals of 1,000
pub filter_headers: Vec<sha256d::Hash>,
pub filter_headers: Vec<FilterHash>,
}
impl_consensus_encoding!(CFCheckpt, filter_type, stop_hash, filter_headers);

View File

@ -19,8 +19,8 @@
//! signatures, which are placed in the scriptSig.
//!
use hashes::{sha256d, Hash};
use hashes::Hash;
use hash_types::SigHash;
use blockdata::script::Script;
use blockdata::transaction::{Transaction, TxIn};
use consensus::encode::Encodable;
@ -32,11 +32,11 @@ pub struct SighashComponents {
tx_version: u32,
tx_locktime: u32,
/// Hash of all the previous outputs
pub hash_prevouts: sha256d::Hash,
pub hash_prevouts: SigHash,
/// Hash of all the input sequence nos
pub hash_sequence: sha256d::Hash,
pub hash_sequence: SigHash,
/// Hash of all the outputs in this transaction
pub hash_outputs: sha256d::Hash,
pub hash_outputs: SigHash,
}
impl SighashComponents {
@ -46,27 +46,27 @@ impl SighashComponents {
/// script_sig and witnesses.
pub fn new(tx: &Transaction) -> SighashComponents {
let hash_prevouts = {
let mut enc = sha256d::Hash::engine();
let mut enc = SigHash::engine();
for txin in &tx.input {
txin.previous_output.consensus_encode(&mut enc).unwrap();
}
sha256d::Hash::from_engine(enc)
SigHash::from_engine(enc)
};
let hash_sequence = {
let mut enc = sha256d::Hash::engine();
let mut enc = SigHash::engine();
for txin in &tx.input {
txin.sequence.consensus_encode(&mut enc).unwrap();
}
sha256d::Hash::from_engine(enc)
SigHash::from_engine(enc)
};
let hash_outputs = {
let mut enc = sha256d::Hash::engine();
let mut enc = SigHash::engine();
for txout in &tx.output {
txout.consensus_encode(&mut enc).unwrap();
}
sha256d::Hash::from_engine(enc)
SigHash::from_engine(enc)
};
SighashComponents {
@ -80,8 +80,8 @@ impl SighashComponents {
/// Compute the BIP143 sighash for a `SIGHASH_ALL` signature for the given
/// input.
pub fn sighash_all(&self, txin: &TxIn, script_code: &Script, value: u64) -> sha256d::Hash {
let mut enc = sha256d::Hash::engine();
pub fn sighash_all(&self, txin: &TxIn, script_code: &Script, value: u64) -> SigHash {
let mut enc = SigHash::engine();
self.tx_version.consensus_encode(&mut enc).unwrap();
self.hash_prevouts.consensus_encode(&mut enc).unwrap();
self.hash_sequence.consensus_encode(&mut enc).unwrap();
@ -95,12 +95,13 @@ impl SighashComponents {
self.hash_outputs.consensus_encode(&mut enc).unwrap();
self.tx_locktime.consensus_encode(&mut enc).unwrap();
1u32.consensus_encode(&mut enc).unwrap(); // hashtype
sha256d::Hash::from_engine(enc)
SigHash::from_engine(enc)
}
}
#[cfg(test)]
mod tests {
use hash_types::SigHash;
use blockdata::script::Script;
use blockdata::transaction::Transaction;
use consensus::encode::deserialize;
@ -140,20 +141,20 @@ mod tests {
tx_version: 1,
tx_locktime: 17,
hash_prevouts: hex_hash!(
"96b827c8483d4e9b96712b6713a7b68d6e8003a781feba36c31143470b4efd37"
SigHash, "96b827c8483d4e9b96712b6713a7b68d6e8003a781feba36c31143470b4efd37"
),
hash_sequence: hex_hash!(
"52b0a642eea2fb7ae638c36f6252b6750293dbe574a806984b8e4d8548339a3b"
SigHash, "52b0a642eea2fb7ae638c36f6252b6750293dbe574a806984b8e4d8548339a3b"
),
hash_outputs: hex_hash!(
"863ef3e1a92afbfdb97f31ad0fc7683ee943e9abcf2501590ff8f6551f47e5e5"
SigHash, "863ef3e1a92afbfdb97f31ad0fc7683ee943e9abcf2501590ff8f6551f47e5e5"
),
}
);
assert_eq!(
comp.sighash_all(&tx.input[1], &witness_script, value),
hex_hash!("c37af31116d1b27caf68aae9e3ac82f1477929014d5b917657d0eb49478cb670")
hex_hash!(SigHash, "c37af31116d1b27caf68aae9e3ac82f1477929014d5b917657d0eb49478cb670")
);
}
@ -177,20 +178,20 @@ mod tests {
tx_version: 1,
tx_locktime: 1170,
hash_prevouts: hex_hash!(
"b0287b4a252ac05af83d2dcef00ba313af78a3e9c329afa216eb3aa2a7b4613a"
SigHash, "b0287b4a252ac05af83d2dcef00ba313af78a3e9c329afa216eb3aa2a7b4613a"
),
hash_sequence: hex_hash!(
"18606b350cd8bf565266bc352f0caddcf01e8fa789dd8a15386327cf8cabe198"
SigHash, "18606b350cd8bf565266bc352f0caddcf01e8fa789dd8a15386327cf8cabe198"
),
hash_outputs: hex_hash!(
"de984f44532e2173ca0d64314fcefe6d30da6f8cf27bafa706da61df8a226c83"
SigHash, "de984f44532e2173ca0d64314fcefe6d30da6f8cf27bafa706da61df8a226c83"
),
}
);
assert_eq!(
comp.sighash_all(&tx.input[0], &witness_script, value),
hex_hash!("64f3b0f4dd2bb3aa1ce8566d220cc74dda9df97d8490cc81d89d735c92e59fb6")
hex_hash!(SigHash, "64f3b0f4dd2bb3aa1ce8566d220cc74dda9df97d8490cc81d89d735c92e59fb6")
);
}
@ -220,20 +221,20 @@ mod tests {
tx_version: 1,
tx_locktime: 0,
hash_prevouts: hex_hash!(
"74afdc312af5183c4198a40ca3c1a275b485496dd3929bca388c4b5e31f7aaa0"
SigHash, "74afdc312af5183c4198a40ca3c1a275b485496dd3929bca388c4b5e31f7aaa0"
),
hash_sequence: hex_hash!(
"3bb13029ce7b1f559ef5e747fcac439f1455a2ec7c5f09b72290795e70665044"
SigHash, "3bb13029ce7b1f559ef5e747fcac439f1455a2ec7c5f09b72290795e70665044"
),
hash_outputs: hex_hash!(
"bc4d309071414bed932f98832b27b4d76dad7e6c1346f487a8fdbb8eb90307cc"
SigHash, "bc4d309071414bed932f98832b27b4d76dad7e6c1346f487a8fdbb8eb90307cc"
),
}
);
assert_eq!(
comp.sighash_all(&tx.input[0], &witness_script, value),
hex_hash!("185c0be5263dce5b4bb50a047973c1b6272bfbd0103a89444597dc40b248ee7c")
hex_hash!(SigHash, "185c0be5263dce5b4bb50a047973c1b6272bfbd0103a89444597dc40b248ee7c")
);
}
}

View File

@ -50,8 +50,8 @@ use std::error;
use std::fmt::{Display, Formatter};
use std::io::Cursor;
use hash_types::BlockHash;
use hashes::{Hash, sha256d, siphash24};
use hashes::{Hash, siphash24};
use hash_types::{BlockHash, FilterHash};
use blockdata::block::Block;
use blockdata::script::Script;
@ -107,12 +107,12 @@ pub struct BlockFilter {
impl BlockFilter {
/// compute this filter's id in a chain of filters
pub fn filter_id(&self, previous_filter_id: &sha256d::Hash) -> sha256d::Hash {
let filter_hash = sha256d::Hash::hash(self.content.as_slice());
pub fn filter_id(&self, previous_filter_id: &FilterHash) -> FilterHash {
let filter_hash = FilterHash::hash(self.content.as_slice());
let mut header_data = [0u8; 64];
header_data[0..32].copy_from_slice(&filter_hash[..]);
header_data[32..64].copy_from_slice(&previous_filter_id[..]);
sha256d::Hash::hash(&header_data)
FilterHash::hash(&header_data)
}
/// create a new filter from pre-computed data
@ -561,9 +561,9 @@ mod test {
let block: Block = deserialize(hex::decode(&t.get(2).unwrap().as_str().unwrap().as_bytes()).unwrap().as_slice()).unwrap();
assert_eq!(block.bitcoin_hash(), block_hash);
let scripts = t.get(3).unwrap().as_array().unwrap();
let previous_filter_id = sha256d::Hash::from_hex(&t.get(4).unwrap().as_str().unwrap()).unwrap();
let previous_filter_id = FilterHash::from_hex(&t.get(4).unwrap().as_str().unwrap()).unwrap();
let filter_content = hex::decode(&t.get(5).unwrap().as_str().unwrap().as_bytes()).unwrap();
let filter_id = sha256d::Hash::from_hex(&t.get(6).unwrap().as_str().unwrap()).unwrap();
let filter_id = FilterHash::from_hex(&t.get(6).unwrap().as_str().unwrap()).unwrap();
let mut txmap = HashMap::new();
let mut si = scripts.iter();

View File

@ -18,33 +18,33 @@
use std::cmp::min;
use std::default::Default;
use hash_types::Txid;
use hashes::{sha256d, Hash};
use hashes::Hash;
use hash_types::{Txid, TxMerkleRoot};
use consensus::encode::Encodable;
/// Any collection of objects for which a merkle root makes sense to calculate
pub trait MerkleRoot {
pub trait MerkleRooted {
/// Construct a merkle tree from a collection, with elements ordered as
/// they were in the original collection, and return the merkle root.
fn merkle_root(&self) -> sha256d::Hash;
fn merkle_root(&self) -> TxMerkleRoot;
}
/// Calculates the merkle root of a list of txids hashes directly
pub fn bitcoin_merkle_root(data: Vec<Txid>) -> sha256d::Hash {
pub fn bitcoin_merkle_root(data: Vec<Txid>) -> TxMerkleRoot {
// Base case
if data.len() < 1 {
return Default::default();
}
if data.len() < 2 {
return data[0].into();
return TxMerkleRoot::from_inner(data[0].into_inner());
}
// Recursion
let mut next = vec![];
for idx in 0..((data.len() + 1) / 2) {
let idx1 = 2 * idx;
let idx2 = min(idx1 + 1, data.len() - 1);
let mut encoder = sha256d::Hash::engine();
let mut encoder = TxMerkleRoot::engine();
data[idx1].consensus_encode(&mut encoder).unwrap();
data[idx2].consensus_encode(&mut encoder).unwrap();
next.push(Txid::from_engine(encoder));

View File

@ -58,8 +58,8 @@
use std::collections::HashSet;
use std::io;
use hash_types::Txid;
use hashes::{sha256d, Hash};
use hashes::Hash;
use hash_types::{Txid, TxMerkleRoot, TxMerkleBranch};
use blockdata::constants::{MAX_BLOCK_WEIGHT, MIN_TRANSACTION_WEIGHT};
use consensus::encode::{self, Decodable, Encodable};
@ -120,7 +120,7 @@ pub struct PartialMerkleTree {
/// node-is-parent-of-matched-txid bits
bits: Vec<bool>,
/// Transaction ids and internal hashes
hashes: Vec<sha256d::Hash>,
hashes: Vec<TxMerkleBranch>,
}
impl PartialMerkleTree {
@ -181,7 +181,7 @@ impl PartialMerkleTree {
&self,
matches: &mut Vec<Txid>,
indexes: &mut Vec<u32>,
) -> Result<sha256d::Hash, MerkleBlockError> {
) -> Result<TxMerkleRoot, MerkleBlockError> {
matches.clear();
indexes.clear();
// An empty set will not work
@ -221,7 +221,7 @@ impl PartialMerkleTree {
if hash_used != self.hashes.len() as u32 {
return Err(BadFormat("Not all hashes were consumed".to_owned()));
}
Ok(hash_merkle_root)
Ok(TxMerkleRoot::from_inner(hash_merkle_root.into_inner()))
}
/// Helper function to efficiently calculate the number of nodes at given height
@ -232,10 +232,10 @@ impl PartialMerkleTree {
}
/// Calculate the hash of a node in the merkle tree (at leaf level: the txid's themselves)
fn calc_hash(&self, height: u32, pos: u32, txids: &[Txid]) -> sha256d::Hash {
fn calc_hash(&self, height: u32, pos: u32, txids: &[Txid]) -> TxMerkleBranch {
if height == 0 {
// Hash at height 0 is the txid itself
txids[pos as usize].into()
TxMerkleBranch::from_inner(txids[pos as usize].into_inner())
} else {
// Calculate left hash
let left = self.calc_hash(height - 1, pos * 2, txids);
@ -291,7 +291,7 @@ impl PartialMerkleTree {
hash_used: &mut u32,
matches: &mut Vec<Txid>,
indexes: &mut Vec<u32>,
) -> Result<sha256d::Hash, MerkleBlockError> {
) -> Result<TxMerkleBranch, MerkleBlockError> {
if *bits_used as usize >= self.bits.len() {
return Err(BadFormat("Overflowed the bits array".to_owned()));
}
@ -306,7 +306,7 @@ impl PartialMerkleTree {
*hash_used += 1;
if height == 0 && parent_of_match {
// in case of height 0, we have a matched txid
matches.push(hash.into());
matches.push(Txid::from_inner(hash.into_inner()));
indexes.push(pos);
}
Ok(hash)
@ -344,11 +344,11 @@ impl PartialMerkleTree {
}
/// Helper method to produce SHA256D(left + right)
fn parent_hash(left: sha256d::Hash, right: sha256d::Hash) -> sha256d::Hash {
let mut encoder = sha256d::Hash::engine();
fn parent_hash(left: TxMerkleBranch, right: TxMerkleBranch) -> TxMerkleBranch {
let mut encoder = TxMerkleBranch::engine();
left.consensus_encode(&mut encoder).unwrap();
right.consensus_encode(&mut encoder).unwrap();
sha256d::Hash::from_engine(encoder)
TxMerkleBranch::from_engine(encoder)
}
}
@ -370,7 +370,7 @@ impl Encodable for PartialMerkleTree {
impl Decodable for PartialMerkleTree {
fn consensus_decode<D: io::Read>(mut d: D) -> Result<Self, encode::Error> {
let num_transactions: u32 = Decodable::consensus_decode(&mut d)?;
let hashes: Vec<sha256d::Hash> = Decodable::consensus_decode(&mut d)?;
let hashes: Vec<TxMerkleBranch> = Decodable::consensus_decode(&mut d)?;
let bytes: Vec<u8> = Decodable::consensus_decode(d)?;
let mut bits: Vec<bool> = vec![false; bytes.len() * 8];
@ -496,9 +496,9 @@ impl Decodable for MerkleBlock {
mod tests {
use std::cmp::min;
use hash_types::Txid;
use hashes::Hash;
use hashes::hex::{FromHex, ToHex};
use hashes::{sha256d, Hash};
use hash_types::{Txid, TxMerkleRoot, TxMerkleBranch};
use secp256k1::rand::prelude::*;
use consensus::encode::{deserialize, serialize};
@ -565,7 +565,7 @@ mod tests {
// Check that it has the same merkle root as the original, and a valid one
assert_eq!(merkle_root_1, merkle_root_2);
assert_ne!(merkle_root_2, sha256d::Hash::default());
assert_ne!(merkle_root_2, TxMerkleRoot::default());
// check that it contains the matched transactions (in the same order!)
assert_eq!(match_txid1, match_txid2);
@ -701,7 +701,7 @@ mod tests {
let hashes = &mut self.hashes;
let mut hash = hashes[n].into_inner();
hash[(bit >> 3) as usize] ^= 1 << (bit & 7);
hashes[n] = sha256d::Hash::from_slice(&hash).unwrap();
hashes[n] = TxMerkleBranch::from_slice(&hash).unwrap();
}
}