1use alloc::{
2 collections::{BTreeMap, BTreeSet},
3 vec::Vec,
4};
5
6use winter_utils::{Deserializable, Serializable};
7
8use super::{MmrDelta, MmrProof};
9use crate::{
10 Word,
11 merkle::{
12 InnerNodeInfo, MerklePath, Rpo256,
13 mmr::{InOrderIndex, MmrError, MmrPeaks, forest::Forest},
14 },
15};
16
17type NodeMap = BTreeMap<InOrderIndex, Word>;
21
22#[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,
68
69 pub(crate) track_latest: bool,
74}
75
76impl Default for PartialMmr {
77 fn default() -> Self {
79 let forest = Forest::empty();
80 let peaks = Vec::new();
81 let nodes = BTreeMap::new();
82 let track_latest = false;
83
84 Self { forest, peaks, nodes, track_latest }
85 }
86}
87
88impl PartialMmr {
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 track_latest = false;
98
99 Self { forest, peaks, nodes, track_latest }
100 }
101
102 pub fn from_parts(peaks: MmrPeaks, nodes: NodeMap, track_latest: bool) -> Self {
107 let forest = peaks.forest();
108 let peaks = peaks.into();
109
110 Self { forest, peaks, nodes, track_latest }
111 }
112
113 pub fn forest(&self) -> Forest {
121 self.forest
122 }
123
124 pub fn num_leaves(&self) -> usize {
126 self.forest.num_leaves()
127 }
128
129 pub fn peaks(&self) -> MmrPeaks {
131 MmrPeaks::new(self.forest, self.peaks.clone()).expect("invalid MMR peaks")
134 }
135
136 pub fn is_tracked(&self, pos: usize) -> bool {
139 let leaves = self.forest.num_leaves();
140 if pos >= leaves {
141 return false;
142 } else if pos == leaves - 1 && self.forest.has_single_leaf_tree() {
143 return self.track_latest;
146 }
147
148 let leaf_index = InOrderIndex::from_leaf_pos(pos);
149 self.is_tracked_node(&leaf_index)
150 }
151
152 pub fn open(&self, pos: usize) -> Result<Option<MmrProof>, MmrError> {
163 let tree_bit = self
164 .forest
165 .leaf_to_corresponding_tree(pos)
166 .ok_or(MmrError::PositionNotFound(pos))?;
167 let depth = tree_bit as usize;
168
169 let mut nodes = Vec::with_capacity(depth);
170 let mut idx = InOrderIndex::from_leaf_pos(pos);
171
172 while let Some(node) = self.nodes.get(&idx.sibling()) {
173 nodes.push(*node);
174 idx = idx.parent();
175 }
176
177 debug_assert!(nodes.is_empty() || nodes.len() == depth);
179
180 if nodes.len() != depth {
181 Ok(None)
183 } else {
184 Ok(Some(MmrProof {
185 forest: self.forest,
186 position: pos,
187 merkle_path: MerklePath::new(nodes),
188 }))
189 }
190 }
191
192 pub fn nodes(&self) -> impl Iterator<Item = (&InOrderIndex, &Word)> {
197 self.nodes.iter()
198 }
199
200 pub fn inner_nodes<'a, I: Iterator<Item = (usize, Word)> + 'a>(
205 &'a self,
206 mut leaves: I,
207 ) -> impl Iterator<Item = InnerNodeInfo> + 'a {
208 let stack = if let Some((pos, leaf)) = leaves.next() {
209 let idx = InOrderIndex::from_leaf_pos(pos);
210 vec![(idx, leaf)]
211 } else {
212 Vec::new()
213 };
214
215 InnerNodeIterator {
216 nodes: &self.nodes,
217 leaves,
218 stack,
219 seen_nodes: BTreeSet::new(),
220 }
221 }
222
223 pub fn add(&mut self, leaf: Word, track: bool) -> Vec<(InOrderIndex, Word)> {
231 self.forest.append_leaf();
232 let merges = self.forest.smallest_tree_height_unchecked();
234 let mut new_nodes = Vec::with_capacity(merges);
235
236 let peak = if merges == 0 {
237 self.track_latest = track;
238 leaf
239 } else {
240 let mut track_right = track;
241 let mut track_left = self.track_latest;
242 self.track_latest = false;
246
247 let mut right = leaf;
248 let mut right_idx = self.forest.rightmost_in_order_index();
249
250 for _ in 0..merges {
251 let left = self.peaks.pop().expect("Missing peak");
252 let left_idx = right_idx.sibling();
253
254 if track_right {
255 let old = self.nodes.insert(left_idx, left);
256 new_nodes.push((left_idx, left));
257
258 debug_assert!(
259 old.is_none(),
260 "Idx {left_idx:?} already contained an element {old:?}",
261 );
262 };
263 if track_left {
264 let old = self.nodes.insert(right_idx, right);
265 new_nodes.push((right_idx, right));
266
267 debug_assert!(
268 old.is_none(),
269 "Idx {right_idx:?} already contained an element {old:?}",
270 );
271 };
272
273 right_idx = right_idx.parent();
278
279 right = Rpo256::merge(&[left, right]);
282
283 track_right = track_right || track_left;
287
288 track_left = self.is_tracked_node(&right_idx.sibling());
291 }
292 right
293 };
294
295 self.peaks.push(peak);
296
297 new_nodes
298 }
299
300 pub fn track(
311 &mut self,
312 leaf_pos: usize,
313 leaf: Word,
314 path: &MerklePath,
315 ) -> Result<(), MmrError> {
316 let tree = Forest::new(1 << path.depth());
319 if (tree & self.forest).is_empty() {
320 return Err(MmrError::UnknownPeak(path.depth()));
321 };
322
323 if leaf_pos + 1 == self.forest.num_leaves()
324 && path.depth() == 0
325 && self.peaks.last().is_some_and(|v| *v == leaf)
326 {
327 self.track_latest = true;
328 return Ok(());
329 }
330
331 let target_forest = self.forest ^ (self.forest & tree.all_smaller_trees_unchecked());
334 let peak_pos = target_forest.num_trees() - 1;
335
336 let path_idx = leaf_pos - (target_forest ^ tree).num_leaves();
338
339 let computed = path
342 .compute_root(path_idx as u64, leaf)
343 .map_err(MmrError::MerkleRootComputationFailed)?;
344 if self.peaks[peak_pos] != computed {
345 return Err(MmrError::PeakPathMismatch);
346 }
347
348 let mut idx = InOrderIndex::from_leaf_pos(leaf_pos);
349 for leaf in path.nodes() {
350 self.nodes.insert(idx.sibling(), *leaf);
351 idx = idx.parent();
352 }
353
354 Ok(())
355 }
356
357 pub fn untrack(&mut self, leaf_pos: usize) {
361 let mut idx = InOrderIndex::from_leaf_pos(leaf_pos);
362
363 while self.nodes.remove(&idx.sibling()).is_some() && !self.nodes.contains_key(&idx) {
369 idx = idx.parent();
370 }
371 }
372
373 pub fn apply(&mut self, delta: MmrDelta) -> Result<Vec<(InOrderIndex, Word)>, MmrError> {
376 if delta.forest < self.forest {
377 return Err(MmrError::InvalidPeaks(format!(
378 "forest of mmr delta {} is less than current forest {}",
379 delta.forest, self.forest
380 )));
381 }
382
383 let mut inserted_nodes = Vec::new();
384
385 if delta.forest == self.forest {
386 if !delta.data.is_empty() {
387 return Err(MmrError::InvalidUpdate);
388 }
389
390 return Ok(inserted_nodes);
391 }
392
393 let changes = self.forest ^ delta.forest;
395 let largest = changes.largest_tree_unchecked();
398 let merges = self.forest & largest.all_smaller_trees_unchecked();
400
401 debug_assert!(
402 !self.track_latest || merges.has_single_leaf_tree(),
403 "if there is an odd element, a merge is required"
404 );
405
406 let (merge_count, new_peaks) = if !merges.is_empty() {
408 let depth = largest.smallest_tree_height_unchecked();
409 let skipped = merges.smallest_tree_height_unchecked();
411 let computed = merges.num_trees() - 1;
412 let merge_count = depth - skipped - computed;
413
414 let new_peaks = delta.forest & largest.all_smaller_trees_unchecked();
415
416 (merge_count, new_peaks)
417 } else {
418 (0, changes)
419 };
420
421 if delta.data.len() != merge_count + new_peaks.num_trees() {
423 return Err(MmrError::InvalidUpdate);
424 }
425
426 let mut update_count = 0;
428
429 if !merges.is_empty() {
430 let mut peak_idx = self.forest.root_in_order_index();
432
433 self.peaks.reverse();
435
436 let mut track = self.track_latest;
438 self.track_latest = false;
439
440 let mut peak_count = 0;
441 let mut target = merges.smallest_tree_unchecked();
442 let mut new = delta.data[0];
443 update_count += 1;
444
445 while target < largest {
446 if target != Forest::new(1) && !track {
449 track = self.is_tracked_node(&peak_idx);
450 }
451
452 let (left, right) = if !(target & merges).is_empty() {
455 let peak = self.peaks[peak_count];
456 let sibling_idx = peak_idx.sibling();
457
458 if self.is_tracked_node(&sibling_idx) {
461 self.nodes.insert(peak_idx, new);
462 inserted_nodes.push((peak_idx, new));
463 }
464 peak_count += 1;
465 (peak, new)
466 } else {
467 let update = delta.data[update_count];
468 update_count += 1;
469 (new, update)
470 };
471
472 if track {
473 let sibling_idx = peak_idx.sibling();
474 if peak_idx.is_left_child() {
475 self.nodes.insert(sibling_idx, right);
476 inserted_nodes.push((sibling_idx, right));
477 } else {
478 self.nodes.insert(sibling_idx, left);
479 inserted_nodes.push((sibling_idx, left));
480 }
481 }
482
483 peak_idx = peak_idx.parent();
484 new = Rpo256::merge(&[left, right]);
485 target = target.next_larger_tree();
486 }
487
488 debug_assert!(peak_count == merges.num_trees());
489
490 self.peaks.reverse();
492 self.peaks.truncate(self.peaks.len() - peak_count);
494 self.peaks.push(new);
496 }
497
498 self.peaks.extend_from_slice(&delta.data[update_count..]);
502 self.forest = delta.forest;
503
504 debug_assert!(self.peaks.len() == self.forest.num_trees());
505
506 Ok(inserted_nodes)
507 }
508
509 fn is_tracked_node(&self, node_index: &InOrderIndex) -> bool {
515 if node_index.is_leaf() {
516 self.nodes.contains_key(&node_index.sibling())
517 } else {
518 let left_child = node_index.left_child();
519 let right_child = node_index.right_child();
520 self.nodes.contains_key(&left_child) | self.nodes.contains_key(&right_child)
521 }
522 }
523}
524
525impl From<MmrPeaks> for PartialMmr {
529 fn from(peaks: MmrPeaks) -> Self {
530 Self::from_peaks(peaks)
531 }
532}
533
534impl From<PartialMmr> for MmrPeaks {
535 fn from(partial_mmr: PartialMmr) -> Self {
536 MmrPeaks::new(partial_mmr.forest, partial_mmr.peaks).unwrap()
539 }
540}
541
542impl From<&MmrPeaks> for PartialMmr {
543 fn from(peaks: &MmrPeaks) -> Self {
544 Self::from_peaks(peaks.clone())
545 }
546}
547
548impl From<&PartialMmr> for MmrPeaks {
549 fn from(partial_mmr: &PartialMmr) -> Self {
550 MmrPeaks::new(partial_mmr.forest, partial_mmr.peaks.clone()).unwrap()
553 }
554}
555
556pub struct InnerNodeIterator<'a, I: Iterator<Item = (usize, Word)>> {
561 nodes: &'a NodeMap,
562 leaves: I,
563 stack: Vec<(InOrderIndex, Word)>,
564 seen_nodes: BTreeSet<InOrderIndex>,
565}
566
567impl<I: Iterator<Item = (usize, Word)>> Iterator for InnerNodeIterator<'_, I> {
568 type Item = InnerNodeInfo;
569
570 fn next(&mut self) -> Option<Self::Item> {
571 while let Some((idx, node)) = self.stack.pop() {
572 let parent_idx = idx.parent();
573 let new_node = self.seen_nodes.insert(parent_idx);
574
575 if new_node && let Some(sibling) = self.nodes.get(&idx.sibling()) {
578 let (left, right) = if parent_idx.left_child() == idx {
579 (node, *sibling)
580 } else {
581 (*sibling, node)
582 };
583 let parent = Rpo256::merge(&[left, right]);
584 let inner_node = InnerNodeInfo { value: parent, left, right };
585
586 self.stack.push((parent_idx, parent));
587 return Some(inner_node);
588 }
589
590 if let Some((pos, leaf)) = self.leaves.next() {
592 let idx = InOrderIndex::from_leaf_pos(pos);
593 self.stack.push((idx, leaf));
594 }
595 }
596
597 None
598 }
599}
600
601impl Serializable for PartialMmr {
602 fn write_into<W: winter_utils::ByteWriter>(&self, target: &mut W) {
603 self.forest.num_leaves().write_into(target);
604 self.peaks.write_into(target);
605 self.nodes.write_into(target);
606 target.write_bool(self.track_latest);
607 }
608}
609
610impl Deserializable for PartialMmr {
611 fn read_from<R: winter_utils::ByteReader>(
612 source: &mut R,
613 ) -> Result<Self, winter_utils::DeserializationError> {
614 let forest = Forest::new(usize::read_from(source)?);
615 let peaks = Vec::<Word>::read_from(source)?;
616 let nodes = NodeMap::read_from(source)?;
617 let track_latest = source.read_bool()?;
618
619 Ok(Self { forest, peaks, nodes, track_latest })
620 }
621}
622
623#[cfg(test)]
627mod tests {
628 use alloc::{collections::BTreeSet, vec::Vec};
629
630 use winter_utils::{Deserializable, Serializable};
631
632 use super::{MmrPeaks, PartialMmr};
633 use crate::{
634 Word,
635 merkle::{
636 NodeIndex, int_to_node,
637 mmr::{Mmr, forest::Forest},
638 store::MerkleStore,
639 },
640 };
641
642 const LEAVES: [Word; 7] = [
643 int_to_node(0),
644 int_to_node(1),
645 int_to_node(2),
646 int_to_node(3),
647 int_to_node(4),
648 int_to_node(5),
649 int_to_node(6),
650 ];
651
652 #[test]
653 fn test_partial_mmr_apply_delta() {
654 let mut mmr = Mmr::default();
656 (0..10).for_each(|i| mmr.add(int_to_node(i)));
657 let mut partial_mmr: PartialMmr = mmr.peaks().into();
658
659 {
661 let node = mmr.get(1).unwrap();
662 let proof = mmr.open(1).unwrap();
663 partial_mmr.track(1, node, &proof.merkle_path).unwrap();
664 }
665
666 {
667 let node = mmr.get(8).unwrap();
668 let proof = mmr.open(8).unwrap();
669 partial_mmr.track(8, node, &proof.merkle_path).unwrap();
670 }
671
672 (10..12).for_each(|i| mmr.add(int_to_node(i)));
674 validate_apply_delta(&mmr, &mut partial_mmr);
675
676 mmr.add(int_to_node(12));
678 validate_apply_delta(&mmr, &mut partial_mmr);
679 {
680 let node = mmr.get(12).unwrap();
681 let proof = mmr.open(12).unwrap();
682 partial_mmr.track(12, node, &proof.merkle_path).unwrap();
683 assert!(partial_mmr.track_latest);
684 }
685
686 (13..16).for_each(|i| mmr.add(int_to_node(i)));
690 validate_apply_delta(&mmr, &mut partial_mmr);
691 }
692
693 fn validate_apply_delta(mmr: &Mmr, partial: &mut PartialMmr) {
694 let tracked_leaves = partial
695 .nodes
696 .iter()
697 .filter(|&(index, _)| index.is_leaf())
698 .map(|(index, _)| index.sibling())
699 .collect::<Vec<_>>();
700 let nodes_before = partial.nodes.clone();
701
702 let delta = mmr.get_delta(partial.forest(), mmr.forest()).unwrap();
704 let nodes_delta = partial.apply(delta).unwrap();
705
706 assert_eq!(mmr.peaks(), partial.peaks());
708
709 let mut expected_nodes = nodes_before;
710 for (key, value) in nodes_delta {
711 assert!(expected_nodes.insert(key, value).is_none());
713 }
714
715 assert_eq!(expected_nodes, partial.nodes);
717
718 for index in tracked_leaves {
720 let pos = index.inner() / 2;
721 let proof1 = partial.open(pos).unwrap().unwrap();
722 let proof2 = mmr.open(pos).unwrap();
723 assert_eq!(proof1, proof2);
724 }
725 }
726
727 #[test]
728 fn test_partial_mmr_inner_nodes_iterator() {
729 let mmr: Mmr = LEAVES.into();
731 let first_peak = mmr.peaks().peaks()[0];
732
733 let node1 = mmr.get(1).unwrap();
737 let proof1 = mmr.open(1).unwrap();
738
739 let mut partial_mmr: PartialMmr = mmr.peaks().into();
741 partial_mmr.track(1, node1, &proof1.merkle_path).unwrap();
742
743 assert_eq!(partial_mmr.inner_nodes([].iter().cloned()).next(), None);
745
746 let mut store: MerkleStore = MerkleStore::new();
748 store.extend(partial_mmr.inner_nodes([(1, node1)].iter().cloned()));
749
750 let index1 = NodeIndex::new(2, 1).unwrap();
751 let path1 = store.get_path(first_peak, index1).unwrap().path;
752
753 assert_eq!(path1, proof1.merkle_path);
754
755 let mut partial_mmr: PartialMmr = mmr.peaks().into();
759
760 let node0 = mmr.get(0).unwrap();
761 let proof0 = mmr.open(0).unwrap();
762
763 let node2 = mmr.get(2).unwrap();
764 let proof2 = mmr.open(2).unwrap();
765
766 partial_mmr.track(0, node0, &proof0.merkle_path).unwrap();
767 partial_mmr.track(1, node1, &proof1.merkle_path).unwrap();
768 partial_mmr.track(2, node2, &proof2.merkle_path).unwrap();
769
770 let leaves = [(0, node0), (1, node1), (2, node2)];
772 let mut nodes = BTreeSet::new();
773 for node in partial_mmr.inner_nodes(leaves.iter().cloned()) {
774 assert!(nodes.insert(node.value));
775 }
776
777 store.extend(partial_mmr.inner_nodes(leaves.iter().cloned()));
779
780 let index0 = NodeIndex::new(2, 0).unwrap();
781 let index1 = NodeIndex::new(2, 1).unwrap();
782 let index2 = NodeIndex::new(2, 2).unwrap();
783
784 let path0 = store.get_path(first_peak, index0).unwrap().path;
785 let path1 = store.get_path(first_peak, index1).unwrap().path;
786 let path2 = store.get_path(first_peak, index2).unwrap().path;
787
788 assert_eq!(path0, proof0.merkle_path);
789 assert_eq!(path1, proof1.merkle_path);
790 assert_eq!(path2, proof2.merkle_path);
791
792 let mut partial_mmr: PartialMmr = mmr.peaks().into();
796
797 let node5 = mmr.get(5).unwrap();
798 let proof5 = mmr.open(5).unwrap();
799
800 partial_mmr.track(1, node1, &proof1.merkle_path).unwrap();
801 partial_mmr.track(5, node5, &proof5.merkle_path).unwrap();
802
803 let mut store: MerkleStore = MerkleStore::new();
805 store.extend(partial_mmr.inner_nodes([(1, node1), (5, node5)].iter().cloned()));
806
807 let index1 = NodeIndex::new(2, 1).unwrap();
808 let index5 = NodeIndex::new(1, 1).unwrap();
809
810 let second_peak = mmr.peaks().peaks()[1];
811
812 let path1 = store.get_path(first_peak, index1).unwrap().path;
813 let path5 = store.get_path(second_peak, index5).unwrap().path;
814
815 assert_eq!(path1, proof1.merkle_path);
816 assert_eq!(path5, proof5.merkle_path);
817 }
818
819 #[test]
820 fn test_partial_mmr_add_without_track() {
821 let mut mmr = Mmr::default();
822 let empty_peaks = MmrPeaks::new(Forest::empty(), vec![]).unwrap();
823 let mut partial_mmr = PartialMmr::from_peaks(empty_peaks);
824
825 for el in (0..256).map(int_to_node) {
826 mmr.add(el);
827 partial_mmr.add(el, false);
828
829 assert_eq!(mmr.peaks(), partial_mmr.peaks());
830 assert_eq!(mmr.forest(), partial_mmr.forest());
831 }
832 }
833
834 #[test]
835 fn test_partial_mmr_add_with_track() {
836 let mut mmr = Mmr::default();
837 let empty_peaks = MmrPeaks::new(Forest::empty(), vec![]).unwrap();
838 let mut partial_mmr = PartialMmr::from_peaks(empty_peaks);
839
840 for i in 0..256 {
841 let el = int_to_node(i as u64);
842 mmr.add(el);
843 partial_mmr.add(el, true);
844
845 assert_eq!(mmr.peaks(), partial_mmr.peaks());
846 assert_eq!(mmr.forest(), partial_mmr.forest());
847
848 for pos in 0..i {
849 let mmr_proof = mmr.open(pos).unwrap();
850 let partialmmr_proof = partial_mmr.open(pos).unwrap().unwrap();
851 assert_eq!(mmr_proof, partialmmr_proof);
852 }
853 }
854 }
855
856 #[test]
857 fn test_partial_mmr_add_existing_track() {
858 let mut mmr = Mmr::from((0..7).map(int_to_node));
859
860 let mut partial_mmr = PartialMmr::from_peaks(mmr.peaks());
862 let path_to_5 = mmr.open(5).unwrap().merkle_path;
863 let leaf_at_5 = mmr.get(5).unwrap();
864 partial_mmr.track(5, leaf_at_5, &path_to_5).unwrap();
865
866 let leaf_at_7 = int_to_node(7);
868 mmr.add(leaf_at_7);
869 partial_mmr.add(leaf_at_7, false);
870
871 assert_eq!(mmr.open(5).unwrap(), partial_mmr.open(5).unwrap().unwrap());
873 }
874
875 #[test]
876 fn test_partial_mmr_add_clears_track_latest_after_merge() {
877 let mut mmr = Mmr::default();
878 let empty_peaks = MmrPeaks::new(Forest::empty(), vec![]).unwrap();
879 let mut partial_mmr = PartialMmr::from_peaks(empty_peaks);
880
881 let leaf_0 = int_to_node(0);
882 mmr.add(leaf_0);
883 partial_mmr.add(leaf_0, true);
884 assert!(partial_mmr.track_latest);
885
886 let leaf_1 = int_to_node(1);
888 mmr.add(leaf_1);
889 partial_mmr.add(leaf_1, false);
890 assert!(!partial_mmr.track_latest);
891
892 mmr.add(int_to_node(2));
894 let delta = mmr.get_delta(partial_mmr.forest(), mmr.forest()).unwrap();
895 partial_mmr.apply(delta).unwrap();
896
897 assert_eq!(mmr.peaks(), partial_mmr.peaks());
898 assert_eq!(mmr.open(0).unwrap(), partial_mmr.open(0).unwrap().unwrap());
899 }
900
901 #[test]
902 fn test_partial_mmr_serialization() {
903 let mmr = Mmr::from((0..7).map(int_to_node));
904 let partial_mmr = PartialMmr::from_peaks(mmr.peaks());
905
906 let bytes = partial_mmr.to_bytes();
907 let decoded = PartialMmr::read_from_bytes(&bytes).unwrap();
908
909 assert_eq!(partial_mmr, decoded);
910 }
911
912 #[test]
913 fn test_partial_mmr_untrack() {
914 let mmr: Mmr = LEAVES.into();
916
917 let node1 = mmr.get(1).unwrap();
919 let proof1 = mmr.open(1).unwrap();
920
921 let node2 = mmr.get(2).unwrap();
923 let proof2 = mmr.open(2).unwrap();
924
925 let mut partial_mmr: PartialMmr = mmr.peaks().into();
927 partial_mmr.track(1, node1, &proof1.merkle_path).unwrap();
928 partial_mmr.track(2, node2, &proof2.merkle_path).unwrap();
929
930 partial_mmr.untrack(1);
932 partial_mmr.untrack(2);
933
934 assert!(!partial_mmr.is_tracked(1));
936 assert!(!partial_mmr.is_tracked(2));
937 assert_eq!(partial_mmr.nodes().count(), 0);
938 }
939}