mirror of
https://github.com/mii443/merkle.rs.git
synced 2025-08-23 00:15:31 +00:00
Implement Iterator
and IntoIterator
for MerkleTree
.
This commit is contained in:
committed by
Romain Ruetschi
parent
261649beca
commit
a1968efbfc
@ -104,3 +104,22 @@ fn bench_big_rnd_proof_check(b: &mut Bencher) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[bench]
|
||||||
|
fn bench_big_rnd_iter(b: &mut Bencher) {
|
||||||
|
let mut values = vec![vec![0u8; 256]; 160];
|
||||||
|
let mut rng = rand::IsaacRng::new_unseeded();
|
||||||
|
|
||||||
|
for mut v in &mut values {
|
||||||
|
rng.fill_bytes(&mut v);
|
||||||
|
}
|
||||||
|
|
||||||
|
let tree = MerkleTree::from_vec(digest, values.clone()).unwrap();
|
||||||
|
|
||||||
|
b.iter(|| {
|
||||||
|
for value in &tree {
|
||||||
|
test::black_box(value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -22,6 +22,7 @@ pub use proof::Proof;
|
|||||||
mod hashutils;
|
mod hashutils;
|
||||||
|
|
||||||
mod tree;
|
mod tree;
|
||||||
|
pub use tree::{ LeavesIterator, LeavesIntoIterator };
|
||||||
|
|
||||||
#[cfg(feature = "serialization-protobuf")]
|
#[cfg(feature = "serialization-protobuf")]
|
||||||
mod proto;
|
mod proto;
|
||||||
|
@ -1,14 +1,13 @@
|
|||||||
|
|
||||||
use ring::digest::Algorithm;
|
use ring::digest::Algorithm;
|
||||||
|
|
||||||
use tree::Tree;
|
use tree::{ Tree, LeavesIterator, LeavesIntoIterator };
|
||||||
use hashutils::HashUtils;
|
use hashutils::HashUtils;
|
||||||
|
|
||||||
use proof::{ Proof, Lemma };
|
use proof::{ Proof, Lemma };
|
||||||
|
|
||||||
/// A Merkle tree is a binary tree, with values of type `T` at the leafs,
|
/// A Merkle tree is a binary tree, with values of type `T` at the leafs,
|
||||||
/// and where every node holds the hash of the concatenation of the hashes of
|
/// and where every internal node holds the hash of the concatenation of the hashes of its children nodes.
|
||||||
/// its children nodes.
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct MerkleTree<T> {
|
pub struct MerkleTree<T> {
|
||||||
|
|
||||||
@ -28,8 +27,8 @@ pub struct MerkleTree<T> {
|
|||||||
impl <T> MerkleTree<T> where T: Into<Vec<u8>> + Clone {
|
impl <T> MerkleTree<T> where T: Into<Vec<u8>> + Clone {
|
||||||
|
|
||||||
/// Constructs a Merkle Tree from a vector of data blocks.
|
/// Constructs a Merkle Tree from a vector of data blocks.
|
||||||
/// Returns None if `values` is empty.
|
/// Returns `None` if `values` is empty.
|
||||||
pub fn from_vec(algo: &'static Algorithm, values: Vec<T>) -> Option<Self> {
|
pub fn from_vec(algorithm: &'static Algorithm, values: Vec<T>) -> Option<Self> {
|
||||||
if values.is_empty() {
|
if values.is_empty() {
|
||||||
return None
|
return None
|
||||||
}
|
}
|
||||||
@ -39,7 +38,7 @@ impl <T> MerkleTree<T> where T: Into<Vec<u8>> + Clone {
|
|||||||
let mut cur = Vec::with_capacity(count);
|
let mut cur = Vec::with_capacity(count);
|
||||||
|
|
||||||
for v in values {
|
for v in values {
|
||||||
let leaf = Tree::make_leaf(algo, v);
|
let leaf = Tree::make_leaf(algorithm, v);
|
||||||
cur.push(leaf);
|
cur.push(leaf);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,7 +52,7 @@ impl <T> MerkleTree<T> where T: Into<Vec<u8>> + Clone {
|
|||||||
let left = cur.remove(0);
|
let left = cur.remove(0);
|
||||||
let right = cur.remove(0);
|
let right = cur.remove(0);
|
||||||
|
|
||||||
let combined_hash = algo.combine_hashes(
|
let combined_hash = algorithm.combine_hashes(
|
||||||
left.hash(),
|
left.hash(),
|
||||||
right.hash()
|
right.hash()
|
||||||
);
|
);
|
||||||
@ -78,7 +77,7 @@ impl <T> MerkleTree<T> where T: Into<Vec<u8>> + Clone {
|
|||||||
let root = cur.remove(0);
|
let root = cur.remove(0);
|
||||||
|
|
||||||
Some(MerkleTree {
|
Some(MerkleTree {
|
||||||
algorithm: algo,
|
algorithm: algorithm,
|
||||||
root: root,
|
root: root,
|
||||||
height: height,
|
height: height,
|
||||||
count: count
|
count: count
|
||||||
@ -111,4 +110,35 @@ impl <T> MerkleTree<T> where T: Into<Vec<u8>> + Clone {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates an `Iterator` over the values contained in this Merkle tree.
|
||||||
|
pub fn iter(&self) -> LeavesIterator<T> {
|
||||||
|
self.root.iter()
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl <T> IntoIterator for MerkleTree<T> {
|
||||||
|
|
||||||
|
type Item = T;
|
||||||
|
type IntoIter = LeavesIntoIterator<T>;
|
||||||
|
|
||||||
|
/// Creates a consuming iterator, that is, one that moves each value out of the Merkle tree.
|
||||||
|
/// The tree cannot be used after calling this.
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
self.root.into_iter()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
impl <'a, T> IntoIterator for &'a MerkleTree<T> {
|
||||||
|
|
||||||
|
type Item = &'a T;
|
||||||
|
type IntoIter = LeavesIterator<'a, T>;
|
||||||
|
|
||||||
|
/// Creates a borrowing `Iterator` over the values contained in this Merkle tree.
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
self.root.iter()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
49
src/tests.rs
49
src/tests.rs
@ -173,3 +173,52 @@ fn test_mutate_proof_first_lemma() {
|
|||||||
i += 1;
|
i += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_tree_iter() {
|
||||||
|
let values = (1..10).map(|x| vec![x]).collect::<Vec<_>>();
|
||||||
|
let tree = MerkleTree::from_vec(digest, values.clone()).unwrap();
|
||||||
|
let iter = tree.iter().map(|x| x.clone()).collect::<Vec<_>>();
|
||||||
|
|
||||||
|
assert_eq!(values, iter);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_tree_into_iter() {
|
||||||
|
let values = (1..10).map(|x| vec![x]).collect::<Vec<_>>();
|
||||||
|
let tree = MerkleTree::from_vec(digest, values.clone()).unwrap();
|
||||||
|
let iter = tree.into_iter().map(|x| x.clone()).collect::<Vec<_>>();
|
||||||
|
|
||||||
|
assert_eq!(values, iter);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_tree_into_iter_loop() {
|
||||||
|
let values = (1..10).map(|x| vec![x]).collect::<Vec<_>>();
|
||||||
|
let tree = MerkleTree::from_vec(digest, values.clone()).unwrap();
|
||||||
|
|
||||||
|
let mut collected = Vec::new();
|
||||||
|
|
||||||
|
for value in tree {
|
||||||
|
collected.push(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_eq!(values, collected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_tree_into_iter_loop_borrow() {
|
||||||
|
let values = (1..10).map(|x| vec![x]).collect::<Vec<_>>();
|
||||||
|
let tree = MerkleTree::from_vec(digest, values.clone()).unwrap();
|
||||||
|
|
||||||
|
let mut collected = Vec::new();
|
||||||
|
|
||||||
|
for value in &tree {
|
||||||
|
collected.push(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
let refs = values.iter().collect::<Vec<_>>();
|
||||||
|
|
||||||
|
assert_eq!(refs, collected);
|
||||||
|
}
|
||||||
|
|
||||||
|
131
src/tree.rs
131
src/tree.rs
@ -24,7 +24,7 @@ pub enum Tree<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <T> Tree<T> where T: Into<Vec<u8>> + Clone {
|
impl <T> Tree<T> {
|
||||||
|
|
||||||
/// Create a new tree
|
/// Create a new tree
|
||||||
pub fn new(hash: Vec<u8>, value: T) -> Self {
|
pub fn new(hash: Vec<u8>, value: T) -> Self {
|
||||||
@ -35,7 +35,9 @@ impl <T> Tree<T> where T: Into<Vec<u8>> + Clone {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new leaf
|
/// Create a new leaf
|
||||||
pub fn make_leaf(algo: &'static Algorithm, value: T) -> Tree<T> {
|
pub fn make_leaf(algo: &'static Algorithm, value: T) -> Tree<T>
|
||||||
|
where T: Into<Vec<u8>> + Clone {
|
||||||
|
|
||||||
let hash = algo.hash_bytes(&value.clone().into());
|
let hash = algo.hash_bytes(&value.clone().into());
|
||||||
Tree::new(hash, value)
|
Tree::new(hash, value)
|
||||||
}
|
}
|
||||||
@ -48,5 +50,130 @@ impl <T> Tree<T> where T: Into<Vec<u8>> + Clone {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a borrowing iterator over the leaves of the tree.
|
||||||
|
pub fn iter(&self) -> LeavesIterator<T> {
|
||||||
|
LeavesIterator::new(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An borrowing iterator over the leaves of a `Tree`.
|
||||||
|
/// Adapted from http://codereview.stackexchange.com/q/110283.
|
||||||
|
#[allow(missing_debug_implementations)]
|
||||||
|
pub struct LeavesIterator<'a, T> where T: 'a {
|
||||||
|
current_value: Option<&'a T>,
|
||||||
|
right_nodes: Vec<&'a Tree<T>>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl <'a, T> LeavesIterator<'a, T> {
|
||||||
|
|
||||||
|
fn new(root: &'a Tree<T>) -> Self {
|
||||||
|
let mut iter = LeavesIterator {
|
||||||
|
current_value: None,
|
||||||
|
right_nodes: Vec::new()
|
||||||
|
};
|
||||||
|
|
||||||
|
iter.add_left(root);
|
||||||
|
|
||||||
|
iter
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_left(&mut self, mut tree: &'a Tree<T>) {
|
||||||
|
loop {
|
||||||
|
match *tree {
|
||||||
|
Tree::Node { ref left, ref right, .. } => {
|
||||||
|
self.right_nodes.push(right);
|
||||||
|
tree = left;
|
||||||
|
},
|
||||||
|
|
||||||
|
Tree::Leaf { ref value, .. } => {
|
||||||
|
self.current_value = Some(value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
impl <'a, T> Iterator for LeavesIterator<'a, T> {
|
||||||
|
|
||||||
|
type Item = &'a T;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<&'a T> {
|
||||||
|
let result = self.current_value.take();
|
||||||
|
|
||||||
|
if let Some(rest) = self.right_nodes.pop() {
|
||||||
|
self.add_left(rest);
|
||||||
|
}
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An iterator over the leaves of a `Tree`.
|
||||||
|
#[allow(missing_debug_implementations)]
|
||||||
|
pub struct LeavesIntoIterator<T> {
|
||||||
|
current_value: Option<T>,
|
||||||
|
right_nodes: Vec<Tree<T>>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl <T> LeavesIntoIterator<T> {
|
||||||
|
|
||||||
|
fn new(root: Tree<T>) -> Self {
|
||||||
|
let mut iter = LeavesIntoIterator {
|
||||||
|
current_value: None,
|
||||||
|
right_nodes: Vec::new()
|
||||||
|
};
|
||||||
|
|
||||||
|
iter.add_left(root);
|
||||||
|
|
||||||
|
iter
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_left(&mut self, mut tree: Tree<T>) {
|
||||||
|
loop {
|
||||||
|
match tree {
|
||||||
|
Tree::Node { left, right, .. } => {
|
||||||
|
self.right_nodes.push(*right);
|
||||||
|
tree = *left;
|
||||||
|
},
|
||||||
|
|
||||||
|
Tree::Leaf { value, .. } => {
|
||||||
|
self.current_value = Some(value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
impl <T> Iterator for LeavesIntoIterator<T> {
|
||||||
|
|
||||||
|
type Item = T;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<T> {
|
||||||
|
let result = self.current_value.take();
|
||||||
|
|
||||||
|
if let Some(rest) = self.right_nodes.pop() {
|
||||||
|
self.add_left(rest);
|
||||||
|
}
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
impl <T> IntoIterator for Tree<T> {
|
||||||
|
|
||||||
|
type Item = T;
|
||||||
|
type IntoIter = LeavesIntoIterator<T>;
|
||||||
|
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
LeavesIntoIterator::new(self)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user