1use alloc::{
14 string::{String, ToString},
15 sync::Arc,
16 vec::Vec,
17};
18use core::{iter::FusedIterator, ops::Index, slice};
19
20use super::{
21 super::{InnerNodeInfo, MerklePath},
22 MmrDelta, MmrError, MmrPath, MmrPeaks, MmrProof,
23 forest::{Forest, TreeSizeIterator},
24 nodes_from_mask,
25};
26use crate::{
27 Word,
28 hash::poseidon2::Poseidon2,
29 utils::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable},
30};
31
32const NODE_CHUNK_CAPACITY: usize = 1024;
37
38#[derive(Debug, Clone, Default, PartialEq, Eq)]
49pub(super) struct NodeStore {
50 chunks: Vec<Arc<Vec<Word>>>,
51}
52
53impl NodeStore {
54 pub fn new() -> Self {
56 Self { chunks: Vec::new() }
57 }
58
59 pub fn len(&self) -> usize {
61 match self.chunks.last() {
62 Some(last) => (self.chunks.len() - 1) * NODE_CHUNK_CAPACITY + last.len(),
63 None => 0,
64 }
65 }
66
67 pub fn push(&mut self, node: Word) {
69 match self.chunks.last_mut() {
70 Some(last) if last.len() < NODE_CHUNK_CAPACITY => {
71 if Arc::get_mut(last).is_none() {
72 let mut copy = Vec::with_capacity(NODE_CHUNK_CAPACITY);
76 copy.extend_from_slice(last);
77 *last = Arc::new(copy);
78 }
79 Arc::get_mut(last).expect("chunk is unique").push(node);
80 },
81 _ => {
82 let mut chunk = Vec::with_capacity(NODE_CHUNK_CAPACITY);
83 chunk.push(node);
84 self.chunks.push(Arc::new(chunk));
85 },
86 }
87 }
88
89 pub fn iter(&self) -> MmrNodeIter<'_> {
91 self.iter_from(0)
92 }
93
94 pub fn iter_from(&self, start: usize) -> MmrNodeIter<'_> {
99 let first_chunk = start / NODE_CHUNK_CAPACITY;
100 let offset = start % NODE_CHUNK_CAPACITY;
101 match self.chunks.get(first_chunk) {
102 Some(chunk) => MmrNodeIter {
103 current: chunk[offset.min(chunk.len())..].iter(),
104 chunks: &self.chunks[first_chunk + 1..],
105 },
106 None => MmrNodeIter { current: [].iter(), chunks: &[] },
107 }
108 }
109}
110
111impl Index<usize> for NodeStore {
112 type Output = Word;
113
114 fn index(&self, index: usize) -> &Word {
115 &self.chunks[index / NODE_CHUNK_CAPACITY][index % NODE_CHUNK_CAPACITY]
116 }
117}
118
119impl FromIterator<Word> for NodeStore {
120 fn from_iter<T: IntoIterator<Item = Word>>(iter: T) -> Self {
121 let mut store = Self::new();
122 for node in iter {
123 store.push(node);
124 }
125 store
126 }
127}
128
129impl PartialEq<&[Word]> for NodeStore {
130 fn eq(&self, other: &&[Word]) -> bool {
131 self.len() == other.len() && self.iter().eq(other.iter())
132 }
133}
134
135#[derive(Debug, Clone)]
148pub struct Mmr {
149 pub(super) forest: Forest,
151
152 pub(super) nodes: NodeStore,
159}
160
161impl Default for Mmr {
162 fn default() -> Self {
163 Self::new()
164 }
165}
166
167impl Mmr {
168 pub fn new() -> Mmr {
173 Mmr {
174 forest: Forest::empty(),
175 nodes: NodeStore::new(),
176 }
177 }
178
179 pub fn try_from_iter<T: IntoIterator<Item = Word>>(values: T) -> Result<Self, MmrError> {
184 Self::try_from_iter_with_limit(values, Forest::MAX_LEAVES)
185 }
186
187 pub fn from_nodes_unchecked(
201 forest: Forest,
202 nodes: impl IntoIterator<Item = Word>,
203 ) -> Result<Self, MmrError> {
204 Self::from_store(forest, nodes.into_iter().collect())
205 }
206
207 fn from_store(forest: Forest, nodes: NodeStore) -> Result<Self, MmrError> {
209 if nodes.len() != forest.num_nodes() {
210 return Err(MmrError::InvalidNodeCount {
211 expected: forest.num_nodes(),
212 actual: nodes.len(),
213 });
214 }
215 Ok(Self { forest, nodes })
216 }
217
218 pub(crate) fn try_from_iter_with_limit<T: IntoIterator<Item = Word>>(
219 values: T,
220 max_leaves: usize,
221 ) -> Result<Self, MmrError> {
222 let mut mmr = Mmr::new();
223 let iter = values.into_iter();
224 let (lower, _) = iter.size_hint();
225 if lower > max_leaves {
226 return Err(MmrError::ForestSizeExceeded { requested: lower, max: max_leaves });
227 }
228 let mut count = 0usize;
229 for v in iter {
230 count += 1;
231 if count > max_leaves {
232 return Err(MmrError::ForestSizeExceeded { requested: count, max: max_leaves });
233 }
234 mmr.add(v)?;
235 }
236 Ok(mmr)
237 }
238
239 fn from_serialized_parts(forest: Forest, nodes: NodeStore) -> Result<Self, String> {
241 let mmr = Self::from_store(forest, nodes).map_err(|err| err.to_string())?;
242 if mmr
243 .inner_nodes()
244 .any(|node| node.value != Poseidon2::merge(&[node.left, node.right]))
245 {
246 return Err("Mmr contains a parent node inconsistent with its children".into());
247 }
248
249 Ok(mmr)
250 }
251
252 pub const fn forest(&self) -> Forest {
257 self.forest
258 }
259
260 pub fn nodes_from(&self, start: usize) -> impl ExactSizeIterator<Item = &Word> + Clone {
270 self.nodes.iter_from(start)
271 }
272
273 pub fn open(&self, pos: usize) -> Result<MmrProof, MmrError> {
285 self.open_at(pos, self.forest)
286 }
287
288 pub fn open_at(&self, pos: usize, forest: Forest) -> Result<MmrProof, MmrError> {
300 if forest > self.forest {
301 return Err(MmrError::ForestOutOfBounds(forest.num_leaves(), self.forest.num_leaves()));
302 }
303 let (leaf, path) = self.collect_merkle_path_and_value(pos, forest)?;
304
305 let path = MmrPath::new(forest, pos, MerklePath::new(path));
306
307 Ok(MmrProof::new(path, leaf))
308 }
309
310 pub fn get(&self, pos: usize) -> Result<Word, MmrError> {
316 let (value, _) = self.collect_merkle_path_and_value(pos, self.forest)?;
317
318 Ok(value)
319 }
320
321 pub fn add(&mut self, el: Word) -> Result<(), MmrError> {
326 let old_forest = self.forest;
328 self.forest.append_leaf()?;
329 self.nodes.push(el);
334
335 let mut left_offset = self.nodes.len().saturating_sub(2);
336 let mut right = el;
337 let mut left_tree = 1usize;
338 while (old_forest.num_leaves() & left_tree) != 0 {
339 right = Poseidon2::merge(&[self.nodes[left_offset], right]);
340 self.nodes.push(right);
341
342 debug_assert!(left_tree <= Forest::MAX_LEAVES);
343 let left_nodes = left_tree * 2 - 1;
344 left_offset = left_offset.saturating_sub(left_nodes);
345
346 match left_tree.checked_shl(1) {
347 Some(next) => left_tree = next,
348 None => break,
349 }
350 }
351
352 Ok(())
353 }
354
355 pub fn peaks(&self) -> MmrPeaks {
357 self.peaks_at(self.forest).expect("failed to get peaks at current forest")
358 }
359
360 pub fn peaks_at(&self, forest: Forest) -> Result<MmrPeaks, MmrError> {
365 if forest > self.forest {
366 return Err(MmrError::ForestOutOfBounds(forest.num_leaves(), self.forest.num_leaves()));
367 }
368
369 let peaks: Vec<Word> = TreeSizeIterator::new(forest)
370 .rev()
371 .map(Forest::num_nodes)
372 .scan(0, |offset, el| {
373 *offset += el;
374 Some(*offset)
375 })
376 .map(|offset| self.nodes[offset - 1])
377 .collect();
378
379 let peaks = MmrPeaks::new(forest, peaks)?;
381
382 Ok(peaks)
383 }
384
385 pub fn get_delta(&self, from_forest: Forest, to_forest: Forest) -> Result<MmrDelta, MmrError> {
390 if to_forest > self.forest {
391 return Err(MmrError::ForestOutOfBounds(
392 to_forest.num_leaves(),
393 self.forest.num_leaves(),
394 ));
395 }
396 if from_forest > to_forest {
397 return Err(MmrError::ForestOutOfBounds(
398 from_forest.num_leaves(),
399 to_forest.num_leaves(),
400 ));
401 }
402
403 if from_forest == to_forest {
404 return Ok(MmrDelta { forest: to_forest, data: Vec::new() });
405 }
406
407 let mut result = Vec::new();
408
409 let candidate_mask = to_forest.num_leaves() ^ from_forest.num_leaves();
411 let mut new_high = super::forest::largest_tree_from_mask(candidate_mask);
412
413 let mut merges = from_forest & new_high.all_smaller_trees_unchecked();
418
419 let common_trees = from_forest ^ merges;
421
422 if !merges.is_empty() {
423 let mut target = merges.smallest_tree_unchecked();
425
426 while target < new_high {
428 let known_mask =
435 common_trees.num_leaves() | merges.num_leaves() | target.num_leaves();
436 let known = nodes_from_mask(known_mask);
437 let sibling = target.num_nodes();
438 result.push(self.nodes[known + sibling - 1]);
439
440 target = target.next_larger_tree()?;
442 while !(merges & target).is_empty() {
443 target = target.next_larger_tree()?;
444 }
445 merges ^= merges & target.all_smaller_trees_unchecked();
447 }
448 } else {
449 new_high = Forest::empty();
452 }
453
454 let mut new_peaks = to_forest ^ common_trees ^ new_high;
458 let old_peaks = to_forest ^ new_peaks;
459 let mut offset = old_peaks.num_nodes();
460 while !new_peaks.is_empty() {
461 let target = new_peaks.largest_tree_unchecked();
462 offset += target.num_nodes();
463 result.push(self.nodes[offset - 1]);
464 new_peaks ^= target;
465 }
466
467 Ok(MmrDelta { forest: to_forest, data: result })
468 }
469
470 pub fn inner_nodes(&self) -> MmrNodes<'_> {
472 MmrNodes {
473 mmr: self,
474 forest: 0,
475 last_right: 0,
476 index: 0,
477 }
478 }
479
480 fn collect_merkle_path_and_value(
491 &self,
492 leaf_idx: usize,
493 forest: Forest,
494 ) -> Result<(Word, Vec<Word>), MmrError> {
495 let tree_bit = forest
497 .leaf_to_corresponding_tree(leaf_idx)
498 .ok_or(MmrError::PositionNotFound(leaf_idx))?;
499
500 let forest_before = forest.trees_larger_than(tree_bit);
502 let index_offset = forest_before.num_nodes();
503
504 let relative_pos = leaf_idx - forest_before.num_leaves();
506
507 let tree_depth = (tree_bit + 1) as usize;
509 let mut path = Vec::with_capacity(tree_depth);
510
511 let mut forest_target: usize = 1usize << tree_bit;
513 let mut index = nodes_from_mask(forest_target) - 1;
514
515 while forest_target > 1 {
517 forest_target >>= 1;
519
520 let right_offset = index - 1;
522 let left_offset = right_offset - nodes_from_mask(forest_target);
523
524 let left_or_right = relative_pos & forest_target;
525 let sibling = if left_or_right != 0 {
526 index = right_offset;
528 self.nodes[index_offset + left_offset]
530 } else {
531 index = left_offset;
532 self.nodes[index_offset + right_offset]
533 };
534
535 path.push(sibling);
536 }
537
538 debug_assert!(path.len() == tree_depth - 1);
539
540 path.reverse();
543
544 let value = self.nodes[index_offset + index];
545 Ok((value, path))
546 }
547}
548
549impl Serializable for Mmr {
558 fn write_into<W: ByteWriter>(&self, target: &mut W) {
559 self.forest.write_into(target);
560 target.write_usize(self.nodes.len());
563 target.write_many(self.nodes.iter());
564 }
565}
566
567impl Deserializable for Mmr {
568 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
569 let forest = Forest::read_from(source)?;
570 let count = source.read_usize()?;
571 if count != forest.num_nodes() {
573 return Err(DeserializationError::InvalidValue(
574 MmrError::InvalidNodeCount {
575 expected: forest.num_nodes(),
576 actual: count,
577 }
578 .to_string(),
579 ));
580 }
581 let nodes = source.read_many_iter(count)?.collect::<Result<NodeStore, _>>()?;
582 Self::from_serialized_parts(forest, nodes).map_err(DeserializationError::InvalidValue)
583 }
584}
585
586#[derive(Clone, Debug)]
595pub(super) struct MmrNodeIter<'a> {
596 current: slice::Iter<'a, Word>,
598 chunks: &'a [Arc<Vec<Word>>],
600}
601
602impl<'a> MmrNodeIter<'a> {
603 fn advance_chunk(&mut self) -> Option<()> {
608 match self.chunks.split_first() {
609 Some((chunk, rest)) => {
610 self.current = chunk.iter();
611 self.chunks = rest;
612 Some(())
613 },
614 None => {
615 self.current = [].iter();
616 None
617 },
618 }
619 }
620}
621
622impl<'a> Iterator for MmrNodeIter<'a> {
623 type Item = &'a Word;
624
625 fn next(&mut self) -> Option<&'a Word> {
626 loop {
627 if let Some(node) = self.current.next() {
628 return Some(node);
629 }
630 self.advance_chunk()?;
631 }
632 }
633
634 fn nth(&mut self, mut n: usize) -> Option<&'a Word> {
635 loop {
636 let len = self.current.len();
637 if n < len {
638 return self.current.nth(n);
639 }
640 n -= len;
641 self.advance_chunk()?;
642 }
643 }
644
645 fn size_hint(&self) -> (usize, Option<usize>) {
646 let len = self.len();
647 (len, Some(len))
648 }
649
650 fn count(self) -> usize {
651 self.len()
652 }
653}
654
655impl ExactSizeIterator for MmrNodeIter<'_> {
656 fn len(&self) -> usize {
657 self.current.len()
658 + match self.chunks.split_last() {
659 Some((last, full)) => full.len() * NODE_CHUNK_CAPACITY + last.len(),
660 None => 0,
661 }
662 }
663}
664
665impl FusedIterator for MmrNodeIter<'_> {}
666
667pub struct MmrNodes<'a> {
669 mmr: &'a Mmr,
671 forest: usize,
675 last_right: usize,
678 index: usize,
680}
681
682impl Iterator for MmrNodes<'_> {
683 type Item = InnerNodeInfo;
684
685 fn next(&mut self) -> Option<Self::Item> {
686 debug_assert!(self.last_right.count_ones() <= 1, "last_right tracks zero or one element");
687
688 let target = self.mmr.forest.without_single_leaf().num_leaves();
690
691 if self.forest < target {
692 if self.last_right == 0 {
693 debug_assert!(self.last_right == 0, "left must be before right");
695 self.forest |= 1;
696 self.index += 1;
697
698 debug_assert!((self.forest & 1) == 1, "right must be after left");
700 self.last_right |= 1;
701 self.index += 1;
702 };
703
704 debug_assert!(
705 self.forest & self.last_right != 0,
706 "parent requires both a left and right",
707 );
708
709 let right_nodes = Forest::new(self.last_right).unwrap().num_nodes();
712 let parent = self.last_right << 1;
714
715 self.forest ^= self.last_right;
718 if self.forest & parent == 0 {
719 debug_assert!(self.forest & 1 == 0, "next iteration yields a left leaf");
721 self.last_right = 0;
722 self.forest ^= parent;
723 } else {
724 self.last_right = parent;
727 }
728
729 let value = self.mmr.nodes[self.index];
731 let right = self.mmr.nodes[self.index - 1];
732 let left = self.mmr.nodes[self.index - 1 - right_nodes];
733 self.index += 1;
734 let node = InnerNodeInfo { value, left, right };
735
736 Some(node)
737 } else {
738 None
739 }
740 }
741}
742
743#[cfg(test)]
746mod tests {
747 use alloc::{sync::Arc, vec::Vec};
748
749 use super::{super::nodes_from_mask, NODE_CHUNK_CAPACITY};
750 use crate::{
751 Felt, Word, ZERO,
752 merkle::mmr::{Forest, Mmr, MmrError},
753 utils::{Deserializable, DeserializationError, Serializable},
754 };
755
756 fn leaves(count: u64) -> impl Iterator<Item = Word> {
757 (0..count).map(|value| Word::new([ZERO, ZERO, ZERO, Felt::new_unchecked(value)]))
758 }
759
760 #[test]
761 fn test_serialization() {
762 let nodes = (0u64..128u64)
763 .map(|value| Word::new([ZERO, ZERO, ZERO, Felt::new_unchecked(value)]))
764 .collect::<Vec<_>>();
765
766 let mmr = Mmr::try_from_iter(nodes).unwrap();
767 let serialized = mmr.to_bytes();
768 let deserialized = Mmr::read_from_bytes(&serialized).unwrap();
769 assert_eq!(mmr.forest, deserialized.forest);
770 assert_eq!(mmr.nodes, deserialized.nodes);
771 }
772
773 #[test]
774 fn test_deserialization_rejects_large_forest() {
775 let mut bytes = (Forest::MAX_LEAVES + 1).to_bytes();
776 bytes.extend_from_slice(&0usize.to_bytes()); let result = Mmr::read_from_bytes(&bytes);
779 assert!(matches!(result, Err(DeserializationError::InvalidValue(_))));
780 }
781
782 #[test]
783 fn test_serialization_matches_vec_format() {
784 let num_leaves = NODE_CHUNK_CAPACITY as u64 + NODE_CHUNK_CAPACITY as u64 / 2;
786 let mmr = Mmr::try_from_iter(leaves(num_leaves)).unwrap();
787 assert!(mmr.nodes.len() > 2 * NODE_CHUNK_CAPACITY);
788
789 let mut expected = mmr.forest.to_bytes();
790 let nodes_vec: Vec<Word> = mmr.nodes.iter().copied().collect();
791 expected.extend_from_slice(&nodes_vec.to_bytes());
792
793 assert_eq!(mmr.to_bytes(), expected);
794 let deserialized = Mmr::read_from_bytes(&expected).unwrap();
795 assert_eq!(mmr.forest, deserialized.forest);
796 assert_eq!(mmr.nodes, deserialized.nodes);
797 }
798
799 #[test]
800 fn test_deserialization_rejects_node_count_mismatch() {
801 let mmr = Mmr::try_from_iter(leaves(8)).unwrap();
802 let mut bytes = mmr.forest.to_bytes();
803 let mut nodes_vec: Vec<Word> = mmr.nodes.iter().copied().collect();
804 nodes_vec.pop();
805 bytes.extend_from_slice(&nodes_vec.to_bytes());
806
807 let result = Mmr::read_from_bytes(&bytes);
808 assert!(matches!(result, Err(DeserializationError::InvalidValue(_))));
809 }
810
811 #[test]
812 fn test_clone_stays_frozen_after_push() {
813 let num_leaves = 2 * NODE_CHUNK_CAPACITY as u64;
814 let mut mmr = Mmr::try_from_iter(leaves(num_leaves)).unwrap();
815 let clone = mmr.clone();
816
817 for leaf in leaves(3 * NODE_CHUNK_CAPACITY as u64).skip(num_leaves as usize) {
818 mmr.add(leaf).unwrap();
819 }
820
821 let reference = Mmr::try_from_iter(leaves(num_leaves)).unwrap();
823 assert_eq!(clone.forest, reference.forest);
824 assert_eq!(clone.nodes, reference.nodes);
825 assert_eq!(clone.peaks(), reference.peaks());
826
827 let reference = Mmr::try_from_iter(leaves(3 * NODE_CHUNK_CAPACITY as u64)).unwrap();
829 assert_eq!(mmr.forest, reference.forest);
830 assert_eq!(mmr.nodes, reference.nodes);
831 assert_eq!(mmr.peaks(), reference.peaks());
832 }
833
834 #[test]
835 fn test_clone_shares_full_chunks() {
836 let mut mmr = Mmr::try_from_iter(leaves(NODE_CHUNK_CAPACITY as u64)).unwrap();
837 let clone = mmr.clone();
838 mmr.add(Word::empty()).unwrap();
839
840 let orig_chunks = &mmr.nodes.chunks;
842 let clone_chunks = &clone.nodes.chunks;
843 assert_eq!(orig_chunks.len(), clone_chunks.len());
844 for (orig, cloned) in orig_chunks.iter().zip(clone_chunks).take(orig_chunks.len() - 1) {
845 assert!(Arc::ptr_eq(orig, cloned));
846 }
847 assert!(!Arc::ptr_eq(orig_chunks.last().unwrap(), clone_chunks.last().unwrap()));
848 }
849
850 #[test]
851 fn test_nodes_from() {
852 let mmr = Mmr::try_from_iter(leaves(2 * NODE_CHUNK_CAPACITY as u64)).unwrap();
854 let num_nodes = mmr.forest().num_nodes();
855 let all: Vec<Word> = mmr.nodes_from(0).copied().collect();
856 assert_eq!(all.len(), num_nodes);
857
858 for start in [
860 0,
861 1,
862 NODE_CHUNK_CAPACITY - 1,
863 NODE_CHUNK_CAPACITY,
864 NODE_CHUNK_CAPACITY + 1,
865 num_nodes - 1,
866 num_nodes,
867 num_nodes + 1,
868 ] {
869 let suffix: Vec<Word> = mmr.nodes_from(start).copied().collect();
870 assert_eq!(suffix, all[start.min(num_nodes)..]);
871 }
872 }
873
874 #[test]
875 fn test_node_iter_skip_matches_nodes_from() {
876 let mmr = Mmr::try_from_iter(leaves(2 * NODE_CHUNK_CAPACITY as u64)).unwrap();
878 let num_nodes = mmr.forest().num_nodes();
879 let all: Vec<Word> = mmr.nodes_from(0).copied().collect();
880
881 for start in [
882 0,
883 1,
884 NODE_CHUNK_CAPACITY - 1,
885 NODE_CHUNK_CAPACITY,
886 NODE_CHUNK_CAPACITY + 1,
887 num_nodes - 1,
888 num_nodes,
889 num_nodes + 1,
890 ] {
891 let skipped: Vec<Word> = mmr.nodes_from(0).skip(start).copied().collect();
892 assert_eq!(skipped, all[start.min(num_nodes)..]);
893 }
894
895 let mut iter = mmr.nodes_from(0);
897 assert_eq!(iter.nth(NODE_CHUNK_CAPACITY + 1), Some(&all[NODE_CHUNK_CAPACITY + 1]));
898 assert_eq!(iter.next(), Some(&all[NODE_CHUNK_CAPACITY + 2]));
899
900 let mut iter = mmr.nodes_from(0);
902 assert_eq!(iter.nth(num_nodes), None);
903 assert_eq!(iter.next(), None);
904 }
905
906 #[test]
907 fn test_node_iter_len() {
908 let mmr = Mmr::try_from_iter(leaves(2 * NODE_CHUNK_CAPACITY as u64)).unwrap();
909 let num_nodes = mmr.forest().num_nodes();
910
911 for start in [0, 1, NODE_CHUNK_CAPACITY, num_nodes - 1, num_nodes, num_nodes + 1] {
912 let iter = mmr.nodes_from(start);
913 assert_eq!(iter.len(), num_nodes.saturating_sub(start));
914 assert_eq!(iter.size_hint(), (iter.len(), Some(iter.len())));
915 }
916
917 let mut iter = mmr.nodes_from(0);
919 iter.next();
920 assert_eq!(iter.len(), num_nodes - 1);
921 iter.nth(NODE_CHUNK_CAPACITY);
922 assert_eq!(iter.len(), num_nodes - NODE_CHUNK_CAPACITY - 2);
923 assert_eq!(iter.count(), num_nodes - NODE_CHUNK_CAPACITY - 2);
924 }
925
926 #[test]
927 fn test_nodes_from_incremental_persistence() {
928 let initial_leaves = NODE_CHUNK_CAPACITY as u64 / 2;
931 let final_leaves = 2 * NODE_CHUNK_CAPACITY as u64;
932
933 let mut mmr = Mmr::try_from_iter(leaves(initial_leaves)).unwrap();
934 let mut persisted: Vec<Word> = mmr.nodes_from(0).copied().collect();
935
936 for leaf in leaves(final_leaves).skip(initial_leaves as usize) {
937 mmr.add(leaf).unwrap();
938 }
939 persisted.extend(mmr.nodes_from(persisted.len()).copied());
940
941 assert_eq!(persisted.len(), mmr.forest().num_nodes());
942 assert!(mmr.nodes == persisted.as_slice());
943 }
944
945 #[test]
946 fn test_from_nodes_unchecked_round_trip() {
947 let multi_chunk = NODE_CHUNK_CAPACITY as u64 + NODE_CHUNK_CAPACITY as u64 / 2;
949 for num_leaves in [0, 1, 8, multi_chunk] {
950 let mmr = Mmr::try_from_iter(leaves(num_leaves)).unwrap();
951 let rebuilt =
952 Mmr::from_nodes_unchecked(mmr.forest(), mmr.nodes_from(0).copied()).unwrap();
953 assert_eq!(mmr.forest, rebuilt.forest);
954 assert_eq!(mmr.nodes, rebuilt.nodes);
955 assert_eq!(mmr.peaks(), rebuilt.peaks());
956
957 let peaks = rebuilt.peaks();
959 for pos in [0, num_leaves.saturating_sub(1) as usize] {
960 if num_leaves > 0 {
961 let proof = rebuilt.open(pos).unwrap();
962 let leaf = rebuilt.get(pos).unwrap();
963 peaks.verify(leaf, proof).unwrap();
964 }
965 }
966 }
967 }
968
969 #[test]
970 fn test_from_nodes_unchecked_rejects_count_mismatch() {
971 let mmr = Mmr::try_from_iter(leaves(8)).unwrap();
972 let nodes: Vec<Word> = mmr.nodes_from(0).copied().collect();
973
974 let too_few =
975 Mmr::from_nodes_unchecked(mmr.forest(), nodes.iter().copied().take(nodes.len() - 1));
976 assert!(matches!(
977 too_few,
978 Err(MmrError::InvalidNodeCount { expected, actual })
979 if expected == nodes.len() && actual == nodes.len() - 1
980 ));
981
982 let too_many =
983 Mmr::from_nodes_unchecked(mmr.forest(), nodes.iter().copied().chain([Word::empty()]));
984 assert!(matches!(
985 too_many,
986 Err(MmrError::InvalidNodeCount { expected, actual })
987 if expected == nodes.len() && actual == nodes.len() + 1
988 ));
989 }
990
991 #[test]
992 fn test_nodes_from_mask_at_max_leaves() {
993 let expected = (Forest::MAX_LEAVES as u128)
994 .saturating_mul(2)
995 .saturating_sub(Forest::MAX_LEAVES.count_ones() as u128);
996 assert!(expected <= usize::MAX as u128);
997 assert_eq!(nodes_from_mask(Forest::MAX_LEAVES), expected as usize);
998 }
999}