Implement tree hash caching (#584)

* Implement basic tree hash caching

* Use spaces to indent top-level Cargo.toml

* Optimize BLS tree hash by hashing bytes directly

* Implement tree hash caching for validator registry

* Persist BeaconState tree hash cache to disk

* Address Paul's review comments
This commit is contained in:
Michael Sproul
2019-11-05 15:46:52 +11:00
committed by GitHub
parent 4ef66a544a
commit c1a2238f1a
38 changed files with 1112 additions and 248 deletions

View File

@@ -131,36 +131,6 @@ impl TreeHash for H256 {
}
}
// TODO: this implementation always panics, it only exists to allow us to compile whilst
// refactoring tree hash. Should be removed.
macro_rules! impl_for_list {
($type: ty) => {
impl<T> TreeHash for $type
where
T: TreeHash,
{
fn tree_hash_type() -> TreeHashType {
unimplemented!("TreeHash is not implemented for Vec or slice")
}
fn tree_hash_packed_encoding(&self) -> Vec<u8> {
unimplemented!("TreeHash is not implemented for Vec or slice")
}
fn tree_hash_packing_factor() -> usize {
unimplemented!("TreeHash is not implemented for Vec or slice")
}
fn tree_hash_root(&self) -> Vec<u8> {
unimplemented!("TreeHash is not implemented for Vec or slice")
}
}
};
}
impl_for_list!(Vec<T>);
impl_for_list!(&[T]);
/// Returns `int` as little-endian bytes with a length of 32.
fn int_to_bytes32(int: u64) -> Vec<u8> {
let mut vec = int.to_le_bytes().to_vec();

View File

@@ -1,6 +1,3 @@
#[macro_use]
extern crate lazy_static;
pub mod impls;
mod merkleize_padded;
mod merkleize_standard;
@@ -27,7 +24,7 @@ pub fn mix_in_length(root: &[u8], length: usize) -> Vec<u8> {
let mut length_bytes = length.to_le_bytes().to_vec();
length_bytes.resize(BYTES_PER_CHUNK, 0);
merkleize_padded::hash_concat(root, &length_bytes)
eth2_hashing::hash_concat(root, &length_bytes)
}
#[derive(Debug, PartialEq, Clone)]

View File

@@ -1,25 +1,10 @@
use super::BYTES_PER_CHUNK;
use eth2_hashing::hash;
use eth2_hashing::{hash, hash_concat, ZERO_HASHES, ZERO_HASHES_MAX_INDEX};
/// The size of the cache that stores padding nodes for a given height.
///
/// Currently, we panic if we encounter a tree with a height larger than `MAX_TREE_DEPTH`.
///
/// It is set to 48 as we expect it to be sufficiently high that we won't exceed it.
pub const MAX_TREE_DEPTH: usize = 48;
lazy_static! {
/// Cached zero hashes where `ZERO_HASHES[i]` is the hash of a Merkle tree with 2^i zero leaves.
static ref ZERO_HASHES: Vec<Vec<u8>> = {
let mut hashes = vec![vec![0; 32]; MAX_TREE_DEPTH + 1];
for i in 0..MAX_TREE_DEPTH {
hashes[i + 1] = hash_concat(&hashes[i], &hashes[i]);
}
hashes
};
}
pub const MAX_TREE_DEPTH: usize = ZERO_HASHES_MAX_INDEX;
/// Merkleize `bytes` and return the root, optionally padding the tree out to `min_leaves` number of
/// leaves.
@@ -236,17 +221,6 @@ fn get_zero_hash(height: usize) -> &'static [u8] {
}
}
/// Concatenate two vectors.
fn concat(mut vec1: Vec<u8>, mut vec2: Vec<u8>) -> Vec<u8> {
vec1.append(&mut vec2);
vec1
}
/// Compute the hash of two other hashes concatenated.
pub fn hash_concat(h1: &[u8], h2: &[u8]) -> Vec<u8> {
hash(&concat(h1.to_vec(), h2.to_vec()))
}
/// Returns the next even number following `n`. If `n` is even, `n` is returned.
fn next_even_number(n: usize) -> usize {
n + n % 2