Add vector type to tree hashing

This commit is contained in:
Paul Hauner
2019-04-17 10:57:36 +10:00
parent 49d066015b
commit af39f096e7
11 changed files with 211 additions and 72 deletions

View File

@@ -9,7 +9,7 @@ where
TreeHashType::Basic => {
TreeHashCache::from_bytes(merkleize(get_packed_leaves(self)?), false)
}
TreeHashType::Composite | TreeHashType::List => {
TreeHashType::Container | TreeHashType::List | TreeHashType::Vector => {
let subtrees = self
.iter()
.map(|item| TreeHashCache::new(item))
@@ -23,7 +23,7 @@ where
fn tree_hash_cache_overlay(&self, chunk_offset: usize) -> Result<BTreeOverlay, Error> {
let lengths = match T::tree_hash_type() {
TreeHashType::Basic => vec![1; self.len() / T::tree_hash_packing_factor()],
TreeHashType::Composite | TreeHashType::List => {
TreeHashType::Container | TreeHashType::List | TreeHashType::Vector => {
let mut lengths = vec![];
for item in self {
@@ -97,7 +97,7 @@ where
TreeHashCache::from_bytes(leaves, true)?,
);
}
TreeHashType::Composite | TreeHashType::List => {
TreeHashType::Container | TreeHashType::List | TreeHashType::Vector => {
let mut i = offset_handler.num_leaf_nodes;
for &start_chunk in offset_handler.iter_leaf_nodes().rev() {
i -= 1;

View File

@@ -13,8 +13,9 @@ pub use standard_tree_hash::{merkle_root, TreeHash};
#[derive(Debug, PartialEq, Clone)]
pub enum TreeHashType {
Basic,
Vector,
List,
Composite,
Container,
}
fn num_sanitized_leaves(num_bytes: usize) -> usize {
@@ -31,15 +32,15 @@ macro_rules! impl_tree_hash_for_ssz_bytes {
($type: ident) => {
impl tree_hash::TreeHash for $type {
fn tree_hash_type() -> tree_hash::TreeHashType {
tree_hash::TreeHashType::List
tree_hash::TreeHashType::Vector
}
fn tree_hash_packed_encoding(&self) -> Vec<u8> {
panic!("bytesN should never be packed.")
unreachable!("Vector should never be packed.")
}
fn tree_hash_packing_factor() -> usize {
panic!("bytesN should never be packed.")
unreachable!("Vector should never be packed.")
}
fn tree_hash_root(&self) -> Vec<u8> {
@@ -48,3 +49,26 @@ macro_rules! impl_tree_hash_for_ssz_bytes {
}
};
}
#[macro_export]
macro_rules! impl_vec_as_fixed_len {
($type: ty) => {
impl tree_hash::TreeHash for $type {
fn tree_hash_type() -> tree_hash::TreeHashType {
tree_hash::TreeHashType::Vector
}
fn tree_hash_packed_encoding(&self) -> Vec<u8> {
unreachable!("Vector should never be packed.")
}
fn tree_hash_packing_factor() -> usize {
unreachable!("Vector should never be packed.")
}
fn tree_hash_root(&self) -> Vec<u8> {
tree_hash::standard_tree_hash::vec_tree_hash_root(self)
}
}
};
}

View File

@@ -3,6 +3,8 @@ use hashing::hash;
use int_to_bytes::int_to_bytes32;
use ssz::ssz_encode;
pub use impls::vec_tree_hash_root;
mod impls;
pub trait TreeHash {
@@ -16,11 +18,18 @@ pub trait TreeHash {
}
pub fn merkle_root(bytes: &[u8]) -> Vec<u8> {
// TODO: replace this with a _more_ efficient fn which is more memory efficient.
// TODO: replace this with a more memory efficient method.
efficient_merkleize(&bytes)[0..32].to_vec()
}
pub fn efficient_merkleize(bytes: &[u8]) -> Vec<u8> {
// If the bytes are just one chunk (or less than one chunk) just return them.
if bytes.len() <= HASHSIZE {
let mut o = bytes.to_vec();
o.resize(HASHSIZE, 0);
return o;
}
let leaves = num_sanitized_leaves(bytes.len());
let nodes = num_nodes(leaves);
let internal_nodes = nodes - leaves;
@@ -29,10 +38,6 @@ pub fn efficient_merkleize(bytes: &[u8]) -> Vec<u8> {
let mut o: Vec<u8> = vec![0; internal_nodes * HASHSIZE];
if o.len() < HASHSIZE {
o.resize(HASHSIZE, 0);
}
o.append(&mut bytes.to_vec());
assert_eq!(o.len(), num_bytes);

View File

@@ -50,7 +50,7 @@ impl TreeHash for [u8; 4] {
impl TreeHash for H256 {
fn tree_hash_type() -> TreeHashType {
TreeHashType::Basic
TreeHashType::Vector
}
fn tree_hash_packed_encoding(&self) -> Vec<u8> {
@@ -62,7 +62,7 @@ impl TreeHash for H256 {
}
fn tree_hash_root(&self) -> Vec<u8> {
ssz_encode(self)
merkle_root(&ssz::ssz_encode(self))
}
}
@@ -83,37 +83,43 @@ where
}
fn tree_hash_root(&self) -> Vec<u8> {
let leaves = match T::tree_hash_type() {
TreeHashType::Basic => {
let mut leaves =
Vec::with_capacity((HASHSIZE / T::tree_hash_packing_factor()) * self.len());
for item in self {
leaves.append(&mut item.tree_hash_packed_encoding());
}
leaves
}
TreeHashType::Composite | TreeHashType::List => {
let mut leaves = Vec::with_capacity(self.len() * HASHSIZE);
for item in self {
leaves.append(&mut item.tree_hash_root())
}
leaves
}
};
// Mix in the length
let mut root_and_len = Vec::with_capacity(HASHSIZE * 2);
root_and_len.append(&mut merkle_root(&leaves));
root_and_len.append(&mut vec_tree_hash_root(self));
root_and_len.append(&mut int_to_bytes32(self.len() as u64));
hash(&root_and_len)
}
}
pub fn vec_tree_hash_root<T>(vec: &[T]) -> Vec<u8>
where
T: TreeHash,
{
let leaves = match T::tree_hash_type() {
TreeHashType::Basic => {
let mut leaves =
Vec::with_capacity((HASHSIZE / T::tree_hash_packing_factor()) * vec.len());
for item in vec {
leaves.append(&mut item.tree_hash_packed_encoding());
}
leaves
}
TreeHashType::Container | TreeHashType::List | TreeHashType::Vector => {
let mut leaves = Vec::with_capacity(vec.len() * HASHSIZE);
for item in vec {
leaves.append(&mut item.tree_hash_root())
}
leaves
}
};
merkle_root(&leaves)
}
#[cfg(test)]
mod test {
use super::*;