Merge pull request #99 from 0xPolygonMiden/vlopes11-merkle-store-containers
feat: add merkle path containers and return them on tree update
This commit is contained in:
commit
7305a72295
4 changed files with 80 additions and 45 deletions
|
@ -18,7 +18,7 @@ mod merkle_tree;
|
||||||
pub use merkle_tree::MerkleTree;
|
pub use merkle_tree::MerkleTree;
|
||||||
|
|
||||||
mod path;
|
mod path;
|
||||||
pub use path::MerklePath;
|
pub use path::{MerklePath, RootPath, ValuePath};
|
||||||
|
|
||||||
mod path_set;
|
mod path_set;
|
||||||
pub use path_set::MerklePathSet;
|
pub use path_set::MerklePathSet;
|
||||||
|
|
|
@ -82,3 +82,27 @@ impl IntoIterator for MerklePath {
|
||||||
self.nodes.into_iter()
|
self.nodes.into_iter()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MERKLE PATH CONTAINERS
|
||||||
|
// ================================================================================================
|
||||||
|
|
||||||
|
/// A container for a [Word] value and its [MerklePath] opening.
|
||||||
|
#[derive(Clone, Debug, Default, PartialEq, Eq)]
|
||||||
|
pub struct ValuePath {
|
||||||
|
/// The node value opening for `path`.
|
||||||
|
pub value: Word,
|
||||||
|
/// The path from `value` to `root` (exclusive).
|
||||||
|
pub path: MerklePath,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A container for a [MerklePath] and its [Word] root.
|
||||||
|
///
|
||||||
|
/// This structure does not provide any guarantees regarding the correctness of the path to the
|
||||||
|
/// root. For more information, check [MerklePath::verify].
|
||||||
|
#[derive(Clone, Debug, Default, PartialEq, Eq)]
|
||||||
|
pub struct RootPath {
|
||||||
|
/// The node value opening for `path`.
|
||||||
|
pub root: Word,
|
||||||
|
/// The path from `value` to `root` (exclusive).
|
||||||
|
pub path: MerklePath,
|
||||||
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
//! implementation of efficient persistent data structures
|
//! implementation of efficient persistent data structures
|
||||||
use super::{
|
use super::{
|
||||||
BTreeMap, BTreeSet, EmptySubtreeRoots, MerkleError, MerklePath, MerklePathSet, MerkleTree,
|
BTreeMap, BTreeSet, EmptySubtreeRoots, MerkleError, MerklePath, MerklePathSet, MerkleTree,
|
||||||
NodeIndex, Rpo256, RpoDigest, SimpleSmt, Vec, Word,
|
NodeIndex, RootPath, Rpo256, RpoDigest, SimpleSmt, ValuePath, Vec, Word,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -122,11 +122,7 @@ impl MerkleStore {
|
||||||
/// This method can return the following errors:
|
/// This method can return the following errors:
|
||||||
/// - `RootNotInStore` if the `root` is not present in the store.
|
/// - `RootNotInStore` if the `root` is not present in the store.
|
||||||
/// - `NodeNotInStore` if a node needed to traverse from `root` to `index` is not present in the store.
|
/// - `NodeNotInStore` if a node needed to traverse from `root` to `index` is not present in the store.
|
||||||
pub fn get_path(
|
pub fn get_path(&self, root: Word, index: NodeIndex) -> Result<ValuePath, MerkleError> {
|
||||||
&self,
|
|
||||||
root: Word,
|
|
||||||
index: NodeIndex,
|
|
||||||
) -> Result<(Word, MerklePath), MerkleError> {
|
|
||||||
let mut hash: RpoDigest = root.into();
|
let mut hash: RpoDigest = root.into();
|
||||||
let mut path = Vec::with_capacity(index.depth().into());
|
let mut path = Vec::with_capacity(index.depth().into());
|
||||||
|
|
||||||
|
@ -150,8 +146,13 @@ impl MerkleStore {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// the path is computed from root to leaf, so it must be reversed
|
||||||
path.reverse();
|
path.reverse();
|
||||||
Ok((hash.into(), MerklePath::new(path)))
|
|
||||||
|
Ok(ValuePath {
|
||||||
|
value: hash.into(),
|
||||||
|
path: MerklePath::new(path),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// STATE MUTATORS
|
// STATE MUTATORS
|
||||||
|
@ -233,17 +234,17 @@ impl MerkleStore {
|
||||||
Ok(smt.root())
|
Ok(smt.root())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds all the nodes of a Merkle path represented by `path`.
|
/// Adds all the nodes of a Merkle path represented by `path`, opening to `node`. Returns the
|
||||||
|
/// new root.
|
||||||
///
|
///
|
||||||
/// This will compute the sibling elements determined by the Merkle `path` and `node`, and
|
/// This will compute the sibling elements determined by the Merkle `path` and `node`, and
|
||||||
/// include all the nodes into the store.
|
/// include all the nodes into the store.
|
||||||
pub fn add_merkle_path(
|
pub fn add_merkle_path(
|
||||||
&mut self,
|
&mut self,
|
||||||
index_value: u64,
|
index_value: u64,
|
||||||
node: Word,
|
mut node: Word,
|
||||||
path: MerklePath,
|
path: MerklePath,
|
||||||
) -> Result<Word, MerkleError> {
|
) -> Result<Word, MerkleError> {
|
||||||
let mut node = node;
|
|
||||||
let mut index = NodeIndex::new(self.nodes.len() as u8, index_value);
|
let mut index = NodeIndex::new(self.nodes.len() as u8, index_value);
|
||||||
|
|
||||||
for sibling in path {
|
for sibling in path {
|
||||||
|
@ -272,6 +273,8 @@ impl MerkleStore {
|
||||||
/// This will compute the sibling elements for each Merkle `path` and include all the nodes
|
/// This will compute the sibling elements for each Merkle `path` and include all the nodes
|
||||||
/// into the store.
|
/// into the store.
|
||||||
///
|
///
|
||||||
|
/// For further reference, check [MerkleStore::add_merkle_path].
|
||||||
|
///
|
||||||
/// # Errors
|
/// # Errors
|
||||||
///
|
///
|
||||||
/// Every path must resolve to the same root, otherwise this will return an `ConflictingRoots`
|
/// Every path must resolve to the same root, otherwise this will return an `ConflictingRoots`
|
||||||
|
@ -301,6 +304,8 @@ impl MerkleStore {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Appends the provided [MerklePathSet] into the store.
|
/// Appends the provided [MerklePathSet] into the store.
|
||||||
|
///
|
||||||
|
/// For further reference, check [MerkleStore::add_merkle_path].
|
||||||
pub fn add_merkle_path_set(&mut self, path_set: &MerklePathSet) -> Result<Word, MerkleError> {
|
pub fn add_merkle_path_set(&mut self, path_set: &MerklePathSet) -> Result<Word, MerkleError> {
|
||||||
let root = path_set.root();
|
let root = path_set.root();
|
||||||
path_set.indexes().try_fold(root, |_, index| {
|
path_set.indexes().try_fold(root, |_, index| {
|
||||||
|
@ -319,16 +324,19 @@ impl MerkleStore {
|
||||||
/// - `NodeNotInStore` if a node needed to traverse from `root` to `index` is not present in the store.
|
/// - `NodeNotInStore` if a node needed to traverse from `root` to `index` is not present in the store.
|
||||||
pub fn set_node(
|
pub fn set_node(
|
||||||
&mut self,
|
&mut self,
|
||||||
root: Word,
|
mut root: Word,
|
||||||
index: NodeIndex,
|
index: NodeIndex,
|
||||||
value: Word,
|
value: Word,
|
||||||
) -> Result<Word, MerkleError> {
|
) -> Result<RootPath, MerkleError> {
|
||||||
let result = self.get_path(root, index)?;
|
let node = value;
|
||||||
if result.0 != value {
|
let ValuePath { value, path } = self.get_path(root, index)?;
|
||||||
self.add_merkle_path(index.value(), value, result.1)
|
|
||||||
} else {
|
// performs the update only if the node value differs from the opening
|
||||||
Ok(root)
|
if node != value {
|
||||||
|
root = self.add_merkle_path(index.value(), node, path.clone())?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(RootPath { root, path })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn merge_roots(&mut self, root1: Word, root2: Word) -> Result<Word, MerkleError> {
|
pub fn merge_roots(&mut self, root1: Word, root2: Word) -> Result<Word, MerkleError> {
|
||||||
|
|
|
@ -90,12 +90,12 @@ fn test_merkle_tree() -> Result<(), MerkleError> {
|
||||||
.get_path(mtree.root(), NodeIndex::new(mtree.depth(), 0))
|
.get_path(mtree.root(), NodeIndex::new(mtree.depth(), 0))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
LEAVES4[0], result.0,
|
LEAVES4[0], result.value,
|
||||||
"Value for merkle path at index 0 must match leaf value"
|
"Value for merkle path at index 0 must match leaf value"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
mtree.get_path(NodeIndex::new(mtree.depth(), 0)),
|
mtree.get_path(NodeIndex::new(mtree.depth(), 0)),
|
||||||
Ok(result.1),
|
Ok(result.path),
|
||||||
"merkle path for index 0 must be the same for the MerkleTree and MerkleStore"
|
"merkle path for index 0 must be the same for the MerkleTree and MerkleStore"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -103,12 +103,12 @@ fn test_merkle_tree() -> Result<(), MerkleError> {
|
||||||
.get_path(mtree.root(), NodeIndex::new(mtree.depth(), 1))
|
.get_path(mtree.root(), NodeIndex::new(mtree.depth(), 1))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
LEAVES4[1], result.0,
|
LEAVES4[1], result.value,
|
||||||
"Value for merkle path at index 0 must match leaf value"
|
"Value for merkle path at index 0 must match leaf value"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
mtree.get_path(NodeIndex::new(mtree.depth(), 1)),
|
mtree.get_path(NodeIndex::new(mtree.depth(), 1)),
|
||||||
Ok(result.1),
|
Ok(result.path),
|
||||||
"merkle path for index 1 must be the same for the MerkleTree and MerkleStore"
|
"merkle path for index 1 must be the same for the MerkleTree and MerkleStore"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -116,12 +116,12 @@ fn test_merkle_tree() -> Result<(), MerkleError> {
|
||||||
.get_path(mtree.root(), NodeIndex::new(mtree.depth(), 2))
|
.get_path(mtree.root(), NodeIndex::new(mtree.depth(), 2))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
LEAVES4[2], result.0,
|
LEAVES4[2], result.value,
|
||||||
"Value for merkle path at index 0 must match leaf value"
|
"Value for merkle path at index 0 must match leaf value"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
mtree.get_path(NodeIndex::new(mtree.depth(), 2)),
|
mtree.get_path(NodeIndex::new(mtree.depth(), 2)),
|
||||||
Ok(result.1),
|
Ok(result.path),
|
||||||
"merkle path for index 0 must be the same for the MerkleTree and MerkleStore"
|
"merkle path for index 0 must be the same for the MerkleTree and MerkleStore"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -129,12 +129,12 @@ fn test_merkle_tree() -> Result<(), MerkleError> {
|
||||||
.get_path(mtree.root(), NodeIndex::new(mtree.depth(), 3))
|
.get_path(mtree.root(), NodeIndex::new(mtree.depth(), 3))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
LEAVES4[3], result.0,
|
LEAVES4[3], result.value,
|
||||||
"Value for merkle path at index 0 must match leaf value"
|
"Value for merkle path at index 0 must match leaf value"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
mtree.get_path(NodeIndex::new(mtree.depth(), 3)),
|
mtree.get_path(NodeIndex::new(mtree.depth(), 3)),
|
||||||
Ok(result.1),
|
Ok(result.path),
|
||||||
"merkle path for index 0 must be the same for the MerkleTree and MerkleStore"
|
"merkle path for index 0 must be the same for the MerkleTree and MerkleStore"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -241,12 +241,12 @@ fn test_sparse_merkle_tree() -> Result<(), MerkleError> {
|
||||||
.get_path(smt.root(), NodeIndex::new(smt.depth(), 0))
|
.get_path(smt.root(), NodeIndex::new(smt.depth(), 0))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
LEAVES4[0], result.0,
|
LEAVES4[0], result.value,
|
||||||
"Value for merkle path at index 0 must match leaf value"
|
"Value for merkle path at index 0 must match leaf value"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
smt.get_path(NodeIndex::new(smt.depth(), 0)),
|
smt.get_path(NodeIndex::new(smt.depth(), 0)),
|
||||||
Ok(result.1),
|
Ok(result.path),
|
||||||
"merkle path for index 0 must be the same for the MerkleTree and MerkleStore"
|
"merkle path for index 0 must be the same for the MerkleTree and MerkleStore"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -254,12 +254,12 @@ fn test_sparse_merkle_tree() -> Result<(), MerkleError> {
|
||||||
.get_path(smt.root(), NodeIndex::new(smt.depth(), 1))
|
.get_path(smt.root(), NodeIndex::new(smt.depth(), 1))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
LEAVES4[1], result.0,
|
LEAVES4[1], result.value,
|
||||||
"Value for merkle path at index 0 must match leaf value"
|
"Value for merkle path at index 0 must match leaf value"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
smt.get_path(NodeIndex::new(smt.depth(), 1)),
|
smt.get_path(NodeIndex::new(smt.depth(), 1)),
|
||||||
Ok(result.1),
|
Ok(result.path),
|
||||||
"merkle path for index 1 must be the same for the MerkleTree and MerkleStore"
|
"merkle path for index 1 must be the same for the MerkleTree and MerkleStore"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -267,12 +267,12 @@ fn test_sparse_merkle_tree() -> Result<(), MerkleError> {
|
||||||
.get_path(smt.root(), NodeIndex::new(smt.depth(), 2))
|
.get_path(smt.root(), NodeIndex::new(smt.depth(), 2))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
LEAVES4[2], result.0,
|
LEAVES4[2], result.value,
|
||||||
"Value for merkle path at index 0 must match leaf value"
|
"Value for merkle path at index 0 must match leaf value"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
smt.get_path(NodeIndex::new(smt.depth(), 2)),
|
smt.get_path(NodeIndex::new(smt.depth(), 2)),
|
||||||
Ok(result.1),
|
Ok(result.path),
|
||||||
"merkle path for index 0 must be the same for the MerkleTree and MerkleStore"
|
"merkle path for index 0 must be the same for the MerkleTree and MerkleStore"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -280,12 +280,12 @@ fn test_sparse_merkle_tree() -> Result<(), MerkleError> {
|
||||||
.get_path(smt.root(), NodeIndex::new(smt.depth(), 3))
|
.get_path(smt.root(), NodeIndex::new(smt.depth(), 3))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
LEAVES4[3], result.0,
|
LEAVES4[3], result.value,
|
||||||
"Value for merkle path at index 0 must match leaf value"
|
"Value for merkle path at index 0 must match leaf value"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
smt.get_path(NodeIndex::new(smt.depth(), 3)),
|
smt.get_path(NodeIndex::new(smt.depth(), 3)),
|
||||||
Ok(result.1),
|
Ok(result.path),
|
||||||
"merkle path for index 0 must be the same for the MerkleTree and MerkleStore"
|
"merkle path for index 0 must be the same for the MerkleTree and MerkleStore"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -375,12 +375,12 @@ fn test_add_merkle_paths() -> Result<(), MerkleError> {
|
||||||
.get_path(set.root(), NodeIndex::new(set.depth() - 1, 0))
|
.get_path(set.root(), NodeIndex::new(set.depth() - 1, 0))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
LEAVES4[0], result.0,
|
LEAVES4[0], result.value,
|
||||||
"Value for merkle path at index 0 must match leaf value"
|
"Value for merkle path at index 0 must match leaf value"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
set.get_path(NodeIndex::new(set.depth(), 0)),
|
set.get_path(NodeIndex::new(set.depth(), 0)),
|
||||||
Ok(result.1),
|
Ok(result.path),
|
||||||
"merkle path for index 0 must be the same for the MerkleTree and MerkleStore"
|
"merkle path for index 0 must be the same for the MerkleTree and MerkleStore"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -388,12 +388,12 @@ fn test_add_merkle_paths() -> Result<(), MerkleError> {
|
||||||
.get_path(set.root(), NodeIndex::new(set.depth() - 1, 1))
|
.get_path(set.root(), NodeIndex::new(set.depth() - 1, 1))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
LEAVES4[1], result.0,
|
LEAVES4[1], result.value,
|
||||||
"Value for merkle path at index 0 must match leaf value"
|
"Value for merkle path at index 0 must match leaf value"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
set.get_path(NodeIndex::new(set.depth(), 1)),
|
set.get_path(NodeIndex::new(set.depth(), 1)),
|
||||||
Ok(result.1),
|
Ok(result.path),
|
||||||
"merkle path for index 1 must be the same for the MerkleTree and MerkleStore"
|
"merkle path for index 1 must be the same for the MerkleTree and MerkleStore"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -401,12 +401,12 @@ fn test_add_merkle_paths() -> Result<(), MerkleError> {
|
||||||
.get_path(set.root(), NodeIndex::new(set.depth() - 1, 2))
|
.get_path(set.root(), NodeIndex::new(set.depth() - 1, 2))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
LEAVES4[2], result.0,
|
LEAVES4[2], result.value,
|
||||||
"Value for merkle path at index 0 must match leaf value"
|
"Value for merkle path at index 0 must match leaf value"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
set.get_path(NodeIndex::new(set.depth(), 2)),
|
set.get_path(NodeIndex::new(set.depth(), 2)),
|
||||||
Ok(result.1),
|
Ok(result.path),
|
||||||
"merkle path for index 0 must be the same for the MerkleTree and MerkleStore"
|
"merkle path for index 0 must be the same for the MerkleTree and MerkleStore"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -414,12 +414,12 @@ fn test_add_merkle_paths() -> Result<(), MerkleError> {
|
||||||
.get_path(set.root(), NodeIndex::new(set.depth() - 1, 3))
|
.get_path(set.root(), NodeIndex::new(set.depth() - 1, 3))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
LEAVES4[3], result.0,
|
LEAVES4[3], result.value,
|
||||||
"Value for merkle path at index 0 must match leaf value"
|
"Value for merkle path at index 0 must match leaf value"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
set.get_path(NodeIndex::new(set.depth(), 3)),
|
set.get_path(NodeIndex::new(set.depth(), 3)),
|
||||||
Ok(result.1),
|
Ok(result.path),
|
||||||
"merkle path for index 0 must be the same for the MerkleTree and MerkleStore"
|
"merkle path for index 0 must be the same for the MerkleTree and MerkleStore"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -474,10 +474,13 @@ fn store_path_opens_from_leaf() {
|
||||||
let store = MerkleStore::default()
|
let store = MerkleStore::default()
|
||||||
.with_merkle_tree([a, b, c, d, e, f, g, h])
|
.with_merkle_tree([a, b, c, d, e, f, g, h])
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let path = store.get_path(root.into(), NodeIndex::new(3, 1)).unwrap();
|
let path = store
|
||||||
|
.get_path(root.into(), NodeIndex::new(3, 1))
|
||||||
|
.unwrap()
|
||||||
|
.path;
|
||||||
|
|
||||||
let expected = MerklePath::new([a.into(), j.into(), n.into()].to_vec());
|
let expected = MerklePath::new([a.into(), j.into(), n.into()].to_vec());
|
||||||
assert_eq!(path.1, expected);
|
assert_eq!(path, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -486,7 +489,7 @@ fn test_set_node() -> Result<(), MerkleError> {
|
||||||
let mut store = MerkleStore::default().with_merkle_tree(LEAVES4)?;
|
let mut store = MerkleStore::default().with_merkle_tree(LEAVES4)?;
|
||||||
let value = int_to_node(42);
|
let value = int_to_node(42);
|
||||||
let index = NodeIndex::new(mtree.depth(), 0);
|
let index = NodeIndex::new(mtree.depth(), 0);
|
||||||
let new_root = store.set_node(mtree.root(), index, value)?;
|
let new_root = store.set_node(mtree.root(), index, value)?.root;
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
store.get_node(new_root, index),
|
store.get_node(new_root, index),
|
||||||
Ok(value),
|
Ok(value),
|
||||||
|
|
Loading…
Add table
Reference in a new issue