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.
|
|
|
|
|
2021-06-17 18:31:26 -07:00
|
|
|
pub mod bridgetree;
|
2022-07-21 21:13:50 -07:00
|
|
|
pub mod position;
|
2021-06-17 18:17:47 -07:00
|
|
|
|
2022-07-21 21:13:50 -07:00
|
|
|
use position::{Level, Position};
|
2022-04-05 11:59:36 -07:00
|
|
|
use std::collections::BTreeSet;
|
2022-07-14 12:45:51 -07:00
|
|
|
|
2021-06-18 13:21:03 -07:00
|
|
|
/// A trait describing the operations that make a value suitable for inclusion in
|
|
|
|
/// an incremental merkle tree.
|
2022-02-24 07:56:56 -08:00
|
|
|
pub trait Hashable: Sized {
|
2021-06-17 18:24:18 -07:00
|
|
|
fn empty_leaf() -> Self;
|
|
|
|
|
2022-07-21 12:20:41 -07:00
|
|
|
fn combine(level: Level, a: &Self, b: &Self) -> Self;
|
2021-06-17 18:24:18 -07:00
|
|
|
|
2022-07-21 12:20:41 -07:00
|
|
|
fn empty_root(level: Level) -> Self {
|
2022-07-21 21:13:50 -07:00
|
|
|
Level::from(0)
|
2021-06-17 18:24:18 -07:00
|
|
|
.iter_to(level)
|
|
|
|
.fold(Self::empty_leaf(), |v, lvl| Self::combine(lvl, &v, &v))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-18 13:21:03 -07:00
|
|
|
/// 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.
|
2021-06-17 18:24:18 -07:00
|
|
|
fn append(&mut self, value: &H) -> bool;
|
2021-01-05 14:11:17 -08:00
|
|
|
|
2021-06-18 13:21:03 -07: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.
|
2021-06-17 18:24:18 -07:00
|
|
|
fn root(&self) -> H;
|
2021-06-18 13:21:03 -07:00
|
|
|
}
|
|
|
|
|
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.
|
2022-04-18 15:01:53 -07:00
|
|
|
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;
|
|
|
|
|
2022-02-18 14:30:47 -08:00
|
|
|
/// Returns the most recently appended leaf value.
|
2022-02-22 20:30:14 -08:00
|
|
|
fn current_position(&self) -> Option<Position>;
|
|
|
|
|
|
|
|
/// Returns the most recently appended leaf value.
|
2022-03-30 20:31:47 -07:00
|
|
|
fn current_leaf(&self) -> Option<&H>;
|
2022-02-18 14:30:47 -08:00
|
|
|
|
2022-03-31 06:06:35 -07:00
|
|
|
/// 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>;
|
2022-02-18 14:30:47 -08:00
|
|
|
|
|
|
|
/// 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
|
2022-03-31 06:06:35 -07:00
|
|
|
/// 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>;
|
2022-04-05 11:59:36 -07:00
|
|
|
|
2022-04-18 15:01:53 -07:00
|
|
|
/// 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,
|
2022-04-18 15:01:53 -07:00
|
|
|
/// 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
|
2022-04-18 15:01:53 -07:00
|
|
|
/// 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
|
|
|
|
2022-03-31 06:06:35 -07: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-06-17 18:24:18 -07:00
|
|
|
|
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.
|
2021-06-17 18:17:47 -07:00
|
|
|
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
|
2022-03-02 09:04:11 -08:00
|
|
|
/// return false and leave the tree unmodified if no checkpoints exist.
|
2021-06-17 18:17:47 -07:00
|
|
|
fn rewind(&mut self) -> bool;
|
2022-04-05 11:59:36 -07:00
|
|
|
|
|
|
|
/// 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
|
2022-04-05 11:59:36 -07:00
|
|
|
/// 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
|
|
|
}
|
|
|
|
|
2022-07-21 14:07:01 -07:00
|
|
|
#[cfg(any(bench, test, feature = "test-dependencies"))]
|
2022-07-21 20:57:03 -07:00
|
|
|
pub mod testing;
|