diff --git a/qa/rpc-tests/mempool_resurrect_test.py b/qa/rpc-tests/mempool_resurrect_test.py index 1cbbd2cd5..faa97d461 100755 --- a/qa/rpc-tests/mempool_resurrect_test.py +++ b/qa/rpc-tests/mempool_resurrect_test.py @@ -54,6 +54,7 @@ class MempoolCoinbaseTest(BitcoinTestFramework): spends2_id = [ self.nodes[0].sendrawtransaction(tx) for tx in spends2_raw ] blocks.extend(self.nodes[0].generate(1)) + self.sync_all() # mempool should be empty, all txns confirmed assert_equal(set(self.nodes[0].getrawmempool()), set()) @@ -74,6 +75,8 @@ class MempoolCoinbaseTest(BitcoinTestFramework): # Generate another block, they should all get mined self.nodes[0].generate(1) + self.sync_all() + # mempool should be empty, all txns confirmed assert_equal(set(self.nodes[0].getrawmempool()), set()) for txid in spends1_id+spends2_id: diff --git a/qa/rpc-tests/test_framework/util.py b/qa/rpc-tests/test_framework/util.py index b41c4b451..78c66089a 100644 --- a/qa/rpc-tests/test_framework/util.py +++ b/qa/rpc-tests/test_framework/util.py @@ -60,6 +60,14 @@ def sync_blocks(rpc_connections, wait=1): break time.sleep(wait) + # Now that the block counts are in sync, wait for the internal + # notifications to finish + while True: + notified = [ x.getblockchaininfo()['fullyNotified'] for x in rpc_connections ] + if notified == [ True ] * len(notified): + break + time.sleep(wait) + def sync_mempools(rpc_connections, wait=1): """ Wait until everybody has the same transactions in their memory diff --git a/qa/rpc-tests/wallet.py b/qa/rpc-tests/wallet.py index 5d221a28c..0268dd292 100755 --- a/qa/rpc-tests/wallet.py +++ b/qa/rpc-tests/wallet.py @@ -31,6 +31,7 @@ class WalletTest (BitcoinTestFramework): print "Mining blocks..." self.nodes[0].generate(4) + self.sync_all() walletinfo = self.nodes[0].getwalletinfo() assert_equal(walletinfo['immature_balance'], 40) diff --git a/qa/rpc-tests/wallet_1941.py b/qa/rpc-tests/wallet_1941.py index d70b514fc..6f90f33bd 100755 --- a/qa/rpc-tests/wallet_1941.py +++ b/qa/rpc-tests/wallet_1941.py @@ -45,6 +45,7 @@ class Wallet1941RegressionTest (BitcoinTestFramework): self.nodes[0].setmocktime(starttime) self.nodes[0].generate(101) + self.sync_all() mytaddr = self.nodes[0].getnewaddress() # where coins were mined myzaddr = self.nodes[0].z_getnewaddress() @@ -63,6 +64,7 @@ class Wallet1941RegressionTest (BitcoinTestFramework): self.nodes[0].generate(1) self.nodes[0].setmocktime(starttime + 9000) self.nodes[0].generate(1) + self.sync_all() # Confirm the balance on node 0. resp = self.nodes[0].z_getbalance(myzaddr) diff --git a/qa/rpc-tests/wallet_anchorfork.py b/qa/rpc-tests/wallet_anchorfork.py index 0e2d19385..1cb16e152 100755 --- a/qa/rpc-tests/wallet_anchorfork.py +++ b/qa/rpc-tests/wallet_anchorfork.py @@ -27,6 +27,7 @@ class WalletAnchorForkTest (BitcoinTestFramework): def run_test (self): print "Mining blocks..." self.nodes[0].generate(4) + self.sync_all() walletinfo = self.nodes[0].getwalletinfo() assert_equal(walletinfo['immature_balance'], 40) diff --git a/qa/rpc-tests/wallet_shieldcoinbase.py b/qa/rpc-tests/wallet_shieldcoinbase.py index d8366c81d..f325b29ca 100755 --- a/qa/rpc-tests/wallet_shieldcoinbase.py +++ b/qa/rpc-tests/wallet_shieldcoinbase.py @@ -44,6 +44,7 @@ class WalletShieldCoinbaseTest (BitcoinTestFramework): print "Mining blocks..." self.nodes[0].generate(1) + self.sync_all() do_not_shield_taddr = self.nodes[0].getnewaddress() self.nodes[0].generate(4) diff --git a/qa/rpc-tests/zcjoinsplit.py b/qa/rpc-tests/zcjoinsplit.py index 7e5aba6e3..b3ca745f8 100755 --- a/qa/rpc-tests/zcjoinsplit.py +++ b/qa/rpc-tests/zcjoinsplit.py @@ -30,6 +30,7 @@ class JoinSplitTest(BitcoinTestFramework): protect_tx = self.nodes[0].signrawtransaction(joinsplit_result["rawtxn"]) self.nodes[0].sendrawtransaction(protect_tx["hex"]) self.nodes[0].generate(1) + self.sync_all() receive_result = self.nodes[0].zcrawreceive(zcsecretkey, joinsplit_result["encryptednote1"]) assert_equal(receive_result["exists"], True) @@ -39,6 +40,7 @@ class JoinSplitTest(BitcoinTestFramework): addrtest = self.nodes[0].getnewaddress() for xx in range(0,10): self.nodes[0].generate(1) + self.sync_all() for x in range(0,50): self.nodes[0].sendtoaddress(addrtest, 0.01); @@ -47,6 +49,7 @@ class JoinSplitTest(BitcoinTestFramework): self.nodes[0].sendrawtransaction(joinsplit_result["rawtxn"]) self.nodes[0].generate(1) + self.sync_all() print "Done!" receive_result = self.nodes[0].zcrawreceive(zcsecretkey, joinsplit_result["encryptednote1"]) diff --git a/qa/rpc-tests/zmq_test.py b/qa/rpc-tests/zmq_test.py index d70e73114..dcb899861 100755 --- a/qa/rpc-tests/zmq_test.py +++ b/qa/rpc-tests/zmq_test.py @@ -39,21 +39,21 @@ class ZMQTest(BitcoinTestFramework): print "listen..." msg = self.zmqSubSocket.recv_multipart() topic = msg[0] - assert_equal(topic, b"hashtx") body = msg[1] - nseq = msg[2] - [nseq] # hush pyflakes msgSequence = struct.unpack(' vImportFiles) } } -void ThreadNotifyRecentlyAdded() -{ - while (true) { - // Run the notifier on an integer second in the steady clock. - auto now = std::chrono::steady_clock::now().time_since_epoch(); - auto nextFire = std::chrono::duration_cast( - now + std::chrono::seconds(1)); - std::this_thread::sleep_until( - std::chrono::time_point(nextFire)); - - boost::this_thread::interruption_point(); - - mempool.NotifyRecentlyAdded(); - } -} - /** Sanity checks * Ensure that Hush is running in a usable environment with all * necessary library support. @@ -2088,6 +2072,17 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) } #endif // ENABLE_MINING + // Start the thread that notifies listeners of transactions that have been + // recently added to the mempool, or have been added to or removed from the + // chain. We perform this before step 10 (import blocks) so that the + // original value of chainActive.Tip(), which corresponds with the wallet's + // view of the chaintip, is passed to ThreadNotifyWallets before the chain + // tip changes again. + boost::function threadnotifywallets = boost::bind(&ThreadNotifyWallets, chainActive.Tip()); + threadGroup.create_thread( + boost::bind(&TraceThread>, "txnotify", threadnotifywallets) + ); + // ********************************************************* Step 9: data directory maintenance // if pruning, unset the service bit and perform the initial blockstore prune @@ -2155,10 +2150,6 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) LogPrintf("mapAddressBook.size() = %u\n", pwalletMain ? pwalletMain->mapAddressBook.size() : 0); #endif - // Start the thread that notifies listeners of transactions that have been - // recently added to the mempool. - threadGroup.create_thread(boost::bind(&TraceThread, "txnotify", &ThreadNotifyRecentlyAdded)); - if (GetBoolArg("-listenonion", DEFAULT_LISTEN_ONION)) StartTorControl(threadGroup, scheduler); diff --git a/src/main.cpp b/src/main.cpp index 2e0394779..848e5422a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4068,21 +4068,8 @@ bool static DisconnectTip(CValidationState &state, bool fBare = false) { // Update chainActive and related variables. UpdateTip(pindexDelete->pprev); - // Get the current commitment tree - SproutMerkleTree newSproutTree; - SaplingMerkleTree newSaplingTree; - assert(pcoinsTip->GetSproutAnchorAt(pcoinsTip->GetBestAnchor(SPROUT), newSproutTree)); - assert(pcoinsTip->GetSaplingAnchorAt(pcoinsTip->GetBestAnchor(SAPLING), newSaplingTree)); - // Let wallets know transactions went from 1-confirmed to - // 0-confirmed or conflicted: - std::vector TxToRemove; - for (int i = 0; i < block.vtx.size(); i++) - { - CTransaction &tx = block.vtx[i]; - SyncWithWallets(tx, NULL); - } - // Update cached incremental witnesses - GetMainSignals().ChainTip(pindexDelete, &block, newSproutTree, newSaplingTree, false); + // Updates to connected wallets are triggered by ThreadNotifyWallets + return true; } @@ -4156,6 +4143,11 @@ static int64_t nTimeFlush = 0; static int64_t nTimeChainState = 0; static int64_t nTimePostConnect = 0; +// Protected by cs_main +std::map> recentlyConflictedTxs; +uint64_t nRecentlyConflictedSequence = 0; +uint64_t nNotifiedSequence = 0; + /** * Connect a new block to chainActive. pblock is either NULL or a pointer to a CBlock * corresponding to pindexNew, to bypass loading it again from disk. @@ -4175,14 +4167,7 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock * } KOMODO_CONNECTING = (int32_t)pindexNew->GetHeight(); //fprintf(stderr,"%s connecting ht.%d maxsize.%d vs %d\n",ASSETCHAINS_SYMBOL,(int32_t)pindexNew->GetHeight(),MAX_BLOCK_SIZE(pindexNew->GetHeight()),(int32_t)::GetSerializeSize(*pblock, SER_NETWORK, PROTOCOL_VERSION)); - // Get the current commitment tree - SproutMerkleTree oldSproutTree; - SaplingMerkleTree oldSaplingTree; - if ( KOMODO_NSPV_FULLNODE ) - { - assert(pcoinsTip->GetSproutAnchorAt(pcoinsTip->GetBestAnchor(SPROUT), oldSproutTree)); - assert(pcoinsTip->GetSaplingAnchorAt(pcoinsTip->GetBestAnchor(SAPLING), oldSaplingTree)); - } + // Apply the block atomically to the chain state. int64_t nTime2 = GetTimeMicros(); nTimeReadFromDisk += nTime2 - nTime1; int64_t nTime3; @@ -4221,7 +4206,7 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock * int64_t nTime5 = GetTimeMicros(); nTimeChainState += nTime5 - nTime4; LogPrint("bench", " - Writing chainstate: %.2fms [%.2fs]\n", (nTime5 - nTime4) * 0.001, nTimeChainState * 0.000001); // Remove conflicting transactions from the mempool. - list txConflicted; + std::list txConflicted; mempool.removeForBlock(pblock->vtx, pindexNew->GetHeight(), txConflicted, !IsInitialBlockDownload()); // Remove transactions that expire at new block height from mempool @@ -4231,18 +4216,11 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock * UpdateTip(pindexNew); if ( KOMODO_NSPV_FULLNODE ) { - // Tell wallet about transactions that went from mempool - // to conflicted: - BOOST_FOREACH(const CTransaction &tx, txConflicted) { - SyncWithWallets(tx, NULL); - } - // ... and about transactions that got confirmed: - BOOST_FOREACH(const CTransaction &tx, pblock->vtx) { - SyncWithWallets(tx, pblock); - } - } - // Update cached incremental witnesses - GetMainSignals().ChainTip(pindexNew, pblock, oldSproutTree, oldSaplingTree, true); + + // Cache the conflicted transactions for subsequent notification. + // Updates to connected wallets are triggered by ThreadNotifyWallets + recentlyConflictedTxs.insert(std::make_pair(pindexNew, txConflicted)); + nRecentlyConflictedSequence += 1; EnforceNodeDeprecation(pindexNew->GetHeight()); @@ -4278,6 +4256,31 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock * //fprintf(stderr,"%s: returning true\n", __FUNCTION__); return true; } +} +std::pair>, uint64_t> DrainRecentlyConflicted() +{ + uint64_t recentlyConflictedSequence; + std::map> txs; + { + LOCK(cs_main); + recentlyConflictedSequence = nRecentlyConflictedSequence; + txs.swap(recentlyConflictedTxs); + } + + return std::make_pair(txs, recentlyConflictedSequence); +} + +void SetChainNotifiedSequence(uint64_t recentlyConflictedSequence) { + assert(Params().NetworkIDString() == "regtest"); + LOCK(cs_main); + nNotifiedSequence = recentlyConflictedSequence; +} + +bool ChainIsFullyNotified() { + assert(Params().NetworkIDString() == "regtest"); + LOCK(cs_main); + return nRecentlyConflictedSequence == nNotifiedSequence; +} /** * Return the tip of the chain with the most work in it, that isn't @@ -5316,10 +5319,10 @@ bool CheckBlock(int32_t *futureblockp,int32_t height,CBlockIndex *pindex,const C return(false); } - if (ptx) - { - SyncWithWallets(*ptx, &block); - } + // if (ptx) + // { + // SyncWithWallets(*ptx, &block); + // } if ( ASSETCHAINS_CC != 0 ) { diff --git a/src/main.h b/src/main.h index c4bf4ea64..060b6b7cc 100644 --- a/src/main.h +++ b/src/main.h @@ -949,4 +949,8 @@ uint64_t CalculateCurrentUsage(); /** Return a CMutableTransaction with contextual default values based on set of consensus rules at height */ CMutableTransaction CreateNewContextualCMutableTransaction(const Consensus::Params& consensusParams, int nHeight); +std::pair>, uint64_t> DrainRecentlyConflicted(); +void SetChainNotifiedSequence(uint64_t recentlyConflictedSequence); +bool ChainIsFullyNotified(); + #endif // BITCOIN_MAIN_H diff --git a/src/txmempool.cpp b/src/txmempool.cpp index ed5951e08..8a99a99e6 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -844,7 +844,7 @@ bool CTxMemPool::nullifierExists(const uint256& nullifier, ShieldedType type) co } } -void CTxMemPool::NotifyRecentlyAdded() +std::pair, uint64_t> CTxMemPool::DrainRecentlyAdded() { uint64_t recentlyAddedSequence; std::vector txs; @@ -857,29 +857,13 @@ void CTxMemPool::NotifyRecentlyAdded() mapRecentlyAddedTx.clear(); } - // A race condition can occur here between these SyncWithWallets calls, and - // the ones triggered by block logic (in ConnectTip and DisconnectTip). It - // is harmless because calling SyncWithWallets(_, NULL) does not alter the - // wallet transaction's block information. - for (auto tx : txs) { - try { - SyncWithWallets(tx, NULL); - } catch (const boost::thread_interrupted&) { - fprintf(stderr,"%s: thread interrupted\n", __FUNCTION__); - throw; - } catch (const std::exception& e) { - PrintExceptionContinue(&e, "CTxMemPool::NotifyRecentlyAdded()"); - } catch (...) { - PrintExceptionContinue(NULL, "CTxMemPool::NotifyRecentlyAdded()"); - } - } + return std::make_pair(txs, recentlyAddedSequence); +} - // Update the notified sequence number. We only need this in regtest mode, - // and should not lock on cs after calling SyncWithWallets otherwise. - if (Params().NetworkIDString() == "regtest") { - LOCK(cs); - nNotifiedSequence = recentlyAddedSequence; - } +void CTxMemPool::SetNotifiedSequence(uint64_t recentlyAddedSequence) { + assert(Params().NetworkIDString() == "regtest"); + LOCK(cs); + nNotifiedSequence = recentlyAddedSequence; } bool CTxMemPool::IsFullyNotified() { diff --git a/src/txmempool.h b/src/txmempool.h index fbf7e4784..f8aa0e9a7 100644 --- a/src/txmempool.h +++ b/src/txmempool.h @@ -240,7 +240,8 @@ public: bool nullifierExists(const uint256& nullifier, ShieldedType type) const; - void NotifyRecentlyAdded(); + std::pair, uint64_t> DrainRecentlyAdded(); + void SetNotifiedSequence(uint64_t recentlyAddedSequence); bool IsFullyNotified(); unsigned long size() diff --git a/src/validationinterface.cpp b/src/validationinterface.cpp index 6ea07be9e..f3bca6205 100644 --- a/src/validationinterface.cpp +++ b/src/validationinterface.cpp @@ -5,6 +5,17 @@ #include "validationinterface.h" +#include "chainparams.h" +#include "init.h" +#include "main.h" +#include "txmempool.h" +#include "ui_interface.h" + +#include + +#include +#include + static CMainSignals g_signals; CMainSignals& GetMainSignals() @@ -18,7 +29,7 @@ void RegisterValidationInterface(CValidationInterface* pwalletIn) { g_signals.EraseTransaction.connect(boost::bind(&CValidationInterface::EraseFromWallet, pwalletIn, _1)); g_signals.UpdatedTransaction.connect(boost::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, _1)); g_signals.RescanWallet.connect(boost::bind(&CValidationInterface::RescanWallet, pwalletIn)); - g_signals.ChainTip.connect(boost::bind(&CValidationInterface::ChainTip, pwalletIn, _1, _2, _3, _4, _5)); + g_signals.ChainTip.connect(boost::bind(&CValidationInterface::ChainTip, pwalletIn, _1, _2, _3)); g_signals.SetBestChain.connect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1)); g_signals.Inventory.connect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1)); g_signals.Broadcast.connect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1)); @@ -29,7 +40,7 @@ void UnregisterValidationInterface(CValidationInterface* pwalletIn) { g_signals.BlockChecked.disconnect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, _1, _2)); g_signals.Broadcast.disconnect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1)); g_signals.Inventory.disconnect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1)); - g_signals.ChainTip.disconnect(boost::bind(&CValidationInterface::ChainTip, pwalletIn, _1, _2, _3, _4, _5)); + g_signals.ChainTip.disconnect(boost::bind(&CValidationInterface::ChainTip, pwalletIn, _1, _2, _3)); g_signals.SetBestChain.disconnect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1)); g_signals.UpdatedTransaction.disconnect(boost::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, _1)); g_signals.EraseTransaction.disconnect(boost::bind(&CValidationInterface::EraseFromWallet, pwalletIn, _1)); @@ -55,10 +66,76 @@ void SyncWithWallets(const CTransaction &tx, const CBlock *pblock) { g_signals.SyncTransaction(tx, pblock); } +struct CachedBlockData { + CBlockIndex *pindex; + std::pair oldTrees; + std::list txConflicted; + + CachedBlockData( + CBlockIndex *pindex, + std::pair oldTrees, + std::list txConflicted): + pindex(pindex), oldTrees(oldTrees), txConflicted(txConflicted) {} +}; + +void ThreadNotifyWallets(CBlockIndex *pindexLastTip) +{ + // If pindexLastTip == nullptr, the wallet is at genesis. + // However, the genesis block is not loaded synchronously. + // We need to wait for ThreadImport to finish. + while (pindexLastTip == nullptr) { + { + LOCK(cs_main); + pindexLastTip = chainActive.Genesis(); + } + MilliSleep(50); + } + + while (true) { + // Run the notifier on an integer second in the steady clock. + auto now = std::chrono::steady_clock::now().time_since_epoch(); + auto nextFire = std::chrono::duration_cast( + now + std::chrono::seconds(1)); + std::this_thread::sleep_until( + std::chrono::time_point(nextFire)); + + boost::this_thread::interruption_point(); + + auto chainParams = Params(); + + // + // Collect all the state we require + // + + // The common ancestor between the last chain tip we notified and the + // current chain tip. + const CBlockIndex *pindexFork; + // The stack of blocks we will notify as having been connected. + // Pushed in reverse, popped in order. + std::vector blockStack; + // Transactions that have been recently conflicted out of the mempool. + std::pair>, uint64_t> recentlyConflicted; + // Transactions that have been recently added to the mempool. + std::pair, uint64_t> recentlyAdded; + + { + LOCK(cs_main); + + // Figure out the path from the last block we notified to the + // current chain tip. + CBlockIndex *pindex = chainActive.Tip(); + pindexFork = chainActive.FindFork(pindexLastTip); + + // Fetch recently-conflicted transactions. These will include any + // block that has been connected since the last cycle, but we only + // notify for the conflicts created by the current active chain. + } + } +} void EraseFromWallets(const uint256 &hash) { g_signals.EraseTransaction(hash); } void RescanWallets() { g_signals.RescanWallet(); -} \ No newline at end of file +} diff --git a/src/validationinterface.h b/src/validationinterface.h index 30b9cf0a7..33cd5728e 100644 --- a/src/validationinterface.h +++ b/src/validationinterface.h @@ -26,8 +26,6 @@ void RegisterValidationInterface(CValidationInterface* pwalletIn); void UnregisterValidationInterface(CValidationInterface* pwalletIn); /** Unregister all wallets from core */ void UnregisterAllValidationInterfaces(); -/** Push an updated transaction to all registered wallets */ -void SyncWithWallets(const CTransaction& tx, const CBlock* pblock = NULL); /** Erase a transaction from all registered wallets */ void EraseFromWallets(const uint256 &hash); /** Rescan all registered wallets */ @@ -39,7 +37,7 @@ protected: virtual void SyncTransaction(const CTransaction &tx, const CBlock *pblock) {} virtual void EraseFromWallet(const uint256 &hash) {} virtual void RescanWallet() {} - virtual void ChainTip(const CBlockIndex *pindex, const CBlock *pblock, SproutMerkleTree sproutTree, SaplingMerkleTree saplingTree, bool added) {} + virtual void ChainTip(const CBlockIndex *pindex, const CBlock *pblock, boost::optional> added) {} virtual void SetBestChain(const CBlockLocator &locator) {} virtual void UpdatedTransaction(const uint256 &hash) {} virtual void Inventory(const uint256 &hash) {} @@ -62,7 +60,7 @@ struct CMainSignals { /** Notifies listeners of an updated transaction without new data (for now: a coinbase potentially becoming visible). */ boost::signals2::signal UpdatedTransaction; /** Notifies listeners of a change to the tip of the active block chain. */ - boost::signals2::signal ChainTip; + boost::signals2::signal>)> ChainTip; /** Notifies listeners of a new active block chain. */ boost::signals2::signal SetBestChain; /** Notifies listeners about an inventory item being seen on the network. */ @@ -75,4 +73,6 @@ struct CMainSignals { CMainSignals& GetMainSignals(); +void ThreadNotifyWallets(CBlockIndex *pindexLastTip); + #endif // BITCOIN_VALIDATIONINTERFACE_H diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 953f738ef..f8127e83d 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -588,9 +588,7 @@ bool CWallet::ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, void CWallet::ChainTip(const CBlockIndex *pindex, const CBlock *pblock, - SproutMerkleTree sproutTree, - SaplingMerkleTree saplingTree, - bool added) + boost::optional> added) { if (added) { // Prevent witness cache building && consolidation transactions diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 79d24a86d..0c3b96330 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -1253,7 +1253,10 @@ public: CAmount GetCredit(const CTransaction& tx, int32_t voutNum, const isminefilter& filter) const; CAmount GetCredit(const CTransaction& tx, const isminefilter& filter) const; CAmount GetChange(const CTransaction& tx) const; - void ChainTip(const CBlockIndex *pindex, const CBlock *pblock, SproutMerkleTree sproutTree, SaplingMerkleTree saplingTree, bool added); + void ChainTip( + const CBlockIndex *pindex, + const CBlock *pblock, + boost::optional> added); void RunSaplingConsolidation(int blockHeight); void CommitConsolidationTx(const CTransaction& tx); /** Saves witness caches and best block locator to disk. */ diff --git a/src/zcbenchmarks.cpp b/src/zcbenchmarks.cpp index c3783e97a..2f79e454b 100644 --- a/src/zcbenchmarks.cpp +++ b/src/zcbenchmarks.cpp @@ -309,7 +309,7 @@ double benchmark_increment_note_witnesses(size_t nTxs) index1.SetHeight(1); // Increment to get transactions witnessed - wallet.ChainTip(&index1, &block1, sproutTree, saplingTree, true); + wallet.ChainTip(&index1, &block1, std::make_pair(sproutTree, saplingTree)); // Second block CBlock block2; @@ -333,7 +333,7 @@ double benchmark_increment_note_witnesses(size_t nTxs) struct timeval tv_start; timer_start(tv_start); - wallet.ChainTip(&index2, &block2, sproutTree, saplingTree, true); + wallet.ChainTip(&index2, &block2, std::make_pair(sproutTree, saplingTree)); return timer_stop(tv_start); }