From d311b48a9f35f4463939bbf50efbe65eea7a5261 Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Tue, 16 Apr 2019 09:34:23 +1000 Subject: [PATCH] Unify tree hash methods --- eth2/utils/tree_hash/src/cached_tree_hash.rs | 10 +- .../tree_hash/src/cached_tree_hash/impls.rs | 12 -- .../src/cached_tree_hash/impls/vec.rs | 36 ++---- eth2/utils/tree_hash/src/lib.rs | 5 +- .../utils/tree_hash/src/standard_tree_hash.rs | 37 ++++--- eth2/utils/tree_hash/tests/tests.rs | 103 ++++++++++-------- 6 files changed, 101 insertions(+), 102 deletions(-) diff --git a/eth2/utils/tree_hash/src/cached_tree_hash.rs b/eth2/utils/tree_hash/src/cached_tree_hash.rs index fc12cfbba..43c0ba2fe 100644 --- a/eth2/utils/tree_hash/src/cached_tree_hash.rs +++ b/eth2/utils/tree_hash/src/cached_tree_hash.rs @@ -17,7 +17,7 @@ pub enum Error { UnableToObtainSlices, UnableToGrowMerkleTree, UnableToShrinkMerkleTree, - ShouldNeverBePacked(ItemType), + ShouldNeverBePacked(TreeHashType), BytesAreNotEvenChunks(usize), NoModifiedFieldForChunk(usize), NoBytesForChunk(usize), @@ -31,15 +31,9 @@ pub trait CachedTreeHash: CachedTreeHashSubTree + Sized { fn clone_without_tree_hash_cache(&self) -> Self; } -pub trait CachedTreeHashSubTree { - fn item_type() -> ItemType; - +pub trait CachedTreeHashSubTree: TreeHash { fn btree_overlay(&self, chunk_offset: usize) -> Result; - fn packed_encoding(&self) -> Result, Error>; - - fn packing_factor() -> usize; - fn new_cache(&self) -> Result; fn update_cache( diff --git a/eth2/utils/tree_hash/src/cached_tree_hash/impls.rs b/eth2/utils/tree_hash/src/cached_tree_hash/impls.rs index 982e98724..190deaf27 100644 --- a/eth2/utils/tree_hash/src/cached_tree_hash/impls.rs +++ b/eth2/utils/tree_hash/src/cached_tree_hash/impls.rs @@ -5,10 +5,6 @@ use ssz::ssz_encode; mod vec; impl CachedTreeHashSubTree for u64 { - fn item_type() -> ItemType { - ItemType::Basic - } - fn new_cache(&self) -> Result { Ok(TreeHashCache::from_bytes( merkleize(ssz_encode(self)), @@ -20,14 +16,6 @@ impl CachedTreeHashSubTree for u64 { BTreeOverlay::from_lengths(chunk_offset, vec![1]) } - fn packed_encoding(&self) -> Result, Error> { - Ok(ssz_encode(self)) - } - - fn packing_factor() -> usize { - HASHSIZE / 8 - } - fn update_cache( &self, other: &Self, diff --git a/eth2/utils/tree_hash/src/cached_tree_hash/impls/vec.rs b/eth2/utils/tree_hash/src/cached_tree_hash/impls/vec.rs index a6fad9ba6..bc86e6054 100644 --- a/eth2/utils/tree_hash/src/cached_tree_hash/impls/vec.rs +++ b/eth2/utils/tree_hash/src/cached_tree_hash/impls/vec.rs @@ -2,18 +2,14 @@ use super::*; impl CachedTreeHashSubTree> for Vec where - T: CachedTreeHashSubTree, + T: CachedTreeHashSubTree + TreeHash, { - fn item_type() -> ItemType { - ItemType::List - } - fn new_cache(&self) -> Result { - match T::item_type() { - ItemType::Basic => { + match T::tree_hash_type() { + TreeHashType::Basic => { TreeHashCache::from_bytes(merkleize(get_packed_leaves(self)?), false) } - ItemType::Composite | ItemType::List => { + TreeHashType::Composite | TreeHashType::List => { let subtrees = self .iter() .map(|item| TreeHashCache::new(item)) @@ -25,9 +21,9 @@ where } fn btree_overlay(&self, chunk_offset: usize) -> Result { - let lengths = match T::item_type() { - ItemType::Basic => vec![1; self.len() / T::packing_factor()], - ItemType::Composite | ItemType::List => { + let lengths = match T::tree_hash_type() { + TreeHashType::Basic => vec![1; self.len() / T::tree_hash_packing_factor()], + TreeHashType::Composite | TreeHashType::List => { let mut lengths = vec![]; for item in self { @@ -41,14 +37,6 @@ where BTreeOverlay::from_lengths(chunk_offset, lengths) } - fn packed_encoding(&self) -> Result, Error> { - Err(Error::ShouldNeverBePacked(Self::item_type())) - } - - fn packing_factor() -> usize { - 1 - } - fn update_cache( &self, other: &Vec, @@ -93,8 +81,8 @@ where cache.splice(old_offset_handler.chunk_range(), modified_cache); } - match T::item_type() { - ItemType::Basic => { + match T::tree_hash_type() { + TreeHashType::Basic => { let leaves = get_packed_leaves(self)?; for (i, chunk) in offset_handler.iter_leaf_nodes().enumerate() { @@ -109,7 +97,7 @@ where TreeHashCache::from_bytes(leaves, true)?, ); } - ItemType::Composite | ItemType::List => { + TreeHashType::Composite | TreeHashType::List => { let mut i = offset_handler.num_leaf_nodes; for &start_chunk in offset_handler.iter_leaf_nodes().rev() { i -= 1; @@ -170,13 +158,13 @@ fn get_packed_leaves(vec: &Vec) -> Result, Error> where T: CachedTreeHashSubTree, { - let num_packed_bytes = (BYTES_PER_CHUNK / T::packing_factor()) * vec.len(); + let num_packed_bytes = (BYTES_PER_CHUNK / T::tree_hash_packing_factor()) * vec.len(); let num_leaves = num_sanitized_leaves(num_packed_bytes); let mut packed = Vec::with_capacity(num_leaves * HASHSIZE); for item in vec { - packed.append(&mut item.packed_encoding()?); + packed.append(&mut item.tree_hash_packed_encoding()); } Ok(sanitise_bytes(packed)) diff --git a/eth2/utils/tree_hash/src/lib.rs b/eth2/utils/tree_hash/src/lib.rs index 4e5302bca..0f0fb60f4 100644 --- a/eth2/utils/tree_hash/src/lib.rs +++ b/eth2/utils/tree_hash/src/lib.rs @@ -5,8 +5,11 @@ pub const BYTES_PER_CHUNK: usize = 32; pub const HASHSIZE: usize = 32; pub const MERKLE_HASH_CHUNCK: usize = 2 * BYTES_PER_CHUNK; +pub use cached_tree_hash::CachedTreeHashSubTree; +pub use standard_tree_hash::TreeHash; + #[derive(Debug, PartialEq, Clone)] -pub enum ItemType { +pub enum TreeHashType { Basic, List, Composite, diff --git a/eth2/utils/tree_hash/src/standard_tree_hash.rs b/eth2/utils/tree_hash/src/standard_tree_hash.rs index c8119a790..e7f94560b 100644 --- a/eth2/utils/tree_hash/src/standard_tree_hash.rs +++ b/eth2/utils/tree_hash/src/standard_tree_hash.rs @@ -4,23 +4,29 @@ use int_to_bytes::int_to_bytes32; use ssz::ssz_encode; pub trait TreeHash { - fn tree_hash_item_type() -> ItemType; + fn tree_hash_type() -> TreeHashType; fn tree_hash_packed_encoding(&self) -> Vec; - fn hash_tree_root(&self) -> Vec; + fn tree_hash_packing_factor() -> usize; + + fn tree_hash_root(&self) -> Vec; } impl TreeHash for u64 { - fn tree_hash_item_type() -> ItemType { - ItemType::Basic + fn tree_hash_type() -> TreeHashType { + TreeHashType::Basic } fn tree_hash_packed_encoding(&self) -> Vec { ssz_encode(self) } - fn hash_tree_root(&self) -> Vec { + fn tree_hash_packing_factor() -> usize { + HASHSIZE / 8 + } + + fn tree_hash_root(&self) -> Vec { int_to_bytes32(*self) } } @@ -29,18 +35,23 @@ impl TreeHash for Vec where T: TreeHash, { - fn tree_hash_item_type() -> ItemType { - ItemType::List + fn tree_hash_type() -> TreeHashType { + TreeHashType::List } fn tree_hash_packed_encoding(&self) -> Vec { unreachable!("List should never be packed.") } - fn hash_tree_root(&self) -> Vec { - let leaves = match T::tree_hash_item_type() { - ItemType::Basic => { - let mut leaves = vec![]; + fn tree_hash_packing_factor() -> usize { + unreachable!("List should never be packed.") + } + + fn tree_hash_root(&self) -> Vec { + 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()); @@ -48,11 +59,11 @@ where leaves } - ItemType::Composite | ItemType::List => { + TreeHashType::Composite | TreeHashType::List => { let mut leaves = Vec::with_capacity(self.len() * HASHSIZE); for item in self { - leaves.append(&mut item.hash_tree_root()) + leaves.append(&mut item.tree_hash_root()) } leaves diff --git a/eth2/utils/tree_hash/tests/tests.rs b/eth2/utils/tree_hash/tests/tests.rs index d65192cd5..f52a17272 100644 --- a/eth2/utils/tree_hash/tests/tests.rs +++ b/eth2/utils/tree_hash/tests/tests.rs @@ -11,6 +11,29 @@ pub struct InternalCache { pub cache: Option, } +impl TreeHash for InternalCache { + fn tree_hash_type() -> TreeHashType { + TreeHashType::Composite + } + + fn tree_hash_packed_encoding(&self) -> Vec { + unreachable!("Struct should never be packed.") + } + + fn tree_hash_packing_factor() -> usize { + unreachable!("Struct should never be packed.") + } + + fn tree_hash_root(&self) -> Vec { + let mut leaves = Vec::with_capacity(4 * HASHSIZE); + + leaves.append(&mut self.a.tree_hash_root()); + leaves.append(&mut self.b.tree_hash_root()); + + efficient_merkleize(&leaves)[0..32].to_vec() + } +} + impl CachedTreeHash for InternalCache { fn update_internal_tree_hash_cache(mut self, mut old: Self) -> Result<(Self, Self), Error> { let mut local_cache = old.cache; @@ -66,10 +89,6 @@ fn works_when_embedded() { } impl CachedTreeHashSubTree for InternalCache { - fn item_type() -> ItemType { - ItemType::Composite - } - fn new_cache(&self) -> Result { let tree = TreeHashCache::from_leaves_and_subtrees( self, @@ -88,14 +107,6 @@ impl CachedTreeHashSubTree for InternalCache { BTreeOverlay::from_lengths(chunk_offset, lengths) } - fn packed_encoding(&self) -> Result, Error> { - Err(Error::ShouldNeverBePacked(Self::item_type())) - } - - fn packing_factor() -> usize { - 1 - } - fn update_cache( &self, other: &Self, @@ -134,31 +145,31 @@ pub struct Inner { } impl TreeHash for Inner { - fn tree_hash_item_type() -> ItemType { - ItemType::Composite + fn tree_hash_type() -> TreeHashType { + TreeHashType::Composite } fn tree_hash_packed_encoding(&self) -> Vec { unreachable!("Struct should never be packed.") } - fn hash_tree_root(&self) -> Vec { + fn tree_hash_packing_factor() -> usize { + unreachable!("Struct should never be packed.") + } + + fn tree_hash_root(&self) -> Vec { let mut leaves = Vec::with_capacity(4 * HASHSIZE); - leaves.append(&mut self.a.hash_tree_root()); - leaves.append(&mut self.b.hash_tree_root()); - leaves.append(&mut self.c.hash_tree_root()); - leaves.append(&mut self.d.hash_tree_root()); + leaves.append(&mut self.a.tree_hash_root()); + leaves.append(&mut self.b.tree_hash_root()); + leaves.append(&mut self.c.tree_hash_root()); + leaves.append(&mut self.d.tree_hash_root()); efficient_merkleize(&leaves)[0..32].to_vec() } } impl CachedTreeHashSubTree for Inner { - fn item_type() -> ItemType { - ItemType::Composite - } - fn new_cache(&self) -> Result { let tree = TreeHashCache::from_leaves_and_subtrees( self, @@ -184,14 +195,6 @@ impl CachedTreeHashSubTree for Inner { BTreeOverlay::from_lengths(chunk_offset, lengths) } - fn packed_encoding(&self) -> Result, Error> { - Err(Error::ShouldNeverBePacked(Self::item_type())) - } - - fn packing_factor() -> usize { - 1 - } - fn update_cache( &self, other: &Self, @@ -226,11 +229,31 @@ pub struct Outer { pub c: u64, } -impl CachedTreeHashSubTree for Outer { - fn item_type() -> ItemType { - ItemType::Composite +impl TreeHash for Outer { + fn tree_hash_type() -> TreeHashType { + TreeHashType::Composite } + fn tree_hash_packed_encoding(&self) -> Vec { + unreachable!("Struct should never be packed.") + } + + fn tree_hash_packing_factor() -> usize { + unreachable!("Struct should never be packed.") + } + + fn tree_hash_root(&self) -> Vec { + let mut leaves = Vec::with_capacity(4 * HASHSIZE); + + leaves.append(&mut self.a.tree_hash_root()); + leaves.append(&mut self.b.tree_hash_root()); + leaves.append(&mut self.c.tree_hash_root()); + + efficient_merkleize(&leaves)[0..32].to_vec() + } +} + +impl CachedTreeHashSubTree for Outer { fn new_cache(&self) -> Result { let tree = TreeHashCache::from_leaves_and_subtrees( self, @@ -254,14 +277,6 @@ impl CachedTreeHashSubTree for Outer { BTreeOverlay::from_lengths(chunk_offset, lengths) } - fn packed_encoding(&self) -> Result, Error> { - Err(Error::ShouldNeverBePacked(Self::item_type())) - } - - fn packing_factor() -> usize { - 1 - } - fn update_cache( &self, other: &Self, @@ -481,7 +496,7 @@ fn test_u64_vec_modifications(original: Vec, modified: Vec) { mix_in_length(&mut expected[0..HASHSIZE], modified.len()); assert_eq!(expected, modified_cache); - assert_eq!(&expected[0..32], &modified.hash_tree_root()[..]); + assert_eq!(&expected[0..32], &modified.tree_hash_root()[..]); } #[test] @@ -604,7 +619,7 @@ fn test_inner_vec_modifications(original: Vec, modified: Vec, refe // Compare the cached tree to the reference tree. assert_trees_eq(&expected, &modified_cache); - assert_eq!(&expected[0..32], &modified.hash_tree_root()[..]); + assert_eq!(&expected[0..32], &modified.tree_hash_root()[..]); } #[test]