|
|
@@ -63,7 +63,7 @@ use std::collections::HashMap;
|
|
|
// Only used for the type aliases below
|
|
|
use pasta_curves::pallas;
|
|
|
|
|
|
-use crate::error::{ContractError, ContractResult};
|
|
|
+use crate::error::ContractResult;
|
|
|
use util::{FieldElement, FieldHasher};
|
|
|
|
|
|
mod empty;
|
|
|
@@ -92,12 +92,13 @@ pub type SmtMemoryFp = SparseMerkleTree<
|
|
|
pub type PathFp = Path<SMT_FP_DEPTH, pallas::Base, PoseidonFp>;
|
|
|
|
|
|
/// Pluggable storage backend for the SMT.
|
|
|
-/// Has a minimal interface to simply put and get objects from the store.
|
|
|
+/// Has a minimal interface to put, get, and delete objects from the store.
|
|
|
pub trait StorageAdapter {
|
|
|
type Value;
|
|
|
|
|
|
- fn put(&mut self, key: BigUint, value: Self::Value) -> bool;
|
|
|
+ fn put(&mut self, key: BigUint, value: Self::Value) -> ContractResult;
|
|
|
fn get(&self, key: &BigUint) -> Option<Self::Value>;
|
|
|
+ fn del(&mut self, key: &BigUint) -> ContractResult;
|
|
|
}
|
|
|
|
|
|
/// An in-memory storage, useful for unit tests and smaller trees.
|
|
|
@@ -115,14 +116,19 @@ impl<F: FieldElement> MemoryStorage<F> {
|
|
|
impl<F: FieldElement> StorageAdapter for MemoryStorage<F> {
|
|
|
type Value = F;
|
|
|
|
|
|
- fn put(&mut self, key: BigUint, value: F) -> bool {
|
|
|
+ fn put(&mut self, key: BigUint, value: F) -> ContractResult {
|
|
|
self.tree.insert(key, value);
|
|
|
- true
|
|
|
+ Ok(())
|
|
|
}
|
|
|
|
|
|
fn get(&self, key: &BigUint) -> Option<F> {
|
|
|
self.tree.get(key).copied()
|
|
|
}
|
|
|
+
|
|
|
+ fn del(&mut self, key: &BigUint) -> ContractResult {
|
|
|
+ self.tree.remove(key);
|
|
|
+ Ok(())
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/// The Sparse Merkle Tree struct.
|
|
|
@@ -212,6 +218,50 @@ impl<
|
|
|
Ok(())
|
|
|
}
|
|
|
|
|
|
+ pub fn remove_leaves(&mut self, leaves: Vec<(F, F)>) -> ContractResult {
|
|
|
+ if leaves.is_empty() {
|
|
|
+ return Ok(())
|
|
|
+ }
|
|
|
+
|
|
|
+ let mut dirty_idxs = Vec::new();
|
|
|
+ for (pos, _leaf) in leaves {
|
|
|
+ let idx = util::leaf_pos_to_index::<N, _>(&pos);
|
|
|
+ self.remove_node(&idx)?;
|
|
|
+
|
|
|
+ // Mark node parent as dirty
|
|
|
+ let parent_idx = util::parent(&idx).unwrap();
|
|
|
+ dirty_idxs.push(parent_idx);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Depth first from the bottom of the tree
|
|
|
+ for _ in 0..N + 1 {
|
|
|
+ let mut new_dirty_idxs = Vec::new();
|
|
|
+
|
|
|
+ for idx in dirty_idxs {
|
|
|
+ let left_idx = util::left_child(&idx);
|
|
|
+ let right_idx = util::right_child(&idx);
|
|
|
+ let left = self.get_node(&left_idx);
|
|
|
+ let right = self.get_node(&right_idx);
|
|
|
+ // Recalculate the node
|
|
|
+ let node = self.hasher.hash([left, right]);
|
|
|
+
|
|
|
+ self.put_node(idx.clone(), node)?;
|
|
|
+
|
|
|
+ // Add this node's parent to the update list
|
|
|
+ let parent_idx = match util::parent(&idx) {
|
|
|
+ Some(idx) => idx,
|
|
|
+ // We are at the root node so no parents exist
|
|
|
+ None => break,
|
|
|
+ };
|
|
|
+ new_dirty_idxs.push(parent_idx);
|
|
|
+ }
|
|
|
+
|
|
|
+ dirty_idxs = new_dirty_idxs;
|
|
|
+ }
|
|
|
+
|
|
|
+ Ok(())
|
|
|
+ }
|
|
|
+
|
|
|
/// Returns the Merkle tree root.
|
|
|
pub fn root(&self) -> F {
|
|
|
self.get_node(&BigUint::from(0u32))
|
|
|
@@ -251,10 +301,11 @@ impl<
|
|
|
}
|
|
|
|
|
|
fn put_node(&mut self, key: BigUint, value: F) -> ContractResult {
|
|
|
- if !self.store.put(key, value) {
|
|
|
- return Err(ContractError::SmtPutFailed)
|
|
|
- }
|
|
|
- Ok(())
|
|
|
+ self.store.put(key, value)
|
|
|
+ }
|
|
|
+
|
|
|
+ fn remove_node(&mut self, key: &BigUint) -> ContractResult {
|
|
|
+ self.store.del(key)
|
|
|
}
|
|
|
}
|
|
|
|