Add sapling nullifier set

This commit is contained in:
Eirik Ogilvie-Wigley
2018-04-18 13:18:57 -06:00
parent 68cf6f3c2d
commit 685e936c31
11 changed files with 204 additions and 136 deletions

View File

@@ -11,6 +11,7 @@
#include "consensus/validation.h"
#include "main.h"
#include "undo.h"
#include "primitives/transaction.h"
#include "pubkey.h"
#include <vector>
@@ -28,6 +29,7 @@ class CCoinsViewTest : public CCoinsView
std::map<uint256, CCoins> map_;
std::map<uint256, ZCIncrementalMerkleTree> mapAnchors_;
std::map<uint256, bool> mapNullifiers_;
std::map<uint256, bool> mapSaplingNullifiers_;
public:
CCoinsViewTest() {
@@ -50,11 +52,12 @@ public:
}
}
bool GetNullifier(const uint256 &nf) const
bool GetNullifier(const uint256 &nf, bool isSapling) const
{
std::map<uint256, bool>::const_iterator it = mapNullifiers_.find(nf);
const std::map<uint256, bool>* mapToUse = isSapling ? &mapSaplingNullifiers_ : &mapNullifiers_;
std::map<uint256, bool>::const_iterator it = mapToUse->find(nf);
if (it == mapNullifiers_.end()) {
if (it == mapToUse->end()) {
return false;
} else {
// The map shouldn't contain any false entries.
@@ -87,11 +90,25 @@ public:
uint256 GetBestBlock() const { return hashBestBlock_; }
void BatchWriteNullifiers(CNullifiersMap& mapNullifiers, std::map<uint256, bool>& cacheNullifiers)
{
for (CNullifiersMap::iterator it = mapNullifiers.begin(); it != mapNullifiers.end(); ) {
if (it->second.entered) {
cacheNullifiers[it->first] = true;
} else {
cacheNullifiers.erase(it->first);
}
mapNullifiers.erase(it++);
}
mapNullifiers.clear();
}
bool BatchWrite(CCoinsMap& mapCoins,
const uint256& hashBlock,
const uint256& hashAnchor,
CAnchorsMap& mapAnchors,
CNullifiersMap& mapNullifiers)
CNullifiersMap& mapNullifiers,
CNullifiersMap& mapSaplingNullifiers)
{
for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end(); ) {
map_[it->first] = it->second.coins;
@@ -112,17 +129,12 @@ public:
}
mapAnchors.erase(it++);
}
for (CNullifiersMap::iterator it = mapNullifiers.begin(); it != mapNullifiers.end(); ) {
if (it->second.entered) {
mapNullifiers_[it->first] = true;
} else {
mapNullifiers_.erase(it->first);
}
mapNullifiers.erase(it++);
}
BatchWriteNullifiers(mapNullifiers, mapNullifiers_);
BatchWriteNullifiers(mapSaplingNullifiers, mapSaplingNullifiers_);
mapCoins.clear();
mapAnchors.clear();
mapNullifiers.clear();
hashBestBlock_ = hashBlock;
hashBestAnchor_ = hashAnchor;
return true;
@@ -141,7 +153,8 @@ public:
// Manually recompute the dynamic usage of the whole data, and compare it.
size_t ret = memusage::DynamicUsage(cacheCoins) +
memusage::DynamicUsage(cacheAnchors) +
memusage::DynamicUsage(cacheNullifiers);
memusage::DynamicUsage(cacheNullifiers) +
memusage::DynamicUsage(cacheSaplingNullifiers);
for (CCoinsMap::iterator it = cacheCoins.begin(); it != cacheCoins.end(); it++) {
ret += it->second.coins.DynamicMemoryUsage();
}
@@ -164,6 +177,17 @@ uint256 appendRandomCommitment(ZCIncrementalMerkleTree &tree)
return cm;
}
std::pair<CTransaction, uint256> createTxWithNullifier()
{
CMutableTransaction mutableTx;
JSDescription jsd;
uint256 nullifier = GetRandHash();
mutableTx.vjoinsplit.push_back(jsd);
jsd.nullifiers[0] = nullifier;
CTransaction tx(mutableTx);
return std::make_pair(tx, nullifier);
}
BOOST_FIXTURE_TEST_SUITE(coins_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(nullifier_regression_test)
@@ -174,15 +198,15 @@ BOOST_AUTO_TEST_CASE(nullifier_regression_test)
CCoinsViewCacheTest cache1(&base);
// Insert a nullifier into the base.
uint256 nf = GetRandHash();
cache1.SetNullifier(nf, true);
auto txWithNullifier = createTxWithNullifier();
cache1.SetNullifiers(txWithNullifier.first, true);
cache1.Flush(); // Flush to base.
// Remove the nullifier from cache
cache1.SetNullifier(nf, false);
cache1.SetNullifiers(txWithNullifier.first, false);
// The nullifier now should be `false`.
BOOST_CHECK(!cache1.GetNullifier(nf));
BOOST_CHECK(!cache1.GetNullifier(txWithNullifier.second, false));
}
// Also correct behavior:
@@ -191,16 +215,16 @@ BOOST_AUTO_TEST_CASE(nullifier_regression_test)
CCoinsViewCacheTest cache1(&base);
// Insert a nullifier into the base.
uint256 nf = GetRandHash();
cache1.SetNullifier(nf, true);
auto txWithNullifier = createTxWithNullifier();
cache1.SetNullifiers(txWithNullifier.first, true);
cache1.Flush(); // Flush to base.
// Remove the nullifier from cache
cache1.SetNullifier(nf, false);
cache1.SetNullifiers(txWithNullifier.first, false);
cache1.Flush(); // Flush to base.
// The nullifier now should be `false`.
BOOST_CHECK(!cache1.GetNullifier(nf));
BOOST_CHECK(!cache1.GetNullifier(txWithNullifier.second, false));
}
// Works because we bring it from the parent cache:
@@ -209,21 +233,21 @@ BOOST_AUTO_TEST_CASE(nullifier_regression_test)
CCoinsViewCacheTest cache1(&base);
// Insert a nullifier into the base.
uint256 nf = GetRandHash();
cache1.SetNullifier(nf, true);
auto txWithNullifier = createTxWithNullifier();
cache1.SetNullifiers(txWithNullifier.first, true);
cache1.Flush(); // Empties cache.
// Create cache on top.
{
// Remove the nullifier.
CCoinsViewCacheTest cache2(&cache1);
BOOST_CHECK(cache2.GetNullifier(nf));
cache2.SetNullifier(nf, false);
BOOST_CHECK(cache2.GetNullifier(txWithNullifier.second, false));
cache1.SetNullifiers(txWithNullifier.first, false);
cache2.Flush(); // Empties cache, flushes to cache1.
}
// The nullifier now should be `false`.
BOOST_CHECK(!cache1.GetNullifier(nf));
BOOST_CHECK(!cache1.GetNullifier(txWithNullifier.second, false));
}
// Was broken:
@@ -232,20 +256,20 @@ BOOST_AUTO_TEST_CASE(nullifier_regression_test)
CCoinsViewCacheTest cache1(&base);
// Insert a nullifier into the base.
uint256 nf = GetRandHash();
cache1.SetNullifier(nf, true);
auto txWithNullifier = createTxWithNullifier();
cache1.SetNullifiers(txWithNullifier.first, true);
cache1.Flush(); // Empties cache.
// Create cache on top.
{
// Remove the nullifier.
CCoinsViewCacheTest cache2(&cache1);
cache2.SetNullifier(nf, false);
cache2.SetNullifiers(txWithNullifier.first, false);
cache2.Flush(); // Empties cache, flushes to cache1.
}
// The nullifier now should be `false`.
BOOST_CHECK(!cache1.GetNullifier(nf));
BOOST_CHECK(!cache1.GetNullifier(txWithNullifier.second, false));
}
}
@@ -414,23 +438,26 @@ BOOST_AUTO_TEST_CASE(nullifiers_test)
CCoinsViewTest base;
CCoinsViewCacheTest cache(&base);
uint256 nf = GetRandHash();
auto txWithNullifier = createTxWithNullifier();
BOOST_CHECK(!cache.GetNullifier(nf));
cache.SetNullifier(nf, true);
BOOST_CHECK(cache.GetNullifier(nf));
BOOST_CHECK(!cache.GetNullifier(txWithNullifier.second, false));
BOOST_CHECK(!cache.GetNullifier(txWithNullifier.second, true));
cache.SetNullifiers(txWithNullifier.first, true);
BOOST_CHECK(cache.GetNullifier(txWithNullifier.second, false));
BOOST_CHECK(!cache.GetNullifier(txWithNullifier.second, true));
cache.Flush();
CCoinsViewCacheTest cache2(&base);
BOOST_CHECK(cache2.GetNullifier(nf));
cache2.SetNullifier(nf, false);
BOOST_CHECK(!cache2.GetNullifier(nf));
BOOST_CHECK(cache2.GetNullifier(txWithNullifier.second, false));
BOOST_CHECK(!cache2.GetNullifier(txWithNullifier.second, true));
cache2.SetNullifiers(txWithNullifier.first, false);
BOOST_CHECK(!cache2.GetNullifier(txWithNullifier.second, false));
cache2.Flush();
CCoinsViewCacheTest cache3(&base);
BOOST_CHECK(!cache3.GetNullifier(nf));
BOOST_CHECK(!cache3.GetNullifier(txWithNullifier.second, false));
}
BOOST_AUTO_TEST_CASE(anchors_flush_test)