From 14b12fde2b180f7813b25a4717cc31dce03d774e Mon Sep 17 00:00:00 2001 From: Sean Bowe Date: Thu, 26 May 2016 13:56:44 -0600 Subject: [PATCH 1/6] Move new coins tests to within coins_tests test suite. --- src/test/coins_tests.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/test/coins_tests.cpp b/src/test/coins_tests.cpp index 7ab975b9..1a70fe92 100644 --- a/src/test/coins_tests.cpp +++ b/src/test/coins_tests.cpp @@ -140,6 +140,18 @@ public: } +void appendRandomCommitment(ZCIncrementalMerkleTree &tree) +{ + libzcash::SpendingKey k = libzcash::SpendingKey::random(); + libzcash::PaymentAddress addr = k.address(); + + libzcash::Note note(addr.a_pk, 0, uint256(), uint256()); + + tree.append(note.cm()); +} + +BOOST_FIXTURE_TEST_SUITE(coins_tests, BasicTestingSetup) + BOOST_AUTO_TEST_CASE(serials_test) { CCoinsViewTest base; @@ -164,16 +176,6 @@ BOOST_AUTO_TEST_CASE(serials_test) BOOST_CHECK(!cache3.GetSerial(myserial)); } -void appendRandomCommitment(ZCIncrementalMerkleTree &tree) -{ - libzcash::SpendingKey k = libzcash::SpendingKey::random(); - libzcash::PaymentAddress addr = k.address(); - - libzcash::Note note(addr.a_pk, 0, uint256(), uint256()); - - tree.append(note.cm()); -} - BOOST_AUTO_TEST_CASE(anchors_flush_test) { CCoinsViewTest base; @@ -273,8 +275,6 @@ BOOST_AUTO_TEST_CASE(anchors_test) } } -BOOST_FIXTURE_TEST_SUITE(coins_tests, BasicTestingSetup) - static const unsigned int NUM_SIMULATION_ITERATIONS = 40000; // This is a large randomized insert/remove simulation test on a variable-size From 8048f4c048ff4f40883686b45fd43980ee31c9d4 Mon Sep 17 00:00:00 2001 From: Sean Bowe Date: Thu, 26 May 2016 13:58:58 -0600 Subject: [PATCH 2/6] Ensure merkle tree fixed point removal is tested against inside coins_tests. --- src/test/coins_tests.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/test/coins_tests.cpp b/src/test/coins_tests.cpp index 1a70fe92..8fb6abcc 100644 --- a/src/test/coins_tests.cpp +++ b/src/test/coins_tests.cpp @@ -24,8 +24,12 @@ class CCoinsViewTest : public CCoinsView std::map mapSerials_; public: + CCoinsViewTest() { + hashBestAnchor_ = ZCIncrementalMerkleTree::empty_root(); + } + bool GetAnchorAt(const uint256& rt, ZCIncrementalMerkleTree &tree) const { - if (rt.IsNull()) { + if (rt == ZCIncrementalMerkleTree::empty_root()) { ZCIncrementalMerkleTree new_tree; tree = new_tree; return true; @@ -214,12 +218,13 @@ BOOST_AUTO_TEST_CASE(anchors_test) CCoinsViewTest base; CCoinsViewCacheTest cache(&base); - BOOST_CHECK(cache.GetBestAnchor() == uint256()); + BOOST_CHECK(cache.GetBestAnchor() == ZCIncrementalMerkleTree::empty_root()); { ZCIncrementalMerkleTree tree; BOOST_CHECK(cache.GetAnchorAt(cache.GetBestAnchor(), tree)); + BOOST_CHECK(cache.GetBestAnchor() == tree.root()); appendRandomCommitment(tree); appendRandomCommitment(tree); appendRandomCommitment(tree); From 6c59778acb68314cb503f37e5d7dc47bb893e8fd Mon Sep 17 00:00:00 2001 From: Sean Bowe Date: Thu, 26 May 2016 14:00:46 -0600 Subject: [PATCH 3/6] Allow pours to be anchored to intermediate treestates of a transaction. --- src/coins.cpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/coins.cpp b/src/coins.cpp index d177b8ee..2e68a8ea 100644 --- a/src/coins.cpp +++ b/src/coins.cpp @@ -386,6 +386,8 @@ CAmount CCoinsViewCache::GetValueIn(const CTransaction& tx) const bool CCoinsViewCache::HavePourRequirements(const CTransaction& tx) const { + boost::unordered_map intermediates; + BOOST_FOREACH(const CPourTx &pour, tx.vpour) { BOOST_FOREACH(const uint256& serial, pour.serials) @@ -398,11 +400,19 @@ bool CCoinsViewCache::HavePourRequirements(const CTransaction& tx) const } ZCIncrementalMerkleTree tree; - if (!GetAnchorAt(pour.anchor, tree)) { - // If we do not have the anchor for the pour, - // it is invalid. + auto it = intermediates.find(pour.anchor); + if (it != intermediates.end()) { + tree = it->second; + } else if (!GetAnchorAt(pour.anchor, tree)) { return false; } + + BOOST_FOREACH(const uint256& commitment, pour.commitments) + { + tree.append(commitment); + } + + intermediates.insert(std::make_pair(tree.root(), tree)); } return true; From 10c33f0f8746a43ebf387d7c7a683f62898a61e3 Mon Sep 17 00:00:00 2001 From: Sean Bowe Date: Thu, 26 May 2016 14:12:45 -0600 Subject: [PATCH 4/6] Test behavior of chained pour consensus rules. --- src/test/coins_tests.cpp | 63 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 62 insertions(+), 1 deletion(-) diff --git a/src/test/coins_tests.cpp b/src/test/coins_tests.cpp index 8fb6abcc..2edca14e 100644 --- a/src/test/coins_tests.cpp +++ b/src/test/coins_tests.cpp @@ -144,7 +144,7 @@ public: } -void appendRandomCommitment(ZCIncrementalMerkleTree &tree) +uint256 appendRandomCommitment(ZCIncrementalMerkleTree &tree) { libzcash::SpendingKey k = libzcash::SpendingKey::random(); libzcash::PaymentAddress addr = k.address(); @@ -152,6 +152,8 @@ void appendRandomCommitment(ZCIncrementalMerkleTree &tree) libzcash::Note note(addr.a_pk, 0, uint256(), uint256()); tree.append(note.cm()); + + return note.cm(); } BOOST_FIXTURE_TEST_SUITE(coins_tests, BasicTestingSetup) @@ -210,6 +212,65 @@ BOOST_AUTO_TEST_CASE(anchors_flush_test) } } +BOOST_AUTO_TEST_CASE(chained_pours) +{ + CCoinsViewTest base; + CCoinsViewCacheTest cache(&base); + + ZCIncrementalMerkleTree tree; + + CPourTx ptx1; + ptx1.anchor = tree.root(); + ptx1.commitments[0] = appendRandomCommitment(tree); + ptx1.commitments[1] = appendRandomCommitment(tree); + + // Although it's not possible given our assumptions, if + // two pours create the same treestate twice, we should + // still be able to anchor to it. + CPourTx ptx1b; + ptx1b.anchor = tree.root(); + ptx1b.commitments[0] = ptx1.commitments[0]; + ptx1b.commitments[1] = ptx1.commitments[1]; + + CPourTx ptx2; + CPourTx ptx3; + + ptx2.anchor = tree.root(); + ptx3.anchor = tree.root(); + + ptx2.commitments[0] = appendRandomCommitment(tree); + ptx2.commitments[1] = appendRandomCommitment(tree); + + ptx3.commitments[0] = appendRandomCommitment(tree); + ptx3.commitments[1] = appendRandomCommitment(tree); + + { + CMutableTransaction mtx; + mtx.vpour.push_back(ptx2); + + BOOST_CHECK(!cache.HavePourRequirements(mtx)); + } + + { + CMutableTransaction mtx; + mtx.vpour.push_back(ptx1); + mtx.vpour.push_back(ptx2); + mtx.vpour.push_back(ptx3); + + BOOST_CHECK(cache.HavePourRequirements(mtx)); + } + + { + CMutableTransaction mtx; + mtx.vpour.push_back(ptx1); + mtx.vpour.push_back(ptx1b); + mtx.vpour.push_back(ptx2); + mtx.vpour.push_back(ptx3); + + BOOST_CHECK(cache.HavePourRequirements(mtx)); + } +} + BOOST_AUTO_TEST_CASE(anchors_test) { // TODO: These tests should be more methodical. From 49ab032b5fe4b4262d0e86aaaa8e6988bf70971b Mon Sep 17 00:00:00 2001 From: Sean Bowe Date: Tue, 7 Jun 2016 21:05:25 -0600 Subject: [PATCH 5/6] Add test to ensure parent treestates only can appear earlier in the transaction or in the global state, not later. --- src/test/coins_tests.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/test/coins_tests.cpp b/src/test/coins_tests.cpp index 2edca14e..c31bb907 100644 --- a/src/test/coins_tests.cpp +++ b/src/test/coins_tests.cpp @@ -251,6 +251,22 @@ BOOST_AUTO_TEST_CASE(chained_pours) BOOST_CHECK(!cache.HavePourRequirements(mtx)); } + { + CMutableTransaction mtx; + mtx.vpour.push_back(ptx2); + mtx.vpour.push_back(ptx1); + + BOOST_CHECK(!cache.HavePourRequirements(mtx)); + } + + { + CMutableTransaction mtx; + mtx.vpour.push_back(ptx1); + mtx.vpour.push_back(ptx2); + + BOOST_CHECK(cache.HavePourRequirements(mtx)); + } + { CMutableTransaction mtx; mtx.vpour.push_back(ptx1); From ecd8ca5dbee9c12bc767864d8f8cf80b33734007 Mon Sep 17 00:00:00 2001 From: Sean Bowe Date: Wed, 8 Jun 2016 09:15:44 -0600 Subject: [PATCH 6/6] Minor changes to coins_tests. --- src/test/coins_tests.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/test/coins_tests.cpp b/src/test/coins_tests.cpp index c31bb907..ce9b7eeb 100644 --- a/src/test/coins_tests.cpp +++ b/src/test/coins_tests.cpp @@ -151,9 +151,9 @@ uint256 appendRandomCommitment(ZCIncrementalMerkleTree &tree) libzcash::Note note(addr.a_pk, 0, uint256(), uint256()); - tree.append(note.cm()); - - return note.cm(); + auto cm = note.cm(); + tree.append(cm); + return cm; } BOOST_FIXTURE_TEST_SUITE(coins_tests, BasicTestingSetup) @@ -252,6 +252,8 @@ BOOST_AUTO_TEST_CASE(chained_pours) } { + // ptx2 is trying to anchor to ptx1 but ptx1 + // appears afterwards -- not a permitted ordering CMutableTransaction mtx; mtx.vpour.push_back(ptx2); mtx.vpour.push_back(ptx1);