//! # `incrementalmerkletree` //! //! Incremental Merkle Trees are fixed-depth Merkle trees with two primary //! capabilities: appending (assigning a value to the next unused leaf and //! advancing the tree) and obtaining the root of the tree. Importantly the tree //! structure attempts to store the least amount of information necessary to //! continue to function; other information should be pruned eagerly to avoid //! waste when the tree state is encoded. //! //! ## Marking //! //! Merkle trees are typically used to show that a value exists in the tree via //! a witness. We need an API that allows us to identify the //! current leaf as a value we wish to compute witnesss for even as //! the tree continues to be appended to in the future; this is called //! maintaining a witness. When we're later uninterested in such a leaf, we can //! prune a witness and remove all unnecessary information from the structure as //! a consequence. //! //! ## Checkpoints and Rollbacks //! //! The structure is not append-only in the strict sense. It is possible to //! identify the current state of the tree as a "checkpoint" and to remove older //! checkpoints that we're no longer interested in. It should be possible to //! roll back to any previous checkpoint. pub mod bridgetree; pub mod position; use position::{Level, Position}; use std::collections::BTreeSet; /// A trait describing the operations that make a value suitable for inclusion in /// an incremental merkle tree. pub trait Hashable: Sized { fn empty_leaf() -> Self; fn combine(level: Level, a: &Self, b: &Self) -> Self; fn empty_root(level: Level) -> Self { Level::from(0) .iter_to(level) .fold(Self::empty_leaf(), |v, lvl| Self::combine(lvl, &v, &v)) } } /// A possibly-empty incremental Merkle frontier. pub trait Frontier { /// Appends a new value to the frontier at the next available slot. /// Returns true if successful and false if the frontier would exceed /// the maximum allowed depth. fn append(&mut self, value: &H) -> bool; /// Obtains the current root of this Merkle frontier by hashing /// against empty nodes up to the maximum height of the pruned /// tree that the frontier represents. fn root(&self) -> H; } /// A Merkle tree that supports incremental appends, marking of /// leaf nodes for construction of witnesses, checkpoints and rollbacks. pub trait Tree { /// Appends a new value to the tree at the next available slot. /// Returns true if successful and false if the tree would exceed /// the maximum allowed depth. fn append(&mut self, value: &H) -> bool; /// Returns the most recently appended leaf value. fn current_position(&self) -> Option; /// Returns the most recently appended leaf value. fn current_leaf(&self) -> Option<&H>; /// Returns the leaf at the specified position if the tree can produce /// a witness for it. fn get_marked_leaf(&self, position: Position) -> Option<&H>; /// Marks the current leaf as one for which we're interested in producing /// a witness. Returns an optional value containing the /// current position if successful or if the current value was already /// marked, or None if the tree is empty. fn mark(&mut self) -> Option; /// Return a set of all the positions for which we have marked. fn marked_positions(&self) -> BTreeSet; /// Obtains the root of the Merkle tree at the specified checkpoint depth /// by hashing against empty nodes up to the maximum height of the tree. /// Returns `None` if there are not enough checkpoints available to reach the /// requested checkpoint depth. fn root(&self, checkpoint_depth: usize) -> Option; /// Obtains a witness to the value at the specified position, /// as of the tree state corresponding to the given root. /// Returns `None` if there is no available witness to that /// position or if the root does not correspond to a checkpointed /// root of the tree. fn witness(&self, position: Position, as_of_root: &H) -> Option>; /// Marks the value at the specified position as a value we're no longer /// interested in maintaining a mark for. Returns true if successful and /// false if we were already not maintaining a mark at this position. fn remove_mark(&mut self, position: Position) -> bool; /// Creates a new checkpoint for the current tree state. It is valid to /// have multiple checkpoints for the same tree state, and each `rewind` /// call will remove a single checkpoint. fn checkpoint(&mut self); /// Rewinds the tree state to the previous checkpoint, and then removes /// that checkpoint record. If there are multiple checkpoints at a given /// tree state, the tree state will not be altered until all checkpoints /// at that tree state have been removed using `rewind`. This function /// return false and leave the tree unmodified if no checkpoints exist. fn rewind(&mut self) -> bool; /// Remove state from the tree that no longer needs to be maintained /// because it is associated with checkpoints or marks that /// have been removed from the tree at positions deeper than those /// reachable by calls to `rewind`. It is always safe to implement /// this as a no-op operation fn garbage_collect(&mut self); } #[cfg(any(bench, test, feature = "test-dependencies"))] pub mod testing;