diff --git a/chain/src/txhashset/bitmap_accumulator.rs b/chain/src/txhashset/bitmap_accumulator.rs index 49b472716..f27ab1a47 100644 --- a/chain/src/txhashset/bitmap_accumulator.rs +++ b/chain/src/txhashset/bitmap_accumulator.rs @@ -19,7 +19,7 @@ use bit_vec::BitVec; use croaring::Bitmap; use crate::core::core::hash::{DefaultHashable, Hash}; -use crate::core::core::pmmr::{self, ReadonlyPMMR, VecBackend, PMMR}; +use crate::core::core::pmmr::{self, ReadablePMMR, ReadonlyPMMR, VecBackend, PMMR}; use crate::core::ser::{self, PMMRable, Readable, Reader, Writeable, Writer}; use crate::error::{Error, ErrorKind}; @@ -176,7 +176,9 @@ impl BitmapAccumulator { /// The root hash of the bitmap accumulator MMR. pub fn root(&self) -> Hash { - ReadonlyPMMR::at(&self.backend, self.backend.size()).root() + ReadonlyPMMR::at(&self.backend, self.backend.size()) + .root() + .expect("no root, invalid tree") } } diff --git a/chain/src/txhashset/txhashset.rs b/chain/src/txhashset/txhashset.rs index 2e99ac113..17bbe0558 100644 --- a/chain/src/txhashset/txhashset.rs +++ b/chain/src/txhashset/txhashset.rs @@ -19,7 +19,7 @@ use crate::core::consensus::WEEK_HEIGHT; use crate::core::core::committed::Committed; use crate::core::core::hash::{Hash, Hashed}; use crate::core::core::merkle_proof::MerkleProof; -use crate::core::core::pmmr::{self, Backend, ReadonlyPMMR, RewindablePMMR, PMMR}; +use crate::core::core::pmmr::{self, Backend, ReadablePMMR, ReadonlyPMMR, RewindablePMMR, PMMR}; use crate::core::core::{Block, BlockHeader, KernelFeatures, Output, OutputIdentifier, TxKernel}; use crate::core::global; use crate::core::ser::{PMMRable, ProtocolVersion}; @@ -369,11 +369,11 @@ impl TxHashSet { TxHashSetRoots { output_roots: OutputRoots { - pmmr_root: output_pmmr.root(), + pmmr_root: output_pmmr.root().expect("no root, invalid tree"), bitmap_root: self.bitmap_accumulator.root(), }, - rproof_root: rproof_pmmr.root(), - kernel_root: kernel_pmmr.root(), + rproof_root: rproof_pmmr.root().expect("no root, invalid tree"), + kernel_root: kernel_pmmr.root().expect("no root, invalid tree"), } } diff --git a/chain/src/txhashset/utxo_view.rs b/chain/src/txhashset/utxo_view.rs index b963f3a4d..3eb2e40c6 100644 --- a/chain/src/txhashset/utxo_view.rs +++ b/chain/src/txhashset/utxo_view.rs @@ -15,7 +15,7 @@ //! Lightweight readonly view into output MMR for convenience. use crate::core::core::hash::{Hash, Hashed}; -use crate::core::core::pmmr::{self, ReadonlyPMMR}; +use crate::core::core::pmmr::{self, ReadablePMMR, ReadonlyPMMR}; use crate::core::core::{Block, BlockHeader, Inputs, Output, OutputIdentifier, Transaction}; use crate::core::global; use crate::error::{Error, ErrorKind}; diff --git a/core/src/core/pmmr/pmmr.rs b/core/src/core/pmmr/pmmr.rs index 52e6e5b96..86a37bbdf 100644 --- a/core/src/core/pmmr/pmmr.rs +++ b/core/src/core/pmmr/pmmr.rs @@ -26,6 +26,138 @@ use crate::ser::{PMMRIndexHashable, PMMRable}; /// 64 bits all ones: 0b11111111...1 const ALL_ONES: u64 = u64::MAX; +/// Trait with common methods for reading from a PMMR +pub trait ReadablePMMR { + /// Leaf type + type Item; + + /// Get the hash at provided position in the MMR. + fn get_hash(&self, pos: u64) -> Option; + + /// Get the data element at provided position in the MMR. + fn get_data(&self, pos: u64) -> Option; + + /// Get the hash from the underlying MMR file (ignores the remove log). + fn get_from_file(&self, pos: u64) -> Option; + + /// Total size of the tree, including intermediary nodes and ignoring any pruning. + fn unpruned_size(&self) -> u64; + + /// Iterator over current (unpruned, unremoved) leaf positions. + fn leaf_pos_iter(&self) -> Box + '_>; + + /// Iterator over current (unpruned, unremoved) leaf insertion indices. + fn leaf_idx_iter(&self, from_idx: u64) -> Box + '_>; + + /// Number of leaves in the MMR + fn n_unpruned_leaves(&self) -> u64; + + /// Is the MMR empty? + fn is_empty(&self) -> bool { + self.unpruned_size() == 0 + } + + /// Takes a single peak position and hashes together + /// all the peaks to the right of this peak (if any). + /// If this return a hash then this is our peaks sibling. + /// If none then the sibling of our peak is the peak to the left. + fn bag_the_rhs(&self, peak_pos: u64) -> Option { + let last_pos = self.unpruned_size(); + let rhs = peaks(last_pos) + .into_iter() + .filter(|&x| x > peak_pos) + .filter_map(|x| self.get_from_file(x)); + + let mut res = None; + for peak in rhs.rev() { + res = match res { + None => Some(peak), + Some(rhash) => Some((peak, rhash).hash_with_index(last_pos)), + } + } + res + } + + /// Returns a vec of the peaks of this MMR. + fn peaks(&self) -> Vec { + peaks(self.unpruned_size()) + .into_iter() + .filter_map(move |pi| { + // here we want to get from underlying hash file + // as the pos *may* have been "removed" + self.get_from_file(pi) + }) + .collect() + } + + /// Hashes of the peaks excluding `peak_pos`, where the rhs is bagged together + fn peak_path(&self, peak_pos: u64) -> Vec { + let rhs = self.bag_the_rhs(peak_pos); + let mut res = peaks(self.unpruned_size()) + .into_iter() + .filter(|&x| x < peak_pos) + .filter_map(|x| self.get_from_file(x)) + .collect::>(); + if let Some(rhs) = rhs { + res.push(rhs); + } + res.reverse(); + + res + } + + /// Computes the root of the MMR. Find all the peaks in the current + /// tree and "bags" them to get a single peak. + fn root(&self) -> Result { + if self.is_empty() { + return Ok(ZERO_HASH); + } + let mut res = None; + let peaks = self.peaks(); + for peak in peaks.into_iter().rev() { + res = match res { + None => Some(peak), + Some(rhash) => Some((peak, rhash).hash_with_index(self.unpruned_size())), + } + } + res.ok_or_else(|| "no root, invalid tree".to_owned()) + } + + /// Build a Merkle proof for the element at the given position. + fn merkle_proof(&self, pos: u64) -> Result { + let last_pos = self.unpruned_size(); + debug!("merkle_proof {}, last_pos {}", pos, last_pos); + + // check this pos is actually a leaf in the MMR + if !is_leaf(pos) { + return Err(format!("not a leaf at pos {}", pos)); + } + + // check we actually have a hash in the MMR at this pos + self.get_hash(pos) + .ok_or_else(|| format!("no element at pos {}", pos))?; + + let family_branch = family_branch(pos, last_pos); + + let mut path = family_branch + .iter() + .filter_map(|x| self.get_from_file(x.1)) + .collect::>(); + + let peak_pos = match family_branch.last() { + Some(&(x, _)) => x, + None => pos, + }; + + path.append(&mut self.peak_path(peak_pos)); + + Ok(MerkleProof { + mmr_size: last_pos, + path, + }) + } +} + /// Prunable Merkle Mountain Range implementation. All positions within the tree /// start at 1 as they're postorder tree traversal positions rather than array /// indices. @@ -74,114 +206,6 @@ where ReadonlyPMMR::at(&self.backend, self.last_pos) } - /// Iterator over current (unpruned, unremoved) leaf positions. - pub fn leaf_pos_iter(&self) -> impl Iterator + '_ { - self.backend.leaf_pos_iter() - } - - /// Number of leafs in the MMR - pub fn n_unpruned_leaves(&self) -> u64 { - self.backend.n_unpruned_leaves() - } - - /// Iterator over current (unpruned, unremoved) leaf insertion indices. - pub fn leaf_idx_iter(&self, from_idx: u64) -> impl Iterator + '_ { - self.backend.leaf_idx_iter(from_idx) - } - - /// Returns a vec of the peaks of this MMR. - pub fn peaks(&self) -> impl DoubleEndedIterator + '_ { - let peaks_pos = peaks(self.last_pos); - peaks_pos.into_iter().filter_map(move |pi| { - // here we want to get from underlying hash file - // as the pos *may* have been "removed" - self.backend.get_from_file(pi) - }) - } - - fn peak_path(&self, peak_pos: u64) -> Vec { - let rhs = self.bag_the_rhs(peak_pos); - let mut res = peaks(self.last_pos) - .into_iter() - .filter(|x| *x < peak_pos) - .filter_map(|x| self.backend.get_from_file(x)) - .collect::>(); - if let Some(rhs) = rhs { - res.push(rhs); - } - res.reverse(); - - res - } - - /// Takes a single peak position and hashes together - /// all the peaks to the right of this peak (if any). - /// If this return a hash then this is our peaks sibling. - /// If none then the sibling of our peak is the peak to the left. - pub fn bag_the_rhs(&self, peak_pos: u64) -> Option { - let rhs = peaks(self.last_pos) - .into_iter() - .filter(|x| *x > peak_pos) - .filter_map(|x| self.backend.get_from_file(x)); - - let mut res = None; - for peak in rhs.rev() { - res = match res { - None => Some(peak), - Some(rhash) => Some((peak, rhash).hash_with_index(self.unpruned_size())), - } - } - res - } - - /// Computes the root of the MMR. Find all the peaks in the current - /// tree and "bags" them to get a single peak. - pub fn root(&self) -> Result { - if self.is_empty() { - return Ok(ZERO_HASH); - } - let mut res = None; - for peak in self.peaks().rev() { - res = match res { - None => Some(peak), - Some(rhash) => Some((peak, rhash).hash_with_index(self.unpruned_size())), - } - } - res.ok_or_else(|| "no root, invalid tree".to_owned()) - } - - /// Build a Merkle proof for the element at the given position. - pub fn merkle_proof(&self, pos: u64) -> Result { - debug!("merkle_proof {}, last_pos {}", pos, self.last_pos); - - // check this pos is actually a leaf in the MMR - if !is_leaf(pos) { - return Err(format!("not a leaf at pos {}", pos)); - } - - // check we actually have a hash in the MMR at this pos - self.get_hash(pos) - .ok_or_else(|| format!("no element at pos {}", pos))?; - - let mmr_size = self.unpruned_size(); - - let family_branch = family_branch(pos, self.last_pos); - - let mut path = family_branch - .iter() - .filter_map(|x| self.get_from_file(x.1)) - .collect::>(); - - let peak_pos = match family_branch.last() { - Some(&(x, _)) => x, - None => pos, - }; - - path.append(&mut self.peak_path(peak_pos)); - - Ok(MerkleProof { mmr_size, path }) - } - /// Push a new element into the MMR. Computes new related peaks at /// the same time if applicable. pub fn push(&mut self, elmt: &T) -> Result { @@ -258,43 +282,6 @@ where Ok(true) } - /// Get the hash at provided position in the MMR. - pub fn get_hash(&self, pos: u64) -> Option { - if pos > self.last_pos { - None - } else if is_leaf(pos) { - // If we are a leaf then get hash from the backend. - self.backend.get_hash(pos) - } else { - // If we are not a leaf get hash ignoring the remove log. - self.backend.get_from_file(pos) - } - } - - /// Get the data element at provided position in the MMR. - pub fn get_data(&self, pos: u64) -> Option { - if pos > self.last_pos { - // If we are beyond the rhs of the MMR return None. - None - } else if is_leaf(pos) { - // If we are a leaf then get data from the backend. - self.backend.get_data(pos) - } else { - // If we are not a leaf then return None as only leaves have data. - None - } - } - - /// Get the hash from the underlying MMR file - /// (ignores the remove log). - fn get_from_file(&self, pos: u64) -> Option { - if pos > self.last_pos { - None - } else { - self.backend.get_from_file(pos) - } - } - /// Walks all unpruned nodes in the MMR and revalidate all parent hashes pub fn validate(&self) -> Result<(), String> { // iterate on all parent nodes @@ -323,17 +310,6 @@ where Ok(()) } - /// Is the MMR empty? - pub fn is_empty(&self) -> bool { - self.last_pos == 0 - } - - /// Total size of the tree, including intermediary nodes and ignoring any - /// pruning. - pub fn unpruned_size(&self) -> u64 { - self.last_pos - } - /// Debugging utility to print information about the MMRs. Short version /// only prints the last 8 nodes. pub fn dump(&self, short: bool) { @@ -396,6 +372,63 @@ where } } +impl<'a, T, B> ReadablePMMR for PMMR<'a, T, B> +where + T: PMMRable, + B: 'a + Backend, +{ + type Item = T::E; + + fn get_hash(&self, pos: u64) -> Option { + if pos > self.last_pos { + None + } else if is_leaf(pos) { + // If we are a leaf then get hash from the backend. + self.backend.get_hash(pos) + } else { + // If we are not a leaf get hash ignoring the remove log. + self.backend.get_from_file(pos) + } + } + + fn get_data(&self, pos: u64) -> Option { + if pos > self.last_pos { + // If we are beyond the rhs of the MMR return None. + None + } else if is_leaf(pos) { + // If we are a leaf then get data from the backend. + self.backend.get_data(pos) + } else { + // If we are not a leaf then return None as only leaves have data. + None + } + } + + fn get_from_file(&self, pos: u64) -> Option { + if pos > self.last_pos { + None + } else { + self.backend.get_from_file(pos) + } + } + + fn unpruned_size(&self) -> u64 { + self.last_pos + } + + fn leaf_pos_iter(&self) -> Box + '_> { + self.backend.leaf_pos_iter() + } + + fn leaf_idx_iter(&self, from_idx: u64) -> Box + '_> { + self.backend.leaf_idx_iter(from_idx) + } + + fn n_unpruned_leaves(&self) -> u64 { + self.backend.n_unpruned_leaves() + } +} + /// Gets the postorder traversal index of all peaks in a MMR given its size. /// Starts with the top peak, which is always on the left /// side of the range, and navigates toward lower siblings toward the right diff --git a/core/src/core/pmmr/readonly_pmmr.rs b/core/src/core/pmmr/readonly_pmmr.rs index de2f24495..bc2f0752e 100644 --- a/core/src/core/pmmr/readonly_pmmr.rs +++ b/core/src/core/pmmr/readonly_pmmr.rs @@ -16,10 +16,10 @@ use std::marker; -use crate::core::hash::{Hash, ZERO_HASH}; -use crate::core::pmmr::pmmr::{bintree_rightmost, peaks}; +use crate::core::hash::Hash; +use crate::core::pmmr::pmmr::{bintree_rightmost, ReadablePMMR}; use crate::core::pmmr::{is_leaf, Backend}; -use crate::ser::{PMMRIndexHashable, PMMRable}; +use crate::ser::PMMRable; /// Readonly view of a PMMR. pub struct ReadonlyPMMR<'a, T, B> @@ -59,93 +59,6 @@ where } } - /// Get the data element at provided position in the MMR. - pub fn get_data(&self, pos: u64) -> Option { - if pos > self.last_pos { - // If we are beyond the rhs of the MMR return None. - None - } else if is_leaf(pos) { - // If we are a leaf then get data from the backend. - self.backend.get_data(pos) - } else { - // If we are not a leaf then return None as only leaves have data. - None - } - } - - /// Get the hash at provided position in the MMR. - pub fn get_hash(&self, pos: u64) -> Option { - if pos > self.last_pos { - None - } else if is_leaf(pos) { - // If we are a leaf then get hash from the backend. - self.backend.get_hash(pos) - } else { - // If we are not a leaf get hash ignoring the remove log. - self.backend.get_from_file(pos) - } - } - - /// Get the hash from the underlying MMR file, ignoring the leafset. - /// Some entries may have been removed from the leafset but not yet pruned from the file. - pub fn get_from_file(&self, pos: u64) -> Option { - if pos > self.last_pos { - None - } else { - self.backend.get_from_file(pos) - } - } - - /// Iterator over current (unpruned, unremoved) leaf positions. - pub fn leaf_pos_iter(&self) -> impl Iterator + '_ { - self.backend.leaf_pos_iter() - } - - /// Iterator over current (unpruned, unremoved) leaf insertion indices. - pub fn leaf_idx_iter(&self, from_idx: u64) -> impl Iterator + '_ { - self.backend.leaf_idx_iter(from_idx) - } - - /// Is the MMR empty? - pub fn is_empty(&self) -> bool { - self.last_pos == 0 - } - - /// Computes the root of the MMR. Find all the peaks in the current - /// tree and "bags" them to get a single peak. - pub fn root(&self) -> Hash { - if self.is_empty() { - return ZERO_HASH; - } - let mut res = None; - for peak in self.peaks().iter().rev() { - res = match res { - None => Some(*peak), - Some(rhash) => Some((*peak, rhash).hash_with_index(self.unpruned_size())), - } - } - res.expect("no root, invalid tree") - } - - /// Returns a vec of the peaks of this MMR. - pub fn peaks(&self) -> Vec { - let peaks_pos = peaks(self.last_pos); - peaks_pos - .into_iter() - .filter_map(|pi| { - // here we want to get from underlying hash file - // as the pos *may* have been "removed" - self.backend.get_from_file(pi) - }) - .collect() - } - - /// Total size of the tree, including intermediary nodes and ignoring any - /// pruning. - pub fn unpruned_size(&self) -> u64 { - self.last_pos - } - /// Helper function which returns un-pruned nodes from the insertion index /// forward /// returns last pmmr index returned along with data @@ -194,3 +107,60 @@ where return_vec } } + +impl<'a, T, B> ReadablePMMR for ReadonlyPMMR<'a, T, B> +where + T: PMMRable, + B: 'a + Backend, +{ + type Item = T::E; + + fn get_hash(&self, pos: u64) -> Option { + if pos > self.last_pos { + None + } else if is_leaf(pos) { + // If we are a leaf then get hash from the backend. + self.backend.get_hash(pos) + } else { + // If we are not a leaf get hash ignoring the remove log. + self.backend.get_from_file(pos) + } + } + + fn get_data(&self, pos: u64) -> Option { + if pos > self.last_pos { + // If we are beyond the rhs of the MMR return None. + None + } else if is_leaf(pos) { + // If we are a leaf then get data from the backend. + self.backend.get_data(pos) + } else { + // If we are not a leaf then return None as only leaves have data. + None + } + } + + fn get_from_file(&self, pos: u64) -> Option { + if pos > self.last_pos { + None + } else { + self.backend.get_from_file(pos) + } + } + + fn unpruned_size(&self) -> u64 { + self.last_pos + } + + fn leaf_pos_iter(&self) -> Box + '_> { + self.backend.leaf_pos_iter() + } + + fn leaf_idx_iter(&self, from_idx: u64) -> Box + '_> { + self.backend.leaf_idx_iter(from_idx) + } + + fn n_unpruned_leaves(&self) -> u64 { + self.backend.n_unpruned_leaves() + } +} diff --git a/core/tests/merkle_proof.rs b/core/tests/merkle_proof.rs index dfcf3432c..f0e6d6bf8 100644 --- a/core/tests/merkle_proof.rs +++ b/core/tests/merkle_proof.rs @@ -15,7 +15,7 @@ mod common; use self::core::core::merkle_proof::MerkleProof; -use self::core::core::pmmr::{VecBackend, PMMR}; +use self::core::core::pmmr::{ReadablePMMR, VecBackend, PMMR}; use self::core::ser::{self, PMMRIndexHashable}; use crate::common::TestElem; use grin_core as core; @@ -90,7 +90,7 @@ fn pmmr_merkle_proof() { assert_eq!(pmmr.get_hash(3).unwrap(), pos_2); assert_eq!(pmmr.root().unwrap(), pos_2); - assert_eq!(pmmr.peaks().collect::>(), [pos_2]); + assert_eq!(pmmr.peaks(), vec![pos_2]); // single peak, path with single sibling let proof = pmmr.merkle_proof(1).unwrap(); @@ -107,7 +107,7 @@ fn pmmr_merkle_proof() { assert_eq!(pmmr.get_hash(4).unwrap(), pos_3); assert_eq!(pmmr.root().unwrap(), (pos_2, pos_3).hash_with_index(4)); - assert_eq!(pmmr.peaks().collect::>(), [pos_2, pos_3]); + assert_eq!(pmmr.peaks(), vec![pos_2, pos_3]); let proof = pmmr.merkle_proof(1).unwrap(); assert_eq!(proof.path, vec![pos_1, pos_3]); diff --git a/core/tests/pmmr.rs b/core/tests/pmmr.rs index 1e02ea135..c903a2dd5 100644 --- a/core/tests/pmmr.rs +++ b/core/tests/pmmr.rs @@ -15,7 +15,7 @@ mod common; use self::core::core::hash::Hash; -use self::core::core::pmmr::{self, VecBackend, PMMR}; +use self::core::core::pmmr::{self, ReadablePMMR, VecBackend, PMMR}; use self::core::ser::PMMRIndexHashable; use crate::common::TestElem; use chrono::prelude::Utc; @@ -278,7 +278,7 @@ fn pmmr_push_root() { pmmr.push(&elems[0]).unwrap(); pmmr.dump(false); let pos_0 = elems[0].hash_with_index(0); - assert_eq!(pmmr.peaks().collect::>(), vec![pos_0]); + assert_eq!(pmmr.peaks(), vec![pos_0]); assert_eq!(pmmr.root().unwrap(), pos_0); assert_eq!(pmmr.unpruned_size(), 1); @@ -287,7 +287,7 @@ fn pmmr_push_root() { 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().collect::>(), vec![pos_2]); + assert_eq!(pmmr.peaks(), vec![pos_2]); assert_eq!(pmmr.root().unwrap(), pos_2); assert_eq!(pmmr.unpruned_size(), 3); @@ -295,7 +295,7 @@ fn pmmr_push_root() { pmmr.push(&elems[2]).unwrap(); pmmr.dump(false); let pos_3 = elems[2].hash_with_index(3); - assert_eq!(pmmr.peaks().collect::>(), vec![pos_2, pos_3]); + assert_eq!(pmmr.peaks(), vec![pos_2, pos_3]); assert_eq!(pmmr.root().unwrap(), (pos_2, pos_3).hash_with_index(4)); assert_eq!(pmmr.unpruned_size(), 4); @@ -305,7 +305,7 @@ fn pmmr_push_root() { 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().collect::>(), vec![pos_6]); + assert_eq!(pmmr.peaks(), vec![pos_6]); assert_eq!(pmmr.root().unwrap(), pos_6); assert_eq!(pmmr.unpruned_size(), 7); @@ -313,7 +313,7 @@ fn pmmr_push_root() { pmmr.push(&elems[4]).unwrap(); pmmr.dump(false); let pos_7 = elems[4].hash_with_index(7); - assert_eq!(pmmr.peaks().collect::>(), vec![pos_6, pos_7]); + assert_eq!(pmmr.peaks(), vec![pos_6, pos_7]); assert_eq!(pmmr.root().unwrap(), (pos_6, pos_7).hash_with_index(8)); assert_eq!(pmmr.unpruned_size(), 8); @@ -321,14 +321,14 @@ fn pmmr_push_root() { 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().collect::>(), vec![pos_6, pos_9]); + assert_eq!(pmmr.peaks(), vec![pos_6, pos_9]); assert_eq!(pmmr.root().unwrap(), (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().collect::>(), vec![pos_6, pos_9, pos_10]); + assert_eq!(pmmr.peaks(), vec![pos_6, pos_9, pos_10]); assert_eq!( pmmr.root().unwrap(), (pos_6, (pos_9, pos_10).hash_with_index(11)).hash_with_index(11) @@ -342,14 +342,14 @@ fn pmmr_push_root() { 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().collect::>(), vec![pos_14]); + assert_eq!(pmmr.peaks(), vec![pos_14]); assert_eq!(pmmr.root().unwrap(), 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().collect::>(), vec![pos_14, pos_15]); + assert_eq!(pmmr.peaks(), vec![pos_14, pos_15]); assert_eq!(pmmr.root().unwrap(), (pos_14, pos_15).hash_with_index(16)); assert_eq!(pmmr.unpruned_size(), 16); } diff --git a/core/tests/vec_backend.rs b/core/tests/vec_backend.rs index d0d313cd9..4ac4419df 100644 --- a/core/tests/vec_backend.rs +++ b/core/tests/vec_backend.rs @@ -14,7 +14,7 @@ mod common; -use self::core::core::pmmr::{VecBackend, PMMR}; +use self::core::core::pmmr::{ReadablePMMR, VecBackend, PMMR}; use crate::common::TestElem; use grin_core as core; diff --git a/store/tests/pmmr.rs b/store/tests/pmmr.rs index 7e4e9bbe0..1f16a2941 100644 --- a/store/tests/pmmr.rs +++ b/store/tests/pmmr.rs @@ -22,7 +22,7 @@ use chrono::prelude::Utc; use croaring::Bitmap; use crate::core::core::hash::DefaultHashable; -use crate::core::core::pmmr::{Backend, PMMR}; +use crate::core::core::pmmr::{Backend, ReadablePMMR, PMMR}; use crate::core::ser::{ Error, PMMRIndexHashable, PMMRable, ProtocolVersion, Readable, Reader, Writeable, Writer, };