feat: bring documentation to accordance with guidelines (#6)

This commit is contained in:
Anton Suprunchuk
2021-10-18 13:03:33 +03:00
committed by GitHub
parent cbda7a0827
commit 93f93a979c
13 changed files with 1067 additions and 327 deletions

View File

@@ -2,7 +2,7 @@
name = "rs_merkle"
version = "0.2.2"
authors = ["Anton Suprunchuk <anton.suprunchuk@gmail.com>"]
description = "The most advanced Merkle Tree librray for Rust"
description = "The most advanced Merkle Tree library for Rust. Supports creating and verifying proofs, multi-proofs, as well as advanced features, such as tree diffs, transactional changes, and rollbacks"
edition = "2018"
license = "Apache-2.0/MIT"
repository = "https://github.com/antouhou/rs-merkle"

View File

@@ -10,6 +10,9 @@ single and several elements, i.e. multi-proofs. Advanced features include making
transactional changes to the tree and rolling back to any previously committed
tree state, similarly to Git.
The library is highly customizable. Hashing function and the way how the tree
is built can be easily configured through a special trait.
`rs-merkle` is
[available on crates.io](https://crates.io/crates/rs_merkle), and
[API Documentation is available on docs.rs](https://docs.rs/rs_merkle/).

View File

@@ -1,4 +1,6 @@
//! This module contains built-in implementations of `rs_merkle::Hasher`
//! This module contains built-in implementations of the [`Hasher`]
//!
//! [`Hasher`]: crate::Hasher
mod sha256;
pub use sha256::Sha256Algorithm as Sha256;

View File

@@ -1,7 +1,33 @@
use crate::Hasher;
use sha2::{digest::FixedOutput, Digest, Sha256};
/// Sha256 implementation of the `rs_merkle::Hasher` trait
/// Sha256 implementation of the [`Hasher`] trait.
///
/// # Examples
///
/// ```
/// # use rs_merkle::{MerkleTree, MerkleProof, algorithms::Sha256, Hasher, Error, utils};
/// # use std::convert::TryFrom;
/// #
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let tree = MerkleTree::<Sha256>::new();
/// let other_tree: MerkleTree<Sha256> = MerkleTree::new();
///
/// let proof_bytes: Vec<u8> = vec![
/// 46, 125, 44, 3, 169, 80, 122, 226, 101, 236, 245, 181, 53, 104, 133, 165, 51, 147, 162,
/// 2, 157, 36, 19, 148, 153, 114, 101, 161, 162, 90, 239, 198, 37, 47, 16, 200, 54, 16,
/// 235, 202, 26, 5, 156, 11, 174, 130, 85, 235, 162, 249, 91, 228, 209, 215, 188, 250,
/// 137, 215, 36, 138, 130, 217, 241, 17, 229, 160, 31, 238, 20, 224, 237, 92, 72, 113, 79,
/// 34, 24, 15, 37, 173, 131, 101, 181, 63, 151, 121, 247, 157, 196, 163, 215, 233, 57, 99,
/// 249, 74,
/// ];
///
/// let proof_result = MerkleProof::<Sha256>::from_bytes(&proof_bytes);
/// # Ok(())
/// # }
/// ```
///
/// [`Hasher`]: crate::Hasher
#[derive(Clone)]
pub struct Sha256Algorithm {}

View File

@@ -1,13 +1,33 @@
use std::fmt::{Debug, Display, Formatter};
#[derive(Copy, Clone, Debug)]
/// A list specifying general categories of tree traversals/parsing errors.
///
/// This list is intended to grow over time and it is not recommended to
/// exhaustively match against it.
///
/// It is used with the [`Error`] type.
///
/// [`Error`]: crate::Error
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[non_exhaustive]
pub enum ErrorKind {
/// Serialized to bytes merkle proof can't be parsed because it can not be divided
SerializedProofSizeIsIncorrect,
/// Not enough helper nodes to calculate the root was passed to the [`PartialTree`].
///
/// [`PartialTree`]: crate::PartialTree
NotEnoughHelperNodes,
HashConversionError,
NotEnoughHashesToCalculateRoot,
LeavesIndicesCountMismatch,
}
/// The error type for tree traversals/parsing errors of the [`MerkleProof`] and [`PartialTree`].
///
/// Errors mostly originate from the data being insufficient to traverse the partial tree
///
/// [`MerkleProof`]: crate::MerkleProof
/// [`PartialTree`]: crate::PartialTree
#[derive(Clone, Debug)]
pub struct Error {
kind: ErrorKind,
@@ -50,6 +70,16 @@ impl Error {
)
}
pub fn leaves_indices_count_mismatch(indices_len: usize, leaves_len: usize) -> Self {
Self::new(
ErrorKind::LeavesIndicesCountMismatch,
format!(
"leaves indices count doesn't match leaves count: {} and {}",
indices_len, leaves_len
),
)
}
pub fn kind(&self) -> ErrorKind {
self.kind
}

View File

@@ -5,7 +5,7 @@ use std::mem;
///
/// # Example
///
/// This example shows how to implement sha256 algorithm
/// This example shows how to implement the sha256 algorithm
///
/// ```
/// use rs_merkle::{Hasher};
@@ -27,9 +27,9 @@ use std::mem;
/// ```
pub trait Hasher: Clone {
/// This type is used as a hash type in the library.
/// It is recommended to use fixed size u8 array as hash. For example,
/// It is recommended to use fixed size u8 array as a hash type. For example,
/// for sha256 the type would be `[u8; 32]`, representing 32 bytes,
/// which is the size of sha256 digest. Also, fixed sized arrays of `u8`
/// which is the size of the sha256 digest. Also, fixed sized arrays of `u8`
/// by default satisfy all trait bounds required by this type.
///
/// # Trait bounds
@@ -40,18 +40,21 @@ pub trait Hasher: Clone {
/// `TryFrom<Vec<u8>>` is required to parse hashes from a serialized proof
type Hash: Copy + PartialEq + Into<Vec<u8>> + TryFrom<Vec<u8>>;
/// This associated function takes arbitrary bytes and returns hash of it.
/// This associated function takes a slice of bytes and returns a hash of it.
/// Used by `concat_and_hash` function to build a tree from concatenated hashes
fn hash(data: &[u8]) -> Self::Hash;
/// Used by `MerkleTree` and `MerkleProof` when calculating the root.
/// The provided default implementation follows propagates left node if it doesn't
/// have a sibling. Left node should always be present. Right node is optional.
/// Used by [`MerkleTree`] and [`PartialTree`] when calculating the root.
/// The provided default implementation propagates the left node if it doesn't
/// have a sibling. The left node should always be present. The right node is optional.
///
/// For the tree to be compatible with different types of proofs this function
/// needs to be overridden. For example, in Bitcoin implementation,
/// if the left node doesn't have a sibling it is concatenated to itself and
/// then hashed instead of just being propagated to the next level.
///
/// [`MerkleTree`]: crate::MerkleTree
/// [`PartialTree`]: crate::PartialTree
fn concat_and_hash(left: &Self::Hash, right: Option<&Self::Hash>) -> Self::Hash {
let mut concatenated: Vec<u8> = (*left).into();

View File

@@ -1,21 +1,145 @@
//! Merkle Trees, also known as Hash Trees, are used to verify that two or more parties have
//! the same data without exchanging the entire data collection.
//! `rs-merkle` is the most advanced Merkle tree library for Rust. Basic features
//! include building a Merkle tree, creation, and verification of Merkle proofs for
//! single and multiple elements, i.e. multi-proofs. Advanced features include making
//! transactional changes to the tree and rolling back to any previously committed
//! tree state, similarly to Git.
//!
//! Merkle Trees are used in Git, Mercurial,ZFS, IPFS, Bitcoin, Ethereum, Cassandra and many more.
//! In Git, for example, Merkle Trees are used to find a delta between the local and remote states,
//! and transfer only the delta. In Bitcoin, Merkle Trees are used to verify that a transaction was
//! included into the block without downloading the whole block contents.
//! The library has two main structs. The first one is [`MerkleTree`],
//! which builds the tree that can be used to verify data integrity and produce a Merkle proof. The
//! second is [`MerkleProof`], which can be used to verify the inclusion of an item in a set.
//!
//! The library is highly customizable. Hashing algorithm and the way how the tree is built
//! can be configured through the [`Hasher`] trait.
//!
//! ## About Merkle trees
//!
//! Merkle trees, also known as hash trees, are used to verify that two or more
//! parties have the same data without exchanging the entire data collection.
//!
//! Merkle trees are used in Git, Mercurial, ZFS, IPFS, Bitcoin, Ethereum, Cassandra,
//! and many more. In Git, for example, Merkle trees are used to find a delta
//! between the local and remote repository states to transfer only the difference
//! between them over the network. In Bitcoin, Merkle trees are used to verify that
//! a transaction was included in the block without downloading the whole block
//! contents. ZFS uses Merkle trees to quickly verify data integrity, offering
//! protection from silent data corruption caused by phantom writes, bugs in disk
//! firmware, power surges, and other causes.
//!
//! ## Examples
//!
//! Basic usage for verifying Merkle proofs:
//!
//! ```
//! # use rs_merkle::{MerkleTree, MerkleProof, algorithms::Sha256, Hasher, Error, utils};
//! # use std::convert::TryFrom;
//! #
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! let leaf_values = ["a", "b", "c", "d", "e", "f"];
//! let leaves: Vec<[u8; 32]> = leaf_values
//! .iter()
//! .map(|x| Sha256::hash(x.as_bytes()))
//! .collect();
//!
//! let merkle_tree = MerkleTree::<Sha256>::from_leaves(&leaves);
//! let indices_to_prove = vec![3, 4];
//! let leaves_to_prove = leaves.get(3..5).ok_or("can't get leaves to prove")?;
//! let merkle_proof = merkle_tree.proof(&indices_to_prove);
//! let merkle_root = merkle_tree.root().ok_or("couldn't get the merkle root")?;
//! // Serialize proof to pass it to the client
//! let proof_bytes = merkle_proof.to_bytes();
//!
//! // Parse proof back on the client
//! let proof = MerkleProof::<Sha256>::try_from(proof_bytes)?;
//!
//! assert!(proof.verify(merkle_root, &indices_to_prove, leaves_to_prove, leaves.len()));
//! # Ok(())
//! # }
//! ```
//!
//! Advanced usage with rolling several commits back:
//!
//! ```
//! # use rs_merkle::{MerkleTree, algorithms::Sha256, Hasher, Error};
//! #
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! let elements = ["a", "b", "c", "d", "e", "f"];
//! let mut leaves: Vec<[u8; 32]> = elements
//! .iter()
//! .map(|x| Sha256::hash(x.as_bytes()))
//! .collect();
//!
//! let mut merkle_tree: MerkleTree<Sha256> = MerkleTree::new();
//!
//! // Appending leaves to the tree without committing
//! merkle_tree.append(&mut leaves);
//!
//! // Without committing changes we can get the root for the uncommitted data, but committed
//! // tree still doesn't have any elements
//! assert_eq!(merkle_tree.root(), None);
//! assert_eq!(
//! merkle_tree.uncommitted_root_hex(),
//! Some("1f7379539707bcaea00564168d1d4d626b09b73f8a2a365234c62d763f854da2".to_string())
//! );
//!
//! // Committing the changes
//! merkle_tree.commit();
//!
//! // Changes applied to the tree after the commit, and there's no uncommitted changes anymore
//! assert_eq!(
//! merkle_tree.root_hex(),
//! Some("1f7379539707bcaea00564168d1d4d626b09b73f8a2a365234c62d763f854da2".to_string())
//! );
//! assert_eq!(merkle_tree.uncommitted_root_hex(), None);
//!
//! // Adding a new leaf
//! merkle_tree.insert(Sha256::hash("g".as_bytes())).commit();
//!
//! // Root was updated after insertion
//! assert_eq!(
//! merkle_tree.root_hex(),
//! Some("e2a80e0e872a6c6eaed37b4c1f220e1935004805585b5f99617e48e9c8fe4034".to_string())
//! );
//!
//! // Adding some more leaves
//! merkle_tree.append(vec![
//! Sha256::hash("h".as_bytes()),
//! Sha256::hash("k".as_bytes()),
//! ].as_mut()).commit();
//! assert_eq!(
//! merkle_tree.root_hex(),
//! Some("09b6890b23e32e607f0e5f670ab224e36af8f6599cbe88b468f4b0f761802dd6".to_string())
//! );
//!
//! // Rolling back to the previous state
//! merkle_tree.rollback();
//! assert_eq!(
//! merkle_tree.root_hex(),
//! Some("e2a80e0e872a6c6eaed37b4c1f220e1935004805585b5f99617e48e9c8fe4034".to_string())
//! );
//!
//! // We can rollback multiple times as well
//! merkle_tree.rollback();
//! assert_eq!(
//! merkle_tree.root_hex(),
//! Some("1f7379539707bcaea00564168d1d4d626b09b73f8a2a365234c62d763f854da2".to_string())
//! );
//! # Ok(())
//! # }
//! ```
pub use error::Error;
pub use error::ErrorKind;
pub use hasher::Hasher;
pub use merkle_proof::MerkleProof;
pub use merkle_tree::MerkleTree;
pub use partial_tree::PartialTree;
mod error;
mod hasher;
mod merkle_proof;
mod merkle_tree;
mod partial_tree;
#[doc(hidden)]
pub mod utils;
pub mod algorithms;
pub mod error;
mod utils;

View File

@@ -4,24 +4,45 @@ use crate::error::Error;
use crate::partial_tree::PartialTree;
use crate::{utils, Hasher};
/// `MerkleProof` is used to parse, verify, calculate a root for merkle proofs.
/// [`MerkleProof`] is used to parse, verify, calculate a root for Merkle proofs.
///
/// # Usage
/// ## Usage
///
/// MerkleProof requires specifying hashing algorithm and hash size in order to work.
/// Check out the `Hasher` trait for examples. rs_merkle provides some built in `Hasher`
/// implementations, for example `rs_merkle::algorithms::Sha256`
/// The hashing algorithm is set through the [`Hasher`] trait, which is supplied as a generic
/// parameter to the [`MerkleProof`]. `rs_merkle` provides some built-in [`Hasher`] implementations,
/// for example, [`algorithms::Sha256`]
///
/// # Example
/// ## Examples
///
/// ```
/// use rs_merkle::{MerkleProof, algorithms::Sha256};
/// # use rs_merkle::{MerkleTree, MerkleProof, algorithms::Sha256, Hasher, Error, utils};
/// # use std::convert::TryFrom;
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let proof_hashes: Vec<[u8; 32]> = vec![
///
/// [
/// 46, 125, 44, 3, 169, 80, 122, 226, 101, 236, 245, 181, 53, 104, 133, 165, 51, 147,
/// 162, 2, 157, 36, 19, 148, 153, 114, 101, 161, 162, 90, 239, 198
/// ],
/// [
/// 37, 47, 16, 200, 54, 16, 235, 202, 26, 5, 156, 11, 174, 130, 85, 235, 162, 249, 91,
/// 228, 209, 215, 188, 250, 137, 215, 36, 138, 130, 217, 241, 17
/// ],
/// [
/// 229, 160, 31, 238, 20, 224, 237, 92, 72, 113, 79, 34, 24, 15, 37, 173, 131, 101,
/// 181, 63, 151, 121, 247, 157, 196, 163, 215, 233, 57, 99, 249, 74
/// ],
/// ];
/// let proof_hashes_copy = proof_hashes.clone();
///
/// let proof = MerkleProof::<Sha256>::new(proof_hashes);
///```
/// let proof = MerkleProof::<Sha256>::new(proof_hashes_copy);
/// assert_eq!(proof.proof_hashes(), &proof_hashes);
/// # Ok(())
/// # }
/// ```
///
/// [`Hasher`]: crate::Hasher
/// [`algorithms::Sha256`]: crate::algorithms::Sha256
pub struct MerkleProof<T: Hasher> {
proof_hashes: Vec<T::Hash>,
}
@@ -31,35 +52,117 @@ impl<T: Hasher> MerkleProof<T> {
MerkleProof { proof_hashes }
}
/// Creates a proof from a slice of bytes. For more details and examples, please see
/// [`try_from`](MerkleProof::try_from)
/// Creates a proof from a slice of bytes
///
/// ## Examples
///
/// ```
/// # use std::convert::TryFrom;
/// # use rs_merkle::{MerkleProof, algorithms::Sha256};
///
/// let proof_bytes: Vec<u8> = vec![
/// 46, 125, 44, 3, 169, 80, 122, 226, 101, 236, 245, 181, 53, 104, 133, 165, 51, 147, 162,
/// 2, 157, 36, 19, 148, 153, 114, 101, 161, 162, 90, 239, 198, 37, 47, 16, 200, 54, 16,
/// 235, 202, 26, 5, 156, 11, 174, 130, 85, 235, 162, 249, 91, 228, 209, 215, 188, 250,
/// 137, 215, 36, 138, 130, 217, 241, 17, 229, 160, 31, 238, 20, 224, 237, 92, 72, 113, 79,
/// 34, 24, 15, 37, 173, 131, 101, 181, 63, 151, 121, 247, 157, 196, 163, 215, 233, 57, 99,
/// 249, 74,
/// ];
///
/// let proof_result = MerkleProof::<Sha256>::from_bytes(proof_bytes.as_slice());
/// ```
///
/// ## Errors
///
/// In case of a parsing error result will contain [`Error`]
///
/// ['Error`]: crate::Error
pub fn from_bytes(bytes: &[u8]) -> Result<Self, Error> {
Self::try_from(bytes)
}
/// Returns all hashes from the proof, sorted from the left to right,
/// bottom to top.
pub fn proof_hashes(&self) -> &[T::Hash] {
&self.proof_hashes
/// Uses proof to verify that a given set of elements is contained in the original data
/// set the proof was made for.
///
/// ## Examples
///
/// ```
/// # use rs_merkle::{MerkleTree, MerkleProof, algorithms::Sha256, Hasher, Error, utils};
/// # use std::convert::TryFrom;
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let leaves = [
/// Sha256::hash("a".as_bytes()),
/// Sha256::hash("b".as_bytes()),
/// Sha256::hash("c".as_bytes()),
/// ];
///
/// let merkle_tree = MerkleTree::<Sha256>::from_leaves(&leaves);
///
/// let indices_to_prove = vec![0, 1];
/// let leaves_to_prove = leaves.get(0..2).ok_or("can't get leaves to prove")?;
///
/// let proof = merkle_tree.proof(&indices_to_prove);
/// let root = merkle_tree.root().ok_or("couldn't get the merkle root")?;
///
/// assert!(proof.verify(root, &indices_to_prove, leaves_to_prove, leaves.len()));
/// # Ok(())
/// # }
/// ```
pub fn verify(
&self,
root: T::Hash,
leaf_indices: &[usize],
leaf_hashes: &[T::Hash],
total_leaves_count: usize,
) -> bool {
match self.root(leaf_indices, leaf_hashes, total_leaves_count) {
Ok(extracted_root) => extracted_root == root,
Err(_) => false,
}
}
/// Returns all hashes from the proof, sorted from the left to right,
/// bottom to top, as a vector of lower hex strings.
/// For a slice of `&[T::Hash]`, see [`proof_hashes`](MerkleProof::proof_hashes)
pub fn proof_hashes_hex(&self) -> Vec<String> {
self.proof_hashes
.iter()
.map(utils::collections::to_hex_string)
.collect()
}
/// Calculates merkle root based on provided leaves and proof hashes
/// Calculates Merkle root based on provided leaves and proof hashes. Used inside the
/// [`MerkleProof::verify`] method, but sometimes can be used on its own.
///
/// ## Examples
///
/// ```
/// # use rs_merkle::{MerkleTree, MerkleProof, algorithms::Sha256, Hasher, Error, utils};
/// # use std::convert::TryFrom;
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let leaves = [
/// Sha256::hash("a".as_bytes()),
/// Sha256::hash("b".as_bytes()),
/// Sha256::hash("c".as_bytes()),
/// ];
///
/// let merkle_tree = MerkleTree::<Sha256>::from_leaves(&leaves);
///
/// let indices_to_prove = vec![0, 1];
/// let leaves_to_prove = leaves.get(0..2).ok_or("can't get leaves to prove")?;
///
/// let proof = merkle_tree.proof(&indices_to_prove);
/// let root = merkle_tree.root().ok_or("couldn't get the merkle root")?;
///
/// assert_eq!(
/// proof.root(&indices_to_prove, leaves_to_prove, leaves.len())?,
/// root
/// );
/// # Ok(())
/// # }
/// ```
pub fn root(
&self,
leaf_indices: &[usize],
leaf_hashes: &[T::Hash],
total_leaves_count: usize,
) -> Result<T::Hash, Error> {
if leaf_indices.len() != leaf_hashes.len() {
return Err(Error::leaves_indices_count_mismatch(
leaf_indices.len(),
leaf_hashes.len(),
));
}
let tree_depth = utils::indices::tree_depth(total_leaves_count);
// Zipping indices and hashes into a vector of (original_index_in_tree, leaf_hash)
@@ -98,7 +201,35 @@ impl<T: Hasher> MerkleProof<T> {
}
}
/// Calculates the root and serializes it into a hex string
/// Calculates the root and serializes it into a hex string.
///
/// ## Examples
///
/// ```
/// # use rs_merkle::{MerkleTree, MerkleProof, algorithms::Sha256, Hasher, Error, utils};
/// # use std::convert::TryFrom;
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let leaves = [
/// Sha256::hash("a".as_bytes()),
/// Sha256::hash("b".as_bytes()),
/// Sha256::hash("c".as_bytes()),
/// ];
///
/// let merkle_tree = MerkleTree::<Sha256>::from_leaves(&leaves);
///
/// let indices_to_prove = vec![0, 1];
/// let leaves_to_prove = leaves.get(0..2).ok_or("can't get leaves to prove")?;
///
/// let proof = merkle_tree.proof(&indices_to_prove);
/// let root_hex = merkle_tree.root_hex().ok_or("couldn't get the merkle root")?;
///
/// assert_eq!(
/// proof.root_hex(&indices_to_prove, leaves_to_prove, leaves.len())?,
/// root_hex
/// );
/// # Ok(())
/// # }
/// ```
pub fn root_hex(
&self,
leaf_indices: &[usize],
@@ -109,29 +240,129 @@ impl<T: Hasher> MerkleProof<T> {
Ok(utils::collections::to_hex_string(&root))
}
/// Verifies the proof for a given set of leaves
pub fn verify(
&self,
root: T::Hash,
leaf_indices: &[usize],
leaf_hashes: &[T::Hash],
total_leaves_count: usize,
) -> bool {
match self.root(leaf_indices, leaf_hashes, total_leaves_count) {
Ok(extracted_root) => extracted_root == root,
Err(_) => false,
}
/// Returns all hashes from the proof, sorted from the left to right,
/// bottom to top.
///
/// ## Examples
///
/// ```
/// # use rs_merkle::{MerkleTree, MerkleProof, algorithms::Sha256, Hasher, Error, utils};
/// # use std::convert::TryFrom;
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let proof_hashes: Vec<[u8; 32]> = vec![
/// [
/// 46, 125, 44, 3, 169, 80, 122, 226, 101, 236, 245, 181, 53, 104, 133, 165, 51, 147,
/// 162, 2, 157, 36, 19, 148, 153, 114, 101, 161, 162, 90, 239, 198
/// ],
/// [
/// 37, 47, 16, 200, 54, 16, 235, 202, 26, 5, 156, 11, 174, 130, 85, 235, 162, 249, 91,
/// 228, 209, 215, 188, 250, 137, 215, 36, 138, 130, 217, 241, 17
/// ],
/// [
/// 229, 160, 31, 238, 20, 224, 237, 92, 72, 113, 79, 34, 24, 15, 37, 173, 131, 101,
/// 181, 63, 151, 121, 247, 157, 196, 163, 215, 233, 57, 99, 249, 74
/// ],
/// ];
/// let proof_hashes_copy = proof_hashes.clone();
///
/// let proof = MerkleProof::<Sha256>::new(proof_hashes_copy);
/// assert_eq!(proof.proof_hashes(), &proof_hashes);
/// # Ok(())
/// # }
/// ```
pub fn proof_hashes(&self) -> &[T::Hash] {
&self.proof_hashes
}
/// Serializes proof hashes to a flat vector of bytes
/// Returns all hashes from the proof, sorted from the left to right,
/// bottom to top, as a vector of lower hex strings.
/// For a slice of [`Hasher::Hash`], see [`MerkleProof::proof_hashes`]
///
/// ## Examples
///
/// ```
/// # use rs_merkle::{MerkleTree, MerkleProof, algorithms::Sha256, Hasher, Error, utils};
/// # use std::convert::TryFrom;
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let proof_bytes: Vec<u8> = vec![
/// 46, 125, 44, 3, 169, 80, 122, 226, 101, 236, 245, 181, 53, 104, 133, 165, 51, 147, 162,
/// 2, 157, 36, 19, 148, 153, 114, 101, 161, 162, 90, 239, 198, 37, 47, 16, 200, 54, 16,
/// 235, 202, 26, 5, 156, 11, 174, 130, 85, 235, 162, 249, 91, 228, 209, 215, 188, 250,
/// 137, 215, 36, 138, 130, 217, 241, 17, 229, 160, 31, 238, 20, 224, 237, 92, 72, 113, 79,
/// 34, 24, 15, 37, 173, 131, 101, 181, 63, 151, 121, 247, 157, 196, 163, 215, 233, 57, 99,
/// 249, 74,
/// ];
///
/// let proof = MerkleProof::<Sha256>::from_bytes(proof_bytes.as_slice())?;
/// assert_eq!(
/// proof.proof_hashes_hex(),
/// vec![
/// "2e7d2c03a9507ae265ecf5b5356885a53393a2029d241394997265a1a25aefc6".to_string(),
/// "252f10c83610ebca1a059c0bae8255eba2f95be4d1d7bcfa89d7248a82d9f111".to_string(),
/// "e5a01fee14e0ed5c48714f22180f25ad8365b53f9779f79dc4a3d7e93963f94a".to_string()
/// ]
/// );
/// # Ok(())
/// # }
/// ```
pub fn proof_hashes_hex(&self) -> Vec<String> {
self.proof_hashes
.iter()
.map(utils::collections::to_hex_string)
.collect()
}
/// Serializes proof hashes to a flat vector of bytes, from left to right, bottom to top.
/// Usually used to pass the proof to the client after extracting it from the tree.
///
/// ## Important
///
/// Please note that some applications may serialize proof differently, for example in reverse
/// order - from top to bottom, right to left. In that case, you'll need to do some
/// manipulations on the proof data manually. Raw proof hashes are available through
/// [`MerkleProof::proof_hashes`]
///
/// ## Examples
///
/// ```
/// # use rs_merkle::{MerkleTree, MerkleProof, algorithms::Sha256, Hasher, Error, utils};
/// # use std::convert::TryFrom;
/// #
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let leaf_values = ["a", "b", "c", "d", "e", "f"];
/// let leaves: Vec<[u8; 32]> = leaf_values
/// .iter()
/// .map(|x| Sha256::hash(x.as_bytes()))
/// .collect();
///
/// let merkle_tree = MerkleTree::<Sha256>::from_leaves(&leaves);
/// let indices_to_prove = vec![3, 4];
/// let leaves_to_prove = leaves.get(3..5).ok_or("can't get leaves to prove")?;
/// let merkle_proof = merkle_tree.proof(&indices_to_prove);
/// let merkle_root = merkle_tree.root().ok_or("couldn't get the merkle root")?;
///
/// // Serialize proof to pass it to the client over the network
/// let proof_bytes = merkle_proof.to_bytes();
///
/// assert_eq!(proof_bytes, vec![
/// 46, 125, 44, 3, 169, 80, 122, 226, 101, 236, 245, 181, 53, 104, 133, 165, 51, 147, 162,
/// 2, 157, 36, 19, 148, 153, 114, 101, 161, 162, 90, 239, 198, 37, 47, 16, 200, 54, 16,
/// 235, 202, 26, 5, 156, 11, 174, 130, 85, 235, 162, 249, 91, 228, 209, 215, 188, 250,
/// 137, 215, 36, 138, 130, 217, 241, 17, 229, 160, 31, 238, 20, 224, 237, 92, 72, 113, 79,
/// 34, 24, 15, 37, 173, 131, 101, 181, 63, 151, 121, 247, 157, 196, 163, 215, 233, 57, 99,
/// 249, 74,
/// ]);
/// # Ok(())
/// # }
/// ```
pub fn to_bytes(&self) -> Vec<u8> {
let vectors: Vec<Vec<u8>> = self
let mut vectors: Vec<Vec<u8>> = self
.proof_hashes()
.iter()
.cloned()
.map(|hash| hash.into())
.collect();
vectors.iter().cloned().flatten().collect()
vectors.drain(..).flatten().collect()
}
}
@@ -140,7 +371,8 @@ impl<T: Hasher> TryFrom<Vec<u8>> for MerkleProof<T> {
/// Parses proof serialized to a collection of bytes. Consumes passed vector.
///
/// # Example
/// # Examples
///
/// ```
/// use std::convert::TryFrom;
/// use rs_merkle::{MerkleProof, algorithms::Sha256};
@@ -166,7 +398,8 @@ impl<T: Hasher> TryFrom<&[u8]> for MerkleProof<T> {
/// Parses proof serialized to a collection of bytes
///
/// # Example
/// ## Examples
///
/// ```
/// use std::convert::TryFrom;
/// use rs_merkle::{MerkleProof, algorithms::Sha256};

View File

@@ -4,93 +4,12 @@ use crate::{utils, Hasher, MerkleProof};
/// [`MerkleTree`] is a Merkle Tree that is well suited for both basic and advanced usage.
///
/// Basic features include creation and verification of merkle proofs from a set of leaves.
/// Basic features include the creation and verification of Merkle proofs from a set of leaves.
/// This is often done in various cryptocurrencies.
///
/// Advanced features include being able to make transactional changes to a tree with
/// being able to roll back to any previous committed state of tree. This scenario is similar
/// to Git and can be found in databases and file systems.
///
/// # Examples
///
/// ## Basic usage for cryptocurrency proofs:
///
/// ```
/// use rs_merkle::{MerkleTree, algorithms::Sha256, Hasher};
///
/// let leaf_values = ["a", "b", "c", "d", "e", "f"];
/// let expected_root_hex = "1f7379539707bcaea00564168d1d4d626b09b73f8a2a365234c62d763f854da2";
/// let leaves: Vec<[u8; 32]> = leaf_values
/// .iter()
/// .map(|x| Sha256::hash(x.as_bytes().to_vec().as_ref()))
/// .collect();
///
/// let merkle_tree = MerkleTree::<Sha256>::from_leaves(&leaves);
/// let hex_root = merkle_tree.root_hex().unwrap();
///
/// assert_eq!(hex_root, expected_root_hex);
///
/// let indices_to_prove = vec![3, 4];
/// let merkle_proof = merkle_tree.proof(&indices_to_prove);
/// ```
///
/// ## Advanced usage with rolling several commits back
///
/// ```
/// use rs_merkle::{MerkleTree, algorithms::Sha256, Hasher};
///
/// let leaf_values = ["a", "b", "c", "d", "e", "f"];
/// let expected_root_hex = "1f7379539707bcaea00564168d1d4d626b09b73f8a2a365234c62d763f854da2";
/// let leaves: Vec<[u8; 32]> = leaf_values
/// .iter()
/// .map(|x| Sha256::hash(x.as_bytes().to_vec().as_ref()))
/// .collect();
///
/// let mut merkle_tree: MerkleTree<Sha256> = MerkleTree::new();
/// merkle_tree.append(leaves.clone().as_mut());
/// // No changes were committed just yet, tree is empty
/// assert_eq!(merkle_tree.root(), None);
///
/// merkle_tree.commit();
///
/// assert_eq!(merkle_tree.uncommitted_root_hex().unwrap(), String::from("1f7379539707bcaea00564168d1d4d626b09b73f8a2a365234c62d763f854da2"));
///
/// // Adding a new leaf
/// merkle_tree.insert(Sha256::hash("g".as_bytes().to_vec().as_ref()));
///
/// // Uncommitted root must reflect the insert
/// assert_eq!(merkle_tree.uncommitted_root_hex().unwrap(), String::from("e2a80e0e872a6c6eaed37b4c1f220e1935004805585b5f99617e48e9c8fe4034"));
///
/// merkle_tree.commit();
///
/// // After calling commit, uncommitted root will become committed
/// assert_eq!(merkle_tree.root_hex().unwrap(), String::from("e2a80e0e872a6c6eaed37b4c1f220e1935004805585b5f99617e48e9c8fe4034"));
///
/// // Adding some more leaves
/// merkle_tree.append(vec![
/// Sha256::hash("h".as_bytes().to_vec().as_ref()),
/// Sha256::hash("k".as_bytes().to_vec().as_ref()),
/// ].as_mut());
///
/// // Checking that the uncommitted root has changed, but the committed one hasn't
/// assert_eq!(merkle_tree.uncommitted_root_hex().unwrap(), String::from("09b6890b23e32e607f0e5f670ab224e36af8f6599cbe88b468f4b0f761802dd6"));
/// assert_eq!(merkle_tree.root_hex().unwrap(), String::from("e2a80e0e872a6c6eaed37b4c1f220e1935004805585b5f99617e48e9c8fe4034"));
///
/// merkle_tree.commit();
///
/// // Checking committed changes again
/// assert_eq!(merkle_tree.root_hex().unwrap(), String::from("09b6890b23e32e607f0e5f670ab224e36af8f6599cbe88b468f4b0f761802dd6"));
///
/// merkle_tree.rollback();
///
/// // Check that we rolled one commit back
/// assert_eq!(merkle_tree.root_hex().unwrap(), String::from("e2a80e0e872a6c6eaed37b4c1f220e1935004805585b5f99617e48e9c8fe4034"));
///
/// merkle_tree.rollback();
///
/// // Rolling back to the state after the very first commit
/// assert_eq!(merkle_tree.root_hex().unwrap(), expected_root_hex);
/// ```
/// Advanced features include being able to make transactional changes to a tree with being able to
/// roll back to any previously committed state of the tree. This scenario is similar to Git and
/// can be found in databases and file systems.
#[derive(Clone)]
pub struct MerkleTree<T: Hasher> {
current_working_tree: PartialTree<T>,
@@ -105,7 +24,7 @@ impl<T: Hasher> Default for MerkleTree<T> {
}
impl<T: Hasher> MerkleTree<T> {
/// Creates a new instance of Merkle Tree. Requires specifying the hash algorithm.
/// Creates a new instance of Merkle Tree. Requires a hash algorithm to be specified.
///
/// # Examples
///
@@ -124,12 +43,23 @@ impl<T: Hasher> MerkleTree<T> {
}
}
/// Returns Merkle tree root
pub fn root(&self) -> Option<T::Hash> {
self.layers().last()?.first().cloned()
}
/// Clones leave hashes and build the tree from them
/// Clones the leaves and builds the tree from them
///
/// ## Examples
///
/// ```
/// # use rs_merkle::{MerkleTree, MerkleProof, algorithms::Sha256, Hasher, Error, utils};
/// # use std::convert::TryFrom;
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let leaves = [
/// Sha256::hash("a".as_bytes()),
/// Sha256::hash("b".as_bytes()),
/// Sha256::hash("c".as_bytes()),
/// ];
///
/// let merkle_tree = MerkleTree::<Sha256>::from_leaves(&leaves);
/// # Ok(())
/// # }
pub fn from_leaves(leaves: &[T::Hash]) -> Self {
let mut tree = Self::new();
@@ -139,20 +69,68 @@ impl<T: Hasher> MerkleTree<T> {
tree
}
/// Returns Merkle tree root serialized as a hex string
/// Returns the tree root - the top hash of the tree. Used in the inclusion proof verification.
///
/// ## Examples
///
/// ```
/// # use rs_merkle::{MerkleTree, MerkleProof, algorithms::Sha256, Hasher, Error, utils};
/// # use std::convert::TryFrom;
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let leaves = [
/// Sha256::hash("a".as_bytes()),
/// Sha256::hash("b".as_bytes()),
/// Sha256::hash("c".as_bytes()),
/// ];
///
/// let merkle_tree = MerkleTree::<Sha256>::from_leaves(&leaves);
///
/// let indices_to_prove = vec![0, 1];
/// let leaves_to_prove = leaves.get(0..2).ok_or("can't get leaves to prove")?;
///
/// let proof = merkle_tree.proof(&indices_to_prove);
/// let root = merkle_tree.root().ok_or("couldn't get the merkle root")?;
///
/// assert!(proof.verify(root, &indices_to_prove, leaves_to_prove, leaves.len()));
/// # Ok(())
/// # }
/// ```
pub fn root(&self) -> Option<T::Hash> {
Some(self.layer_tuples().last()?.first()?.1)
}
/// Similar to [`MerkleTree::root`], but returns a hex encoded string instead of
/// [`Hasher::Hash`].
///
/// ## Examples
///
/// ```
/// # use rs_merkle::{MerkleTree, MerkleProof, algorithms::Sha256, Hasher, Error, utils};
/// # use std::convert::TryFrom;
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let leaves = [
/// Sha256::hash("a".as_bytes()),
/// Sha256::hash("b".as_bytes()),
/// Sha256::hash("c".as_bytes()),
/// ];
///
/// let merkle_tree = MerkleTree::<Sha256>::from_leaves(&leaves);
/// let root = merkle_tree.root_hex().ok_or("couldn't get the merkle root")?;
///
/// assert_eq!(
/// root,
/// "7075152d03a5cd92104887b476862778ec0c87be5c2fa1c0a90f87c49fad6eff".to_string()
/// );
/// # Ok(())
/// # }
/// ```
pub fn root_hex(&self) -> Option<String> {
let root = self.root()?;
Some(utils::collections::to_hex_string(&root))
}
/// Returns tree depth. Tree depth is how many layers there is between
/// leaves and root
pub fn depth(&self) -> usize {
self.layers().len() - 1
}
/// Returns helper nodes required to build a partial tree for the given indices
/// to be able to extract a root from it. Useful in constructing merkle proofs
/// to be able to extract a root from it. Useful in constructing Merkle proofs
fn helper_nodes(&self, leaf_indices: &[usize]) -> Vec<T::Hash> {
let mut helper_nodes = Vec::<T::Hash>::new();
@@ -171,20 +149,15 @@ impl<T: Hasher> MerkleTree<T> {
let mut current_layer_indices = leaf_indices.to_vec();
let mut helper_nodes: Vec<Vec<(usize, T::Hash)>> = Vec::new();
for tree_layer in self.layers() {
for tree_layer in self.layer_tuples() {
let mut helpers_layer = Vec::new();
let siblings = utils::indices::sibling_indices(&current_layer_indices);
// Filter all nodes that do not require an additional hash to be calculated
let helper_indices = utils::collections::difference(&siblings, &current_layer_indices);
for index in helper_indices {
match tree_layer.get(index) {
Some(hash) => {
helpers_layer.push((index, *hash));
}
// This means that there's no right sibling to the current index, thus
// we don't need to include anything in the proof for that index
None => continue,
if let Some(tuple) = tree_layer.get(index) {
helpers_layer.push(*tuple);
}
}
@@ -195,82 +168,188 @@ impl<T: Hasher> MerkleTree<T> {
helper_nodes
}
/// Returns merkle proof required to prove inclusion of items at given indices
/// Returns the Merkle proof required to prove the inclusion of items in a data set.
///
/// ## Examples
///
/// ```
/// # use rs_merkle::{MerkleTree, MerkleProof, algorithms::Sha256, Hasher, Error, utils};
/// # use std::convert::TryFrom;
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let leaves: Vec<[u8; 32]> = ["a", "b", "c", "d", "e", "f"]
/// .iter()
/// .map(|x| Sha256::hash(x.as_bytes()))
/// .collect();
///
/// let merkle_tree = MerkleTree::<Sha256>::from_leaves(&leaves);
/// let indices_to_prove = vec![3, 4];
/// let leaves_to_prove = leaves.get(3..5).ok_or("can't get leaves to prove")?;
/// let merkle_proof = merkle_tree.proof(&indices_to_prove);
/// let merkle_root = merkle_tree.root().ok_or("couldn't get the merkle root")?;
/// // Serialize proof to pass it to the client
/// let proof_bytes = merkle_proof.to_bytes();
///
/// // Parse proof back on the client
/// let proof = MerkleProof::<Sha256>::try_from(proof_bytes)?;
///
/// assert!(proof.verify(merkle_root, &indices_to_prove, leaves_to_prove, leaves.len()));
/// # Ok(())
/// # }
/// ```
pub fn proof(&self, leaf_indices: &[usize]) -> MerkleProof<T> {
MerkleProof::<T>::new(self.helper_nodes(leaf_indices))
}
/// Returns tree leaves, i.e. the bottom level
pub fn leaves(&self) -> Option<Vec<T::Hash>> {
self.layers().first().cloned()
}
/// Returns the whole tree, where the first layer is leaves and
/// consequent layers are nodes.
pub fn layers(&self) -> Vec<Vec<T::Hash>> {
self.current_working_tree.layer_nodes()
}
/// Same as [`layers`](MerkleTree::layers), but serializes each hash as a hex string
pub fn layers_hex(&self) -> Vec<Vec<String>> {
self.layers()
.iter()
.map(|layer| {
layer
.iter()
.map(utils::collections::to_hex_string)
.collect()
})
.collect()
}
/// Inserts a new leaf. Please note it won't modify the root just yet; For the changes
/// to be applied to the root, [`commit`](MerkleTree::commit) method should be called first. To get the root
/// of the new tree without applying the changes, you can use [`uncommitted_root`](MerkleTree::uncommitted_root)
/// to be applied to the root, [`MerkleTree::commit`] method should be called first. To get the
/// root of the new tree without applying the changes, you can use
/// [`MerkleTree::uncommitted_root`]
///
/// # Example
/// // TODO
pub fn insert(&mut self, leaf: T::Hash) {
self.uncommitted_leaves.push(leaf)
/// # Examples
///
/// Get the root after an insert:
///
/// ```
/// # use rs_merkle::{MerkleTree, MerkleProof, algorithms::Sha256, Hasher, Error, utils};
/// # use std::convert::TryFrom;
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let mut merkle_tree = MerkleTree::<Sha256>::new();
/// merkle_tree.insert(Sha256::hash("a".as_bytes()));
///
/// assert_eq!(merkle_tree.root(), None);
///
/// merkle_tree.commit();
/// assert_eq!(
/// merkle_tree.root_hex(),
/// Some("ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb".to_string())
/// );
/// # Ok(())
/// # }
/// ```
///
/// Inserts also can be chained with [`MerkleTree::commit`] for convenience:
///
/// ```
/// # use rs_merkle::{MerkleTree, MerkleProof, algorithms::Sha256, Hasher, Error, utils};
/// # use std::convert::TryFrom;
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let mut merkle_tree = MerkleTree::<Sha256>::new();
/// merkle_tree
/// .insert(Sha256::hash("a".as_bytes()))
/// .commit();
///
/// assert_eq!(
/// merkle_tree.root_hex(),
/// Some("ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb".to_string())
/// );
/// # Ok(())
/// # }
/// ```
pub fn insert(&mut self, leaf: T::Hash) -> &mut Self {
self.uncommitted_leaves.push(leaf);
self
}
/// Appends leaves to the tree. Behaves similarly to [`commit`](MerkleTree::commit), but for a list of items.
/// Takes ownership of the elements of the [`std::vec::Vec<T>`], similarly to [`append`](std::vec::Vec::append) of a [`std::vec::Vec<T>`]
pub fn append(&mut self, leaves: &mut Vec<T::Hash>) {
self.uncommitted_leaves.append(leaves)
/// Appends leaves to the tree. Behaves similarly to [`MerkleTree::insert`], but for a list of
/// items. Takes ownership of the elements of the [`std::vec::Vec<T>`],
/// similarly to [`std::vec::Vec::append`].
///
/// ## Examples
///
/// ```
/// # use rs_merkle::{MerkleTree, MerkleProof, algorithms::Sha256, Hasher, Error, utils};
/// # use std::convert::TryFrom;
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let mut merkle_tree = MerkleTree::<Sha256>::new();
/// let mut leaves = vec![
/// Sha256::hash("a".as_bytes()),
/// Sha256::hash("b".as_bytes()),
/// ];
/// merkle_tree
/// .append(&mut leaves)
/// .commit();
///
/// assert_eq!(
/// merkle_tree.root_hex(),
/// Some("e5a01fee14e0ed5c48714f22180f25ad8365b53f9779f79dc4a3d7e93963f94a".to_string())
/// );
/// # Ok(())
/// # }
/// ```
pub fn append(&mut self, leaves: &mut Vec<T::Hash>) -> &mut Self {
self.uncommitted_leaves.append(leaves);
self
}
/// Calculates the root of the uncommitted changes as if they were committed.
/// Will return the same hash as [`root`](MerkleTree::root) after [`commit`](MerkleTree::commit)
pub fn uncommitted_root(&self) -> Option<T::Hash> {
let shadow_tree = self.uncommitted_diff()?;
shadow_tree.root().cloned()
}
/// Same as `uncommitted_root`, but serialized to a hex string
pub fn uncommitted_root_hex(&self) -> Option<String> {
let root = self.uncommitted_root()?;
Some(utils::collections::to_hex_string(&root))
}
/// Commits changes made by [`insert`](MerkleTree::insert) and [`append`](MerkleTree::append)
/// Commits the changes made by [`MerkleTree::insert`] and [`MerkleTree::append`]
/// and modifies the root.
/// Commits changes to the history, so the tree can be rolled back to any previous commit.
/// Commits are saved to the history, so the tree can be rolled back to any previous commit
/// using [`MerkleTree::rollback`]
///
/// ## Examples
///
/// ```
/// # use rs_merkle::{MerkleTree, MerkleProof, algorithms::Sha256, Hasher, Error, utils};
/// # use std::convert::TryFrom;
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let mut merkle_tree = MerkleTree::<Sha256>::new();
/// let mut leaves = vec![
/// Sha256::hash("a".as_bytes()),
/// Sha256::hash("b".as_bytes()),
/// ];
/// merkle_tree.append(&mut leaves);
/// assert_eq!(
/// merkle_tree.root_hex(),
/// None
/// );
///
/// merkle_tree.commit();
/// assert_eq!(
/// merkle_tree.root_hex(),
/// Some("e5a01fee14e0ed5c48714f22180f25ad8365b53f9779f79dc4a3d7e93963f94a".to_string())
/// );
/// # Ok(())
/// # }
/// ```
pub fn commit(&mut self) {
if let Some(diff) = self.uncommitted_diff() {
self.history.push(diff.clone());
self.current_working_tree.merge_unverified(diff);
self.uncommitted_leaves.clear();
}
}
/// Aborts all uncommitted [`insert`](MerkleTree::insert) and [`append`](MerkleTree::append)
/// operations without applying them to the tree.
pub fn abort_uncommitted(&mut self) {
self.uncommitted_leaves.clear()
}
/// Rolls back one commit and reverts tree to the previous state.
/// Removes the latest commit from the changes history
/// Rolls back one commit and reverts the tree to the previous state.
/// Removes the most recent commit from the history.
///
/// ## Examples
///
/// ```
/// # use rs_merkle::{MerkleTree, MerkleProof, algorithms::Sha256, Hasher, Error, utils};
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let mut merkle_tree = MerkleTree::<Sha256>::new();
///
/// merkle_tree.insert(Sha256::hash("a".as_bytes())).commit();
/// assert_eq!(
/// merkle_tree.root_hex(),
/// Some("ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb".to_string())
/// );
///
/// merkle_tree.insert(Sha256::hash("b".as_bytes())).commit();
/// assert_eq!(
/// merkle_tree.root_hex(),
/// Some("e5a01fee14e0ed5c48714f22180f25ad8365b53f9779f79dc4a3d7e93963f94a".to_string())
/// );
///
/// // Rollback to the previous state
/// merkle_tree.rollback();
/// assert_eq!(
/// merkle_tree.root_hex(),
/// Some("ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb".to_string())
/// );
/// # Ok(())
/// # }
/// ```
pub fn rollback(&mut self) {
// Remove the most recent commit
self.history.pop();
@@ -284,14 +363,189 @@ impl<T: Hasher> MerkleTree<T> {
}
}
/// Calculates the root of the uncommitted changes as if they were committed.
/// Will return the same hash as [`MerkleTree::root`] after [`MerkleTree::commit`]
///
/// For examples, please check [`MerkleTree::uncommitted_root_hex`]
pub fn uncommitted_root(&self) -> Option<T::Hash> {
let shadow_tree = self.uncommitted_diff()?;
shadow_tree.root().cloned()
}
/// Calculates the root of the uncommitted changes as if they were committed. Serializes
/// the result as a hex string.
/// Will return the same hash as [`MerkleTree::root_hex`] after [`MerkleTree::commit`]
///
/// ### Examples
///
/// ```
/// # use rs_merkle::{MerkleTree, MerkleProof, algorithms::Sha256, Hasher, Error, utils};
/// # use std::convert::TryFrom;
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let mut merkle_tree = MerkleTree::<Sha256>::new();
/// let mut leaves = vec![
/// Sha256::hash("a".as_bytes()),
/// Sha256::hash("b".as_bytes()),
/// ];
/// merkle_tree.append(&mut leaves);
/// assert_eq!(
/// merkle_tree.root_hex(),
/// None
/// );
/// assert_eq!(
/// merkle_tree.uncommitted_root_hex(),
/// Some("e5a01fee14e0ed5c48714f22180f25ad8365b53f9779f79dc4a3d7e93963f94a".to_string())
/// );
///
/// merkle_tree.commit();
/// assert_eq!(
/// merkle_tree.root_hex(),
/// Some("e5a01fee14e0ed5c48714f22180f25ad8365b53f9779f79dc4a3d7e93963f94a".to_string())
/// );
/// # Ok(())
/// # }
/// ```
pub fn uncommitted_root_hex(&self) -> Option<String> {
let root = self.uncommitted_root()?;
Some(utils::collections::to_hex_string(&root))
}
/// Clears all uncommitted changes made by [`MerkleTree::insert`] and [`MerkleTree::append`]
/// operations without applying them to the tree.
///
/// ## Examples
///
/// ```
/// # use rs_merkle::{MerkleTree, MerkleProof, algorithms::Sha256, Hasher, Error, utils};
/// # use std::convert::TryFrom;
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let mut merkle_tree = MerkleTree::<Sha256>::new();
/// let mut leaves = vec![
/// Sha256::hash("a".as_bytes()),
/// Sha256::hash("b".as_bytes()),
/// ];
/// assert_eq!(
/// merkle_tree.root(),
/// None
/// );
///
/// merkle_tree.append(&mut leaves);
/// merkle_tree.abort_uncommitted();
/// merkle_tree.commit();
///
/// assert_eq!(
/// merkle_tree.root(),
/// None
/// );
/// # Ok(())
/// # }
/// ```
pub fn abort_uncommitted(&mut self) {
self.uncommitted_leaves.clear()
}
/// Returns the tree depth. A tree depth is how many layers there is between the
/// leaves and the root
///
/// ## Examples
///
/// ```
/// # use rs_merkle::{MerkleTree, MerkleProof, algorithms::Sha256, Hasher, Error, utils};
/// # use std::convert::TryFrom;
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let leaves = [
/// Sha256::hash("a".as_bytes()),
/// Sha256::hash("b".as_bytes()),
/// Sha256::hash("c".as_bytes()),
/// ];
///
/// let merkle_tree = MerkleTree::<Sha256>::from_leaves(&leaves);
/// assert_eq!(merkle_tree.depth(), 2);
/// # Ok(())
/// # }
/// ```
pub fn depth(&self) -> usize {
self.layer_tuples().len() - 1
}
/// Returns a copy of the tree leaves - the base level of the tree.
///
/// ### Examples
///
/// ```
/// # use rs_merkle::{MerkleTree, MerkleProof, algorithms::Sha256, Hasher, Error, utils};
/// # use std::convert::TryFrom;
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let leaves = [
/// Sha256::hash("a".as_bytes()),
/// Sha256::hash("b".as_bytes()),
/// Sha256::hash("c".as_bytes()),
/// ];
///
/// let merkle_tree = MerkleTree::<Sha256>::from_leaves(&leaves);
/// assert_eq!(merkle_tree.leaves(), Some(leaves.to_vec()));
/// # Ok(())
/// # }
/// ```
pub fn leaves(&self) -> Option<Vec<T::Hash>> {
Some(self.layers().first()?.to_vec())
}
/// Returns the number of leaves in the tree.
///
/// ## Examples
///
/// ```
/// # use rs_merkle::{MerkleTree, MerkleProof, algorithms::Sha256, Hasher, Error, utils};
/// # use std::convert::TryFrom;
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let leaves = [
/// Sha256::hash("a".as_bytes()),
/// Sha256::hash("b".as_bytes()),
/// Sha256::hash("c".as_bytes()),
/// ];
///
/// let merkle_tree = MerkleTree::<Sha256>::from_leaves(&leaves);
/// assert_eq!(merkle_tree.leaves_len(), 3);
/// # Ok(())
/// # }
/// ```
pub fn leaves_len(&self) -> usize {
if let Some(leaves) = self.leaves_tuples() {
return leaves.len();
}
0
}
fn leaves_tuples(&self) -> Option<&[(usize, T::Hash)]> {
Some(self.layer_tuples().first()?.as_slice())
}
/// Returns the whole tree, where the first layer is leaves and
/// consequent layers are nodes.
fn layers(&self) -> Vec<Vec<T::Hash>> {
self.current_working_tree.layer_nodes()
}
fn layer_tuples(&self) -> &[Vec<(usize, T::Hash)>] {
self.current_working_tree.layers()
}
/// Creates a diff from a changes that weren't committed to the main tree yet. Can be used
/// to get uncommitted root or can be merged with the main tree
fn uncommitted_diff(&self) -> Option<PartialTree<T>> {
if self.uncommitted_leaves.is_empty() {
return None;
}
let committed_leaves_count = self.leaves_len();
let shadow_indices: Vec<usize> = self
.uncommitted_leaves
.iter()
.enumerate()
.map(|(index, _)| index)
.map(|(index, _)| committed_leaves_count + index)
.collect();
// Tuples (index, hash) needed to construct a partial tree, since partial tree can't
// maintain indices otherwise
@@ -303,10 +557,7 @@ impl<T: Hasher> MerkleTree<T> {
let mut partial_tree_tuples = self.helper_node_tuples(&shadow_indices);
// Figuring what tree height would be if we've committed the changes
let mut leaves_in_new_tree = self.uncommitted_leaves.len();
if let Some(committed_leaves) = self.leaves() {
leaves_in_new_tree += committed_leaves.len();
}
let leaves_in_new_tree = self.leaves_len() + self.uncommitted_leaves.len();
let uncommitted_tree_depth = utils::indices::tree_depth(leaves_in_new_tree);
match partial_tree_tuples.first_mut() {

View File

@@ -5,7 +5,13 @@ type PartialTreeLayer<H> = Vec<(usize, H)>;
/// Partial tree represents a part of the original tree that is enough to calculate the root.
/// Used in to extract the root in a merkle proof, to apply diff to a tree or to merge
/// multiple trees into one
/// multiple trees into one.
///
/// It is a rare case when you need to use this struct on it's own. It's mostly used inside
/// [`MerkleTree`] and [`MerkleProof`]
///
/// [`MerkleTree`]: crate::MerkleTree
/// [`MerkleProof`]: crate::MerkleProof
#[derive(Clone)]
pub struct PartialTree<T: Hasher> {
layers: Vec<Vec<(usize, T::Hash)>>,

View File

@@ -17,7 +17,10 @@ fn combine<T: Clone>(active: Vec<T>, rest: Vec<T>, mut combinations: Vec<Vec<T>>
}
} else {
let mut next = active.clone();
next.push(rest.get(0).unwrap().clone());
if let Some(first) = rest.get(0) {
next.push(first.clone());
}
combinations = combine(next, rest.clone().drain(1..).collect(), combinations);
combinations = combine(active, rest.clone().drain(1..).collect(), combinations);
@@ -35,7 +38,7 @@ pub fn setup() -> TestData {
let expected_root_hex = "1f7379539707bcaea00564168d1d4d626b09b73f8a2a365234c62d763f854da2";
let leaf_hashes = leaf_values
.iter()
.map(|x| Sha256::hash(x.as_bytes().to_vec().as_ref()))
.map(|x| Sha256::hash(x.as_bytes()))
.collect();
TestData {
@@ -80,32 +83,24 @@ pub fn setup_proof_test_cases() -> Vec<ProofTestCases> {
let leaves: Vec<[u8; 32]> = tree_elements
.iter()
.map(|x| Sha256::hash(x.as_bytes().to_vec().as_ref()))
.map(|x| Sha256::hash(x.as_bytes()))
.collect();
let merkle_tree = MerkleTree::<Sha256>::from_leaves(&leaves);
let tuples: Vec<(usize, [u8; 32])> = leaves.iter().cloned().enumerate().collect();
let indices = tree_elements
.iter()
.enumerate()
.map(|(index, _)| index)
.collect();
let possible_proof_elements_combinations = combinations(tuples);
let possible_proof_index_combinations = combinations(indices);
let cases: Vec<MerkleProofTestCase> = possible_proof_index_combinations
let cases: Vec<MerkleProofTestCase> = possible_proof_elements_combinations
.par_iter()
.cloned()
.map(|index_combination| {
MerkleProofTestCase::new(
index_combination
.iter()
.map(|index| leaves.get(*index).unwrap().clone())
.collect(),
index_combination,
)
.map(|proof_elements| {
let (indices, leaves2): (Vec<usize>, Vec<[u8; 32]>) =
proof_elements.iter().cloned().unzip();
MerkleProofTestCase::new(leaves2, indices)
})
.collect();
let merkle_tree = MerkleTree::<Sha256>::from_leaves(&leaves);
let case = ProofTestCases { merkle_tree, cases };
case
})

View File

@@ -3,32 +3,30 @@ mod common;
pub mod root {
use crate::common;
use rayon::prelude::*;
use rs_merkle::{algorithms::Sha256, Hasher, MerkleTree};
use rs_merkle::{algorithms::Sha256, Error, Hasher, MerkleTree};
use std::time::Instant;
#[test]
pub fn should_return_a_correct_root() {
pub fn should_return_a_correct_root() -> Result<(), Error> {
let test_data = common::setup();
let expected_root = test_data.expected_root_hex.clone();
let leaf_hashes = &test_data.leaf_hashes;
let indices_to_prove = vec![3, 4];
let leaves_to_prove: Vec<[u8; 32]> = indices_to_prove
.iter()
.cloned()
.map(|i| leaf_hashes.get(i).unwrap().clone())
.map(|i| leaf_hashes.get(*i).unwrap().clone())
.collect();
let merkle_tree = MerkleTree::<Sha256>::from_leaves(&test_data.leaf_hashes);
let proof = merkle_tree.proof(&indices_to_prove);
let extracted_root = proof
.root_hex(
&indices_to_prove,
&leaves_to_prove,
test_data.leaf_values.len(),
)
.unwrap();
let extracted_root = proof.root_hex(
&indices_to_prove,
&leaves_to_prove,
test_data.leaf_values.len(),
)?;
assert_eq!(extracted_root, expected_root);
assert_eq!(extracted_root, expected_root.to_string());
let test_preparation_started = Instant::now();
let test_cases = common::setup_proof_test_cases();
@@ -60,26 +58,27 @@ pub mod root {
let test_run_started = Instant::now();
test_cases.par_iter().for_each(|test_case| {
let merkle_tree = &test_case.merkle_tree;
let root = merkle_tree.root().unwrap().clone();
let root = merkle_tree.root();
test_case.cases.par_iter().for_each(|case| {
let proof = merkle_tree.proof(&case.leaf_indices_to_prove);
let extracted_root = proof
.root(
&case.leaf_indices_to_prove,
&case.leaf_hashes_to_prove,
merkle_tree.leaves().unwrap().len(),
)
.unwrap();
let extracted_root = proof.root(
&case.leaf_indices_to_prove,
&case.leaf_hashes_to_prove,
merkle_tree.leaves_len(),
);
assert_eq!(extracted_root, root)
assert_eq!(extracted_root.ok(), root)
});
});
println!(
"{} test cases executed in {:.2}s",
test_cases_count,
test_run_started.elapsed().as_secs_f32()
);
Ok(())
}
}
@@ -111,10 +110,10 @@ pub mod to_bytes {
pub mod from_bytes {
use crate::common;
use rs_merkle::{algorithms::Sha256, MerkleProof};
use rs_merkle::{algorithms::Sha256, Error, MerkleProof};
#[test]
pub fn should_return_result_with_proof() {
pub fn should_return_result_with_proof() -> Result<(), Error> {
let expected_proof_hashes = [
"2e7d2c03a9507ae265ecf5b5356885a53393a2029d241394997265a1a25aefc6",
"252f10c83610ebca1a059c0bae8255eba2f95be4d1d7bcfa89d7248a82d9f111",
@@ -130,10 +129,12 @@ pub mod from_bytes {
249, 74,
];
let proof = MerkleProof::<Sha256>::from_bytes(&bytes).unwrap();
let proof = MerkleProof::<Sha256>::from_bytes(&bytes)?;
let hex_hashes = proof.proof_hashes_hex();
assert_eq!(hex_hashes, expected_proof_hashes);
Ok(())
}
#[test]

View File

@@ -9,9 +9,11 @@ pub mod root {
let test_data = common::setup();
let merkle_tree = MerkleTree::<Sha256>::from_leaves(&test_data.leaf_hashes);
let hex_root = merkle_tree.root_hex().unwrap();
assert_eq!(hex_root, test_data.expected_root_hex);
assert_eq!(
merkle_tree.root_hex(),
Some(test_data.expected_root_hex.to_string())
);
}
}
@@ -54,15 +56,13 @@ pub mod proof {
pub mod commit {
use crate::common;
use rs_merkle::{algorithms::Sha256, Hasher, MerkleTree};
use rs_merkle::{algorithms::Sha256, Error, Hasher, MerkleTree};
#[test]
pub fn should_give_correct_root_after_commit() {
let test_data = common::setup();
let expected_root = test_data.expected_root_hex.clone();
let leaf_hashes = &test_data.leaf_hashes;
// let indices_to_prove = vec![3, 4];
// let leaves_to_prove = indices_to_prove.iter().cloned().map(|i| leaf_hashes.get(i).unwrap().clone()).collect();
let vec = Vec::<[u8; 32]>::new();
// Passing empty vec to create an empty tree
@@ -70,18 +70,18 @@ pub mod commit {
let merkle_tree2 = MerkleTree::<Sha256>::from_leaves(&leaf_hashes);
// Adding leaves
merkle_tree.append(leaf_hashes.clone().as_mut());
let root = merkle_tree.uncommitted_root_hex().unwrap();
let root = merkle_tree.uncommitted_root_hex();
assert_eq!(merkle_tree2.root_hex().unwrap(), expected_root);
assert_eq!(root, expected_root);
assert_eq!(merkle_tree2.root_hex(), Some(expected_root.to_string()));
assert_eq!(root, Some(expected_root.to_string()));
let expected_root = "e2a80e0e872a6c6eaed37b4c1f220e1935004805585b5f99617e48e9c8fe4034";
let leaf = Sha256::hash("g".as_bytes().to_vec().as_ref());
let leaf = Sha256::hash("g".as_bytes());
merkle_tree.insert(leaf);
assert_eq!(
merkle_tree.uncommitted_root_hex().unwrap(),
String::from(expected_root)
merkle_tree.uncommitted_root_hex(),
Some(expected_root.to_string())
);
// No changes were committed just yet, tree is empty
@@ -89,31 +89,99 @@ pub mod commit {
merkle_tree.commit();
let mut new_leaves = vec![
Sha256::hash("h".as_bytes().to_vec().as_ref()),
Sha256::hash("k".as_bytes().to_vec().as_ref()),
];
let mut new_leaves = vec![Sha256::hash("h".as_bytes()), Sha256::hash("k".as_bytes())];
merkle_tree.append(&mut new_leaves);
assert_eq!(
merkle_tree.root_hex().unwrap(),
String::from("e2a80e0e872a6c6eaed37b4c1f220e1935004805585b5f99617e48e9c8fe4034")
merkle_tree.root_hex(),
Some("e2a80e0e872a6c6eaed37b4c1f220e1935004805585b5f99617e48e9c8fe4034".to_string())
);
assert_eq!(
merkle_tree.uncommitted_root_hex().unwrap(),
String::from("09b6890b23e32e607f0e5f670ab224e36af8f6599cbe88b468f4b0f761802dd6")
merkle_tree.uncommitted_root_hex(),
Some("09b6890b23e32e607f0e5f670ab224e36af8f6599cbe88b468f4b0f761802dd6".to_string())
);
merkle_tree.commit();
let leaves = merkle_tree.leaves().unwrap();
let leaves = merkle_tree
.leaves()
.expect("expect the tree to have some leaves");
let reconstructed_tree = MerkleTree::<Sha256>::from_leaves(&leaves);
// Check that the commit is applied correctly
assert_eq!(
reconstructed_tree.root_hex().unwrap(),
String::from("09b6890b23e32e607f0e5f670ab224e36af8f6599cbe88b468f4b0f761802dd6")
reconstructed_tree.root_hex(),
Some("09b6890b23e32e607f0e5f670ab224e36af8f6599cbe88b468f4b0f761802dd6".to_string())
);
}
#[test]
pub fn should_not_change_the_result_when_called_twice() {
let elements = ["a", "b", "c", "d", "e", "f"];
let mut leaves: Vec<[u8; 32]> = elements
.iter()
.map(|x| Sha256::hash(x.as_bytes()))
.collect();
let mut merkle_tree: MerkleTree<Sha256> = MerkleTree::new();
// Appending leaves to the tree without committing
merkle_tree.append(&mut leaves);
// Without committing changes we can get the root for the uncommitted data, but committed
// tree still doesn't have any elements
assert_eq!(merkle_tree.root(), None);
assert_eq!(
merkle_tree.uncommitted_root_hex(),
Some("1f7379539707bcaea00564168d1d4d626b09b73f8a2a365234c62d763f854da2".to_string())
);
// Committing the changes
merkle_tree.commit();
// Changes applied to the tree after commit, and since there's no new staged changes
assert_eq!(
merkle_tree.root_hex(),
Some("1f7379539707bcaea00564168d1d4d626b09b73f8a2a365234c62d763f854da2".to_string())
);
assert_eq!(merkle_tree.uncommitted_root_hex(), None);
// Adding a new leaf
merkle_tree.insert(Sha256::hash("g".as_bytes()));
assert_eq!(
merkle_tree.uncommitted_root_hex(),
Some("e2a80e0e872a6c6eaed37b4c1f220e1935004805585b5f99617e48e9c8fe4034".to_string())
);
merkle_tree.commit();
// Root was updated after insertion
assert_eq!(
merkle_tree.root_hex(),
Some("e2a80e0e872a6c6eaed37b4c1f220e1935004805585b5f99617e48e9c8fe4034".to_string())
);
// Adding some more leaves
merkle_tree
.append(vec![Sha256::hash("h".as_bytes()), Sha256::hash("k".as_bytes())].as_mut());
merkle_tree.commit();
merkle_tree.commit();
assert_eq!(
merkle_tree.root_hex(),
Some("09b6890b23e32e607f0e5f670ab224e36af8f6599cbe88b468f4b0f761802dd6".to_string())
);
// Rolling back to the previous state
merkle_tree.rollback();
assert_eq!(
merkle_tree.root_hex(),
Some("e2a80e0e872a6c6eaed37b4c1f220e1935004805585b5f99617e48e9c8fe4034".to_string())
);
// We can rollback multiple times as well
merkle_tree.rollback();
assert_eq!(
merkle_tree.root_hex(),
Some("1f7379539707bcaea00564168d1d4d626b09b73f8a2a365234c62d763f854da2".to_string())
);
assert_eq!(reconstructed_tree.layers(), merkle_tree.layers());
}
}
@@ -121,12 +189,12 @@ pub mod rollback {
use crate::common;
use rs_merkle::{algorithms::Sha256, Hasher, MerkleTree};
#[test]
pub fn should_rollback_previous_commit() {
let leaf_values = ["a", "b", "c", "d", "e", "f"];
let expected_root_hex = "1f7379539707bcaea00564168d1d4d626b09b73f8a2a365234c62d763f854da2";
let leaves: Vec<[u8; 32]> = leaf_values
.iter()
.map(|x| Sha256::hash(x.as_bytes().to_vec().as_ref()))
.map(|x| Sha256::hash(x.as_bytes()))
.collect();
let mut merkle_tree: MerkleTree<Sha256> = MerkleTree::new();
@@ -137,65 +205,63 @@ pub mod rollback {
merkle_tree.commit();
assert_eq!(
merkle_tree.uncommitted_root_hex().unwrap(),
String::from("1f7379539707bcaea00564168d1d4d626b09b73f8a2a365234c62d763f854da2")
merkle_tree.root_hex(),
Some("1f7379539707bcaea00564168d1d4d626b09b73f8a2a365234c62d763f854da2".to_string())
);
// Adding a new leaf
merkle_tree.insert(Sha256::hash("g".as_bytes().to_vec().as_ref()));
merkle_tree.insert(Sha256::hash("g".as_bytes()));
// Uncommitted root must reflect the insert
assert_eq!(
merkle_tree.uncommitted_root_hex().unwrap(),
String::from("e2a80e0e872a6c6eaed37b4c1f220e1935004805585b5f99617e48e9c8fe4034")
merkle_tree.uncommitted_root_hex(),
Some("e2a80e0e872a6c6eaed37b4c1f220e1935004805585b5f99617e48e9c8fe4034".to_string())
);
merkle_tree.commit();
// After calling commit, uncommitted root will become committed
assert_eq!(
merkle_tree.root_hex().unwrap(),
String::from("e2a80e0e872a6c6eaed37b4c1f220e1935004805585b5f99617e48e9c8fe4034")
merkle_tree.root_hex(),
Some("e2a80e0e872a6c6eaed37b4c1f220e1935004805585b5f99617e48e9c8fe4034".to_string())
);
// Adding some more leaves
merkle_tree.append(
vec![
Sha256::hash("h".as_bytes().to_vec().as_ref()),
Sha256::hash("k".as_bytes().to_vec().as_ref()),
]
.as_mut(),
);
merkle_tree
.append(vec![Sha256::hash("h".as_bytes()), Sha256::hash("k".as_bytes())].as_mut());
// Checking that the uncommitted root has changed, but the committed one hasn't
assert_eq!(
merkle_tree.uncommitted_root_hex().unwrap(),
String::from("09b6890b23e32e607f0e5f670ab224e36af8f6599cbe88b468f4b0f761802dd6")
merkle_tree.uncommitted_root_hex(),
Some("09b6890b23e32e607f0e5f670ab224e36af8f6599cbe88b468f4b0f761802dd6".to_string())
);
assert_eq!(
merkle_tree.root_hex().unwrap(),
String::from("e2a80e0e872a6c6eaed37b4c1f220e1935004805585b5f99617e48e9c8fe4034")
merkle_tree.root_hex(),
Some("e2a80e0e872a6c6eaed37b4c1f220e1935004805585b5f99617e48e9c8fe4034".to_string())
);
merkle_tree.commit();
// Checking committed changes again
assert_eq!(
merkle_tree.root_hex().unwrap(),
String::from("09b6890b23e32e607f0e5f670ab224e36af8f6599cbe88b468f4b0f761802dd6")
merkle_tree.root_hex(),
Some("09b6890b23e32e607f0e5f670ab224e36af8f6599cbe88b468f4b0f761802dd6".to_string())
);
merkle_tree.rollback();
// Check that we rolled one commit back
assert_eq!(
merkle_tree.root_hex().unwrap(),
String::from("e2a80e0e872a6c6eaed37b4c1f220e1935004805585b5f99617e48e9c8fe4034")
merkle_tree.root_hex(),
Some("e2a80e0e872a6c6eaed37b4c1f220e1935004805585b5f99617e48e9c8fe4034".to_string())
);
merkle_tree.rollback();
// Rolling back to the state after the very first commit
assert_eq!(merkle_tree.root_hex().unwrap(), expected_root_hex);
assert_eq!(
merkle_tree.root_hex(),
Some("1f7379539707bcaea00564168d1d4d626b09b73f8a2a365234c62d763f854da2".to_string())
);
}
}