mirror of
https://github.com/mimblewimble/grin.git
synced 2025-01-20 19:11:08 +03:00
Refactor PMMR read methods into trait (#3454)
This commit is contained in:
parent
defc714f6e
commit
0aec8b533b
9 changed files with 273 additions and 268 deletions
|
@ -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")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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"),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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<Hash>;
|
||||
|
||||
/// Get the data element at provided position in the MMR.
|
||||
fn get_data(&self, pos: u64) -> Option<Self::Item>;
|
||||
|
||||
/// Get the hash from the underlying MMR file (ignores the remove log).
|
||||
fn get_from_file(&self, pos: u64) -> Option<Hash>;
|
||||
|
||||
/// 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<dyn Iterator<Item = u64> + '_>;
|
||||
|
||||
/// Iterator over current (unpruned, unremoved) leaf insertion indices.
|
||||
fn leaf_idx_iter(&self, from_idx: u64) -> Box<dyn Iterator<Item = u64> + '_>;
|
||||
|
||||
/// 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<Hash> {
|
||||
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<Hash> {
|
||||
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<Hash> {
|
||||
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::<Vec<_>>();
|
||||
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<Hash, String> {
|
||||
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<MerkleProof, String> {
|
||||
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::<Vec<_>>();
|
||||
|
||||
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<Item = u64> + '_ {
|
||||
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<Item = u64> + '_ {
|
||||
self.backend.leaf_idx_iter(from_idx)
|
||||
}
|
||||
|
||||
/// Returns a vec of the peaks of this MMR.
|
||||
pub fn peaks(&self) -> impl DoubleEndedIterator<Item = Hash> + '_ {
|
||||
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<Hash> {
|
||||
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::<Vec<_>>();
|
||||
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<Hash> {
|
||||
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<Hash, String> {
|
||||
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<MerkleProof, String> {
|
||||
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::<Vec<_>>();
|
||||
|
||||
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<u64, String> {
|
||||
|
@ -258,43 +282,6 @@ where
|
|||
Ok(true)
|
||||
}
|
||||
|
||||
/// Get the hash at provided position in the MMR.
|
||||
pub fn get_hash(&self, pos: u64) -> Option<Hash> {
|
||||
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<T::E> {
|
||||
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<Hash> {
|
||||
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<T>,
|
||||
{
|
||||
type Item = T::E;
|
||||
|
||||
fn get_hash(&self, pos: u64) -> Option<Hash> {
|
||||
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<Self::Item> {
|
||||
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<Hash> {
|
||||
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<dyn Iterator<Item = u64> + '_> {
|
||||
self.backend.leaf_pos_iter()
|
||||
}
|
||||
|
||||
fn leaf_idx_iter(&self, from_idx: u64) -> Box<dyn Iterator<Item = u64> + '_> {
|
||||
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
|
||||
|
|
|
@ -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<T::E> {
|
||||
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<Hash> {
|
||||
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<Hash> {
|
||||
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<Item = u64> + '_ {
|
||||
self.backend.leaf_pos_iter()
|
||||
}
|
||||
|
||||
/// Iterator over current (unpruned, unremoved) leaf insertion indices.
|
||||
pub fn leaf_idx_iter(&self, from_idx: u64) -> impl Iterator<Item = u64> + '_ {
|
||||
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<Hash> {
|
||||
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<T>,
|
||||
{
|
||||
type Item = T::E;
|
||||
|
||||
fn get_hash(&self, pos: u64) -> Option<Hash> {
|
||||
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<Self::Item> {
|
||||
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<Hash> {
|
||||
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<dyn Iterator<Item = u64> + '_> {
|
||||
self.backend.leaf_pos_iter()
|
||||
}
|
||||
|
||||
fn leaf_idx_iter(&self, from_idx: u64) -> Box<dyn Iterator<Item = u64> + '_> {
|
||||
self.backend.leaf_idx_iter(from_idx)
|
||||
}
|
||||
|
||||
fn n_unpruned_leaves(&self) -> u64 {
|
||||
self.backend.n_unpruned_leaves()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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::<Vec<_>>(), [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::<Vec<_>>(), [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]);
|
||||
|
|
|
@ -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<_>>(), 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<_>>(), 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<_>>(), 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<_>>(), 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<_>>(), 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<_>>(), 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<_>>(), 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<_>>(), 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<_>>(), 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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue