diff --git a/src/interfaces/chain.h b/src/interfaces/chain.h --- a/src/interfaces/chain.h +++ b/src/interfaces/chain.h @@ -139,7 +139,7 @@ virtual bool isPotentialTip(const BlockHash &hash) = 0; //! Get locator for the current chain tip. - virtual CBlockLocator getLocator() = 0; + virtual CBlockLocator getTipLocator() = 0; //! Return height of the latest block common to locator and chain, which //! is guaranteed to be an ancestor of the block used to create the diff --git a/src/interfaces/chain.cpp b/src/interfaces/chain.cpp --- a/src/interfaces/chain.cpp +++ b/src/interfaces/chain.cpp @@ -139,7 +139,7 @@ return block && block->GetAncestor(::ChainActive().Height()) == ::ChainActive().Tip(); } - CBlockLocator getLocator() override { + CBlockLocator getTipLocator() override { return ::ChainActive().GetLocator(); } Optional findLocatorFork(const CBlockLocator &locator) override { diff --git a/src/qt/test/wallettests.cpp b/src/qt/test/wallettests.cpp --- a/src/qt/test/wallettests.cpp +++ b/src/qt/test/wallettests.cpp @@ -134,8 +134,9 @@ locked_chain->getBlockHash(0), BlockHash(), reserver, true /* fUpdate */); QCOMPARE(result.status, CWallet::ScanResult::SUCCESS); - QCOMPARE(result.stop_block, ::ChainActive().Tip()->GetBlockHash()); - QVERIFY(result.failed_block.IsNull()); + QCOMPARE(result.last_scanned_block, + ::ChainActive().Tip()->GetBlockHash()); + QVERIFY(result.last_failed_block.IsNull()); } wallet->SetBroadcastTransactions(true); diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -4009,11 +4009,11 @@ }, RPCResult{"{\n" " \"start_height\" (numeric) The block height where " - "the rescan has started. If omitted, rescan started from " - "the genesis block.\n" + "the rescan started (the requested height or 0\n" " \"stop_height\" (numeric) The height of the last " - "rescanned block. If omitted, rescan stopped at the " - "chain tip.\n" + "rescanned block. May be null in rare cases if there was " + "a reorg and the call didn't scan any blocks because " + "they were already scanned in the background.\n" "}\n"}, RPCExamples{HelpExampleCli("rescanblockchain", "100000 120000") + HelpExampleRpc("rescanblockchain", "100000, 120000")}, @@ -4066,6 +4066,11 @@ if (tip_height) { start_block = locked_chain->getBlockHash(start_height); + // If called with a stop_height, set the stop_height here to + // trigger a rescan to that height. + // If called without a stop height, leave stop_height as null here + // so rescan continues to the tip (even if the tip advances during + // rescan). if (stop_height) { stop_block = locked_chain->getBlockHash(*stop_height); } @@ -4087,8 +4092,9 @@ } UniValue response(UniValue::VOBJ); response.pushKV("start_height", start_height); - response.pushKV("stop_height", - result.stop_height ? *result.stop_height : UniValue()); + response.pushKV("stop_height", result.last_scanned_height + ? *result.last_scanned_height + : UniValue()); return response; } diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp --- a/src/wallet/test/wallet_tests.cpp +++ b/src/wallet/test/wallet_tests.cpp @@ -53,9 +53,9 @@ CWallet::ScanResult result = wallet.ScanForWalletTransactions( BlockHash(), BlockHash(), reserver, false /* update */); BOOST_CHECK_EQUAL(result.status, CWallet::ScanResult::SUCCESS); - BOOST_CHECK(result.failed_block.IsNull()); - BOOST_CHECK(result.stop_block.IsNull()); - BOOST_CHECK(!result.stop_height); + BOOST_CHECK(result.last_failed_block.IsNull()); + BOOST_CHECK(result.last_scanned_block.IsNull()); + BOOST_CHECK(!result.last_scanned_height); BOOST_CHECK_EQUAL(wallet.GetImmatureBalance(), Amount::zero()); } @@ -70,9 +70,9 @@ CWallet::ScanResult result = wallet.ScanForWalletTransactions( oldTip->GetBlockHash(), BlockHash(), reserver, false /* update */); BOOST_CHECK_EQUAL(result.status, CWallet::ScanResult::SUCCESS); - BOOST_CHECK(result.failed_block.IsNull()); - BOOST_CHECK_EQUAL(result.stop_block, newTip->GetBlockHash()); - BOOST_CHECK_EQUAL(*result.stop_height, newTip->nHeight); + BOOST_CHECK(result.last_failed_block.IsNull()); + BOOST_CHECK_EQUAL(result.last_scanned_block, newTip->GetBlockHash()); + BOOST_CHECK_EQUAL(*result.last_scanned_height, newTip->nHeight); BOOST_CHECK_EQUAL(wallet.GetImmatureBalance(), 100 * COIN); } @@ -91,9 +91,9 @@ CWallet::ScanResult result = wallet.ScanForWalletTransactions( oldTip->GetBlockHash(), BlockHash(), reserver, false /* update */); BOOST_CHECK_EQUAL(result.status, CWallet::ScanResult::FAILURE); - BOOST_CHECK_EQUAL(result.failed_block, oldTip->GetBlockHash()); - BOOST_CHECK_EQUAL(result.stop_block, newTip->GetBlockHash()); - BOOST_CHECK_EQUAL(*result.stop_height, newTip->nHeight); + BOOST_CHECK_EQUAL(result.last_failed_block, oldTip->GetBlockHash()); + BOOST_CHECK_EQUAL(result.last_scanned_block, newTip->GetBlockHash()); + BOOST_CHECK_EQUAL(*result.last_scanned_height, newTip->nHeight); BOOST_CHECK_EQUAL(wallet.GetImmatureBalance(), 50 * COIN); } @@ -111,9 +111,9 @@ CWallet::ScanResult result = wallet.ScanForWalletTransactions( oldTip->GetBlockHash(), BlockHash(), reserver, false /* update */); BOOST_CHECK_EQUAL(result.status, CWallet::ScanResult::FAILURE); - BOOST_CHECK_EQUAL(result.failed_block, newTip->GetBlockHash()); - BOOST_CHECK(result.stop_block.IsNull()); - BOOST_CHECK(!result.stop_height); + BOOST_CHECK_EQUAL(result.last_failed_block, newTip->GetBlockHash()); + BOOST_CHECK(result.last_scanned_block.IsNull()); + BOOST_CHECK(!result.last_scanned_height); BOOST_CHECK_EQUAL(wallet.GetImmatureBalance(), Amount::zero()); } } @@ -370,10 +370,11 @@ ::ChainActive().Genesis()->GetBlockHash(), BlockHash(), reserver, false /* update */); BOOST_CHECK_EQUAL(result.status, CWallet::ScanResult::SUCCESS); - BOOST_CHECK_EQUAL(result.stop_block, + BOOST_CHECK_EQUAL(result.last_scanned_block, ::ChainActive().Tip()->GetBlockHash()); - BOOST_CHECK_EQUAL(*result.stop_height, ::ChainActive().Height()); - BOOST_CHECK(result.failed_block.IsNull()); + BOOST_CHECK_EQUAL(*result.last_scanned_height, + ::ChainActive().Height()); + BOOST_CHECK(result.last_failed_block.IsNull()); } ~ListCoinsTestingSetup() { wallet.reset(); } diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -1072,14 +1072,14 @@ //! Hash and height of most recent block that was successfully scanned. //! Unset if no blocks were scanned due to read errors or the chain //! being empty. - BlockHash stop_block; - Optional stop_height; + BlockHash last_scanned_block; + Optional last_scanned_height; //! Hash of the most recent block that could not be scanned due to //! read errors or pruning. Will be set if status is FAILURE, unset if //! status is SUCCESS, and may or may not be set if status is //! USER_ABORT. - BlockHash failed_block; + BlockHash last_failed_block; }; ScanResult ScanForWalletTransactions(const BlockHash &first_block, const BlockHash &last_block, diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -1806,8 +1806,9 @@ reserver, update); if (result.status == ScanResult::FAILURE) { int64_t time_max; - if (!chain().findBlock(result.failed_block, nullptr /* block */, - nullptr /* time */, &time_max)) { + if (!chain().findBlock(result.last_failed_block, + nullptr /* block */, nullptr /* time */, + &time_max)) { throw std::logic_error( "ScanForWalletTransactions returned invalid block hash"); } @@ -1822,15 +1823,17 @@ * us. If fUpdate is true, found transactions that already exist in the wallet * will be updated. * - * @param[in] start_block if not null, the scan will start at this block instead - * of the genesis block - * @param[in] stop_block if not null, the scan will stop at this block instead - * of the chain tip + * @param[in] start_block Scan starting block. If block is not on the active + * chain, the scan will return SUCCESS immediately. + * @param[in] stop_block Scan ending block. If block is not on the active + * chain, the scan will continue until it reaches the + * chain tip. * - * @return ScanResult indicating success or failure of the scan. SUCCESS if - * 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. + * @return ScanResult returning scan information and indicating success or + * failure. Return status will be set to SUCCESS if 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. * * @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 @@ -1900,7 +1903,7 @@ // block. // TODO: This should return success instead of failure, see // https://github.com/bitcoin/bitcoin/pull/14711#issuecomment-458342518 - result.failed_block = block_hash; + result.last_failed_block = block_hash; result.status = ScanResult::FAILURE; break; } @@ -1911,12 +1914,12 @@ } // scan succeeded, record block as most recent successfully // scanned - result.stop_block = block_hash; - result.stop_height = *block_height; + result.last_scanned_block = block_hash; + result.last_scanned_height = *block_height; } else { // could not scan block, keep scanning but record this block as // the most recent failure - result.failed_block = block_hash; + result.last_failed_block = block_hash; result.status = ScanResult::FAILURE; } if (block_hash == stop_block) { @@ -1952,12 +1955,12 @@ 100); if (block_height && fAbortRescan) { WalletLogPrintf("Rescan aborted at block %d. Progress=%f\n", - block_height.value_or(0), progress_current); + *block_height, progress_current); result.status = ScanResult::USER_ABORT; } else if (block_height && chain().shutdownRequested()) { WalletLogPrintf("Rescan interrupted by shutdown request at block " "%d. Progress=%f\n", - block_height.value_or(0), progress_current); + *block_height, progress_current); result.status = ScanResult::USER_ABORT; } } @@ -4586,7 +4589,7 @@ // Temporary. Removed in upcoming lock cleanup auto locked_chain = chain.assumeLocked(); - walletInstance->ChainStateFlushed(locked_chain->getLocator()); + walletInstance->ChainStateFlushed(locked_chain->getTipLocator()); } else if (wallet_creation_flags & WALLET_FLAG_DISABLE_PRIVATE_KEYS) { // Make it impossible to disable private keys after creation chain.initError( @@ -4754,7 +4757,7 @@ } walletInstance->WalletLogPrintf("Rescan completed in %15dms\n", GetTimeMillis() - nStart); - walletInstance->ChainStateFlushed(locked_chain->getLocator()); + walletInstance->ChainStateFlushed(locked_chain->getTipLocator()); walletInstance->database->IncrementUpdateCounter(); // Restore wallet transaction metadata after -zapwallettxes=1