Changeset View
Changeset View
Standalone View
Standalone View
src/wallet/wallet.cpp
Show First 20 Lines • Show All 1,682 Lines • ▼ Show 20 Lines | |||||
/** | /** | ||||
* Scan active chain for relevant transactions after importing keys. This should | * Scan active chain for relevant transactions after importing keys. This should | ||||
* be called whenever new keys are added to the wallet, with the oldest key | * be called whenever new keys are added to the wallet, with the oldest key | ||||
* creation time. | * creation time. | ||||
* | * | ||||
* @return Earliest timestamp that could be successfully scanned from. Timestamp | * @return Earliest timestamp that could be successfully scanned from. Timestamp | ||||
* returned will be higher than startTime if relevant blocks could not be read. | * returned will be higher than startTime if relevant blocks could not be read. | ||||
*/ | */ | ||||
int64_t CWallet::RescanFromTime(int64_t startTime, bool update) { | int64_t CWallet::RescanFromTime(int64_t startTime, | ||||
AssertLockHeld(cs_main); | const WalletRescanReserver &reserver, | ||||
AssertLockHeld(cs_wallet); | bool update) { | ||||
// Find starting block. May be null if nCreateTime is greater than the | // Find starting block. May be null if nCreateTime is greater than the | ||||
// highest blockchain timestamp, in which case there is nothing that needs | // highest blockchain timestamp, in which case there is nothing that needs | ||||
// to be scanned. | // to be scanned. | ||||
CBlockIndex *const startBlock = | CBlockIndex *startBlock = nullptr; | ||||
{ | |||||
LOCK(cs_main); | |||||
startBlock = | |||||
chainActive.FindEarliestAtLeast(startTime - TIMESTAMP_WINDOW); | chainActive.FindEarliestAtLeast(startTime - TIMESTAMP_WINDOW); | ||||
LogPrintf("%s: Rescanning last %i blocks\n", __func__, | LogPrintf("%s: Rescanning last %i blocks\n", __func__, | ||||
startBlock ? chainActive.Height() - startBlock->nHeight + 1 : 0); | startBlock ? chainActive.Height() - startBlock->nHeight + 1 | ||||
: 0); | |||||
} | |||||
if (startBlock) { | if (startBlock) { | ||||
const CBlockIndex *const failedBlock = | const CBlockIndex *const failedBlock = | ||||
ScanForWalletTransactions(startBlock, nullptr, update); | ScanForWalletTransactions(startBlock, nullptr, reserver, update); | ||||
if (failedBlock) { | if (failedBlock) { | ||||
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 | * Returns null if scan was successful. Otherwise, if a complete rescan was not | ||||
* possible (due to pruning or corruption), returns pointer to the most recent | * possible (due to pruning or corruption), returns pointer to the most recent | ||||
* block that could not be scanned. | * block that could not be scanned. | ||||
* | * | ||||
* If pindexStop is not a nullptr, the scan will stop at the block-index defined | * If pindexStop is not a nullptr, the scan will stop at the block-index | ||||
* by pindexStop. | * defined by pindexStop | ||||
* | |||||
* Caller needs to make sure pindexStop (and the optional pindexStart) are on | |||||
* the main chain after to the addition of any new keys you want to detect | |||||
* transactions for. | |||||
*/ | */ | ||||
CBlockIndex *CWallet::ScanForWalletTransactions(CBlockIndex *pindexStart, | CBlockIndex *CWallet::ScanForWalletTransactions( | ||||
CBlockIndex *pindexStop, | CBlockIndex *pindexStart, CBlockIndex *pindexStop, | ||||
bool fUpdate) { | const WalletRescanReserver &reserver, bool fUpdate) { | ||||
int64_t nNow = GetTime(); | int64_t nNow = GetTime(); | ||||
assert(reserver.isReserved()); | |||||
if (pindexStop) { | if (pindexStop) { | ||||
assert(pindexStop->nHeight >= pindexStart->nHeight); | assert(pindexStop->nHeight >= pindexStart->nHeight); | ||||
} | } | ||||
CBlockIndex *pindex = pindexStart; | CBlockIndex *pindex = pindexStart; | ||||
CBlockIndex *ret = nullptr; | CBlockIndex *ret = nullptr; | ||||
{ | { | ||||
LOCK2(cs_main, cs_wallet); | |||||
fAbortRescan = false; | fAbortRescan = false; | ||||
fScanningWallet = true; | |||||
// Show rescan progress in GUI as dialog or on splashscreen, if -rescan | // Show rescan progress in GUI as dialog or on splashscreen, if -rescan | ||||
// on startup. | // on startup. | ||||
ShowProgress(_("Rescanning..."), 0); | ShowProgress(_("Rescanning..."), 0); | ||||
double dProgressStart = | CBlockIndex *tip = nullptr; | ||||
double dProgressStart; | |||||
double dProgressTip; | |||||
{ | |||||
LOCK(cs_main); | |||||
tip = chainActive.Tip(); | |||||
dProgressStart = | |||||
GuessVerificationProgress(chainParams.TxData(), pindex); | GuessVerificationProgress(chainParams.TxData(), pindex); | ||||
double dProgressTip = | dProgressTip = GuessVerificationProgress(chainParams.TxData(), tip); | ||||
GuessVerificationProgress(chainParams.TxData(), chainActive.Tip()); | } | ||||
while (pindex && !fAbortRescan) { | while (pindex && !fAbortRescan) { | ||||
if (pindex->nHeight % 100 == 0 && | if (pindex->nHeight % 100 == 0 && | ||||
dProgressTip - dProgressStart > 0.0) { | dProgressTip - dProgressStart > 0.0) { | ||||
double gvp = 0; | |||||
{ | |||||
LOCK(cs_main); | |||||
gvp = | |||||
GuessVerificationProgress(chainParams.TxData(), pindex); | |||||
} | |||||
ShowProgress( | ShowProgress( | ||||
_("Rescanning..."), | _("Rescanning..."), | ||||
std::max(1, std::min<int>( | std::max( | ||||
99, (GuessVerificationProgress( | 1, std::min(99, (int)((gvp - dProgressStart) / | ||||
chainParams.TxData(), pindex) - | |||||
dProgressStart) / | |||||
(dProgressTip - dProgressStart) * | (dProgressTip - dProgressStart) * | ||||
100))); | 100)))); | ||||
} | } | ||||
if (GetTime() >= nNow + 60) { | if (GetTime() >= nNow + 60) { | ||||
nNow = GetTime(); | nNow = GetTime(); | ||||
LOCK(cs_main); | |||||
LogPrintf( | LogPrintf( | ||||
"Still rescanning. At block %d. Progress=%f\n", | "Still rescanning. At block %d. Progress=%f\n", | ||||
pindex->nHeight, | pindex->nHeight, | ||||
GuessVerificationProgress(chainParams.TxData(), pindex)); | GuessVerificationProgress(chainParams.TxData(), pindex)); | ||||
} | } | ||||
CBlock block; | CBlock block; | ||||
if (ReadBlockFromDisk(block, pindex, GetConfig())) { | if (ReadBlockFromDisk(block, pindex, GetConfig())) { | ||||
LOCK2(cs_main, cs_wallet); | |||||
if (pindex && !chainActive.Contains(pindex)) { | |||||
// Abort scan if current block is no longer active, to | |||||
// prevent marking transactions as coming from the wrong | |||||
// block. | |||||
ret = pindex; | |||||
break; | |||||
} | |||||
for (size_t posInBlock = 0; posInBlock < block.vtx.size(); | for (size_t posInBlock = 0; posInBlock < block.vtx.size(); | ||||
++posInBlock) { | ++posInBlock) { | ||||
AddToWalletIfInvolvingMe(block.vtx[posInBlock], pindex, | AddToWalletIfInvolvingMe(block.vtx[posInBlock], pindex, | ||||
posInBlock, fUpdate); | posInBlock, fUpdate); | ||||
} | } | ||||
} else { | } else { | ||||
ret = pindex; | ret = pindex; | ||||
} | } | ||||
if (pindex == pindexStop) { | if (pindex == pindexStop) { | ||||
break; | break; | ||||
} | } | ||||
{ | |||||
LOCK(cs_main); | |||||
pindex = chainActive.Next(pindex); | pindex = chainActive.Next(pindex); | ||||
if (tip != chainActive.Tip()) { | |||||
tip = chainActive.Tip(); | |||||
// in case the tip has changed, update progress max | |||||
dProgressTip = | |||||
GuessVerificationProgress(chainParams.TxData(), tip); | |||||
} | |||||
} | |||||
} | } | ||||
if (pindex && fAbortRescan) { | if (pindex && fAbortRescan) { | ||||
LogPrintf("Rescan aborted at block %d. Progress=%f\n", | LogPrintf("Rescan aborted at block %d. Progress=%f\n", | ||||
pindex->nHeight, | pindex->nHeight, | ||||
GuessVerificationProgress(chainParams.TxData(), pindex)); | GuessVerificationProgress(chainParams.TxData(), pindex)); | ||||
} | } | ||||
// Hide progress dialog in GUI. | // Hide progress dialog in GUI. | ||||
ShowProgress(_("Rescanning..."), 100); | ShowProgress(_("Rescanning..."), 100); | ||||
fScanningWallet = false; | |||||
} | } | ||||
return ret; | return ret; | ||||
} | } | ||||
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) { | ||||
▲ Show 20 Lines • Show All 2,534 Lines • ▼ Show 20 Lines | if (chainActive.Tip() && chainActive.Tip() != pindexRescan) { | ||||
// birthday (as adjusted for block time variability) | // birthday (as adjusted for block time variability) | ||||
while (pindexRescan && walletInstance->nTimeFirstKey && | while (pindexRescan && walletInstance->nTimeFirstKey && | ||||
(pindexRescan->GetBlockTime() < | (pindexRescan->GetBlockTime() < | ||||
(walletInstance->nTimeFirstKey - TIMESTAMP_WINDOW))) { | (walletInstance->nTimeFirstKey - TIMESTAMP_WINDOW))) { | ||||
pindexRescan = chainActive.Next(pindexRescan); | pindexRescan = chainActive.Next(pindexRescan); | ||||
} | } | ||||
nStart = GetTimeMillis(); | nStart = GetTimeMillis(); | ||||
walletInstance->ScanForWalletTransactions(pindexRescan, nullptr, true); | { | ||||
WalletRescanReserver reserver(walletInstance); | |||||
if (!reserver.reserve()) { | |||||
InitError( | |||||
_("Failed to rescan the wallet during initialization")); | |||||
return nullptr; | |||||
} | |||||
walletInstance->ScanForWalletTransactions(pindexRescan, nullptr, | |||||
reserver, true); | |||||
} | |||||
LogPrintf(" rescan %15dms\n", GetTimeMillis() - nStart); | LogPrintf(" rescan %15dms\n", GetTimeMillis() - nStart); | ||||
walletInstance->SetBestChain(chainActive.GetLocator()); | walletInstance->SetBestChain(chainActive.GetLocator()); | ||||
walletInstance->dbw->IncrementUpdateCounter(); | walletInstance->dbw->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) && | ||||
gArgs.GetArg("-zapwallettxes", "1") != "2") { | gArgs.GetArg("-zapwallettxes", "1") != "2") { | ||||
CWalletDB walletdb(*walletInstance->dbw); | CWalletDB walletdb(*walletInstance->dbw); | ||||
▲ Show 20 Lines • Show All 124 Lines • Show Last 20 Lines |