|
|
@ -1,7 +1,7 @@ |
|
|
|
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
|
|
|
// Copyright (c) 2009-2014 The Bitcoin Core developers
|
|
|
|
// Distributed under the MIT software license, see the accompanying
|
|
|
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
|
|
// file COPYING or https://www.opensource.org/licenses/mit-license.php .
|
|
|
|
|
|
|
|
#include "validationinterface.h" |
|
|
|
|
|
|
@ -28,15 +28,18 @@ void RegisterValidationInterface(CValidationInterface* pwalletIn) { |
|
|
|
g_signals.SyncTransaction.connect(boost::bind(&CValidationInterface::SyncTransaction, pwalletIn, _1, _2)); |
|
|
|
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)); |
|
|
|
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)); |
|
|
|
g_signals.BlockChecked.connect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, _1, _2)); |
|
|
|
g_signals.ScriptForMining.connect(boost::bind(&CValidationInterface::GetScriptForMining, pwalletIn, _1)); |
|
|
|
g_signals.BlockFound.connect(boost::bind(&CValidationInterface::ResetRequestCount, pwalletIn, _1)); |
|
|
|
} |
|
|
|
|
|
|
|
void UnregisterValidationInterface(CValidationInterface* pwalletIn) { |
|
|
|
g_signals.BlockFound.disconnect(boost::bind(&CValidationInterface::ResetRequestCount, pwalletIn, _1)); |
|
|
|
g_signals.ScriptForMining.disconnect(boost::bind(&CValidationInterface::GetScriptForMining, pwalletIn, _1)); |
|
|
|
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)); |
|
|
@ -45,11 +48,12 @@ void UnregisterValidationInterface(CValidationInterface* pwalletIn) { |
|
|
|
g_signals.UpdatedTransaction.disconnect(boost::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, _1)); |
|
|
|
g_signals.EraseTransaction.disconnect(boost::bind(&CValidationInterface::EraseFromWallet, pwalletIn, _1)); |
|
|
|
g_signals.SyncTransaction.disconnect(boost::bind(&CValidationInterface::SyncTransaction, pwalletIn, _1, _2)); |
|
|
|
g_signals.RescanWallet.disconnect(boost::bind(&CValidationInterface::RescanWallet, pwalletIn)); |
|
|
|
g_signals.UpdatedBlockTip.disconnect(boost::bind(&CValidationInterface::UpdatedBlockTip, pwalletIn, _1)); |
|
|
|
} |
|
|
|
|
|
|
|
void UnregisterAllValidationInterfaces() { |
|
|
|
g_signals.BlockFound.disconnect_all_slots(); |
|
|
|
g_signals.ScriptForMining.disconnect_all_slots(); |
|
|
|
g_signals.BlockChecked.disconnect_all_slots(); |
|
|
|
g_signals.Broadcast.disconnect_all_slots(); |
|
|
|
g_signals.Inventory.disconnect_all_slots(); |
|
|
@ -58,7 +62,6 @@ void UnregisterAllValidationInterfaces() { |
|
|
|
g_signals.UpdatedTransaction.disconnect_all_slots(); |
|
|
|
g_signals.EraseTransaction.disconnect_all_slots(); |
|
|
|
g_signals.SyncTransaction.disconnect_all_slots(); |
|
|
|
g_signals.RescanWallet.disconnect_all_slots(); |
|
|
|
g_signals.UpdatedBlockTip.disconnect_all_slots(); |
|
|
|
} |
|
|
|
|
|
|
@ -129,13 +132,119 @@ void ThreadNotifyWallets(CBlockIndex *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.
|
|
|
|
recentlyConflicted = DrainRecentlyConflicted(); |
|
|
|
|
|
|
|
// Iterate backwards over the connected blocks we need to notify.
|
|
|
|
while (pindex && pindex != pindexFork) { |
|
|
|
// Get the Sprout commitment tree as of the start of this block.
|
|
|
|
SproutMerkleTree oldSproutTree; |
|
|
|
assert(pcoinsTip->GetSproutAnchorAt(pindex->hashSproutAnchor, oldSproutTree)); |
|
|
|
|
|
|
|
// Get the Sapling commitment tree as of the start of this block.
|
|
|
|
// We can get this from the `hashFinalSaplingRoot` of the last block
|
|
|
|
// However, this is only reliable if the last block was on or after
|
|
|
|
// the Sapling activation height. Otherwise, the last anchor was the
|
|
|
|
// empty root.
|
|
|
|
SaplingMerkleTree oldSaplingTree; |
|
|
|
if (chainParams.GetConsensus().NetworkUpgradeActive( |
|
|
|
pindex->pprev->nHeight, Consensus::UPGRADE_SAPLING)) { |
|
|
|
assert(pcoinsTip->GetSaplingAnchorAt( |
|
|
|
pindex->pprev->hashFinalSaplingRoot, oldSaplingTree)); |
|
|
|
} else { |
|
|
|
assert(pcoinsTip->GetSaplingAnchorAt(SaplingMerkleTree::empty_root(), oldSaplingTree)); |
|
|
|
} |
|
|
|
|
|
|
|
blockStack.emplace_back( |
|
|
|
pindex, |
|
|
|
std::make_pair(oldSproutTree, oldSaplingTree), |
|
|
|
recentlyConflicted.first.at(pindex)); |
|
|
|
|
|
|
|
pindex = pindex->pprev; |
|
|
|
} |
|
|
|
|
|
|
|
recentlyAdded = mempool.DrainRecentlyAdded(); |
|
|
|
} |
|
|
|
|
|
|
|
//
|
|
|
|
// Execute wallet logic based on the collected state. We MUST NOT take
|
|
|
|
// the cs_main or mempool.cs locks again until after the next sleep;
|
|
|
|
// doing so introduces a locking side-channel between this code and the
|
|
|
|
// network message processing thread.
|
|
|
|
//
|
|
|
|
|
|
|
|
// Notify block disconnects
|
|
|
|
while (pindexLastTip && pindexLastTip != pindexFork) { |
|
|
|
// Read block from disk.
|
|
|
|
CBlock block; |
|
|
|
if (!ReadBlockFromDisk(block, pindexLastTip, chainParams.GetConsensus())) { |
|
|
|
LogPrintf("*** %s\n", "Failed to read block while notifying wallets of block disconnects"); |
|
|
|
uiInterface.ThreadSafeMessageBox( |
|
|
|
_("Error: A fatal internal error occurred, see debug.log for details"), |
|
|
|
"", CClientUIInterface::MSG_ERROR); |
|
|
|
StartShutdown(); |
|
|
|
} |
|
|
|
|
|
|
|
// Let wallets know transactions went from 1-confirmed to
|
|
|
|
// 0-confirmed or conflicted:
|
|
|
|
for (const CTransaction &tx : block.vtx) { |
|
|
|
SyncWithWallets(tx, NULL); |
|
|
|
} |
|
|
|
// Update cached incremental witnesses
|
|
|
|
GetMainSignals().ChainTip(pindexLastTip, &block, boost::none); |
|
|
|
|
|
|
|
// On to the next block!
|
|
|
|
pindexLastTip = pindexLastTip->pprev; |
|
|
|
} |
|
|
|
|
|
|
|
// Notify block connections
|
|
|
|
while (!blockStack.empty()) { |
|
|
|
auto blockData = blockStack.back(); |
|
|
|
blockStack.pop_back(); |
|
|
|
|
|
|
|
// Read block from disk.
|
|
|
|
CBlock block; |
|
|
|
if (!ReadBlockFromDisk(block, blockData.pindex, chainParams.GetConsensus())) { |
|
|
|
LogPrintf("*** %s\n", "Failed to read block while notifying wallets of block connects"); |
|
|
|
uiInterface.ThreadSafeMessageBox( |
|
|
|
_("Error: A fatal internal error occurred, see debug.log for details"), |
|
|
|
"", CClientUIInterface::MSG_ERROR); |
|
|
|
StartShutdown(); |
|
|
|
} |
|
|
|
|
|
|
|
// Tell wallet about transactions that went from mempool
|
|
|
|
// to conflicted:
|
|
|
|
for (const CTransaction &tx : blockData.txConflicted) { |
|
|
|
SyncWithWallets(tx, NULL); |
|
|
|
} |
|
|
|
// ... and about transactions that got confirmed:
|
|
|
|
for (const CTransaction &tx : block.vtx) { |
|
|
|
SyncWithWallets(tx, &block); |
|
|
|
} |
|
|
|
// Update cached incremental witnesses
|
|
|
|
GetMainSignals().ChainTip(blockData.pindex, &block, blockData.oldTrees); |
|
|
|
|
|
|
|
// This block is done!
|
|
|
|
pindexLastTip = blockData.pindex; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
void EraseFromWallets(const uint256 &hash) { |
|
|
|
g_signals.EraseTransaction(hash); |
|
|
|
} |
|
|
|
|
|
|
|
void RescanWallets() { |
|
|
|
g_signals.RescanWallet(); |
|
|
|
// Notify transactions in the mempool
|
|
|
|
for (auto tx : recentlyAdded.first) { |
|
|
|
try { |
|
|
|
SyncWithWallets(tx, NULL); |
|
|
|
} catch (const boost::thread_interrupted&) { |
|
|
|
throw; |
|
|
|
} catch (const std::exception& e) { |
|
|
|
PrintExceptionContinue(&e, "ThreadNotifyWallets()"); |
|
|
|
} catch (...) { |
|
|
|
PrintExceptionContinue(NULL, "ThreadNotifyWallets()"); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Update the notified sequence numbers. We only need this in regtest mode,
|
|
|
|
// and should not lock on cs or cs_main here otherwise.
|
|
|
|
if (chainParams.NetworkIDString() == "regtest") { |
|
|
|
SetChainNotifiedSequence(recentlyConflicted.second); |
|
|
|
mempool.SetNotifiedSequence(recentlyAdded.second); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|