use std::marker;
use std::u64;
use croaring::Bitmap;
use crate::core::hash::{Hash, ZERO_HASH};
use crate::core::merkle_proof::MerkleProof;
use crate::core::pmmr::{Backend, ReadonlyPMMR};
use crate::core::BlockHeader;
use crate::ser::{PMMRIndexHashable, PMMRable};
const ALL_ONES: u64 = u64::MAX;
pub struct PMMR<'a, T, B>
where
T: PMMRable,
B: Backend<T>,
{
pub last_pos: u64,
backend: &'a mut B,
_marker: marker::PhantomData<T>,
}
impl<'a, T, B> PMMR<'a, T, B>
where
T: PMMRable,
B: 'a + Backend<T>,
{
pub fn new(backend: &'a mut B) -> PMMR<'_, T, B> {
PMMR {
backend,
last_pos: 0,
_marker: marker::PhantomData,
}
}
pub fn at(backend: &'a mut B, last_pos: u64) -> PMMR<'_, T, B> {
PMMR {
backend,
last_pos,
_marker: marker::PhantomData,
}
}
pub fn readonly_pmmr(&self) -> ReadonlyPMMR<'_, T, B> {
ReadonlyPMMR::at(&self.backend, self.last_pos)
}
pub fn leaf_pos_iter(&self) -> impl Iterator<Item = u64> + '_ {
self.backend.leaf_pos_iter()
}
pub fn n_unpruned_leaves(&self) -> u64 {
self.backend.n_unpruned_leaves()
}
pub fn leaf_idx_iter(&self, from_idx: u64) -> impl Iterator<Item = u64> + '_ {
self.backend.leaf_idx_iter(from_idx)
}
pub fn peaks(&self) -> Vec<Hash> {
let peaks_pos = peaks(self.last_pos);
peaks_pos
.into_iter()
.filter_map(|pi| {
self.backend.get_from_file(pi)
})
.collect()
}
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
}
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))
.collect::<Vec<_>>();
let mut res = None;
for peak in rhs.into_iter().rev() {
res = match res {
None => Some(peak),
Some(rhash) => Some((peak, rhash).hash_with_index(self.unpruned_size())),
}
}
res
}
pub fn root(&self) -> Result<Hash, String> {
if self.is_empty() {
return Ok(ZERO_HASH);
}
let mut res = None;
for peak in self.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())
}
pub fn merkle_proof(&self, pos: u64) -> Result<MerkleProof, String> {
debug!("merkle_proof {}, last_pos {}", pos, self.last_pos);
if !is_leaf(pos) {
return Err(format!("not a leaf at pos {}", 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 })
}
pub fn push(&mut self, elmt: &T) -> Result<u64, String> {
let elmt_pos = self.last_pos + 1;
let mut current_hash = elmt.hash_with_index(elmt_pos - 1);
let mut hashes = vec![current_hash];
let mut pos = elmt_pos;
let (peak_map, height) = peak_map_height(pos - 1);
if height != 0 {
return Err(format!("bad mmr size {}", pos - 1));
}
let mut peak = 1;
while (peak_map & peak) != 0 {
let left_sibling = pos + 1 - 2 * peak;
let left_hash = self
.backend
.get_from_file(left_sibling)
.ok_or("missing left sibling in tree, should not have been pruned")?;
peak *= 2;
pos += 1;
current_hash = (left_hash, current_hash).hash_with_index(pos - 1);
hashes.push(current_hash);
}
self.backend.append(elmt, hashes)?;
self.last_pos = pos;
Ok(elmt_pos)
}
pub fn snapshot(&mut self, header: &BlockHeader) -> Result<(), String> {
self.backend.snapshot(header)?;
Ok(())
}
pub fn rewind(&mut self, position: u64, rewind_rm_pos: &Bitmap) -> Result<(), String> {
let mut pos = position;
while bintree_postorder_height(pos + 1) > 0 {
pos += 1;
}
self.backend.rewind(pos, rewind_rm_pos)?;
self.last_pos = pos;
Ok(())
}
pub fn prune(&mut self, position: u64) -> Result<bool, String> {
if !is_leaf(position) {
return Err(format!("Node at {} is not a leaf, can't prune.", position));
}
if self.backend.get_hash(position).is_none() {
return Ok(false);
}
self.backend.remove(position)?;
Ok(true)
}
pub fn get_hash(&self, pos: u64) -> Option<Hash> {
if pos > self.last_pos {
None
} else if is_leaf(pos) {
self.backend.get_hash(pos)
} else {
self.backend.get_from_file(pos)
}
}
pub fn get_data(&self, pos: u64) -> Option<T::E> {
if pos > self.last_pos {
None
} else if is_leaf(pos) {
self.backend.get_data(pos)
} else {
None
}
}
fn get_from_file(&self, pos: u64) -> Option<Hash> {
if pos > self.last_pos {
None
} else {
self.backend.get_from_file(pos)
}
}
pub fn validate(&self) -> Result<(), String> {
for n in 1..(self.last_pos + 1) {
let height = bintree_postorder_height(n);
if height > 0 {
if let Some(hash) = self.get_hash(n) {
let left_pos = n - (1 << height);
let right_pos = n - 1;
if let Some(left_child_hs) = self.get_from_file(left_pos) {
if let Some(right_child_hs) = self.get_from_file(right_pos) {
if (left_child_hs, right_child_hs).hash_with_index(n - 1) != hash {
return Err(format!(
"Invalid MMR, hash of parent at {} does \
not match children.",
n
));
}
}
}
}
}
}
Ok(())
}
pub fn is_empty(&self) -> bool {
self.last_pos == 0
}
pub fn unpruned_size(&self) -> u64 {
self.last_pos
}
pub fn dump(&self, short: bool) {
let sz = self.unpruned_size();
if sz > 2000 && !short {
return;
}
let start = if short && sz > 7 { sz / 8 - 1 } else { 0 };
for n in start..(sz / 8 + 1) {
let mut idx = "".to_owned();
let mut hashes = "".to_owned();
for m in (n * 8)..(n + 1) * 8 {
if m >= sz {
break;
}
idx.push_str(&format!("{:>8} ", m + 1));
let ohs = self.get_hash(m + 1);
match ohs {
Some(hs) => hashes.push_str(&format!("{} ", hs)),
None => hashes.push_str(&format!("{:>8} ", "??")),
}
}
trace!("{}", idx);
trace!("{}", hashes);
}
}
pub fn dump_stats(&self) {
debug!("pmmr: unpruned - {}", self.unpruned_size());
self.backend.dump_stats();
}
pub fn dump_from_file(&self, short: bool) {
let sz = self.unpruned_size();
if sz > 2000 && !short {
return;
}
let start = if short && sz > 7 { sz / 8 - 1 } else { 0 };
for n in start..(sz / 8 + 1) {
let mut idx = "".to_owned();
let mut hashes = "".to_owned();
for m in (n * 8)..(n + 1) * 8 {
if m >= sz {
break;
}
idx.push_str(&format!("{:>8} ", m + 1));
let ohs = self.get_from_file(m + 1);
match ohs {
Some(hs) => hashes.push_str(&format!("{} ", hs)),
None => hashes.push_str(&format!("{:>8} ", " .")),
}
}
debug!("{}", idx);
debug!("{}", hashes);
}
}
}
pub fn peaks(num: u64) -> Vec<u64> {
if num == 0 {
return vec![];
}
let mut peak_size = ALL_ONES >> num.leading_zeros();
let mut num_left = num;
let mut sum_prev_peaks = 0;
let mut peaks = vec![];
while peak_size != 0 {
if num_left >= peak_size {
peaks.push(sum_prev_peaks + peak_size);
sum_prev_peaks += peak_size;
num_left -= peak_size;
}
peak_size >>= 1;
}
if num_left > 0 {
return vec![];
}
peaks
}
pub fn n_leaves(size: u64) -> u64 {
let (sizes, height) = peak_sizes_height(size);
let nleaves = sizes.into_iter().map(|n| (n + 1) / 2 as u64).sum();
if height == 0 {
nleaves
} else {
nleaves + 1
}
}
pub fn insertion_to_pmmr_index(mut sz: u64) -> u64 {
if sz == 0 {
return 0;
}
sz -= 1;
2 * sz - sz.count_ones() as u64 + 1
}
pub fn peak_sizes_height(size: u64) -> (Vec<u64>, u64) {
if size == 0 {
return (vec![], 0);
}
let mut peak_size = ALL_ONES >> size.leading_zeros();
let mut sizes = vec![];
let mut size_left = size;
while peak_size != 0 {
if size_left >= peak_size {
sizes.push(peak_size);
size_left -= peak_size;
}
peak_size >>= 1;
}
(sizes, size_left)
}
pub fn peak_map_height(mut pos: u64) -> (u64, u64) {
if pos == 0 {
return (0, 0);
}
let mut peak_size = ALL_ONES >> pos.leading_zeros();
let mut bitmap = 0;
while peak_size != 0 {
bitmap <<= 1;
if pos >= peak_size {
pos -= peak_size;
bitmap |= 1;
}
peak_size >>= 1;
}
(bitmap, pos)
}
pub fn bintree_postorder_height(num: u64) -> u64 {
if num == 0 {
return 0;
}
peak_map_height(num - 1).1
}
pub fn is_leaf(pos: u64) -> bool {
bintree_postorder_height(pos) == 0
}
pub fn family(pos: u64) -> (u64, u64) {
let (peak_map, height) = peak_map_height(pos - 1);
let peak = 1 << height;
if (peak_map & peak) != 0 {
(pos + 1, pos + 1 - 2 * peak)
} else {
(pos + 2 * peak, pos + 2 * peak - 1)
}
}
pub fn is_left_sibling(pos: u64) -> bool {
let (peak_map, height) = peak_map_height(pos - 1);
let peak = 1 << height;
(peak_map & peak) == 0
}
pub fn path(pos: u64, last_pos: u64) -> Vec<u64> {
let (peak_map, height) = peak_map_height(pos - 1);
let mut peak = 1 << height;
let mut path = vec![];
let mut current = pos;
while current <= last_pos {
path.push(current);
current += if (peak_map & peak) != 0 { 1 } else { 2 * peak };
peak <<= 1;
}
path
}
pub fn family_branch(pos: u64, last_pos: u64) -> Vec<(u64, u64)> {
let (peak_map, height) = peak_map_height(pos - 1);
let mut peak = 1 << height;
let mut branch = vec![];
let mut current = pos;
let mut sibling;
while current < last_pos {
if (peak_map & peak) != 0 {
current += 1;
sibling = current - 2 * peak;
} else {
current += 2 * peak;
sibling = current - 1;
};
if current > last_pos {
break;
}
branch.push((current, sibling));
peak <<= 1;
}
branch
}
pub fn bintree_rightmost(num: u64) -> u64 {
num - bintree_postorder_height(num)
}
pub fn bintree_leftmost(num: u64) -> u64 {
let height = bintree_postorder_height(num);
num + 2 - (2 << height)
}