From e7ed4e00ea63721369218f64de05634ad8784f58 Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Fri, 31 Jan 2025 12:57:36 -0700 Subject: [PATCH 1/3] incrementalmerkletree: Allow test-dependencies construction of invalid legacy incremental witnesses. --- incrementalmerkletree/CHANGELOG.md | 6 ++++++ incrementalmerkletree/src/witness.rs | 22 +++++++++++++++++++--- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/incrementalmerkletree/CHANGELOG.md b/incrementalmerkletree/CHANGELOG.md index f9f7669..90db2e7 100644 --- a/incrementalmerkletree/CHANGELOG.md +++ b/incrementalmerkletree/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to Rust's notion of ## Unreleased +### Added +- `incrementalmerkletree::witness::IncrementalWitness::invalid_empty_witness` + has been under the `test-dependencies` feature flag to permit use testing + against `zcashd` test vectors that depend upon appending nodes to the + (invalid) empty witness. + ## [0.8.1] - 2024-12-11 ### Changed diff --git a/incrementalmerkletree/src/witness.rs b/incrementalmerkletree/src/witness.rs index 0c9e441..6b46ad8 100644 --- a/incrementalmerkletree/src/witness.rs +++ b/incrementalmerkletree/src/witness.rs @@ -57,16 +57,32 @@ impl IncrementalWitness { }) } + /// Creates an invalid empty `IncrementalWitness`. This constructor is provided for backwards + /// compatibility with the encodings of `zcashd` `IncrementalWitness` values; that type permits + /// multiple distinct encodings of the same witness state, and in some cases it is necessary to + /// create an empty witness and then append leaves in order to obtain the encoded forms + /// produced by `zcashd` (and which we must reproduce in order to demonstrate interoperability + /// with `zcashd` test vectors.) This should not be used except in a testing context. + #[cfg(feature = "test-dependencies")] + pub fn invalid_empty_witness() -> Self { + Self { + tree: CommitmentTree::empty(), + filled: vec![], + cursor_depth: 0, + cursor: None, + } + } + /// Constructs an `IncrementalWitness` from its parts. /// - /// Returns `None` if the parts do not form a valid witness, for example if `tree` is - /// empty (and thus there is no position to witness). + /// Returns `None` if the parts do not form a valid witness, for example if all of the parts + /// are empty (and thus there is no position to witness). pub fn from_parts( tree: CommitmentTree, filled: Vec, cursor: Option>, ) -> Option { - (!tree.is_empty()).then(|| { + (!(tree.is_empty() && filled.is_empty() && cursor.is_none())).then(|| { let mut witness = IncrementalWitness { tree, filled, From 9edc305fa1aca8104317720607b81a5ec8b61377 Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Fri, 31 Jan 2025 13:02:25 -0700 Subject: [PATCH 2/3] Fix clippy beta lints --- .../src/complete_tree.rs | 12 +++++------ incrementalmerkletree-testing/src/lib.rs | 4 ++-- incrementalmerkletree/src/lib.rs | 4 ++-- shardtree/src/store/caching.rs | 4 ++-- shardtree/src/testing.rs | 20 +++++++++---------- 5 files changed, 21 insertions(+), 23 deletions(-) diff --git a/incrementalmerkletree-testing/src/complete_tree.rs b/incrementalmerkletree-testing/src/complete_tree.rs index b4f4460..d7eefe7 100644 --- a/incrementalmerkletree-testing/src/complete_tree.rs +++ b/incrementalmerkletree-testing/src/complete_tree.rs @@ -106,7 +106,7 @@ impl CompleteTr self.mark(); } Retention::Checkpoint { id, marking } => { - let latest_checkpoint = self.checkpoints.keys().rev().next(); + let latest_checkpoint = self.checkpoints.keys().next_back(); if Some(&id) > latest_checkpoint { append(&mut self.leaves, value, DEPTH)?; if marking == Marking::Marked { @@ -145,7 +145,7 @@ impl CompleteTr if !self.marks.contains(&pos) { self.marks.insert(pos); - if let Some(checkpoint) = self.checkpoints.values_mut().rev().next() { + if let Some(checkpoint) = self.checkpoints.values_mut().next_back() { checkpoint.marked.insert(pos); } } @@ -277,7 +277,7 @@ impl bool { if self.marks.contains(&position) { - if let Some(c) = self.checkpoints.values_mut().rev().next() { + if let Some(c) = self.checkpoints.values_mut().next_back() { c.forgotten.insert(position); } else { self.marks.remove(&position); @@ -289,7 +289,7 @@ impl bool { - if Some(&id) > self.checkpoints.keys().rev().next() { + if Some(&id) > self.checkpoints.keys().next_back() { Self::checkpoint(self, id, self.current_position()); true } else { @@ -335,8 +335,6 @@ impl, F: Fn(usiz } pub fn check_remove_mark, F: Fn(usize) -> T>(new_tree: F) { - let samples = vec![ + let samples = [ vec![ append_str("a", Retention::Ephemeral), append_str( @@ -1126,7 +1126,7 @@ pub fn check_rewind_remove_mark, F: Fn(usi // test framework itself previously did not correctly handle // chain state restoration. - let samples = vec![ + let samples = [ vec![ append_str("x", Retention::Marked), Checkpoint(C::from_u64(1)), diff --git a/incrementalmerkletree/src/lib.rs b/incrementalmerkletree/src/lib.rs index 939a235..e11e574 100644 --- a/incrementalmerkletree/src/lib.rs +++ b/incrementalmerkletree/src/lib.rs @@ -466,13 +466,13 @@ impl Address { /// Returns the minimum value among the range of leaf positions that are contained within the /// tree with its root at this address. pub fn position_range_start(&self) -> Position { - (self.index << self.level.0).try_into().unwrap() + (self.index << self.level.0).into() } /// Returns the (exclusive) end of the range of leaf positions that are contained within the /// tree with its root at this address. pub fn position_range_end(&self) -> Position { - ((self.index + 1) << self.level.0).try_into().unwrap() + ((self.index + 1) << self.level.0).into() } /// Returns the maximum value among the range of leaf positions that are contained within the diff --git a/shardtree/src/store/caching.rs b/shardtree/src/store/caching.rs index f472760..dbcc275 100644 --- a/shardtree/src/store/caching.rs +++ b/shardtree/src/store/caching.rs @@ -1034,7 +1034,7 @@ mod tests { #[test] fn check_remove_mark() { - let samples = vec![ + let samples = [ vec![ append_str("a", Retention::Ephemeral), append_str( @@ -1128,7 +1128,7 @@ mod tests { // test framework itself previously did not correctly handle // chain state restoration. - let samples = vec![ + let samples = [ vec![ append_str("x", Retention::Marked), Checkpoint(1), diff --git a/shardtree/src/testing.rs b/shardtree/src/testing.rs index b564885..3f70de1 100644 --- a/shardtree/src/testing.rs +++ b/shardtree/src/testing.rs @@ -1,5 +1,3 @@ -use std::convert::TryFrom; - use assert_matches::assert_matches; use proptest::bool::weighted; use proptest::collection::vec; @@ -96,17 +94,19 @@ where }) } +/// A random shardtree of size up to 2^6 with shards of size 2^3, along with vectors of the +/// checkpointed and marked positions within the tree. +type ArbShardtreeParts = ( + ShardTree::Value, usize>, 6, 3>, + Vec, + Vec, +); + /// Constructs a random shardtree of size up to 2^6 with shards of size 2^3. Returns the tree, -/// along with vectors of the checkpoint and mark positions. +/// along with vectors of the checkpointed and marked positions. pub fn arb_shardtree( arb_leaf: H, -) -> impl Strategy< - Value = ( - ShardTree, 6, 3>, - Vec, - Vec, - ), -> +) -> impl Strategy> where H::Value: Hashable + Clone + PartialEq, { From 2e76b90d9a12b42b7aef22a1c8d5e15f90241e17 Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Fri, 31 Jan 2025 12:58:17 -0700 Subject: [PATCH 3/3] Release incrementalmerkletree version 0.8.2 --- Cargo.lock | 2 +- incrementalmerkletree/CHANGELOG.md | 2 ++ incrementalmerkletree/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0830af5..7a97e8c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -103,7 +103,7 @@ checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" [[package]] name = "incrementalmerkletree" -version = "0.8.1" +version = "0.8.2" dependencies = [ "either", "proptest", diff --git a/incrementalmerkletree/CHANGELOG.md b/incrementalmerkletree/CHANGELOG.md index 90db2e7..d8805ea 100644 --- a/incrementalmerkletree/CHANGELOG.md +++ b/incrementalmerkletree/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to Rust's notion of ## Unreleased +## [0.8.2] - 2025-01-31 + ### Added - `incrementalmerkletree::witness::IncrementalWitness::invalid_empty_witness` has been under the `test-dependencies` feature flag to permit use testing diff --git a/incrementalmerkletree/Cargo.toml b/incrementalmerkletree/Cargo.toml index 18bc16b..409224c 100644 --- a/incrementalmerkletree/Cargo.toml +++ b/incrementalmerkletree/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "incrementalmerkletree" description = "Common types, interfaces, and utilities for Merkle tree data structures" -version = "0.8.1" +version = "0.8.2" authors = [ "Sean Bowe ", "Kris Nuttycombe ",