New hash types: MerkleRoot/Branch, WitnessCommit, SigHash, FilterHash
This commit is contained in:
parent
4746ccb88e
commit
f5a8087105
|
@ -20,18 +20,16 @@
|
||||||
//! these blocks and the blockchain.
|
//! these blocks and the blockchain.
|
||||||
//!
|
//!
|
||||||
|
|
||||||
use hashes::{sha256d, Hash};
|
|
||||||
|
|
||||||
use util;
|
use util;
|
||||||
use util::Error::{BlockBadTarget, BlockBadProofOfWork};
|
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 util::uint::Uint256;
|
||||||
use hash_types::{Txid, BlockHash};
|
|
||||||
use consensus::encode::Encodable;
|
use consensus::encode::Encodable;
|
||||||
use network::constants::Network;
|
use network::constants::Network;
|
||||||
use blockdata::transaction::Transaction;
|
use blockdata::transaction::Transaction;
|
||||||
use blockdata::constants::max_target;
|
use blockdata::constants::max_target;
|
||||||
use hashes::HashEngine;
|
|
||||||
|
|
||||||
/// A block header, which contains all the block's information except
|
/// A block header, which contains all the block's information except
|
||||||
/// the actual transactions
|
/// the actual transactions
|
||||||
|
@ -42,7 +40,7 @@ pub struct BlockHeader {
|
||||||
/// Reference to the previous block in the chain
|
/// Reference to the previous block in the chain
|
||||||
pub prev_blockhash: BlockHash,
|
pub prev_blockhash: BlockHash,
|
||||||
/// The root hash of the merkle tree of transactions in the block
|
/// 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
|
/// The timestamp of the block, as claimed by the miner
|
||||||
pub time: u32,
|
pub time: u32,
|
||||||
/// The target value below which the blockhash must lie, encoded as a
|
/// The target value below which the blockhash must lie, encoded as a
|
||||||
|
@ -83,7 +81,7 @@ impl Block {
|
||||||
.rposition(|o| {
|
.rposition(|o| {
|
||||||
o.script_pubkey.len () >= 38 &&
|
o.script_pubkey.len () >= 38 &&
|
||||||
o.script_pubkey[0..6] == [0x6a, 0x24, 0xaa, 0x21, 0xa9, 0xed] }) {
|
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
|
// witness reserved value is in coinbase input witness
|
||||||
if coinbase.input[0].witness.len() == 1 && coinbase.input[0].witness[0].len() == 32 {
|
if coinbase.input[0].witness.len() == 1 && coinbase.input[0].witness[0].len() == 32 {
|
||||||
let witness_root = self.witness_root();
|
let witness_root = self.witness_root();
|
||||||
|
@ -96,23 +94,24 @@ impl Block {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// compute witness commitment for the transaction list
|
/// compute witness commitment for the transaction list
|
||||||
pub fn compute_witness_commitment (witness_root: &sha256d::Hash, witness_reserved_value: &[u8]) -> sha256d::Hash {
|
pub fn compute_witness_commitment (witness_root: &WitnessMerkleRoot, witness_reserved_value: &[u8]) -> WitnessCommitment {
|
||||||
let mut encoder = sha256d::Hash::engine();
|
let mut encoder = WitnessCommitment::engine();
|
||||||
witness_root.consensus_encode(&mut encoder).unwrap();
|
witness_root.consensus_encode(&mut encoder).unwrap();
|
||||||
encoder.input(witness_reserved_value);
|
encoder.input(witness_reserved_value);
|
||||||
sha256d::Hash::from_engine(encoder)
|
WitnessCommitment::from_engine(encoder)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Merkle root of transactions hashed for witness
|
/// 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());
|
let mut txhashes = vec!(Txid::default());
|
||||||
txhashes.extend(self.txdata.iter().skip(1).map(|t|t.bitcoin_hash()));
|
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 {
|
impl MerkleRooted for Block {
|
||||||
fn merkle_root(&self) -> sha256d::Hash {
|
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())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -213,7 +212,7 @@ mod tests {
|
||||||
|
|
||||||
use blockdata::block::{Block, BlockHeader};
|
use blockdata::block::{Block, BlockHeader};
|
||||||
use consensus::encode::{deserialize, serialize};
|
use consensus::encode::{deserialize, serialize};
|
||||||
use util::hash::MerkleRoot;
|
use util::hash::MerkleRooted;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn block_test() {
|
fn block_test() {
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
use std::default::Default;
|
use std::default::Default;
|
||||||
|
|
||||||
use hashes::hex::FromHex;
|
use hashes::hex::FromHex;
|
||||||
|
use hashes::sha256d;
|
||||||
use blockdata::opcodes;
|
use blockdata::opcodes;
|
||||||
use blockdata::script;
|
use blockdata::script;
|
||||||
use blockdata::transaction::{OutPoint, Transaction, TxOut, TxIn};
|
use blockdata::transaction::{OutPoint, Transaction, TxOut, TxIn};
|
||||||
|
@ -97,7 +97,8 @@ fn bitcoin_genesis_tx() -> Transaction {
|
||||||
/// Constructs and returns the genesis block
|
/// Constructs and returns the genesis block
|
||||||
pub fn genesis_block(network: Network) -> Block {
|
pub fn genesis_block(network: Network) -> Block {
|
||||||
let txdata = vec![bitcoin_genesis_tx()];
|
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 {
|
match network {
|
||||||
Network::Bitcoin => {
|
Network::Bitcoin => {
|
||||||
Block {
|
Block {
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
use std::default::Default;
|
use std::default::Default;
|
||||||
use std::{fmt, io};
|
use std::{fmt, io};
|
||||||
|
|
||||||
use hashes::{self, sha256d, Hash};
|
use hashes::{self, Hash, sha256d};
|
||||||
use hashes::hex::FromHex;
|
use hashes::hex::FromHex;
|
||||||
|
|
||||||
use util::endian;
|
use util::endian;
|
||||||
|
@ -316,14 +316,14 @@ impl Transaction {
|
||||||
/// # Panics
|
/// # Panics
|
||||||
/// Panics if `input_index` is greater than or equal to `self.input.len()`
|
/// 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
|
assert!(input_index < self.input.len()); // Panic on OOB
|
||||||
|
|
||||||
let (sighash, anyone_can_pay) = SigHashType::from_u32(sighash_u32).split_anyonecanpay_flag();
|
let (sighash, anyone_can_pay) = SigHashType::from_u32(sighash_u32).split_anyonecanpay_flag();
|
||||||
|
|
||||||
// Special-case sighash_single bug because this is easy enough.
|
// Special-case sighash_single bug because this is easy enough.
|
||||||
if sighash == SigHashType::Single && input_index >= self.output.len() {
|
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,
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
0, 0, 0, 0, 0, 0, 0, 0]).unwrap();
|
0, 0, 0, 0, 0, 0, 0, 0]).unwrap();
|
||||||
|
@ -371,7 +371,7 @@ impl Transaction {
|
||||||
// hash the result
|
// hash the result
|
||||||
let mut raw_vec = serialize(&tx);
|
let mut raw_vec = serialize(&tx);
|
||||||
raw_vec.extend_from_slice(&endian::u32_to_array_le(sighash_u32));
|
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
|
/// 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 consensus::encode::deserialize;
|
||||||
use util::hash::BitcoinHash;
|
use util::hash::BitcoinHash;
|
||||||
|
|
||||||
use hashes::{sha256d, Hash};
|
use hashes::Hash;
|
||||||
use hashes::hex::FromHex;
|
use hashes::hex::FromHex;
|
||||||
|
|
||||||
use hash_types::*;
|
use hash_types::*;
|
||||||
|
@ -813,7 +813,7 @@ mod tests {
|
||||||
let script = Script::from(Vec::<u8>::from_hex(script).unwrap());
|
let script = Script::from(Vec::<u8>::from_hex(script).unwrap());
|
||||||
let mut raw_expected = Vec::<u8>::from_hex(expected_result).unwrap();
|
let mut raw_expected = Vec::<u8>::from_hex(expected_result).unwrap();
|
||||||
raw_expected.reverse();
|
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);
|
let actual_result = tx.signature_hash(input_index, &script, hash_type as u32);
|
||||||
assert_eq!(actual_result, expected_result);
|
assert_eq!(actual_result, expected_result);
|
||||||
|
|
|
@ -35,6 +35,7 @@ use std::io::{Cursor, Read, Write};
|
||||||
use hashes::hex::ToHex;
|
use hashes::hex::ToHex;
|
||||||
|
|
||||||
use hashes::{sha256d, Hash as HashTrait};
|
use hashes::{sha256d, Hash as HashTrait};
|
||||||
|
use hash_types::{FilterHash, TxMerkleBranch};
|
||||||
|
|
||||||
use util::endian;
|
use util::endian;
|
||||||
use util::psbt;
|
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!(Transaction);
|
||||||
impl_vec!(TxOut);
|
impl_vec!(TxOut);
|
||||||
impl_vec!(TxIn);
|
impl_vec!(TxIn);
|
||||||
|
|
|
@ -20,9 +20,6 @@ use std::io;
|
||||||
|
|
||||||
use consensus::encode::{Encodable, Decodable, Error};
|
use consensus::encode::{Encodable, Decodable, Error};
|
||||||
use hashes::{sha256, sha256d, hash160, Hash};
|
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};
|
use hashes::hex::{ToHex, FromHex};
|
||||||
|
|
||||||
macro_rules! impl_hashencode {
|
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!(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!(Wtxid, sha256d::Hash, 32, doc="A bitcoin witness transaction ID.");
|
||||||
hash_newtype!(BlockHash, sha256d::Hash, 32, doc="A bitcoin block hash.");
|
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!(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!(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!(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!(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!(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!(Txid);
|
||||||
impl_hashencode!(Wtxid);
|
impl_hashencode!(Wtxid);
|
||||||
|
impl_hashencode!(SigHash);
|
||||||
impl_hashencode!(BlockHash);
|
impl_hashencode!(BlockHash);
|
||||||
|
impl_hashencode!(TxMerkleRoot);
|
||||||
|
impl_hashencode!(TxMerkleBranch);
|
||||||
|
impl_hashencode!(WitnessMerkleRoot);
|
||||||
|
impl_hashencode!(FilterHash);
|
||||||
|
|
|
@ -227,7 +227,7 @@ macro_rules! display_from_debug {
|
||||||
macro_rules! hex_script (($s:expr) => (::blockdata::script::Script::from(::hex::decode($s).unwrap())));
|
macro_rules! hex_script (($s:expr) => (::blockdata::script::Script::from(::hex::decode($s).unwrap())));
|
||||||
|
|
||||||
#[cfg(test)]
|
#[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 {
|
macro_rules! serde_struct_impl {
|
||||||
($name:ident, $($fe:ident),*) => (
|
($name:ident, $($fe:ident),*) => (
|
||||||
|
|
|
@ -77,6 +77,7 @@ pub mod network;
|
||||||
pub mod blockdata;
|
pub mod blockdata;
|
||||||
pub mod util;
|
pub mod util;
|
||||||
pub mod consensus;
|
pub mod consensus;
|
||||||
|
// Do not remove: required in order to get hash types implementation macros to work correctly
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
pub mod hash_types;
|
pub mod hash_types;
|
||||||
|
|
||||||
|
|
|
@ -362,11 +362,11 @@ mod test {
|
||||||
NetworkMessage::Version(version_msg),
|
NetworkMessage::Version(version_msg),
|
||||||
NetworkMessage::Verack,
|
NetworkMessage::Verack,
|
||||||
NetworkMessage::Addr(vec![(45, Address::new(&([123,255,000,100], 833).into(), ServiceFlags::NETWORK))]),
|
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::Inv(vec![Inventory{inv_type: InvType::Block, hash: hash([8u8; 32]).into()}]),
|
||||||
NetworkMessage::GetData(vec![Inventory{inv_type: InvType::Transaction, hash: hash([45u8; 32])}]),
|
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])}]),
|
NetworkMessage::NotFound(vec![Inventory{inv_type: InvType::Error, hash: hash([45u8; 32]).into()}]),
|
||||||
NetworkMessage::GetBlocks(GetBlocksMessage::new(vec![hash([1u8; 32]), hash([4u8; 32])], hash([5u8; 32]))),
|
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]), hash([40u8; 32])], hash([50u8; 32]))),
|
NetworkMessage::GetHeaders(GetHeadersMessage::new(vec![hash([10u8; 32]).into(), hash([40u8; 32]).into()], hash([50u8; 32]).into())),
|
||||||
NetworkMessage::MemPool,
|
NetworkMessage::MemPool,
|
||||||
NetworkMessage::Tx(tx),
|
NetworkMessage::Tx(tx),
|
||||||
NetworkMessage::Block(block),
|
NetworkMessage::Block(block),
|
||||||
|
@ -377,10 +377,10 @@ mod test {
|
||||||
NetworkMessage::Pong(23),
|
NetworkMessage::Pong(23),
|
||||||
NetworkMessage::GetCFilters(GetCFilters{filter_type: 2, start_height: 52, stop_hash: hash([42u8; 32]).into()}),
|
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::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::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]), previous_filter: hash([12u8; 32]), filter_hashes: vec![hash([4u8; 32]), hash([12u8; 32])]}),
|
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])}),
|
NetworkMessage::GetCFCheckpt(GetCFCheckpt{filter_type: 17, stop_hash: hash([25u8; 32]).into()}),
|
||||||
NetworkMessage::CFCheckpt(CFCheckpt{filter_type: 27, stop_hash: hash([77u8; 32]), filter_headers: vec![hash([3u8; 32]), hash([99u8; 32])]}),
|
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::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])}),
|
NetworkMessage::Reject(Reject{message: "Test reject".into(), ccode: RejectReason::Duplicate, reason: "Cause".into(), hash: hash([255u8; 32])}),
|
||||||
];
|
];
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
|
|
||||||
use network::constants;
|
use network::constants;
|
||||||
use consensus::encode::{self, Decodable, Encodable};
|
use consensus::encode::{self, Decodable, Encodable};
|
||||||
use hashes::sha256d;
|
use hash_types::FilterHash;
|
||||||
|
|
||||||
use std::io;
|
use std::io;
|
||||||
|
|
||||||
|
@ -49,9 +49,9 @@ pub struct GetBlocksMessage {
|
||||||
/// Locator hashes --- ordered newest to oldest. The remote peer will
|
/// Locator hashes --- ordered newest to oldest. The remote peer will
|
||||||
/// reply with its longest known chain, starting from a locator hash
|
/// reply with its longest known chain, starting from a locator hash
|
||||||
/// if possible and block 1 otherwise.
|
/// 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
|
/// 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
|
/// The `getheaders` message
|
||||||
|
@ -62,9 +62,9 @@ pub struct GetHeadersMessage {
|
||||||
/// Locator hashes --- ordered newest to oldest. The remote peer will
|
/// Locator hashes --- ordered newest to oldest. The remote peer will
|
||||||
/// reply with its longest known chain, starting from a locator hash
|
/// reply with its longest known chain, starting from a locator hash
|
||||||
/// if possible and block 1 otherwise.
|
/// 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
|
/// 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
|
/// An inventory object --- a reference to a Bitcoin object
|
||||||
|
@ -73,7 +73,7 @@ pub struct Inventory {
|
||||||
/// The type of object that is referenced
|
/// The type of object that is referenced
|
||||||
pub inv_type: InvType,
|
pub inv_type: InvType,
|
||||||
/// The object's hash
|
/// The object's hash
|
||||||
pub hash: sha256d::Hash
|
pub hash: FilterHash
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ::std::hash::Hash for Inventory {
|
impl ::std::hash::Hash for Inventory {
|
||||||
|
@ -84,7 +84,7 @@ impl ::std::hash::Hash for Inventory {
|
||||||
|
|
||||||
impl GetBlocksMessage {
|
impl GetBlocksMessage {
|
||||||
/// Construct a new `getblocks` message
|
/// 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 {
|
GetBlocksMessage {
|
||||||
version: constants::PROTOCOL_VERSION,
|
version: constants::PROTOCOL_VERSION,
|
||||||
locator_hashes: locator_hashes.clone(),
|
locator_hashes: locator_hashes.clone(),
|
||||||
|
@ -97,7 +97,7 @@ impl_consensus_encoding!(GetBlocksMessage, version, locator_hashes, stop_hash);
|
||||||
|
|
||||||
impl GetHeadersMessage {
|
impl GetHeadersMessage {
|
||||||
/// Construct a new `getheaders` message
|
/// 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 {
|
GetHeadersMessage {
|
||||||
version: constants::PROTOCOL_VERSION,
|
version: constants::PROTOCOL_VERSION,
|
||||||
locator_hashes: locator_hashes,
|
locator_hashes: locator_hashes,
|
||||||
|
|
|
@ -2,8 +2,7 @@
|
||||||
//! BIP157 Client Side Block Filtering network messages
|
//! BIP157 Client Side Block Filtering network messages
|
||||||
//!
|
//!
|
||||||
|
|
||||||
use hash_types::BlockHash;
|
use hash_types::{BlockHash, FilterHash};
|
||||||
use hashes::sha256d;
|
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Clone, Debug)]
|
#[derive(PartialEq, Eq, Clone, Debug)]
|
||||||
/// getcfilters message
|
/// getcfilters message
|
||||||
|
@ -37,7 +36,7 @@ pub struct GetCFHeaders {
|
||||||
/// The height of the first block in the requested range
|
/// The height of the first block in the requested range
|
||||||
pub start_height: u32,
|
pub start_height: u32,
|
||||||
/// The hash of the last block in the requested range
|
/// 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);
|
impl_consensus_encoding!(GetCFHeaders, filter_type, start_height, stop_hash);
|
||||||
|
|
||||||
|
@ -47,11 +46,11 @@ pub struct CFHeaders {
|
||||||
/// Filter type for which headers are requested
|
/// Filter type for which headers are requested
|
||||||
pub filter_type: u8,
|
pub filter_type: u8,
|
||||||
/// The hash of the last block in the requested range
|
/// 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
|
/// 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
|
/// 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);
|
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
|
/// Filter type for which headers are requested
|
||||||
pub filter_type: u8,
|
pub filter_type: u8,
|
||||||
/// The hash of the last block in the requested range
|
/// 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);
|
impl_consensus_encoding!(GetCFCheckpt, filter_type, stop_hash);
|
||||||
|
|
||||||
|
@ -71,8 +70,8 @@ pub struct CFCheckpt {
|
||||||
/// Filter type for which headers are requested
|
/// Filter type for which headers are requested
|
||||||
pub filter_type: u8,
|
pub filter_type: u8,
|
||||||
/// The hash of the last block in the requested range
|
/// 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
|
/// 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);
|
impl_consensus_encoding!(CFCheckpt, filter_type, stop_hash, filter_headers);
|
|
@ -19,8 +19,8 @@
|
||||||
//! signatures, which are placed in the scriptSig.
|
//! signatures, which are placed in the scriptSig.
|
||||||
//!
|
//!
|
||||||
|
|
||||||
use hashes::{sha256d, Hash};
|
use hashes::Hash;
|
||||||
|
use hash_types::SigHash;
|
||||||
use blockdata::script::Script;
|
use blockdata::script::Script;
|
||||||
use blockdata::transaction::{Transaction, TxIn};
|
use blockdata::transaction::{Transaction, TxIn};
|
||||||
use consensus::encode::Encodable;
|
use consensus::encode::Encodable;
|
||||||
|
@ -32,11 +32,11 @@ pub struct SighashComponents {
|
||||||
tx_version: u32,
|
tx_version: u32,
|
||||||
tx_locktime: u32,
|
tx_locktime: u32,
|
||||||
/// Hash of all the previous outputs
|
/// Hash of all the previous outputs
|
||||||
pub hash_prevouts: sha256d::Hash,
|
pub hash_prevouts: SigHash,
|
||||||
/// Hash of all the input sequence nos
|
/// Hash of all the input sequence nos
|
||||||
pub hash_sequence: sha256d::Hash,
|
pub hash_sequence: SigHash,
|
||||||
/// Hash of all the outputs in this transaction
|
/// Hash of all the outputs in this transaction
|
||||||
pub hash_outputs: sha256d::Hash,
|
pub hash_outputs: SigHash,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SighashComponents {
|
impl SighashComponents {
|
||||||
|
@ -46,27 +46,27 @@ impl SighashComponents {
|
||||||
/// script_sig and witnesses.
|
/// script_sig and witnesses.
|
||||||
pub fn new(tx: &Transaction) -> SighashComponents {
|
pub fn new(tx: &Transaction) -> SighashComponents {
|
||||||
let hash_prevouts = {
|
let hash_prevouts = {
|
||||||
let mut enc = sha256d::Hash::engine();
|
let mut enc = SigHash::engine();
|
||||||
for txin in &tx.input {
|
for txin in &tx.input {
|
||||||
txin.previous_output.consensus_encode(&mut enc).unwrap();
|
txin.previous_output.consensus_encode(&mut enc).unwrap();
|
||||||
}
|
}
|
||||||
sha256d::Hash::from_engine(enc)
|
SigHash::from_engine(enc)
|
||||||
};
|
};
|
||||||
|
|
||||||
let hash_sequence = {
|
let hash_sequence = {
|
||||||
let mut enc = sha256d::Hash::engine();
|
let mut enc = SigHash::engine();
|
||||||
for txin in &tx.input {
|
for txin in &tx.input {
|
||||||
txin.sequence.consensus_encode(&mut enc).unwrap();
|
txin.sequence.consensus_encode(&mut enc).unwrap();
|
||||||
}
|
}
|
||||||
sha256d::Hash::from_engine(enc)
|
SigHash::from_engine(enc)
|
||||||
};
|
};
|
||||||
|
|
||||||
let hash_outputs = {
|
let hash_outputs = {
|
||||||
let mut enc = sha256d::Hash::engine();
|
let mut enc = SigHash::engine();
|
||||||
for txout in &tx.output {
|
for txout in &tx.output {
|
||||||
txout.consensus_encode(&mut enc).unwrap();
|
txout.consensus_encode(&mut enc).unwrap();
|
||||||
}
|
}
|
||||||
sha256d::Hash::from_engine(enc)
|
SigHash::from_engine(enc)
|
||||||
};
|
};
|
||||||
|
|
||||||
SighashComponents {
|
SighashComponents {
|
||||||
|
@ -80,8 +80,8 @@ impl SighashComponents {
|
||||||
|
|
||||||
/// Compute the BIP143 sighash for a `SIGHASH_ALL` signature for the given
|
/// Compute the BIP143 sighash for a `SIGHASH_ALL` signature for the given
|
||||||
/// input.
|
/// input.
|
||||||
pub fn sighash_all(&self, txin: &TxIn, script_code: &Script, value: u64) -> sha256d::Hash {
|
pub fn sighash_all(&self, txin: &TxIn, script_code: &Script, value: u64) -> SigHash {
|
||||||
let mut enc = sha256d::Hash::engine();
|
let mut enc = SigHash::engine();
|
||||||
self.tx_version.consensus_encode(&mut enc).unwrap();
|
self.tx_version.consensus_encode(&mut enc).unwrap();
|
||||||
self.hash_prevouts.consensus_encode(&mut enc).unwrap();
|
self.hash_prevouts.consensus_encode(&mut enc).unwrap();
|
||||||
self.hash_sequence.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.hash_outputs.consensus_encode(&mut enc).unwrap();
|
||||||
self.tx_locktime.consensus_encode(&mut enc).unwrap();
|
self.tx_locktime.consensus_encode(&mut enc).unwrap();
|
||||||
1u32.consensus_encode(&mut enc).unwrap(); // hashtype
|
1u32.consensus_encode(&mut enc).unwrap(); // hashtype
|
||||||
sha256d::Hash::from_engine(enc)
|
SigHash::from_engine(enc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use hash_types::SigHash;
|
||||||
use blockdata::script::Script;
|
use blockdata::script::Script;
|
||||||
use blockdata::transaction::Transaction;
|
use blockdata::transaction::Transaction;
|
||||||
use consensus::encode::deserialize;
|
use consensus::encode::deserialize;
|
||||||
|
@ -140,20 +141,20 @@ mod tests {
|
||||||
tx_version: 1,
|
tx_version: 1,
|
||||||
tx_locktime: 17,
|
tx_locktime: 17,
|
||||||
hash_prevouts: hex_hash!(
|
hash_prevouts: hex_hash!(
|
||||||
"96b827c8483d4e9b96712b6713a7b68d6e8003a781feba36c31143470b4efd37"
|
SigHash, "96b827c8483d4e9b96712b6713a7b68d6e8003a781feba36c31143470b4efd37"
|
||||||
),
|
),
|
||||||
hash_sequence: hex_hash!(
|
hash_sequence: hex_hash!(
|
||||||
"52b0a642eea2fb7ae638c36f6252b6750293dbe574a806984b8e4d8548339a3b"
|
SigHash, "52b0a642eea2fb7ae638c36f6252b6750293dbe574a806984b8e4d8548339a3b"
|
||||||
),
|
),
|
||||||
hash_outputs: hex_hash!(
|
hash_outputs: hex_hash!(
|
||||||
"863ef3e1a92afbfdb97f31ad0fc7683ee943e9abcf2501590ff8f6551f47e5e5"
|
SigHash, "863ef3e1a92afbfdb97f31ad0fc7683ee943e9abcf2501590ff8f6551f47e5e5"
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
comp.sighash_all(&tx.input[1], &witness_script, value),
|
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_version: 1,
|
||||||
tx_locktime: 1170,
|
tx_locktime: 1170,
|
||||||
hash_prevouts: hex_hash!(
|
hash_prevouts: hex_hash!(
|
||||||
"b0287b4a252ac05af83d2dcef00ba313af78a3e9c329afa216eb3aa2a7b4613a"
|
SigHash, "b0287b4a252ac05af83d2dcef00ba313af78a3e9c329afa216eb3aa2a7b4613a"
|
||||||
),
|
),
|
||||||
hash_sequence: hex_hash!(
|
hash_sequence: hex_hash!(
|
||||||
"18606b350cd8bf565266bc352f0caddcf01e8fa789dd8a15386327cf8cabe198"
|
SigHash, "18606b350cd8bf565266bc352f0caddcf01e8fa789dd8a15386327cf8cabe198"
|
||||||
),
|
),
|
||||||
hash_outputs: hex_hash!(
|
hash_outputs: hex_hash!(
|
||||||
"de984f44532e2173ca0d64314fcefe6d30da6f8cf27bafa706da61df8a226c83"
|
SigHash, "de984f44532e2173ca0d64314fcefe6d30da6f8cf27bafa706da61df8a226c83"
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
comp.sighash_all(&tx.input[0], &witness_script, value),
|
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_version: 1,
|
||||||
tx_locktime: 0,
|
tx_locktime: 0,
|
||||||
hash_prevouts: hex_hash!(
|
hash_prevouts: hex_hash!(
|
||||||
"74afdc312af5183c4198a40ca3c1a275b485496dd3929bca388c4b5e31f7aaa0"
|
SigHash, "74afdc312af5183c4198a40ca3c1a275b485496dd3929bca388c4b5e31f7aaa0"
|
||||||
),
|
),
|
||||||
hash_sequence: hex_hash!(
|
hash_sequence: hex_hash!(
|
||||||
"3bb13029ce7b1f559ef5e747fcac439f1455a2ec7c5f09b72290795e70665044"
|
SigHash, "3bb13029ce7b1f559ef5e747fcac439f1455a2ec7c5f09b72290795e70665044"
|
||||||
),
|
),
|
||||||
hash_outputs: hex_hash!(
|
hash_outputs: hex_hash!(
|
||||||
"bc4d309071414bed932f98832b27b4d76dad7e6c1346f487a8fdbb8eb90307cc"
|
SigHash, "bc4d309071414bed932f98832b27b4d76dad7e6c1346f487a8fdbb8eb90307cc"
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
comp.sighash_all(&tx.input[0], &witness_script, value),
|
comp.sighash_all(&tx.input[0], &witness_script, value),
|
||||||
hex_hash!("185c0be5263dce5b4bb50a047973c1b6272bfbd0103a89444597dc40b248ee7c")
|
hex_hash!(SigHash, "185c0be5263dce5b4bb50a047973c1b6272bfbd0103a89444597dc40b248ee7c")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,8 +50,8 @@ use std::error;
|
||||||
use std::fmt::{Display, Formatter};
|
use std::fmt::{Display, Formatter};
|
||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
|
|
||||||
use hash_types::BlockHash;
|
use hashes::{Hash, siphash24};
|
||||||
use hashes::{Hash, sha256d, siphash24};
|
use hash_types::{BlockHash, FilterHash};
|
||||||
|
|
||||||
use blockdata::block::Block;
|
use blockdata::block::Block;
|
||||||
use blockdata::script::Script;
|
use blockdata::script::Script;
|
||||||
|
@ -107,12 +107,12 @@ pub struct BlockFilter {
|
||||||
|
|
||||||
impl BlockFilter {
|
impl BlockFilter {
|
||||||
/// compute this filter's id in a chain of filters
|
/// compute this filter's id in a chain of filters
|
||||||
pub fn filter_id(&self, previous_filter_id: &sha256d::Hash) -> sha256d::Hash {
|
pub fn filter_id(&self, previous_filter_id: &FilterHash) -> FilterHash {
|
||||||
let filter_hash = sha256d::Hash::hash(self.content.as_slice());
|
let filter_hash = FilterHash::hash(self.content.as_slice());
|
||||||
let mut header_data = [0u8; 64];
|
let mut header_data = [0u8; 64];
|
||||||
header_data[0..32].copy_from_slice(&filter_hash[..]);
|
header_data[0..32].copy_from_slice(&filter_hash[..]);
|
||||||
header_data[32..64].copy_from_slice(&previous_filter_id[..]);
|
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
|
/// 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();
|
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);
|
assert_eq!(block.bitcoin_hash(), block_hash);
|
||||||
let scripts = t.get(3).unwrap().as_array().unwrap();
|
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_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 txmap = HashMap::new();
|
||||||
let mut si = scripts.iter();
|
let mut si = scripts.iter();
|
||||||
|
|
|
@ -18,33 +18,33 @@
|
||||||
use std::cmp::min;
|
use std::cmp::min;
|
||||||
use std::default::Default;
|
use std::default::Default;
|
||||||
|
|
||||||
use hash_types::Txid;
|
use hashes::Hash;
|
||||||
use hashes::{sha256d, Hash};
|
use hash_types::{Txid, TxMerkleRoot};
|
||||||
|
|
||||||
use consensus::encode::Encodable;
|
use consensus::encode::Encodable;
|
||||||
|
|
||||||
/// Any collection of objects for which a merkle root makes sense to calculate
|
/// 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
|
/// Construct a merkle tree from a collection, with elements ordered as
|
||||||
/// they were in the original collection, and return the merkle root.
|
/// 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
|
/// 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
|
// Base case
|
||||||
if data.len() < 1 {
|
if data.len() < 1 {
|
||||||
return Default::default();
|
return Default::default();
|
||||||
}
|
}
|
||||||
if data.len() < 2 {
|
if data.len() < 2 {
|
||||||
return data[0].into();
|
return TxMerkleRoot::from_inner(data[0].into_inner());
|
||||||
}
|
}
|
||||||
// Recursion
|
// Recursion
|
||||||
let mut next = vec![];
|
let mut next = vec![];
|
||||||
for idx in 0..((data.len() + 1) / 2) {
|
for idx in 0..((data.len() + 1) / 2) {
|
||||||
let idx1 = 2 * idx;
|
let idx1 = 2 * idx;
|
||||||
let idx2 = min(idx1 + 1, data.len() - 1);
|
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[idx1].consensus_encode(&mut encoder).unwrap();
|
||||||
data[idx2].consensus_encode(&mut encoder).unwrap();
|
data[idx2].consensus_encode(&mut encoder).unwrap();
|
||||||
next.push(Txid::from_engine(encoder));
|
next.push(Txid::from_engine(encoder));
|
||||||
|
|
|
@ -58,8 +58,8 @@
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::io;
|
use std::io;
|
||||||
|
|
||||||
use hash_types::Txid;
|
use hashes::Hash;
|
||||||
use hashes::{sha256d, Hash};
|
use hash_types::{Txid, TxMerkleRoot, TxMerkleBranch};
|
||||||
|
|
||||||
use blockdata::constants::{MAX_BLOCK_WEIGHT, MIN_TRANSACTION_WEIGHT};
|
use blockdata::constants::{MAX_BLOCK_WEIGHT, MIN_TRANSACTION_WEIGHT};
|
||||||
use consensus::encode::{self, Decodable, Encodable};
|
use consensus::encode::{self, Decodable, Encodable};
|
||||||
|
@ -120,7 +120,7 @@ pub struct PartialMerkleTree {
|
||||||
/// node-is-parent-of-matched-txid bits
|
/// node-is-parent-of-matched-txid bits
|
||||||
bits: Vec<bool>,
|
bits: Vec<bool>,
|
||||||
/// Transaction ids and internal hashes
|
/// Transaction ids and internal hashes
|
||||||
hashes: Vec<sha256d::Hash>,
|
hashes: Vec<TxMerkleBranch>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialMerkleTree {
|
impl PartialMerkleTree {
|
||||||
|
@ -181,7 +181,7 @@ impl PartialMerkleTree {
|
||||||
&self,
|
&self,
|
||||||
matches: &mut Vec<Txid>,
|
matches: &mut Vec<Txid>,
|
||||||
indexes: &mut Vec<u32>,
|
indexes: &mut Vec<u32>,
|
||||||
) -> Result<sha256d::Hash, MerkleBlockError> {
|
) -> Result<TxMerkleRoot, MerkleBlockError> {
|
||||||
matches.clear();
|
matches.clear();
|
||||||
indexes.clear();
|
indexes.clear();
|
||||||
// An empty set will not work
|
// An empty set will not work
|
||||||
|
@ -221,7 +221,7 @@ impl PartialMerkleTree {
|
||||||
if hash_used != self.hashes.len() as u32 {
|
if hash_used != self.hashes.len() as u32 {
|
||||||
return Err(BadFormat("Not all hashes were consumed".to_owned()));
|
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
|
/// 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)
|
/// 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 {
|
if height == 0 {
|
||||||
// Hash at height 0 is the txid itself
|
// Hash at height 0 is the txid itself
|
||||||
txids[pos as usize].into()
|
TxMerkleBranch::from_inner(txids[pos as usize].into_inner())
|
||||||
} else {
|
} else {
|
||||||
// Calculate left hash
|
// Calculate left hash
|
||||||
let left = self.calc_hash(height - 1, pos * 2, txids);
|
let left = self.calc_hash(height - 1, pos * 2, txids);
|
||||||
|
@ -291,7 +291,7 @@ impl PartialMerkleTree {
|
||||||
hash_used: &mut u32,
|
hash_used: &mut u32,
|
||||||
matches: &mut Vec<Txid>,
|
matches: &mut Vec<Txid>,
|
||||||
indexes: &mut Vec<u32>,
|
indexes: &mut Vec<u32>,
|
||||||
) -> Result<sha256d::Hash, MerkleBlockError> {
|
) -> Result<TxMerkleBranch, MerkleBlockError> {
|
||||||
if *bits_used as usize >= self.bits.len() {
|
if *bits_used as usize >= self.bits.len() {
|
||||||
return Err(BadFormat("Overflowed the bits array".to_owned()));
|
return Err(BadFormat("Overflowed the bits array".to_owned()));
|
||||||
}
|
}
|
||||||
|
@ -306,7 +306,7 @@ impl PartialMerkleTree {
|
||||||
*hash_used += 1;
|
*hash_used += 1;
|
||||||
if height == 0 && parent_of_match {
|
if height == 0 && parent_of_match {
|
||||||
// in case of height 0, we have a matched txid
|
// 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);
|
indexes.push(pos);
|
||||||
}
|
}
|
||||||
Ok(hash)
|
Ok(hash)
|
||||||
|
@ -344,11 +344,11 @@ impl PartialMerkleTree {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Helper method to produce SHA256D(left + right)
|
/// Helper method to produce SHA256D(left + right)
|
||||||
fn parent_hash(left: sha256d::Hash, right: sha256d::Hash) -> sha256d::Hash {
|
fn parent_hash(left: TxMerkleBranch, right: TxMerkleBranch) -> TxMerkleBranch {
|
||||||
let mut encoder = sha256d::Hash::engine();
|
let mut encoder = TxMerkleBranch::engine();
|
||||||
left.consensus_encode(&mut encoder).unwrap();
|
left.consensus_encode(&mut encoder).unwrap();
|
||||||
right.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 {
|
impl Decodable for PartialMerkleTree {
|
||||||
fn consensus_decode<D: io::Read>(mut d: D) -> Result<Self, encode::Error> {
|
fn consensus_decode<D: io::Read>(mut d: D) -> Result<Self, encode::Error> {
|
||||||
let num_transactions: u32 = Decodable::consensus_decode(&mut d)?;
|
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 bytes: Vec<u8> = Decodable::consensus_decode(d)?;
|
||||||
let mut bits: Vec<bool> = vec![false; bytes.len() * 8];
|
let mut bits: Vec<bool> = vec![false; bytes.len() * 8];
|
||||||
|
@ -496,9 +496,9 @@ impl Decodable for MerkleBlock {
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::cmp::min;
|
use std::cmp::min;
|
||||||
|
|
||||||
use hash_types::Txid;
|
use hashes::Hash;
|
||||||
use hashes::hex::{FromHex, ToHex};
|
use hashes::hex::{FromHex, ToHex};
|
||||||
use hashes::{sha256d, Hash};
|
use hash_types::{Txid, TxMerkleRoot, TxMerkleBranch};
|
||||||
use secp256k1::rand::prelude::*;
|
use secp256k1::rand::prelude::*;
|
||||||
|
|
||||||
use consensus::encode::{deserialize, serialize};
|
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
|
// Check that it has the same merkle root as the original, and a valid one
|
||||||
assert_eq!(merkle_root_1, merkle_root_2);
|
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!)
|
// check that it contains the matched transactions (in the same order!)
|
||||||
assert_eq!(match_txid1, match_txid2);
|
assert_eq!(match_txid1, match_txid2);
|
||||||
|
@ -701,7 +701,7 @@ mod tests {
|
||||||
let hashes = &mut self.hashes;
|
let hashes = &mut self.hashes;
|
||||||
let mut hash = hashes[n].into_inner();
|
let mut hash = hashes[n].into_inner();
|
||||||
hash[(bit >> 3) as usize] ^= 1 << (bit & 7);
|
hash[(bit >> 3) as usize] ^= 1 << (bit & 7);
|
||||||
hashes[n] = sha256d::Hash::from_slice(&hash).unwrap();
|
hashes[n] = TxMerkleBranch::from_slice(&hash).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue