mirror of
https://github.com/sigp/lighthouse.git
synced 2026-03-20 13:24:44 +00:00
Refactor tree hashing (#861)
* Pre-allocated tree hash caches * Add SmallVec to tree hash cache * Avoid allocation for validator.pubkey * Avoid iterator which seems to be doing heap alloc * Add more smallvecs * MOAR SMALLVEC * Move non-test code to Hash256 tree hash * Fix byte ordering error * Add incomplete but working merkle stream impl * Fix zero hash error * Add zero hash fn * Add MerkleStream comments * Add smallvec, tidy * Integrate into tree hash derive * Update ssz_types tree hash * Don't heap alloc for mix in length * Add byte-level streaming to MerkleStream * Avoid recursion in write method * Update BLS to MerkleStream * Fix some not-compiling tests * Remove debug profiling * Remove code duplication * Move beacon state tree hash to new hasher * Fix failing tests * Update comments * Add some fast-paths to tree_hash::merkle_root * Remove unncessary test * Rename MerkleStream -> MerkleHasher * Rename new_with_leaf_count -> with_leaves * Tidy * Remove NonZeroUsize * Remove todo * Update smallvec
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
use super::*;
|
||||
use core::num::NonZeroUsize;
|
||||
use ethereum_types::{H256, U128, U256};
|
||||
use smallvec::SmallVec;
|
||||
|
||||
macro_rules! impl_decodable_for_uint {
|
||||
($type: ident, $bit_size: expr) => {
|
||||
@@ -364,25 +365,39 @@ macro_rules! impl_decodable_for_u8_array {
|
||||
impl_decodable_for_u8_array!(4);
|
||||
impl_decodable_for_u8_array!(32);
|
||||
|
||||
impl<T: Decode> Decode for Vec<T> {
|
||||
fn is_ssz_fixed_len() -> bool {
|
||||
false
|
||||
}
|
||||
macro_rules! impl_for_vec {
|
||||
($type: ty) => {
|
||||
impl<T: Decode> Decode for $type {
|
||||
fn is_ssz_fixed_len() -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn from_ssz_bytes(bytes: &[u8]) -> Result<Self, DecodeError> {
|
||||
if bytes.is_empty() {
|
||||
Ok(vec![])
|
||||
} else if T::is_ssz_fixed_len() {
|
||||
bytes
|
||||
.chunks(T::ssz_fixed_len())
|
||||
.map(|chunk| T::from_ssz_bytes(chunk))
|
||||
.collect()
|
||||
} else {
|
||||
decode_list_of_variable_length_items(bytes)
|
||||
fn from_ssz_bytes(bytes: &[u8]) -> Result<Self, DecodeError> {
|
||||
if bytes.is_empty() {
|
||||
Ok(vec![].into())
|
||||
} else if T::is_ssz_fixed_len() {
|
||||
bytes
|
||||
.chunks(T::ssz_fixed_len())
|
||||
.map(|chunk| T::from_ssz_bytes(chunk))
|
||||
.collect()
|
||||
} else {
|
||||
decode_list_of_variable_length_items(bytes).map(|vec| vec.into())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_for_vec!(Vec<T>);
|
||||
impl_for_vec!(SmallVec<[T; 1]>);
|
||||
impl_for_vec!(SmallVec<[T; 2]>);
|
||||
impl_for_vec!(SmallVec<[T; 3]>);
|
||||
impl_for_vec!(SmallVec<[T; 4]>);
|
||||
impl_for_vec!(SmallVec<[T; 5]>);
|
||||
impl_for_vec!(SmallVec<[T; 6]>);
|
||||
impl_for_vec!(SmallVec<[T; 7]>);
|
||||
impl_for_vec!(SmallVec<[T; 8]>);
|
||||
|
||||
/// Decodes `bytes` as if it were a list of variable-length items.
|
||||
///
|
||||
/// The `ssz::SszDecoder` can also perform this functionality, however it it significantly faster
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use super::*;
|
||||
use core::num::NonZeroUsize;
|
||||
use ethereum_types::{H256, U128, U256};
|
||||
use smallvec::SmallVec;
|
||||
|
||||
macro_rules! impl_encodable_for_uint {
|
||||
($type: ident, $bit_size: expr) => {
|
||||
@@ -230,40 +231,54 @@ impl<T: Encode> Encode for Option<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Encode> Encode for Vec<T> {
|
||||
fn is_ssz_fixed_len() -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn ssz_bytes_len(&self) -> usize {
|
||||
if <T as Encode>::is_ssz_fixed_len() {
|
||||
<T as Encode>::ssz_fixed_len() * self.len()
|
||||
} else {
|
||||
let mut len = self.iter().map(|item| item.ssz_bytes_len()).sum();
|
||||
len += BYTES_PER_LENGTH_OFFSET * self.len();
|
||||
len
|
||||
}
|
||||
}
|
||||
|
||||
fn ssz_append(&self, buf: &mut Vec<u8>) {
|
||||
if T::is_ssz_fixed_len() {
|
||||
buf.reserve(T::ssz_fixed_len() * self.len());
|
||||
|
||||
for item in self {
|
||||
item.ssz_append(buf);
|
||||
}
|
||||
} else {
|
||||
let mut encoder = SszEncoder::list(buf, self.len() * BYTES_PER_LENGTH_OFFSET);
|
||||
|
||||
for item in self {
|
||||
encoder.append(item);
|
||||
macro_rules! impl_for_vec {
|
||||
($type: ty) => {
|
||||
impl<T: Encode> Encode for $type {
|
||||
fn is_ssz_fixed_len() -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
encoder.finalize();
|
||||
fn ssz_bytes_len(&self) -> usize {
|
||||
if <T as Encode>::is_ssz_fixed_len() {
|
||||
<T as Encode>::ssz_fixed_len() * self.len()
|
||||
} else {
|
||||
let mut len = self.iter().map(|item| item.ssz_bytes_len()).sum();
|
||||
len += BYTES_PER_LENGTH_OFFSET * self.len();
|
||||
len
|
||||
}
|
||||
}
|
||||
|
||||
fn ssz_append(&self, buf: &mut Vec<u8>) {
|
||||
if T::is_ssz_fixed_len() {
|
||||
buf.reserve(T::ssz_fixed_len() * self.len());
|
||||
|
||||
for item in self {
|
||||
item.ssz_append(buf);
|
||||
}
|
||||
} else {
|
||||
let mut encoder = SszEncoder::list(buf, self.len() * BYTES_PER_LENGTH_OFFSET);
|
||||
|
||||
for item in self {
|
||||
encoder.append(item);
|
||||
}
|
||||
|
||||
encoder.finalize();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_for_vec!(Vec<T>);
|
||||
impl_for_vec!(SmallVec<[T; 1]>);
|
||||
impl_for_vec!(SmallVec<[T; 2]>);
|
||||
impl_for_vec!(SmallVec<[T; 3]>);
|
||||
impl_for_vec!(SmallVec<[T; 4]>);
|
||||
impl_for_vec!(SmallVec<[T; 5]>);
|
||||
impl_for_vec!(SmallVec<[T; 6]>);
|
||||
impl_for_vec!(SmallVec<[T; 7]>);
|
||||
impl_for_vec!(SmallVec<[T; 8]>);
|
||||
|
||||
impl Encode for bool {
|
||||
fn is_ssz_fixed_len() -> bool {
|
||||
true
|
||||
|
||||
Reference in New Issue
Block a user