incrementalmerkletree/src/lib.rs

127 lines
5.4 KiB
Rust
Raw Normal View History

2021-01-05 12:40:05 -08:00
//! # `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.
//!
2022-07-21 17:12:39 -07:00
//! ## Marking
2021-01-05 12:40:05 -08:00
//!
//! Merkle trees are typically used to show that a value exists in the tree via
2022-07-21 17:17:36 -07:00
//! 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
2021-01-05 12:40:05 -08:00
//! 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<H> {
/// 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;
2021-01-05 14:11:17 -08:00
/// 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;
}
2022-07-21 17:12:39 -07:00
/// A Merkle tree that supports incremental appends, marking of
/// leaf nodes for construction of witnesses, checkpoints and rollbacks.
pub trait Tree<H> {
/// 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<Position>;
/// 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
2022-07-21 17:17:36 -07:00
/// a witness for it.
2022-07-21 17:12:39 -07:00
fn get_marked_leaf(&self, position: Position) -> Option<&H>;
/// Marks the current leaf as one for which we're interested in producing
2022-07-21 17:17:36 -07:00
/// 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.
2022-07-21 17:12:39 -07:00
fn mark(&mut self) -> Option<Position>;
2021-01-05 14:11:17 -08:00
2022-07-21 17:12:39 -07:00
/// Return a set of all the positions for which we have marked.
fn marked_positions(&self) -> BTreeSet<Position>;
/// 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<H>;
2022-07-21 17:17:36 -07:00
/// Obtains a witness to the value at the specified position,
/// as of the tree state corresponding to the given root.
2022-07-21 17:17:36 -07:00
/// 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.
2022-07-21 17:17:36 -07:00
fn witness(&self, position: Position, as_of_root: &H) -> Option<Vec<H>>;
2021-01-05 14:11:17 -08:00
/// Marks the value at the specified position as a value we're no longer
2022-07-21 17:12:39 -07:00
/// 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;
2021-12-01 14:41:33 -08:00
/// 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);
2021-01-05 14:11:17 -08:00
2021-12-01 14:41:33 -08:00
/// 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
2022-07-21 17:12:39 -07:00
/// 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);
2021-01-05 14:11:17 -08:00
}
#[cfg(any(bench, test, feature = "test-dependencies"))]
pub mod testing;