Changeset View
Changeset View
Standalone View
Standalone View
src/wallet/wallet.cpp
Show First 20 Lines • Show All 1,714 Lines • ▼ Show 20 Lines | bool start = chain().findFirstBlockWithTimeAndHeight( | ||||
FoundBlock().hash(start_block).height(start_height)); | FoundBlock().hash(start_block).height(start_height)); | ||||
WalletLogPrintf("%s: Rescanning last %i blocks\n", __func__, | WalletLogPrintf("%s: Rescanning last %i blocks\n", __func__, | ||||
start ? WITH_LOCK(cs_wallet, return GetLastBlockHeight()) - | start ? WITH_LOCK(cs_wallet, return GetLastBlockHeight()) - | ||||
start_height + 1 | start_height + 1 | ||||
: 0); | : 0); | ||||
if (start) { | if (start) { | ||||
// TODO: this should take into account failure by ScanResult::USER_ABORT | // TODO: this should take into account failure by ScanResult::USER_ABORT | ||||
ScanResult result = ScanForWalletTransactions(start_block, BlockHash(), | ScanResult result = ScanForWalletTransactions( | ||||
reserver, update); | start_block, {} /* max_height */, reserver, update); | ||||
if (result.status == ScanResult::FAILURE) { | if (result.status == ScanResult::FAILURE) { | ||||
int64_t time_max; | int64_t time_max; | ||||
CHECK_NONFATAL(chain().findBlock(result.last_failed_block, | CHECK_NONFATAL(chain().findBlock(result.last_failed_block, | ||||
FoundBlock().maxTime(time_max))); | FoundBlock().maxTime(time_max))); | ||||
return time_max + TIMESTAMP_WINDOW + 1; | return time_max + TIMESTAMP_WINDOW + 1; | ||||
} | } | ||||
} | } | ||||
return startTime; | return startTime; | ||||
} | } | ||||
/** | /** | ||||
* Scan the block chain (starting in start_block) for transactions from or to | * Scan the block chain (starting in start_block) 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. | ||||
* | * | ||||
* @param[in] start_block Scan starting block. If block is not on the active | * @param[in] start_block Scan starting block. If block is not on the active | ||||
* chain, the scan will return SUCCESS immediately. | * chain, the scan will return SUCCESS immediately. | ||||
* @param[in] stop_block Scan ending block. If block is not on the active | * @param[in] max_height Optional max scanning height. If unset there is | ||||
* chain, the scan will continue until it reaches the | * no maximum and scanning can continue to the tip | ||||
* chain tip. | |||||
* | * | ||||
* @return ScanResult returning scan information and indicating success or | * @return ScanResult returning scan information and indicating success or | ||||
* failure. Return status will be set to SUCCESS if scan was | * failure. Return status will be set to SUCCESS if scan was | ||||
* successful. FAILURE if a complete rescan was not possible (due to | * successful. FAILURE if a complete rescan was not possible (due to | ||||
* pruning or corruption). USER_ABORT if the rescan was aborted before | * pruning or corruption). USER_ABORT if the rescan was aborted before | ||||
* it could complete. | * it could complete. | ||||
* | * | ||||
* @pre Caller needs to make sure start_block (and the optional stop_block) are | * @pre Caller needs to make sure start_block (and the optional stop_block) are | ||||
* on 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. | ||||
*/ | */ | ||||
CWallet::ScanResult CWallet::ScanForWalletTransactions( | CWallet::ScanResult CWallet::ScanForWalletTransactions( | ||||
const BlockHash &start_block, const BlockHash &stop_block, | const BlockHash &start_block, Optional<int> max_height, | ||||
const WalletRescanReserver &reserver, bool fUpdate) { | const WalletRescanReserver &reserver, bool fUpdate) { | ||||
int64_t nNow = GetTime(); | int64_t nNow = GetTime(); | ||||
int64_t start_time = GetTimeMillis(); | int64_t start_time = GetTimeMillis(); | ||||
assert(reserver.isReserved()); | assert(reserver.isReserved()); | ||||
BlockHash block_hash = start_block; | BlockHash block_hash = start_block; | ||||
ScanResult result; | ScanResult result; | ||||
Show All 14 Lines | CWallet::ScanResult CWallet::ScanForWalletTransactions( | ||||
double progress_begin; | double progress_begin; | ||||
double progress_end; | double progress_end; | ||||
{ | { | ||||
auto locked_chain = chain().lock(); | auto locked_chain = chain().lock(); | ||||
if (Optional<int> tip_height = locked_chain->getHeight()) { | if (Optional<int> tip_height = locked_chain->getHeight()) { | ||||
tip_hash = locked_chain->getBlockHash(*tip_height); | tip_hash = locked_chain->getBlockHash(*tip_height); | ||||
} | } | ||||
block_height = locked_chain->getBlockHeight(block_hash); | block_height = locked_chain->getBlockHeight(block_hash); | ||||
BlockHash end_hash = tip_hash; | |||||
if (max_height) { | |||||
chain().findAncestorByHeight(tip_hash, *max_height, | |||||
FoundBlock().hash(end_hash)); | |||||
} | |||||
progress_begin = chain().guessVerificationProgress(block_hash); | progress_begin = chain().guessVerificationProgress(block_hash); | ||||
progress_end = chain().guessVerificationProgress( | progress_end = chain().guessVerificationProgress(end_hash); | ||||
stop_block.IsNull() ? tip_hash : stop_block); | |||||
} | } | ||||
double progress_current = progress_begin; | double progress_current = progress_begin; | ||||
while (block_height && !fAbortRescan && !chain().shutdownRequested()) { | while (block_height && !fAbortRescan && !chain().shutdownRequested()) { | ||||
m_scanning_progress = (progress_current - progress_begin) / | m_scanning_progress = (progress_current - progress_begin) / | ||||
(progress_end - progress_begin); | (progress_end - progress_begin); | ||||
if (*block_height % 100 == 0 && progress_end - progress_begin > 0.0) { | if (*block_height % 100 == 0 && progress_end - progress_begin > 0.0) { | ||||
ShowProgress( | ShowProgress( | ||||
strprintf("%s " + _("Rescanning...").translated, | strprintf("%s " + _("Rescanning...").translated, | ||||
Show All 33 Lines | while (block_height && !fAbortRescan && !chain().shutdownRequested()) { | ||||
result.last_scanned_block = block_hash; | result.last_scanned_block = block_hash; | ||||
result.last_scanned_height = *block_height; | result.last_scanned_height = *block_height; | ||||
} else { | } else { | ||||
// could not scan block, keep scanning but record this block as | // could not scan block, keep scanning but record this block as | ||||
// the most recent failure | // the most recent failure | ||||
result.last_failed_block = block_hash; | result.last_failed_block = block_hash; | ||||
result.status = ScanResult::FAILURE; | result.status = ScanResult::FAILURE; | ||||
} | } | ||||
if (block_hash == stop_block) { | if (max_height && *block_height >= *max_height) { | ||||
break; | break; | ||||
} | } | ||||
{ | { | ||||
auto locked_chain = chain().lock(); | auto locked_chain = chain().lock(); | ||||
Optional<int> tip_height = locked_chain->getHeight(); | Optional<int> tip_height = locked_chain->getHeight(); | ||||
if (!tip_height || *tip_height <= block_height || | if (!tip_height || *tip_height <= block_height || | ||||
!locked_chain->getBlockHeight(block_hash)) { | !locked_chain->getBlockHeight(block_hash)) { | ||||
// break successfully when rescan has reached the tip, or | // break successfully when rescan has reached the tip, or | ||||
// previous block is no longer on the chain due to a reorg | // previous block is no longer on the chain due to a reorg | ||||
break; | break; | ||||
} | } | ||||
// increment block and verification progress | // increment block and verification progress | ||||
block_hash = locked_chain->getBlockHash(++*block_height); | block_hash = locked_chain->getBlockHash(++*block_height); | ||||
progress_current = chain().guessVerificationProgress(block_hash); | progress_current = chain().guessVerificationProgress(block_hash); | ||||
// handle updated tip hash | // handle updated tip hash | ||||
const BlockHash prev_tip_hash = tip_hash; | const BlockHash prev_tip_hash = tip_hash; | ||||
tip_hash = locked_chain->getBlockHash(*tip_height); | tip_hash = locked_chain->getBlockHash(*tip_height); | ||||
if (stop_block.IsNull() && prev_tip_hash != tip_hash) { | if (!max_height && prev_tip_hash != tip_hash) { | ||||
// in case the tip has changed, update progress max | // in case the tip has changed, update progress max | ||||
progress_end = chain().guessVerificationProgress(tip_hash); | progress_end = chain().guessVerificationProgress(tip_hash); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
// Hide progress dialog in GUI. | // Hide progress dialog in GUI. | ||||
ShowProgress( | ShowProgress( | ||||
▲ Show 20 Lines • Show All 2,550 Lines • ▼ Show 20 Lines | if (tip_height && *tip_height != rescan_height) { | ||||
} | } | ||||
{ | { | ||||
WalletRescanReserver reserver(*walletInstance); | WalletRescanReserver reserver(*walletInstance); | ||||
if (!reserver.reserve() || | if (!reserver.reserve() || | ||||
(ScanResult::SUCCESS != | (ScanResult::SUCCESS != | ||||
walletInstance | walletInstance | ||||
->ScanForWalletTransactions( | ->ScanForWalletTransactions( | ||||
locked_chain->getBlockHash(rescan_height), BlockHash(), | locked_chain->getBlockHash(rescan_height), | ||||
reserver, true /* update */) | {} /* max_height */, reserver, true /* update */) | ||||
.status)) { | .status)) { | ||||
error = _("Failed to rescan the wallet during initialization"); | error = _("Failed to rescan the wallet during initialization"); | ||||
return nullptr; | return nullptr; | ||||
} | } | ||||
} | } | ||||
walletInstance->ChainStateFlushed(locked_chain->getTipLocator()); | walletInstance->ChainStateFlushed(locked_chain->getTipLocator()); | ||||
walletInstance->database->IncrementUpdateCounter(); | walletInstance->database->IncrementUpdateCounter(); | ||||
▲ Show 20 Lines • Show All 336 Lines • Show Last 20 Lines |