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 mut tracked_leaves = BTreeSet::new();
770 for leaf_pos in tracked {
771 if !tracked_leaves.insert(leaf_pos) {
772 return Err(DeserializationError::InvalidValue(
773 "duplicate tracked leaf in partial mmr encoding".to_string(),
774 ));
775 }
776 }
777
778 let peaks = MmrPeaks::new(forest, peaks_vec).map_err(|e| {
780 DeserializationError::InvalidValue(format!("invalid partial mmr peaks: {e}"))
781 })?;
782
783 Self::from_parts(peaks, nodes, tracked_leaves)
785 .map_err(|e| DeserializationError::InvalidValue(format!("invalid partial mmr: {e}")))
786 }
787}
788
789#[cfg(test)]
793mod tests {
794 use alloc::{
795 collections::{BTreeMap, BTreeSet},
796 vec::Vec,
797 };
798
799 use super::{MmrPeaks, PartialMmr};
800 use crate::{
801 Word,
802 merkle::{
803 NodeIndex, int_to_node,
804 mmr::{InOrderIndex, Mmr, forest::Forest},
805 store::MerkleStore,
806 },
807 utils::{ByteWriter, Deserializable, DeserializationError, Serializable},
808 };
809
810 const LEAVES: [Word; 7] = [
811 int_to_node(0),
812 int_to_node(1),
813 int_to_node(2),
814 int_to_node(3),
815 int_to_node(4),
816 int_to_node(5),
817 int_to_node(6),
818 ];
819
820 #[test]
821 fn test_partial_mmr_apply_delta() {
822 let mut mmr = Mmr::default();
824 (0..10).for_each(|i| mmr.add(int_to_node(i)).unwrap());
825 let mut partial_mmr: PartialMmr = mmr.peaks().into();
826
827 {
829 let node = mmr.get(1).unwrap();
830 let proof = mmr.open(1).unwrap();
831 partial_mmr.track(1, node, proof.path().merkle_path()).unwrap();
832 }
833
834 {
835 let node = mmr.get(8).unwrap();
836 let proof = mmr.open(8).unwrap();
837 partial_mmr.track(8, node, proof.path().merkle_path()).unwrap();
838 }
839
840 (10..12).for_each(|i| mmr.add(int_to_node(i)).unwrap());
842 validate_apply_delta(&mmr, &mut partial_mmr);
843
844 mmr.add(int_to_node(12)).unwrap();
846 validate_apply_delta(&mmr, &mut partial_mmr);
847 {
848 let node = mmr.get(12).unwrap();
849 let proof = mmr.open(12).unwrap();
850 partial_mmr.track(12, node, proof.path().merkle_path()).unwrap();
851 assert!(partial_mmr.is_tracked(12));
853 }
854
855 (13..16).for_each(|i| mmr.add(int_to_node(i)).unwrap());
859 validate_apply_delta(&mmr, &mut partial_mmr);
860 }
861
862 fn validate_apply_delta(mmr: &Mmr, partial: &mut PartialMmr) {
863 let tracked_positions: Vec<_> = partial.tracked_leaves.iter().copied().collect();
865 let nodes_before = partial.nodes.clone();
866
867 let delta = mmr.get_delta(partial.forest(), mmr.forest()).unwrap();
869 let nodes_delta = partial.apply(delta).unwrap();
870
871 assert_eq!(mmr.peaks(), partial.peaks());
873
874 let mut expected_nodes = nodes_before;
875 for (key, value) in nodes_delta {
876 assert!(expected_nodes.insert(key, value).is_none());
878 }
879
880 assert_eq!(expected_nodes, partial.nodes);
882
883 for pos in tracked_positions {
885 let proof1 = partial.open(pos).unwrap().unwrap();
886 let proof2 = mmr.open(pos).unwrap();
887 assert_eq!(proof1, proof2);
888 }
889 }
890
891 #[test]
892 fn test_partial_mmr_inner_nodes_iterator() {
893 let mmr = Mmr::try_from_iter(LEAVES.iter().copied()).unwrap();
895 let first_peak = mmr.peaks().peaks()[0];
896
897 let node1 = mmr.get(1).unwrap();
901 let proof1 = mmr.open(1).unwrap();
902
903 let mut partial_mmr: PartialMmr = mmr.peaks().into();
905 partial_mmr.track(1, node1, proof1.path().merkle_path()).unwrap();
906
907 assert_eq!(partial_mmr.inner_nodes([].iter().cloned()).next(), None);
909
910 let mut store: MerkleStore = MerkleStore::new();
912 store.extend(partial_mmr.inner_nodes([(1, node1)].iter().cloned()));
913
914 let index1 = NodeIndex::new(2, 1).unwrap();
915 let path1 = store.get_path(first_peak, index1).unwrap().path;
916
917 assert_eq!(path1, *proof1.path().merkle_path());
918
919 let mut partial_mmr: PartialMmr = mmr.peaks().into();
923
924 let node0 = mmr.get(0).unwrap();
925 let proof0 = mmr.open(0).unwrap();
926
927 let node2 = mmr.get(2).unwrap();
928 let proof2 = mmr.open(2).unwrap();
929
930 partial_mmr.track(0, node0, proof0.path().merkle_path()).unwrap();
931 partial_mmr.track(1, node1, proof1.path().merkle_path()).unwrap();
932 partial_mmr.track(2, node2, proof2.path().merkle_path()).unwrap();
933
934 let leaves = [(0, node0), (1, node1), (2, node2)];
936 let mut nodes = BTreeSet::new();
937 for node in partial_mmr.inner_nodes(leaves.iter().cloned()) {
938 assert!(nodes.insert(node.value));
939 }
940
941 store.extend(partial_mmr.inner_nodes(leaves.iter().cloned()));
943
944 let index0 = NodeIndex::new(2, 0).unwrap();
945 let index1 = NodeIndex::new(2, 1).unwrap();
946 let index2 = NodeIndex::new(2, 2).unwrap();
947
948 let path0 = store.get_path(first_peak, index0).unwrap().path;
949 let path1 = store.get_path(first_peak, index1).unwrap().path;
950 let path2 = store.get_path(first_peak, index2).unwrap().path;
951
952 assert_eq!(path0, *proof0.path().merkle_path());
953 assert_eq!(path1, *proof1.path().merkle_path());
954 assert_eq!(path2, *proof2.path().merkle_path());
955
956 let mut partial_mmr: PartialMmr = mmr.peaks().into();
960
961 let node5 = mmr.get(5).unwrap();
962 let proof5 = mmr.open(5).unwrap();
963
964 partial_mmr.track(1, node1, proof1.path().merkle_path()).unwrap();
965 partial_mmr.track(5, node5, proof5.path().merkle_path()).unwrap();
966
967 let mut store: MerkleStore = MerkleStore::new();
969 store.extend(partial_mmr.inner_nodes([(1, node1), (5, node5)].iter().cloned()));
970
971 let index1 = NodeIndex::new(2, 1).unwrap();
972 let index5 = NodeIndex::new(1, 1).unwrap();
973
974 let second_peak = mmr.peaks().peaks()[1];
975
976 let path1 = store.get_path(first_peak, index1).unwrap().path;
977 let path5 = store.get_path(second_peak, index5).unwrap().path;
978
979 assert_eq!(path1, *proof1.path().merkle_path());
980 assert_eq!(path5, *proof5.path().merkle_path());
981 }
982
983 #[test]
984 fn test_partial_mmr_add_without_track() {
985 let mut mmr = Mmr::default();
986 let empty_peaks = MmrPeaks::new(Forest::empty(), vec![]).unwrap();
987 let mut partial_mmr = PartialMmr::from_peaks(empty_peaks);
988
989 for el in (0..256).map(int_to_node) {
990 mmr.add(el).unwrap();
991 partial_mmr.add(el, false).unwrap();
992
993 assert_eq!(mmr.peaks(), partial_mmr.peaks());
994 assert_eq!(mmr.forest(), partial_mmr.forest());
995 }
996 }
997
998 #[test]
999 fn test_partial_mmr_add_with_track() {
1000 let mut mmr = Mmr::default();
1001 let empty_peaks = MmrPeaks::new(Forest::empty(), vec![]).unwrap();
1002 let mut partial_mmr = PartialMmr::from_peaks(empty_peaks);
1003
1004 for i in 0..256 {
1005 let el = int_to_node(i as u64);
1006 mmr.add(el).unwrap();
1007 partial_mmr.add(el, true).unwrap();
1008
1009 assert_eq!(mmr.peaks(), partial_mmr.peaks());
1010 assert_eq!(mmr.forest(), partial_mmr.forest());
1011
1012 for pos in 0..i {
1013 let mmr_proof = mmr.open(pos).unwrap();
1014 let partialmmr_proof = partial_mmr.open(pos).unwrap().unwrap();
1015 assert_eq!(mmr_proof, partialmmr_proof);
1016 }
1017 }
1018 }
1019
1020 #[test]
1021 fn test_partial_mmr_add_existing_track() {
1022 let mut mmr = Mmr::try_from_iter((0..7).map(int_to_node)).unwrap();
1023
1024 let mut partial_mmr = PartialMmr::from_peaks(mmr.peaks());
1026 let path_to_5 = mmr.open(5).unwrap().path().merkle_path().clone();
1027 let leaf_at_5 = mmr.get(5).unwrap();
1028 partial_mmr.track(5, leaf_at_5, &path_to_5).unwrap();
1029
1030 let leaf_at_7 = int_to_node(7);
1032 mmr.add(leaf_at_7).unwrap();
1033 partial_mmr.add(leaf_at_7, false).unwrap();
1034
1035 assert_eq!(mmr.open(5).unwrap(), partial_mmr.open(5).unwrap().unwrap());
1037 }
1038
1039 #[test]
1040 fn test_partial_mmr_add_updates_tracked_dangling_leaf() {
1041 let mut mmr = Mmr::default();
1044 let mut partial_mmr = PartialMmr::default();
1045
1046 let leaf0 = int_to_node(0);
1048 mmr.add(leaf0).unwrap();
1049 partial_mmr.add(leaf0, true).unwrap();
1050
1051 assert_eq!(mmr.open(0).unwrap(), partial_mmr.open(0).unwrap().unwrap());
1053
1054 let leaf1 = int_to_node(1);
1056 mmr.add(leaf1).unwrap();
1057 partial_mmr.add(leaf1, false).unwrap();
1058
1059 assert!(partial_mmr.is_tracked(0));
1061 assert!(!partial_mmr.is_tracked(1));
1062 assert_eq!(mmr.open(0).unwrap(), partial_mmr.open(0).unwrap().unwrap());
1063 }
1064
1065 #[test]
1066 fn test_partial_mmr_serialization() {
1067 let mmr = Mmr::try_from_iter((0..7).map(int_to_node)).unwrap();
1068 let partial_mmr = PartialMmr::from_peaks(mmr.peaks());
1069
1070 let bytes = partial_mmr.to_bytes();
1071 let decoded = PartialMmr::read_from_bytes(&bytes).unwrap();
1072
1073 assert_eq!(partial_mmr, decoded);
1074 }
1075
1076 #[test]
1077 fn test_partial_mmr_deserialization_rejects_duplicate_tracked_leaves() {
1078 let mmr = Mmr::try_from_iter(LEAVES.iter().copied()).unwrap();
1079 let mut partial_mmr = PartialMmr::from_peaks(mmr.peaks());
1080 let leaf_pos = 1usize;
1081 let node = mmr.get(leaf_pos).unwrap();
1082 let proof = mmr.open(leaf_pos).unwrap();
1083 partial_mmr.track(leaf_pos, node, proof.path().merkle_path()).unwrap();
1084
1085 let mut bytes = Vec::new();
1086 partial_mmr.forest.num_leaves().write_into(&mut bytes);
1087 partial_mmr.peaks.write_into(&mut bytes);
1088 partial_mmr.nodes.write_into(&mut bytes);
1089 bytes.write_u8(PartialMmr::TRACKED_LEAVES_MARKER);
1090 vec![leaf_pos, leaf_pos].write_into(&mut bytes);
1091
1092 let result = PartialMmr::read_from_bytes(&bytes);
1093
1094 assert!(matches!(result, Err(DeserializationError::InvalidValue(_))));
1095 }
1096
1097 #[test]
1098 fn test_partial_mmr_deserialization_rejects_large_forest() {
1099 let mut bytes = (Forest::MAX_LEAVES + 1).to_bytes();
1100 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);
1105 assert!(matches!(result, Err(DeserializationError::InvalidValue(_))));
1106 }
1107
1108 #[test]
1109 fn test_partial_mmr_untrack() {
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 node2 = mmr.get(2).unwrap();
1119 let proof2 = mmr.open(2).unwrap();
1120
1121 let mut partial_mmr: PartialMmr = mmr.peaks().into();
1123 partial_mmr.track(1, node1, proof1.path().merkle_path()).unwrap();
1124 partial_mmr.track(2, node2, proof2.path().merkle_path()).unwrap();
1125
1126 partial_mmr.untrack(1);
1128 partial_mmr.untrack(2);
1129
1130 assert!(!partial_mmr.is_tracked(1));
1132 assert!(!partial_mmr.is_tracked(2));
1133 assert_eq!(partial_mmr.nodes().count(), 0);
1134 }
1135
1136 #[test]
1137 fn test_partial_mmr_untrack_returns_removed_nodes() {
1138 let mmr = Mmr::try_from_iter(LEAVES.iter().copied()).unwrap();
1140
1141 let node1 = mmr.get(1).unwrap();
1143 let proof1 = mmr.open(1).unwrap();
1144
1145 let mut partial_mmr: PartialMmr = mmr.peaks().into();
1147
1148 partial_mmr.track(1, node1, proof1.path().merkle_path()).unwrap();
1150
1151 let nodes_before: BTreeSet<_> =
1153 partial_mmr.nodes().map(|(&idx, &word)| (idx, word)).collect();
1154
1155 let removed: BTreeSet<_> = partial_mmr.untrack(1).into_iter().collect();
1157
1158 assert_eq!(removed, nodes_before);
1160
1161 assert!(!partial_mmr.is_tracked(1));
1163 assert_eq!(partial_mmr.nodes().count(), 0);
1164 }
1165
1166 #[test]
1167 fn test_partial_mmr_untrack_shared_nodes() {
1168 let mmr = Mmr::try_from_iter(LEAVES.iter().copied()).unwrap();
1170
1171 let node0 = mmr.get(0).unwrap();
1173 let proof0 = mmr.open(0).unwrap();
1174
1175 let node1 = mmr.get(1).unwrap();
1176 let proof1 = mmr.open(1).unwrap();
1177
1178 let mut partial_mmr: PartialMmr = mmr.peaks().into();
1180
1181 partial_mmr.track(0, node0, proof0.path().merkle_path()).unwrap();
1183 partial_mmr.track(1, node1, proof1.path().merkle_path()).unwrap();
1184
1185 assert_eq!(partial_mmr.nodes().count(), 3);
1194
1195 let removed0 = partial_mmr.untrack(0);
1201 assert_eq!(removed0.len(), 0);
1202 assert_eq!(partial_mmr.nodes().count(), 3);
1203 assert!(partial_mmr.is_tracked(1));
1204 assert!(!partial_mmr.is_tracked(0));
1205
1206 let removed1 = partial_mmr.untrack(1);
1212 assert_eq!(removed1.len(), 3);
1213 assert_eq!(partial_mmr.nodes().count(), 0);
1214 assert!(!partial_mmr.is_tracked(1));
1215 }
1216
1217 #[test]
1218 fn test_partial_mmr_untrack_preserves_upper_siblings() {
1219 let mut mmr = Mmr::default();
1220 (0..8).for_each(|i| mmr.add(int_to_node(i)).unwrap());
1221
1222 let mut partial_mmr: PartialMmr = mmr.peaks().into();
1223 for pos in [0, 2] {
1224 let node = mmr.get(pos).unwrap();
1225 let proof = mmr.open(pos).unwrap();
1226 partial_mmr.track(pos, node, proof.path().merkle_path()).unwrap();
1227 }
1228
1229 partial_mmr.untrack(0);
1230
1231 let proof_partial = partial_mmr.open(2).unwrap().unwrap();
1232 let proof_full = mmr.open(2).unwrap();
1233 assert_eq!(proof_partial, proof_full);
1234 }
1235
1236 #[test]
1237 fn test_partial_mmr_deserialize_missing_marker_fails() {
1238 let mut mmr = Mmr::default();
1239 (0..3).for_each(|i| mmr.add(int_to_node(i)).unwrap());
1240 let peaks = mmr.peaks();
1241
1242 let mut bytes = Vec::new();
1243 peaks.num_leaves().write_into(&mut bytes);
1244 peaks.peaks().to_vec().write_into(&mut bytes);
1245 BTreeMap::<InOrderIndex, Word>::new().write_into(&mut bytes);
1246 assert!(PartialMmr::read_from_bytes(&bytes).is_err());
1247 }
1248
1249 #[test]
1250 fn test_partial_mmr_deserialize_invalid_marker_fails() {
1251 let mut mmr = Mmr::default();
1252 (0..3).for_each(|i| mmr.add(int_to_node(i)).unwrap());
1253 let peaks = mmr.peaks();
1254
1255 let mut bytes = Vec::new();
1256 peaks.num_leaves().write_into(&mut bytes);
1257 peaks.peaks().to_vec().write_into(&mut bytes);
1258 BTreeMap::<InOrderIndex, Word>::new().write_into(&mut bytes);
1259 bytes.write_u8(0x7f);
1260 Vec::<usize>::new().write_into(&mut bytes);
1261
1262 assert!(PartialMmr::read_from_bytes(&bytes).is_err());
1263 }
1264
1265 #[test]
1266 fn test_partial_mmr_open_returns_proof_with_leaf() {
1267 let mmr = Mmr::try_from_iter(LEAVES.iter().copied()).unwrap();
1269
1270 let leaf1 = mmr.get(1).unwrap();
1272 let mmr_proof = mmr.open(1).unwrap();
1273
1274 let mut partial_mmr: PartialMmr = mmr.peaks().into();
1276 partial_mmr.track(1, leaf1, mmr_proof.path().merkle_path()).unwrap();
1277
1278 let partial_proof = partial_mmr.open(1).unwrap().unwrap();
1280 assert_eq!(partial_proof.leaf(), leaf1);
1281 assert_eq!(partial_proof, mmr_proof);
1282
1283 partial_mmr.untrack(1);
1285 assert!(partial_mmr.open(1).unwrap().is_none());
1286 }
1287
1288 #[test]
1289 fn test_partial_mmr_add_tracks_leaf() {
1290 let mut partial_mmr = PartialMmr::default();
1292
1293 let leaf0 = int_to_node(0);
1295 let leaf1 = int_to_node(1);
1296 let leaf2 = int_to_node(2);
1297
1298 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();
1304 assert!(proof0.is_some());
1305 assert_eq!(proof0.unwrap().leaf(), leaf0);
1306
1307 let proof1 = partial_mmr.open(1).unwrap();
1309 assert!(proof1.is_none());
1310
1311 let proof2 = partial_mmr.open(2).unwrap();
1313 assert!(proof2.is_some());
1314 assert_eq!(proof2.unwrap().leaf(), leaf2);
1315
1316 assert_eq!(partial_mmr.get(0), Some(leaf0));
1318 assert_eq!(partial_mmr.get(1), None);
1319 assert_eq!(partial_mmr.get(2), Some(leaf2));
1320
1321 let tracked: Vec<_> = partial_mmr.leaves().collect();
1323 assert_eq!(tracked, vec![(0, leaf0), (2, leaf2)]);
1324 }
1325
1326 #[test]
1327 fn test_partial_mmr_track_dangling_leaf() {
1328 let mut mmr = Mmr::default();
1330 mmr.add(int_to_node(0)).unwrap();
1331 let mut partial_mmr: PartialMmr = mmr.peaks().into();
1332
1333 let leaf0 = mmr.get(0).unwrap();
1334 let proof0 = mmr.open(0).unwrap();
1336
1337 partial_mmr.track(0, leaf0, proof0.path().merkle_path()).unwrap();
1339
1340 assert!(partial_mmr.is_tracked(0));
1342 assert_eq!(partial_mmr.open(0).unwrap().unwrap(), proof0);
1343 }
1344
1345 #[test]
1346 fn test_from_parts_validation() {
1347 use alloc::collections::BTreeMap;
1348
1349 use super::InOrderIndex;
1350
1351 let mmr = Mmr::try_from_iter(LEAVES.iter().copied()).unwrap();
1353 let peaks = mmr.peaks();
1354
1355 let result = PartialMmr::from_parts(peaks.clone(), BTreeMap::new(), BTreeSet::new());
1357 assert!(result.is_ok());
1358
1359 let mut out_of_bounds = BTreeSet::new();
1361 out_of_bounds.insert(100);
1362 let result = PartialMmr::from_parts(peaks.clone(), BTreeMap::new(), out_of_bounds);
1363 assert!(result.is_err());
1364
1365 let mut tracked_no_value = BTreeSet::new();
1367 tracked_no_value.insert(0);
1368 let result = PartialMmr::from_parts(peaks.clone(), BTreeMap::new(), tracked_no_value);
1369 assert!(result.is_err());
1370
1371 let mut nodes_with_leaf = BTreeMap::new();
1373 let leaf_idx = InOrderIndex::from_leaf_pos(0);
1374 nodes_with_leaf.insert(leaf_idx, int_to_node(0));
1375 let mut tracked_valid = BTreeSet::new();
1376 tracked_valid.insert(0);
1377 let result = PartialMmr::from_parts(peaks.clone(), nodes_with_leaf, tracked_valid);
1378 assert!(result.is_ok());
1379
1380 let mut invalid_nodes = BTreeMap::new();
1382 let invalid_idx = InOrderIndex::from_leaf_pos(100); invalid_nodes.insert(invalid_idx, int_to_node(0));
1384 let result = PartialMmr::from_parts(peaks.clone(), invalid_nodes, BTreeSet::new());
1385 assert!(result.is_err());
1386
1387 let mut nodes_with_zero = BTreeMap::new();
1389 let zero_idx = InOrderIndex::read_from_bytes(&0usize.to_bytes()).unwrap();
1391 nodes_with_zero.insert(zero_idx, int_to_node(0));
1392 let result = PartialMmr::from_parts(peaks.clone(), nodes_with_zero, BTreeSet::new());
1393 assert!(result.is_err());
1394
1395 let mut nodes_with_large_even = BTreeMap::new();
1397 let large_even_idx = InOrderIndex::read_from_bytes(&1000usize.to_bytes()).unwrap();
1398 nodes_with_large_even.insert(large_even_idx, int_to_node(0));
1399 let result = PartialMmr::from_parts(peaks.clone(), nodes_with_large_even, BTreeSet::new());
1400 assert!(result.is_err());
1401
1402 let mut nodes_with_separator = BTreeMap::new();
1407 let separator_idx = InOrderIndex::read_from_bytes(&8usize.to_bytes()).unwrap();
1408 nodes_with_separator.insert(separator_idx, int_to_node(0));
1409 let result = PartialMmr::from_parts(peaks.clone(), nodes_with_separator, BTreeSet::new());
1410 assert!(result.is_err(), "separator index 8 should be rejected");
1411
1412 let mut nodes_with_separator_12 = BTreeMap::new();
1413 let separator_idx_12 = InOrderIndex::read_from_bytes(&12usize.to_bytes()).unwrap();
1414 nodes_with_separator_12.insert(separator_idx_12, int_to_node(0));
1415 let result = PartialMmr::from_parts(peaks, nodes_with_separator_12, BTreeSet::new());
1416 assert!(result.is_err(), "separator index 12 should be rejected");
1417
1418 let empty_peaks = MmrPeaks::new(Forest::empty(), vec![]).unwrap();
1420 let mut nodes_with_empty_forest = BTreeMap::new();
1421 nodes_with_empty_forest.insert(InOrderIndex::from_leaf_pos(0), int_to_node(0));
1422 let result = PartialMmr::from_parts(empty_peaks, nodes_with_empty_forest, BTreeSet::new());
1423 assert!(result.is_err());
1424 }
1425
1426 #[test]
1427 fn test_from_parts_validation_deserialization() {
1428 let mmr = Mmr::try_from_iter(LEAVES.iter().copied()).unwrap();
1430 let partial_mmr = PartialMmr::from_peaks(mmr.peaks());
1431
1432 let bytes = partial_mmr.to_bytes();
1434 let decoded = PartialMmr::read_from_bytes(&bytes);
1435 assert!(decoded.is_ok());
1436
1437 let mut partial_with_node = PartialMmr::from_peaks(mmr.peaks());
1442 let node = mmr.get(1).unwrap();
1443 let proof = mmr.open(1).unwrap();
1444 partial_with_node.track(1, node, proof.path().merkle_path()).unwrap();
1445
1446 let valid_bytes = partial_with_node.to_bytes();
1448 let valid_decoded = PartialMmr::read_from_bytes(&valid_bytes);
1449 assert!(valid_decoded.is_ok());
1450
1451 let mut bad_bytes = Vec::new();
1454 bad_bytes.extend_from_slice(&7usize.to_bytes());
1456 bad_bytes.extend_from_slice(&3usize.to_bytes()); for i in 0..3 {
1459 bad_bytes.extend_from_slice(&int_to_node(i as u64).to_bytes());
1460 }
1461 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);
1466 bad_bytes.extend_from_slice(&0usize.to_bytes());
1468
1469 let result = PartialMmr::read_from_bytes(&bad_bytes);
1470 assert!(result.is_err());
1471 }
1472
1473 #[test]
1474 fn test_from_parts_unchecked() {
1475 use alloc::collections::BTreeMap;
1476
1477 let mmr = Mmr::try_from_iter(LEAVES.iter().copied()).unwrap();
1479 let peaks = mmr.peaks();
1480
1481 let partial =
1483 PartialMmr::from_parts_unchecked(peaks.clone(), BTreeMap::new(), BTreeSet::new());
1484 assert_eq!(partial.forest(), peaks.forest());
1485
1486 let mut invalid_tracked = BTreeSet::new();
1488 invalid_tracked.insert(999);
1489 let partial = PartialMmr::from_parts_unchecked(peaks, BTreeMap::new(), invalid_tracked);
1490 assert!(partial.tracked_leaves.contains(&999));
1491 }
1492}