use super::{NodeIndex, SerializedProof, BYTES_PER_CHUNK};
use crate::cache::Cache;
use crate::error::{Error, Result};
use crate::field::Node;
use crate::merkle_tree_overlay::MerkleTreeOverlay;
use crate::path::Path;
use crate::tree_arithmetic::zeroed::sibling_index;
use std::marker::PhantomData;
#[derive(Clone, Debug, Default, PartialEq)]
pub struct Proof<T: MerkleTreeOverlay> {
cache: Cache,
_phantom: PhantomData<T>,
}
impl<T: MerkleTreeOverlay> Proof<T> {
pub fn new(proof: SerializedProof) -> Self {
let mut ret = Self {
cache: Cache::new(),
_phantom: PhantomData,
};
ret.load(proof).unwrap();
ret
}
pub fn load(&mut self, proof: SerializedProof) -> Result<()> {
for (i, index) in proof.indices.iter().enumerate() {
let chunk = proof.chunks[i * BYTES_PER_CHUNK..(i + 1) * BYTES_PER_CHUNK].to_vec();
self.cache.insert(*index, chunk.clone());
}
Ok(())
}
pub fn extract(&self, path: Vec<Path>) -> Result<SerializedProof> {
if path.len() == 0 {
return Err(Error::EmptyPath());
}
let node = T::get_node(path.clone())?;
let mut visitor = node.get_index();
let mut indices: Vec<NodeIndex> = vec![visitor];
let mut chunks: Vec<u8> = self
.cache
.get(visitor)
.ok_or(Error::ChunkNotLoaded(visitor))?
.clone();
while visitor > 0 {
let sibling = sibling_index(visitor);
let left = 2 * sibling + 1;
let right = 2 * sibling + 2;
if !(indices.contains(&left) && indices.contains(&right)) {
indices.push(sibling);
chunks.extend(
self.cache
.get(sibling)
.ok_or(Error::ChunkNotLoaded(sibling))?,
);
}
visitor = (visitor + 1) / 2 - 1;
}
Ok(SerializedProof { indices, chunks })
}
pub fn get_bytes(&self, path: Vec<Path>) -> Result<Vec<u8>> {
if path.len() == 0 {
return Err(Error::EmptyPath());
}
let (index, begin, end) = bytes_at_path_helper::<T>(path)?;
Ok(self.cache.get(index).ok_or(Error::ChunkNotLoaded(index))?[begin..end].to_vec())
}
pub fn set_bytes(&mut self, path: Vec<Path>, bytes: Vec<u8>) -> Result<()> {
if path.len() == 0 {
return Err(Error::EmptyPath());
}
let (index, begin, end) = bytes_at_path_helper::<T>(path)?;
let chunk = self
.cache
.get(index)
.ok_or(Error::ChunkNotLoaded(index))?
.to_vec()
.iter()
.cloned()
.enumerate()
.map(|(i, b)| {
if i >= begin && i < end {
bytes[i - begin]
} else {
b
}
})
.collect();
self.cache.insert(index, chunk);
Ok(())
}
pub fn is_valid(&self, root: Vec<u8>) -> bool {
self.cache.is_valid(root)
}
pub fn fill(&mut self) -> Result<()> {
self.cache.fill()
}
pub fn root(&self) -> Option<&Vec<u8>> {
self.cache.get(0)
}
pub fn refresh(&mut self) -> Result<()> {
self.cache.refresh()
}
}
fn bytes_at_path_helper<T: MerkleTreeOverlay + ?Sized>(
path: Vec<Path>,
) -> Result<(NodeIndex, usize, usize)> {
if path.len() == 0 {
return Err(Error::EmptyPath());
}
match T::get_node(path.clone())? {
Node::Composite(c) => Ok((c.index, 0, 32)),
Node::Length(l) => Ok((l.index, 0, 32)),
Node::Primitive(l) => {
for p in l.clone() {
if p.ident == path.last().unwrap().to_string() {
return Ok((p.index, p.offset as usize, (p.offset + p.size) as usize));
}
}
Err(Error::InvalidPath(path[0].clone()))
}
}
}