From 5340c49de702e8d1127ffc69d5974148586e234c Mon Sep 17 00:00:00 2001 From: Michael Sproul Date: Tue, 15 Feb 2022 16:52:33 +1100 Subject: [PATCH] Use smallvec for tree hash packed encoding --- Cargo.toml | 1 + consensus/ssz_types/src/bitfield.rs | 4 +- consensus/ssz_types/src/fixed_vector.rs | 2 +- consensus/ssz_types/src/variable_list.rs | 2 +- consensus/tree_hash/src/impls.rs | 25 ++++++----- consensus/tree_hash/src/lib.rs | 52 ++-------------------- consensus/tree_hash_derive/src/lib.rs | 6 +-- consensus/types/src/graffiti.rs | 2 +- consensus/types/src/participation_flags.rs | 2 +- consensus/types/src/slot_epoch.rs | 2 +- consensus/types/src/slot_epoch_macros.rs | 4 +- crypto/bls/src/macros.rs | 2 +- 12 files changed, 31 insertions(+), 73 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f5bb36ac53..1180e4d195 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -91,6 +91,7 @@ warp = { git = "https://github.com/macladson/warp", rev ="7e75acc" } eth2_ssz = { path = "consensus/ssz" } eth2_ssz_types = { path = "consensus/ssz_types" } tree_hash = { path = "consensus/tree_hash" } +tree_hash_derive = { path = "consensus/tree_hash_derive" } eth2_serde_utils = { path = "consensus/serde_utils" } [profile.release] diff --git a/consensus/ssz_types/src/bitfield.rs b/consensus/ssz_types/src/bitfield.rs index dfad3aedcb..57b262bea1 100644 --- a/consensus/ssz_types/src/bitfield.rs +++ b/consensus/ssz_types/src/bitfield.rs @@ -611,7 +611,7 @@ impl tree_hash::TreeHash for Bitfield> { tree_hash::TreeHashType::List } - fn tree_hash_packed_encoding(&self) -> Vec { + fn tree_hash_packed_encoding(&self) -> tree_hash::PackedEncoding { unreachable!("List should never be packed.") } @@ -632,7 +632,7 @@ impl tree_hash::TreeHash for Bitfield> { tree_hash::TreeHashType::Vector } - fn tree_hash_packed_encoding(&self) -> Vec { + fn tree_hash_packed_encoding(&self) -> tree_hash::PackedEncoding { unreachable!("Vector should never be packed.") } diff --git a/consensus/ssz_types/src/fixed_vector.rs b/consensus/ssz_types/src/fixed_vector.rs index ca5d40f14f..53aab99391 100644 --- a/consensus/ssz_types/src/fixed_vector.rs +++ b/consensus/ssz_types/src/fixed_vector.rs @@ -167,7 +167,7 @@ where tree_hash::TreeHashType::Vector } - fn tree_hash_packed_encoding(&self) -> Vec { + fn tree_hash_packed_encoding(&self) -> tree_hash::PackedEncoding { unreachable!("Vector should never be packed.") } diff --git a/consensus/ssz_types/src/variable_list.rs b/consensus/ssz_types/src/variable_list.rs index 1414d12c8c..a3e8c5d550 100644 --- a/consensus/ssz_types/src/variable_list.rs +++ b/consensus/ssz_types/src/variable_list.rs @@ -184,7 +184,7 @@ where tree_hash::TreeHashType::List } - fn tree_hash_packed_encoding(&self) -> Vec { + fn tree_hash_packed_encoding(&self) -> tree_hash::PackedEncoding { unreachable!("List should never be packed.") } diff --git a/consensus/tree_hash/src/impls.rs b/consensus/tree_hash/src/impls.rs index 00fed489c7..2c7ade30d0 100644 --- a/consensus/tree_hash/src/impls.rs +++ b/consensus/tree_hash/src/impls.rs @@ -1,5 +1,6 @@ use super::*; use ethereum_types::{H160, H256, U128, U256}; +use smallvec::{smallvec, ToSmallVec}; fn int_to_hash256(int: u64) -> Hash256 { let mut bytes = [0; HASHSIZE]; @@ -14,8 +15,8 @@ macro_rules! impl_for_bitsize { TreeHashType::Basic } - fn tree_hash_packed_encoding(&self) -> Vec { - self.to_le_bytes().to_vec() + fn tree_hash_packed_encoding(&self) -> PackedEncoding { + self.to_le_bytes().to_smallvec() } fn tree_hash_packing_factor() -> usize { @@ -41,7 +42,7 @@ impl TreeHash for bool { TreeHashType::Basic } - fn tree_hash_packed_encoding(&self) -> Vec { + fn tree_hash_packed_encoding(&self) -> PackedEncoding { (*self as u8).tree_hash_packed_encoding() } @@ -62,7 +63,7 @@ macro_rules! impl_for_lt_32byte_u8_array { TreeHashType::Vector } - fn tree_hash_packed_encoding(&self) -> Vec { + fn tree_hash_packed_encoding(&self) -> PackedEncoding { unreachable!("bytesN should never be packed.") } @@ -87,8 +88,8 @@ impl TreeHash for U128 { TreeHashType::Basic } - fn tree_hash_packed_encoding(&self) -> Vec { - let mut result = vec![0; 16]; + fn tree_hash_packed_encoding(&self) -> PackedEncoding { + let mut result = smallvec![0; 16]; self.to_little_endian(&mut result); result } @@ -109,8 +110,8 @@ impl TreeHash for U256 { TreeHashType::Basic } - fn tree_hash_packed_encoding(&self) -> Vec { - let mut result = vec![0; 32]; + fn tree_hash_packed_encoding(&self) -> PackedEncoding { + let mut result = smallvec![0; 32]; self.to_little_endian(&mut result); result } @@ -131,8 +132,8 @@ impl TreeHash for H160 { TreeHashType::Vector } - fn tree_hash_packed_encoding(&self) -> Vec { - let mut result = vec![0; 32]; + fn tree_hash_packed_encoding(&self) -> PackedEncoding { + let mut result = smallvec![0; 32]; result[0..20].copy_from_slice(self.as_bytes()); result } @@ -153,8 +154,8 @@ impl TreeHash for H256 { TreeHashType::Vector } - fn tree_hash_packed_encoding(&self) -> Vec { - self.as_bytes().to_vec() + fn tree_hash_packed_encoding(&self) -> PackedEncoding { + self.as_bytes().to_smallvec() } fn tree_hash_packing_factor() -> usize { diff --git a/consensus/tree_hash/src/lib.rs b/consensus/tree_hash/src/lib.rs index 997ae867f7..d6ffe7b072 100644 --- a/consensus/tree_hash/src/lib.rs +++ b/consensus/tree_hash/src/lib.rs @@ -8,6 +8,7 @@ pub use merkleize_padded::merkleize_padded; pub use merkleize_standard::merkleize_standard; use eth2_hashing::{hash_fixed, ZERO_HASHES, ZERO_HASHES_MAX_INDEX}; +use smallvec::SmallVec; pub const BYTES_PER_CHUNK: usize = 32; pub const HASHSIZE: usize = 32; @@ -15,6 +16,7 @@ pub const MERKLE_HASH_CHUNK: usize = 2 * BYTES_PER_CHUNK; pub const MAX_UNION_SELECTOR: u8 = 127; pub type Hash256 = ethereum_types::H256; +pub type PackedEncoding = SmallVec<[u8; BYTES_PER_CHUNK]>; /// Convenience method for `MerkleHasher` which also provides some fast-paths for small trees. /// @@ -109,7 +111,7 @@ pub enum TreeHashType { pub trait TreeHash { fn tree_hash_type() -> TreeHashType; - fn tree_hash_packed_encoding(&self) -> Vec; + fn tree_hash_packed_encoding(&self) -> PackedEncoding; fn tree_hash_packing_factor() -> usize; @@ -125,7 +127,7 @@ where T::tree_hash_type() } - fn tree_hash_packed_encoding(&self) -> Vec { + fn tree_hash_packed_encoding(&self) -> PackedEncoding { T::tree_hash_packed_encoding(*self) } @@ -138,52 +140,6 @@ where } } -#[macro_export] -macro_rules! tree_hash_ssz_encoding_as_vector { - ($type: ident) => { - impl tree_hash::TreeHash for $type { - fn tree_hash_type() -> tree_hash::TreeHashType { - tree_hash::TreeHashType::Vector - } - - fn tree_hash_packed_encoding(&self) -> Vec { - unreachable!("Vector should never be packed.") - } - - fn tree_hash_packing_factor() -> usize { - unreachable!("Vector should never be packed.") - } - - fn tree_hash_root(&self) -> Vec { - tree_hash::merkle_root(&ssz::ssz_encode(self)) - } - } - }; -} - -#[macro_export] -macro_rules! tree_hash_ssz_encoding_as_list { - ($type: ident) => { - impl tree_hash::TreeHash for $type { - fn tree_hash_type() -> tree_hash::TreeHashType { - tree_hash::TreeHashType::List - } - - fn tree_hash_packed_encoding(&self) -> Vec { - unreachable!("List should never be packed.") - } - - fn tree_hash_packing_factor() -> usize { - unreachable!("List should never be packed.") - } - - fn tree_hash_root(&self) -> Vec { - ssz::ssz_encode(self).tree_hash_root() - } - } - }; -} - #[cfg(test)] mod test { use super::*; diff --git a/consensus/tree_hash_derive/src/lib.rs b/consensus/tree_hash_derive/src/lib.rs index f2695b1f8b..4cbec9a814 100644 --- a/consensus/tree_hash_derive/src/lib.rs +++ b/consensus/tree_hash_derive/src/lib.rs @@ -150,7 +150,7 @@ fn tree_hash_derive_struct(item: &DeriveInput, struct_data: &DataStruct) -> Toke tree_hash::TreeHashType::Container } - fn tree_hash_packed_encoding(&self) -> Vec { + fn tree_hash_packed_encoding(&self) -> tree_hash::PackedEncoding { unreachable!("Struct should never be packed.") } @@ -231,7 +231,7 @@ fn tree_hash_derive_enum_transparent( tree_hash::TreeHashType::Container } - fn tree_hash_packed_encoding(&self) -> Vec { + fn tree_hash_packed_encoding(&self) -> tree_hash::PackedEncoding { unreachable!("Enum should never be packed") } @@ -288,7 +288,7 @@ fn tree_hash_derive_enum_union(derive_input: &DeriveInput, enum_data: &DataEnum) tree_hash::TreeHashType::Container } - fn tree_hash_packed_encoding(&self) -> Vec { + fn tree_hash_packed_encoding(&self) -> tree_hash::PackedEncoding { unreachable!("Enum should never be packed") } diff --git a/consensus/types/src/graffiti.rs b/consensus/types/src/graffiti.rs index f5f74b601b..91e41600fc 100644 --- a/consensus/types/src/graffiti.rs +++ b/consensus/types/src/graffiti.rs @@ -159,7 +159,7 @@ impl TreeHash for Graffiti { <[u8; GRAFFITI_BYTES_LEN]>::tree_hash_type() } - fn tree_hash_packed_encoding(&self) -> Vec { + fn tree_hash_packed_encoding(&self) -> tree_hash::PackedEncoding { self.0.tree_hash_packed_encoding() } diff --git a/consensus/types/src/participation_flags.rs b/consensus/types/src/participation_flags.rs index 74c2cf73ba..80835521b6 100644 --- a/consensus/types/src/participation_flags.rs +++ b/consensus/types/src/participation_flags.rs @@ -78,7 +78,7 @@ impl TreeHash for ParticipationFlags { u8::tree_hash_type() } - fn tree_hash_packed_encoding(&self) -> Vec { + fn tree_hash_packed_encoding(&self) -> tree_hash::PackedEncoding { self.bits.tree_hash_packed_encoding() } diff --git a/consensus/types/src/slot_epoch.rs b/consensus/types/src/slot_epoch.rs index e68055d34d..277aa9deae 100644 --- a/consensus/types/src/slot_epoch.rs +++ b/consensus/types/src/slot_epoch.rs @@ -16,7 +16,7 @@ use crate::{ChainSpec, SignedRoot}; use rand::RngCore; use safe_arith::{ArithError, SafeArith}; use serde_derive::{Deserialize, Serialize}; -use ssz::{ssz_encode, Decode, DecodeError, Encode}; +use ssz::{Decode, DecodeError, Encode}; use std::fmt; use std::hash::Hash; use std::iter::Iterator; diff --git a/consensus/types/src/slot_epoch_macros.rs b/consensus/types/src/slot_epoch_macros.rs index b8e6202fe3..fafc455ef8 100644 --- a/consensus/types/src/slot_epoch_macros.rs +++ b/consensus/types/src/slot_epoch_macros.rs @@ -290,8 +290,8 @@ macro_rules! impl_ssz { tree_hash::TreeHashType::Basic } - fn tree_hash_packed_encoding(&self) -> Vec { - ssz_encode(self) + fn tree_hash_packed_encoding(&self) -> tree_hash::PackedEncoding { + self.0.tree_hash_packed_encoding() } fn tree_hash_packing_factor() -> usize { diff --git a/crypto/bls/src/macros.rs b/crypto/bls/src/macros.rs index a5fce70a96..f3a7374ba7 100644 --- a/crypto/bls/src/macros.rs +++ b/crypto/bls/src/macros.rs @@ -7,7 +7,7 @@ macro_rules! impl_tree_hash { tree_hash::TreeHashType::Vector } - fn tree_hash_packed_encoding(&self) -> Vec { + fn tree_hash_packed_encoding(&self) -> tree_hash::PackedEncoding { unreachable!("Vector should never be packed.") }