use crate::{Id32, MerkleTree};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SetBlockResult {
Ok,
Unknown,
HashFailed,
}
pub struct MerkleTreeState {
root: Id32,
num_blocks: u32,
num_pieces: u32,
piece_hashes: Option<Vec<Id32>>,
block_hashes: Vec<Option<Id32>>,
block_verified: Vec<bool>,
}
impl MerkleTreeState {
pub fn new(root: Id32, num_blocks: u32, num_pieces: u32) -> Self {
MerkleTreeState {
root,
num_blocks,
num_pieces,
piece_hashes: None,
block_hashes: vec![None; num_blocks as usize],
block_verified: vec![false; num_blocks as usize],
}
}
pub fn root(&self) -> Id32 {
self.root
}
pub fn num_pieces(&self) -> u32 {
self.num_pieces
}
pub fn num_blocks(&self) -> u32 {
self.num_blocks
}
pub fn has_piece_hash(&self, piece_index: u32) -> bool {
self.piece_hashes
.as_ref()
.is_some_and(|ph| (piece_index as usize) < ph.len())
}
pub fn set_piece_hashes(&mut self, hashes: Vec<Id32>) {
self.piece_hashes = Some(hashes);
}
pub fn set_piece_hashes_and_verify(
&mut self,
hashes: Vec<Id32>,
blocks_per_piece: u32,
) -> Vec<u32> {
self.piece_hashes = Some(hashes);
let mut verified_pieces = Vec::new();
for piece in 0..self.num_pieces {
let first_block = piece * blocks_per_piece;
let last_block = ((piece + 1) * blocks_per_piece).min(self.num_blocks);
let all_stored =
(first_block..last_block).all(|b| self.block_hashes[b as usize].is_some());
if !all_stored {
continue;
}
let block_slice: Vec<Id32> = (first_block..last_block)
.map(|b| self.block_hashes[b as usize].unwrap())
.collect();
let piece_hash = MerkleTree::root_from_hashes(&block_slice);
if let Some(ref ph) = self.piece_hashes {
if piece as usize >= ph.len() {
continue;
}
if piece_hash == ph[piece as usize] {
for b in first_block..last_block {
self.block_verified[b as usize] = true;
}
verified_pieces.push(piece);
}
}
}
verified_pieces
}
pub fn set_block_hash(&mut self, block_index: u32, hash: Id32) -> SetBlockResult {
if block_index >= self.num_blocks {
return SetBlockResult::HashFailed;
}
self.block_hashes[block_index as usize] = Some(hash);
let piece_hashes = match &self.piece_hashes {
Some(ph) => ph,
None => return SetBlockResult::Unknown,
};
let blocks_per_piece = if self.num_pieces > 0 {
self.num_blocks.div_ceil(self.num_pieces)
} else {
return SetBlockResult::Unknown;
};
let piece_index = block_index / blocks_per_piece;
if piece_index as usize >= piece_hashes.len() {
return SetBlockResult::HashFailed;
}
let first_block = piece_index * blocks_per_piece;
let last_block = ((piece_index + 1) * blocks_per_piece).min(self.num_blocks);
let all_present =
(first_block..last_block).all(|b| self.block_hashes[b as usize].is_some());
if !all_present {
return SetBlockResult::Unknown;
}
let block_slice: Vec<Id32> = (first_block..last_block)
.map(|b| self.block_hashes[b as usize].unwrap())
.collect();
let computed = MerkleTree::root_from_hashes(&block_slice);
if computed == piece_hashes[piece_index as usize] {
for b in first_block..last_block {
self.block_verified[b as usize] = true;
}
SetBlockResult::Ok
} else {
SetBlockResult::HashFailed
}
}
pub fn is_block_verified(&self, block_index: u32) -> bool {
self.block_verified
.get(block_index as usize)
.copied()
.unwrap_or(false)
}
pub fn piece_verified(&self, piece_index: u32, blocks_per_piece: u32) -> bool {
let first = piece_index * blocks_per_piece;
let last = ((piece_index + 1) * blocks_per_piece).min(self.num_blocks);
(first..last).all(|b| self.block_verified[b as usize])
}
pub fn piece_hashes(&self) -> Option<&[Id32]> {
self.piece_hashes.as_deref()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{Id32, MerkleTree, sha256};
fn make_block_hashes(n: usize) -> Vec<Id32> {
(0..n).map(|i| sha256(&[i as u8])).collect()
}
#[test]
fn new_state_has_no_piece_hashes() {
let state = MerkleTreeState::new(Id32::ZERO, 16, 1);
assert!(!state.has_piece_hash(0));
}
#[test]
fn set_piece_hashes_and_query() {
let block_hashes = make_block_hashes(4);
let tree = MerkleTree::from_leaves(&block_hashes);
let pieces = tree.piece_layer(2).to_vec();
let mut state = MerkleTreeState::new(tree.root(), 4, 2);
state.set_piece_hashes(pieces);
assert!(state.has_piece_hash(0));
assert!(state.has_piece_hash(1));
assert!(!state.has_piece_hash(2)); }
#[test]
fn set_block_hash_ok_when_all_siblings_present() {
let block_hashes = make_block_hashes(4);
let tree = MerkleTree::from_leaves(&block_hashes);
let pieces = tree.piece_layer(2).to_vec();
let mut state = MerkleTreeState::new(tree.root(), 4, 2);
state.set_piece_hashes(pieces);
let result = state.set_block_hash(0, block_hashes[0]);
assert_eq!(result, SetBlockResult::Unknown);
assert!(!state.is_block_verified(0));
let result = state.set_block_hash(1, block_hashes[1]);
assert_eq!(result, SetBlockResult::Ok);
assert!(state.is_block_verified(0));
assert!(state.is_block_verified(1));
}
#[test]
fn set_block_hash_unknown_no_piece_hashes() {
let mut state = MerkleTreeState::new(Id32::ZERO, 4, 2);
let hash = sha256(b"block0");
let result = state.set_block_hash(0, hash);
assert_eq!(result, SetBlockResult::Unknown);
assert!(!state.is_block_verified(0));
}
#[test]
fn set_block_hash_failed() {
let block_hashes = make_block_hashes(4);
let tree = MerkleTree::from_leaves(&block_hashes);
let pieces = tree.piece_layer(2).to_vec();
let mut state = MerkleTreeState::new(tree.root(), 4, 2);
state.set_piece_hashes(pieces);
state.set_block_hash(0, block_hashes[0]);
let wrong_hash = sha256(b"wrong");
let result = state.set_block_hash(1, wrong_hash);
assert_eq!(result, SetBlockResult::HashFailed);
}
#[test]
fn piece_verified_after_all_blocks() {
let block_hashes = make_block_hashes(4);
let tree = MerkleTree::from_leaves(&block_hashes);
let pieces = tree.piece_layer(2).to_vec();
let mut state = MerkleTreeState::new(tree.root(), 4, 2);
state.set_piece_hashes(pieces);
assert_eq!(
state.set_block_hash(0, block_hashes[0]),
SetBlockResult::Unknown
);
assert!(!state.piece_verified(0, 2)); assert_eq!(state.set_block_hash(1, block_hashes[1]), SetBlockResult::Ok);
assert!(state.piece_verified(0, 2)); }
#[test]
fn deferred_verification_unknown_then_ok() {
let block_hashes = make_block_hashes(4);
let tree = MerkleTree::from_leaves(&block_hashes);
let pieces = tree.piece_layer(2).to_vec();
let mut state = MerkleTreeState::new(tree.root(), 4, 2);
assert_eq!(
state.set_block_hash(0, block_hashes[0]),
SetBlockResult::Unknown
);
assert_eq!(
state.set_block_hash(1, block_hashes[1]),
SetBlockResult::Unknown
);
let verified = state.set_piece_hashes_and_verify(pieces, 2);
assert_eq!(verified.len(), 1);
assert!(verified.contains(&0u32)); assert!(state.is_block_verified(0));
assert!(state.is_block_verified(1));
}
}