Changeset View
Changeset View
Standalone View
Standalone View
src/wallet/wallet.cpp
Show First 20 Lines • Show All 1,796 Lines • ▼ Show 20 Lines | CBlockIndex *startBlock = nullptr; | ||||
::ChainActive().FindEarliestAtLeast(startTime - TIMESTAMP_WINDOW); | ::ChainActive().FindEarliestAtLeast(startTime - TIMESTAMP_WINDOW); | ||||
WalletLogPrintf("%s: Rescanning last %i blocks\n", __func__, | WalletLogPrintf("%s: Rescanning last %i blocks\n", __func__, | ||||
startBlock | startBlock | ||||
? ::ChainActive().Height() - startBlock->nHeight + 1 | ? ::ChainActive().Height() - startBlock->nHeight + 1 | ||||
: 0); | : 0); | ||||
} | } | ||||
if (startBlock) { | if (startBlock) { | ||||
const CBlockIndex *const failedBlock = | const CBlockIndex *failedBlock; | ||||
ScanForWalletTransactions(startBlock, nullptr, reserver, update); | // TODO: this should take into account failure by ScanResult::USER_ABORT | ||||
if (failedBlock) { | if (ScanResult::FAILURE == | ||||
ScanForWalletTransactions(startBlock, nullptr, reserver, | |||||
failedBlock, update)) { | |||||
return failedBlock->GetBlockTimeMax() + TIMESTAMP_WINDOW + 1; | return failedBlock->GetBlockTimeMax() + TIMESTAMP_WINDOW + 1; | ||||
} | } | ||||
} | } | ||||
return startTime; | return startTime; | ||||
} | } | ||||
/** | /** | ||||
* Scan the block chain (starting in pindexStart) for transactions from or to | * Scan the block chain (starting in pindexStart) for transactions from or to | ||||
* us. If fUpdate is true, found transactions that already exist in the wallet | * us. If fUpdate is true, found transactions that already exist in the wallet | ||||
* will be updated. | * will be updated. | ||||
* | * | ||||
* Returns null if scan was successful. Otherwise, if a complete rescan was not | * @param[in] pindexStop if not a nullptr, the scan will stop at this | ||||
* possible (due to pruning or corruption), returns pointer to the most recent | * block-index | ||||
* block that could not be scanned. | * @param[out] failed_block if FAILURE is returned, will be set to the most | ||||
* recent block that could not be scanned, otherwise nullptr. | |||||
* | * | ||||
* If pindexStop is not a nullptr, the scan will stop at the block-index | * @return ScanResult indicating success or failure of the scan. SUCCESS if | ||||
* defined by pindexStop | * scan was successful. FAILURE if a complete rescan was not possible (due to | ||||
* pruning or corruption). USER_ABORT if the rescan was aborted before it | |||||
* could complete. | |||||
* | * | ||||
* Caller needs to make sure pindexStop (and the optional pindexStart) are on | * @pre Caller needs to make sure pindexStop (and the optional pindexStart) are | ||||
* the main chain after to the addition of any new keys you want to detect | * on the main chain after to the addition of any new keys you want to detect | ||||
* transactions for. | * transactions for. | ||||
*/ | */ | ||||
const CBlockIndex *CWallet::ScanForWalletTransactions( | CWallet::ScanResult CWallet::ScanForWalletTransactions( | ||||
const CBlockIndex *const pindexStart, const CBlockIndex *const pindexStop, | const CBlockIndex *const pindexStart, const CBlockIndex *const pindexStop, | ||||
const WalletRescanReserver &reserver, bool fUpdate) { | const WalletRescanReserver &reserver, const CBlockIndex *&failed_block, | ||||
bool fUpdate) { | |||||
int64_t nNow = GetTime(); | int64_t nNow = GetTime(); | ||||
assert(reserver.isReserved()); | assert(reserver.isReserved()); | ||||
if (pindexStop) { | if (pindexStop) { | ||||
assert(pindexStop->nHeight >= pindexStart->nHeight); | assert(pindexStop->nHeight >= pindexStart->nHeight); | ||||
} | } | ||||
const CBlockIndex *pindex = pindexStart; | const CBlockIndex *pindex = pindexStart; | ||||
const CBlockIndex *ret = nullptr; | failed_block = nullptr; | ||||
if (pindex) { | if (pindex) { | ||||
WalletLogPrintf("Rescan started from block %d...\n", pindex->nHeight); | WalletLogPrintf("Rescan started from block %d...\n", pindex->nHeight); | ||||
} | } | ||||
{ | { | ||||
fAbortRescan = false; | fAbortRescan = false; | ||||
Show All 38 Lines | if (pindex) { | ||||
CBlock block; | CBlock block; | ||||
if (ReadBlockFromDisk(block, pindex, chainParams.GetConsensus())) { | if (ReadBlockFromDisk(block, pindex, chainParams.GetConsensus())) { | ||||
auto locked_chain = chain().lock(); | auto locked_chain = chain().lock(); | ||||
LOCK(cs_wallet); | LOCK(cs_wallet); | ||||
if (pindex && !::ChainActive().Contains(pindex)) { | if (pindex && !::ChainActive().Contains(pindex)) { | ||||
// Abort scan if current block is no longer active, to | // Abort scan if current block is no longer active, to | ||||
// prevent marking transactions as coming from the wrong | // prevent marking transactions as coming from the wrong | ||||
// block. | // block. | ||||
ret = pindex; | failed_block = pindex; | ||||
break; | break; | ||||
} | } | ||||
for (size_t posInBlock = 0; posInBlock < block.vtx.size(); | for (size_t posInBlock = 0; posInBlock < block.vtx.size(); | ||||
++posInBlock) { | ++posInBlock) { | ||||
SyncTransaction(block.vtx[posInBlock], pindex, posInBlock, | SyncTransaction(block.vtx[posInBlock], pindex, posInBlock, | ||||
fUpdate); | fUpdate); | ||||
} | } | ||||
} else { | } else { | ||||
ret = pindex; | failed_block = pindex; | ||||
} | } | ||||
if (pindex == pindexStop) { | if (pindex == pindexStop) { | ||||
break; | break; | ||||
} | } | ||||
{ | { | ||||
auto locked_chain = chain().lock(); | auto locked_chain = chain().lock(); | ||||
pindex = ::ChainActive().Next(pindex); | pindex = ::ChainActive().Next(pindex); | ||||
progress_current = | progress_current = | ||||
GuessVerificationProgress(chainParams.TxData(), pindex); | GuessVerificationProgress(chainParams.TxData(), pindex); | ||||
if (pindexStop == nullptr && tip != ::ChainActive().Tip()) { | if (pindexStop == nullptr && tip != ::ChainActive().Tip()) { | ||||
tip = ::ChainActive().Tip(); | tip = ::ChainActive().Tip(); | ||||
// in case the tip has changed, update progress max | // in case the tip has changed, update progress max | ||||
progress_end = | progress_end = | ||||
GuessVerificationProgress(chainParams.TxData(), tip); | GuessVerificationProgress(chainParams.TxData(), tip); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
// Hide progress dialog in GUI. | |||||
ShowProgress(strprintf("%s " + _("Rescanning..."), GetDisplayName()), | |||||
100); | |||||
if (pindex && fAbortRescan) { | if (pindex && fAbortRescan) { | ||||
WalletLogPrintf("Rescan aborted at block %d. Progress=%f\n", | WalletLogPrintf("Rescan aborted at block %d. Progress=%f\n", | ||||
pindex->nHeight, progress_current); | pindex->nHeight, progress_current); | ||||
return ScanResult::USER_ABORT; | |||||
} else if (pindex && ShutdownRequested()) { | } else if (pindex && ShutdownRequested()) { | ||||
WalletLogPrintf("Rescan interrupted by shutdown request at block " | WalletLogPrintf("Rescan interrupted by shutdown request at block " | ||||
"%d. Progress=%f\n", | "%d. Progress=%f\n", | ||||
pindex->nHeight, progress_current); | pindex->nHeight, progress_current); | ||||
return ScanResult::USER_ABORT; | |||||
} | } | ||||
// Hide progress dialog in GUI. | |||||
ShowProgress(strprintf("%s " + _("Rescanning..."), GetDisplayName()), | |||||
100); | |||||
} | } | ||||
return ret; | |||||
return failed_block ? ScanResult::FAILURE : ScanResult::SUCCESS; | |||||
} | } | ||||
void CWallet::ReacceptWalletTransactions() { | void CWallet::ReacceptWalletTransactions() { | ||||
// If transactions aren't being broadcasted, don't let them into local | // If transactions aren't being broadcasted, don't let them into local | ||||
// mempool either. | // mempool either. | ||||
if (!fBroadcastTransactions) { | if (!fBroadcastTransactions) { | ||||
return; | return; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 2,763 Lines • ▼ Show 20 Lines | if (::ChainActive().Tip() && ::ChainActive().Tip() != pindexRescan) { | ||||
(pindexRescan->GetBlockTime() < | (pindexRescan->GetBlockTime() < | ||||
(walletInstance->nTimeFirstKey - TIMESTAMP_WINDOW))) { | (walletInstance->nTimeFirstKey - TIMESTAMP_WINDOW))) { | ||||
pindexRescan = ::ChainActive().Next(pindexRescan); | pindexRescan = ::ChainActive().Next(pindexRescan); | ||||
} | } | ||||
nStart = GetTimeMillis(); | nStart = GetTimeMillis(); | ||||
{ | { | ||||
WalletRescanReserver reserver(walletInstance.get()); | WalletRescanReserver reserver(walletInstance.get()); | ||||
if (!reserver.reserve()) { | const CBlockIndex *stop_block; | ||||
if (!reserver.reserve() || | |||||
(ScanResult::SUCCESS != | |||||
walletInstance->ScanForWalletTransactions( | |||||
pindexRescan, nullptr, reserver, stop_block, true))) { | |||||
InitError( | InitError( | ||||
_("Failed to rescan the wallet during initialization")); | _("Failed to rescan the wallet during initialization")); | ||||
return nullptr; | return nullptr; | ||||
} | } | ||||
walletInstance->ScanForWalletTransactions(pindexRescan, nullptr, | |||||
reserver, true); | |||||
} | } | ||||
walletInstance->WalletLogPrintf("Rescan completed in %15dms\n", | walletInstance->WalletLogPrintf("Rescan completed in %15dms\n", | ||||
GetTimeMillis() - nStart); | GetTimeMillis() - nStart); | ||||
walletInstance->ChainStateFlushed(::ChainActive().GetLocator()); | walletInstance->ChainStateFlushed(::ChainActive().GetLocator()); | ||||
walletInstance->database->IncrementUpdateCounter(); | walletInstance->database->IncrementUpdateCounter(); | ||||
// Restore wallet transaction metadata after -zapwallettxes=1 | // Restore wallet transaction metadata after -zapwallettxes=1 | ||||
if (gArgs.GetBoolArg("-zapwallettxes", false) && | if (gArgs.GetBoolArg("-zapwallettxes", false) && | ||||
▲ Show 20 Lines • Show All 205 Lines • Show Last 20 Lines |