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 {} is out of bounds (forest has {} leaves)",
128 pos, num_leaves
129 )));
130 }
131 let leaf_idx = InOrderIndex::from_leaf_pos(pos);
132 if !nodes.contains_key(&leaf_idx) {
133 return Err(MmrError::InconsistentPartialMmr(format!(
134 "tracked leaf at position {} has no value in nodes",
135 pos
136 )));
137 }
138 }
139
140 for idx in nodes.keys() {
143 if !forest.is_valid_in_order_index(idx) {
144 return Err(MmrError::InconsistentPartialMmr(format!(
145 "node index {} is not a valid index in the forest",
146 idx.inner()
147 )));
148 }
149 }
150
151 let peaks = peaks.into();
152 Ok(Self { forest, peaks, nodes, tracked_leaves })
153 }
154
155 pub fn from_parts_unchecked(
165 peaks: MmrPeaks,
166 nodes: NodeMap,
167 tracked_leaves: BTreeSet<usize>,
168 ) -> Self {
169 let forest = peaks.forest();
170 let peaks = peaks.into();
171
172 Self { forest, peaks, nodes, tracked_leaves }
173 }
174
175 pub fn forest(&self) -> Forest {
183 self.forest
184 }
185
186 pub fn num_leaves(&self) -> usize {
188 self.forest.num_leaves()
189 }
190
191 pub fn peaks(&self) -> MmrPeaks {
193 MmrPeaks::new(self.forest, self.peaks.clone()).expect("invalid MMR peaks")
196 }
197
198 pub fn is_tracked(&self, pos: usize) -> bool {
201 self.tracked_leaves.contains(&pos)
202 }
203
204 pub fn get(&self, pos: usize) -> Option<Word> {
206 if !self.tracked_leaves.contains(&pos) {
207 return None;
208 }
209 let leaf_idx = InOrderIndex::from_leaf_pos(pos);
210 self.nodes.get(&leaf_idx).copied()
211 }
212
213 pub fn leaves(&self) -> impl Iterator<Item = (usize, Word)> + '_ {
215 self.tracked_leaves.iter().map(|&pos| {
216 let leaf_idx = InOrderIndex::from_leaf_pos(pos);
217 let leaf = *self.nodes.get(&leaf_idx).expect("tracked leaf must have value in nodes");
218 (pos, leaf)
219 })
220 }
221
222 pub fn open(&self, pos: usize) -> Result<Option<MmrProof>, MmrError> {
232 let tree_bit = self
233 .forest
234 .leaf_to_corresponding_tree(pos)
235 .ok_or(MmrError::PositionNotFound(pos))?;
236
237 if !self.tracked_leaves.contains(&pos) {
239 return Ok(None);
240 }
241
242 let leaf_idx = InOrderIndex::from_leaf_pos(pos);
244 let leaf = *self.nodes.get(&leaf_idx).expect("tracked leaf must have value in nodes");
245
246 let depth = tree_bit as usize;
248 let mut nodes = Vec::with_capacity(depth);
249 let mut idx = leaf_idx;
250
251 for _ in 0..depth {
252 let Some(node) = self.nodes.get(&idx.sibling()) else {
253 return Err(MmrError::InconsistentPartialMmr(format!(
254 "missing sibling for tracked leaf at position {pos}"
255 )));
256 };
257 nodes.push(*node);
258 idx = idx.parent();
259 }
260
261 let path = MmrPath::new(self.forest, pos, MerklePath::new(nodes));
262 Ok(Some(MmrProof::new(path, leaf)))
263 }
264
265 pub fn nodes(&self) -> impl Iterator<Item = (&InOrderIndex, &Word)> {
270 self.nodes.iter()
271 }
272
273 pub fn inner_nodes<'a, I: Iterator<Item = (usize, Word)> + 'a>(
278 &'a self,
279 mut leaves: I,
280 ) -> impl Iterator<Item = InnerNodeInfo> + 'a {
281 let stack = if let Some((pos, leaf)) = leaves.next() {
282 let idx = InOrderIndex::from_leaf_pos(pos);
283 vec![(idx, leaf)]
284 } else {
285 Vec::new()
286 };
287
288 InnerNodeIterator {
289 nodes: &self.nodes,
290 leaves,
291 stack,
292 seen_nodes: BTreeSet::new(),
293 }
294 }
295
296 pub fn add(&mut self, leaf: Word, track: bool) -> Vec<(InOrderIndex, Word)> {
304 self.forest.append_leaf();
305 let num_merges = self.forest.smallest_tree_height_unchecked();
309 let mut new_nodes = Vec::with_capacity(num_merges + 1);
310
311 let leaf_pos = self.forest.num_leaves() - 1;
313 let leaf_idx = InOrderIndex::from_leaf_pos(leaf_pos);
314 if track {
315 self.tracked_leaves.insert(leaf_pos);
316 self.nodes.insert(leaf_idx, leaf);
317 new_nodes.push((leaf_idx, leaf));
318 }
319
320 let peak = if num_merges == 0 {
321 leaf
322 } else {
323 let mut track_right = track;
324 let prev_last_pos = self.forest.num_leaves() - 2;
327 let mut track_left = self.tracked_leaves.contains(&prev_last_pos);
328
329 let mut right = leaf;
330 let mut right_idx = self.forest.rightmost_in_order_index();
331
332 for _ in 0..num_merges {
333 let left = self.peaks.pop().expect("Missing peak");
334 let left_idx = right_idx.sibling();
335
336 if track_right {
337 let old = self.nodes.insert(left_idx, left);
338 debug_assert!(
341 old.is_none() || old == Some(left),
342 "Idx {left_idx:?} already contained a different element {old:?}",
343 );
344 if old.is_none() {
345 new_nodes.push((left_idx, left));
346 }
347 };
348 if track_left {
349 let old = self.nodes.insert(right_idx, right);
350 debug_assert!(
351 old.is_none() || old == Some(right),
352 "Idx {right_idx:?} already contained a different element {old:?}",
353 );
354 if old.is_none() {
355 new_nodes.push((right_idx, right));
356 }
357 };
358
359 right_idx = right_idx.parent();
364
365 right = Poseidon2::merge(&[left, right]);
368
369 track_right = track_right || track_left;
373
374 track_left = self.is_tracked_node(&right_idx.sibling());
377 }
378 right
379 };
380
381 self.peaks.push(peak);
382
383 new_nodes
384 }
385
386 pub fn track(
396 &mut self,
397 leaf_pos: usize,
398 leaf: Word,
399 path: &MerklePath,
400 ) -> Result<(), MmrError> {
401 let tree = Forest::new(1 << path.depth());
404 if (tree & self.forest).is_empty() {
405 return Err(MmrError::UnknownPeak(path.depth()));
406 };
407
408 let target_forest = self.forest ^ (self.forest & tree.all_smaller_trees_unchecked());
411 let peak_pos = target_forest.num_trees() - 1;
412
413 let path_idx = leaf_pos - (target_forest ^ tree).num_leaves();
415
416 let computed = path
419 .compute_root(path_idx as u64, leaf)
420 .map_err(MmrError::MerkleRootComputationFailed)?;
421 if self.peaks[peak_pos] != computed {
422 return Err(MmrError::PeakPathMismatch);
423 }
424
425 self.tracked_leaves.insert(leaf_pos);
427
428 let leaf_idx = InOrderIndex::from_leaf_pos(leaf_pos);
430 self.nodes.insert(leaf_idx, leaf);
431
432 let mut idx = leaf_idx;
434 for node in path.nodes() {
435 self.nodes.insert(idx.sibling(), *node);
436 idx = idx.parent();
437 }
438
439 Ok(())
440 }
441
442 pub fn untrack(&mut self, leaf_pos: usize) -> Vec<(InOrderIndex, Word)> {
451 self.tracked_leaves.remove(&leaf_pos);
453
454 let mut idx = InOrderIndex::from_leaf_pos(leaf_pos);
455 let mut removed = Vec::new();
456
457 let sibling_idx = idx.sibling();
460 let sibling_pos = sibling_idx.to_leaf_pos().expect("sibling of a leaf is always a leaf");
461 if self.tracked_leaves.contains(&sibling_pos) {
462 return removed;
465 }
466
467 let Some(rel_pos) = self.forest.leaf_relative_position(leaf_pos) else {
468 return removed;
470 };
471 let tree_start = leaf_pos - rel_pos;
472
473 if let Some(word) = self.nodes.remove(&idx) {
475 removed.push((idx, word));
476 }
477
478 loop {
480 let level = idx.level() as usize;
483 let subtree_size = 1usize << level;
484 let subtree_start_rel = (rel_pos >> level) << level;
485 let subtree_start = tree_start + subtree_start_rel;
486 let subtree_end = subtree_start + subtree_size;
487 if self.tracked_leaves.range(subtree_start..subtree_end).next().is_some() {
488 break;
489 }
490
491 let sibling_idx = idx.sibling();
492
493 let Some(word) = self.nodes.remove(&sibling_idx) else {
495 break;
496 };
497 removed.push((sibling_idx, word));
498
499 if self.nodes.contains_key(&idx) {
501 break;
502 }
503 idx = idx.parent();
504 }
505
506 removed
507 }
508
509 pub fn apply(&mut self, delta: MmrDelta) -> Result<Vec<(InOrderIndex, Word)>, MmrError> {
512 if delta.forest < self.forest {
513 return Err(MmrError::InvalidPeaks(format!(
514 "forest of mmr delta {} is less than current forest {}",
515 delta.forest, self.forest
516 )));
517 }
518
519 let mut inserted_nodes = Vec::new();
520
521 if delta.forest == self.forest {
522 if !delta.data.is_empty() {
523 return Err(MmrError::InvalidUpdate);
524 }
525
526 return Ok(inserted_nodes);
527 }
528
529 let changes = self.forest ^ delta.forest;
531 let largest = changes.largest_tree_unchecked();
534 let trees_to_merge = self.forest & largest.all_smaller_trees_unchecked();
536
537 let (merge_count, new_peaks) = if !trees_to_merge.is_empty() {
539 let depth = largest.smallest_tree_height_unchecked();
540 let skipped = trees_to_merge.smallest_tree_height_unchecked();
542 let computed = trees_to_merge.num_trees() - 1;
543 let merge_count = depth - skipped - computed;
544
545 let new_peaks = delta.forest & largest.all_smaller_trees_unchecked();
546
547 (merge_count, new_peaks)
548 } else {
549 (0, changes)
550 };
551
552 if delta.data.len() != merge_count + new_peaks.num_trees() {
554 return Err(MmrError::InvalidUpdate);
555 }
556
557 let mut update_count = 0;
559
560 if !trees_to_merge.is_empty() {
561 let mut peak_idx = self.forest.root_in_order_index();
563
564 self.peaks.reverse();
566
567 let mut track = false;
568
569 let mut peak_count = 0;
570 let mut target = trees_to_merge.smallest_tree_unchecked();
571 let mut new = delta.data[0];
572 update_count += 1;
573
574 while target < largest {
575 if !track {
578 track = self.is_tracked_node(&peak_idx);
579 }
580
581 let (left, right) = if !(target & trees_to_merge).is_empty() {
584 let peak = self.peaks[peak_count];
585 let sibling_idx = peak_idx.sibling();
586
587 if self.is_tracked_node(&sibling_idx) {
590 self.nodes.insert(peak_idx, new);
591 inserted_nodes.push((peak_idx, new));
592 }
593 peak_count += 1;
594 (peak, new)
595 } else {
596 let update = delta.data[update_count];
597 update_count += 1;
598 (new, update)
599 };
600
601 if track {
602 let sibling_idx = peak_idx.sibling();
603 if peak_idx.is_left_child() {
604 self.nodes.insert(sibling_idx, right);
605 inserted_nodes.push((sibling_idx, right));
606 } else {
607 self.nodes.insert(sibling_idx, left);
608 inserted_nodes.push((sibling_idx, left));
609 }
610 }
611
612 peak_idx = peak_idx.parent();
613 new = Poseidon2::merge(&[left, right]);
614 target = target.next_larger_tree();
615 }
616
617 debug_assert!(peak_count == trees_to_merge.num_trees());
618
619 self.peaks.reverse();
621 self.peaks.truncate(self.peaks.len() - peak_count);
623 self.peaks.push(new);
625 }
626
627 self.peaks.extend_from_slice(&delta.data[update_count..]);
631 self.forest = delta.forest;
632
633 debug_assert!(self.peaks.len() == self.forest.num_trees());
634
635 Ok(inserted_nodes)
636 }
637
638 fn is_tracked_node(&self, node_index: &InOrderIndex) -> bool {
644 if let Some(leaf_pos) = node_index.to_leaf_pos() {
645 self.tracked_leaves.contains(&leaf_pos)
647 } else {
648 let left_child = node_index.left_child();
649 let right_child = node_index.right_child();
650 self.nodes.contains_key(&left_child) | self.nodes.contains_key(&right_child)
651 }
652 }
653}
654
655impl From<MmrPeaks> for PartialMmr {
659 fn from(peaks: MmrPeaks) -> Self {
660 Self::from_peaks(peaks)
661 }
662}
663
664impl From<PartialMmr> for MmrPeaks {
665 fn from(partial_mmr: PartialMmr) -> Self {
666 MmrPeaks::new(partial_mmr.forest, partial_mmr.peaks).unwrap()
669 }
670}
671
672impl From<&MmrPeaks> for PartialMmr {
673 fn from(peaks: &MmrPeaks) -> Self {
674 Self::from_peaks(peaks.clone())
675 }
676}
677
678impl From<&PartialMmr> for MmrPeaks {
679 fn from(partial_mmr: &PartialMmr) -> Self {
680 MmrPeaks::new(partial_mmr.forest, partial_mmr.peaks.clone()).unwrap()
683 }
684}
685
686pub struct InnerNodeIterator<'a, I: Iterator<Item = (usize, Word)>> {
691 nodes: &'a NodeMap,
692 leaves: I,
693 stack: Vec<(InOrderIndex, Word)>,
694 seen_nodes: BTreeSet<InOrderIndex>,
695}
696
697impl<I: Iterator<Item = (usize, Word)>> Iterator for InnerNodeIterator<'_, I> {
698 type Item = InnerNodeInfo;
699
700 fn next(&mut self) -> Option<Self::Item> {
701 while let Some((idx, node)) = self.stack.pop() {
702 let parent_idx = idx.parent();
703 let new_node = self.seen_nodes.insert(parent_idx);
704
705 if new_node && let Some(sibling) = self.nodes.get(&idx.sibling()) {
708 let (left, right) = if parent_idx.left_child() == idx {
709 (node, *sibling)
710 } else {
711 (*sibling, node)
712 };
713 let parent = Poseidon2::merge(&[left, right]);
714 let inner_node = InnerNodeInfo { value: parent, left, right };
715
716 self.stack.push((parent_idx, parent));
717 return Some(inner_node);
718 }
719
720 if let Some((pos, leaf)) = self.leaves.next() {
722 let idx = InOrderIndex::from_leaf_pos(pos);
723 self.stack.push((idx, leaf));
724 }
725 }
726
727 None
728 }
729}
730
731impl Serializable for PartialMmr {
732 fn write_into<W: ByteWriter>(&self, target: &mut W) {
733 self.forest.num_leaves().write_into(target);
734 self.peaks.write_into(target);
735 self.nodes.write_into(target);
736 target.write_u8(Self::TRACKED_LEAVES_MARKER);
738 let tracked: Vec<usize> = self.tracked_leaves.iter().copied().collect();
739 tracked.write_into(target);
740 }
741}
742
743impl Deserializable for PartialMmr {
744 fn read_from<R: ByteReader>(
745 source: &mut R,
746 ) -> Result<Self, crate::utils::DeserializationError> {
747 use crate::utils::DeserializationError;
748
749 let forest = Forest::new(usize::read_from(source)?);
750 let peaks_vec = Vec::<Word>::read_from(source)?;
751 let nodes = NodeMap::read_from(source)?;
752 if !source.has_more_bytes() {
753 return Err(DeserializationError::UnexpectedEOF);
754 }
755 let marker = source.read_u8()?;
756 if marker != Self::TRACKED_LEAVES_MARKER {
757 return Err(DeserializationError::InvalidValue(
758 "unknown partial mmr serialization format".to_string(),
759 ));
760 }
761 let tracked: Vec<usize> = Vec::read_from(source)?;
762 let tracked_leaves: BTreeSet<usize> = tracked.into_iter().collect();
763
764 let peaks = MmrPeaks::new(forest, peaks_vec).map_err(|e| {
766 DeserializationError::InvalidValue(format!("invalid partial mmr peaks: {}", e))
767 })?;
768
769 Self::from_parts(peaks, nodes, tracked_leaves)
771 .map_err(|e| DeserializationError::InvalidValue(format!("invalid partial mmr: {}", e)))
772 }
773}
774
775#[cfg(test)]
779mod tests {
780 use alloc::{
781 collections::{BTreeMap, BTreeSet},
782 vec::Vec,
783 };
784
785 use super::{MmrPeaks, PartialMmr};
786 use crate::{
787 Word,
788 merkle::{
789 NodeIndex, int_to_node,
790 mmr::{InOrderIndex, Mmr, forest::Forest},
791 store::MerkleStore,
792 },
793 utils::{ByteWriter, Deserializable, Serializable},
794 };
795
796 const LEAVES: [Word; 7] = [
797 int_to_node(0),
798 int_to_node(1),
799 int_to_node(2),
800 int_to_node(3),
801 int_to_node(4),
802 int_to_node(5),
803 int_to_node(6),
804 ];
805
806 #[test]
807 fn test_partial_mmr_apply_delta() {
808 let mut mmr = Mmr::default();
810 (0..10).for_each(|i| mmr.add(int_to_node(i)));
811 let mut partial_mmr: PartialMmr = mmr.peaks().into();
812
813 {
815 let node = mmr.get(1).unwrap();
816 let proof = mmr.open(1).unwrap();
817 partial_mmr.track(1, node, proof.path().merkle_path()).unwrap();
818 }
819
820 {
821 let node = mmr.get(8).unwrap();
822 let proof = mmr.open(8).unwrap();
823 partial_mmr.track(8, node, proof.path().merkle_path()).unwrap();
824 }
825
826 (10..12).for_each(|i| mmr.add(int_to_node(i)));
828 validate_apply_delta(&mmr, &mut partial_mmr);
829
830 mmr.add(int_to_node(12));
832 validate_apply_delta(&mmr, &mut partial_mmr);
833 {
834 let node = mmr.get(12).unwrap();
835 let proof = mmr.open(12).unwrap();
836 partial_mmr.track(12, node, proof.path().merkle_path()).unwrap();
837 assert!(partial_mmr.is_tracked(12));
839 }
840
841 (13..16).for_each(|i| mmr.add(int_to_node(i)));
845 validate_apply_delta(&mmr, &mut partial_mmr);
846 }
847
848 fn validate_apply_delta(mmr: &Mmr, partial: &mut PartialMmr) {
849 let tracked_positions: Vec<_> = partial.tracked_leaves.iter().copied().collect();
851 let nodes_before = partial.nodes.clone();
852
853 let delta = mmr.get_delta(partial.forest(), mmr.forest()).unwrap();
855 let nodes_delta = partial.apply(delta).unwrap();
856
857 assert_eq!(mmr.peaks(), partial.peaks());
859
860 let mut expected_nodes = nodes_before;
861 for (key, value) in nodes_delta {
862 assert!(expected_nodes.insert(key, value).is_none());
864 }
865
866 assert_eq!(expected_nodes, partial.nodes);
868
869 for pos in tracked_positions {
871 let proof1 = partial.open(pos).unwrap().unwrap();
872 let proof2 = mmr.open(pos).unwrap();
873 assert_eq!(proof1, proof2);
874 }
875 }
876
877 #[test]
878 fn test_partial_mmr_inner_nodes_iterator() {
879 let mmr: Mmr = LEAVES.into();
881 let first_peak = mmr.peaks().peaks()[0];
882
883 let node1 = mmr.get(1).unwrap();
887 let proof1 = mmr.open(1).unwrap();
888
889 let mut partial_mmr: PartialMmr = mmr.peaks().into();
891 partial_mmr.track(1, node1, proof1.path().merkle_path()).unwrap();
892
893 assert_eq!(partial_mmr.inner_nodes([].iter().cloned()).next(), None);
895
896 let mut store: MerkleStore = MerkleStore::new();
898 store.extend(partial_mmr.inner_nodes([(1, node1)].iter().cloned()));
899
900 let index1 = NodeIndex::new(2, 1).unwrap();
901 let path1 = store.get_path(first_peak, index1).unwrap().path;
902
903 assert_eq!(path1, *proof1.path().merkle_path());
904
905 let mut partial_mmr: PartialMmr = mmr.peaks().into();
909
910 let node0 = mmr.get(0).unwrap();
911 let proof0 = mmr.open(0).unwrap();
912
913 let node2 = mmr.get(2).unwrap();
914 let proof2 = mmr.open(2).unwrap();
915
916 partial_mmr.track(0, node0, proof0.path().merkle_path()).unwrap();
917 partial_mmr.track(1, node1, proof1.path().merkle_path()).unwrap();
918 partial_mmr.track(2, node2, proof2.path().merkle_path()).unwrap();
919
920 let leaves = [(0, node0), (1, node1), (2, node2)];
922 let mut nodes = BTreeSet::new();
923 for node in partial_mmr.inner_nodes(leaves.iter().cloned()) {
924 assert!(nodes.insert(node.value));
925 }
926
927 store.extend(partial_mmr.inner_nodes(leaves.iter().cloned()));
929
930 let index0 = NodeIndex::new(2, 0).unwrap();
931 let index1 = NodeIndex::new(2, 1).unwrap();
932 let index2 = NodeIndex::new(2, 2).unwrap();
933
934 let path0 = store.get_path(first_peak, index0).unwrap().path;
935 let path1 = store.get_path(first_peak, index1).unwrap().path;
936 let path2 = store.get_path(first_peak, index2).unwrap().path;
937
938 assert_eq!(path0, *proof0.path().merkle_path());
939 assert_eq!(path1, *proof1.path().merkle_path());
940 assert_eq!(path2, *proof2.path().merkle_path());
941
942 let mut partial_mmr: PartialMmr = mmr.peaks().into();
946
947 let node5 = mmr.get(5).unwrap();
948 let proof5 = mmr.open(5).unwrap();
949
950 partial_mmr.track(1, node1, proof1.path().merkle_path()).unwrap();
951 partial_mmr.track(5, node5, proof5.path().merkle_path()).unwrap();
952
953 let mut store: MerkleStore = MerkleStore::new();
955 store.extend(partial_mmr.inner_nodes([(1, node1), (5, node5)].iter().cloned()));
956
957 let index1 = NodeIndex::new(2, 1).unwrap();
958 let index5 = NodeIndex::new(1, 1).unwrap();
959
960 let second_peak = mmr.peaks().peaks()[1];
961
962 let path1 = store.get_path(first_peak, index1).unwrap().path;
963 let path5 = store.get_path(second_peak, index5).unwrap().path;
964
965 assert_eq!(path1, *proof1.path().merkle_path());
966 assert_eq!(path5, *proof5.path().merkle_path());
967 }
968
969 #[test]
970 fn test_partial_mmr_add_without_track() {
971 let mut mmr = Mmr::default();
972 let empty_peaks = MmrPeaks::new(Forest::empty(), vec![]).unwrap();
973 let mut partial_mmr = PartialMmr::from_peaks(empty_peaks);
974
975 for el in (0..256).map(int_to_node) {
976 mmr.add(el);
977 partial_mmr.add(el, false);
978
979 assert_eq!(mmr.peaks(), partial_mmr.peaks());
980 assert_eq!(mmr.forest(), partial_mmr.forest());
981 }
982 }
983
984 #[test]
985 fn test_partial_mmr_add_with_track() {
986 let mut mmr = Mmr::default();
987 let empty_peaks = MmrPeaks::new(Forest::empty(), vec![]).unwrap();
988 let mut partial_mmr = PartialMmr::from_peaks(empty_peaks);
989
990 for i in 0..256 {
991 let el = int_to_node(i as u64);
992 mmr.add(el);
993 partial_mmr.add(el, true);
994
995 assert_eq!(mmr.peaks(), partial_mmr.peaks());
996 assert_eq!(mmr.forest(), partial_mmr.forest());
997
998 for pos in 0..i {
999 let mmr_proof = mmr.open(pos).unwrap();
1000 let partialmmr_proof = partial_mmr.open(pos).unwrap().unwrap();
1001 assert_eq!(mmr_proof, partialmmr_proof);
1002 }
1003 }
1004 }
1005
1006 #[test]
1007 fn test_partial_mmr_add_existing_track() {
1008 let mut mmr = Mmr::from((0..7).map(int_to_node));
1009
1010 let mut partial_mmr = PartialMmr::from_peaks(mmr.peaks());
1012 let path_to_5 = mmr.open(5).unwrap().path().merkle_path().clone();
1013 let leaf_at_5 = mmr.get(5).unwrap();
1014 partial_mmr.track(5, leaf_at_5, &path_to_5).unwrap();
1015
1016 let leaf_at_7 = int_to_node(7);
1018 mmr.add(leaf_at_7);
1019 partial_mmr.add(leaf_at_7, false);
1020
1021 assert_eq!(mmr.open(5).unwrap(), partial_mmr.open(5).unwrap().unwrap());
1023 }
1024
1025 #[test]
1026 fn test_partial_mmr_add_updates_tracked_dangling_leaf() {
1027 let mut mmr = Mmr::default();
1030 let mut partial_mmr = PartialMmr::default();
1031
1032 let leaf0 = int_to_node(0);
1034 mmr.add(leaf0);
1035 partial_mmr.add(leaf0, true);
1036
1037 assert_eq!(mmr.open(0).unwrap(), partial_mmr.open(0).unwrap().unwrap());
1039
1040 let leaf1 = int_to_node(1);
1042 mmr.add(leaf1);
1043 partial_mmr.add(leaf1, false);
1044
1045 assert!(partial_mmr.is_tracked(0));
1047 assert!(!partial_mmr.is_tracked(1));
1048 assert_eq!(mmr.open(0).unwrap(), partial_mmr.open(0).unwrap().unwrap());
1049 }
1050
1051 #[test]
1052 fn test_partial_mmr_serialization() {
1053 let mmr = Mmr::from((0..7).map(int_to_node));
1054 let partial_mmr = PartialMmr::from_peaks(mmr.peaks());
1055
1056 let bytes = partial_mmr.to_bytes();
1057 let decoded = PartialMmr::read_from_bytes(&bytes).unwrap();
1058
1059 assert_eq!(partial_mmr, decoded);
1060 }
1061
1062 #[test]
1063 fn test_partial_mmr_untrack() {
1064 let mmr: Mmr = LEAVES.into();
1066
1067 let node1 = mmr.get(1).unwrap();
1069 let proof1 = mmr.open(1).unwrap();
1070
1071 let node2 = mmr.get(2).unwrap();
1073 let proof2 = mmr.open(2).unwrap();
1074
1075 let mut partial_mmr: PartialMmr = mmr.peaks().into();
1077 partial_mmr.track(1, node1, proof1.path().merkle_path()).unwrap();
1078 partial_mmr.track(2, node2, proof2.path().merkle_path()).unwrap();
1079
1080 partial_mmr.untrack(1);
1082 partial_mmr.untrack(2);
1083
1084 assert!(!partial_mmr.is_tracked(1));
1086 assert!(!partial_mmr.is_tracked(2));
1087 assert_eq!(partial_mmr.nodes().count(), 0);
1088 }
1089
1090 #[test]
1091 fn test_partial_mmr_untrack_returns_removed_nodes() {
1092 let mmr: Mmr = LEAVES.into();
1094
1095 let node1 = mmr.get(1).unwrap();
1097 let proof1 = mmr.open(1).unwrap();
1098
1099 let mut partial_mmr: PartialMmr = mmr.peaks().into();
1101
1102 partial_mmr.track(1, node1, proof1.path().merkle_path()).unwrap();
1104
1105 let nodes_before: BTreeSet<_> =
1107 partial_mmr.nodes().map(|(&idx, &word)| (idx, word)).collect();
1108
1109 let removed: BTreeSet<_> = partial_mmr.untrack(1).into_iter().collect();
1111
1112 assert_eq!(removed, nodes_before);
1114
1115 assert!(!partial_mmr.is_tracked(1));
1117 assert_eq!(partial_mmr.nodes().count(), 0);
1118 }
1119
1120 #[test]
1121 fn test_partial_mmr_untrack_shared_nodes() {
1122 let mmr: Mmr = LEAVES.into();
1124
1125 let node0 = mmr.get(0).unwrap();
1127 let proof0 = mmr.open(0).unwrap();
1128
1129 let node1 = mmr.get(1).unwrap();
1130 let proof1 = mmr.open(1).unwrap();
1131
1132 let mut partial_mmr: PartialMmr = mmr.peaks().into();
1134
1135 partial_mmr.track(0, node0, proof0.path().merkle_path()).unwrap();
1137 partial_mmr.track(1, node1, proof1.path().merkle_path()).unwrap();
1138
1139 assert_eq!(partial_mmr.nodes().count(), 3);
1148
1149 let removed0 = partial_mmr.untrack(0);
1155 assert_eq!(removed0.len(), 0);
1156 assert_eq!(partial_mmr.nodes().count(), 3);
1157 assert!(partial_mmr.is_tracked(1));
1158 assert!(!partial_mmr.is_tracked(0));
1159
1160 let removed1 = partial_mmr.untrack(1);
1166 assert_eq!(removed1.len(), 3);
1167 assert_eq!(partial_mmr.nodes().count(), 0);
1168 assert!(!partial_mmr.is_tracked(1));
1169 }
1170
1171 #[test]
1172 fn test_partial_mmr_untrack_preserves_upper_siblings() {
1173 let mut mmr = Mmr::default();
1174 (0..8).for_each(|i| mmr.add(int_to_node(i)));
1175
1176 let mut partial_mmr: PartialMmr = mmr.peaks().into();
1177 for pos in [0, 2] {
1178 let node = mmr.get(pos).unwrap();
1179 let proof = mmr.open(pos).unwrap();
1180 partial_mmr.track(pos, node, proof.path().merkle_path()).unwrap();
1181 }
1182
1183 partial_mmr.untrack(0);
1184
1185 let proof_partial = partial_mmr.open(2).unwrap().unwrap();
1186 let proof_full = mmr.open(2).unwrap();
1187 assert_eq!(proof_partial, proof_full);
1188 }
1189
1190 #[test]
1191 fn test_partial_mmr_deserialize_missing_marker_fails() {
1192 let mut mmr = Mmr::default();
1193 (0..3).for_each(|i| mmr.add(int_to_node(i)));
1194 let peaks = mmr.peaks();
1195
1196 let mut bytes = Vec::new();
1197 peaks.num_leaves().write_into(&mut bytes);
1198 peaks.peaks().to_vec().write_into(&mut bytes);
1199 BTreeMap::<InOrderIndex, Word>::new().write_into(&mut bytes);
1200 assert!(PartialMmr::read_from_bytes(&bytes).is_err());
1201 }
1202
1203 #[test]
1204 fn test_partial_mmr_deserialize_invalid_marker_fails() {
1205 let mut mmr = Mmr::default();
1206 (0..3).for_each(|i| mmr.add(int_to_node(i)));
1207 let peaks = mmr.peaks();
1208
1209 let mut bytes = Vec::new();
1210 peaks.num_leaves().write_into(&mut bytes);
1211 peaks.peaks().to_vec().write_into(&mut bytes);
1212 BTreeMap::<InOrderIndex, Word>::new().write_into(&mut bytes);
1213 bytes.write_u8(0x7f);
1214 Vec::<usize>::new().write_into(&mut bytes);
1215
1216 assert!(PartialMmr::read_from_bytes(&bytes).is_err());
1217 }
1218
1219 #[test]
1220 fn test_partial_mmr_open_returns_proof_with_leaf() {
1221 let mmr: Mmr = LEAVES.into();
1223
1224 let leaf1 = mmr.get(1).unwrap();
1226 let mmr_proof = mmr.open(1).unwrap();
1227
1228 let mut partial_mmr: PartialMmr = mmr.peaks().into();
1230 partial_mmr.track(1, leaf1, mmr_proof.path().merkle_path()).unwrap();
1231
1232 let partial_proof = partial_mmr.open(1).unwrap().unwrap();
1234 assert_eq!(partial_proof.leaf(), leaf1);
1235 assert_eq!(partial_proof, mmr_proof);
1236
1237 partial_mmr.untrack(1);
1239 assert!(partial_mmr.open(1).unwrap().is_none());
1240 }
1241
1242 #[test]
1243 fn test_partial_mmr_add_tracks_leaf() {
1244 let mut partial_mmr = PartialMmr::default();
1246
1247 let leaf0 = int_to_node(0);
1249 let leaf1 = int_to_node(1);
1250 let leaf2 = int_to_node(2);
1251
1252 partial_mmr.add(leaf0, true); partial_mmr.add(leaf1, false); partial_mmr.add(leaf2, true); let proof0 = partial_mmr.open(0).unwrap();
1258 assert!(proof0.is_some());
1259 assert_eq!(proof0.unwrap().leaf(), leaf0);
1260
1261 let proof1 = partial_mmr.open(1).unwrap();
1263 assert!(proof1.is_none());
1264
1265 let proof2 = partial_mmr.open(2).unwrap();
1267 assert!(proof2.is_some());
1268 assert_eq!(proof2.unwrap().leaf(), leaf2);
1269
1270 assert_eq!(partial_mmr.get(0), Some(leaf0));
1272 assert_eq!(partial_mmr.get(1), None);
1273 assert_eq!(partial_mmr.get(2), Some(leaf2));
1274
1275 let tracked: Vec<_> = partial_mmr.leaves().collect();
1277 assert_eq!(tracked, vec![(0, leaf0), (2, leaf2)]);
1278 }
1279
1280 #[test]
1281 fn test_partial_mmr_track_dangling_leaf() {
1282 let mut mmr = Mmr::default();
1284 mmr.add(int_to_node(0));
1285 let mut partial_mmr: PartialMmr = mmr.peaks().into();
1286
1287 let leaf0 = mmr.get(0).unwrap();
1288 let proof0 = mmr.open(0).unwrap();
1290
1291 partial_mmr.track(0, leaf0, proof0.path().merkle_path()).unwrap();
1293
1294 assert!(partial_mmr.is_tracked(0));
1296 assert_eq!(partial_mmr.open(0).unwrap().unwrap(), proof0);
1297 }
1298
1299 #[test]
1300 fn test_from_parts_validation() {
1301 use alloc::collections::BTreeMap;
1302
1303 use super::InOrderIndex;
1304
1305 let mmr: Mmr = LEAVES.into();
1307 let peaks = mmr.peaks();
1308
1309 let result = PartialMmr::from_parts(peaks.clone(), BTreeMap::new(), BTreeSet::new());
1311 assert!(result.is_ok());
1312
1313 let mut out_of_bounds = BTreeSet::new();
1315 out_of_bounds.insert(100);
1316 let result = PartialMmr::from_parts(peaks.clone(), BTreeMap::new(), out_of_bounds);
1317 assert!(result.is_err());
1318
1319 let mut tracked_no_value = BTreeSet::new();
1321 tracked_no_value.insert(0);
1322 let result = PartialMmr::from_parts(peaks.clone(), BTreeMap::new(), tracked_no_value);
1323 assert!(result.is_err());
1324
1325 let mut nodes_with_leaf = BTreeMap::new();
1327 let leaf_idx = super::InOrderIndex::from_leaf_pos(0);
1328 nodes_with_leaf.insert(leaf_idx, int_to_node(0));
1329 let mut tracked_valid = BTreeSet::new();
1330 tracked_valid.insert(0);
1331 let result = PartialMmr::from_parts(peaks.clone(), nodes_with_leaf, tracked_valid);
1332 assert!(result.is_ok());
1333
1334 let mut invalid_nodes = BTreeMap::new();
1336 let invalid_idx = InOrderIndex::from_leaf_pos(100); invalid_nodes.insert(invalid_idx, int_to_node(0));
1338 let result = PartialMmr::from_parts(peaks.clone(), invalid_nodes, BTreeSet::new());
1339 assert!(result.is_err());
1340
1341 let mut nodes_with_zero = BTreeMap::new();
1343 let zero_idx = InOrderIndex::read_from_bytes(&0usize.to_bytes()).unwrap();
1345 nodes_with_zero.insert(zero_idx, int_to_node(0));
1346 let result = PartialMmr::from_parts(peaks.clone(), nodes_with_zero, BTreeSet::new());
1347 assert!(result.is_err());
1348
1349 let mut nodes_with_large_even = BTreeMap::new();
1351 let large_even_idx = InOrderIndex::read_from_bytes(&1000usize.to_bytes()).unwrap();
1352 nodes_with_large_even.insert(large_even_idx, int_to_node(0));
1353 let result = PartialMmr::from_parts(peaks.clone(), nodes_with_large_even, BTreeSet::new());
1354 assert!(result.is_err());
1355
1356 let mut nodes_with_separator = BTreeMap::new();
1361 let separator_idx = InOrderIndex::read_from_bytes(&8usize.to_bytes()).unwrap();
1362 nodes_with_separator.insert(separator_idx, int_to_node(0));
1363 let result = PartialMmr::from_parts(peaks.clone(), nodes_with_separator, BTreeSet::new());
1364 assert!(result.is_err(), "separator index 8 should be rejected");
1365
1366 let mut nodes_with_separator_12 = BTreeMap::new();
1367 let separator_idx_12 = InOrderIndex::read_from_bytes(&12usize.to_bytes()).unwrap();
1368 nodes_with_separator_12.insert(separator_idx_12, int_to_node(0));
1369 let result =
1370 PartialMmr::from_parts(peaks.clone(), nodes_with_separator_12, BTreeSet::new());
1371 assert!(result.is_err(), "separator index 12 should be rejected");
1372
1373 let empty_peaks = MmrPeaks::new(Forest::empty(), vec![]).unwrap();
1375 let mut nodes_with_empty_forest = BTreeMap::new();
1376 nodes_with_empty_forest.insert(InOrderIndex::from_leaf_pos(0), int_to_node(0));
1377 let result = PartialMmr::from_parts(empty_peaks, nodes_with_empty_forest, BTreeSet::new());
1378 assert!(result.is_err());
1379 }
1380
1381 #[test]
1382 fn test_from_parts_validation_deserialization() {
1383 let mmr: Mmr = LEAVES.into();
1385 let partial_mmr = PartialMmr::from_peaks(mmr.peaks());
1386
1387 let bytes = partial_mmr.to_bytes();
1389 let decoded = PartialMmr::read_from_bytes(&bytes);
1390 assert!(decoded.is_ok());
1391
1392 let mut partial_with_node = PartialMmr::from_peaks(mmr.peaks());
1397 let node = mmr.get(1).unwrap();
1398 let proof = mmr.open(1).unwrap();
1399 partial_with_node.track(1, node, proof.path().merkle_path()).unwrap();
1400
1401 let valid_bytes = partial_with_node.to_bytes();
1403 let valid_decoded = PartialMmr::read_from_bytes(&valid_bytes);
1404 assert!(valid_decoded.is_ok());
1405
1406 let mut bad_bytes = Vec::new();
1409 bad_bytes.extend_from_slice(&7usize.to_bytes());
1411 bad_bytes.extend_from_slice(&3usize.to_bytes()); for i in 0..3 {
1414 bad_bytes.extend_from_slice(&int_to_node(i as u64).to_bytes());
1415 }
1416 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.extend_from_slice(&0usize.to_bytes());
1422
1423 let result = PartialMmr::read_from_bytes(&bad_bytes);
1424 assert!(result.is_err());
1425 }
1426
1427 #[test]
1428 fn test_from_parts_unchecked() {
1429 use alloc::collections::BTreeMap;
1430
1431 let mmr: Mmr = LEAVES.into();
1433 let peaks = mmr.peaks();
1434
1435 let partial =
1437 PartialMmr::from_parts_unchecked(peaks.clone(), BTreeMap::new(), BTreeSet::new());
1438 assert_eq!(partial.forest(), peaks.forest());
1439
1440 let mut invalid_tracked = BTreeSet::new();
1442 invalid_tracked.insert(999);
1443 let partial =
1444 PartialMmr::from_parts_unchecked(peaks.clone(), BTreeMap::new(), invalid_tracked);
1445 assert!(partial.tracked_leaves.contains(&999));
1446 }
1447}