Browse Source

Anchors and nullifiers should always be inherited from the parent cache.

v1.0.9-lin
Sean Bowe 8 years ago
parent
commit
f398a94766
  1. 25
      src/coins.cpp
  2. 168
      src/test/coins_tests.cpp

25
src/coins.cpp

@ -303,16 +303,12 @@ bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins,
CAnchorsMap::iterator parent_it = cacheAnchors.find(child_it->first);
if (parent_it == cacheAnchors.end()) {
if (child_it->second.entered) {
// Parent doesn't have an entry, but child has a new commitment root.
CAnchorsCacheEntry& entry = cacheAnchors[child_it->first];
entry.entered = child_it->second.entered;
entry.tree = child_it->second.tree;
entry.flags = CAnchorsCacheEntry::DIRTY;
CAnchorsCacheEntry& entry = cacheAnchors[child_it->first];
entry.entered = true;
entry.tree = child_it->second.tree;
entry.flags = CAnchorsCacheEntry::DIRTY;
cachedCoinsUsage += memusage::DynamicUsage(entry.tree);
}
cachedCoinsUsage += memusage::DynamicUsage(entry.tree);
} else {
if (parent_it->second.entered != child_it->second.entered) {
// The parent may have removed the entry.
@ -332,14 +328,9 @@ bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins,
CNullifiersMap::iterator parent_it = cacheNullifiers.find(child_it->first);
if (parent_it == cacheNullifiers.end()) {
if (child_it->second.entered) {
// Parent doesn't have an entry, but child has a SPENT nullifier.
// Move the spent nullifier up.
CNullifiersCacheEntry& entry = cacheNullifiers[child_it->first];
entry.entered = true;
entry.flags = CNullifiersCacheEntry::DIRTY;
}
CNullifiersCacheEntry& entry = cacheNullifiers[child_it->first];
entry.entered = child_it->second.entered;
entry.flags = CNullifiersCacheEntry::DIRTY;
} else {
if (parent_it->second.entered != child_it->second.entered) {
parent_it->second.entered = child_it->second.entered;

168
src/test/coins_tests.cpp

@ -166,6 +166,174 @@ uint256 appendRandomCommitment(ZCIncrementalMerkleTree &tree)
BOOST_FIXTURE_TEST_SUITE(coins_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(nullifier_regression_test)
{
// Correct behavior:
{
CCoinsViewTest base;
CCoinsViewCacheTest cache1(&base);
// Insert a nullifier into the base.
uint256 nf = GetRandHash();
cache1.SetNullifier(nf, true);
cache1.Flush(); // Flush to base.
// Remove the nullifier from cache
cache1.SetNullifier(nf, false);
// The nullifier now should be `false`.
BOOST_CHECK(!cache1.GetNullifier(nf));
}
// Also correct behavior:
{
CCoinsViewTest base;
CCoinsViewCacheTest cache1(&base);
// Insert a nullifier into the base.
uint256 nf = GetRandHash();
cache1.SetNullifier(nf, true);
cache1.Flush(); // Flush to base.
// Remove the nullifier from cache
cache1.SetNullifier(nf, false);
cache1.Flush(); // Flush to base.
// The nullifier now should be `false`.
BOOST_CHECK(!cache1.GetNullifier(nf));
}
// Works because we bring it from the parent cache:
{
CCoinsViewTest base;
CCoinsViewCacheTest cache1(&base);
// Insert a nullifier into the base.
uint256 nf = GetRandHash();
cache1.SetNullifier(nf, true);
cache1.Flush(); // Empties cache.
// Create cache on top.
{
// Remove the nullifier.
CCoinsViewCacheTest cache2(&cache1);
BOOST_CHECK(cache2.GetNullifier(nf));
cache2.SetNullifier(nf, false);
cache2.Flush(); // Empties cache, flushes to cache1.
}
// The nullifier now should be `false`.
BOOST_CHECK(!cache1.GetNullifier(nf));
}
// Was broken:
{
CCoinsViewTest base;
CCoinsViewCacheTest cache1(&base);
// Insert a nullifier into the base.
uint256 nf = GetRandHash();
cache1.SetNullifier(nf, true);
cache1.Flush(); // Empties cache.
// Create cache on top.
{
// Remove the nullifier.
CCoinsViewCacheTest cache2(&cache1);
cache2.SetNullifier(nf, false);
cache2.Flush(); // Empties cache, flushes to cache1.
}
// The nullifier now should be `false`.
BOOST_CHECK(!cache1.GetNullifier(nf));
}
}
BOOST_AUTO_TEST_CASE(anchor_regression_test)
{
// Correct behavior:
{
CCoinsViewTest base;
CCoinsViewCacheTest cache1(&base);
// Insert anchor into base.
ZCIncrementalMerkleTree tree;
uint256 cm = GetRandHash();
tree.append(cm);
cache1.PushAnchor(tree);
cache1.Flush();
cache1.PopAnchor(ZCIncrementalMerkleTree::empty_root());
BOOST_CHECK(cache1.GetBestAnchor() == ZCIncrementalMerkleTree::empty_root());
BOOST_CHECK(!cache1.GetAnchorAt(tree.root(), tree));
}
// Also correct behavior:
{
CCoinsViewTest base;
CCoinsViewCacheTest cache1(&base);
// Insert anchor into base.
ZCIncrementalMerkleTree tree;
uint256 cm = GetRandHash();
tree.append(cm);
cache1.PushAnchor(tree);
cache1.Flush();
cache1.PopAnchor(ZCIncrementalMerkleTree::empty_root());
cache1.Flush();
BOOST_CHECK(cache1.GetBestAnchor() == ZCIncrementalMerkleTree::empty_root());
BOOST_CHECK(!cache1.GetAnchorAt(tree.root(), tree));
}
// Works because we bring the anchor in from parent cache.
{
CCoinsViewTest base;
CCoinsViewCacheTest cache1(&base);
// Insert anchor into base.
ZCIncrementalMerkleTree tree;
uint256 cm = GetRandHash();
tree.append(cm);
cache1.PushAnchor(tree);
cache1.Flush();
{
// Pop anchor.
CCoinsViewCacheTest cache2(&cache1);
BOOST_CHECK(cache2.GetAnchorAt(tree.root(), tree));
cache2.PopAnchor(ZCIncrementalMerkleTree::empty_root());
cache2.Flush();
}
BOOST_CHECK(cache1.GetBestAnchor() == ZCIncrementalMerkleTree::empty_root());
BOOST_CHECK(!cache1.GetAnchorAt(tree.root(), tree));
}
// Was broken:
{
CCoinsViewTest base;
CCoinsViewCacheTest cache1(&base);
// Insert anchor into base.
ZCIncrementalMerkleTree tree;
uint256 cm = GetRandHash();
tree.append(cm);
cache1.PushAnchor(tree);
cache1.Flush();
{
// Pop anchor.
CCoinsViewCacheTest cache2(&cache1);
cache2.PopAnchor(ZCIncrementalMerkleTree::empty_root());
cache2.Flush();
}
BOOST_CHECK(cache1.GetBestAnchor() == ZCIncrementalMerkleTree::empty_root());
BOOST_CHECK(!cache1.GetAnchorAt(tree.root(), tree));
}
}
BOOST_AUTO_TEST_CASE(nullifiers_test)
{
CCoinsViewTest base;

Loading…
Cancel
Save