Readonly pmmr cleanup (#2083)
* avoid locking txhashset by using a readonly PMMR * rustfmt
This commit is contained in:
@@ -282,53 +282,6 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper function to get the last N nodes inserted, i.e. the last
|
||||
/// n nodes along the bottom of the tree.
|
||||
/// May return less than n items if the MMR has been pruned/compacted.
|
||||
pub fn get_last_n_insertions(&self, n: u64) -> Vec<(Hash, T::E)> {
|
||||
let mut return_vec = vec![];
|
||||
let mut last_leaf = self.last_pos;
|
||||
for _ in 0..n as u64 {
|
||||
if last_leaf == 0 {
|
||||
break;
|
||||
}
|
||||
last_leaf = bintree_rightmost(last_leaf);
|
||||
|
||||
if let Some(hash) = self.backend.get_hash(last_leaf) {
|
||||
if let Some(data) = self.backend.get_data(last_leaf) {
|
||||
return_vec.push((hash, data));
|
||||
}
|
||||
}
|
||||
last_leaf -= 1;
|
||||
}
|
||||
return_vec
|
||||
}
|
||||
|
||||
/// Helper function which returns un-pruned nodes from the insertion index
|
||||
/// forward
|
||||
/// returns last insertion index returned along with data
|
||||
pub fn elements_from_insertion_index(
|
||||
&self,
|
||||
mut index: u64,
|
||||
max_count: u64,
|
||||
) -> (u64, Vec<T::E>) {
|
||||
let mut return_vec = vec![];
|
||||
if index == 0 {
|
||||
index = 1;
|
||||
}
|
||||
let mut return_index = index;
|
||||
let mut pmmr_index = insertion_to_pmmr_index(index);
|
||||
while return_vec.len() < max_count as usize && pmmr_index <= self.last_pos {
|
||||
if let Some(t) = self.get_data(pmmr_index) {
|
||||
return_vec.push(t);
|
||||
return_index = index;
|
||||
}
|
||||
index += 1;
|
||||
pmmr_index = insertion_to_pmmr_index(index);
|
||||
}
|
||||
(return_index, return_vec)
|
||||
}
|
||||
|
||||
/// Walks all unpruned nodes in the MMR and revalidate all parent hashes
|
||||
pub fn validate(&self) -> Result<(), String> {
|
||||
// iterate on all parent nodes
|
||||
|
||||
@@ -16,9 +16,10 @@
|
||||
|
||||
use std::marker;
|
||||
|
||||
use core::hash::Hash;
|
||||
use core::hash::{Hash, ZERO_HASH};
|
||||
use core::pmmr::pmmr::{bintree_rightmost, insertion_to_pmmr_index, peaks};
|
||||
use core::pmmr::{is_leaf, Backend};
|
||||
use ser::PMMRable;
|
||||
use ser::{PMMRIndexHashable, PMMRable};
|
||||
|
||||
/// Readonly view of a PMMR.
|
||||
pub struct ReadonlyPMMR<'a, T, B>
|
||||
@@ -84,4 +85,90 @@ where
|
||||
self.backend.get_from_file(pos)
|
||||
}
|
||||
}
|
||||
|
||||
/// 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 insertion index returned along with data
|
||||
pub fn elements_from_insertion_index(
|
||||
&self,
|
||||
mut index: u64,
|
||||
max_count: u64,
|
||||
) -> (u64, Vec<T::E>) {
|
||||
let mut return_vec = vec![];
|
||||
if index == 0 {
|
||||
index = 1;
|
||||
}
|
||||
let mut return_index = index;
|
||||
let mut pmmr_index = insertion_to_pmmr_index(index);
|
||||
while return_vec.len() < max_count as usize && pmmr_index <= self.last_pos {
|
||||
if let Some(t) = self.get_data(pmmr_index) {
|
||||
return_vec.push(t);
|
||||
return_index = index;
|
||||
}
|
||||
index += 1;
|
||||
pmmr_index = insertion_to_pmmr_index(index);
|
||||
}
|
||||
(return_index, return_vec)
|
||||
}
|
||||
|
||||
/// Helper function to get the last N nodes inserted, i.e. the last
|
||||
/// n nodes along the bottom of the tree.
|
||||
/// May return less than n items if the MMR has been pruned/compacted.
|
||||
pub fn get_last_n_insertions(&self, n: u64) -> Vec<(Hash, T::E)> {
|
||||
let mut return_vec = vec![];
|
||||
let mut last_leaf = self.last_pos;
|
||||
for _ in 0..n as u64 {
|
||||
if last_leaf == 0 {
|
||||
break;
|
||||
}
|
||||
last_leaf = bintree_rightmost(last_leaf);
|
||||
|
||||
if let Some(hash) = self.backend.get_hash(last_leaf) {
|
||||
if let Some(data) = self.backend.get_data(last_leaf) {
|
||||
return_vec.push((hash, data));
|
||||
}
|
||||
}
|
||||
last_leaf -= 1;
|
||||
}
|
||||
return_vec
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
use std::marker;
|
||||
|
||||
use core::hash::Hash;
|
||||
use core::hash::{Hash, ZERO_HASH};
|
||||
use core::pmmr::{bintree_postorder_height, is_leaf, peaks, Backend};
|
||||
use ser::{PMMRIndexHashable, PMMRable};
|
||||
|
||||
@@ -88,9 +88,17 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
|
||||
Reference in New Issue
Block a user