mirror of
https://github.com/Qortal/pirate-librustzcash.git
synced 2025-08-01 12:51:30 +00:00
add quickcheck(failing) also failing append
This commit is contained in:
@@ -6,3 +6,4 @@ edition = "2018"
|
|||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
assert_matches = "1.3.0"
|
assert_matches = "1.3.0"
|
||||||
|
quickcheck = "0.8"
|
@@ -3,6 +3,7 @@
|
|||||||
//! To be used in zebra and via FFI bindings in zcashd
|
//! 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 assert_matches;
|
||||||
|
#[cfg(test)] #[macro_use] extern crate quickcheck;
|
||||||
|
|
||||||
mod tree;
|
mod tree;
|
||||||
|
|
||||||
|
128
src/tree.rs
128
src/tree.rs
@@ -111,7 +111,6 @@ impl Tree {
|
|||||||
|
|
||||||
/// Append one leaf to the tree.
|
/// Append one leaf to the tree.
|
||||||
pub fn append_leaf(&mut self, root: NodeLink, new_leaf: NodeData) -> AppendTransaction {
|
pub fn append_leaf(&mut self, root: NodeLink, new_leaf: NodeData) -> AppendTransaction {
|
||||||
|
|
||||||
let is_complete= self.resolve_link(root).node.complete();
|
let is_complete= self.resolve_link(root).node.complete();
|
||||||
|
|
||||||
let (new_root_node, mut appended) = if is_complete {
|
let (new_root_node, mut appended) = if is_complete {
|
||||||
@@ -162,6 +161,18 @@ impl Tree {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
fn for_children<F: FnMut(NodeLink, NodeLink)>(&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) {
|
fn pop(&mut self) {
|
||||||
self.stored.remove(&(self.stored_count-1));
|
self.stored.remove(&(self.stored_count-1));
|
||||||
self.stored_count = 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 {
|
mod tests {
|
||||||
|
|
||||||
use super::{MMRNode, NodeData, Tree, NodeLink};
|
use super::{MMRNode, NodeData, Tree, NodeLink};
|
||||||
|
use quickcheck::TestResult;
|
||||||
|
|
||||||
fn leaf(height: u32) -> NodeData {
|
fn leaf(height: u32) -> NodeData {
|
||||||
NodeData {
|
NodeData {
|
||||||
@@ -301,7 +313,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn initial() -> Tree {
|
fn initial() -> (NodeLink, Tree) {
|
||||||
let node1: MMRNode = leaf(1).into();
|
let node1: MMRNode = leaf(1).into();
|
||||||
let node2: MMRNode = leaf(2).into();
|
let node2: MMRNode = leaf(2).into();
|
||||||
|
|
||||||
@@ -311,15 +323,13 @@ mod tests {
|
|||||||
right: Some(NodeLink::Stored(1)),
|
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
|
// returns tree with specified number of leafs and it's root
|
||||||
fn generated(length: u32) -> (Tree, NodeLink) {
|
fn generated(length: u32) -> (Tree, NodeLink) {
|
||||||
assert!(length > 3);
|
assert!(length >= 3);
|
||||||
let mut tree = initial();
|
let (mut root, mut tree) = initial();
|
||||||
let mut root = NodeLink::Stored(2);
|
|
||||||
|
|
||||||
for i in 2..length {
|
for i in 2..length {
|
||||||
root = tree.append_leaf(root, leaf(i+1).into()).new_root;
|
root = tree.append_leaf(root, leaf(i+1).into()).new_root;
|
||||||
}
|
}
|
||||||
@@ -329,8 +339,10 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn discrete_append() {
|
fn discrete_append() {
|
||||||
let mut tree = initial();
|
let (root, mut tree) = initial();
|
||||||
let append_tx = tree.append_leaf(NodeLink::Stored(2), leaf(3));
|
|
||||||
|
// ** APPEND 3 **
|
||||||
|
let append_tx = tree.append_leaf(root, leaf(3));
|
||||||
let new_root_link = append_tx.new_root;
|
let new_root_link = append_tx.new_root;
|
||||||
let new_root = tree.resolve_link(new_root_link).node;
|
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!(new_root.data.end_height, 3);
|
||||||
assert_eq!(append_tx.appended.len(), 1);
|
assert_eq!(append_tx.appended.len(), 1);
|
||||||
|
|
||||||
|
// ** APPEND 4 **
|
||||||
let append_tx = tree.append_leaf(new_root_link, leaf(4));
|
let append_tx = tree.append_leaf(new_root_link, leaf(4));
|
||||||
let new_root_link = append_tx.new_root;
|
let new_root_link = append_tx.new_root;
|
||||||
let new_root = tree.resolve_link(new_root_link).node;
|
let new_root = tree.resolve_link(new_root_link).node;
|
||||||
@@ -372,6 +385,9 @@ mod tests {
|
|||||||
// and new root, (6) is stored one
|
// and new root, (6) is stored one
|
||||||
assert_eq!(new_root.data.end_height, 4);
|
assert_eq!(new_root.data.end_height, 4);
|
||||||
assert_eq!(append_tx.appended.len(), 3);
|
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 append_tx = tree.append_leaf(new_root_link, leaf(5));
|
||||||
let new_root_link = append_tx.new_root;
|
let new_root_link = append_tx.new_root;
|
||||||
@@ -397,6 +413,81 @@ mod tests {
|
|||||||
// and new root, (8g) is generated one
|
// and new root, (8g) is generated one
|
||||||
assert_eq!(new_root.data.end_height, 5);
|
assert_eq!(new_root.data.end_height, 5);
|
||||||
assert_eq!(append_tx.appended.len(), 1);
|
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]
|
#[test]
|
||||||
@@ -483,4 +574,23 @@ mod tests {
|
|||||||
assert_eq!(delete_tx.truncated, 2);
|
assert_eq!(delete_tx.truncated, 2);
|
||||||
assert_eq!(tree.len(), 16);
|
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 })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
Reference in New Issue
Block a user