use bitcoin::{
consensus,
hashes::{sha256d::Hash as DHash, Hash},
Transaction,
};
use tracing::error;
pub fn merkle_root_from_path<T: AsRef<[u8]>>(
coinbase_tx_prefix: &[u8],
coinbase_tx_suffix: &[u8],
extranonce: &[u8],
path: &[T],
) -> Option<Vec<u8>> {
let mut coinbase =
Vec::with_capacity(coinbase_tx_prefix.len() + coinbase_tx_suffix.len() + extranonce.len());
coinbase.extend_from_slice(coinbase_tx_prefix);
coinbase.extend_from_slice(extranonce);
coinbase.extend_from_slice(coinbase_tx_suffix);
let coinbase: Transaction = match consensus::deserialize(&coinbase[..]) {
Ok(trans) => trans,
Err(e) => {
error!("ERROR: {}", e);
dbg!(e);
return None;
}
};
let coinbase_id: [u8; 32] = *coinbase.compute_txid().as_ref();
Some(merkle_root_from_path_(coinbase_id, path).to_vec())
}
pub fn merkle_root_from_path_<T: AsRef<[u8]>>(coinbase_id: [u8; 32], path: &[T]) -> [u8; 32] {
match path.len() {
0 => coinbase_id,
_ => reduce_path(coinbase_id, path),
}
}
fn reduce_path<T: AsRef<[u8]>>(coinbase_id: [u8; 32], path: &[T]) -> [u8; 32] {
let mut root = coinbase_id;
for node in path {
let to_hash = [&root[..], node.as_ref()].concat();
let hash = DHash::hash(&to_hash);
root = *hash.as_ref();
}
root
}