use crate::{common::find_peaks, error::MerkleMountainRangeError, ArrayLike, Hash, MerkleMountainRange};
use digest::Digest;
use serde::{Deserialize, Serialize};
use std::convert::TryFrom;
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
pub struct PrunedHashSet {
base_offset: usize,
peak_indices: Vec<usize>,
peak_hashes: Vec<Hash>,
hashes: Vec<Hash>,
}
impl<D, B> TryFrom<&MerkleMountainRange<D, B>> for PrunedHashSet
where
D: Digest,
B: ArrayLike<Value = Hash>,
{
type Error = MerkleMountainRangeError;
fn try_from(base_mmr: &MerkleMountainRange<D, B>) -> Result<Self, Self::Error> {
let base_offset = base_mmr.len()?;
let peak_indices = find_peaks(base_offset);
let peak_hashes = peak_indices
.iter()
.map(|i| match base_mmr.get_node_hash(*i)? {
Some(h) => Ok(h),
None => Err(MerkleMountainRangeError::HashNotFound(*i)),
})
.collect::<Result<_, _>>()?;
Ok(PrunedHashSet {
base_offset,
peak_indices,
peak_hashes,
hashes: Vec::new(),
})
}
}
impl ArrayLike for PrunedHashSet {
type Error = MerkleMountainRangeError;
type Value = Hash;
#[inline(always)]
fn len(&self) -> Result<usize, Self::Error> {
Ok(self.base_offset + self.hashes.len())
}
fn is_empty(&self) -> Result<bool, Self::Error> {
Ok(self.len()? == 0)
}
fn push(&mut self, item: Self::Value) -> Result<usize, Self::Error> {
self.hashes.push(item);
Ok(self.len()? - 1)
}
fn get(&self, index: usize) -> Result<Option<Self::Value>, Self::Error> {
if index < self.base_offset {
return Ok(match self.peak_indices.binary_search(&index) {
Ok(nth_peak) => Some(self.peak_hashes[nth_peak].clone()),
Err(_) => None,
});
}
self.hashes.get(index - self.base_offset)
}
fn clear(&mut self) -> Result<(), Self::Error> {
self.base_offset = 0;
self.peak_indices.clear();
self.peak_hashes.clear();
self.hashes.clear();
Ok(())
}
fn position(&self, item: &Self::Value) -> Result<Option<usize>, Self::Error> {
for index in 0..self.len()? {
if let Some(stored_item) = self.get(index)? {
if stored_item == *item {
return Ok(Some(index));
}
}
}
Ok(None)
}
}