commonware_storage/mmr/mod.rs
1//! A Merkle Mountain Range (MMR) is an append-only data structure that allows for efficient
2//! verification of the inclusion of an element, or some range of consecutive elements, in a list.
3//!
4//! # Terminology
5//!
6//! An MMR is a list of perfect binary trees (aka _mountains_) of strictly decreasing height. The
7//! roots of these trees are called the _peaks_ of the MMR. Each _element_ stored in the MMR is
8//! represented by some leaf node in one of these perfect trees, storing a positioned hash of the
9//! element. Non-leaf nodes store a positioned hash of their children.
10//!
11//! The _size_ of an MMR is the total number of nodes summed over all trees.
12//!
13//! The nodes of the MMR are ordered by a post-order traversal of the MMR trees, starting from the
14//! from tallest tree to shortest. The _position_ of a node in the MMR is defined as the 0-based
15//! index of the node in this ordering. This implies the positions of elements, which are always
16//! leaves, may not be contiguous even if they were consecutively added. An element's _location_ is
17//! its 0-based index in the order of element insertion (aka its leaf index). In the example below,
18//! the right-most element has position 18 and location 10.
19//!
20//! As the MMR is an append-only data structure, node positions never change and can be used as
21//! stable identifiers.
22//!
23//! The _height_ of a node is 0 for a leaf, 1 for the parent of 2 leaves, and so on.
24//!
25//! The _root digest_ (or just _root_) of an MMR is the result of hashing together the size of the
26//! MMR and the digests of every peak in decreasing order of height.
27//!
28//! # Examples
29//!
30//! (Borrowed from <https://docs.grin.mw/wiki/chain-state/merkle-mountain-range/>): After adding 11
31//! elements to an MMR, it will have 19 nodes total with 3 peaks corresponding to 3 perfect binary
32//! trees as pictured below, with nodes identified by their positions:
33//!
34//! ```text
35//! Height
36//! 3 14
37//! / \
38//! / \
39//! / \
40//! / \
41//! 2 6 13
42//! / \ / \
43//! 1 2 5 9 12 17
44//! / \ / \ / \ / \ / \
45//! 0 0 1 3 4 7 8 10 11 15 16 18
46//!
47//! Location 0 1 2 3 4 5 6 7 8 9 10
48//! ```
49//!
50//! The root hash in this example is computed as:
51//!
52//! ```text
53//!
54//! Hash(19,
55//! Hash(14, // first peak
56//! Hash(6,
57//! Hash(2, Hash(0, element_0), Hash(1, element_1)),
58//! Hash(5, Hash(3, element_2), Hash(4, element_4))
59//! )
60//! Hash(13,
61//! Hash(9, Hash(7, element_7), Hash(8, element_8)),
62//! Hash(12, Hash(10, element_10), Hash(11, element_11))
63//! )
64//! )
65//! Hash(17, Hash(15, element_15), Hash(16, element_16)) // second peak
66//! Hash(18, element_18) // third peak
67//! )
68//! ```
69
70pub mod hasher;
71pub mod iterator;
72pub mod location;
73pub mod mem;
74pub mod position;
75pub mod proof;
76pub mod stability;
77
78cfg_if::cfg_if! {
79 if #[cfg(feature = "std")] {
80 pub mod bitmap;
81 pub mod grafting;
82 pub mod journaled;
83 pub mod storage;
84 pub mod verification;
85 }
86}
87
88pub use hasher::Standard as StandardHasher;
89pub use location::{Location, LocationError, MAX_LOCATION};
90pub use position::{Position, MAX_POSITION};
91pub use proof::Proof;
92use thiserror::Error;
93
94/// Errors that can occur when interacting with an MMR.
95#[derive(Error, Debug)]
96pub enum Error {
97 #[cfg(feature = "std")]
98 #[error("metadata error: {0}")]
99 MetadataError(#[from] crate::metadata::Error),
100 #[cfg(feature = "std")]
101 #[error("journal error: {0}")]
102 JournalError(#[from] crate::journal::Error),
103 #[cfg(feature = "std")]
104 #[error("runtime error: {0}")]
105 Runtime(#[from] commonware_runtime::Error),
106 #[error("missing node: {0}")]
107 MissingNode(Position),
108 #[error("invalid proof")]
109 InvalidProof,
110 #[error("root mismatch")]
111 RootMismatch,
112 #[error("element pruned: {0}")]
113 ElementPruned(Position),
114 #[error("position is not a leaf: {0}")]
115 PositionNotLeaf(Position),
116 #[error("invalid position: {0}")]
117 InvalidPosition(Position),
118 #[error("missing digest: {0}")]
119 MissingDigest(Position),
120 #[error("missing grafted digest for leaf: {0}")]
121 MissingGraftedDigest(Location),
122 #[error("invalid proof length")]
123 InvalidProofLength,
124 #[error("invalid size: {0}")]
125 InvalidSize(u64),
126 #[error("empty")]
127 Empty,
128 #[error("pruned chunks causes u64 overflow")]
129 PrunedChunksOverflow,
130 #[error("location {0} > MAX_LOCATION")]
131 LocationOverflow(Location),
132 #[error("range out of bounds: end location {0} exceeds MMR size")]
133 RangeOutOfBounds(Location),
134 #[error("bitmap has unmerkleized updates")]
135 DirtyState,
136 #[error("bit offset {0} out of bounds (size: {1})")]
137 BitOutOfBounds(u64, u64),
138 #[error("invalid pinned nodes")]
139 InvalidPinnedNodes,
140 #[error("data corrupted: {0}")]
141 DataCorrupted(&'static str),
142}