Introduce support for GetBestAnchor(SAPLING).

This commit is contained in:
Sean Bowe 2018-04-27 16:00:21 -06:00
parent 2bd59e1473
commit 18322f074c
12 changed files with 97 additions and 44 deletions

View File

@ -47,10 +47,11 @@ bool CCoinsView::GetNullifier(const uint256 &nullifier, ShieldedType type) const
bool CCoinsView::GetCoins(const uint256 &txid, CCoins &coins) const { return false; } bool CCoinsView::GetCoins(const uint256 &txid, CCoins &coins) const { return false; }
bool CCoinsView::HaveCoins(const uint256 &txid) const { return false; } bool CCoinsView::HaveCoins(const uint256 &txid) const { return false; }
uint256 CCoinsView::GetBestBlock() const { return uint256(); } uint256 CCoinsView::GetBestBlock() const { return uint256(); }
uint256 CCoinsView::GetBestAnchor() const { return uint256(); }; uint256 CCoinsView::GetBestAnchor(ShieldedType type) const { return uint256(); };
bool CCoinsView::BatchWrite(CCoinsMap &mapCoins, bool CCoinsView::BatchWrite(CCoinsMap &mapCoins,
const uint256 &hashBlock, const uint256 &hashBlock,
const uint256 &hashSproutAnchor, const uint256 &hashSproutAnchor,
const uint256 &hashSaplingAnchor,
CAnchorsSproutMap &mapSproutAnchors, CAnchorsSproutMap &mapSproutAnchors,
CNullifiersMap &mapSproutNullifiers, CNullifiersMap &mapSproutNullifiers,
CNullifiersMap &mapSaplingNullifiers) { return false; } CNullifiersMap &mapSaplingNullifiers) { return false; }
@ -64,14 +65,15 @@ bool CCoinsViewBacked::GetNullifier(const uint256 &nullifier, ShieldedType type)
bool CCoinsViewBacked::GetCoins(const uint256 &txid, CCoins &coins) const { return base->GetCoins(txid, coins); } 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); } bool CCoinsViewBacked::HaveCoins(const uint256 &txid) const { return base->HaveCoins(txid); }
uint256 CCoinsViewBacked::GetBestBlock() const { return base->GetBestBlock(); } uint256 CCoinsViewBacked::GetBestBlock() const { return base->GetBestBlock(); }
uint256 CCoinsViewBacked::GetBestAnchor() const { return base->GetBestAnchor(); } uint256 CCoinsViewBacked::GetBestAnchor(ShieldedType type) const { return base->GetBestAnchor(type); }
void CCoinsViewBacked::SetBackend(CCoinsView &viewIn) { base = &viewIn; } void CCoinsViewBacked::SetBackend(CCoinsView &viewIn) { base = &viewIn; }
bool CCoinsViewBacked::BatchWrite(CCoinsMap &mapCoins, bool CCoinsViewBacked::BatchWrite(CCoinsMap &mapCoins,
const uint256 &hashBlock, const uint256 &hashBlock,
const uint256 &hashSproutAnchor, const uint256 &hashSproutAnchor,
const uint256 &hashSaplingAnchor,
CAnchorsSproutMap &mapSproutAnchors, CAnchorsSproutMap &mapSproutAnchors,
CNullifiersMap &mapSproutNullifiers, CNullifiersMap &mapSproutNullifiers,
CNullifiersMap &mapSaplingNullifiers) { return base->BatchWrite(mapCoins, hashBlock, hashSproutAnchor, mapSproutAnchors, mapSproutNullifiers, mapSaplingNullifiers); } CNullifiersMap &mapSaplingNullifiers) { return base->BatchWrite(mapCoins, hashBlock, hashSproutAnchor, hashSaplingAnchor, mapSproutAnchors, mapSproutNullifiers, mapSaplingNullifiers); }
bool CCoinsViewBacked::GetStats(CCoinsStats &stats) const { return base->GetStats(stats); } bool CCoinsViewBacked::GetStats(CCoinsStats &stats) const { return base->GetStats(stats); }
CCoinsKeyHasher::CCoinsKeyHasher() : salt(GetRandHash()) {} CCoinsKeyHasher::CCoinsKeyHasher() : salt(GetRandHash()) {}
@ -161,7 +163,7 @@ bool CCoinsViewCache::GetNullifier(const uint256 &nullifier, ShieldedType type)
void CCoinsViewCache::PushSproutAnchor(const ZCIncrementalMerkleTree &tree) { void CCoinsViewCache::PushSproutAnchor(const ZCIncrementalMerkleTree &tree) {
uint256 newrt = tree.root(); uint256 newrt = tree.root();
auto currentRoot = GetBestAnchor(); auto currentRoot = GetBestAnchor(SPROUT);
// We don't want to overwrite an anchor we already have. // We don't want to overwrite an anchor we already have.
// This occurs when a block doesn't modify mapSproutAnchors at all, // This occurs when a block doesn't modify mapSproutAnchors at all,
@ -186,7 +188,7 @@ void CCoinsViewCache::PushSproutAnchor(const ZCIncrementalMerkleTree &tree) {
} }
void CCoinsViewCache::PopAnchor(const uint256 &newrt) { void CCoinsViewCache::PopAnchor(const uint256 &newrt) {
auto currentRoot = GetBestAnchor(); auto currentRoot = GetBestAnchor(SPROUT);
// Blocks might not change the commitment tree, in which // Blocks might not change the commitment tree, in which
// case restoring the "old" anchor during a reorg must // case restoring the "old" anchor during a reorg must
@ -280,10 +282,21 @@ uint256 CCoinsViewCache::GetBestBlock() const {
} }
uint256 CCoinsViewCache::GetBestAnchor() const { uint256 CCoinsViewCache::GetBestAnchor(ShieldedType type) const {
switch (type) {
case SPROUT:
if (hashSproutAnchor.IsNull()) if (hashSproutAnchor.IsNull())
hashSproutAnchor = base->GetBestAnchor(); hashSproutAnchor = base->GetBestAnchor(type);
return hashSproutAnchor; return hashSproutAnchor;
break;
case SAPLING:
if (hashSaplingAnchor.IsNull())
hashSaplingAnchor = base->GetBestAnchor(type);
return hashSaplingAnchor;
break;
default:
throw std::runtime_error("Unknown shielded type " + type);
}
} }
void CCoinsViewCache::SetBestBlock(const uint256 &hashBlockIn) { void CCoinsViewCache::SetBestBlock(const uint256 &hashBlockIn) {
@ -315,6 +328,7 @@ void BatchWriteNullifiers(CNullifiersMap &mapNullifiers, CNullifiersMap &cacheNu
bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins, bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins,
const uint256 &hashBlockIn, const uint256 &hashBlockIn,
const uint256 &hashSproutAnchorIn, const uint256 &hashSproutAnchorIn,
const uint256 &hashSaplingAnchorIn,
CAnchorsSproutMap &mapSproutAnchors, CAnchorsSproutMap &mapSproutAnchors,
CNullifiersMap &mapSproutNullifiers, CNullifiersMap &mapSproutNullifiers,
CNullifiersMap &mapSaplingNullifiers) { CNullifiersMap &mapSaplingNullifiers) {
@ -383,12 +397,13 @@ bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins,
::BatchWriteNullifiers(mapSaplingNullifiers, cacheSaplingNullifiers); ::BatchWriteNullifiers(mapSaplingNullifiers, cacheSaplingNullifiers);
hashSproutAnchor = hashSproutAnchorIn; hashSproutAnchor = hashSproutAnchorIn;
hashSaplingAnchor = hashSaplingAnchorIn;
hashBlock = hashBlockIn; hashBlock = hashBlockIn;
return true; return true;
} }
bool CCoinsViewCache::Flush() { bool CCoinsViewCache::Flush() {
bool fOk = base->BatchWrite(cacheCoins, hashBlock, hashSproutAnchor, cacheSproutAnchors, cacheSproutNullifiers, cacheSaplingNullifiers); bool fOk = base->BatchWrite(cacheCoins, hashBlock, hashSproutAnchor, hashSaplingAnchor, cacheSproutAnchors, cacheSproutNullifiers, cacheSaplingNullifiers);
cacheCoins.clear(); cacheCoins.clear();
cacheSproutAnchors.clear(); cacheSproutAnchors.clear();
cacheSproutNullifiers.clear(); cacheSproutNullifiers.clear();

View File

@ -343,13 +343,14 @@ public:
virtual uint256 GetBestBlock() const; virtual uint256 GetBestBlock() const;
//! Get the current "tip" or the latest anchored tree root in the chain //! Get the current "tip" or the latest anchored tree root in the chain
virtual uint256 GetBestAnchor() const; virtual uint256 GetBestAnchor(ShieldedType type) const;
//! Do a bulk modification (multiple CCoins changes + BestBlock change). //! Do a bulk modification (multiple CCoins changes + BestBlock change).
//! The passed mapCoins can be modified. //! The passed mapCoins can be modified.
virtual bool BatchWrite(CCoinsMap &mapCoins, virtual bool BatchWrite(CCoinsMap &mapCoins,
const uint256 &hashBlock, const uint256 &hashBlock,
const uint256 &hashSproutAnchor, const uint256 &hashSproutAnchor,
const uint256 &hashSaplingAnchor,
CAnchorsSproutMap &mapSproutAnchors, CAnchorsSproutMap &mapSproutAnchors,
CNullifiersMap &mapSproutNullifiers, CNullifiersMap &mapSproutNullifiers,
CNullifiersMap &mapSaplingNullifiers); CNullifiersMap &mapSaplingNullifiers);
@ -375,11 +376,12 @@ public:
bool GetCoins(const uint256 &txid, CCoins &coins) const; bool GetCoins(const uint256 &txid, CCoins &coins) const;
bool HaveCoins(const uint256 &txid) const; bool HaveCoins(const uint256 &txid) const;
uint256 GetBestBlock() const; uint256 GetBestBlock() const;
uint256 GetBestAnchor() const; uint256 GetBestAnchor(ShieldedType type) const;
void SetBackend(CCoinsView &viewIn); void SetBackend(CCoinsView &viewIn);
bool BatchWrite(CCoinsMap &mapCoins, bool BatchWrite(CCoinsMap &mapCoins,
const uint256 &hashBlock, const uint256 &hashBlock,
const uint256 &hashSproutAnchor, const uint256 &hashSproutAnchor,
const uint256 &hashSaplingAnchor,
CAnchorsSproutMap &mapSproutAnchors, CAnchorsSproutMap &mapSproutAnchors,
CNullifiersMap &mapSproutNullifiers, CNullifiersMap &mapSproutNullifiers,
CNullifiersMap &mapSaplingNullifiers); CNullifiersMap &mapSaplingNullifiers);
@ -424,6 +426,7 @@ protected:
mutable uint256 hashBlock; mutable uint256 hashBlock;
mutable CCoinsMap cacheCoins; mutable CCoinsMap cacheCoins;
mutable uint256 hashSproutAnchor; mutable uint256 hashSproutAnchor;
mutable uint256 hashSaplingAnchor;
mutable CAnchorsSproutMap cacheSproutAnchors; mutable CAnchorsSproutMap cacheSproutAnchors;
mutable CNullifiersMap cacheSproutNullifiers; mutable CNullifiersMap cacheSproutNullifiers;
mutable CNullifiersMap cacheSaplingNullifiers; mutable CNullifiersMap cacheSaplingNullifiers;
@ -441,11 +444,12 @@ public:
bool GetCoins(const uint256 &txid, CCoins &coins) const; bool GetCoins(const uint256 &txid, CCoins &coins) const;
bool HaveCoins(const uint256 &txid) const; bool HaveCoins(const uint256 &txid) const;
uint256 GetBestBlock() const; uint256 GetBestBlock() const;
uint256 GetBestAnchor() const; uint256 GetBestAnchor(ShieldedType type) const;
void SetBestBlock(const uint256 &hashBlock); void SetBestBlock(const uint256 &hashBlock);
bool BatchWrite(CCoinsMap &mapCoins, bool BatchWrite(CCoinsMap &mapCoins,
const uint256 &hashBlock, const uint256 &hashBlock,
const uint256 &hashSproutAnchor, const uint256 &hashSproutAnchor,
const uint256 &hashSaplingAnchor,
CAnchorsSproutMap &mapSproutAnchors, CAnchorsSproutMap &mapSproutAnchors,
CNullifiersMap &mapSproutNullifiers, CNullifiersMap &mapSproutNullifiers,
CNullifiersMap &mapSaplingNullifiers); CNullifiersMap &mapSaplingNullifiers);

View File

@ -47,7 +47,7 @@ public:
return a; return a;
} }
uint256 GetBestAnchor() const { uint256 GetBestAnchor(ShieldedType type) const {
uint256 a; uint256 a;
return a; return a;
} }
@ -55,6 +55,7 @@ public:
bool BatchWrite(CCoinsMap &mapCoins, bool BatchWrite(CCoinsMap &mapCoins,
const uint256 &hashBlock, const uint256 &hashBlock,
const uint256 &hashSproutAnchor, const uint256 &hashSproutAnchor,
const uint256 &hashSaplingAnchor,
CAnchorsSproutMap &mapSproutAnchors, CAnchorsSproutMap &mapSproutAnchors,
CNullifiersMap &mapSproutNullifiers, CNullifiersMap &mapSproutNullifiers,
CNullifiersMap &mapSaplingNullifiers) { CNullifiersMap &mapSaplingNullifiers) {

View File

@ -42,7 +42,7 @@ public:
return a; return a;
} }
uint256 GetBestAnchor() const { uint256 GetBestAnchor(ShieldedType type) const {
uint256 a; uint256 a;
return a; return a;
} }
@ -50,6 +50,7 @@ public:
bool BatchWrite(CCoinsMap &mapCoins, bool BatchWrite(CCoinsMap &mapCoins,
const uint256 &hashBlock, const uint256 &hashBlock,
const uint256 &hashSproutAnchor, const uint256 &hashSproutAnchor,
const uint256 &hashSaplingAnchor,
CAnchorsSproutMap &mapSproutAnchors, CAnchorsSproutMap &mapSproutAnchors,
CNullifiersMap &mapSproutNullifiers, CNullifiersMap &mapSproutNullifiers,
CNullifiersMap saplingNullifiersMap) { CNullifiersMap saplingNullifiersMap) {

View File

@ -2330,7 +2330,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
// Construct the incremental merkle tree at the current // Construct the incremental merkle tree at the current
// block position, // block position,
auto old_tree_root = view.GetBestAnchor(); auto old_tree_root = view.GetBestAnchor(SPROUT);
// saving the top anchor in the block index as we go. // saving the top anchor in the block index as we go.
if (!fJustCheck) { if (!fJustCheck) {
pindex->hashSproutAnchor = old_tree_root; pindex->hashSproutAnchor = old_tree_root;
@ -2658,7 +2658,7 @@ bool static DisconnectTip(CValidationState &state, bool fBare = false) {
if (!ReadBlockFromDisk(block, pindexDelete)) if (!ReadBlockFromDisk(block, pindexDelete))
return AbortNode(state, "Failed to read block"); return AbortNode(state, "Failed to read block");
// Apply the block atomically to the chain state. // Apply the block atomically to the chain state.
uint256 anchorBeforeDisconnect = pcoinsTip->GetBestAnchor(); uint256 anchorBeforeDisconnect = pcoinsTip->GetBestAnchor(SPROUT);
int64_t nStart = GetTimeMicros(); int64_t nStart = GetTimeMicros();
{ {
CCoinsViewCache view(pcoinsTip); CCoinsViewCache view(pcoinsTip);
@ -2667,7 +2667,7 @@ bool static DisconnectTip(CValidationState &state, bool fBare = false) {
assert(view.Flush()); assert(view.Flush());
} }
LogPrint("bench", "- Disconnect block: %.2fms\n", (GetTimeMicros() - nStart) * 0.001); LogPrint("bench", "- Disconnect block: %.2fms\n", (GetTimeMicros() - nStart) * 0.001);
uint256 anchorAfterDisconnect = pcoinsTip->GetBestAnchor(); uint256 anchorAfterDisconnect = pcoinsTip->GetBestAnchor(SPROUT);
// Write the chain state to disk, if necessary. // Write the chain state to disk, if necessary.
if (!FlushStateToDisk(state, FLUSH_STATE_IF_NEEDED)) if (!FlushStateToDisk(state, FLUSH_STATE_IF_NEEDED))
return false; return false;
@ -2692,7 +2692,7 @@ bool static DisconnectTip(CValidationState &state, bool fBare = false) {
UpdateTip(pindexDelete->pprev); UpdateTip(pindexDelete->pprev);
// Get the current commitment tree // Get the current commitment tree
ZCIncrementalMerkleTree newTree; ZCIncrementalMerkleTree newTree;
assert(pcoinsTip->GetSproutAnchorAt(pcoinsTip->GetBestAnchor(), newTree)); assert(pcoinsTip->GetSproutAnchorAt(pcoinsTip->GetBestAnchor(SPROUT), newTree));
// Let wallets know transactions went from 1-confirmed to // Let wallets know transactions went from 1-confirmed to
// 0-confirmed or conflicted: // 0-confirmed or conflicted:
BOOST_FOREACH(const CTransaction &tx, block.vtx) { BOOST_FOREACH(const CTransaction &tx, block.vtx) {
@ -2726,7 +2726,7 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock *
} }
// Get the current commitment tree // Get the current commitment tree
ZCIncrementalMerkleTree oldTree; ZCIncrementalMerkleTree oldTree;
assert(pcoinsTip->GetSproutAnchorAt(pcoinsTip->GetBestAnchor(), oldTree)); assert(pcoinsTip->GetSproutAnchorAt(pcoinsTip->GetBestAnchor(SPROUT), oldTree));
// Apply the block atomically to the chain state. // Apply the block atomically to the chain state.
int64_t nTime2 = GetTimeMicros(); nTimeReadFromDisk += nTime2 - nTime1; int64_t nTime2 = GetTimeMicros(); nTimeReadFromDisk += nTime2 - nTime1;
int64_t nTime3; int64_t nTime3;
@ -3942,7 +3942,7 @@ bool static LoadBlockIndexDB()
return true; return true;
chainActive.SetTip(it->second); chainActive.SetTip(it->second);
// Set hashSproutAnchorEnd for the end of best chain // Set hashSproutAnchorEnd for the end of best chain
it->second->hashSproutAnchorEnd = pcoinsTip->GetBestAnchor(); it->second->hashSproutAnchorEnd = pcoinsTip->GetBestAnchor(SPROUT);
PruneBlockIndexCandidates(); PruneBlockIndexCandidates();

View File

@ -770,7 +770,7 @@ UniValue getblockchaininfo(const UniValue& params, bool fHelp)
obj.push_back(Pair("pruned", fPruneMode)); obj.push_back(Pair("pruned", fPruneMode));
ZCIncrementalMerkleTree tree; ZCIncrementalMerkleTree tree;
pcoinsTip->GetSproutAnchorAt(pcoinsTip->GetBestAnchor(), tree); pcoinsTip->GetSproutAnchorAt(pcoinsTip->GetBestAnchor(SPROUT), tree);
obj.push_back(Pair("commitments", static_cast<uint64_t>(tree.size()))); obj.push_back(Pair("commitments", static_cast<uint64_t>(tree.size())));
CBlockIndex* tip = chainActive.Tip(); CBlockIndex* tip = chainActive.Tip();

View File

@ -26,6 +26,7 @@ class CCoinsViewTest : public CCoinsView
{ {
uint256 hashBestBlock_; uint256 hashBestBlock_;
uint256 hashBestSproutAnchor_; uint256 hashBestSproutAnchor_;
uint256 hashBestSaplingAnchor_;
std::map<uint256, CCoins> map_; std::map<uint256, CCoins> map_;
std::map<uint256, ZCIncrementalMerkleTree> mapSproutAnchors_; std::map<uint256, ZCIncrementalMerkleTree> mapSproutAnchors_;
std::map<uint256, bool> mapSproutNullifiers_; std::map<uint256, bool> mapSproutNullifiers_;
@ -34,6 +35,7 @@ class CCoinsViewTest : public CCoinsView
public: public:
CCoinsViewTest() { CCoinsViewTest() {
hashBestSproutAnchor_ = ZCIncrementalMerkleTree::empty_root(); hashBestSproutAnchor_ = ZCIncrementalMerkleTree::empty_root();
hashBestSaplingAnchor_ = ZCSaplingIncrementalMerkleTree::empty_root();
} }
bool GetSproutAnchorAt(const uint256& rt, ZCIncrementalMerkleTree &tree) const { bool GetSproutAnchorAt(const uint256& rt, ZCIncrementalMerkleTree &tree) const {
@ -75,7 +77,18 @@ public:
} }
} }
uint256 GetBestAnchor() const { return hashBestSproutAnchor_; } uint256 GetBestAnchor(ShieldedType type) const {
switch (type) {
case SPROUT:
return hashBestSproutAnchor_;
break;
case SAPLING:
return hashBestSaplingAnchor_;
break;
default:
throw std::runtime_error("Unknown shielded type " + type);
}
}
bool GetCoins(const uint256& txid, CCoins& coins) const bool GetCoins(const uint256& txid, CCoins& coins) const
{ {
@ -115,6 +128,7 @@ public:
bool BatchWrite(CCoinsMap& mapCoins, bool BatchWrite(CCoinsMap& mapCoins,
const uint256& hashBlock, const uint256& hashBlock,
const uint256& hashSproutAnchor, const uint256& hashSproutAnchor,
const uint256& hashSaplingAnchor,
CAnchorsSproutMap& mapSproutAnchors, CAnchorsSproutMap& mapSproutAnchors,
CNullifiersMap& mapSproutNullifiers, CNullifiersMap& mapSproutNullifiers,
CNullifiersMap& mapSaplingNullifiers) CNullifiersMap& mapSaplingNullifiers)
@ -146,6 +160,7 @@ public:
mapSproutAnchors.clear(); mapSproutAnchors.clear();
hashBestBlock_ = hashBlock; hashBestBlock_ = hashBlock;
hashBestSproutAnchor_ = hashSproutAnchor; hashBestSproutAnchor_ = hashSproutAnchor;
hashBestSaplingAnchor_ = hashSaplingAnchor;
return true; return true;
} }
@ -402,7 +417,7 @@ BOOST_AUTO_TEST_CASE(anchor_regression_test)
cache1.Flush(); cache1.Flush();
cache1.PopAnchor(ZCIncrementalMerkleTree::empty_root()); cache1.PopAnchor(ZCIncrementalMerkleTree::empty_root());
BOOST_CHECK(cache1.GetBestAnchor() == ZCIncrementalMerkleTree::empty_root()); BOOST_CHECK(cache1.GetBestAnchor(SPROUT) == ZCIncrementalMerkleTree::empty_root());
BOOST_CHECK(!cache1.GetSproutAnchorAt(tree.root(), tree)); BOOST_CHECK(!cache1.GetSproutAnchorAt(tree.root(), tree));
} }
@ -420,7 +435,7 @@ BOOST_AUTO_TEST_CASE(anchor_regression_test)
cache1.PopAnchor(ZCIncrementalMerkleTree::empty_root()); cache1.PopAnchor(ZCIncrementalMerkleTree::empty_root());
cache1.Flush(); cache1.Flush();
BOOST_CHECK(cache1.GetBestAnchor() == ZCIncrementalMerkleTree::empty_root()); BOOST_CHECK(cache1.GetBestAnchor(SPROUT) == ZCIncrementalMerkleTree::empty_root());
BOOST_CHECK(!cache1.GetSproutAnchorAt(tree.root(), tree)); BOOST_CHECK(!cache1.GetSproutAnchorAt(tree.root(), tree));
} }
@ -444,7 +459,7 @@ BOOST_AUTO_TEST_CASE(anchor_regression_test)
cache2.Flush(); cache2.Flush();
} }
BOOST_CHECK(cache1.GetBestAnchor() == ZCIncrementalMerkleTree::empty_root()); BOOST_CHECK(cache1.GetBestAnchor(SPROUT) == ZCIncrementalMerkleTree::empty_root());
BOOST_CHECK(!cache1.GetSproutAnchorAt(tree.root(), tree)); BOOST_CHECK(!cache1.GetSproutAnchorAt(tree.root(), tree));
} }
@ -467,7 +482,7 @@ BOOST_AUTO_TEST_CASE(anchor_regression_test)
cache2.Flush(); cache2.Flush();
} }
BOOST_CHECK(cache1.GetBestAnchor() == ZCIncrementalMerkleTree::empty_root()); BOOST_CHECK(cache1.GetBestAnchor(SPROUT) == ZCIncrementalMerkleTree::empty_root());
BOOST_CHECK(!cache1.GetSproutAnchorAt(tree.root(), tree)); BOOST_CHECK(!cache1.GetSproutAnchorAt(tree.root(), tree));
} }
} }
@ -502,7 +517,7 @@ BOOST_AUTO_TEST_CASE(anchors_flush_test)
{ {
CCoinsViewCacheTest cache(&base); CCoinsViewCacheTest cache(&base);
ZCIncrementalMerkleTree tree; ZCIncrementalMerkleTree tree;
BOOST_CHECK(cache.GetSproutAnchorAt(cache.GetBestAnchor(), tree)); BOOST_CHECK(cache.GetSproutAnchorAt(cache.GetBestAnchor(SPROUT), tree));
appendRandomCommitment(tree); appendRandomCommitment(tree);
newrt = tree.root(); newrt = tree.root();
@ -514,10 +529,10 @@ BOOST_AUTO_TEST_CASE(anchors_flush_test)
{ {
CCoinsViewCacheTest cache(&base); CCoinsViewCacheTest cache(&base);
ZCIncrementalMerkleTree tree; ZCIncrementalMerkleTree tree;
BOOST_CHECK(cache.GetSproutAnchorAt(cache.GetBestAnchor(), tree)); BOOST_CHECK(cache.GetSproutAnchorAt(cache.GetBestAnchor(SPROUT), tree));
// Get the cached entry. // Get the cached entry.
BOOST_CHECK(cache.GetSproutAnchorAt(cache.GetBestAnchor(), tree)); BOOST_CHECK(cache.GetSproutAnchorAt(cache.GetBestAnchor(SPROUT), tree));
uint256 check_rt = tree.root(); uint256 check_rt = tree.root();
@ -610,13 +625,13 @@ BOOST_AUTO_TEST_CASE(anchors_test)
CCoinsViewTest base; CCoinsViewTest base;
CCoinsViewCacheTest cache(&base); CCoinsViewCacheTest cache(&base);
BOOST_CHECK(cache.GetBestAnchor() == ZCIncrementalMerkleTree::empty_root()); BOOST_CHECK(cache.GetBestAnchor(SPROUT) == ZCIncrementalMerkleTree::empty_root());
{ {
ZCIncrementalMerkleTree tree; ZCIncrementalMerkleTree tree;
BOOST_CHECK(cache.GetSproutAnchorAt(cache.GetBestAnchor(), tree)); BOOST_CHECK(cache.GetSproutAnchorAt(cache.GetBestAnchor(SPROUT), tree));
BOOST_CHECK(cache.GetBestAnchor() == tree.root()); BOOST_CHECK(cache.GetBestAnchor(SPROUT) == tree.root());
appendRandomCommitment(tree); appendRandomCommitment(tree);
appendRandomCommitment(tree); appendRandomCommitment(tree);
appendRandomCommitment(tree); appendRandomCommitment(tree);
@ -632,11 +647,11 @@ BOOST_AUTO_TEST_CASE(anchors_test)
uint256 newrt2; uint256 newrt2;
cache.PushSproutAnchor(tree); cache.PushSproutAnchor(tree);
BOOST_CHECK(cache.GetBestAnchor() == newrt); BOOST_CHECK(cache.GetBestAnchor(SPROUT) == newrt);
{ {
ZCIncrementalMerkleTree confirm_same; ZCIncrementalMerkleTree confirm_same;
BOOST_CHECK(cache.GetSproutAnchorAt(cache.GetBestAnchor(), confirm_same)); BOOST_CHECK(cache.GetSproutAnchorAt(cache.GetBestAnchor(SPROUT), confirm_same));
BOOST_CHECK(confirm_same.root() == newrt); BOOST_CHECK(confirm_same.root() == newrt);
} }
@ -647,10 +662,10 @@ BOOST_AUTO_TEST_CASE(anchors_test)
newrt2 = tree.root(); newrt2 = tree.root();
cache.PushSproutAnchor(tree); cache.PushSproutAnchor(tree);
BOOST_CHECK(cache.GetBestAnchor() == newrt2); BOOST_CHECK(cache.GetBestAnchor(SPROUT) == newrt2);
ZCIncrementalMerkleTree test_tree; ZCIncrementalMerkleTree test_tree;
BOOST_CHECK(cache.GetSproutAnchorAt(cache.GetBestAnchor(), test_tree)); BOOST_CHECK(cache.GetSproutAnchorAt(cache.GetBestAnchor(SPROUT), test_tree));
BOOST_CHECK(tree.root() == test_tree.root()); BOOST_CHECK(tree.root() == test_tree.root());

View File

@ -27,6 +27,7 @@ static const char DB_BLOCK_INDEX = 'b';
static const char DB_BEST_BLOCK = 'B'; static const char DB_BEST_BLOCK = 'B';
static const char DB_BEST_SPROUT_ANCHOR = 'a'; static const char DB_BEST_SPROUT_ANCHOR = 'a';
static const char DB_BEST_SAPLING_ANCHOR = 'x';
static const char DB_FLAG = 'F'; static const char DB_FLAG = 'F';
static const char DB_REINDEX_FLAG = 'R'; static const char DB_REINDEX_FLAG = 'R';
static const char DB_LAST_BLOCK = 'l'; static const char DB_LAST_BLOCK = 'l';
@ -83,10 +84,22 @@ uint256 CCoinsViewDB::GetBestBlock() const {
return hashBestChain; return hashBestChain;
} }
uint256 CCoinsViewDB::GetBestAnchor() const { uint256 CCoinsViewDB::GetBestAnchor(ShieldedType type) const {
uint256 hashBestAnchor; uint256 hashBestAnchor;
switch (type) {
case SPROUT:
if (!db.Read(DB_BEST_SPROUT_ANCHOR, hashBestAnchor)) if (!db.Read(DB_BEST_SPROUT_ANCHOR, hashBestAnchor))
return ZCIncrementalMerkleTree::empty_root(); return ZCIncrementalMerkleTree::empty_root();
break;
case SAPLING:
if (!db.Read(DB_BEST_SAPLING_ANCHOR, hashBestAnchor))
return ZCSaplingIncrementalMerkleTree::empty_root();
break;
default:
throw runtime_error("Unknown shielded type " + type);
}
return hashBestAnchor; return hashBestAnchor;
} }
@ -108,6 +121,7 @@ void BatchWriteNullifiers(CDBBatch& batch, CNullifiersMap& mapToUse, const char&
bool CCoinsViewDB::BatchWrite(CCoinsMap &mapCoins, bool CCoinsViewDB::BatchWrite(CCoinsMap &mapCoins,
const uint256 &hashBlock, const uint256 &hashBlock,
const uint256 &hashSproutAnchor, const uint256 &hashSproutAnchor,
const uint256 &hashSaplingAnchor,
CAnchorsSproutMap &mapSproutAnchors, CAnchorsSproutMap &mapSproutAnchors,
CNullifiersMap &mapSproutNullifiers, CNullifiersMap &mapSproutNullifiers,
CNullifiersMap &mapSaplingNullifiers) { CNullifiersMap &mapSaplingNullifiers) {
@ -147,6 +161,8 @@ bool CCoinsViewDB::BatchWrite(CCoinsMap &mapCoins,
batch.Write(DB_BEST_BLOCK, hashBlock); batch.Write(DB_BEST_BLOCK, hashBlock);
if (!hashSproutAnchor.IsNull()) if (!hashSproutAnchor.IsNull())
batch.Write(DB_BEST_SPROUT_ANCHOR, hashSproutAnchor); batch.Write(DB_BEST_SPROUT_ANCHOR, hashSproutAnchor);
if (!hashSaplingAnchor.IsNull())
batch.Write(DB_BEST_SAPLING_ANCHOR, hashSaplingAnchor);
LogPrint("coindb", "Committing %u changed transactions (out of %u) to coin database...\n", (unsigned int)changed, (unsigned int)count); LogPrint("coindb", "Committing %u changed transactions (out of %u) to coin database...\n", (unsigned int)changed, (unsigned int)count);
return db.WriteBatch(batch); return db.WriteBatch(batch);

View File

@ -40,10 +40,11 @@ public:
bool GetCoins(const uint256 &txid, CCoins &coins) const; bool GetCoins(const uint256 &txid, CCoins &coins) const;
bool HaveCoins(const uint256 &txid) const; bool HaveCoins(const uint256 &txid) const;
uint256 GetBestBlock() const; uint256 GetBestBlock() const;
uint256 GetBestAnchor() const; uint256 GetBestAnchor(ShieldedType type) const;
bool BatchWrite(CCoinsMap &mapCoins, bool BatchWrite(CCoinsMap &mapCoins,
const uint256 &hashBlock, const uint256 &hashBlock,
const uint256 &hashSproutAnchor, const uint256 &hashSproutAnchor,
const uint256 &hashSaplingAnchor,
CAnchorsSproutMap &mapSproutAnchors, CAnchorsSproutMap &mapSproutAnchors,
CNullifiersMap &mapSproutNullifiers, CNullifiersMap &mapSproutNullifiers,
CNullifiersMap &mapSaplingNullifiers); CNullifiersMap &mapSaplingNullifiers);

View File

@ -693,7 +693,7 @@ UniValue AsyncRPCOperation_mergetoaddress::perform_joinsplit(MergeToAddressJSInf
uint256 anchor; uint256 anchor;
{ {
LOCK(cs_main); LOCK(cs_main);
anchor = pcoinsTip->GetBestAnchor(); // As there are no inputs, ask the wallet for the best anchor anchor = pcoinsTip->GetBestAnchor(SPROUT); // As there are no inputs, ask the wallet for the best anchor
} }
return perform_joinsplit(info, witnesses, anchor); return perform_joinsplit(info, witnesses, anchor);
} }

View File

@ -914,7 +914,7 @@ UniValue AsyncRPCOperation_sendmany::perform_joinsplit(AsyncJoinSplitInfo & info
uint256 anchor; uint256 anchor;
{ {
LOCK(cs_main); LOCK(cs_main);
anchor = pcoinsTip->GetBestAnchor(); // As there are no inputs, ask the wallet for the best anchor anchor = pcoinsTip->GetBestAnchor(SPROUT); // As there are no inputs, ask the wallet for the best anchor
} }
return perform_joinsplit(info, witnesses, anchor); return perform_joinsplit(info, witnesses, anchor);
} }

View File

@ -314,7 +314,7 @@ UniValue AsyncRPCOperation_shieldcoinbase::perform_joinsplit(ShieldCoinbaseJSInf
{ {
LOCK(cs_main); LOCK(cs_main);
consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus()); consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus());
anchor = pcoinsTip->GetBestAnchor(); anchor = pcoinsTip->GetBestAnchor(SPROUT);
} }