Browse Source

Merge pull request #99 from 0xPolygonMiden/vlopes11-merkle-store-containers

feat: add merkle path containers and return them on tree update
al-gkr-basic-workflow
Victor Lopes 2 years ago
committed by GitHub
parent
commit
7305a72295
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 80 additions and 45 deletions
  1. +1
    -1
      src/merkle/mod.rs
  2. +24
    -0
      src/merkle/path.rs
  3. +25
    -17
      src/merkle/store/mod.rs
  4. +30
    -27
      src/merkle/store/tests.rs

+ 1
- 1
src/merkle/mod.rs

@ -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;

+ 24
- 0
src/merkle/path.rs

@ -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,
}

+ 25
- 17
src/merkle/store/mod.rs

@ -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(
&self,
root: Word,
index: NodeIndex,
) -> Result<(Word, MerklePath), MerkleError> {
pub fn get_path(&self, root: Word, index: NodeIndex) -> Result<ValuePath, 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> {
let result = self.get_path(root, index)?;
if result.0 != value {
self.add_merkle_path(index.value(), value, result.1)
} else {
Ok(root)
) -> Result<RootPath, MerkleError> {
let node = value;
let ValuePath { value, path } = self.get_path(root, index)?;
// performs the update only if the node value differs from the opening
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> {

+ 30
- 27
src/merkle/store/tests.rs

@ -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…
Cancel
Save