irontide_core/
merkle_state.rs1#![allow(
2 clippy::cast_possible_truncation,
3 reason = "M175: BEP 52 Merkle tree — proof depth bounded by tree height (≤ 32 for any realistic file)"
4)]
5
6use crate::{Id32, MerkleTree};
13
14#[derive(Debug, Clone, Copy, PartialEq, Eq)]
16pub enum SetBlockResult {
17 Ok,
19 Unknown,
22 HashFailed,
24}
25
26pub struct MerkleTreeState {
32 root: Id32,
34 num_blocks: u32,
36 num_pieces: u32,
38 piece_hashes: Option<Vec<Id32>>,
40 block_hashes: Vec<Option<Id32>>,
42 block_verified: Vec<bool>,
45}
46
47impl MerkleTreeState {
48 #[must_use]
50 pub fn new(root: Id32, num_blocks: u32, num_pieces: u32) -> Self {
51 Self {
52 root,
53 num_blocks,
54 num_pieces,
55 piece_hashes: None,
56 block_hashes: vec![None; num_blocks as usize],
57 block_verified: vec![false; num_blocks as usize],
58 }
59 }
60
61 #[must_use]
63 pub fn root(&self) -> Id32 {
64 self.root
65 }
66
67 #[must_use]
69 pub fn num_pieces(&self) -> u32 {
70 self.num_pieces
71 }
72
73 #[must_use]
75 pub fn num_blocks(&self) -> u32 {
76 self.num_blocks
77 }
78
79 #[must_use]
81 pub fn has_piece_hash(&self, piece_index: u32) -> bool {
82 self.piece_hashes
83 .as_ref()
84 .is_some_and(|ph| (piece_index as usize) < ph.len())
85 }
86
87 pub fn set_piece_hashes(&mut self, hashes: Vec<Id32>) {
89 self.piece_hashes = Some(hashes);
90 }
91
92 pub fn set_piece_hashes_and_verify(
96 &mut self,
97 hashes: Vec<Id32>,
98 blocks_per_piece: u32,
99 ) -> Vec<u32> {
100 self.piece_hashes = Some(hashes);
101
102 let mut verified_pieces = Vec::new();
103
104 for piece in 0..self.num_pieces {
105 let first_block = piece * blocks_per_piece;
106 let last_block = ((piece + 1) * blocks_per_piece).min(self.num_blocks);
107
108 let all_stored =
110 (first_block..last_block).all(|b| self.block_hashes[b as usize].is_some());
111
112 if !all_stored {
113 continue;
114 }
115
116 let block_slice: Vec<Id32> = (first_block..last_block)
118 .map(|b| self.block_hashes[b as usize].unwrap())
119 .collect();
120
121 let piece_hash = MerkleTree::root_from_hashes(&block_slice);
122 if let Some(ref ph) = self.piece_hashes {
123 if piece as usize >= ph.len() {
124 continue;
125 }
126 if piece_hash == ph[piece as usize] {
127 for b in first_block..last_block {
128 self.block_verified[b as usize] = true;
129 }
130 verified_pieces.push(piece);
131 }
132 }
133 }
134
135 verified_pieces
136 }
137
138 pub fn set_block_hash(&mut self, block_index: u32, hash: Id32) -> SetBlockResult {
144 if block_index >= self.num_blocks {
145 return SetBlockResult::HashFailed;
146 }
147
148 self.block_hashes[block_index as usize] = Some(hash);
150
151 let Some(piece_hashes) = &self.piece_hashes else {
152 return SetBlockResult::Unknown;
153 };
154
155 let blocks_per_piece = if self.num_pieces > 0 {
157 self.num_blocks.div_ceil(self.num_pieces)
158 } else {
159 return SetBlockResult::Unknown;
160 };
161 let piece_index = block_index / blocks_per_piece;
162
163 if piece_index as usize >= piece_hashes.len() {
164 return SetBlockResult::HashFailed;
165 }
166
167 let first_block = piece_index * blocks_per_piece;
169 let last_block = ((piece_index + 1) * blocks_per_piece).min(self.num_blocks);
170
171 let all_present =
172 (first_block..last_block).all(|b| self.block_hashes[b as usize].is_some());
173
174 if !all_present {
175 return SetBlockResult::Unknown;
178 }
179
180 let block_slice: Vec<Id32> = (first_block..last_block)
182 .map(|b| self.block_hashes[b as usize].unwrap())
183 .collect();
184
185 let computed = MerkleTree::root_from_hashes(&block_slice);
186 if computed == piece_hashes[piece_index as usize] {
187 for b in first_block..last_block {
188 self.block_verified[b as usize] = true;
189 }
190 SetBlockResult::Ok
191 } else {
192 SetBlockResult::HashFailed
193 }
194 }
195
196 #[must_use]
198 pub fn is_block_verified(&self, block_index: u32) -> bool {
199 self.block_verified
200 .get(block_index as usize)
201 .copied()
202 .unwrap_or(false)
203 }
204
205 #[must_use]
207 pub fn piece_verified(&self, piece_index: u32, blocks_per_piece: u32) -> bool {
208 let first = piece_index * blocks_per_piece;
209 let last = ((piece_index + 1) * blocks_per_piece).min(self.num_blocks);
210 (first..last).all(|b| self.block_verified[b as usize])
211 }
212
213 #[must_use]
215 pub fn piece_hashes(&self) -> Option<&[Id32]> {
216 self.piece_hashes.as_deref()
217 }
218}
219
220#[cfg(test)]
221mod tests {
222 use super::*;
223 use crate::{Id32, MerkleTree, sha256};
224
225 fn make_block_hashes(n: usize) -> Vec<Id32> {
226 (0..n).map(|i| sha256(&[i as u8])).collect()
227 }
228
229 #[test]
230 fn new_state_has_no_piece_hashes() {
231 let state = MerkleTreeState::new(Id32::ZERO, 16, 1);
232 assert!(!state.has_piece_hash(0));
233 }
234
235 #[test]
236 fn set_piece_hashes_and_query() {
237 let block_hashes = make_block_hashes(4);
238 let tree = MerkleTree::from_leaves(&block_hashes);
239 let pieces = tree.piece_layer(2).to_vec(); let mut state = MerkleTreeState::new(tree.root(), 4, 2);
242 state.set_piece_hashes(pieces);
243 assert!(state.has_piece_hash(0));
244 assert!(state.has_piece_hash(1));
245 assert!(!state.has_piece_hash(2)); }
247
248 #[test]
249 fn set_block_hash_ok_when_all_siblings_present() {
250 let block_hashes = make_block_hashes(4);
252 let tree = MerkleTree::from_leaves(&block_hashes);
253 let pieces = tree.piece_layer(2).to_vec();
254
255 let mut state = MerkleTreeState::new(tree.root(), 4, 2);
256 state.set_piece_hashes(pieces);
257
258 let result = state.set_block_hash(0, block_hashes[0]);
260 assert_eq!(result, SetBlockResult::Unknown);
261 assert!(!state.is_block_verified(0));
262
263 let result = state.set_block_hash(1, block_hashes[1]);
265 assert_eq!(result, SetBlockResult::Ok);
266 assert!(state.is_block_verified(0));
267 assert!(state.is_block_verified(1));
268 }
269
270 #[test]
271 fn set_block_hash_unknown_no_piece_hashes() {
272 let mut state = MerkleTreeState::new(Id32::ZERO, 4, 2);
274 let hash = sha256(b"block0");
275 let result = state.set_block_hash(0, hash);
276 assert_eq!(result, SetBlockResult::Unknown);
277 assert!(!state.is_block_verified(0));
278 }
279
280 #[test]
281 fn set_block_hash_failed() {
282 let block_hashes = make_block_hashes(4);
283 let tree = MerkleTree::from_leaves(&block_hashes);
284 let pieces = tree.piece_layer(2).to_vec();
285
286 let mut state = MerkleTreeState::new(tree.root(), 4, 2);
287 state.set_piece_hashes(pieces);
288
289 state.set_block_hash(0, block_hashes[0]);
291 let wrong_hash = sha256(b"wrong");
293 let result = state.set_block_hash(1, wrong_hash);
294 assert_eq!(result, SetBlockResult::HashFailed);
295 }
296
297 #[test]
298 fn piece_verified_after_all_blocks() {
299 let block_hashes = make_block_hashes(4);
300 let tree = MerkleTree::from_leaves(&block_hashes);
301 let pieces = tree.piece_layer(2).to_vec();
302
303 let mut state = MerkleTreeState::new(tree.root(), 4, 2);
304 state.set_piece_hashes(pieces);
305
306 assert_eq!(
308 state.set_block_hash(0, block_hashes[0]),
309 SetBlockResult::Unknown
310 );
311 assert!(!state.piece_verified(0, 2)); assert_eq!(state.set_block_hash(1, block_hashes[1]), SetBlockResult::Ok);
313 assert!(state.piece_verified(0, 2)); }
315
316 #[test]
317 fn deferred_verification_unknown_then_ok() {
318 let block_hashes = make_block_hashes(4);
320 let tree = MerkleTree::from_leaves(&block_hashes);
321 let pieces = tree.piece_layer(2).to_vec();
322
323 let mut state = MerkleTreeState::new(tree.root(), 4, 2);
324
325 assert_eq!(
327 state.set_block_hash(0, block_hashes[0]),
328 SetBlockResult::Unknown
329 );
330 assert_eq!(
331 state.set_block_hash(1, block_hashes[1]),
332 SetBlockResult::Unknown
333 );
334
335 let verified = state.set_piece_hashes_and_verify(pieces, 2);
337 assert_eq!(verified.len(), 1);
338 assert!(verified.contains(&0u32)); assert!(state.is_block_verified(0));
340 assert!(state.is_block_verified(1));
341 }
342}