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

@@ -43,7 +43,7 @@ bool CCoins::Spend(uint32_t nPos)
return true;
}
bool CCoinsView::GetAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tree) const { return false; }
bool CCoinsView::GetNullifier(const uint256 &nullifier) const { return false; }
bool CCoinsView::GetNullifier(const uint256 &nullifier, bool isSapling) const { return false; }
bool CCoinsView::GetCoins(const uint256 &txid, CCoins &coins) const { return false; }
bool CCoinsView::HaveCoins(const uint256 &txid) const { return false; }
uint256 CCoinsView::GetBestBlock() const { return uint256(); }
@@ -52,14 +52,15 @@ bool CCoinsView::BatchWrite(CCoinsMap &mapCoins,
const uint256 &hashBlock,
const uint256 &hashAnchor,
CAnchorsMap &mapAnchors,
CNullifiersMap &mapNullifiers) { return false; }
CNullifiersMap &mapNullifiers,
CNullifiersMap &mapSaplingNullifiers) { return false; }
bool CCoinsView::GetStats(CCoinsStats &stats) const { return false; }
CCoinsViewBacked::CCoinsViewBacked(CCoinsView *viewIn) : base(viewIn) { }
bool CCoinsViewBacked::GetAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tree) const { return base->GetAnchorAt(rt, tree); }
bool CCoinsViewBacked::GetNullifier(const uint256 &nullifier) const { return base->GetNullifier(nullifier); }
bool CCoinsViewBacked::GetNullifier(const uint256 &nullifier, bool isSapling) const { return base->GetNullifier(nullifier, isSapling); }
bool CCoinsViewBacked::GetCoins(const uint256 &txid, CCoins &coins) const { return base->GetCoins(txid, coins); }
bool CCoinsViewBacked::HaveCoins(const uint256 &txid) const { return base->HaveCoins(txid); }
uint256 CCoinsViewBacked::GetBestBlock() const { return base->GetBestBlock(); }
@@ -69,7 +70,8 @@ bool CCoinsViewBacked::BatchWrite(CCoinsMap &mapCoins,
const uint256 &hashBlock,
const uint256 &hashAnchor,
CAnchorsMap &mapAnchors,
CNullifiersMap &mapNullifiers) { return base->BatchWrite(mapCoins, hashBlock, hashAnchor, mapAnchors, mapNullifiers); }
CNullifiersMap &mapNullifiers,
CNullifiersMap &mapSaplingNullifiers) { return base->BatchWrite(mapCoins, hashBlock, hashAnchor, mapAnchors, mapNullifiers, mapSaplingNullifiers); }
bool CCoinsViewBacked::GetStats(CCoinsStats &stats) const { return base->GetStats(stats); }
CCoinsKeyHasher::CCoinsKeyHasher() : salt(GetRandHash()) {}
@@ -85,6 +87,7 @@ size_t CCoinsViewCache::DynamicMemoryUsage() const {
return memusage::DynamicUsage(cacheCoins) +
memusage::DynamicUsage(cacheAnchors) +
memusage::DynamicUsage(cacheNullifiers) +
memusage::DynamicUsage(cacheSaplingNullifiers) +
cachedCoinsUsage;
}
@@ -130,16 +133,17 @@ bool CCoinsViewCache::GetAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tr
return true;
}
bool CCoinsViewCache::GetNullifier(const uint256 &nullifier) const {
CNullifiersMap::iterator it = cacheNullifiers.find(nullifier);
if (it != cacheNullifiers.end())
bool CCoinsViewCache::GetNullifier(const uint256 &nullifier, bool isSapling) const {
CNullifiersMap* cacheToUse = isSapling ? &cacheSaplingNullifiers : &cacheNullifiers;
CNullifiersMap::iterator it = cacheToUse->find(nullifier);
if (it != cacheToUse->end())
return it->second.entered;
CNullifiersCacheEntry entry;
bool tmp = base->GetNullifier(nullifier);
bool tmp = base->GetNullifier(nullifier, isSapling);
entry.entered = tmp;
cacheNullifiers.insert(std::make_pair(nullifier, entry));
cacheToUse->insert(std::make_pair(nullifier, entry));
return tmp;
}
@@ -196,10 +200,15 @@ void CCoinsViewCache::PopAnchor(const uint256 &newrt) {
}
}
void CCoinsViewCache::SetNullifier(const uint256 &nullifier, bool spent) {
std::pair<CNullifiersMap::iterator, bool> ret = cacheNullifiers.insert(std::make_pair(nullifier, CNullifiersCacheEntry()));
ret.first->second.entered = spent;
ret.first->second.flags |= CNullifiersCacheEntry::DIRTY;
void CCoinsViewCache::SetNullifiers(const CTransaction& tx, bool spent) {
for (const JSDescription &joinsplit : tx.vjoinsplit) {
for (const uint256 &nullifier : joinsplit.nullifiers) {
std::pair<CNullifiersMap::iterator, bool> ret = cacheNullifiers.insert(std::make_pair(nullifier, CNullifiersCacheEntry()));
ret.first->second.entered = spent;
ret.first->second.flags |= CNullifiersCacheEntry::DIRTY;
}
}
// TODO add sapling nullifiers
}
bool CCoinsViewCache::GetCoins(const uint256 &txid, CCoins &coins) const {
@@ -267,11 +276,34 @@ void CCoinsViewCache::SetBestBlock(const uint256 &hashBlockIn) {
hashBlock = hashBlockIn;
}
void BatchWriteNullifiers(CNullifiersMap &mapNullifiers, CNullifiersMap &cacheNullifiers)
{
for (CNullifiersMap::iterator child_it = mapNullifiers.begin(); child_it != mapNullifiers.end();) {
if (child_it->second.flags & CNullifiersCacheEntry::DIRTY) { // Ignore non-dirty entries (optimization).
CNullifiersMap::iterator parent_it = cacheNullifiers.find(child_it->first);
if (parent_it == cacheNullifiers.end()) {
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;
parent_it->second.flags |= CNullifiersCacheEntry::DIRTY;
}
}
}
CNullifiersMap::iterator itOld = child_it++;
mapNullifiers.erase(itOld);
}
}
bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins,
const uint256 &hashBlockIn,
const uint256 &hashAnchorIn,
CAnchorsMap &mapAnchors,
CNullifiersMap &mapNullifiers) {
CNullifiersMap &mapNullifiers,
CNullifiersMap &mapSaplingNullifiers) {
assert(!hasModifier);
for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();) {
if (it->second.flags & CCoinsCacheEntry::DIRTY) { // Ignore non-dirty entries (optimization).
@@ -333,25 +365,8 @@ bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins,
mapAnchors.erase(itOld);
}
for (CNullifiersMap::iterator child_it = mapNullifiers.begin(); child_it != mapNullifiers.end();)
{
if (child_it->second.flags & CNullifiersCacheEntry::DIRTY) { // Ignore non-dirty entries (optimization).
CNullifiersMap::iterator parent_it = cacheNullifiers.find(child_it->first);
if (parent_it == cacheNullifiers.end()) {
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;
parent_it->second.flags |= CNullifiersCacheEntry::DIRTY;
}
}
}
CNullifiersMap::iterator itOld = child_it++;
mapNullifiers.erase(itOld);
}
::BatchWriteNullifiers(mapNullifiers, cacheNullifiers);
::BatchWriteNullifiers(mapSaplingNullifiers, cacheSaplingNullifiers);
hashAnchor = hashAnchorIn;
hashBlock = hashBlockIn;
@@ -359,10 +374,11 @@ bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins,
}
bool CCoinsViewCache::Flush() {
bool fOk = base->BatchWrite(cacheCoins, hashBlock, hashAnchor, cacheAnchors, cacheNullifiers);
bool fOk = base->BatchWrite(cacheCoins, hashBlock, hashAnchor, cacheAnchors, cacheNullifiers, cacheSaplingNullifiers);
cacheCoins.clear();
cacheAnchors.clear();
cacheNullifiers.clear();
cacheSaplingNullifiers.clear();
cachedCoinsUsage = 0;
return fOk;
}
@@ -400,7 +416,7 @@ bool CCoinsViewCache::HaveJoinSplitRequirements(const CTransaction& tx) const
{
BOOST_FOREACH(const uint256& nullifier, joinsplit.nullifiers)
{
if (GetNullifier(nullifier)) {
if (GetNullifier(nullifier, false)) {
// If the nullifier is set, this transaction
// double-spends!
return false;
@@ -422,6 +438,7 @@ bool CCoinsViewCache::HaveJoinSplitRequirements(const CTransaction& tx) const
intermediates.insert(std::make_pair(tree.root(), tree));
}
// TODO check sapling nullifiers
return true;
}