Browse Source

Introduce support for GetBestAnchor(SAPLING).

pull/4/head
Sean Bowe 6 years ago
parent
commit
18322f074c
  1. 35
      src/coins.cpp
  2. 10
      src/coins.h
  3. 3
      src/gtest/test_mempool.cpp
  4. 3
      src/gtest/test_validation.cpp
  5. 12
      src/main.cpp
  6. 2
      src/rpcblockchain.cpp
  7. 45
      src/test/coins_tests.cpp
  8. 22
      src/txdb.cpp
  9. 3
      src/txdb.h
  10. 2
      src/wallet/asyncrpcoperation_mergetoaddress.cpp
  11. 2
      src/wallet/asyncrpcoperation_sendmany.cpp
  12. 2
      src/wallet/asyncrpcoperation_shieldcoinbase.cpp

35
src/coins.cpp

@ -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::HaveCoins(const uint256 &txid) const { return false; }
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,
const uint256 &hashBlock,
const uint256 &hashSproutAnchor,
const uint256 &hashSaplingAnchor,
CAnchorsSproutMap &mapSproutAnchors,
CNullifiersMap &mapSproutNullifiers,
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::HaveCoins(const uint256 &txid) const { return base->HaveCoins(txid); }
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; }
bool CCoinsViewBacked::BatchWrite(CCoinsMap &mapCoins,
const uint256 &hashBlock,
const uint256 &hashSproutAnchor,
const uint256 &hashSaplingAnchor,
CAnchorsSproutMap &mapSproutAnchors,
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); }
CCoinsKeyHasher::CCoinsKeyHasher() : salt(GetRandHash()) {}
@ -161,7 +163,7 @@ bool CCoinsViewCache::GetNullifier(const uint256 &nullifier, ShieldedType type)
void CCoinsViewCache::PushSproutAnchor(const ZCIncrementalMerkleTree &tree) {
uint256 newrt = tree.root();
auto currentRoot = GetBestAnchor();
auto currentRoot = GetBestAnchor(SPROUT);
// We don't want to overwrite an anchor we already have.
// 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) {
auto currentRoot = GetBestAnchor();
auto currentRoot = GetBestAnchor(SPROUT);
// Blocks might not change the commitment tree, in which
// case restoring the "old" anchor during a reorg must
@ -280,10 +282,21 @@ uint256 CCoinsViewCache::GetBestBlock() const {
}
uint256 CCoinsViewCache::GetBestAnchor() const {
if (hashSproutAnchor.IsNull())
hashSproutAnchor = base->GetBestAnchor();
return hashSproutAnchor;
uint256 CCoinsViewCache::GetBestAnchor(ShieldedType type) const {
switch (type) {
case SPROUT:
if (hashSproutAnchor.IsNull())
hashSproutAnchor = base->GetBestAnchor(type);
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) {
@ -315,6 +328,7 @@ void BatchWriteNullifiers(CNullifiersMap &mapNullifiers, CNullifiersMap &cacheNu
bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins,
const uint256 &hashBlockIn,
const uint256 &hashSproutAnchorIn,
const uint256 &hashSaplingAnchorIn,
CAnchorsSproutMap &mapSproutAnchors,
CNullifiersMap &mapSproutNullifiers,
CNullifiersMap &mapSaplingNullifiers) {
@ -383,12 +397,13 @@ bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins,
::BatchWriteNullifiers(mapSaplingNullifiers, cacheSaplingNullifiers);
hashSproutAnchor = hashSproutAnchorIn;
hashSaplingAnchor = hashSaplingAnchorIn;
hashBlock = hashBlockIn;
return true;
}
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();
cacheSproutAnchors.clear();
cacheSproutNullifiers.clear();

10
src/coins.h

@ -343,13 +343,14 @@ public:
virtual uint256 GetBestBlock() const;
//! 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).
//! The passed mapCoins can be modified.
virtual bool BatchWrite(CCoinsMap &mapCoins,
const uint256 &hashBlock,
const uint256 &hashSproutAnchor,
const uint256 &hashSaplingAnchor,
CAnchorsSproutMap &mapSproutAnchors,
CNullifiersMap &mapSproutNullifiers,
CNullifiersMap &mapSaplingNullifiers);
@ -375,11 +376,12 @@ public:
bool GetCoins(const uint256 &txid, CCoins &coins) const;
bool HaveCoins(const uint256 &txid) const;
uint256 GetBestBlock() const;
uint256 GetBestAnchor() const;
uint256 GetBestAnchor(ShieldedType type) const;
void SetBackend(CCoinsView &viewIn);
bool BatchWrite(CCoinsMap &mapCoins,
const uint256 &hashBlock,
const uint256 &hashSproutAnchor,
const uint256 &hashSaplingAnchor,
CAnchorsSproutMap &mapSproutAnchors,
CNullifiersMap &mapSproutNullifiers,
CNullifiersMap &mapSaplingNullifiers);
@ -424,6 +426,7 @@ protected:
mutable uint256 hashBlock;
mutable CCoinsMap cacheCoins;
mutable uint256 hashSproutAnchor;
mutable uint256 hashSaplingAnchor;
mutable CAnchorsSproutMap cacheSproutAnchors;
mutable CNullifiersMap cacheSproutNullifiers;
mutable CNullifiersMap cacheSaplingNullifiers;
@ -441,11 +444,12 @@ public:
bool GetCoins(const uint256 &txid, CCoins &coins) const;
bool HaveCoins(const uint256 &txid) const;
uint256 GetBestBlock() const;
uint256 GetBestAnchor() const;
uint256 GetBestAnchor(ShieldedType type) const;
void SetBestBlock(const uint256 &hashBlock);
bool BatchWrite(CCoinsMap &mapCoins,
const uint256 &hashBlock,
const uint256 &hashSproutAnchor,
const uint256 &hashSaplingAnchor,
CAnchorsSproutMap &mapSproutAnchors,
CNullifiersMap &mapSproutNullifiers,
CNullifiersMap &mapSaplingNullifiers);

3
src/gtest/test_mempool.cpp

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

3
src/gtest/test_validation.cpp

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

12
src/main.cpp

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

2
src/rpcblockchain.cpp

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

45
src/test/coins_tests.cpp

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

22
src/txdb.cpp

@ -27,6 +27,7 @@ static const char DB_BLOCK_INDEX = 'b';
static const char DB_BEST_BLOCK = 'B';
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_REINDEX_FLAG = 'R';
static const char DB_LAST_BLOCK = 'l';
@ -83,10 +84,22 @@ uint256 CCoinsViewDB::GetBestBlock() const {
return hashBestChain;
}
uint256 CCoinsViewDB::GetBestAnchor() const {
uint256 CCoinsViewDB::GetBestAnchor(ShieldedType type) const {
uint256 hashBestAnchor;
if (!db.Read(DB_BEST_SPROUT_ANCHOR, hashBestAnchor))
return ZCIncrementalMerkleTree::empty_root();
switch (type) {
case SPROUT:
if (!db.Read(DB_BEST_SPROUT_ANCHOR, hashBestAnchor))
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;
}
@ -108,6 +121,7 @@ void BatchWriteNullifiers(CDBBatch& batch, CNullifiersMap& mapToUse, const char&
bool CCoinsViewDB::BatchWrite(CCoinsMap &mapCoins,
const uint256 &hashBlock,
const uint256 &hashSproutAnchor,
const uint256 &hashSaplingAnchor,
CAnchorsSproutMap &mapSproutAnchors,
CNullifiersMap &mapSproutNullifiers,
CNullifiersMap &mapSaplingNullifiers) {
@ -147,6 +161,8 @@ bool CCoinsViewDB::BatchWrite(CCoinsMap &mapCoins,
batch.Write(DB_BEST_BLOCK, hashBlock);
if (!hashSproutAnchor.IsNull())
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);
return db.WriteBatch(batch);

3
src/txdb.h

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

2
src/wallet/asyncrpcoperation_mergetoaddress.cpp

@ -693,7 +693,7 @@ UniValue AsyncRPCOperation_mergetoaddress::perform_joinsplit(MergeToAddressJSInf
uint256 anchor;
{
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);
}

2
src/wallet/asyncrpcoperation_sendmany.cpp

@ -914,7 +914,7 @@ UniValue AsyncRPCOperation_sendmany::perform_joinsplit(AsyncJoinSplitInfo & info
uint256 anchor;
{
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);
}

2
src/wallet/asyncrpcoperation_shieldcoinbase.cpp

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

Loading…
Cancel
Save