From e038bd18b59033712746de8927dc23f8ce4d2430 Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Sun, 14 Apr 2019 10:34:54 +1000 Subject: [PATCH] Add failing test for grow merkle tree --- eth2/utils/ssz/src/cached_tree_hash.rs | 24 ++++++++++++++++++-- eth2/utils/ssz/src/cached_tree_hash/impls.rs | 24 +++++++++++++++++--- eth2/utils/ssz/src/cached_tree_hash/tests.rs | 2 -- 3 files changed, 43 insertions(+), 7 deletions(-) diff --git a/eth2/utils/ssz/src/cached_tree_hash.rs b/eth2/utils/ssz/src/cached_tree_hash.rs index 84ef82233..42faf1211 100644 --- a/eth2/utils/ssz/src/cached_tree_hash.rs +++ b/eth2/utils/ssz/src/cached_tree_hash.rs @@ -16,6 +16,8 @@ pub enum Error { ShouldNotProduceOffsetHandler, NoFirstNode, NoBytesForRoot, + UnableToObtainSlices, + UnableToGrowMerkleTree, BytesAreNotEvenChunks(usize), NoModifiedFieldForChunk(usize), NoBytesForChunk(usize), @@ -74,6 +76,13 @@ impl TreeHashCache { item.build_tree_hash_cache() } + pub fn from_elems(cache: Vec, chunk_modified: Vec) -> Self { + Self { + cache, + chunk_modified, + } + } + pub fn from_leaves_and_subtrees( item: &T, leaves_and_subtrees: Vec, @@ -149,7 +158,7 @@ impl TreeHashCache { // Update the `chunk_modified` vec, marking all spliced-in nodes as changed. self.chunk_modified.splice(chunk_range.clone(), bools); self.cache - .splice(node_range_to_byte_range(chunk_range), bytes); + .splice(node_range_to_byte_range(&chunk_range), bytes); } pub fn maybe_update_chunk(&mut self, chunk: usize, to: &[u8]) -> Result<(), Error> { @@ -167,6 +176,13 @@ impl TreeHashCache { Ok(()) } + pub fn slices(&self, chunk_range: Range) -> Option<(&[u8], &[bool])> { + Some(( + self.cache.get(node_range_to_byte_range(&chunk_range))?, + self.chunk_modified.get(chunk_range)?, + )) + } + pub fn modify_chunk(&mut self, chunk: usize, to: &[u8]) -> Result<(), Error> { let start = chunk * BYTES_PER_CHUNK; let end = start + BYTES_PER_CHUNK; @@ -231,7 +247,7 @@ fn num_nodes(num_leaves: usize) -> usize { 2 * num_leaves - 1 } -fn node_range_to_byte_range(node_range: Range) -> Range { +fn node_range_to_byte_range(node_range: &Range) -> Range { node_range.start * HASHSIZE..node_range.end * HASHSIZE } @@ -281,6 +297,10 @@ impl OffsetHandler { }) } + pub fn node_range(&self) -> Result, Error> { + Ok(*self.offsets.first().ok_or_else(|| Error::NoFirstNode)?..self.next_node()) + } + pub fn total_nodes(&self) -> usize { self.num_internal_nodes + self.num_leaf_nodes } diff --git a/eth2/utils/ssz/src/cached_tree_hash/impls.rs b/eth2/utils/ssz/src/cached_tree_hash/impls.rs index dca00b6ba..2010aeb0d 100644 --- a/eth2/utils/ssz/src/cached_tree_hash/impls.rs +++ b/eth2/utils/ssz/src/cached_tree_hash/impls.rs @@ -113,9 +113,27 @@ where ) -> Result { let offset_handler = OffsetHandler::new(self, chunk)?; - if other.len().next_power_of_two() > self.len().next_power_of_two() { - // - } else if other.len().next_power_of_two() < self.len().next_power_of_two() { + if self.len().next_power_of_two() > other.len().next_power_of_two() { + // Get slices of the exsiting tree from the cache. + let (old_bytes, old_flags) = cache + .slices(offset_handler.node_range()?) + .ok_or_else(|| Error::UnableToObtainSlices)?; + + // From the existing slices build new, expanded Vecs. + let (new_bytes, new_flags) = grow_merkle_cache( + old_bytes, + old_flags, + other.len().next_power_of_two().leading_zeros() as usize, + self.len().next_power_of_two().leading_zeros() as usize, + ).ok_or_else(|| Error::UnableToGrowMerkleTree)?; + + // Create a `TreeHashCache` from the raw elements. + let expanded_cache = TreeHashCache::from_elems(new_bytes, new_flags); + + // Splice the newly created `TreeHashCache` over the existing, smaller elements. + cache.splice(offset_handler.node_range()?, expanded_cache); + // + } else if self.len().next_power_of_two() < other.len().next_power_of_two() { panic!("shrinking below power of two is not implemented") } diff --git a/eth2/utils/ssz/src/cached_tree_hash/tests.rs b/eth2/utils/ssz/src/cached_tree_hash/tests.rs index 9b8e81bc9..c402fd15b 100644 --- a/eth2/utils/ssz/src/cached_tree_hash/tests.rs +++ b/eth2/utils/ssz/src/cached_tree_hash/tests.rs @@ -408,7 +408,6 @@ fn extended_u64_vec_len_within_pow_2_boundary() { test_u64_vec_modifications(original_vec, modified_vec); } -/* #[test] fn extended_u64_vec_len_outside_pow_2_boundary() { let original_vec: Vec = (0..2_u64.pow(5)).collect(); @@ -417,7 +416,6 @@ fn extended_u64_vec_len_outside_pow_2_boundary() { test_u64_vec_modifications(original_vec, modified_vec); } -*/ #[test] fn large_vec_of_u64_builds() {