1use alloc::{
2 collections::{BTreeMap, BTreeSet},
3 string::ToString,
4 vec::Vec,
5};
6
7use super::{MmrDelta, MmrPath, MmrProof};
8use crate::{
9 Word,
10 hash::poseidon2::Poseidon2,
11 merkle::{
12 InnerNodeInfo, MerklePath,
13 mmr::{InOrderIndex, MmrError, MmrPeaks, forest::Forest},
14 },
15 utils::{ByteReader, ByteWriter, Deserializable, Serializable},
16};
17
18type NodeMap = BTreeMap<InOrderIndex, Word>;
22
23#[derive(Debug, Clone, PartialEq, Eq)]
30pub struct PartialMmr {
31 pub(crate) forest: Forest,
42
43 pub(crate) peaks: Vec<Word>,
55
56 pub(crate) nodes: NodeMap,
67
68 pub(crate) tracked_leaves: BTreeSet<usize>,
70}
71
72impl Default for PartialMmr {
73 fn default() -> Self {
75 let forest = Forest::empty();
76 let peaks = Vec::new();
77 let nodes = BTreeMap::new();
78 let tracked_leaves = BTreeSet::new();
79
80 Self { forest, peaks, nodes, tracked_leaves }
81 }
82}
83
84impl PartialMmr {
85 const TRACKED_LEAVES_MARKER: u8 = 0xff;
88
89 pub fn from_peaks(peaks: MmrPeaks) -> Self {
94 let forest = peaks.forest();
95 let peaks = peaks.into();
96 let nodes = BTreeMap::new();
97 let tracked_leaves = BTreeSet::new();
98
99 Self { forest, peaks, nodes, tracked_leaves }
100 }
101
102 pub fn from_parts(
116 peaks: MmrPeaks,
117 nodes: NodeMap,
118 tracked_leaves: BTreeSet<usize>,
119 ) -> Result<Self, MmrError> {
120 let forest = peaks.forest();
121 let num_leaves = forest.num_leaves();
122
123 for &pos in &tracked_leaves {
125 if pos >= num_leaves {
126 return Err(MmrError::InconsistentPartialMmr(format!(
127 "tracked leaf position {pos} is out of bounds (forest has {num_leaves} leaves)"
128 )));
129 }
130 let leaf_idx = InOrderIndex::from_leaf_pos(pos);
131 if !nodes.contains_key(&leaf_idx) {
132 return Err(MmrError::InconsistentPartialMmr(format!(
133 "tracked leaf at position {pos} has no value in nodes"
134 )));
135 }
136 }
137
138 for idx in nodes.keys() {
141 if !forest.is_valid_in_order_index(idx) {
142 return Err(MmrError::InconsistentPartialMmr(format!(
143 "node index {} is not a valid index in the forest",
144 idx.inner()
145 )));
146 }
147 }
148
149 let peaks = peaks.into();
150 let partial_mmr = Self { forest, peaks, nodes, tracked_leaves };
151
152 for &pos in &partial_mmr.tracked_leaves {
154 match partial_mmr.open(pos) {
155 Ok(Some(_)) => {},
156 Ok(None) => {
157 return Err(MmrError::InconsistentPartialMmr(format!(
158 "tracked leaf at position {pos} has no authentication path"
159 )));
160 },
161 Err(err) => return Err(err),
162 }
163 }
164
165 Ok(partial_mmr)
166 }
167
168 pub fn from_parts_unchecked(
178 peaks: MmrPeaks,
179 nodes: NodeMap,
180 tracked_leaves: BTreeSet<usize>,
181 ) -> Self {
182 let forest = peaks.forest();
183 let peaks = peaks.into();
184
185 Self { forest, peaks, nodes, tracked_leaves }
186 }
187
188 pub fn forest(&self) -> Forest {
196 self.forest
197 }
198
199 pub fn num_leaves(&self) -> usize {
201 self.forest.num_leaves()
202 }
203
204 pub fn peaks(&self) -> MmrPeaks {
206 MmrPeaks::new(self.forest, self.peaks.clone()).expect("invalid MMR peaks")
209 }
210
211 pub fn is_tracked(&self, pos: usize) -> bool {
214 self.tracked_leaves.contains(&pos)
215 }
216
217 pub fn get(&self, pos: usize) -> Option<Word> {
219 if !self.tracked_leaves.contains(&pos) {
220 return None;
221 }
222 let leaf_idx = InOrderIndex::from_leaf_pos(pos);
223 self.nodes.get(&leaf_idx).copied()
224 }
225
226 pub fn leaves(&self) -> impl Iterator<Item = (usize, Word)> + '_ {
228 self.tracked_leaves.iter().map(|&pos| {
229 let leaf_idx = InOrderIndex::from_leaf_pos(pos);
230 let leaf = *self.nodes.get(&leaf_idx).expect("tracked leaf must have value in nodes");
231 (pos, leaf)
232 })
233 }
234
235 pub fn open(&self, pos: usize) -> Result<Option<MmrProof>, MmrError> {
245 let tree_bit = self
246 .forest
247 .leaf_to_corresponding_tree(pos)
248 .ok_or(MmrError::PositionNotFound(pos))?;
249
250 if !self.tracked_leaves.contains(&pos) {
252 return Ok(None);
253 }
254
255 let leaf_idx = InOrderIndex::from_leaf_pos(pos);
257 let leaf = *self.nodes.get(&leaf_idx).expect("tracked leaf must have value in nodes");
258
259 let depth = tree_bit as usize;
261 let mut nodes = Vec::with_capacity(depth);
262 let mut idx = leaf_idx;
263
264 for _ in 0..depth {
265 let Some(node) = self.nodes.get(&idx.sibling()) else {
266 return Err(MmrError::InconsistentPartialMmr(format!(
267 "missing sibling for tracked leaf at position {pos}"
268 )));
269 };
270 nodes.push(*node);
271 idx = idx.parent();
272 }
273
274 let path = MmrPath::new(self.forest, pos, MerklePath::new(nodes));
275 Ok(Some(MmrProof::new(path, leaf)))
276 }
277
278 pub fn nodes(&self) -> impl Iterator<Item = (&InOrderIndex, &Word)> {
283 self.nodes.iter()
284 }
285
286 pub fn inner_nodes<'a, I: Iterator<Item = (usize, Word)> + 'a>(
291 &'a self,
292 mut leaves: I,
293 ) -> impl Iterator<Item = InnerNodeInfo> + 'a {
294 let stack = if let Some((pos, leaf)) = leaves.next() {
295 let idx = InOrderIndex::from_leaf_pos(pos);
296 vec![(idx, leaf)]
297 } else {
298 Vec::new()
299 };
300
301 InnerNodeIterator {
302 nodes: &self.nodes,
303 leaves,
304 stack,
305 seen_nodes: BTreeSet::new(),
306 }
307 }
308
309 pub fn add(&mut self, leaf: Word, track: bool) -> Result<Vec<(InOrderIndex, Word)>, MmrError> {
320 self.forest.append_leaf()?;
322 let num_merges = self.forest.smallest_tree_height_unchecked();
326 let mut new_nodes = Vec::with_capacity(num_merges + 1);
327
328 let leaf_pos = self.forest.num_leaves() - 1;
330 let leaf_idx = InOrderIndex::from_leaf_pos(leaf_pos);
331 if track {
332 self.tracked_leaves.insert(leaf_pos);
333 self.nodes.insert(leaf_idx, leaf);
334 new_nodes.push((leaf_idx, leaf));
335 }
336
337 let peak = if num_merges == 0 {
338 leaf
339 } else {
340 let mut track_right = track;
341 let prev_last_pos = self.forest.num_leaves() - 2;
344 let mut track_left = self.tracked_leaves.contains(&prev_last_pos);
345
346 let mut right = leaf;
347 let mut right_idx = self.forest.rightmost_in_order_index_unchecked();
348
349 for _ in 0..num_merges {
350 let left = self.peaks.pop().expect("Missing peak");
351 let left_idx = right_idx.sibling();
352
353 if track_right {
354 let old = self.nodes.insert(left_idx, left);
355 debug_assert!(
358 old.is_none() || old == Some(left),
359 "Idx {left_idx:?} already contained a different element {old:?}",
360 );
361 if old.is_none() {
362 new_nodes.push((left_idx, left));
363 }
364 };
365 if track_left {
366 let old = self.nodes.insert(right_idx, right);
367 debug_assert!(
368 old.is_none() || old == Some(right),
369 "Idx {right_idx:?} already contained a different element {old:?}",
370 );
371 if old.is_none() {
372 new_nodes.push((right_idx, right));
373 }
374 };
375
376 right_idx = right_idx.parent();
381
382 right = Poseidon2::merge(&[left, right]);
385
386 track_right = track_right || track_left;
390
391 track_left = self.is_tracked_node(right_idx.sibling());
394 }
395 right
396 };
397
398 self.peaks.push(peak);
399
400 Ok(new_nodes)
401 }
402
403 pub fn track(
413 &mut self,
414 leaf_pos: usize,
415 leaf: Word,
416 path: &MerklePath,
417 ) -> Result<(), MmrError> {
418 let path_depth = path.depth();
421 let tree_leaves =
422 1usize.checked_shl(path_depth as u32).ok_or(MmrError::UnknownPeak(path_depth))?;
423 let tree = Forest::new(tree_leaves).map_err(|_| MmrError::UnknownPeak(path_depth))?;
424 if (tree & self.forest).is_empty() {
425 return Err(MmrError::UnknownPeak(path_depth));
426 };
427
428 let owning_tree = self
432 .forest
433 .leaf_to_corresponding_tree(leaf_pos)
434 .ok_or(MmrError::PositionNotFound(leaf_pos))?;
435 if owning_tree != u32::from(path_depth) {
436 return Err(MmrError::PositionNotFound(leaf_pos));
437 }
438
439 let target_forest = self.forest ^ (self.forest & tree.all_smaller_trees_unchecked());
442 let peak_pos = target_forest.num_trees() - 1;
443
444 let path_idx = leaf_pos - (target_forest ^ tree).num_leaves();
446
447 let computed = path
450 .compute_root(path_idx as u64, leaf)
451 .map_err(MmrError::MerkleRootComputationFailed)?;
452 if self.peaks[peak_pos] != computed {
453 return Err(MmrError::PeakPathMismatch);
454 }
455
456 self.tracked_leaves.insert(leaf_pos);
458
459 let leaf_idx = InOrderIndex::from_leaf_pos(leaf_pos);
461 self.nodes.insert(leaf_idx, leaf);
462
463 let mut idx = leaf_idx;
465 for node in path.nodes() {
466 self.nodes.insert(idx.sibling(), *node);
467 idx = idx.parent();
468 }
469
470 Ok(())
471 }
472
473 pub fn untrack(&mut self, leaf_pos: usize) -> Vec<(InOrderIndex, Word)> {
482 self.tracked_leaves.remove(&leaf_pos);
484
485 let mut idx = InOrderIndex::from_leaf_pos(leaf_pos);
486 let mut removed = Vec::new();
487
488 let sibling_idx = idx.sibling();
491 let sibling_pos = sibling_idx.to_leaf_pos().expect("sibling of a leaf is always a leaf");
492 if self.tracked_leaves.contains(&sibling_pos) {
493 return removed;
496 }
497
498 let Some(rel_pos) = self.forest.leaf_relative_position(leaf_pos) else {
499 return removed;
501 };
502 let tree_start = leaf_pos - rel_pos;
503
504 if let Some(word) = self.nodes.remove(&idx) {
506 removed.push((idx, word));
507 }
508
509 loop {
511 let level = idx.level() as usize;
514 let subtree_size = 1usize << level;
515 let subtree_start_rel = (rel_pos >> level) << level;
516 let subtree_start = tree_start + subtree_start_rel;
517 let subtree_end = subtree_start + subtree_size;
518 if self.tracked_leaves.range(subtree_start..subtree_end).next().is_some() {
519 break;
520 }
521
522 let sibling_idx = idx.sibling();
523
524 let Some(word) = self.nodes.remove(&sibling_idx) else {
526 break;
527 };
528 removed.push((sibling_idx, word));
529
530 if self.nodes.contains_key(&idx) {
532 break;
533 }
534 idx = idx.parent();
535 }
536
537 removed
538 }
539
540 pub fn apply(&mut self, delta: MmrDelta) -> Result<Vec<(InOrderIndex, Word)>, MmrError> {
543 if delta.forest < self.forest {
544 return Err(MmrError::InvalidPeaks(format!(
545 "forest of mmr delta {} is less than current forest {}",
546 delta.forest, self.forest
547 )));
548 }
549
550 let mut inserted_nodes = Vec::new();
551
552 if delta.forest == self.forest {
553 if !delta.data.is_empty() {
554 return Err(MmrError::InvalidUpdate);
555 }
556
557 return Ok(inserted_nodes);
558 }
559
560 let changes = self.forest.num_leaves() ^ delta.forest.num_leaves();
562 let largest = super::forest::largest_tree_from_mask(changes);
565 let trees_to_merge = self.forest & largest.all_smaller_trees_unchecked();
567
568 let (merge_count, new_peaks) = if !trees_to_merge.is_empty() {
570 let depth = largest.smallest_tree_height_unchecked();
571 let skipped = trees_to_merge.smallest_tree_height_unchecked();
573 let computed = trees_to_merge.num_trees() - 1;
574 let merge_count = depth - skipped - computed;
575
576 let new_peaks = delta.forest & largest.all_smaller_trees_unchecked();
577
578 (merge_count, new_peaks)
579 } else {
580 let new_peaks = Forest::new(changes)
581 .expect("changes must be a valid forest under apply invariants");
582 (0, new_peaks)
583 };
584
585 if delta.data.len() != merge_count + new_peaks.num_trees() {
587 return Err(MmrError::InvalidUpdate);
588 }
589
590 let mut update_count = 0;
592
593 if !trees_to_merge.is_empty() {
594 let mut peak_idx = self.forest.root_in_order_index_unchecked();
596
597 self.peaks.reverse();
599
600 let mut track = false;
601
602 let mut peak_count = 0;
603 let mut target = trees_to_merge.smallest_tree_unchecked();
604 let mut new = delta.data[0];
605 update_count += 1;
606
607 while target < largest {
608 if !track {
611 track = self.is_tracked_node(peak_idx);
612 }
613
614 let (left, right) = if !(target & trees_to_merge).is_empty() {
617 let peak = self.peaks[peak_count];
618 let sibling_idx = peak_idx.sibling();
619
620 if self.is_tracked_node(sibling_idx) {
623 self.nodes.insert(peak_idx, new);
624 inserted_nodes.push((peak_idx, new));
625 }
626 peak_count += 1;
627 (peak, new)
628 } else {
629 let update = delta.data[update_count];
630 update_count += 1;
631 (new, update)
632 };
633
634 if track {
635 let sibling_idx = peak_idx.sibling();
636 if peak_idx.is_left_child() {
637 self.nodes.insert(sibling_idx, right);
638 inserted_nodes.push((sibling_idx, right));
639 } else {
640 self.nodes.insert(sibling_idx, left);
641 inserted_nodes.push((sibling_idx, left));
642 }
643 }
644
645 peak_idx = peak_idx.parent();
646 new = Poseidon2::merge(&[left, right]);
647 target = target.next_larger_tree()?;
648 }
649
650 debug_assert!(peak_count == trees_to_merge.num_trees());
651
652 self.peaks.reverse();
654 self.peaks.truncate(self.peaks.len() - peak_count);
656 self.peaks.push(new);
658 }
659
660 self.peaks.extend_from_slice(&delta.data[update_count..]);
664 self.forest = delta.forest;
665
666 debug_assert!(self.peaks.len() == self.forest.num_trees());
667
668 Ok(inserted_nodes)
669 }
670
671 fn is_tracked_node(&self, node_index: InOrderIndex) -> bool {
677 if let Some(leaf_pos) = node_index.to_leaf_pos() {
678 self.tracked_leaves.contains(&leaf_pos)
680 } else {
681 let left_child = node_index.left_child();
682 let right_child = node_index.right_child();
683 self.nodes.contains_key(&left_child) | self.nodes.contains_key(&right_child)
684 }
685 }
686}
687
688impl From<MmrPeaks> for PartialMmr {
692 fn from(peaks: MmrPeaks) -> Self {
693 Self::from_peaks(peaks)
694 }
695}
696
697impl From<PartialMmr> for MmrPeaks {
698 fn from(partial_mmr: PartialMmr) -> Self {
699 MmrPeaks::new(partial_mmr.forest, partial_mmr.peaks).unwrap()
702 }
703}
704
705impl From<&MmrPeaks> for PartialMmr {
706 fn from(peaks: &MmrPeaks) -> Self {
707 Self::from_peaks(peaks.clone())
708 }
709}
710
711impl From<&PartialMmr> for MmrPeaks {
712 fn from(partial_mmr: &PartialMmr) -> Self {
713 MmrPeaks::new(partial_mmr.forest, partial_mmr.peaks.clone()).unwrap()
716 }
717}
718
719pub struct InnerNodeIterator<'a, I: Iterator<Item = (usize, Word)>> {
724 nodes: &'a NodeMap,
725 leaves: I,
726 stack: Vec<(InOrderIndex, Word)>,
727 seen_nodes: BTreeSet<InOrderIndex>,
728}
729
730impl<I: Iterator<Item = (usize, Word)>> Iterator for InnerNodeIterator<'_, I> {
731 type Item = InnerNodeInfo;
732
733 fn next(&mut self) -> Option<Self::Item> {
734 while let Some((idx, node)) = self.stack.pop() {
735 let parent_idx = idx.parent();
736 let new_node = self.seen_nodes.insert(parent_idx);
737
738 if new_node && let Some(sibling) = self.nodes.get(&idx.sibling()) {
741 let (left, right) = if parent_idx.left_child() == idx {
742 (node, *sibling)
743 } else {
744 (*sibling, node)
745 };
746 let parent = Poseidon2::merge(&[left, right]);
747 let inner_node = InnerNodeInfo { value: parent, left, right };
748
749 self.stack.push((parent_idx, parent));
750 return Some(inner_node);
751 }
752
753 if let Some((pos, leaf)) = self.leaves.next() {
755 let idx = InOrderIndex::from_leaf_pos(pos);
756 self.stack.push((idx, leaf));
757 }
758 }
759
760 None
761 }
762}
763
764impl Serializable for PartialMmr {
765 fn write_into<W: ByteWriter>(&self, target: &mut W) {
766 self.forest.num_leaves().write_into(target);
767 self.peaks.write_into(target);
768 self.nodes.write_into(target);
769 target.write_u8(Self::TRACKED_LEAVES_MARKER);
771 let tracked: Vec<usize> = self.tracked_leaves.iter().copied().collect();
772 tracked.write_into(target);
773 }
774}
775
776impl Deserializable for PartialMmr {
777 fn read_from<R: ByteReader>(
778 source: &mut R,
779 ) -> Result<Self, crate::utils::DeserializationError> {
780 use crate::utils::DeserializationError;
781
782 let forest = Forest::new(usize::read_from(source)?)?;
783 let peaks_vec = Vec::<Word>::read_from(source)?;
784 let nodes = NodeMap::read_from(source)?;
785 if !source.has_more_bytes() {
786 return Err(DeserializationError::UnexpectedEOF);
787 }
788 let marker = source.read_u8()?;
789 if marker != Self::TRACKED_LEAVES_MARKER {
790 return Err(DeserializationError::InvalidValue(
791 "unknown partial mmr serialization format".to_string(),
792 ));
793 }
794 let tracked: Vec<usize> = Vec::read_from(source)?;
795 let mut tracked_leaves = BTreeSet::new();
796 for leaf_pos in tracked {
797 if !tracked_leaves.insert(leaf_pos) {
798 return Err(DeserializationError::InvalidValue(
799 "duplicate tracked leaf in partial mmr encoding".to_string(),
800 ));
801 }
802 }
803
804 let peaks = MmrPeaks::new(forest, peaks_vec).map_err(|e| {
806 DeserializationError::InvalidValue(format!("invalid partial mmr peaks: {e}"))
807 })?;
808
809 Self::from_parts(peaks, nodes, tracked_leaves)
811 .map_err(|e| DeserializationError::InvalidValue(format!("invalid partial mmr: {e}")))
812 }
813}
814
815#[cfg(test)]
819mod tests {
820 use alloc::{
821 collections::{BTreeMap, BTreeSet},
822 vec::Vec,
823 };
824
825 use super::{MerklePath, MmrError, MmrPeaks, PartialMmr};
826 use crate::{
827 Word,
828 merkle::{
829 NodeIndex, int_to_node,
830 mmr::{InOrderIndex, Mmr, forest::Forest},
831 store::MerkleStore,
832 },
833 utils::{ByteWriter, Deserializable, DeserializationError, Serializable},
834 };
835
836 const LEAVES: [Word; 7] = [
837 int_to_node(0),
838 int_to_node(1),
839 int_to_node(2),
840 int_to_node(3),
841 int_to_node(4),
842 int_to_node(5),
843 int_to_node(6),
844 ];
845
846 #[test]
847 fn test_partial_mmr_apply_delta() {
848 let mut mmr = Mmr::default();
850 (0..10).for_each(|i| mmr.add(int_to_node(i)).unwrap());
851 let mut partial_mmr: PartialMmr = mmr.peaks().into();
852
853 {
855 let node = mmr.get(1).unwrap();
856 let proof = mmr.open(1).unwrap();
857 partial_mmr.track(1, node, proof.path().merkle_path()).unwrap();
858 }
859
860 {
861 let node = mmr.get(8).unwrap();
862 let proof = mmr.open(8).unwrap();
863 partial_mmr.track(8, node, proof.path().merkle_path()).unwrap();
864 }
865
866 (10..12).for_each(|i| mmr.add(int_to_node(i)).unwrap());
868 validate_apply_delta(&mmr, &mut partial_mmr);
869
870 mmr.add(int_to_node(12)).unwrap();
872 validate_apply_delta(&mmr, &mut partial_mmr);
873 {
874 let node = mmr.get(12).unwrap();
875 let proof = mmr.open(12).unwrap();
876 partial_mmr.track(12, node, proof.path().merkle_path()).unwrap();
877 assert!(partial_mmr.is_tracked(12));
879 }
880
881 (13..16).for_each(|i| mmr.add(int_to_node(i)).unwrap());
885 validate_apply_delta(&mmr, &mut partial_mmr);
886 }
887
888 fn validate_apply_delta(mmr: &Mmr, partial: &mut PartialMmr) {
889 let tracked_positions: Vec<_> = partial.tracked_leaves.iter().copied().collect();
891 let nodes_before = partial.nodes.clone();
892
893 let delta = mmr.get_delta(partial.forest(), mmr.forest()).unwrap();
895 let nodes_delta = partial.apply(delta).unwrap();
896
897 assert_eq!(mmr.peaks(), partial.peaks());
899
900 let mut expected_nodes = nodes_before;
901 for (key, value) in nodes_delta {
902 assert!(expected_nodes.insert(key, value).is_none());
904 }
905
906 assert_eq!(expected_nodes, partial.nodes);
908
909 for pos in tracked_positions {
911 let proof1 = partial.open(pos).unwrap().unwrap();
912 let proof2 = mmr.open(pos).unwrap();
913 assert_eq!(proof1, proof2);
914 }
915 }
916
917 #[test]
918 fn test_partial_mmr_inner_nodes_iterator() {
919 let mmr = Mmr::try_from_iter(LEAVES.iter().copied()).unwrap();
921 let first_peak = mmr.peaks().peaks()[0];
922
923 let node1 = mmr.get(1).unwrap();
927 let proof1 = mmr.open(1).unwrap();
928
929 let mut partial_mmr: PartialMmr = mmr.peaks().into();
931 partial_mmr.track(1, node1, proof1.path().merkle_path()).unwrap();
932
933 assert_eq!(partial_mmr.inner_nodes([].iter().cloned()).next(), None);
935
936 let mut store: MerkleStore = MerkleStore::new();
938 store.extend(partial_mmr.inner_nodes([(1, node1)].iter().cloned()));
939
940 let index1 = NodeIndex::new(2, 1).unwrap();
941 let path1 = store.get_path(first_peak, index1).unwrap().path;
942
943 assert_eq!(path1, *proof1.path().merkle_path());
944
945 let mut partial_mmr: PartialMmr = mmr.peaks().into();
949
950 let node0 = mmr.get(0).unwrap();
951 let proof0 = mmr.open(0).unwrap();
952
953 let node2 = mmr.get(2).unwrap();
954 let proof2 = mmr.open(2).unwrap();
955
956 partial_mmr.track(0, node0, proof0.path().merkle_path()).unwrap();
957 partial_mmr.track(1, node1, proof1.path().merkle_path()).unwrap();
958 partial_mmr.track(2, node2, proof2.path().merkle_path()).unwrap();
959
960 let leaves = [(0, node0), (1, node1), (2, node2)];
962 let mut nodes = BTreeSet::new();
963 for node in partial_mmr.inner_nodes(leaves.iter().cloned()) {
964 assert!(nodes.insert(node.value));
965 }
966
967 store.extend(partial_mmr.inner_nodes(leaves.iter().cloned()));
969
970 let index0 = NodeIndex::new(2, 0).unwrap();
971 let index1 = NodeIndex::new(2, 1).unwrap();
972 let index2 = NodeIndex::new(2, 2).unwrap();
973
974 let path0 = store.get_path(first_peak, index0).unwrap().path;
975 let path1 = store.get_path(first_peak, index1).unwrap().path;
976 let path2 = store.get_path(first_peak, index2).unwrap().path;
977
978 assert_eq!(path0, *proof0.path().merkle_path());
979 assert_eq!(path1, *proof1.path().merkle_path());
980 assert_eq!(path2, *proof2.path().merkle_path());
981
982 let mut partial_mmr: PartialMmr = mmr.peaks().into();
986
987 let node5 = mmr.get(5).unwrap();
988 let proof5 = mmr.open(5).unwrap();
989
990 partial_mmr.track(1, node1, proof1.path().merkle_path()).unwrap();
991 partial_mmr.track(5, node5, proof5.path().merkle_path()).unwrap();
992
993 let mut store: MerkleStore = MerkleStore::new();
995 store.extend(partial_mmr.inner_nodes([(1, node1), (5, node5)].iter().cloned()));
996
997 let index1 = NodeIndex::new(2, 1).unwrap();
998 let index5 = NodeIndex::new(1, 1).unwrap();
999
1000 let second_peak = mmr.peaks().peaks()[1];
1001
1002 let path1 = store.get_path(first_peak, index1).unwrap().path;
1003 let path5 = store.get_path(second_peak, index5).unwrap().path;
1004
1005 assert_eq!(path1, *proof1.path().merkle_path());
1006 assert_eq!(path5, *proof5.path().merkle_path());
1007 }
1008
1009 #[test]
1010 fn test_partial_mmr_add_without_track() {
1011 let mut mmr = Mmr::default();
1012 let empty_peaks = MmrPeaks::new(Forest::empty(), vec![]).unwrap();
1013 let mut partial_mmr = PartialMmr::from_peaks(empty_peaks);
1014
1015 for el in (0..256).map(int_to_node) {
1016 mmr.add(el).unwrap();
1017 partial_mmr.add(el, false).unwrap();
1018
1019 assert_eq!(mmr.peaks(), partial_mmr.peaks());
1020 assert_eq!(mmr.forest(), partial_mmr.forest());
1021 }
1022 }
1023
1024 #[test]
1025 fn test_partial_mmr_add_with_track() {
1026 let mut mmr = Mmr::default();
1027 let empty_peaks = MmrPeaks::new(Forest::empty(), vec![]).unwrap();
1028 let mut partial_mmr = PartialMmr::from_peaks(empty_peaks);
1029
1030 for i in 0..256 {
1031 let el = int_to_node(i as u64);
1032 mmr.add(el).unwrap();
1033 partial_mmr.add(el, true).unwrap();
1034
1035 assert_eq!(mmr.peaks(), partial_mmr.peaks());
1036 assert_eq!(mmr.forest(), partial_mmr.forest());
1037
1038 for pos in 0..i {
1039 let mmr_proof = mmr.open(pos).unwrap();
1040 let partialmmr_proof = partial_mmr.open(pos).unwrap().unwrap();
1041 assert_eq!(mmr_proof, partialmmr_proof);
1042 }
1043 }
1044 }
1045
1046 #[test]
1047 fn test_partial_mmr_add_existing_track() {
1048 let mut mmr = Mmr::try_from_iter((0..7).map(int_to_node)).unwrap();
1049
1050 let mut partial_mmr = PartialMmr::from_peaks(mmr.peaks());
1052 let path_to_5 = mmr.open(5).unwrap().path().merkle_path().clone();
1053 let leaf_at_5 = mmr.get(5).unwrap();
1054 partial_mmr.track(5, leaf_at_5, &path_to_5).unwrap();
1055
1056 let leaf_at_7 = int_to_node(7);
1058 mmr.add(leaf_at_7).unwrap();
1059 partial_mmr.add(leaf_at_7, false).unwrap();
1060
1061 assert_eq!(mmr.open(5).unwrap(), partial_mmr.open(5).unwrap().unwrap());
1063 }
1064
1065 #[test]
1066 fn test_partial_mmr_add_updates_tracked_dangling_leaf() {
1067 let mut mmr = Mmr::default();
1070 let mut partial_mmr = PartialMmr::default();
1071
1072 let leaf0 = int_to_node(0);
1074 mmr.add(leaf0).unwrap();
1075 partial_mmr.add(leaf0, true).unwrap();
1076
1077 assert_eq!(mmr.open(0).unwrap(), partial_mmr.open(0).unwrap().unwrap());
1079
1080 let leaf1 = int_to_node(1);
1082 mmr.add(leaf1).unwrap();
1083 partial_mmr.add(leaf1, false).unwrap();
1084
1085 assert!(partial_mmr.is_tracked(0));
1087 assert!(!partial_mmr.is_tracked(1));
1088 assert_eq!(mmr.open(0).unwrap(), partial_mmr.open(0).unwrap().unwrap());
1089 }
1090
1091 #[test]
1092 fn test_partial_mmr_serialization() {
1093 let mmr = Mmr::try_from_iter((0..7).map(int_to_node)).unwrap();
1094 let partial_mmr = PartialMmr::from_peaks(mmr.peaks());
1095
1096 let bytes = partial_mmr.to_bytes();
1097 let decoded = PartialMmr::read_from_bytes(&bytes).unwrap();
1098
1099 assert_eq!(partial_mmr, decoded);
1100 }
1101
1102 #[test]
1103 fn test_partial_mmr_deserialization_rejects_duplicate_tracked_leaves() {
1104 let mmr = Mmr::try_from_iter(LEAVES.iter().copied()).unwrap();
1105 let mut partial_mmr = PartialMmr::from_peaks(mmr.peaks());
1106 let leaf_pos = 1usize;
1107 let node = mmr.get(leaf_pos).unwrap();
1108 let proof = mmr.open(leaf_pos).unwrap();
1109 partial_mmr.track(leaf_pos, node, proof.path().merkle_path()).unwrap();
1110
1111 let mut bytes = Vec::new();
1112 partial_mmr.forest.num_leaves().write_into(&mut bytes);
1113 partial_mmr.peaks.write_into(&mut bytes);
1114 partial_mmr.nodes.write_into(&mut bytes);
1115 bytes.write_u8(PartialMmr::TRACKED_LEAVES_MARKER);
1116 vec![leaf_pos, leaf_pos].write_into(&mut bytes);
1117
1118 let result = PartialMmr::read_from_bytes(&bytes);
1119
1120 assert!(matches!(result, Err(DeserializationError::InvalidValue(_))));
1121 }
1122
1123 #[test]
1124 fn test_partial_mmr_deserialization_rejects_large_forest() {
1125 let mut bytes = (Forest::MAX_LEAVES + 1).to_bytes();
1126 bytes.extend_from_slice(&0usize.to_bytes()); bytes.extend_from_slice(&0usize.to_bytes()); bytes.extend_from_slice(&0usize.to_bytes()); let result = PartialMmr::read_from_bytes(&bytes);
1131 assert!(matches!(result, Err(DeserializationError::InvalidValue(_))));
1132 }
1133
1134 #[test]
1135 fn test_partial_mmr_untrack() {
1136 let mmr = Mmr::try_from_iter(LEAVES.iter().copied()).unwrap();
1138
1139 let node1 = mmr.get(1).unwrap();
1141 let proof1 = mmr.open(1).unwrap();
1142
1143 let node2 = mmr.get(2).unwrap();
1145 let proof2 = mmr.open(2).unwrap();
1146
1147 let mut partial_mmr: PartialMmr = mmr.peaks().into();
1149 partial_mmr.track(1, node1, proof1.path().merkle_path()).unwrap();
1150 partial_mmr.track(2, node2, proof2.path().merkle_path()).unwrap();
1151
1152 partial_mmr.untrack(1);
1154 partial_mmr.untrack(2);
1155
1156 assert!(!partial_mmr.is_tracked(1));
1158 assert!(!partial_mmr.is_tracked(2));
1159 assert_eq!(partial_mmr.nodes().count(), 0);
1160 }
1161
1162 #[test]
1163 fn test_partial_mmr_untrack_returns_removed_nodes() {
1164 let mmr = Mmr::try_from_iter(LEAVES.iter().copied()).unwrap();
1166
1167 let node1 = mmr.get(1).unwrap();
1169 let proof1 = mmr.open(1).unwrap();
1170
1171 let mut partial_mmr: PartialMmr = mmr.peaks().into();
1173
1174 partial_mmr.track(1, node1, proof1.path().merkle_path()).unwrap();
1176
1177 let nodes_before: BTreeSet<_> =
1179 partial_mmr.nodes().map(|(&idx, &word)| (idx, word)).collect();
1180
1181 let removed: BTreeSet<_> = partial_mmr.untrack(1).into_iter().collect();
1183
1184 assert_eq!(removed, nodes_before);
1186
1187 assert!(!partial_mmr.is_tracked(1));
1189 assert_eq!(partial_mmr.nodes().count(), 0);
1190 }
1191
1192 #[test]
1193 fn test_partial_mmr_untrack_shared_nodes() {
1194 let mmr = Mmr::try_from_iter(LEAVES.iter().copied()).unwrap();
1196
1197 let node0 = mmr.get(0).unwrap();
1199 let proof0 = mmr.open(0).unwrap();
1200
1201 let node1 = mmr.get(1).unwrap();
1202 let proof1 = mmr.open(1).unwrap();
1203
1204 let mut partial_mmr: PartialMmr = mmr.peaks().into();
1206
1207 partial_mmr.track(0, node0, proof0.path().merkle_path()).unwrap();
1209 partial_mmr.track(1, node1, proof1.path().merkle_path()).unwrap();
1210
1211 assert_eq!(partial_mmr.nodes().count(), 3);
1220
1221 let removed0 = partial_mmr.untrack(0);
1227 assert_eq!(removed0.len(), 0);
1228 assert_eq!(partial_mmr.nodes().count(), 3);
1229 assert!(partial_mmr.is_tracked(1));
1230 assert!(!partial_mmr.is_tracked(0));
1231
1232 let removed1 = partial_mmr.untrack(1);
1238 assert_eq!(removed1.len(), 3);
1239 assert_eq!(partial_mmr.nodes().count(), 0);
1240 assert!(!partial_mmr.is_tracked(1));
1241 }
1242
1243 #[test]
1244 fn test_partial_mmr_untrack_preserves_upper_siblings() {
1245 let mut mmr = Mmr::default();
1246 (0..8).for_each(|i| mmr.add(int_to_node(i)).unwrap());
1247
1248 let mut partial_mmr: PartialMmr = mmr.peaks().into();
1249 for pos in [0, 2] {
1250 let node = mmr.get(pos).unwrap();
1251 let proof = mmr.open(pos).unwrap();
1252 partial_mmr.track(pos, node, proof.path().merkle_path()).unwrap();
1253 }
1254
1255 partial_mmr.untrack(0);
1256
1257 let proof_partial = partial_mmr.open(2).unwrap().unwrap();
1258 let proof_full = mmr.open(2).unwrap();
1259 assert_eq!(proof_partial, proof_full);
1260 }
1261
1262 #[test]
1263 fn test_partial_mmr_deserialize_missing_marker_fails() {
1264 let mut mmr = Mmr::default();
1265 (0..3).for_each(|i| mmr.add(int_to_node(i)).unwrap());
1266 let peaks = mmr.peaks();
1267
1268 let mut bytes = Vec::new();
1269 peaks.num_leaves().write_into(&mut bytes);
1270 peaks.peaks().to_vec().write_into(&mut bytes);
1271 BTreeMap::<InOrderIndex, Word>::new().write_into(&mut bytes);
1272 assert!(PartialMmr::read_from_bytes(&bytes).is_err());
1273 }
1274
1275 #[test]
1276 fn test_partial_mmr_deserialize_invalid_marker_fails() {
1277 let mut mmr = Mmr::default();
1278 (0..3).for_each(|i| mmr.add(int_to_node(i)).unwrap());
1279 let peaks = mmr.peaks();
1280
1281 let mut bytes = Vec::new();
1282 peaks.num_leaves().write_into(&mut bytes);
1283 peaks.peaks().to_vec().write_into(&mut bytes);
1284 BTreeMap::<InOrderIndex, Word>::new().write_into(&mut bytes);
1285 bytes.write_u8(0x7f);
1286 Vec::<usize>::new().write_into(&mut bytes);
1287
1288 assert!(PartialMmr::read_from_bytes(&bytes).is_err());
1289 }
1290
1291 #[test]
1292 fn test_partial_mmr_open_returns_proof_with_leaf() {
1293 let mmr = Mmr::try_from_iter(LEAVES.iter().copied()).unwrap();
1295
1296 let leaf1 = mmr.get(1).unwrap();
1298 let mmr_proof = mmr.open(1).unwrap();
1299
1300 let mut partial_mmr: PartialMmr = mmr.peaks().into();
1302 partial_mmr.track(1, leaf1, mmr_proof.path().merkle_path()).unwrap();
1303
1304 let partial_proof = partial_mmr.open(1).unwrap().unwrap();
1306 assert_eq!(partial_proof.leaf(), leaf1);
1307 assert_eq!(partial_proof, mmr_proof);
1308
1309 partial_mmr.untrack(1);
1311 assert!(partial_mmr.open(1).unwrap().is_none());
1312 }
1313
1314 #[test]
1315 fn test_partial_mmr_add_tracks_leaf() {
1316 let mut partial_mmr = PartialMmr::default();
1318
1319 let leaf0 = int_to_node(0);
1321 let leaf1 = int_to_node(1);
1322 let leaf2 = int_to_node(2);
1323
1324 partial_mmr.add(leaf0, true).unwrap(); partial_mmr.add(leaf1, false).unwrap(); partial_mmr.add(leaf2, true).unwrap(); let proof0 = partial_mmr.open(0).unwrap();
1330 assert!(proof0.is_some());
1331 assert_eq!(proof0.unwrap().leaf(), leaf0);
1332
1333 let proof1 = partial_mmr.open(1).unwrap();
1335 assert!(proof1.is_none());
1336
1337 let proof2 = partial_mmr.open(2).unwrap();
1339 assert!(proof2.is_some());
1340 assert_eq!(proof2.unwrap().leaf(), leaf2);
1341
1342 assert_eq!(partial_mmr.get(0), Some(leaf0));
1344 assert_eq!(partial_mmr.get(1), None);
1345 assert_eq!(partial_mmr.get(2), Some(leaf2));
1346
1347 let tracked: Vec<_> = partial_mmr.leaves().collect();
1349 assert_eq!(tracked, vec![(0, leaf0), (2, leaf2)]);
1350 }
1351
1352 #[test]
1353 fn test_partial_mmr_track_dangling_leaf() {
1354 let mut mmr = Mmr::default();
1356 mmr.add(int_to_node(0)).unwrap();
1357 let mut partial_mmr: PartialMmr = mmr.peaks().into();
1358
1359 let leaf0 = mmr.get(0).unwrap();
1360 let proof0 = mmr.open(0).unwrap();
1362
1363 partial_mmr.track(0, leaf0, proof0.path().merkle_path()).unwrap();
1365
1366 assert!(partial_mmr.is_tracked(0));
1368 assert_eq!(partial_mmr.open(0).unwrap().unwrap(), proof0);
1369 }
1370
1371 #[test]
1372 fn test_partial_mmr_track_rejects_position_path_tree_mismatches() {
1373 let mmr = Mmr::try_from_iter(LEAVES.iter().copied()).unwrap();
1374 let path_for_large_tree = mmr.open(0).unwrap();
1375 let path_for_middle_tree = mmr.open(4).unwrap();
1376
1377 let mut partial_mmr: PartialMmr = mmr.peaks().into();
1380 let result =
1381 partial_mmr.track(0, mmr.get(0).unwrap(), path_for_middle_tree.path().merkle_path());
1382 assert!(matches!(result, Err(MmrError::PositionNotFound(0))));
1383 assert!(!partial_mmr.is_tracked(0));
1384
1385 let result =
1388 partial_mmr.track(4, mmr.get(4).unwrap(), path_for_large_tree.path().merkle_path());
1389 assert!(matches!(result, Err(MmrError::PositionNotFound(4))));
1390 assert!(!partial_mmr.is_tracked(4));
1391 }
1392
1393 #[test]
1394 fn test_partial_mmr_track_rejects_position_outside_forest() {
1395 let mmr = Mmr::try_from_iter(LEAVES.iter().copied()).unwrap();
1396 let proof = mmr.open(0).unwrap();
1397 let mut partial_mmr: PartialMmr = mmr.peaks().into();
1398
1399 let result = partial_mmr.track(LEAVES.len(), int_to_node(7), proof.path().merkle_path());
1400
1401 assert!(matches!(result, Err(MmrError::PositionNotFound(7))));
1402 assert!(!partial_mmr.is_tracked(LEAVES.len()));
1403 }
1404
1405 #[test]
1406 fn test_partial_mmr_track_preserves_unknown_peak_error() {
1407 let mmr = Mmr::try_from_iter(LEAVES.iter().copied()).unwrap();
1408 let mut partial_mmr: PartialMmr = mmr.peaks().into();
1409 let path = MerklePath::new(vec![Word::empty(); 3]);
1410
1411 let result = partial_mmr.track(0, mmr.get(0).unwrap(), &path);
1412
1413 assert!(matches!(result, Err(MmrError::UnknownPeak(3))));
1414 assert!(!partial_mmr.is_tracked(0));
1415 }
1416
1417 #[test]
1418 fn test_partial_mmr_track_valid_proofs_round_trip_across_all_peaks() {
1419 let mmr = Mmr::try_from_iter(LEAVES.iter().copied()).unwrap();
1420
1421 for leaf_pos in 0..LEAVES.len() {
1422 let leaf = mmr.get(leaf_pos).unwrap();
1423 let proof = mmr.open(leaf_pos).unwrap();
1424 let mut partial_mmr: PartialMmr = mmr.peaks().into();
1425
1426 partial_mmr.track(leaf_pos, leaf, proof.path().merkle_path()).unwrap();
1427
1428 assert_eq!(partial_mmr.open(leaf_pos).unwrap(), Some(proof));
1429 }
1430 }
1431
1432 #[test]
1433 fn test_from_parts_validation() {
1434 use alloc::collections::BTreeMap;
1435
1436 use super::InOrderIndex;
1437
1438 let mmr = Mmr::try_from_iter(LEAVES.iter().copied()).unwrap();
1440 let peaks = mmr.peaks();
1441
1442 let result = PartialMmr::from_parts(peaks.clone(), BTreeMap::new(), BTreeSet::new());
1444 assert!(result.is_ok());
1445
1446 let mut out_of_bounds = BTreeSet::new();
1448 out_of_bounds.insert(100);
1449 let result = PartialMmr::from_parts(peaks.clone(), BTreeMap::new(), out_of_bounds);
1450 assert!(result.is_err());
1451
1452 let mut tracked_no_value = BTreeSet::new();
1454 tracked_no_value.insert(0);
1455 let result = PartialMmr::from_parts(peaks.clone(), BTreeMap::new(), tracked_no_value);
1456 assert!(result.is_err());
1457
1458 let tracked_pos = 0;
1460 let mut complete_partial = PartialMmr::from_peaks(peaks.clone());
1461 complete_partial
1462 .track(
1463 tracked_pos,
1464 mmr.get(tracked_pos).unwrap(),
1465 mmr.open(tracked_pos).unwrap().path().merkle_path(),
1466 )
1467 .unwrap();
1468 let mut tracked_valid = BTreeSet::new();
1469 tracked_valid.insert(tracked_pos);
1470 let result = PartialMmr::from_parts(peaks.clone(), complete_partial.nodes, tracked_valid);
1471 assert!(result.is_ok());
1472
1473 let mut invalid_nodes = BTreeMap::new();
1475 let invalid_idx = InOrderIndex::from_leaf_pos(100); invalid_nodes.insert(invalid_idx, int_to_node(0));
1477 let result = PartialMmr::from_parts(peaks.clone(), invalid_nodes, BTreeSet::new());
1478 assert!(result.is_err());
1479
1480 assert!(InOrderIndex::read_from_bytes(&0usize.to_bytes()).is_err());
1484
1485 let mut nodes_with_large_even = BTreeMap::new();
1487 let large_even_idx = InOrderIndex::read_from_bytes(&1000usize.to_bytes()).unwrap();
1488 nodes_with_large_even.insert(large_even_idx, int_to_node(0));
1489 let result = PartialMmr::from_parts(peaks.clone(), nodes_with_large_even, BTreeSet::new());
1490 assert!(result.is_err());
1491
1492 let mut nodes_with_separator = BTreeMap::new();
1497 let separator_idx = InOrderIndex::read_from_bytes(&8usize.to_bytes()).unwrap();
1498 nodes_with_separator.insert(separator_idx, int_to_node(0));
1499 let result = PartialMmr::from_parts(peaks.clone(), nodes_with_separator, BTreeSet::new());
1500 assert!(result.is_err(), "separator index 8 should be rejected");
1501
1502 let mut nodes_with_separator_12 = BTreeMap::new();
1503 let separator_idx_12 = InOrderIndex::read_from_bytes(&12usize.to_bytes()).unwrap();
1504 nodes_with_separator_12.insert(separator_idx_12, int_to_node(0));
1505 let result = PartialMmr::from_parts(peaks, nodes_with_separator_12, BTreeSet::new());
1506 assert!(result.is_err(), "separator index 12 should be rejected");
1507
1508 let empty_peaks = MmrPeaks::new(Forest::empty(), vec![]).unwrap();
1510 let mut nodes_with_empty_forest = BTreeMap::new();
1511 nodes_with_empty_forest.insert(InOrderIndex::from_leaf_pos(0), int_to_node(0));
1512 let result = PartialMmr::from_parts(empty_peaks, nodes_with_empty_forest, BTreeSet::new());
1513 assert!(result.is_err());
1514 }
1515
1516 #[test]
1517 fn test_from_parts_rejects_missing_ancestor_sibling() {
1518 let mmr = Mmr::try_from_iter(LEAVES.iter().copied()).unwrap();
1519 let peaks = mmr.peaks();
1520 let tracked_pos = 0;
1521 let mut partial_mmr = PartialMmr::from_peaks(peaks.clone());
1522 partial_mmr
1523 .track(
1524 tracked_pos,
1525 mmr.get(tracked_pos).unwrap(),
1526 mmr.open(tracked_pos).unwrap().path().merkle_path(),
1527 )
1528 .unwrap();
1529
1530 let missing_sibling = InOrderIndex::from_leaf_pos(tracked_pos).parent().sibling();
1531 assert!(partial_mmr.nodes.remove(&missing_sibling).is_some());
1532
1533 let result = PartialMmr::from_parts(peaks, partial_mmr.nodes, partial_mmr.tracked_leaves);
1534 assert!(matches!(result, Err(MmrError::InconsistentPartialMmr(_))));
1535 }
1536
1537 #[test]
1538 fn test_from_parts_validation_deserialization() {
1539 let mmr = Mmr::try_from_iter(LEAVES.iter().copied()).unwrap();
1541 let partial_mmr = PartialMmr::from_peaks(mmr.peaks());
1542
1543 let bytes = partial_mmr.to_bytes();
1545 let decoded = PartialMmr::read_from_bytes(&bytes);
1546 assert!(decoded.is_ok());
1547
1548 let mut partial_with_node = PartialMmr::from_peaks(mmr.peaks());
1553 let node = mmr.get(1).unwrap();
1554 let proof = mmr.open(1).unwrap();
1555 partial_with_node.track(1, node, proof.path().merkle_path()).unwrap();
1556
1557 let valid_bytes = partial_with_node.to_bytes();
1559 let valid_decoded = PartialMmr::read_from_bytes(&valid_bytes);
1560 assert!(valid_decoded.is_ok());
1561
1562 let mut bad_bytes = Vec::new();
1565 bad_bytes.extend_from_slice(&7usize.to_bytes());
1567 bad_bytes.extend_from_slice(&3usize.to_bytes()); for i in 0..3 {
1570 bad_bytes.extend_from_slice(&int_to_node(i as u64).to_bytes());
1571 }
1572 bad_bytes.extend_from_slice(&1usize.to_bytes()); bad_bytes.extend_from_slice(&0usize.to_bytes()); bad_bytes.extend_from_slice(&int_to_node(0).to_bytes()); bad_bytes.push(PartialMmr::TRACKED_LEAVES_MARKER);
1577 bad_bytes.extend_from_slice(&0usize.to_bytes());
1579
1580 let result = PartialMmr::read_from_bytes(&bad_bytes);
1581 assert!(result.is_err());
1582 }
1583
1584 #[test]
1585 fn test_deserialization_rejects_missing_ancestor_sibling() {
1586 let mmr = Mmr::try_from_iter(LEAVES.iter().copied()).unwrap();
1587 let tracked_pos = 0;
1588 let mut partial_mmr = PartialMmr::from_peaks(mmr.peaks());
1589 partial_mmr
1590 .track(
1591 tracked_pos,
1592 mmr.get(tracked_pos).unwrap(),
1593 mmr.open(tracked_pos).unwrap().path().merkle_path(),
1594 )
1595 .unwrap();
1596
1597 let missing_sibling = InOrderIndex::from_leaf_pos(tracked_pos).parent().sibling();
1598 assert!(partial_mmr.nodes.remove(&missing_sibling).is_some());
1599
1600 let result = PartialMmr::read_from_bytes(&partial_mmr.to_bytes());
1601 assert!(matches!(result, Err(DeserializationError::InvalidValue(_))));
1602 }
1603
1604 #[test]
1605 fn test_from_parts_unchecked() {
1606 use alloc::collections::BTreeMap;
1607
1608 let mmr = Mmr::try_from_iter(LEAVES.iter().copied()).unwrap();
1610 let peaks = mmr.peaks();
1611
1612 let partial =
1614 PartialMmr::from_parts_unchecked(peaks.clone(), BTreeMap::new(), BTreeSet::new());
1615 assert_eq!(partial.forest(), peaks.forest());
1616
1617 let mut invalid_tracked = BTreeSet::new();
1619 invalid_tracked.insert(999);
1620 let partial = PartialMmr::from_parts_unchecked(peaks, BTreeMap::new(), invalid_tracked);
1621 assert!(partial.tracked_leaves.contains(&999));
1622 }
1623}