use core::iter;
use crate::prelude::*;
use crate::io;
use core::cmp::min;
use crate::hashes::Hash;
use crate::consensus::encode::Encodable;
pub fn bitcoin_merkle_root_inline<T>(hashes: &mut [T]) -> Option<T>
where
T: Hash + Encodable,
<T as Hash>::Engine: io::Write,
{
match hashes.len() {
0 => None,
1 => Some(hashes[0]),
_ => Some(merkle_root_r(hashes)),
}
}
pub fn bitcoin_merkle_root<T, I>(mut hashes: I) -> Option<T>
where
T: Hash + Encodable,
<T as Hash>::Engine: io::Write,
I: Iterator<Item=T>,
{
let first = hashes.next()?;
let second = match hashes.next() {
Some(second) => second,
None => return Some(first),
};
let mut hashes = iter::once(first).chain(iter::once(second)).chain(hashes);
let (min, max) = hashes.size_hint();
let mut alloc = Vec::with_capacity(max.unwrap_or(min) / 2 + 1);
while let Some(hash1) = hashes.next() {
let hash2 = hashes.next().unwrap_or(hash1);
let mut encoder = T::engine();
hash1.consensus_encode(&mut encoder).expect("in-memory writers don't error");
hash2.consensus_encode(&mut encoder).expect("in-memory writers don't error");
alloc.push(T::from_engine(encoder));
}
Some(merkle_root_r(&mut alloc))
}
fn merkle_root_r<T>(hashes: &mut [T]) -> T
where
T: Hash + Encodable,
<T as Hash>::Engine: io::Write,
{
if hashes.len() == 1 {
return hashes[0]
}
for idx in 0..((hashes.len() + 1) / 2) {
let idx1 = 2 * idx;
let idx2 = min(idx1 + 1, hashes.len() - 1);
let mut encoder = T::engine();
hashes[idx1].consensus_encode(&mut encoder).expect("in-memory writers don't error");
hashes[idx2].consensus_encode(&mut encoder).expect("in-memory writers don't error");
hashes[idx] = T::from_engine(encoder);
}
let half_len = hashes.len() / 2 + hashes.len() % 2;
merkle_root_r(&mut hashes[0..half_len])
}
#[cfg(test)]
mod tests {
use crate::consensus::encode::deserialize;
use crate::hashes::sha256d;
use crate::blockdata::block::Block;
use super::*;
#[test]
fn both_merkle_root_functions_return_the_same_result() {
let segwit_block = include_bytes!("../../test_data/testnet_block_000000000000045e0b1660b6445b5e5c5ab63c9a4f956be7e1e69be04fa4497b.raw");
let block: Block = deserialize(&segwit_block[..]).expect("Failed to deserialize block");
assert!(block.check_merkle_root()); let hashes_iter = block.txdata.iter().map(|obj| obj.txid().as_hash());
let mut hashes_array: [sha256d::Hash; 15] = [Hash::all_zeros(); 15];
for (i, hash) in hashes_iter.clone().enumerate() {
hashes_array[i] = hash;
}
let from_iter = bitcoin_merkle_root(hashes_iter);
let from_array = bitcoin_merkle_root_inline(&mut hashes_array);
assert_eq!(from_iter, from_array);
}
}