From e7d67364cca6c63d40eb25ad3abed2688d87bee6 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Fri, 23 Aug 2019 16:25:34 +0300 Subject: [PATCH] add quickcheck(failing) also failing append --- Cargo.toml | 3 +- src/lib.rs | 1 + src/tree.rs | 128 ++++++++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 122 insertions(+), 10 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 522af41..839ef38 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,4 +5,5 @@ authors = ["NikVolf "] edition = "2018" [dev-dependencies] -assert_matches = "1.3.0" \ No newline at end of file +assert_matches = "1.3.0" +quickcheck = "0.8" \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 1b5ad79..e398029 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,6 +3,7 @@ //! To be used in zebra and via FFI bindings in zcashd #[cfg(test)] #[macro_use] extern crate assert_matches; +#[cfg(test)] #[macro_use] extern crate quickcheck; mod tree; diff --git a/src/tree.rs b/src/tree.rs index 136c9cf..5a38740 100644 --- a/src/tree.rs +++ b/src/tree.rs @@ -111,7 +111,6 @@ impl Tree { /// Append one leaf to the tree. pub fn append_leaf(&mut self, root: NodeLink, new_leaf: NodeData) -> AppendTransaction { - let is_complete= self.resolve_link(root).node.complete(); let (new_root_node, mut appended) = if is_complete { @@ -162,6 +161,18 @@ impl Tree { } } + #[cfg(test)] + fn for_children(&mut self, node: NodeLink, mut f: F) { + let (left, right) = { + let link = self.resolve_link(node); + ( + link.node.left.expect("test use only (l)"), + link.node.right.expect("test use only (r)"), + ) + }; + f(left, right) + } + fn pop(&mut self) { self.stored.remove(&(self.stored_count-1)); self.stored_count = self.stored_count - 1; @@ -268,6 +279,7 @@ fn combine_nodes<'a>(left: IndexedNode<'a>, right: IndexedNode<'a>) -> MMRNode { mod tests { use super::{MMRNode, NodeData, Tree, NodeLink}; + use quickcheck::TestResult; fn leaf(height: u32) -> NodeData { NodeData { @@ -301,7 +313,7 @@ mod tests { } } - fn initial() -> Tree { + fn initial() -> (NodeLink, Tree) { let node1: MMRNode = leaf(1).into(); let node2: MMRNode = leaf(2).into(); @@ -311,15 +323,13 @@ mod tests { right: Some(NodeLink::Stored(1)), }; - Tree::populate(vec![node1, node2, node3]) + (NodeLink::Stored(2), Tree::populate(vec![node1, node2, node3])) } // returns tree with specified number of leafs and it's root fn generated(length: u32) -> (Tree, NodeLink) { - assert!(length > 3); - let mut tree = initial(); - let mut root = NodeLink::Stored(2); - + assert!(length >= 3); + let (mut root, mut tree) = initial(); for i in 2..length { root = tree.append_leaf(root, leaf(i+1).into()).new_root; } @@ -329,8 +339,10 @@ mod tests { #[test] fn discrete_append() { - let mut tree = initial(); - let append_tx = tree.append_leaf(NodeLink::Stored(2), leaf(3)); + let (root, mut tree) = initial(); + + // ** APPEND 3 ** + let append_tx = tree.append_leaf(root, leaf(3)); let new_root_link = append_tx.new_root; let new_root = tree.resolve_link(new_root_link).node; @@ -350,6 +362,7 @@ mod tests { assert_eq!(new_root.data.end_height, 3); assert_eq!(append_tx.appended.len(), 1); + // ** APPEND 4 ** let append_tx = tree.append_leaf(new_root_link, leaf(4)); let new_root_link = append_tx.new_root; let new_root = tree.resolve_link(new_root_link).node; @@ -372,6 +385,9 @@ mod tests { // and new root, (6) is stored one assert_eq!(new_root.data.end_height, 4); assert_eq!(append_tx.appended.len(), 3); + assert_matches!(new_root_link, NodeLink::Stored(6)); + + // ** APPEND 5 ** let append_tx = tree.append_leaf(new_root_link, leaf(5)); let new_root_link = append_tx.new_root; @@ -397,6 +413,81 @@ mod tests { // and new root, (8g) is generated one assert_eq!(new_root.data.end_height, 5); assert_eq!(append_tx.appended.len(), 1); + assert_matches!(new_root_link, NodeLink::Generated(_)); + tree.for_children(new_root_link, |l, r| { + assert_matches!(l, NodeLink::Stored(6)); + assert_matches!(r, NodeLink::Stored(7)); + }); + + // *** APPEND #6 *** + + let append_tx = tree.append_leaf(new_root_link, leaf(6)); + let new_root_link = append_tx.new_root; + let new_root = tree.resolve_link(new_root_link).node; + + // intermediate tree: + // ( 8g ) + // / \ + // ( 6 ) \ + // / \ \ + // (2) (5) \ + // / \ / \ \ + // (0) (1) (3) (4) (7) + // + // new tree: + // (---8g---) + // / \ + // ( 6 ) \ + // / \ \ + // (2) (5) (9) + // / \ / \ / \ + // (0) (1) (3) (4) (7) (8) + // + // so (7) is added as real leaf + // and new root, (8g) is generated one + assert_eq!(new_root.data.end_height, 6); + assert_eq!(append_tx.appended.len(), 2); + assert_matches!(new_root_link, NodeLink::Generated(_)); + tree.for_children(new_root_link, |l, r| { + assert_matches!(l, NodeLink::Stored(6)); + assert_matches!(r, NodeLink::Stored(9)); + }); + + // *** APPEND #7 *** + + let append_tx = tree.append_leaf(new_root_link, leaf(7)); + let new_root_link = append_tx.new_root; + let new_root = tree.resolve_link(new_root_link).node; + + // intermediate tree: + // (---8g---) + // / \ + // ( 6 ) \ + // / \ \ + // (2) (5) (9) + // / \ / \ / \ + // (0) (1) (3) (4) (7) (8) + // + // new tree: + // (---12g--) + // / \ + // (---11g---) \ + // / \ \ + // ( 6 ) \ \ + // / \ \ \ + // (2) (5) (9) \ + // / \ / \ / \ \ + // (0) (1) (3) (4) (7) (8) (10) + // + // so (7) is added as real leaf + // and new root, (8g) is generated one + assert_eq!(new_root.data.end_height, 7); + assert_eq!(append_tx.appended.len(), 1); + assert_matches!(new_root_link, NodeLink::Generated(_)); + tree.for_children(new_root_link, |l, r| { + assert_matches!(l, NodeLink::Generated(_)); + assert_matches!(r, NodeLink::Stored(10)); + }); } #[test] @@ -483,4 +574,23 @@ mod tests { assert_eq!(delete_tx.truncated, 2); assert_eq!(tree.len(), 16); } + + + quickcheck! { + fn there_and_back(number: u32) -> TestResult { + if (number > 1024*1024) { + TestResult::discard() + } else { + let (mut root, mut tree) = initial(); + for i in 0..number { + root = tree.append_leaf(root, leaf(i+3)).new_root; + } + for i in 0..number { + root = tree.truncate_leaf(root).new_root; + } + + TestResult::from_bool(if let NodeLink::Stored(2) = root { true } else { false }) + } + } + } } \ No newline at end of file