use blvm_protocol::{BlockHeader, Hash, Transaction};
use sha2::{Digest, Sha256};
#[cfg(any(feature = "production", feature = "profile"))]
pub fn calculate_wtxid(tx: &Transaction, witnesses: Option<&[Vec<Vec<u8>>]>) -> Hash {
use blvm_protocol::block::calculate_tx_id;
let txid = calculate_tx_id(tx);
let has_witness = witnesses
.map(|w| w.iter().any(|s| !s.is_empty()))
.unwrap_or(false);
if !has_witness {
return txid;
}
let witnesses = witnesses.expect("checked above");
let serialized = segwit_serialize_for_wtxid(tx, witnesses);
let first = Sha256::digest(&serialized);
let second = Sha256::digest(first);
let mut out = [0u8; 32];
out.copy_from_slice(&second);
out
}
#[cfg(any(feature = "production", feature = "profile"))]
fn segwit_serialize_for_wtxid(tx: &Transaction, witnesses: &[Vec<Vec<u8>>]) -> Vec<u8> {
use blvm_protocol::serialization::varint::encode_varint;
let mut out = Vec::new();
out.extend_from_slice(&(tx.version as u32).to_le_bytes());
out.push(0x00);
out.push(0x01);
out.extend_from_slice(&encode_varint(tx.inputs.len() as u64));
for input in &tx.inputs {
out.extend_from_slice(&input.prevout.hash);
out.extend_from_slice(&input.prevout.index.to_le_bytes());
out.extend_from_slice(&encode_varint(input.script_sig.len() as u64));
out.extend_from_slice(&input.script_sig);
out.extend_from_slice(&(input.sequence as u32).to_le_bytes());
}
out.extend_from_slice(&encode_varint(tx.outputs.len() as u64));
for output in &tx.outputs {
out.extend_from_slice(&(output.value as u64).to_le_bytes());
out.extend_from_slice(&encode_varint(output.script_pubkey.len() as u64));
out.extend_from_slice(&output.script_pubkey);
}
out.extend_from_slice(&(tx.lock_time as u32).to_le_bytes());
for stack in witnesses {
out.extend_from_slice(&encode_varint(stack.len() as u64));
for elem in stack {
out.extend_from_slice(&encode_varint(elem.len() as u64));
out.extend_from_slice(elem);
}
}
out
}
#[cfg(not(any(feature = "production", feature = "profile")))]
pub fn calculate_wtxid(_tx: &Transaction, _witnesses: Option<&[Vec<Vec<u8>>]>) -> Hash {
use blvm_protocol::block::calculate_tx_id;
calculate_tx_id(_tx)
}
pub fn calculate_txid(tx: &Transaction) -> Hash {
let serialized = bincode::serialize(tx).unwrap_or_default();
let mut hasher = Sha256::new();
hasher.update(&serialized);
let first = hasher.finalize();
let mut hasher2 = Sha256::new();
hasher2.update(first);
let final_bytes = hasher2.finalize();
let mut out = [0u8; 32];
out.copy_from_slice(&final_bytes);
out
}
pub fn calculate_block_header_hash(header: &BlockHeader) -> Hash {
let serialized = bincode::serialize(header).unwrap_or_default();
let mut hasher = Sha256::new();
hasher.update(&serialized);
let first = hasher.finalize();
let mut hasher2 = Sha256::new();
hasher2.update(first);
let final_bytes = hasher2.finalize();
let mut out = [0u8; 32];
out.copy_from_slice(&final_bytes);
out
}