use alloc::boxed::Box;
use super::{BlockNumber, Nullifier, NullifierBlock, NullifierTree, NullifierTreeError};
use crate::Word;
use crate::crypto::merkle::MerkleError;
#[cfg(feature = "std")]
use crate::crypto::merkle::smt::{LargeSmt, LargeSmtError, SmtStorage};
use crate::crypto::merkle::smt::{MutationSet, SMT_DEPTH, Smt, SmtProof};
pub trait NullifierTreeBackend: Sized {
type Error: core::error::Error + Send + 'static;
fn num_entries(&self) -> usize;
fn entries(&self) -> Box<dyn Iterator<Item = (Word, Word)> + '_>;
fn open(&self, key: &Word) -> SmtProof;
fn apply_mutations(
&mut self,
set: MutationSet<SMT_DEPTH, Word, Word>,
) -> Result<(), Self::Error>;
fn compute_mutations(
&self,
updates: impl IntoIterator<Item = (Word, Word)>,
) -> Result<MutationSet<SMT_DEPTH, Word, Word>, Self::Error>;
fn insert(&mut self, key: Word, value: NullifierBlock) -> Result<NullifierBlock, Self::Error>;
fn get_value(&self, key: &Word) -> NullifierBlock;
fn root(&self) -> Word;
}
impl NullifierTreeBackend for Smt {
type Error = MerkleError;
fn num_entries(&self) -> usize {
Smt::num_entries(self)
}
fn entries(&self) -> Box<dyn Iterator<Item = (Word, Word)> + '_> {
Box::new(Smt::entries(self).map(|(k, v)| (*k, *v)))
}
fn open(&self, key: &Word) -> SmtProof {
Smt::open(self, key)
}
fn apply_mutations(
&mut self,
set: MutationSet<SMT_DEPTH, Word, Word>,
) -> Result<(), Self::Error> {
Smt::apply_mutations(self, set)
}
fn compute_mutations(
&self,
updates: impl IntoIterator<Item = (Word, Word)>,
) -> Result<MutationSet<SMT_DEPTH, Word, Word>, Self::Error> {
Smt::compute_mutations(self, updates)
}
fn insert(&mut self, key: Word, value: NullifierBlock) -> Result<NullifierBlock, Self::Error> {
Smt::insert(self, key, value.into()).map(|word| {
NullifierBlock::try_from(word).expect("SMT should only store valid NullifierBlocks")
})
}
fn get_value(&self, key: &Word) -> NullifierBlock {
NullifierBlock::new(Smt::get_value(self, key))
.expect("SMT should only store valid NullifierBlocks")
}
fn root(&self) -> Word {
Smt::root(self)
}
}
#[cfg(feature = "std")]
impl<Backend> NullifierTreeBackend for LargeSmt<Backend>
where
Backend: SmtStorage,
{
type Error = MerkleError;
fn num_entries(&self) -> usize {
LargeSmt::num_entries(self)
}
fn entries(&self) -> Box<dyn Iterator<Item = (Word, Word)> + '_> {
Box::new(LargeSmt::entries(self).expect("Storage I/O error accessing entries"))
}
fn open(&self, key: &Word) -> SmtProof {
LargeSmt::open(self, key)
}
fn apply_mutations(
&mut self,
set: MutationSet<SMT_DEPTH, Word, Word>,
) -> Result<(), Self::Error> {
LargeSmt::apply_mutations(self, set).map_err(large_smt_error_to_merkle_error)
}
fn compute_mutations(
&self,
updates: impl IntoIterator<Item = (Word, Word)>,
) -> Result<MutationSet<SMT_DEPTH, Word, Word>, Self::Error> {
LargeSmt::compute_mutations(self, updates).map_err(large_smt_error_to_merkle_error)
}
fn insert(&mut self, key: Word, value: NullifierBlock) -> Result<NullifierBlock, Self::Error> {
LargeSmt::insert(self, key, value.into()).map(|word| {
NullifierBlock::try_from(word).expect("SMT should only store valid NullifierBlocks")
})
}
fn get_value(&self, key: &Word) -> NullifierBlock {
LargeSmt::get_value(self, key)
.try_into()
.expect("unable to create NullifierBlock")
}
fn root(&self) -> Word {
LargeSmt::root(self)
}
}
impl NullifierTree<Smt> {
pub fn with_entries(
entries: impl IntoIterator<Item = (Nullifier, BlockNumber)>,
) -> Result<Self, NullifierTreeError> {
let leaves = entries.into_iter().map(|(nullifier, block_num)| {
(nullifier.as_word(), NullifierBlock::from(block_num).into())
});
let smt = Smt::with_entries(leaves)
.map_err(NullifierTreeError::DuplicateNullifierBlockNumbers)?;
Ok(Self::new_unchecked(smt))
}
}
#[cfg(feature = "std")]
impl<Backend> NullifierTree<LargeSmt<Backend>>
where
Backend: SmtStorage,
{
pub fn with_storage_from_entries(
storage: Backend,
entries: impl IntoIterator<Item = (Nullifier, BlockNumber)>,
) -> Result<Self, NullifierTreeError> {
let leaves = entries.into_iter().map(|(nullifier, block_num)| {
(nullifier.as_word(), NullifierBlock::from(block_num).into())
});
let smt = LargeSmt::<Backend>::with_entries(storage, leaves)
.map_err(large_smt_error_to_merkle_error)
.map_err(NullifierTreeError::DuplicateNullifierBlockNumbers)?;
Ok(Self::new_unchecked(smt))
}
}
#[cfg(feature = "std")]
pub(super) fn large_smt_error_to_merkle_error(err: LargeSmtError) -> MerkleError {
match err {
LargeSmtError::Storage(storage_err) => {
panic!("Storage error encountered: {:?}", storage_err)
},
LargeSmtError::StorageNotEmpty => {
panic!("StorageNotEmpty error encountered: {:?}", err)
},
LargeSmtError::Merkle(merkle_err) => merkle_err,
LargeSmtError::RootMismatch { expected, actual } => MerkleError::ConflictingRoots {
expected_root: expected,
actual_root: actual,
},
}
}