diff --git a/core/src/core/pmmr.rs b/core/src/core/pmmr.rs index 3f5cefa9f..4ebb4e86a 100644 --- a/core/src/core/pmmr.rs +++ b/core/src/core/pmmr.rs @@ -36,9 +36,8 @@ //! either be a simple Vec or a database. use core::hash::Hash; -use ser; -use ser::{PMMRIndexHashable, PMMRable}; -use ser::{Readable, Reader, Writeable, Writer}; +use ser::{self, PMMRIndexHashable, PMMRable, Readable, Reader, Writeable, Writer}; + use std::clone::Clone; use std::marker; use util; @@ -267,7 +266,8 @@ where T: PMMRable, B: 'a + Backend, { - last_pos: u64, + /// The last position in the PMMR + pub last_pos: u64, backend: &'a mut B, // only needed for parameterizing Backend _marker: marker::PhantomData, @@ -288,8 +288,7 @@ where } /// Build a new prunable Merkle Mountain Range pre-initialized until - /// last_pos - /// with the provided backend. + /// last_pos with the provided backend. pub fn at(backend: &'a mut B, last_pos: u64) -> PMMR { PMMR { last_pos: last_pos, @@ -1020,1005 +1019,13 @@ fn bintree_jump_left(num: u64) -> u64 { num - ((1 << (most_significant_pos(num) - 1)) - 1) } -// Check if the binary representation of a number is all ones. -fn all_ones(num: u64) -> bool { +/// Check if the binary representation of a number is all ones. +pub fn all_ones(num: u64) -> bool { let ones = num.count_ones(); num.leading_zeros() + ones == 64 && ones > 0 } -// Get the position of the most significant bit in a number. -fn most_significant_pos(num: u64) -> u64 { +/// Get the position of the most significant bit in a number. +pub fn most_significant_pos(num: u64) -> u64 { 64 - u64::from(num.leading_zeros()) } - -#[cfg(test)] -mod test { - use super::*; - use core::hash::Hash; - use core::{Reader, Writer}; - use ser::{Error, Readable, Writeable}; - use ser::{PMMRIndexHashable, PMMRable}; - - /// Simple MMR backend implementation based on a Vector. Pruning does not - /// compact the Vec itself. - #[derive(Clone, Debug)] - pub struct VecBackend - where - T: PMMRable, - { - /// Backend elements - pub elems: Vec)>>, - /// Positions of removed elements - pub remove_list: Vec, - } - - impl Backend for VecBackend - where - T: PMMRable, - { - fn append(&mut self, _position: u64, data: Vec<(Hash, Option)>) -> Result<(), String> { - self.elems.append(&mut map_vec!(data, |d| Some(d.clone()))); - Ok(()) - } - - fn get_hash(&self, position: u64) -> Option { - if self.remove_list.contains(&position) { - None - } else { - if let Some(ref elem) = self.elems[(position - 1) as usize] { - Some(elem.0) - } else { - None - } - } - } - - fn get_data(&self, position: u64) -> Option { - if self.remove_list.contains(&position) { - None - } else { - if let Some(ref elem) = self.elems[(position - 1) as usize] { - elem.1.clone() - } else { - None - } - } - } - - fn get_from_file(&self, position: u64) -> Option { - if let Some(ref x) = self.elems[(position - 1) as usize] { - Some(x.0) - } else { - None - } - } - - fn get_data_from_file(&self, position: u64) -> Option { - if let Some(ref x) = self.elems[(position - 1) as usize] { - x.1.clone() - } else { - None - } - } - - fn remove(&mut self, positions: Vec, _index: u32) -> Result<(), String> { - for n in positions { - self.remove_list.push(n) - } - Ok(()) - } - - fn rewind(&mut self, position: u64, _index: u32) -> Result<(), String> { - self.elems = self.elems[0..(position as usize) + 1].to_vec(); - Ok(()) - } - - fn get_data_file_path(&self) -> String { - "".to_string() - } - - fn dump_stats(&self) {} - } - - impl VecBackend - where - T: PMMRable, - { - /// Instantiates a new VecBackend - pub fn new() -> VecBackend { - VecBackend { - elems: vec![], - remove_list: vec![], - } - } - - /// Current number of elements in the underlying Vec. - pub fn used_size(&self) -> usize { - let mut usz = self.elems.len(); - for (idx, _) in self.elems.iter().enumerate() { - let idx = idx as u64; - if self.remove_list.contains(&idx) { - usz -= 1; - } - } - usz - } - } - - #[test] - fn some_all_ones() { - for n in vec![1, 7, 255] { - assert!(all_ones(n), "{} should be all ones", n); - } - for n in vec![0, 6, 9, 128] { - assert!(!all_ones(n), "{} should not be all ones", n); - } - } - - #[test] - fn some_most_signif() { - assert_eq!(most_significant_pos(0), 0); - assert_eq!(most_significant_pos(1), 1); - assert_eq!(most_significant_pos(6), 3); - assert_eq!(most_significant_pos(7), 3); - assert_eq!(most_significant_pos(8), 4); - assert_eq!(most_significant_pos(128), 8); - } - - #[test] - #[allow(unused_variables)] - fn first_100_mmr_heights() { - let first_100_str = "0 0 1 0 0 1 2 0 0 1 0 0 1 2 3 0 0 1 0 0 1 2 0 0 1 0 0 1 2 3 4 \ - 0 0 1 0 0 1 2 0 0 1 0 0 1 2 3 0 0 1 0 0 1 2 0 0 1 0 0 1 2 3 4 5 \ - 0 0 1 0 0 1 2 0 0 1 0 0 1 2 3 0 0 1 0 0 1 2 0 0 1 0 0 1 2 3 4 0 0 1 0 0"; - let first_100 = first_100_str.split(' ').map(|n| n.parse::().unwrap()); - let mut count = 1; - for n in first_100 { - assert_eq!( - n, - bintree_postorder_height(count), - "expected {}, got {}", - n, - bintree_postorder_height(count) - ); - count += 1; - } - } - - #[test] - fn test_n_leaves() { - // make sure we handle an empty MMR correctly - assert_eq!(n_leaves(0), 0); - - // and various sizes on non-empty MMRs - assert_eq!(n_leaves(1), 1); - assert_eq!(n_leaves(2), 2); - assert_eq!(n_leaves(3), 2); - assert_eq!(n_leaves(4), 3); - assert_eq!(n_leaves(5), 4); - assert_eq!(n_leaves(6), 4); - assert_eq!(n_leaves(7), 4); - assert_eq!(n_leaves(8), 5); - assert_eq!(n_leaves(9), 6); - assert_eq!(n_leaves(10), 6); - } - - /// Find parent and sibling positions for various node positions. - #[test] - fn various_families() { - // 0 0 1 0 0 1 2 0 0 1 0 0 1 2 3 - assert_eq!(family(1), (3, 2)); - assert_eq!(family(2), (3, 1)); - assert_eq!(family(3), (7, 6)); - assert_eq!(family(4), (6, 5)); - assert_eq!(family(5), (6, 4)); - assert_eq!(family(6), (7, 3)); - assert_eq!(family(7), (15, 14)); - assert_eq!(family(1_000), (1_001, 997)); - } - - #[test] - fn test_is_left_sibling() { - assert_eq!(is_left_sibling(1), true); - assert_eq!(is_left_sibling(2), false); - assert_eq!(is_left_sibling(3), true); - } - - #[test] - fn various_branches() { - // the two leaf nodes in a 3 node tree (height 1) - assert_eq!(family_branch(1, 3), [(3, 2)]); - assert_eq!(family_branch(2, 3), [(3, 1)]); - - // the root node in a 3 node tree - assert_eq!(family_branch(3, 3), []); - - // leaf node in a larger tree of 7 nodes (height 2) - assert_eq!(family_branch(1, 7), [(3, 2), (7, 6)]); - - // note these only go as far up as the local peak, not necessarily the single - // root - assert_eq!(family_branch(1, 4), [(3, 2)]); - // pos 4 in a tree of size 4 is a local peak - assert_eq!(family_branch(4, 4), []); - // pos 4 in a tree of size 5 is also still a local peak - assert_eq!(family_branch(4, 5), []); - // pos 4 in a tree of size 6 has a parent and a sibling - assert_eq!(family_branch(4, 6), [(6, 5)]); - // a tree of size 7 is all under a single root - assert_eq!(family_branch(4, 7), [(6, 5), (7, 3)]); - - // ok now for a more realistic one, a tree with over a million nodes in it - // find the "family path" back up the tree from a leaf node at 0 - // Note: the first two entries in the branch are consistent with a small 7 node - // tree Note: each sibling is on the left branch, this is an example of the - // largest possible list of peaks before we start combining them into larger - // peaks. - assert_eq!( - family_branch(1, 1_049_000), - [ - (3, 2), - (7, 6), - (15, 14), - (31, 30), - (63, 62), - (127, 126), - (255, 254), - (511, 510), - (1023, 1022), - (2047, 2046), - (4095, 4094), - (8191, 8190), - (16383, 16382), - (32767, 32766), - (65535, 65534), - (131071, 131070), - (262143, 262142), - (524287, 524286), - (1048575, 1048574), - ] - ); - } - - #[test] - fn some_peaks() { - // 0 0 1 0 0 1 2 0 0 1 0 0 1 2 3 - - let empty: Vec = vec![]; - - // make sure we handle an empty MMR correctly - assert_eq!(peaks(0), empty); - - // and various non-empty MMRs - assert_eq!(peaks(1), [1]); - assert_eq!(peaks(2), empty); - assert_eq!(peaks(3), [3]); - assert_eq!(peaks(4), [3, 4]); - assert_eq!(peaks(5), empty); - assert_eq!(peaks(6), empty); - assert_eq!(peaks(7), [7]); - assert_eq!(peaks(8), [7, 8]); - assert_eq!(peaks(9), empty); - assert_eq!(peaks(10), [7, 10]); - assert_eq!(peaks(11), [7, 10, 11]); - assert_eq!(peaks(22), [15, 22]); - assert_eq!(peaks(32), [31, 32]); - assert_eq!(peaks(35), [31, 34, 35]); - assert_eq!(peaks(42), [31, 38, 41, 42]); - - // large realistic example with almost 1.5 million nodes - // note the distance between peaks decreases toward the right (trees get - // smaller) - assert_eq!( - peaks(1048555), - [ - 524287, 786430, 917501, 983036, 1015803, 1032186, 1040377, 1044472, 1046519, - 1047542, 1048053, 1048308, 1048435, 1048498, 1048529, 1048544, 1048551, 1048554, - 1048555, - ], - ); - } - - #[derive(Copy, Clone, Debug, PartialEq, Eq)] - struct TestElem([u32; 4]); - - impl PMMRable for TestElem { - fn len() -> usize { - 16 - } - } - - impl Writeable for TestElem { - fn write(&self, writer: &mut W) -> Result<(), Error> { - writer.write_u32(self.0[0])?; - writer.write_u32(self.0[1])?; - writer.write_u32(self.0[2])?; - writer.write_u32(self.0[3]) - } - } - - impl Readable for TestElem { - fn read(reader: &mut Reader) -> Result { - Ok(TestElem([ - reader.read_u32()?, - reader.read_u32()?, - reader.read_u32()?, - reader.read_u32()?, - ])) - } - } - - #[test] - fn empty_merkle_proof() { - let proof = MerkleProof::empty(); - assert_eq!(proof.verify(), false); - } - - #[test] - fn pmmr_merkle_proof() { - // 0 0 1 0 0 1 2 0 0 1 0 0 1 2 3 - - let mut ba = VecBackend::new(); - let mut pmmr = PMMR::new(&mut ba); - - pmmr.push(TestElem([0, 0, 0, 1])).unwrap(); - assert_eq!(pmmr.last_pos, 1); - let proof = pmmr.merkle_proof(1).unwrap(); - let root = pmmr.root(); - assert_eq!(proof.peaks, [root]); - assert!(proof.path.is_empty()); - assert!(proof.verify()); - - // push two more elements into the PMMR - pmmr.push(TestElem([0, 0, 0, 2])).unwrap(); - pmmr.push(TestElem([0, 0, 0, 3])).unwrap(); - assert_eq!(pmmr.last_pos, 4); - - let proof1 = pmmr.merkle_proof(1).unwrap(); - assert_eq!(proof1.peaks.len(), 2); - assert_eq!(proof1.path.len(), 1); - assert!(proof1.verify()); - - let proof2 = pmmr.merkle_proof(2).unwrap(); - assert_eq!(proof2.peaks.len(), 2); - assert_eq!(proof2.path.len(), 1); - assert!(proof2.verify()); - - // check that we cannot generate a merkle proof for pos 3 (not a leaf node) - assert_eq!( - pmmr.merkle_proof(3).err(), - Some(format!("not a leaf at pos 3")) - ); - - let proof4 = pmmr.merkle_proof(4).unwrap(); - assert_eq!(proof4.peaks.len(), 2); - assert!(proof4.path.is_empty()); - assert!(proof4.verify()); - - // now add a few more elements to the PMMR to build a larger merkle proof - for x in 4..1000 { - pmmr.push(TestElem([0, 0, 0, x])).unwrap(); - } - let proof = pmmr.merkle_proof(1).unwrap(); - assert_eq!(proof.peaks.len(), 8); - assert_eq!(proof.path.len(), 9); - assert!(proof.verify()); - } - - #[test] - fn pmmr_merkle_proof_prune_and_rewind() { - let mut ba = VecBackend::new(); - let mut pmmr = PMMR::new(&mut ba); - pmmr.push(TestElem([0, 0, 0, 1])).unwrap(); - pmmr.push(TestElem([0, 0, 0, 2])).unwrap(); - let proof = pmmr.merkle_proof(2).unwrap(); - - // now prune an element and check we can still generate - // the correct Merkle proof for the other element (after sibling pruned) - pmmr.prune(1, 1).unwrap(); - let proof_2 = pmmr.merkle_proof(2).unwrap(); - assert_eq!(proof, proof_2); - } - - #[test] - fn merkle_proof_ser_deser() { - let mut ba = VecBackend::new(); - let mut pmmr = PMMR::new(&mut ba); - for x in 0..15 { - pmmr.push(TestElem([0, 0, 0, x])).unwrap(); - } - let proof = pmmr.merkle_proof(9).unwrap(); - assert!(proof.verify()); - - let mut vec = Vec::new(); - ser::serialize(&mut vec, &proof).expect("serialization failed"); - let proof_2: MerkleProof = ser::deserialize(&mut &vec[..]).unwrap(); - - assert_eq!(proof, proof_2); - } - - #[test] - #[allow(unused_variables)] - fn pmmr_push_root() { - let elems = [ - TestElem([0, 0, 0, 1]), - TestElem([0, 0, 0, 2]), - TestElem([0, 0, 0, 3]), - TestElem([0, 0, 0, 4]), - TestElem([0, 0, 0, 5]), - TestElem([0, 0, 0, 6]), - TestElem([0, 0, 0, 7]), - TestElem([0, 0, 0, 8]), - TestElem([1, 0, 0, 0]), - ]; - - let mut ba = VecBackend::new(); - let mut pmmr = PMMR::new(&mut ba); - - // one element - pmmr.push(elems[0]).unwrap(); - pmmr.dump(false); - let pos_0 = elems[0].hash_with_index(0); - assert_eq!(pmmr.peaks(), vec![pos_0]); - assert_eq!(pmmr.root(), pos_0); - assert_eq!(pmmr.unpruned_size(), 1); - - // two elements - pmmr.push(elems[1]).unwrap(); - pmmr.dump(false); - let pos_1 = elems[1].hash_with_index(1); - let pos_2 = (pos_0, pos_1).hash_with_index(2); - assert_eq!(pmmr.peaks(), vec![pos_2]); - assert_eq!(pmmr.root(), pos_2); - assert_eq!(pmmr.unpruned_size(), 3); - - // three elements - pmmr.push(elems[2]).unwrap(); - pmmr.dump(false); - let pos_3 = elems[2].hash_with_index(3); - assert_eq!(pmmr.peaks(), vec![pos_2, pos_3]); - assert_eq!(pmmr.root(), (pos_2, pos_3).hash_with_index(4)); - assert_eq!(pmmr.unpruned_size(), 4); - - // four elements - pmmr.push(elems[3]).unwrap(); - pmmr.dump(false); - let pos_4 = elems[3].hash_with_index(4); - let pos_5 = (pos_3, pos_4).hash_with_index(5); - let pos_6 = (pos_2, pos_5).hash_with_index(6); - assert_eq!(pmmr.peaks(), vec![pos_6]); - assert_eq!(pmmr.root(), pos_6); - assert_eq!(pmmr.unpruned_size(), 7); - - // five elements - pmmr.push(elems[4]).unwrap(); - pmmr.dump(false); - let pos_7 = elems[4].hash_with_index(7); - assert_eq!(pmmr.peaks(), vec![pos_6, pos_7]); - assert_eq!(pmmr.root(), (pos_6, pos_7).hash_with_index(8)); - assert_eq!(pmmr.unpruned_size(), 8); - - // six elements - pmmr.push(elems[5]).unwrap(); - let pos_8 = elems[5].hash_with_index(8); - let pos_9 = (pos_7, pos_8).hash_with_index(9); - assert_eq!(pmmr.peaks(), vec![pos_6, pos_9]); - assert_eq!(pmmr.root(), (pos_6, pos_9).hash_with_index(10)); - assert_eq!(pmmr.unpruned_size(), 10); - - // seven elements - pmmr.push(elems[6]).unwrap(); - let pos_10 = elems[6].hash_with_index(10); - assert_eq!(pmmr.peaks(), vec![pos_6, pos_9, pos_10]); - assert_eq!( - pmmr.root(), - (pos_6, (pos_9, pos_10).hash_with_index(11)).hash_with_index(11) - ); - assert_eq!(pmmr.unpruned_size(), 11); - - // 001001200100123 - // eight elements - pmmr.push(elems[7]).unwrap(); - let pos_11 = elems[7].hash_with_index(11); - let pos_12 = (pos_10, pos_11).hash_with_index(12); - let pos_13 = (pos_9, pos_12).hash_with_index(13); - let pos_14 = (pos_6, pos_13).hash_with_index(14); - assert_eq!(pmmr.peaks(), vec![pos_14]); - assert_eq!(pmmr.root(), pos_14); - assert_eq!(pmmr.unpruned_size(), 15); - - // nine elements - pmmr.push(elems[8]).unwrap(); - let pos_15 = elems[8].hash_with_index(15); - assert_eq!(pmmr.peaks(), vec![pos_14, pos_15]); - assert_eq!(pmmr.root(), (pos_14, pos_15).hash_with_index(16)); - assert_eq!(pmmr.unpruned_size(), 16); - } - - #[test] - fn pmmr_get_last_n_insertions() { - let elems = [ - TestElem([0, 0, 0, 1]), - TestElem([0, 0, 0, 2]), - TestElem([0, 0, 0, 3]), - TestElem([0, 0, 0, 4]), - TestElem([0, 0, 0, 5]), - TestElem([0, 0, 0, 6]), - TestElem([0, 0, 0, 7]), - TestElem([0, 0, 0, 8]), - TestElem([1, 0, 0, 0]), - ]; - - let mut ba = VecBackend::new(); - let mut pmmr = PMMR::new(&mut ba); - - // test when empty - let res = pmmr.get_last_n_insertions(19); - assert!(res.len() == 0); - - pmmr.push(elems[0]).unwrap(); - let res = pmmr.get_last_n_insertions(19); - assert!(res.len() == 1); - - pmmr.push(elems[1]).unwrap(); - - let res = pmmr.get_last_n_insertions(12); - assert!(res.len() == 2); - - pmmr.push(elems[2]).unwrap(); - - let res = pmmr.get_last_n_insertions(2); - assert!(res.len() == 2); - - pmmr.push(elems[3]).unwrap(); - - let res = pmmr.get_last_n_insertions(19); - assert!(res.len() == 4); - - pmmr.push(elems[5]).unwrap(); - pmmr.push(elems[6]).unwrap(); - pmmr.push(elems[7]).unwrap(); - pmmr.push(elems[8]).unwrap(); - - let res = pmmr.get_last_n_insertions(7); - assert!(res.len() == 7); - } - - #[test] - #[allow(unused_variables)] - fn pmmr_prune() { - let elems = [ - TestElem([0, 0, 0, 1]), - TestElem([0, 0, 0, 2]), - TestElem([0, 0, 0, 3]), - TestElem([0, 0, 0, 4]), - TestElem([0, 0, 0, 5]), - TestElem([0, 0, 0, 6]), - TestElem([0, 0, 0, 7]), - TestElem([0, 0, 0, 8]), - TestElem([1, 0, 0, 0]), - ]; - - let orig_root: Hash; - let sz: u64; - let mut ba = VecBackend::new(); - { - let mut pmmr = PMMR::new(&mut ba); - for elem in &elems[..] { - pmmr.push(*elem).unwrap(); - } - orig_root = pmmr.root(); - sz = pmmr.unpruned_size(); - } - - // pruning a leaf with no parent should do nothing - { - let mut pmmr: PMMR = PMMR::at(&mut ba, sz); - pmmr.prune(16, 0).unwrap(); - assert_eq!(orig_root, pmmr.root()); - } - assert_eq!(ba.used_size(), 16); - - // pruning leaves with no shared parent just removes 1 element - { - let mut pmmr: PMMR = PMMR::at(&mut ba, sz); - pmmr.prune(2, 0).unwrap(); - assert_eq!(orig_root, pmmr.root()); - } - assert_eq!(ba.used_size(), 15); - - { - let mut pmmr: PMMR = PMMR::at(&mut ba, sz); - pmmr.prune(4, 0).unwrap(); - assert_eq!(orig_root, pmmr.root()); - } - assert_eq!(ba.used_size(), 14); - - // pruning a non-leaf node has no effect - { - let mut pmmr: PMMR = PMMR::at(&mut ba, sz); - pmmr.prune(3, 0).unwrap_err(); - assert_eq!(orig_root, pmmr.root()); - } - assert_eq!(ba.used_size(), 14); - - // pruning sibling removes subtree - { - let mut pmmr: PMMR = PMMR::at(&mut ba, sz); - pmmr.prune(5, 0).unwrap(); - assert_eq!(orig_root, pmmr.root()); - } - assert_eq!(ba.used_size(), 12); - - // pruning all leaves under level >1 removes all subtree - { - let mut pmmr: PMMR = PMMR::at(&mut ba, sz); - pmmr.prune(1, 0).unwrap(); - assert_eq!(orig_root, pmmr.root()); - } - assert_eq!(ba.used_size(), 9); - - // pruning everything should only leave us with a single peak - { - let mut pmmr: PMMR = PMMR::at(&mut ba, sz); - for n in 1..16 { - let _ = pmmr.prune(n, 0); - } - assert_eq!(orig_root, pmmr.root()); - } - assert_eq!(ba.used_size(), 1); - } - - #[test] - fn pmmr_next_pruned_idx() { - let mut pl = PruneList::new(); - - assert_eq!(pl.pruned_nodes.len(), 0); - assert_eq!(pl.next_pruned_idx(1), Some(0)); - assert_eq!(pl.next_pruned_idx(2), Some(0)); - assert_eq!(pl.next_pruned_idx(3), Some(0)); - - pl.add(2); - assert_eq!(pl.pruned_nodes.len(), 1); - assert_eq!(pl.pruned_nodes, [2]); - assert_eq!(pl.next_pruned_idx(1), Some(0)); - assert_eq!(pl.next_pruned_idx(2), None); - assert_eq!(pl.next_pruned_idx(3), Some(1)); - assert_eq!(pl.next_pruned_idx(4), Some(1)); - - pl.add(1); - assert_eq!(pl.pruned_nodes.len(), 1); - assert_eq!(pl.pruned_nodes, [3]); - assert_eq!(pl.next_pruned_idx(1), None); - assert_eq!(pl.next_pruned_idx(2), None); - assert_eq!(pl.next_pruned_idx(3), None); - assert_eq!(pl.next_pruned_idx(4), Some(1)); - assert_eq!(pl.next_pruned_idx(5), Some(1)); - - pl.add(3); - assert_eq!(pl.pruned_nodes.len(), 1); - assert_eq!(pl.pruned_nodes, [3]); - assert_eq!(pl.next_pruned_idx(1), None); - assert_eq!(pl.next_pruned_idx(2), None); - assert_eq!(pl.next_pruned_idx(3), None); - assert_eq!(pl.next_pruned_idx(4), Some(1)); - assert_eq!(pl.next_pruned_idx(5), Some(1)); - } - - #[test] - fn pmmr_prune_leaf_shift() { - let mut pl = PruneList::new(); - - // start with an empty prune list (nothing shifted) - assert_eq!(pl.pruned_nodes.len(), 0); - assert_eq!(pl.get_leaf_shift(1), Some(0)); - assert_eq!(pl.get_leaf_shift(2), Some(0)); - assert_eq!(pl.get_leaf_shift(4), Some(0)); - - // now add a single leaf pos to the prune list - // note this does not shift anything (we only start shifting after pruning a - // parent) - pl.add(1); - assert_eq!(pl.pruned_nodes.len(), 1); - assert_eq!(pl.pruned_nodes, [1]); - assert_eq!(pl.get_leaf_shift(1), Some(0)); - assert_eq!(pl.get_leaf_shift(2), Some(0)); - assert_eq!(pl.get_leaf_shift(3), Some(0)); - assert_eq!(pl.get_leaf_shift(4), Some(0)); - - // now add the sibling leaf pos (pos 1 and pos 2) which will prune the parent - // at pos 3 this in turn will "leaf shift" the leaf at pos 3 by 2 - pl.add(2); - assert_eq!(pl.pruned_nodes.len(), 1); - assert_eq!(pl.pruned_nodes, [3]); - assert_eq!(pl.get_leaf_shift(1), None); - assert_eq!(pl.get_leaf_shift(2), None); - assert_eq!(pl.get_leaf_shift(3), Some(2)); - assert_eq!(pl.get_leaf_shift(4), Some(2)); - assert_eq!(pl.get_leaf_shift(5), Some(2)); - - // now prune an additional leaf at pos 4 - // leaf offset of subsequent pos will be 2 - // 00100120 - pl.add(4); - assert_eq!(pl.pruned_nodes, [3, 4]); - assert_eq!(pl.get_leaf_shift(1), None); - assert_eq!(pl.get_leaf_shift(2), None); - assert_eq!(pl.get_leaf_shift(3), Some(2)); - assert_eq!(pl.get_leaf_shift(4), Some(2)); - assert_eq!(pl.get_leaf_shift(5), Some(2)); - assert_eq!(pl.get_leaf_shift(6), Some(2)); - assert_eq!(pl.get_leaf_shift(7), Some(2)); - assert_eq!(pl.get_leaf_shift(8), Some(2)); - - // now prune the sibling at pos 5 - // the two smaller subtrees (pos 3 and pos 6) are rolled up to larger subtree - // (pos 7) the leaf offset is now 4 to cover entire subtree containing first - // 4 leaves 00100120 - pl.add(5); - assert_eq!(pl.pruned_nodes, [7]); - assert_eq!(pl.get_leaf_shift(1), None); - assert_eq!(pl.get_leaf_shift(2), None); - assert_eq!(pl.get_leaf_shift(3), None); - assert_eq!(pl.get_leaf_shift(4), None); - assert_eq!(pl.get_leaf_shift(5), None); - assert_eq!(pl.get_leaf_shift(6), None); - assert_eq!(pl.get_leaf_shift(7), Some(4)); - assert_eq!(pl.get_leaf_shift(8), Some(4)); - assert_eq!(pl.get_leaf_shift(9), Some(4)); - - // now check we can prune some of these in an arbitrary order - // final result is one leaf (pos 2) and one small subtree (pos 6) pruned - // with leaf offset of 2 to account for the pruned subtree - let mut pl = PruneList::new(); - pl.add(2); - pl.add(5); - pl.add(4); - assert_eq!(pl.pruned_nodes, [2, 6]); - assert_eq!(pl.get_leaf_shift(1), Some(0)); - assert_eq!(pl.get_leaf_shift(2), Some(0)); - assert_eq!(pl.get_leaf_shift(3), Some(0)); - assert_eq!(pl.get_leaf_shift(4), None); - assert_eq!(pl.get_leaf_shift(5), None); - assert_eq!(pl.get_leaf_shift(6), Some(2)); - assert_eq!(pl.get_leaf_shift(7), Some(2)); - assert_eq!(pl.get_leaf_shift(8), Some(2)); - assert_eq!(pl.get_leaf_shift(9), Some(2)); - - pl.add(1); - assert_eq!(pl.pruned_nodes, [7]); - assert_eq!(pl.get_leaf_shift(1), None); - assert_eq!(pl.get_leaf_shift(2), None); - assert_eq!(pl.get_leaf_shift(3), None); - assert_eq!(pl.get_leaf_shift(4), None); - assert_eq!(pl.get_leaf_shift(5), None); - assert_eq!(pl.get_leaf_shift(6), None); - assert_eq!(pl.get_leaf_shift(7), Some(4)); - assert_eq!(pl.get_leaf_shift(8), Some(4)); - assert_eq!(pl.get_leaf_shift(9), Some(4)); - } - - #[test] - fn pmmr_prune_shift() { - let mut pl = PruneList::new(); - assert!(pl.pruned_nodes.is_empty()); - assert_eq!(pl.get_shift(1), Some(0)); - assert_eq!(pl.get_shift(2), Some(0)); - assert_eq!(pl.get_shift(3), Some(0)); - - // prune a single leaf node - // pruning only a leaf node does not shift any subsequent pos - // we will only start shifting when a parent can be pruned - pl.add(1); - assert_eq!(pl.pruned_nodes, [1]); - assert_eq!(pl.get_shift(1), Some(0)); - assert_eq!(pl.get_shift(2), Some(0)); - assert_eq!(pl.get_shift(3), Some(0)); - - pl.add(2); - assert_eq!(pl.pruned_nodes, [3]); - assert_eq!(pl.get_shift(1), None); - assert_eq!(pl.get_shift(2), None); - // pos 3 is in the prune list, so removed but not compacted, but still shifted - assert_eq!(pl.get_shift(3), Some(2)); - assert_eq!(pl.get_shift(4), Some(2)); - assert_eq!(pl.get_shift(5), Some(2)); - assert_eq!(pl.get_shift(6), Some(2)); - - // pos 3 is not a leaf and is already in prune list - // prune it and check we are still consistent - pl.add(3); - assert_eq!(pl.pruned_nodes, [3]); - assert_eq!(pl.get_shift(1), None); - assert_eq!(pl.get_shift(2), None); - // pos 3 is in the prune list, so removed but not compacted, but still shifted - assert_eq!(pl.get_shift(3), Some(2)); - assert_eq!(pl.get_shift(4), Some(2)); - assert_eq!(pl.get_shift(5), Some(2)); - assert_eq!(pl.get_shift(6), Some(2)); - - pl.add(4); - assert_eq!(pl.pruned_nodes, [3, 4]); - assert_eq!(pl.get_shift(1), None); - assert_eq!(pl.get_shift(2), None); - // pos 3 is in the prune list, so removed but not compacted, but still shifted - assert_eq!(pl.get_shift(3), Some(2)); - // pos 4 is also in the prune list and also shifted by same amount - assert_eq!(pl.get_shift(4), Some(2)); - // subsequent nodes also shifted consistently - assert_eq!(pl.get_shift(5), Some(2)); - assert_eq!(pl.get_shift(6), Some(2)); - - pl.add(5); - assert_eq!(pl.pruned_nodes, [7]); - assert_eq!(pl.get_shift(1), None); - assert_eq!(pl.get_shift(2), None); - assert_eq!(pl.get_shift(3), None); - assert_eq!(pl.get_shift(4), None); - assert_eq!(pl.get_shift(5), None); - assert_eq!(pl.get_shift(6), None); - // everything prior to pos 7 is compacted away - // pos 7 is shifted by 6 to account for this - assert_eq!(pl.get_shift(7), Some(6)); - assert_eq!(pl.get_shift(8), Some(6)); - assert_eq!(pl.get_shift(9), Some(6)); - - // prune a bunch more - for x in 6..1000 { - pl.add(x); - } - // and check we shift by a large number (hopefully the correct number...) - assert_eq!(pl.get_shift(1010), Some(996)); - - let mut pl = PruneList::new(); - pl.add(2); - pl.add(5); - pl.add(4); - assert_eq!(pl.pruned_nodes, [2, 6]); - assert_eq!(pl.get_shift(1), Some(0)); - assert_eq!(pl.get_shift(2), Some(0)); - assert_eq!(pl.get_shift(3), Some(0)); - assert_eq!(pl.get_shift(4), None); - assert_eq!(pl.get_shift(5), None); - assert_eq!(pl.get_shift(6), Some(2)); - assert_eq!(pl.get_shift(7), Some(2)); - assert_eq!(pl.get_shift(8), Some(2)); - assert_eq!(pl.get_shift(9), Some(2)); - - // TODO - put some of these tests back in place for completeness - - // - // let mut pl = PruneList::new(); - // pl.add(4); - // assert_eq!(pl.pruned_nodes.len(), 1); - // assert_eq!(pl.pruned_nodes, [4]); - // assert_eq!(pl.get_shift(1), Some(0)); - // assert_eq!(pl.get_shift(2), Some(0)); - // assert_eq!(pl.get_shift(3), Some(0)); - // assert_eq!(pl.get_shift(4), None); - // assert_eq!(pl.get_shift(5), Some(1)); - // assert_eq!(pl.get_shift(6), Some(1)); - // - // - // pl.add(5); - // assert_eq!(pl.pruned_nodes.len(), 1); - // assert_eq!(pl.pruned_nodes[0], 6); - // assert_eq!(pl.get_shift(8), Some(3)); - // assert_eq!(pl.get_shift(2), Some(0)); - // assert_eq!(pl.get_shift(5), None); - // - // pl.add(2); - // assert_eq!(pl.pruned_nodes.len(), 2); - // assert_eq!(pl.pruned_nodes[0], 2); - // assert_eq!(pl.get_shift(8), Some(4)); - // assert_eq!(pl.get_shift(1), Some(0)); - // - // pl.add(8); - // pl.add(11); - // assert_eq!(pl.pruned_nodes.len(), 4); - // - // pl.add(1); - // assert_eq!(pl.pruned_nodes.len(), 3); - // assert_eq!(pl.pruned_nodes[0], 7); - // assert_eq!(pl.get_shift(12), Some(9)); - // - // pl.add(12); - // assert_eq!(pl.pruned_nodes.len(), 3); - // assert_eq!(pl.get_shift(12), None); - // assert_eq!(pl.get_shift(9), Some(8)); - // assert_eq!(pl.get_shift(17), Some(11)); - } - - #[test] - fn check_all_ones() { - for i in 0..1000000 { - assert_eq!(old_all_ones(i), all_ones(i)); - } - } - - // Check if the binary representation of a number is all ones. - fn old_all_ones(num: u64) -> bool { - if num == 0 { - return false; - } - let mut bit = 1; - while num >= bit { - if num & bit == 0 { - return false; - } - bit = bit << 1; - } - true - } - - #[test] - fn check_most_significant_pos() { - for i in 0u64..1000000 { - assert_eq!(old_most_significant_pos(i), most_significant_pos(i)); - } - } - - // Get the position of the most significant bit in a number. - fn old_most_significant_pos(num: u64) -> u64 { - let mut pos = 0; - let mut bit = 1; - while num >= bit { - bit = bit << 1; - pos += 1; - } - pos - } - - #[test] - fn check_insertion_to_pmmr_index() { - assert_eq!(insertion_to_pmmr_index(1), 1); - assert_eq!(insertion_to_pmmr_index(2), 2); - assert_eq!(insertion_to_pmmr_index(3), 4); - assert_eq!(insertion_to_pmmr_index(4), 5); - assert_eq!(insertion_to_pmmr_index(5), 8); - assert_eq!(insertion_to_pmmr_index(6), 9); - assert_eq!(insertion_to_pmmr_index(7), 11); - assert_eq!(insertion_to_pmmr_index(8), 12); - } - - #[test] - fn check_elements_from_insertion_index() { - let mut ba = VecBackend::new(); - let mut pmmr = PMMR::new(&mut ba); - for x in 1..1000 { - pmmr.push(TestElem([0, 0, 0, x])).unwrap(); - } - // Normal case - let res = pmmr.elements_from_insertion_index(1, 100); - assert_eq!(res.0, 100); - assert_eq!(res.1.len(), 100); - assert_eq!(res.1[0].0[3], 1); - assert_eq!(res.1[99].0[3], 100); - - // middle of pack - let res = pmmr.elements_from_insertion_index(351, 70); - assert_eq!(res.0, 420); - assert_eq!(res.1.len(), 70); - assert_eq!(res.1[0].0[3], 351); - assert_eq!(res.1[69].0[3], 420); - - // past the end - let res = pmmr.elements_from_insertion_index(650, 1000); - assert_eq!(res.0, 999); - assert_eq!(res.1.len(), 350); - assert_eq!(res.1[0].0[3], 650); - assert_eq!(res.1[349].0[3], 999); - - // pruning a few nodes should get consistent results - pmmr.prune(insertion_to_pmmr_index(650), 0).unwrap(); - pmmr.prune(insertion_to_pmmr_index(651), 0).unwrap(); - pmmr.prune(insertion_to_pmmr_index(800), 0).unwrap(); - pmmr.prune(insertion_to_pmmr_index(900), 0).unwrap(); - pmmr.prune(insertion_to_pmmr_index(998), 0).unwrap(); - let res = pmmr.elements_from_insertion_index(650, 1000); - assert_eq!(res.0, 999); - assert_eq!(res.1.len(), 345); - assert_eq!(res.1[0].0[3], 652); - assert_eq!(res.1[344].0[3], 999); - } -} diff --git a/core/tests/pmmr.rs b/core/tests/pmmr.rs new file mode 100644 index 000000000..f13b8fa45 --- /dev/null +++ b/core/tests/pmmr.rs @@ -0,0 +1,1003 @@ +// Copyright 2018 The Grin Developers +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! PMMR tests +#[macro_use] +extern crate grin_core as core; + +use core::core::hash::Hash; +use core::core::pmmr::{self, Backend, MerkleProof, PruneList, PMMR}; +use core::ser::{self, Error, PMMRIndexHashable, PMMRable, Readable, Reader, Writeable, Writer}; + +/// Simple MMR backend implementation based on a Vector. Pruning does not +/// compact the Vec itself. +#[derive(Clone, Debug)] +pub struct VecBackend +where + T: PMMRable, +{ + /// Backend elements + pub elems: Vec)>>, + /// Positions of removed elements + pub remove_list: Vec, +} + +impl Backend for VecBackend +where + T: PMMRable, +{ + fn append(&mut self, _position: u64, data: Vec<(Hash, Option)>) -> Result<(), String> { + self.elems.append(&mut map_vec!(data, |d| Some(d.clone()))); + Ok(()) + } + + fn get_hash(&self, position: u64) -> Option { + if self.remove_list.contains(&position) { + None + } else { + if let Some(ref elem) = self.elems[(position - 1) as usize] { + Some(elem.0) + } else { + None + } + } + } + + fn get_data(&self, position: u64) -> Option { + if self.remove_list.contains(&position) { + None + } else { + if let Some(ref elem) = self.elems[(position - 1) as usize] { + elem.1.clone() + } else { + None + } + } + } + + fn get_from_file(&self, position: u64) -> Option { + if let Some(ref x) = self.elems[(position - 1) as usize] { + Some(x.0) + } else { + None + } + } + + fn get_data_from_file(&self, position: u64) -> Option { + if let Some(ref x) = self.elems[(position - 1) as usize] { + x.1.clone() + } else { + None + } + } + + fn remove(&mut self, positions: Vec, _index: u32) -> Result<(), String> { + for n in positions { + self.remove_list.push(n) + } + Ok(()) + } + + fn rewind(&mut self, position: u64, _index: u32) -> Result<(), String> { + self.elems = self.elems[0..(position as usize) + 1].to_vec(); + Ok(()) + } + + fn get_data_file_path(&self) -> String { + "".to_string() + } + + fn dump_stats(&self) {} +} + +impl VecBackend +where + T: PMMRable, +{ + /// Instantiates a new VecBackend + pub fn new() -> VecBackend { + VecBackend { + elems: vec![], + remove_list: vec![], + } + } + + /// Current number of elements in the underlying Vec. + pub fn used_size(&self) -> usize { + let mut usz = self.elems.len(); + for (idx, _) in self.elems.iter().enumerate() { + let idx = idx as u64; + if self.remove_list.contains(&idx) { + usz -= 1; + } + } + usz + } +} + +#[test] +fn some_all_ones() { + for n in vec![1, 7, 255] { + assert!(pmmr::all_ones(n), "{} should be all ones", n); + } + for n in vec![0, 6, 9, 128] { + assert!(!pmmr::all_ones(n), "{} should not be all ones", n); + } +} + +#[test] +fn some_most_signif() { + assert_eq!(pmmr::most_significant_pos(0), 0); + assert_eq!(pmmr::most_significant_pos(1), 1); + assert_eq!(pmmr::most_significant_pos(6), 3); + assert_eq!(pmmr::most_significant_pos(7), 3); + assert_eq!(pmmr::most_significant_pos(8), 4); + assert_eq!(pmmr::most_significant_pos(128), 8); +} + +#[test] +#[allow(unused_variables)] +fn first_100_mmr_heights() { + let first_100_str = "0 0 1 0 0 1 2 0 0 1 0 0 1 2 3 0 0 1 0 0 1 2 0 0 1 0 0 1 2 3 4 \ + 0 0 1 0 0 1 2 0 0 1 0 0 1 2 3 0 0 1 0 0 1 2 0 0 1 0 0 1 2 3 4 5 \ + 0 0 1 0 0 1 2 0 0 1 0 0 1 2 3 0 0 1 0 0 1 2 0 0 1 0 0 1 2 3 4 0 0 1 0 0"; + let first_100 = first_100_str.split(' ').map(|n| n.parse::().unwrap()); + let mut count = 1; + for n in first_100 { + assert_eq!( + n, + pmmr::bintree_postorder_height(count), + "expected {}, got {}", + n, + pmmr::bintree_postorder_height(count) + ); + count += 1; + } +} + +#[test] +fn test_n_leaves() { + // make sure we handle an empty MMR correctly + assert_eq!(pmmr::n_leaves(0), 0); + + // and various sizes on non-empty MMRs + assert_eq!(pmmr::n_leaves(1), 1); + assert_eq!(pmmr::n_leaves(2), 2); + assert_eq!(pmmr::n_leaves(3), 2); + assert_eq!(pmmr::n_leaves(4), 3); + assert_eq!(pmmr::n_leaves(5), 4); + assert_eq!(pmmr::n_leaves(6), 4); + assert_eq!(pmmr::n_leaves(7), 4); + assert_eq!(pmmr::n_leaves(8), 5); + assert_eq!(pmmr::n_leaves(9), 6); + assert_eq!(pmmr::n_leaves(10), 6); +} + +/// Find parent and sibling positions for various node positions. +#[test] +fn various_families() { + // 0 0 1 0 0 1 2 0 0 1 0 0 1 2 3 + assert_eq!(pmmr::family(1), (3, 2)); + assert_eq!(pmmr::family(2), (3, 1)); + assert_eq!(pmmr::family(3), (7, 6)); + assert_eq!(pmmr::family(4), (6, 5)); + assert_eq!(pmmr::family(5), (6, 4)); + assert_eq!(pmmr::family(6), (7, 3)); + assert_eq!(pmmr::family(7), (15, 14)); + assert_eq!(pmmr::family(1_000), (1_001, 997)); +} + +#[test] +fn test_is_left_sibling() { + assert_eq!(pmmr::is_left_sibling(1), true); + assert_eq!(pmmr::is_left_sibling(2), false); + assert_eq!(pmmr::is_left_sibling(3), true); +} + +#[test] +fn various_branches() { + // the two leaf nodes in a 3 node tree (height 1) + assert_eq!(pmmr::family_branch(1, 3), [(3, 2)]); + assert_eq!(pmmr::family_branch(2, 3), [(3, 1)]); + + // the root node in a 3 node tree + assert_eq!(pmmr::family_branch(3, 3), []); + + // leaf node in a larger tree of 7 nodes (height 2) + assert_eq!(pmmr::family_branch(1, 7), [(3, 2), (7, 6)]); + + // note these only go as far up as the local peak, not necessarily the single + // root + assert_eq!(pmmr::family_branch(1, 4), [(3, 2)]); + // pos 4 in a tree of size 4 is a local peak + assert_eq!(pmmr::family_branch(4, 4), []); + // pos 4 in a tree of size 5 is also still a local peak + assert_eq!(pmmr::family_branch(4, 5), []); + // pos 4 in a tree of size 6 has a parent and a sibling + assert_eq!(pmmr::family_branch(4, 6), [(6, 5)]); + // a tree of size 7 is all under a single root + assert_eq!(pmmr::family_branch(4, 7), [(6, 5), (7, 3)]); + + // ok now for a more realistic one, a tree with over a million nodes in it + // find the "family path" back up the tree from a leaf node at 0 + // Note: the first two entries in the branch are consistent with a small 7 node + // tree Note: each sibling is on the left branch, this is an example of the + // largest possible list of peaks before we start combining them into larger + // peaks. + assert_eq!( + pmmr::family_branch(1, 1_049_000), + [ + (3, 2), + (7, 6), + (15, 14), + (31, 30), + (63, 62), + (127, 126), + (255, 254), + (511, 510), + (1023, 1022), + (2047, 2046), + (4095, 4094), + (8191, 8190), + (16383, 16382), + (32767, 32766), + (65535, 65534), + (131071, 131070), + (262143, 262142), + (524287, 524286), + (1048575, 1048574), + ] + ); +} + +#[test] +fn some_peaks() { + // 0 0 1 0 0 1 2 0 0 1 0 0 1 2 3 + + let empty: Vec = vec![]; + + // make sure we handle an empty MMR correctly + assert_eq!(pmmr::peaks(0), empty); + + // and various non-empty MMRs + assert_eq!(pmmr::peaks(1), [1]); + assert_eq!(pmmr::peaks(2), empty); + assert_eq!(pmmr::peaks(3), [3]); + assert_eq!(pmmr::peaks(4), [3, 4]); + assert_eq!(pmmr::peaks(5), empty); + assert_eq!(pmmr::peaks(6), empty); + assert_eq!(pmmr::peaks(7), [7]); + assert_eq!(pmmr::peaks(8), [7, 8]); + assert_eq!(pmmr::peaks(9), empty); + assert_eq!(pmmr::peaks(10), [7, 10]); + assert_eq!(pmmr::peaks(11), [7, 10, 11]); + assert_eq!(pmmr::peaks(22), [15, 22]); + assert_eq!(pmmr::peaks(32), [31, 32]); + assert_eq!(pmmr::peaks(35), [31, 34, 35]); + assert_eq!(pmmr::peaks(42), [31, 38, 41, 42]); + + // large realistic example with almost 1.5 million nodes + // note the distance between peaks decreases toward the right (trees get + // smaller) + assert_eq!( + pmmr::peaks(1048555), + [ + 524287, 786430, 917501, 983036, 1015803, 1032186, 1040377, 1044472, 1046519, 1047542, + 1048053, 1048308, 1048435, 1048498, 1048529, 1048544, 1048551, 1048554, 1048555, + ], + ); +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +struct TestElem([u32; 4]); + +impl PMMRable for TestElem { + fn len() -> usize { + 16 + } +} + +impl Writeable for TestElem { + fn write(&self, writer: &mut W) -> Result<(), Error> { + writer.write_u32(self.0[0])?; + writer.write_u32(self.0[1])?; + writer.write_u32(self.0[2])?; + writer.write_u32(self.0[3]) + } +} + +impl Readable for TestElem { + fn read(reader: &mut Reader) -> Result { + Ok(TestElem([ + reader.read_u32()?, + reader.read_u32()?, + reader.read_u32()?, + reader.read_u32()?, + ])) + } +} + +#[test] +fn empty_merkle_proof() { + let proof = MerkleProof::empty(); + assert_eq!(proof.verify(), false); +} + +#[test] +fn pmmr_merkle_proof() { + // 0 0 1 0 0 1 2 0 0 1 0 0 1 2 3 + + let mut ba = VecBackend::new(); + let mut pmmr = PMMR::new(&mut ba); + + pmmr.push(TestElem([0, 0, 0, 1])).unwrap(); + assert_eq!(pmmr.last_pos, 1); + let proof = pmmr.merkle_proof(1).unwrap(); + let root = pmmr.root(); + assert_eq!(proof.peaks, [root]); + assert!(proof.path.is_empty()); + assert!(proof.verify()); + + // push two more elements into the PMMR + pmmr.push(TestElem([0, 0, 0, 2])).unwrap(); + pmmr.push(TestElem([0, 0, 0, 3])).unwrap(); + assert_eq!(pmmr.last_pos, 4); + + let proof1 = pmmr.merkle_proof(1).unwrap(); + assert_eq!(proof1.peaks.len(), 2); + assert_eq!(proof1.path.len(), 1); + assert!(proof1.verify()); + + let proof2 = pmmr.merkle_proof(2).unwrap(); + assert_eq!(proof2.peaks.len(), 2); + assert_eq!(proof2.path.len(), 1); + assert!(proof2.verify()); + + // check that we cannot generate a merkle proof for pos 3 (not a leaf node) + assert_eq!( + pmmr.merkle_proof(3).err(), + Some(format!("not a leaf at pos 3")) + ); + + let proof4 = pmmr.merkle_proof(4).unwrap(); + assert_eq!(proof4.peaks.len(), 2); + assert!(proof4.path.is_empty()); + assert!(proof4.verify()); + + // now add a few more elements to the PMMR to build a larger merkle proof + for x in 4..1000 { + pmmr.push(TestElem([0, 0, 0, x])).unwrap(); + } + let proof = pmmr.merkle_proof(1).unwrap(); + assert_eq!(proof.peaks.len(), 8); + assert_eq!(proof.path.len(), 9); + assert!(proof.verify()); +} + +#[test] +fn pmmr_merkle_proof_prune_and_rewind() { + let mut ba = VecBackend::new(); + let mut pmmr = PMMR::new(&mut ba); + pmmr.push(TestElem([0, 0, 0, 1])).unwrap(); + pmmr.push(TestElem([0, 0, 0, 2])).unwrap(); + let proof = pmmr.merkle_proof(2).unwrap(); + + // now prune an element and check we can still generate + // the correct Merkle proof for the other element (after sibling pruned) + pmmr.prune(1, 1).unwrap(); + let proof_2 = pmmr.merkle_proof(2).unwrap(); + assert_eq!(proof, proof_2); +} + +#[test] +fn merkle_proof_ser_deser() { + let mut ba = VecBackend::new(); + let mut pmmr = PMMR::new(&mut ba); + for x in 0..15 { + pmmr.push(TestElem([0, 0, 0, x])).unwrap(); + } + let proof = pmmr.merkle_proof(9).unwrap(); + assert!(proof.verify()); + + let mut vec = Vec::new(); + ser::serialize(&mut vec, &proof).expect("serialization failed"); + let proof_2: MerkleProof = ser::deserialize(&mut &vec[..]).unwrap(); + + assert_eq!(proof, proof_2); +} + +#[test] +#[allow(unused_variables)] +fn pmmr_push_root() { + let elems = [ + TestElem([0, 0, 0, 1]), + TestElem([0, 0, 0, 2]), + TestElem([0, 0, 0, 3]), + TestElem([0, 0, 0, 4]), + TestElem([0, 0, 0, 5]), + TestElem([0, 0, 0, 6]), + TestElem([0, 0, 0, 7]), + TestElem([0, 0, 0, 8]), + TestElem([1, 0, 0, 0]), + ]; + + let mut ba = VecBackend::new(); + let mut pmmr = PMMR::new(&mut ba); + + // one element + pmmr.push(elems[0]).unwrap(); + pmmr.dump(false); + let pos_0 = elems[0].hash_with_index(0); + assert_eq!(pmmr.peaks(), vec![pos_0]); + assert_eq!(pmmr.root(), pos_0); + assert_eq!(pmmr.unpruned_size(), 1); + + // two elements + pmmr.push(elems[1]).unwrap(); + pmmr.dump(false); + let pos_1 = elems[1].hash_with_index(1); + let pos_2 = (pos_0, pos_1).hash_with_index(2); + assert_eq!(pmmr.peaks(), vec![pos_2]); + assert_eq!(pmmr.root(), pos_2); + assert_eq!(pmmr.unpruned_size(), 3); + + // three elements + pmmr.push(elems[2]).unwrap(); + pmmr.dump(false); + let pos_3 = elems[2].hash_with_index(3); + assert_eq!(pmmr.peaks(), vec![pos_2, pos_3]); + assert_eq!(pmmr.root(), (pos_2, pos_3).hash_with_index(4)); + assert_eq!(pmmr.unpruned_size(), 4); + + // four elements + pmmr.push(elems[3]).unwrap(); + pmmr.dump(false); + let pos_4 = elems[3].hash_with_index(4); + let pos_5 = (pos_3, pos_4).hash_with_index(5); + let pos_6 = (pos_2, pos_5).hash_with_index(6); + assert_eq!(pmmr.peaks(), vec![pos_6]); + assert_eq!(pmmr.root(), pos_6); + assert_eq!(pmmr.unpruned_size(), 7); + + // five elements + pmmr.push(elems[4]).unwrap(); + pmmr.dump(false); + let pos_7 = elems[4].hash_with_index(7); + assert_eq!(pmmr.peaks(), vec![pos_6, pos_7]); + assert_eq!(pmmr.root(), (pos_6, pos_7).hash_with_index(8)); + assert_eq!(pmmr.unpruned_size(), 8); + + // six elements + pmmr.push(elems[5]).unwrap(); + let pos_8 = elems[5].hash_with_index(8); + let pos_9 = (pos_7, pos_8).hash_with_index(9); + assert_eq!(pmmr.peaks(), vec![pos_6, pos_9]); + assert_eq!(pmmr.root(), (pos_6, pos_9).hash_with_index(10)); + assert_eq!(pmmr.unpruned_size(), 10); + + // seven elements + pmmr.push(elems[6]).unwrap(); + let pos_10 = elems[6].hash_with_index(10); + assert_eq!(pmmr.peaks(), vec![pos_6, pos_9, pos_10]); + assert_eq!( + pmmr.root(), + (pos_6, (pos_9, pos_10).hash_with_index(11)).hash_with_index(11) + ); + assert_eq!(pmmr.unpruned_size(), 11); + + // 001001200100123 + // eight elements + pmmr.push(elems[7]).unwrap(); + let pos_11 = elems[7].hash_with_index(11); + let pos_12 = (pos_10, pos_11).hash_with_index(12); + let pos_13 = (pos_9, pos_12).hash_with_index(13); + let pos_14 = (pos_6, pos_13).hash_with_index(14); + assert_eq!(pmmr.peaks(), vec![pos_14]); + assert_eq!(pmmr.root(), pos_14); + assert_eq!(pmmr.unpruned_size(), 15); + + // nine elements + pmmr.push(elems[8]).unwrap(); + let pos_15 = elems[8].hash_with_index(15); + assert_eq!(pmmr.peaks(), vec![pos_14, pos_15]); + assert_eq!(pmmr.root(), (pos_14, pos_15).hash_with_index(16)); + assert_eq!(pmmr.unpruned_size(), 16); +} + +#[test] +fn pmmr_get_last_n_insertions() { + let elems = [ + TestElem([0, 0, 0, 1]), + TestElem([0, 0, 0, 2]), + TestElem([0, 0, 0, 3]), + TestElem([0, 0, 0, 4]), + TestElem([0, 0, 0, 5]), + TestElem([0, 0, 0, 6]), + TestElem([0, 0, 0, 7]), + TestElem([0, 0, 0, 8]), + TestElem([1, 0, 0, 0]), + ]; + + let mut ba = VecBackend::new(); + let mut pmmr = PMMR::new(&mut ba); + + // test when empty + let res = pmmr.get_last_n_insertions(19); + assert!(res.len() == 0); + + pmmr.push(elems[0]).unwrap(); + let res = pmmr.get_last_n_insertions(19); + assert!(res.len() == 1); + + pmmr.push(elems[1]).unwrap(); + + let res = pmmr.get_last_n_insertions(12); + assert!(res.len() == 2); + + pmmr.push(elems[2]).unwrap(); + + let res = pmmr.get_last_n_insertions(2); + assert!(res.len() == 2); + + pmmr.push(elems[3]).unwrap(); + + let res = pmmr.get_last_n_insertions(19); + assert!(res.len() == 4); + + pmmr.push(elems[5]).unwrap(); + pmmr.push(elems[6]).unwrap(); + pmmr.push(elems[7]).unwrap(); + pmmr.push(elems[8]).unwrap(); + + let res = pmmr.get_last_n_insertions(7); + assert!(res.len() == 7); +} + +#[test] +#[allow(unused_variables)] +fn pmmr_prune() { + let elems = [ + TestElem([0, 0, 0, 1]), + TestElem([0, 0, 0, 2]), + TestElem([0, 0, 0, 3]), + TestElem([0, 0, 0, 4]), + TestElem([0, 0, 0, 5]), + TestElem([0, 0, 0, 6]), + TestElem([0, 0, 0, 7]), + TestElem([0, 0, 0, 8]), + TestElem([1, 0, 0, 0]), + ]; + + let orig_root: Hash; + let sz: u64; + let mut ba = VecBackend::new(); + { + let mut pmmr = PMMR::new(&mut ba); + for elem in &elems[..] { + pmmr.push(*elem).unwrap(); + } + orig_root = pmmr.root(); + sz = pmmr.unpruned_size(); + } + + // pruning a leaf with no parent should do nothing + { + let mut pmmr: PMMR = PMMR::at(&mut ba, sz); + pmmr.prune(16, 0).unwrap(); + assert_eq!(orig_root, pmmr.root()); + } + assert_eq!(ba.used_size(), 16); + + // pruning leaves with no shared parent just removes 1 element + { + let mut pmmr: PMMR = PMMR::at(&mut ba, sz); + pmmr.prune(2, 0).unwrap(); + assert_eq!(orig_root, pmmr.root()); + } + assert_eq!(ba.used_size(), 15); + + { + let mut pmmr: PMMR = PMMR::at(&mut ba, sz); + pmmr.prune(4, 0).unwrap(); + assert_eq!(orig_root, pmmr.root()); + } + assert_eq!(ba.used_size(), 14); + + // pruning a non-leaf node has no effect + { + let mut pmmr: PMMR = PMMR::at(&mut ba, sz); + pmmr.prune(3, 0).unwrap_err(); + assert_eq!(orig_root, pmmr.root()); + } + assert_eq!(ba.used_size(), 14); + + // pruning sibling removes subtree + { + let mut pmmr: PMMR = PMMR::at(&mut ba, sz); + pmmr.prune(5, 0).unwrap(); + assert_eq!(orig_root, pmmr.root()); + } + assert_eq!(ba.used_size(), 12); + + // pruning all leaves under level >1 removes all subtree + { + let mut pmmr: PMMR = PMMR::at(&mut ba, sz); + pmmr.prune(1, 0).unwrap(); + assert_eq!(orig_root, pmmr.root()); + } + assert_eq!(ba.used_size(), 9); + + // pruning everything should only leave us with a single peak + { + let mut pmmr: PMMR = PMMR::at(&mut ba, sz); + for n in 1..16 { + let _ = pmmr.prune(n, 0); + } + assert_eq!(orig_root, pmmr.root()); + } + assert_eq!(ba.used_size(), 1); +} + +#[test] +fn pmmr_next_pruned_idx() { + let mut pl = PruneList::new(); + + assert_eq!(pl.pruned_nodes.len(), 0); + assert_eq!(pl.next_pruned_idx(1), Some(0)); + assert_eq!(pl.next_pruned_idx(2), Some(0)); + assert_eq!(pl.next_pruned_idx(3), Some(0)); + + pl.add(2); + assert_eq!(pl.pruned_nodes.len(), 1); + assert_eq!(pl.pruned_nodes, [2]); + assert_eq!(pl.next_pruned_idx(1), Some(0)); + assert_eq!(pl.next_pruned_idx(2), None); + assert_eq!(pl.next_pruned_idx(3), Some(1)); + assert_eq!(pl.next_pruned_idx(4), Some(1)); + + pl.add(1); + assert_eq!(pl.pruned_nodes.len(), 1); + assert_eq!(pl.pruned_nodes, [3]); + assert_eq!(pl.next_pruned_idx(1), None); + assert_eq!(pl.next_pruned_idx(2), None); + assert_eq!(pl.next_pruned_idx(3), None); + assert_eq!(pl.next_pruned_idx(4), Some(1)); + assert_eq!(pl.next_pruned_idx(5), Some(1)); + + pl.add(3); + assert_eq!(pl.pruned_nodes.len(), 1); + assert_eq!(pl.pruned_nodes, [3]); + assert_eq!(pl.next_pruned_idx(1), None); + assert_eq!(pl.next_pruned_idx(2), None); + assert_eq!(pl.next_pruned_idx(3), None); + assert_eq!(pl.next_pruned_idx(4), Some(1)); + assert_eq!(pl.next_pruned_idx(5), Some(1)); +} + +#[test] +fn pmmr_prune_leaf_shift() { + let mut pl = PruneList::new(); + + // start with an empty prune list (nothing shifted) + assert_eq!(pl.pruned_nodes.len(), 0); + assert_eq!(pl.get_leaf_shift(1), Some(0)); + assert_eq!(pl.get_leaf_shift(2), Some(0)); + assert_eq!(pl.get_leaf_shift(4), Some(0)); + + // now add a single leaf pos to the prune list + // note this does not shift anything (we only start shifting after pruning a + // parent) + pl.add(1); + assert_eq!(pl.pruned_nodes.len(), 1); + assert_eq!(pl.pruned_nodes, [1]); + assert_eq!(pl.get_leaf_shift(1), Some(0)); + assert_eq!(pl.get_leaf_shift(2), Some(0)); + assert_eq!(pl.get_leaf_shift(3), Some(0)); + assert_eq!(pl.get_leaf_shift(4), Some(0)); + + // now add the sibling leaf pos (pos 1 and pos 2) which will prune the parent + // at pos 3 this in turn will "leaf shift" the leaf at pos 3 by 2 + pl.add(2); + assert_eq!(pl.pruned_nodes.len(), 1); + assert_eq!(pl.pruned_nodes, [3]); + assert_eq!(pl.get_leaf_shift(1), None); + assert_eq!(pl.get_leaf_shift(2), None); + assert_eq!(pl.get_leaf_shift(3), Some(2)); + assert_eq!(pl.get_leaf_shift(4), Some(2)); + assert_eq!(pl.get_leaf_shift(5), Some(2)); + + // now prune an additional leaf at pos 4 + // leaf offset of subsequent pos will be 2 + // 00100120 + pl.add(4); + assert_eq!(pl.pruned_nodes, [3, 4]); + assert_eq!(pl.get_leaf_shift(1), None); + assert_eq!(pl.get_leaf_shift(2), None); + assert_eq!(pl.get_leaf_shift(3), Some(2)); + assert_eq!(pl.get_leaf_shift(4), Some(2)); + assert_eq!(pl.get_leaf_shift(5), Some(2)); + assert_eq!(pl.get_leaf_shift(6), Some(2)); + assert_eq!(pl.get_leaf_shift(7), Some(2)); + assert_eq!(pl.get_leaf_shift(8), Some(2)); + + // now prune the sibling at pos 5 + // the two smaller subtrees (pos 3 and pos 6) are rolled up to larger subtree + // (pos 7) the leaf offset is now 4 to cover entire subtree containing first + // 4 leaves 00100120 + pl.add(5); + assert_eq!(pl.pruned_nodes, [7]); + assert_eq!(pl.get_leaf_shift(1), None); + assert_eq!(pl.get_leaf_shift(2), None); + assert_eq!(pl.get_leaf_shift(3), None); + assert_eq!(pl.get_leaf_shift(4), None); + assert_eq!(pl.get_leaf_shift(5), None); + assert_eq!(pl.get_leaf_shift(6), None); + assert_eq!(pl.get_leaf_shift(7), Some(4)); + assert_eq!(pl.get_leaf_shift(8), Some(4)); + assert_eq!(pl.get_leaf_shift(9), Some(4)); + + // now check we can prune some of these in an arbitrary order + // final result is one leaf (pos 2) and one small subtree (pos 6) pruned + // with leaf offset of 2 to account for the pruned subtree + let mut pl = PruneList::new(); + pl.add(2); + pl.add(5); + pl.add(4); + assert_eq!(pl.pruned_nodes, [2, 6]); + assert_eq!(pl.get_leaf_shift(1), Some(0)); + assert_eq!(pl.get_leaf_shift(2), Some(0)); + assert_eq!(pl.get_leaf_shift(3), Some(0)); + assert_eq!(pl.get_leaf_shift(4), None); + assert_eq!(pl.get_leaf_shift(5), None); + assert_eq!(pl.get_leaf_shift(6), Some(2)); + assert_eq!(pl.get_leaf_shift(7), Some(2)); + assert_eq!(pl.get_leaf_shift(8), Some(2)); + assert_eq!(pl.get_leaf_shift(9), Some(2)); + + pl.add(1); + assert_eq!(pl.pruned_nodes, [7]); + assert_eq!(pl.get_leaf_shift(1), None); + assert_eq!(pl.get_leaf_shift(2), None); + assert_eq!(pl.get_leaf_shift(3), None); + assert_eq!(pl.get_leaf_shift(4), None); + assert_eq!(pl.get_leaf_shift(5), None); + assert_eq!(pl.get_leaf_shift(6), None); + assert_eq!(pl.get_leaf_shift(7), Some(4)); + assert_eq!(pl.get_leaf_shift(8), Some(4)); + assert_eq!(pl.get_leaf_shift(9), Some(4)); +} + +#[test] +fn pmmr_prune_shift() { + let mut pl = PruneList::new(); + assert!(pl.pruned_nodes.is_empty()); + assert_eq!(pl.get_shift(1), Some(0)); + assert_eq!(pl.get_shift(2), Some(0)); + assert_eq!(pl.get_shift(3), Some(0)); + + // prune a single leaf node + // pruning only a leaf node does not shift any subsequent pos + // we will only start shifting when a parent can be pruned + pl.add(1); + assert_eq!(pl.pruned_nodes, [1]); + assert_eq!(pl.get_shift(1), Some(0)); + assert_eq!(pl.get_shift(2), Some(0)); + assert_eq!(pl.get_shift(3), Some(0)); + + pl.add(2); + assert_eq!(pl.pruned_nodes, [3]); + assert_eq!(pl.get_shift(1), None); + assert_eq!(pl.get_shift(2), None); + // pos 3 is in the prune list, so removed but not compacted, but still shifted + assert_eq!(pl.get_shift(3), Some(2)); + assert_eq!(pl.get_shift(4), Some(2)); + assert_eq!(pl.get_shift(5), Some(2)); + assert_eq!(pl.get_shift(6), Some(2)); + + // pos 3 is not a leaf and is already in prune list + // prune it and check we are still consistent + pl.add(3); + assert_eq!(pl.pruned_nodes, [3]); + assert_eq!(pl.get_shift(1), None); + assert_eq!(pl.get_shift(2), None); + // pos 3 is in the prune list, so removed but not compacted, but still shifted + assert_eq!(pl.get_shift(3), Some(2)); + assert_eq!(pl.get_shift(4), Some(2)); + assert_eq!(pl.get_shift(5), Some(2)); + assert_eq!(pl.get_shift(6), Some(2)); + + pl.add(4); + assert_eq!(pl.pruned_nodes, [3, 4]); + assert_eq!(pl.get_shift(1), None); + assert_eq!(pl.get_shift(2), None); + // pos 3 is in the prune list, so removed but not compacted, but still shifted + assert_eq!(pl.get_shift(3), Some(2)); + // pos 4 is also in the prune list and also shifted by same amount + assert_eq!(pl.get_shift(4), Some(2)); + // subsequent nodes also shifted consistently + assert_eq!(pl.get_shift(5), Some(2)); + assert_eq!(pl.get_shift(6), Some(2)); + + pl.add(5); + assert_eq!(pl.pruned_nodes, [7]); + assert_eq!(pl.get_shift(1), None); + assert_eq!(pl.get_shift(2), None); + assert_eq!(pl.get_shift(3), None); + assert_eq!(pl.get_shift(4), None); + assert_eq!(pl.get_shift(5), None); + assert_eq!(pl.get_shift(6), None); + // everything prior to pos 7 is compacted away + // pos 7 is shifted by 6 to account for this + assert_eq!(pl.get_shift(7), Some(6)); + assert_eq!(pl.get_shift(8), Some(6)); + assert_eq!(pl.get_shift(9), Some(6)); + + // prune a bunch more + for x in 6..1000 { + pl.add(x); + } + // and check we shift by a large number (hopefully the correct number...) + assert_eq!(pl.get_shift(1010), Some(996)); + + let mut pl = PruneList::new(); + pl.add(2); + pl.add(5); + pl.add(4); + assert_eq!(pl.pruned_nodes, [2, 6]); + assert_eq!(pl.get_shift(1), Some(0)); + assert_eq!(pl.get_shift(2), Some(0)); + assert_eq!(pl.get_shift(3), Some(0)); + assert_eq!(pl.get_shift(4), None); + assert_eq!(pl.get_shift(5), None); + assert_eq!(pl.get_shift(6), Some(2)); + assert_eq!(pl.get_shift(7), Some(2)); + assert_eq!(pl.get_shift(8), Some(2)); + assert_eq!(pl.get_shift(9), Some(2)); + + // TODO - put some of these tests back in place for completeness + + // + // let mut pl = PruneList::new(); + // pl.add(4); + // assert_eq!(pl.pruned_nodes.len(), 1); + // assert_eq!(pl.pruned_nodes, [4]); + // assert_eq!(pl.get_shift(1), Some(0)); + // assert_eq!(pl.get_shift(2), Some(0)); + // assert_eq!(pl.get_shift(3), Some(0)); + // assert_eq!(pl.get_shift(4), None); + // assert_eq!(pl.get_shift(5), Some(1)); + // assert_eq!(pl.get_shift(6), Some(1)); + // + // + // pl.add(5); + // assert_eq!(pl.pruned_nodes.len(), 1); + // assert_eq!(pl.pruned_nodes[0], 6); + // assert_eq!(pl.get_shift(8), Some(3)); + // assert_eq!(pl.get_shift(2), Some(0)); + // assert_eq!(pl.get_shift(5), None); + // + // pl.add(2); + // assert_eq!(pl.pruned_nodes.len(), 2); + // assert_eq!(pl.pruned_nodes[0], 2); + // assert_eq!(pl.get_shift(8), Some(4)); + // assert_eq!(pl.get_shift(1), Some(0)); + // + // pl.add(8); + // pl.add(11); + // assert_eq!(pl.pruned_nodes.len(), 4); + // + // pl.add(1); + // assert_eq!(pl.pruned_nodes.len(), 3); + // assert_eq!(pl.pruned_nodes[0], 7); + // assert_eq!(pl.get_shift(12), Some(9)); + // + // pl.add(12); + // assert_eq!(pl.pruned_nodes.len(), 3); + // assert_eq!(pl.get_shift(12), None); + // assert_eq!(pl.get_shift(9), Some(8)); + // assert_eq!(pl.get_shift(17), Some(11)); +} + +#[test] +fn check_all_ones() { + for i in 0..1000000 { + assert_eq!(old_all_ones(i), pmmr::all_ones(i)); + } +} + +// Check if the binary representation of a number is all ones. +fn old_all_ones(num: u64) -> bool { + if num == 0 { + return false; + } + let mut bit = 1; + while num >= bit { + if num & bit == 0 { + return false; + } + bit = bit << 1; + } + true +} + +#[test] +fn check_most_significant_pos() { + for i in 0u64..1000000 { + assert_eq!(old_most_significant_pos(i), pmmr::most_significant_pos(i)); + } +} + +// Get the position of the most significant bit in a number. +fn old_most_significant_pos(num: u64) -> u64 { + let mut pos = 0; + let mut bit = 1; + while num >= bit { + bit = bit << 1; + pos += 1; + } + pos +} + +#[test] +fn check_insertion_to_pmmr_index() { + assert_eq!(pmmr::insertion_to_pmmr_index(1), 1); + assert_eq!(pmmr::insertion_to_pmmr_index(2), 2); + assert_eq!(pmmr::insertion_to_pmmr_index(3), 4); + assert_eq!(pmmr::insertion_to_pmmr_index(4), 5); + assert_eq!(pmmr::insertion_to_pmmr_index(5), 8); + assert_eq!(pmmr::insertion_to_pmmr_index(6), 9); + assert_eq!(pmmr::insertion_to_pmmr_index(7), 11); + assert_eq!(pmmr::insertion_to_pmmr_index(8), 12); +} + +#[test] +fn check_elements_from_insertion_index() { + let mut ba = VecBackend::new(); + let mut pmmr = PMMR::new(&mut ba); + for x in 1..1000 { + pmmr.push(TestElem([0, 0, 0, x])).unwrap(); + } + // Normal case + let res = pmmr.elements_from_insertion_index(1, 100); + assert_eq!(res.0, 100); + assert_eq!(res.1.len(), 100); + assert_eq!(res.1[0].0[3], 1); + assert_eq!(res.1[99].0[3], 100); + + // middle of pack + let res = pmmr.elements_from_insertion_index(351, 70); + assert_eq!(res.0, 420); + assert_eq!(res.1.len(), 70); + assert_eq!(res.1[0].0[3], 351); + assert_eq!(res.1[69].0[3], 420); + + // past the end + let res = pmmr.elements_from_insertion_index(650, 1000); + assert_eq!(res.0, 999); + assert_eq!(res.1.len(), 350); + assert_eq!(res.1[0].0[3], 650); + assert_eq!(res.1[349].0[3], 999); + + // pruning a few nodes should get consistent results + pmmr.prune(pmmr::insertion_to_pmmr_index(650), 0).unwrap(); + pmmr.prune(pmmr::insertion_to_pmmr_index(651), 0).unwrap(); + pmmr.prune(pmmr::insertion_to_pmmr_index(800), 0).unwrap(); + pmmr.prune(pmmr::insertion_to_pmmr_index(900), 0).unwrap(); + pmmr.prune(pmmr::insertion_to_pmmr_index(998), 0).unwrap(); + let res = pmmr.elements_from_insertion_index(650, 1000); + assert_eq!(res.0, 999); + assert_eq!(res.1.len(), 345); + assert_eq!(res.1[0].0[3], 652); + assert_eq!(res.1[344].0[3], 999); +}