use super::*;
impl<N: Network> Header<N> {
pub fn to_root(&self) -> Result<Field<N>> {
Ok(*self.to_tree()?.root())
}
pub fn to_path(&self, leaf: &HeaderLeaf<N>) -> Result<HeaderPath<N>> {
self.to_tree()?.prove(leaf.index() as usize, &leaf.to_bits_le())
}
pub fn to_leaf(&self, id: &Field<N>) -> Result<HeaderLeaf<N>> {
if id == &*self.previous_state_root {
Ok(HeaderLeaf::<N>::new(0, *self.previous_state_root))
}
else if id == &self.transactions_root {
Ok(HeaderLeaf::<N>::new(1, self.transactions_root))
}
else if id == &self.finalize_root {
Ok(HeaderLeaf::<N>::new(2, self.finalize_root))
}
else if id == &self.ratifications_root {
Ok(HeaderLeaf::<N>::new(3, self.ratifications_root))
}
else if id == &self.solutions_root {
Ok(HeaderLeaf::<N>::new(4, self.solutions_root))
}
else if id == &self.subdag_root {
Ok(HeaderLeaf::<N>::new(5, self.subdag_root))
}
else if id == &self.metadata.to_hash()? {
Ok(HeaderLeaf::<N>::new(7, *id))
}
else {
bail!("Non-existent block header leaf ID: {id}")
}
}
pub fn to_tree(&self) -> Result<HeaderTree<N>> {
let num_leaves = usize::pow(2, HEADER_DEPTH as u32);
let mut leaves: Vec<Vec<bool>> = Vec::with_capacity(num_leaves);
leaves.push(HeaderLeaf::<N>::new(0, *self.previous_state_root).to_bits_le());
leaves.push(HeaderLeaf::<N>::new(1, self.transactions_root).to_bits_le());
leaves.push(HeaderLeaf::<N>::new(2, self.finalize_root).to_bits_le());
leaves.push(HeaderLeaf::<N>::new(3, self.ratifications_root).to_bits_le());
leaves.push(HeaderLeaf::<N>::new(4, self.solutions_root).to_bits_le());
leaves.push(HeaderLeaf::<N>::new(5, self.subdag_root).to_bits_le());
leaves.push(HeaderLeaf::<N>::new(6, Field::zero()).to_bits_le());
leaves.push(HeaderLeaf::<N>::new(7, self.metadata.to_hash()?).to_bits_le());
ensure!(num_leaves == leaves.len(), "Incorrect number of leaves in the Merkle tree for the block header");
N::merkle_tree_bhp::<HEADER_DEPTH>(&leaves)
}
}
#[cfg(test)]
mod tests {
use super::*;
use console::network::Testnet3;
type CurrentNetwork = Testnet3;
const ITERATIONS: u64 = 1_000;
fn check_path<N: Network>(header_path: HeaderPath<N>, root: Field<N>, leaf: &HeaderLeaf<N>) -> Result<()> {
assert!(N::verify_merkle_path_bhp(&header_path, &root, &leaf.to_bits_le()));
let expected_bytes = header_path.to_bytes_le()?;
assert_eq!(header_path, HeaderPath::<N>::read_le(&expected_bytes[..])?);
assert!(HeaderPath::<N>::read_le(&expected_bytes[1..]).is_err());
Ok(())
}
#[test]
fn test_merkle() -> Result<()> {
let rng = &mut TestRng::default();
for _ in 0..ITERATIONS {
let coinbase_target = u64::rand(rng);
let proof_target = rng.gen_range(0..coinbase_target);
let header = Header::<CurrentNetwork>::from(
Into::<<CurrentNetwork as Network>::StateRoot>::into(Field::rand(rng)),
Field::rand(rng),
Field::rand(rng),
Field::rand(rng),
Field::rand(rng),
Field::rand(rng),
Metadata::new(
CurrentNetwork::ID,
u64::rand(rng),
u32::rand(rng),
u128::rand(rng),
u128::rand(rng),
coinbase_target,
proof_target,
u64::rand(rng),
rng.gen_range(0..i64::MAX),
rng.gen_range(0..i64::MAX),
)?,
)?;
let root = header.to_root()?;
let leaf = header.to_leaf(&*header.previous_state_root())?;
assert_eq!(leaf.index(), 0);
check_path(header.to_path(&leaf)?, root, &leaf)?;
let leaf = header.to_leaf(&header.transactions_root())?;
assert_eq!(leaf.index(), 1);
check_path(header.to_path(&leaf)?, root, &leaf)?;
let leaf = header.to_leaf(&header.finalize_root())?;
assert_eq!(leaf.index(), 2);
check_path(header.to_path(&leaf)?, root, &leaf)?;
let leaf = header.to_leaf(&header.ratifications_root())?;
assert_eq!(leaf.index(), 3);
check_path(header.to_path(&leaf)?, root, &leaf)?;
let leaf = header.to_leaf(&header.solutions_root())?;
assert_eq!(leaf.index(), 4);
check_path(header.to_path(&leaf)?, root, &leaf)?;
let leaf = header.to_leaf(&header.subdag_root())?;
assert_eq!(leaf.index(), 5);
check_path(header.to_path(&leaf)?, root, &leaf)?;
let leaf = header.to_leaf(&CurrentNetwork::hash_bhp1024(&header.metadata().to_bits_le())?)?;
assert_eq!(leaf.index(), 7);
check_path(header.to_path(&leaf)?, root, &leaf)?;
}
Ok(())
}
}