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 Ok(Self { forest, peaks, nodes, tracked_leaves })
151 }
152
153 pub fn from_parts_unchecked(
163 peaks: MmrPeaks,
164 nodes: NodeMap,
165 tracked_leaves: BTreeSet<usize>,
166 ) -> Self {
167 let forest = peaks.forest();
168 let peaks = peaks.into();
169
170 Self { forest, peaks, nodes, tracked_leaves }
171 }
172
173 pub fn forest(&self) -> Forest {
181 self.forest
182 }
183
184 pub fn num_leaves(&self) -> usize {
186 self.forest.num_leaves()
187 }
188
189 pub fn peaks(&self) -> MmrPeaks {
191 MmrPeaks::new(self.forest, self.peaks.clone()).expect("invalid MMR peaks")
194 }
195
196 pub fn is_tracked(&self, pos: usize) -> bool {
199 self.tracked_leaves.contains(&pos)
200 }
201
202 pub fn get(&self, pos: usize) -> Option<Word> {
204 if !self.tracked_leaves.contains(&pos) {
205 return None;
206 }
207 let leaf_idx = InOrderIndex::from_leaf_pos(pos);
208 self.nodes.get(&leaf_idx).copied()
209 }
210
211 pub fn leaves(&self) -> impl Iterator<Item = (usize, Word)> + '_ {
213 self.tracked_leaves.iter().map(|&pos| {
214 let leaf_idx = InOrderIndex::from_leaf_pos(pos);
215 let leaf = *self.nodes.get(&leaf_idx).expect("tracked leaf must have value in nodes");
216 (pos, leaf)
217 })
218 }
219
220 pub fn open(&self, pos: usize) -> Result<Option<MmrProof>, MmrError> {
230 let tree_bit = self
231 .forest
232 .leaf_to_corresponding_tree(pos)
233 .ok_or(MmrError::PositionNotFound(pos))?;
234
235 if !self.tracked_leaves.contains(&pos) {
237 return Ok(None);
238 }
239
240 let leaf_idx = InOrderIndex::from_leaf_pos(pos);
242 let leaf = *self.nodes.get(&leaf_idx).expect("tracked leaf must have value in nodes");
243
244 let depth = tree_bit as usize;
246 let mut nodes = Vec::with_capacity(depth);
247 let mut idx = leaf_idx;
248
249 for _ in 0..depth {
250 let Some(node) = self.nodes.get(&idx.sibling()) else {
251 return Err(MmrError::InconsistentPartialMmr(format!(
252 "missing sibling for tracked leaf at position {pos}"
253 )));
254 };
255 nodes.push(*node);
256 idx = idx.parent();
257 }
258
259 let path = MmrPath::new(self.forest, pos, MerklePath::new(nodes));
260 Ok(Some(MmrProof::new(path, leaf)))
261 }
262
263 pub fn nodes(&self) -> impl Iterator<Item = (&InOrderIndex, &Word)> {
268 self.nodes.iter()
269 }
270
271 pub fn inner_nodes<'a, I: Iterator<Item = (usize, Word)> + 'a>(
276 &'a self,
277 mut leaves: I,
278 ) -> impl Iterator<Item = InnerNodeInfo> + 'a {
279 let stack = if let Some((pos, leaf)) = leaves.next() {
280 let idx = InOrderIndex::from_leaf_pos(pos);
281 vec![(idx, leaf)]
282 } else {
283 Vec::new()
284 };
285
286 InnerNodeIterator {
287 nodes: &self.nodes,
288 leaves,
289 stack,
290 seen_nodes: BTreeSet::new(),
291 }
292 }
293
294 pub fn add(&mut self, leaf: Word, track: bool) -> Result<Vec<(InOrderIndex, Word)>, MmrError> {
305 self.forest.append_leaf()?;
307 let num_merges = self.forest.smallest_tree_height_unchecked();
311 let mut new_nodes = Vec::with_capacity(num_merges + 1);
312
313 let leaf_pos = self.forest.num_leaves() - 1;
315 let leaf_idx = InOrderIndex::from_leaf_pos(leaf_pos);
316 if track {
317 self.tracked_leaves.insert(leaf_pos);
318 self.nodes.insert(leaf_idx, leaf);
319 new_nodes.push((leaf_idx, leaf));
320 }
321
322 let peak = if num_merges == 0 {
323 leaf
324 } else {
325 let mut track_right = track;
326 let prev_last_pos = self.forest.num_leaves() - 2;
329 let mut track_left = self.tracked_leaves.contains(&prev_last_pos);
330
331 let mut right = leaf;
332 let mut right_idx = self.forest.rightmost_in_order_index();
333
334 for _ in 0..num_merges {
335 let left = self.peaks.pop().expect("Missing peak");
336 let left_idx = right_idx.sibling();
337
338 if track_right {
339 let old = self.nodes.insert(left_idx, left);
340 debug_assert!(
343 old.is_none() || old == Some(left),
344 "Idx {left_idx:?} already contained a different element {old:?}",
345 );
346 if old.is_none() {
347 new_nodes.push((left_idx, left));
348 }
349 };
350 if track_left {
351 let old = self.nodes.insert(right_idx, right);
352 debug_assert!(
353 old.is_none() || old == Some(right),
354 "Idx {right_idx:?} already contained a different element {old:?}",
355 );
356 if old.is_none() {
357 new_nodes.push((right_idx, right));
358 }
359 };
360
361 right_idx = right_idx.parent();
366
367 right = Poseidon2::merge(&[left, right]);
370
371 track_right = track_right || track_left;
375
376 track_left = self.is_tracked_node(right_idx.sibling());
379 }
380 right
381 };
382
383 self.peaks.push(peak);
384
385 Ok(new_nodes)
386 }
387
388 pub fn track(
398 &mut self,
399 leaf_pos: usize,
400 leaf: Word,
401 path: &MerklePath,
402 ) -> Result<(), MmrError> {
403 let path_depth = path.depth();
406 let tree_leaves =
407 1usize.checked_shl(path_depth as u32).ok_or(MmrError::UnknownPeak(path_depth))?;
408 let tree = Forest::new(tree_leaves).map_err(|_| MmrError::UnknownPeak(path_depth))?;
409 if (tree & self.forest).is_empty() {
410 return Err(MmrError::UnknownPeak(path_depth));
411 };
412
413 let target_forest = self.forest ^ (self.forest & tree.all_smaller_trees_unchecked());
416 let peak_pos = target_forest.num_trees() - 1;
417
418 let path_idx = leaf_pos - (target_forest ^ tree).num_leaves();
420
421 let computed = path
424 .compute_root(path_idx as u64, leaf)
425 .map_err(MmrError::MerkleRootComputationFailed)?;
426 if self.peaks[peak_pos] != computed {
427 return Err(MmrError::PeakPathMismatch);
428 }
429
430 self.tracked_leaves.insert(leaf_pos);
432
433 let leaf_idx = InOrderIndex::from_leaf_pos(leaf_pos);
435 self.nodes.insert(leaf_idx, leaf);
436
437 let mut idx = leaf_idx;
439 for node in path.nodes() {
440 self.nodes.insert(idx.sibling(), *node);
441 idx = idx.parent();
442 }
443
444 Ok(())
445 }
446
447 pub fn untrack(&mut self, leaf_pos: usize) -> Vec<(InOrderIndex, Word)> {
456 self.tracked_leaves.remove(&leaf_pos);
458
459 let mut idx = InOrderIndex::from_leaf_pos(leaf_pos);
460 let mut removed = Vec::new();
461
462 let sibling_idx = idx.sibling();
465 let sibling_pos = sibling_idx.to_leaf_pos().expect("sibling of a leaf is always a leaf");
466 if self.tracked_leaves.contains(&sibling_pos) {
467 return removed;
470 }
471
472 let Some(rel_pos) = self.forest.leaf_relative_position(leaf_pos) else {
473 return removed;
475 };
476 let tree_start = leaf_pos - rel_pos;
477
478 if let Some(word) = self.nodes.remove(&idx) {
480 removed.push((idx, word));
481 }
482
483 loop {
485 let level = idx.level() as usize;
488 let subtree_size = 1usize << level;
489 let subtree_start_rel = (rel_pos >> level) << level;
490 let subtree_start = tree_start + subtree_start_rel;
491 let subtree_end = subtree_start + subtree_size;
492 if self.tracked_leaves.range(subtree_start..subtree_end).next().is_some() {
493 break;
494 }
495
496 let sibling_idx = idx.sibling();
497
498 let Some(word) = self.nodes.remove(&sibling_idx) else {
500 break;
501 };
502 removed.push((sibling_idx, word));
503
504 if self.nodes.contains_key(&idx) {
506 break;
507 }
508 idx = idx.parent();
509 }
510
511 removed
512 }
513
514 pub fn apply(&mut self, delta: MmrDelta) -> Result<Vec<(InOrderIndex, Word)>, MmrError> {
517 if delta.forest < self.forest {
518 return Err(MmrError::InvalidPeaks(format!(
519 "forest of mmr delta {} is less than current forest {}",
520 delta.forest, self.forest
521 )));
522 }
523
524 let mut inserted_nodes = Vec::new();
525
526 if delta.forest == self.forest {
527 if !delta.data.is_empty() {
528 return Err(MmrError::InvalidUpdate);
529 }
530
531 return Ok(inserted_nodes);
532 }
533
534 let changes = self.forest.num_leaves() ^ delta.forest.num_leaves();
536 let largest = super::forest::largest_tree_from_mask(changes);
539 let trees_to_merge = self.forest & largest.all_smaller_trees_unchecked();
541
542 let (merge_count, new_peaks) = if !trees_to_merge.is_empty() {
544 let depth = largest.smallest_tree_height_unchecked();
545 let skipped = trees_to_merge.smallest_tree_height_unchecked();
547 let computed = trees_to_merge.num_trees() - 1;
548 let merge_count = depth - skipped - computed;
549
550 let new_peaks = delta.forest & largest.all_smaller_trees_unchecked();
551
552 (merge_count, new_peaks)
553 } else {
554 let new_peaks = Forest::new(changes)
555 .expect("changes must be a valid forest under apply invariants");
556 (0, new_peaks)
557 };
558
559 if delta.data.len() != merge_count + new_peaks.num_trees() {
561 return Err(MmrError::InvalidUpdate);
562 }
563
564 let mut update_count = 0;
566
567 if !trees_to_merge.is_empty() {
568 let mut peak_idx = self.forest.root_in_order_index();
570
571 self.peaks.reverse();
573
574 let mut track = false;
575
576 let mut peak_count = 0;
577 let mut target = trees_to_merge.smallest_tree_unchecked();
578 let mut new = delta.data[0];
579 update_count += 1;
580
581 while target < largest {
582 if !track {
585 track = self.is_tracked_node(peak_idx);
586 }
587
588 let (left, right) = if !(target & trees_to_merge).is_empty() {
591 let peak = self.peaks[peak_count];
592 let sibling_idx = peak_idx.sibling();
593
594 if self.is_tracked_node(sibling_idx) {
597 self.nodes.insert(peak_idx, new);
598 inserted_nodes.push((peak_idx, new));
599 }
600 peak_count += 1;
601 (peak, new)
602 } else {
603 let update = delta.data[update_count];
604 update_count += 1;
605 (new, update)
606 };
607
608 if track {
609 let sibling_idx = peak_idx.sibling();
610 if peak_idx.is_left_child() {
611 self.nodes.insert(sibling_idx, right);
612 inserted_nodes.push((sibling_idx, right));
613 } else {
614 self.nodes.insert(sibling_idx, left);
615 inserted_nodes.push((sibling_idx, left));
616 }
617 }
618
619 peak_idx = peak_idx.parent();
620 new = Poseidon2::merge(&[left, right]);
621 target = target.next_larger_tree()?;
622 }
623
624 debug_assert!(peak_count == trees_to_merge.num_trees());
625
626 self.peaks.reverse();
628 self.peaks.truncate(self.peaks.len() - peak_count);
630 self.peaks.push(new);
632 }
633
634 self.peaks.extend_from_slice(&delta.data[update_count..]);
638 self.forest = delta.forest;
639
640 debug_assert!(self.peaks.len() == self.forest.num_trees());
641
642 Ok(inserted_nodes)
643 }
644
645 fn is_tracked_node(&self, node_index: InOrderIndex) -> bool {
651 if let Some(leaf_pos) = node_index.to_leaf_pos() {
652 self.tracked_leaves.contains(&leaf_pos)
654 } else {
655 let left_child = node_index.left_child();
656 let right_child = node_index.right_child();
657 self.nodes.contains_key(&left_child) | self.nodes.contains_key(&right_child)
658 }
659 }
660}
661
662impl From<MmrPeaks> for PartialMmr {
666 fn from(peaks: MmrPeaks) -> Self {
667 Self::from_peaks(peaks)
668 }
669}
670
671impl From<PartialMmr> for MmrPeaks {
672 fn from(partial_mmr: PartialMmr) -> Self {
673 MmrPeaks::new(partial_mmr.forest, partial_mmr.peaks).unwrap()
676 }
677}
678
679impl From<&MmrPeaks> for PartialMmr {
680 fn from(peaks: &MmrPeaks) -> Self {
681 Self::from_peaks(peaks.clone())
682 }
683}
684
685impl From<&PartialMmr> for MmrPeaks {
686 fn from(partial_mmr: &PartialMmr) -> Self {
687 MmrPeaks::new(partial_mmr.forest, partial_mmr.peaks.clone()).unwrap()
690 }
691}
692
693pub struct InnerNodeIterator<'a, I: Iterator<Item = (usize, Word)>> {
698 nodes: &'a NodeMap,
699 leaves: I,
700 stack: Vec<(InOrderIndex, Word)>,
701 seen_nodes: BTreeSet<InOrderIndex>,
702}
703
704impl<I: Iterator<Item = (usize, Word)>> Iterator for InnerNodeIterator<'_, I> {
705 type Item = InnerNodeInfo;
706
707 fn next(&mut self) -> Option<Self::Item> {
708 while let Some((idx, node)) = self.stack.pop() {
709 let parent_idx = idx.parent();
710 let new_node = self.seen_nodes.insert(parent_idx);
711
712 if new_node && let Some(sibling) = self.nodes.get(&idx.sibling()) {
715 let (left, right) = if parent_idx.left_child() == idx {
716 (node, *sibling)
717 } else {
718 (*sibling, node)
719 };
720 let parent = Poseidon2::merge(&[left, right]);
721 let inner_node = InnerNodeInfo { value: parent, left, right };
722
723 self.stack.push((parent_idx, parent));
724 return Some(inner_node);
725 }
726
727 if let Some((pos, leaf)) = self.leaves.next() {
729 let idx = InOrderIndex::from_leaf_pos(pos);
730 self.stack.push((idx, leaf));
731 }
732 }
733
734 None
735 }
736}
737
738impl Serializable for PartialMmr {
739 fn write_into<W: ByteWriter>(&self, target: &mut W) {
740 self.forest.num_leaves().write_into(target);
741 self.peaks.write_into(target);
742 self.nodes.write_into(target);
743 target.write_u8(Self::TRACKED_LEAVES_MARKER);
745 let tracked: Vec<usize> = self.tracked_leaves.iter().copied().collect();
746 tracked.write_into(target);
747 }
748}
749
750impl Deserializable for PartialMmr {
751 fn read_from<R: ByteReader>(
752 source: &mut R,
753 ) -> Result<Self, crate::utils::DeserializationError> {
754 use crate::utils::DeserializationError;
755
756 let forest = Forest::new(usize::read_from(source)?)?;
757 let peaks_vec = Vec::<Word>::read_from(source)?;
758 let nodes = NodeMap::read_from(source)?;
759 if !source.has_more_bytes() {
760 return Err(DeserializationError::UnexpectedEOF);
761 }
762 let marker = source.read_u8()?;
763 if marker != Self::TRACKED_LEAVES_MARKER {
764 return Err(DeserializationError::InvalidValue(
765 "unknown partial mmr serialization format".to_string(),
766 ));
767 }
768 let tracked: Vec<usize> = Vec::read_from(source)?;
769 let tracked_leaves: BTreeSet<usize> = tracked.into_iter().collect();
770
771 let peaks = MmrPeaks::new(forest, peaks_vec).map_err(|e| {
773 DeserializationError::InvalidValue(format!("invalid partial mmr peaks: {e}"))
774 })?;
775
776 Self::from_parts(peaks, nodes, tracked_leaves)
778 .map_err(|e| DeserializationError::InvalidValue(format!("invalid partial mmr: {e}")))
779 }
780}
781
782#[cfg(test)]
786mod tests {
787 use alloc::{
788 collections::{BTreeMap, BTreeSet},
789 vec::Vec,
790 };
791
792 use super::{MmrPeaks, PartialMmr};
793 use crate::{
794 Word,
795 merkle::{
796 NodeIndex, int_to_node,
797 mmr::{InOrderIndex, Mmr, forest::Forest},
798 store::MerkleStore,
799 },
800 utils::{ByteWriter, Deserializable, DeserializationError, Serializable},
801 };
802
803 const LEAVES: [Word; 7] = [
804 int_to_node(0),
805 int_to_node(1),
806 int_to_node(2),
807 int_to_node(3),
808 int_to_node(4),
809 int_to_node(5),
810 int_to_node(6),
811 ];
812
813 #[test]
814 fn test_partial_mmr_apply_delta() {
815 let mut mmr = Mmr::default();
817 (0..10).for_each(|i| mmr.add(int_to_node(i)).unwrap());
818 let mut partial_mmr: PartialMmr = mmr.peaks().into();
819
820 {
822 let node = mmr.get(1).unwrap();
823 let proof = mmr.open(1).unwrap();
824 partial_mmr.track(1, node, proof.path().merkle_path()).unwrap();
825 }
826
827 {
828 let node = mmr.get(8).unwrap();
829 let proof = mmr.open(8).unwrap();
830 partial_mmr.track(8, node, proof.path().merkle_path()).unwrap();
831 }
832
833 (10..12).for_each(|i| mmr.add(int_to_node(i)).unwrap());
835 validate_apply_delta(&mmr, &mut partial_mmr);
836
837 mmr.add(int_to_node(12)).unwrap();
839 validate_apply_delta(&mmr, &mut partial_mmr);
840 {
841 let node = mmr.get(12).unwrap();
842 let proof = mmr.open(12).unwrap();
843 partial_mmr.track(12, node, proof.path().merkle_path()).unwrap();
844 assert!(partial_mmr.is_tracked(12));
846 }
847
848 (13..16).for_each(|i| mmr.add(int_to_node(i)).unwrap());
852 validate_apply_delta(&mmr, &mut partial_mmr);
853 }
854
855 fn validate_apply_delta(mmr: &Mmr, partial: &mut PartialMmr) {
856 let tracked_positions: Vec<_> = partial.tracked_leaves.iter().copied().collect();
858 let nodes_before = partial.nodes.clone();
859
860 let delta = mmr.get_delta(partial.forest(), mmr.forest()).unwrap();
862 let nodes_delta = partial.apply(delta).unwrap();
863
864 assert_eq!(mmr.peaks(), partial.peaks());
866
867 let mut expected_nodes = nodes_before;
868 for (key, value) in nodes_delta {
869 assert!(expected_nodes.insert(key, value).is_none());
871 }
872
873 assert_eq!(expected_nodes, partial.nodes);
875
876 for pos in tracked_positions {
878 let proof1 = partial.open(pos).unwrap().unwrap();
879 let proof2 = mmr.open(pos).unwrap();
880 assert_eq!(proof1, proof2);
881 }
882 }
883
884 #[test]
885 fn test_partial_mmr_inner_nodes_iterator() {
886 let mmr = Mmr::try_from_iter(LEAVES.iter().copied()).unwrap();
888 let first_peak = mmr.peaks().peaks()[0];
889
890 let node1 = mmr.get(1).unwrap();
894 let proof1 = mmr.open(1).unwrap();
895
896 let mut partial_mmr: PartialMmr = mmr.peaks().into();
898 partial_mmr.track(1, node1, proof1.path().merkle_path()).unwrap();
899
900 assert_eq!(partial_mmr.inner_nodes([].iter().cloned()).next(), None);
902
903 let mut store: MerkleStore = MerkleStore::new();
905 store.extend(partial_mmr.inner_nodes([(1, node1)].iter().cloned()));
906
907 let index1 = NodeIndex::new(2, 1).unwrap();
908 let path1 = store.get_path(first_peak, index1).unwrap().path;
909
910 assert_eq!(path1, *proof1.path().merkle_path());
911
912 let mut partial_mmr: PartialMmr = mmr.peaks().into();
916
917 let node0 = mmr.get(0).unwrap();
918 let proof0 = mmr.open(0).unwrap();
919
920 let node2 = mmr.get(2).unwrap();
921 let proof2 = mmr.open(2).unwrap();
922
923 partial_mmr.track(0, node0, proof0.path().merkle_path()).unwrap();
924 partial_mmr.track(1, node1, proof1.path().merkle_path()).unwrap();
925 partial_mmr.track(2, node2, proof2.path().merkle_path()).unwrap();
926
927 let leaves = [(0, node0), (1, node1), (2, node2)];
929 let mut nodes = BTreeSet::new();
930 for node in partial_mmr.inner_nodes(leaves.iter().cloned()) {
931 assert!(nodes.insert(node.value));
932 }
933
934 store.extend(partial_mmr.inner_nodes(leaves.iter().cloned()));
936
937 let index0 = NodeIndex::new(2, 0).unwrap();
938 let index1 = NodeIndex::new(2, 1).unwrap();
939 let index2 = NodeIndex::new(2, 2).unwrap();
940
941 let path0 = store.get_path(first_peak, index0).unwrap().path;
942 let path1 = store.get_path(first_peak, index1).unwrap().path;
943 let path2 = store.get_path(first_peak, index2).unwrap().path;
944
945 assert_eq!(path0, *proof0.path().merkle_path());
946 assert_eq!(path1, *proof1.path().merkle_path());
947 assert_eq!(path2, *proof2.path().merkle_path());
948
949 let mut partial_mmr: PartialMmr = mmr.peaks().into();
953
954 let node5 = mmr.get(5).unwrap();
955 let proof5 = mmr.open(5).unwrap();
956
957 partial_mmr.track(1, node1, proof1.path().merkle_path()).unwrap();
958 partial_mmr.track(5, node5, proof5.path().merkle_path()).unwrap();
959
960 let mut store: MerkleStore = MerkleStore::new();
962 store.extend(partial_mmr.inner_nodes([(1, node1), (5, node5)].iter().cloned()));
963
964 let index1 = NodeIndex::new(2, 1).unwrap();
965 let index5 = NodeIndex::new(1, 1).unwrap();
966
967 let second_peak = mmr.peaks().peaks()[1];
968
969 let path1 = store.get_path(first_peak, index1).unwrap().path;
970 let path5 = store.get_path(second_peak, index5).unwrap().path;
971
972 assert_eq!(path1, *proof1.path().merkle_path());
973 assert_eq!(path5, *proof5.path().merkle_path());
974 }
975
976 #[test]
977 fn test_partial_mmr_add_without_track() {
978 let mut mmr = Mmr::default();
979 let empty_peaks = MmrPeaks::new(Forest::empty(), vec![]).unwrap();
980 let mut partial_mmr = PartialMmr::from_peaks(empty_peaks);
981
982 for el in (0..256).map(int_to_node) {
983 mmr.add(el).unwrap();
984 partial_mmr.add(el, false).unwrap();
985
986 assert_eq!(mmr.peaks(), partial_mmr.peaks());
987 assert_eq!(mmr.forest(), partial_mmr.forest());
988 }
989 }
990
991 #[test]
992 fn test_partial_mmr_add_with_track() {
993 let mut mmr = Mmr::default();
994 let empty_peaks = MmrPeaks::new(Forest::empty(), vec![]).unwrap();
995 let mut partial_mmr = PartialMmr::from_peaks(empty_peaks);
996
997 for i in 0..256 {
998 let el = int_to_node(i as u64);
999 mmr.add(el).unwrap();
1000 partial_mmr.add(el, true).unwrap();
1001
1002 assert_eq!(mmr.peaks(), partial_mmr.peaks());
1003 assert_eq!(mmr.forest(), partial_mmr.forest());
1004
1005 for pos in 0..i {
1006 let mmr_proof = mmr.open(pos).unwrap();
1007 let partialmmr_proof = partial_mmr.open(pos).unwrap().unwrap();
1008 assert_eq!(mmr_proof, partialmmr_proof);
1009 }
1010 }
1011 }
1012
1013 #[test]
1014 fn test_partial_mmr_add_existing_track() {
1015 let mut mmr = Mmr::try_from_iter((0..7).map(int_to_node)).unwrap();
1016
1017 let mut partial_mmr = PartialMmr::from_peaks(mmr.peaks());
1019 let path_to_5 = mmr.open(5).unwrap().path().merkle_path().clone();
1020 let leaf_at_5 = mmr.get(5).unwrap();
1021 partial_mmr.track(5, leaf_at_5, &path_to_5).unwrap();
1022
1023 let leaf_at_7 = int_to_node(7);
1025 mmr.add(leaf_at_7).unwrap();
1026 partial_mmr.add(leaf_at_7, false).unwrap();
1027
1028 assert_eq!(mmr.open(5).unwrap(), partial_mmr.open(5).unwrap().unwrap());
1030 }
1031
1032 #[test]
1033 fn test_partial_mmr_add_updates_tracked_dangling_leaf() {
1034 let mut mmr = Mmr::default();
1037 let mut partial_mmr = PartialMmr::default();
1038
1039 let leaf0 = int_to_node(0);
1041 mmr.add(leaf0).unwrap();
1042 partial_mmr.add(leaf0, true).unwrap();
1043
1044 assert_eq!(mmr.open(0).unwrap(), partial_mmr.open(0).unwrap().unwrap());
1046
1047 let leaf1 = int_to_node(1);
1049 mmr.add(leaf1).unwrap();
1050 partial_mmr.add(leaf1, false).unwrap();
1051
1052 assert!(partial_mmr.is_tracked(0));
1054 assert!(!partial_mmr.is_tracked(1));
1055 assert_eq!(mmr.open(0).unwrap(), partial_mmr.open(0).unwrap().unwrap());
1056 }
1057
1058 #[test]
1059 fn test_partial_mmr_serialization() {
1060 let mmr = Mmr::try_from_iter((0..7).map(int_to_node)).unwrap();
1061 let partial_mmr = PartialMmr::from_peaks(mmr.peaks());
1062
1063 let bytes = partial_mmr.to_bytes();
1064 let decoded = PartialMmr::read_from_bytes(&bytes).unwrap();
1065
1066 assert_eq!(partial_mmr, decoded);
1067 }
1068
1069 #[test]
1070 fn test_partial_mmr_deserialization_rejects_large_forest() {
1071 let mut bytes = (Forest::MAX_LEAVES + 1).to_bytes();
1072 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);
1077 assert!(matches!(result, Err(DeserializationError::InvalidValue(_))));
1078 }
1079
1080 #[test]
1081 fn test_partial_mmr_untrack() {
1082 let mmr = Mmr::try_from_iter(LEAVES.iter().copied()).unwrap();
1084
1085 let node1 = mmr.get(1).unwrap();
1087 let proof1 = mmr.open(1).unwrap();
1088
1089 let node2 = mmr.get(2).unwrap();
1091 let proof2 = mmr.open(2).unwrap();
1092
1093 let mut partial_mmr: PartialMmr = mmr.peaks().into();
1095 partial_mmr.track(1, node1, proof1.path().merkle_path()).unwrap();
1096 partial_mmr.track(2, node2, proof2.path().merkle_path()).unwrap();
1097
1098 partial_mmr.untrack(1);
1100 partial_mmr.untrack(2);
1101
1102 assert!(!partial_mmr.is_tracked(1));
1104 assert!(!partial_mmr.is_tracked(2));
1105 assert_eq!(partial_mmr.nodes().count(), 0);
1106 }
1107
1108 #[test]
1109 fn test_partial_mmr_untrack_returns_removed_nodes() {
1110 let mmr = Mmr::try_from_iter(LEAVES.iter().copied()).unwrap();
1112
1113 let node1 = mmr.get(1).unwrap();
1115 let proof1 = mmr.open(1).unwrap();
1116
1117 let mut partial_mmr: PartialMmr = mmr.peaks().into();
1119
1120 partial_mmr.track(1, node1, proof1.path().merkle_path()).unwrap();
1122
1123 let nodes_before: BTreeSet<_> =
1125 partial_mmr.nodes().map(|(&idx, &word)| (idx, word)).collect();
1126
1127 let removed: BTreeSet<_> = partial_mmr.untrack(1).into_iter().collect();
1129
1130 assert_eq!(removed, nodes_before);
1132
1133 assert!(!partial_mmr.is_tracked(1));
1135 assert_eq!(partial_mmr.nodes().count(), 0);
1136 }
1137
1138 #[test]
1139 fn test_partial_mmr_untrack_shared_nodes() {
1140 let mmr = Mmr::try_from_iter(LEAVES.iter().copied()).unwrap();
1142
1143 let node0 = mmr.get(0).unwrap();
1145 let proof0 = mmr.open(0).unwrap();
1146
1147 let node1 = mmr.get(1).unwrap();
1148 let proof1 = mmr.open(1).unwrap();
1149
1150 let mut partial_mmr: PartialMmr = mmr.peaks().into();
1152
1153 partial_mmr.track(0, node0, proof0.path().merkle_path()).unwrap();
1155 partial_mmr.track(1, node1, proof1.path().merkle_path()).unwrap();
1156
1157 assert_eq!(partial_mmr.nodes().count(), 3);
1166
1167 let removed0 = partial_mmr.untrack(0);
1173 assert_eq!(removed0.len(), 0);
1174 assert_eq!(partial_mmr.nodes().count(), 3);
1175 assert!(partial_mmr.is_tracked(1));
1176 assert!(!partial_mmr.is_tracked(0));
1177
1178 let removed1 = partial_mmr.untrack(1);
1184 assert_eq!(removed1.len(), 3);
1185 assert_eq!(partial_mmr.nodes().count(), 0);
1186 assert!(!partial_mmr.is_tracked(1));
1187 }
1188
1189 #[test]
1190 fn test_partial_mmr_untrack_preserves_upper_siblings() {
1191 let mut mmr = Mmr::default();
1192 (0..8).for_each(|i| mmr.add(int_to_node(i)).unwrap());
1193
1194 let mut partial_mmr: PartialMmr = mmr.peaks().into();
1195 for pos in [0, 2] {
1196 let node = mmr.get(pos).unwrap();
1197 let proof = mmr.open(pos).unwrap();
1198 partial_mmr.track(pos, node, proof.path().merkle_path()).unwrap();
1199 }
1200
1201 partial_mmr.untrack(0);
1202
1203 let proof_partial = partial_mmr.open(2).unwrap().unwrap();
1204 let proof_full = mmr.open(2).unwrap();
1205 assert_eq!(proof_partial, proof_full);
1206 }
1207
1208 #[test]
1209 fn test_partial_mmr_deserialize_missing_marker_fails() {
1210 let mut mmr = Mmr::default();
1211 (0..3).for_each(|i| mmr.add(int_to_node(i)).unwrap());
1212 let peaks = mmr.peaks();
1213
1214 let mut bytes = Vec::new();
1215 peaks.num_leaves().write_into(&mut bytes);
1216 peaks.peaks().to_vec().write_into(&mut bytes);
1217 BTreeMap::<InOrderIndex, Word>::new().write_into(&mut bytes);
1218 assert!(PartialMmr::read_from_bytes(&bytes).is_err());
1219 }
1220
1221 #[test]
1222 fn test_partial_mmr_deserialize_invalid_marker_fails() {
1223 let mut mmr = Mmr::default();
1224 (0..3).for_each(|i| mmr.add(int_to_node(i)).unwrap());
1225 let peaks = mmr.peaks();
1226
1227 let mut bytes = Vec::new();
1228 peaks.num_leaves().write_into(&mut bytes);
1229 peaks.peaks().to_vec().write_into(&mut bytes);
1230 BTreeMap::<InOrderIndex, Word>::new().write_into(&mut bytes);
1231 bytes.write_u8(0x7f);
1232 Vec::<usize>::new().write_into(&mut bytes);
1233
1234 assert!(PartialMmr::read_from_bytes(&bytes).is_err());
1235 }
1236
1237 #[test]
1238 fn test_partial_mmr_open_returns_proof_with_leaf() {
1239 let mmr = Mmr::try_from_iter(LEAVES.iter().copied()).unwrap();
1241
1242 let leaf1 = mmr.get(1).unwrap();
1244 let mmr_proof = mmr.open(1).unwrap();
1245
1246 let mut partial_mmr: PartialMmr = mmr.peaks().into();
1248 partial_mmr.track(1, leaf1, mmr_proof.path().merkle_path()).unwrap();
1249
1250 let partial_proof = partial_mmr.open(1).unwrap().unwrap();
1252 assert_eq!(partial_proof.leaf(), leaf1);
1253 assert_eq!(partial_proof, mmr_proof);
1254
1255 partial_mmr.untrack(1);
1257 assert!(partial_mmr.open(1).unwrap().is_none());
1258 }
1259
1260 #[test]
1261 fn test_partial_mmr_add_tracks_leaf() {
1262 let mut partial_mmr = PartialMmr::default();
1264
1265 let leaf0 = int_to_node(0);
1267 let leaf1 = int_to_node(1);
1268 let leaf2 = int_to_node(2);
1269
1270 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();
1276 assert!(proof0.is_some());
1277 assert_eq!(proof0.unwrap().leaf(), leaf0);
1278
1279 let proof1 = partial_mmr.open(1).unwrap();
1281 assert!(proof1.is_none());
1282
1283 let proof2 = partial_mmr.open(2).unwrap();
1285 assert!(proof2.is_some());
1286 assert_eq!(proof2.unwrap().leaf(), leaf2);
1287
1288 assert_eq!(partial_mmr.get(0), Some(leaf0));
1290 assert_eq!(partial_mmr.get(1), None);
1291 assert_eq!(partial_mmr.get(2), Some(leaf2));
1292
1293 let tracked: Vec<_> = partial_mmr.leaves().collect();
1295 assert_eq!(tracked, vec![(0, leaf0), (2, leaf2)]);
1296 }
1297
1298 #[test]
1299 fn test_partial_mmr_track_dangling_leaf() {
1300 let mut mmr = Mmr::default();
1302 mmr.add(int_to_node(0)).unwrap();
1303 let mut partial_mmr: PartialMmr = mmr.peaks().into();
1304
1305 let leaf0 = mmr.get(0).unwrap();
1306 let proof0 = mmr.open(0).unwrap();
1308
1309 partial_mmr.track(0, leaf0, proof0.path().merkle_path()).unwrap();
1311
1312 assert!(partial_mmr.is_tracked(0));
1314 assert_eq!(partial_mmr.open(0).unwrap().unwrap(), proof0);
1315 }
1316
1317 #[test]
1318 fn test_from_parts_validation() {
1319 use alloc::collections::BTreeMap;
1320
1321 use super::InOrderIndex;
1322
1323 let mmr = Mmr::try_from_iter(LEAVES.iter().copied()).unwrap();
1325 let peaks = mmr.peaks();
1326
1327 let result = PartialMmr::from_parts(peaks.clone(), BTreeMap::new(), BTreeSet::new());
1329 assert!(result.is_ok());
1330
1331 let mut out_of_bounds = BTreeSet::new();
1333 out_of_bounds.insert(100);
1334 let result = PartialMmr::from_parts(peaks.clone(), BTreeMap::new(), out_of_bounds);
1335 assert!(result.is_err());
1336
1337 let mut tracked_no_value = BTreeSet::new();
1339 tracked_no_value.insert(0);
1340 let result = PartialMmr::from_parts(peaks.clone(), BTreeMap::new(), tracked_no_value);
1341 assert!(result.is_err());
1342
1343 let mut nodes_with_leaf = BTreeMap::new();
1345 let leaf_idx = InOrderIndex::from_leaf_pos(0);
1346 nodes_with_leaf.insert(leaf_idx, int_to_node(0));
1347 let mut tracked_valid = BTreeSet::new();
1348 tracked_valid.insert(0);
1349 let result = PartialMmr::from_parts(peaks.clone(), nodes_with_leaf, tracked_valid);
1350 assert!(result.is_ok());
1351
1352 let mut invalid_nodes = BTreeMap::new();
1354 let invalid_idx = InOrderIndex::from_leaf_pos(100); invalid_nodes.insert(invalid_idx, int_to_node(0));
1356 let result = PartialMmr::from_parts(peaks.clone(), invalid_nodes, BTreeSet::new());
1357 assert!(result.is_err());
1358
1359 let mut nodes_with_zero = BTreeMap::new();
1361 let zero_idx = InOrderIndex::read_from_bytes(&0usize.to_bytes()).unwrap();
1363 nodes_with_zero.insert(zero_idx, int_to_node(0));
1364 let result = PartialMmr::from_parts(peaks.clone(), nodes_with_zero, BTreeSet::new());
1365 assert!(result.is_err());
1366
1367 let mut nodes_with_large_even = BTreeMap::new();
1369 let large_even_idx = InOrderIndex::read_from_bytes(&1000usize.to_bytes()).unwrap();
1370 nodes_with_large_even.insert(large_even_idx, int_to_node(0));
1371 let result = PartialMmr::from_parts(peaks.clone(), nodes_with_large_even, BTreeSet::new());
1372 assert!(result.is_err());
1373
1374 let mut nodes_with_separator = BTreeMap::new();
1379 let separator_idx = InOrderIndex::read_from_bytes(&8usize.to_bytes()).unwrap();
1380 nodes_with_separator.insert(separator_idx, int_to_node(0));
1381 let result = PartialMmr::from_parts(peaks.clone(), nodes_with_separator, BTreeSet::new());
1382 assert!(result.is_err(), "separator index 8 should be rejected");
1383
1384 let mut nodes_with_separator_12 = BTreeMap::new();
1385 let separator_idx_12 = InOrderIndex::read_from_bytes(&12usize.to_bytes()).unwrap();
1386 nodes_with_separator_12.insert(separator_idx_12, int_to_node(0));
1387 let result = PartialMmr::from_parts(peaks, nodes_with_separator_12, BTreeSet::new());
1388 assert!(result.is_err(), "separator index 12 should be rejected");
1389
1390 let empty_peaks = MmrPeaks::new(Forest::empty(), vec![]).unwrap();
1392 let mut nodes_with_empty_forest = BTreeMap::new();
1393 nodes_with_empty_forest.insert(InOrderIndex::from_leaf_pos(0), int_to_node(0));
1394 let result = PartialMmr::from_parts(empty_peaks, nodes_with_empty_forest, BTreeSet::new());
1395 assert!(result.is_err());
1396 }
1397
1398 #[test]
1399 fn test_from_parts_validation_deserialization() {
1400 let mmr = Mmr::try_from_iter(LEAVES.iter().copied()).unwrap();
1402 let partial_mmr = PartialMmr::from_peaks(mmr.peaks());
1403
1404 let bytes = partial_mmr.to_bytes();
1406 let decoded = PartialMmr::read_from_bytes(&bytes);
1407 assert!(decoded.is_ok());
1408
1409 let mut partial_with_node = PartialMmr::from_peaks(mmr.peaks());
1414 let node = mmr.get(1).unwrap();
1415 let proof = mmr.open(1).unwrap();
1416 partial_with_node.track(1, node, proof.path().merkle_path()).unwrap();
1417
1418 let valid_bytes = partial_with_node.to_bytes();
1420 let valid_decoded = PartialMmr::read_from_bytes(&valid_bytes);
1421 assert!(valid_decoded.is_ok());
1422
1423 let mut bad_bytes = Vec::new();
1426 bad_bytes.extend_from_slice(&7usize.to_bytes());
1428 bad_bytes.extend_from_slice(&3usize.to_bytes()); for i in 0..3 {
1431 bad_bytes.extend_from_slice(&int_to_node(i as u64).to_bytes());
1432 }
1433 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());
1439
1440 let result = PartialMmr::read_from_bytes(&bad_bytes);
1441 assert!(result.is_err());
1442 }
1443
1444 #[test]
1445 fn test_from_parts_unchecked() {
1446 use alloc::collections::BTreeMap;
1447
1448 let mmr = Mmr::try_from_iter(LEAVES.iter().copied()).unwrap();
1450 let peaks = mmr.peaks();
1451
1452 let partial =
1454 PartialMmr::from_parts_unchecked(peaks.clone(), BTreeMap::new(), BTreeSet::new());
1455 assert_eq!(partial.forest(), peaks.forest());
1456
1457 let mut invalid_tracked = BTreeSet::new();
1459 invalid_tracked.insert(999);
1460 let partial = PartialMmr::from_parts_unchecked(peaks, BTreeMap::new(), invalid_tracked);
1461 assert!(partial.tracked_leaves.contains(&999));
1462 }
1463}