Anchors and nullifiers should always be inherited from the parent cache.
This commit is contained in:
parent
27c2ccb880
commit
f398a94766
|
@ -303,16 +303,12 @@ bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins,
|
||||||
CAnchorsMap::iterator parent_it = cacheAnchors.find(child_it->first);
|
CAnchorsMap::iterator parent_it = cacheAnchors.find(child_it->first);
|
||||||
|
|
||||||
if (parent_it == cacheAnchors.end()) {
|
if (parent_it == cacheAnchors.end()) {
|
||||||
if (child_it->second.entered) {
|
CAnchorsCacheEntry& entry = cacheAnchors[child_it->first];
|
||||||
// Parent doesn't have an entry, but child has a new commitment root.
|
entry.entered = child_it->second.entered;
|
||||||
|
entry.tree = child_it->second.tree;
|
||||||
|
entry.flags = CAnchorsCacheEntry::DIRTY;
|
||||||
|
|
||||||
CAnchorsCacheEntry& entry = cacheAnchors[child_it->first];
|
cachedCoinsUsage += memusage::DynamicUsage(entry.tree);
|
||||||
entry.entered = true;
|
|
||||||
entry.tree = child_it->second.tree;
|
|
||||||
entry.flags = CAnchorsCacheEntry::DIRTY;
|
|
||||||
|
|
||||||
cachedCoinsUsage += memusage::DynamicUsage(entry.tree);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (parent_it->second.entered != child_it->second.entered) {
|
if (parent_it->second.entered != child_it->second.entered) {
|
||||||
// The parent may have removed the entry.
|
// 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);
|
CNullifiersMap::iterator parent_it = cacheNullifiers.find(child_it->first);
|
||||||
|
|
||||||
if (parent_it == cacheNullifiers.end()) {
|
if (parent_it == cacheNullifiers.end()) {
|
||||||
if (child_it->second.entered) {
|
CNullifiersCacheEntry& entry = cacheNullifiers[child_it->first];
|
||||||
// Parent doesn't have an entry, but child has a SPENT nullifier.
|
entry.entered = child_it->second.entered;
|
||||||
// Move the spent nullifier up.
|
entry.flags = CNullifiersCacheEntry::DIRTY;
|
||||||
|
|
||||||
CNullifiersCacheEntry& entry = cacheNullifiers[child_it->first];
|
|
||||||
entry.entered = true;
|
|
||||||
entry.flags = CNullifiersCacheEntry::DIRTY;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (parent_it->second.entered != child_it->second.entered) {
|
if (parent_it->second.entered != child_it->second.entered) {
|
||||||
parent_it->second.entered = child_it->second.entered;
|
parent_it->second.entered = child_it->second.entered;
|
||||||
|
|
|
@ -166,6 +166,174 @@ uint256 appendRandomCommitment(ZCIncrementalMerkleTree &tree)
|
||||||
|
|
||||||
BOOST_FIXTURE_TEST_SUITE(coins_tests, BasicTestingSetup)
|
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)
|
BOOST_AUTO_TEST_CASE(nullifiers_test)
|
||||||
{
|
{
|
||||||
CCoinsViewTest base;
|
CCoinsViewTest base;
|
||||||
|
|
Loading…
Reference in New Issue