From bb24d686500375564a2137f0940b329b6905bce6 Mon Sep 17 00:00:00 2001 From: Ben Woosley Date: Wed, 25 Apr 2018 15:41:55 -0400 Subject: [PATCH 1/3] Make CWallet::ScanForWalletTransactions args and return value const --- src/wallet/rpcwallet.cpp | 2 +- src/wallet/wallet.cpp | 6 +++--- src/wallet/wallet.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index bfac990639bf8..1514c978b87e5 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -3332,7 +3332,7 @@ UniValue rescanblockchain(const JSONRPCRequest& request) } } - CBlockIndex *stopBlock = pwallet->ScanForWalletTransactions(pindexStart, pindexStop, reserver, true); + const CBlockIndex* stopBlock = pwallet->ScanForWalletTransactions(pindexStart, pindexStop, reserver, true); if (!stopBlock) { if (pwallet->IsAbortingRescan()) { throw JSONRPCError(RPC_MISC_ERROR, "Rescan aborted."); diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 8ea4c5c4957d1..0e135d978d1d5 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -1637,7 +1637,7 @@ int64_t CWallet::RescanFromTime(int64_t startTime, const WalletRescanReserver& r * the main chain after to the addition of any new keys you want to detect * transactions for. */ -CBlockIndex* CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, CBlockIndex* pindexStop, const WalletRescanReserver &reserver, bool fUpdate) +const CBlockIndex* CWallet::ScanForWalletTransactions(const CBlockIndex* const pindexStart, const CBlockIndex* const pindexStop, const WalletRescanReserver& reserver, bool fUpdate) { int64_t nNow = GetTime(); const CChainParams& chainParams = Params(); @@ -1647,8 +1647,8 @@ CBlockIndex* CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, CBlock assert(pindexStop->nHeight >= pindexStart->nHeight); } - CBlockIndex* pindex = pindexStart; - CBlockIndex* ret = nullptr; + const CBlockIndex* pindex = pindexStart; + const CBlockIndex* ret = nullptr; if (pindex) WalletLogPrintf("Rescan started from block %d...\n", pindex->nHeight); diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index f96798201f1fa..dcd1ee687be31 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -896,7 +896,7 @@ class CWallet final : public CCryptoKeyStore, public CValidationInterface void BlockConnected(const std::shared_ptr& pblock, const CBlockIndex *pindex, const std::vector& vtxConflicted) override; void BlockDisconnected(const std::shared_ptr& pblock) override; int64_t RescanFromTime(int64_t startTime, const WalletRescanReserver& reserver, bool update); - CBlockIndex* ScanForWalletTransactions(CBlockIndex* pindexStart, CBlockIndex* pindexStop, const WalletRescanReserver& reserver, bool fUpdate = false); + const CBlockIndex* ScanForWalletTransactions(const CBlockIndex* const pindexStart, const CBlockIndex* const pindexStop, const WalletRescanReserver& reserver, bool fUpdate = false); void TransactionRemovedFromMempool(const CTransactionRef &ptx) override; void ReacceptWalletTransactions(); void ResendWalletTransactions(int64_t nBestBlockTime, CConnman* connman) override EXCLUSIVE_LOCKS_REQUIRED(cs_main); From 3002d6cf31821622e9f21d51e536cafc5cfb10ae Mon Sep 17 00:00:00 2001 From: Ben Woosley Date: Sun, 29 Apr 2018 15:45:44 +0000 Subject: [PATCH 2/3] Return a status enum from ScanForWalletTransactions Return the failed block as an out var. This clarifies the outcome as the prior return value could be null due to user abort or failure. --- src/qt/test/wallettests.cpp | 7 ++++- src/test/test_bitcoin.h | 8 ++++++ src/wallet/rpcwallet.cpp | 18 +++++++------ src/wallet/test/wallet_tests.cpp | 15 ++++++++--- src/wallet/wallet.cpp | 44 +++++++++++++++++++------------- src/wallet/wallet.h | 8 +++++- 6 files changed, 68 insertions(+), 32 deletions(-) diff --git a/src/qt/test/wallettests.cpp b/src/qt/test/wallettests.cpp index f02fd8aea7f7f..5646070a3ff29 100644 --- a/src/qt/test/wallettests.cpp +++ b/src/qt/test/wallettests.cpp @@ -146,7 +146,12 @@ void TestGUI() auto locked_chain = wallet->chain().lock(); WalletRescanReserver reserver(wallet.get()); reserver.reserve(); - wallet->ScanForWalletTransactions(chainActive.Genesis(), nullptr, reserver, true); + const CBlockIndex* const null_block = nullptr; + const CBlockIndex* stop_block; + QCOMPARE( + wallet->ScanForWalletTransactions(chainActive.Genesis(), nullptr, reserver, stop_block, true /* fUpdate */), + CWallet::ScanResult::SUCCESS); + QCOMPARE(stop_block, null_block); } wallet->SetBroadcastTransactions(true); diff --git a/src/test/test_bitcoin.h b/src/test/test_bitcoin.h index 38727671338f9..182571b004106 100644 --- a/src/test/test_bitcoin.h +++ b/src/test/test_bitcoin.h @@ -15,9 +15,17 @@ #include #include +#include #include +// Enable BOOST_CHECK_EQUAL for enum class types +template +std::ostream& operator<<(typename std::enable_if::value, std::ostream>::type& stream, const T& e) +{ + return stream << static_cast::type>(e); +} + extern uint256 insecure_rand_seed; extern FastRandomContext insecure_rand_ctx; diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 1514c978b87e5..c3f12f373d8f9 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -3332,16 +3332,18 @@ UniValue rescanblockchain(const JSONRPCRequest& request) } } - const CBlockIndex* stopBlock = pwallet->ScanForWalletTransactions(pindexStart, pindexStop, reserver, true); - if (!stopBlock) { - if (pwallet->IsAbortingRescan()) { - throw JSONRPCError(RPC_MISC_ERROR, "Rescan aborted."); - } - // if we got a nullptr returned, ScanForWalletTransactions did rescan up to the requested stopindex + const CBlockIndex* stopBlock; + CWallet::ScanResult result = + pwallet->ScanForWalletTransactions(pindexStart, pindexStop, reserver, stopBlock, true); + switch (result) { + case CWallet::ScanResult::SUCCESS: stopBlock = pindexStop ? pindexStop : pChainTip; - } - else { + break; + case CWallet::ScanResult::FAILURE: throw JSONRPCError(RPC_MISC_ERROR, "Rescan failed. Potentially corrupted data files."); + case CWallet::ScanResult::USER_ABORT: + throw JSONRPCError(RPC_MISC_ERROR, "Rescan aborted."); + // no default case, so the compiler can warn about missing cases } UniValue response(UniValue::VOBJ); response.pushKV("start_height", pindexStart->nHeight); diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp index c6aac8aad5666..dccda1acf1b33 100644 --- a/src/wallet/test/wallet_tests.cpp +++ b/src/wallet/test/wallet_tests.cpp @@ -38,7 +38,7 @@ BOOST_FIXTURE_TEST_CASE(rescan, TestChain100Setup) auto chain = interfaces::MakeChain(); // Cap last block file size, and mine new block in a new block file. - CBlockIndex* const nullBlock = nullptr; + const CBlockIndex* const null_block = nullptr; CBlockIndex* oldTip = chainActive.Tip(); GetBlockFileInfo(oldTip->GetBlockPos().nFile)->nSize = MAX_BLOCKFILE_SIZE; CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())); @@ -53,7 +53,9 @@ BOOST_FIXTURE_TEST_CASE(rescan, TestChain100Setup) AddKey(wallet, coinbaseKey); WalletRescanReserver reserver(&wallet); reserver.reserve(); - BOOST_CHECK_EQUAL(nullBlock, wallet.ScanForWalletTransactions(oldTip, nullptr, reserver)); + const CBlockIndex* stop_block; + BOOST_CHECK_EQUAL(wallet.ScanForWalletTransactions(oldTip, nullptr, reserver, stop_block), CWallet::ScanResult::SUCCESS); + BOOST_CHECK_EQUAL(stop_block, null_block); BOOST_CHECK_EQUAL(wallet.GetImmatureBalance(), 100 * COIN); } @@ -68,7 +70,9 @@ BOOST_FIXTURE_TEST_CASE(rescan, TestChain100Setup) AddKey(wallet, coinbaseKey); WalletRescanReserver reserver(&wallet); reserver.reserve(); - BOOST_CHECK_EQUAL(oldTip, wallet.ScanForWalletTransactions(oldTip, nullptr, reserver)); + const CBlockIndex* stop_block; + BOOST_CHECK_EQUAL(wallet.ScanForWalletTransactions(oldTip, nullptr, reserver, stop_block), CWallet::ScanResult::FAILURE); + BOOST_CHECK_EQUAL(oldTip, stop_block); BOOST_CHECK_EQUAL(wallet.GetImmatureBalance(), 50 * COIN); } @@ -286,7 +290,10 @@ class ListCoinsTestingSetup : public TestChain100Setup AddKey(*wallet, coinbaseKey); WalletRescanReserver reserver(wallet.get()); reserver.reserve(); - wallet->ScanForWalletTransactions(chainActive.Genesis(), nullptr, reserver); + const CBlockIndex* const null_block = nullptr; + const CBlockIndex* stop_block; + BOOST_CHECK_EQUAL(wallet->ScanForWalletTransactions(chainActive.Genesis(), nullptr, reserver, stop_block), CWallet::ScanResult::SUCCESS); + BOOST_CHECK_EQUAL(stop_block, null_block); } ~ListCoinsTestingSetup() diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 0e135d978d1d5..28ee32b128bb6 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -1613,8 +1613,9 @@ int64_t CWallet::RescanFromTime(int64_t startTime, const WalletRescanReserver& r } if (startBlock) { - const CBlockIndex* const failedBlock = ScanForWalletTransactions(startBlock, nullptr, reserver, update); - if (failedBlock) { + const CBlockIndex* failedBlock; + // TODO: this should take into account failure by ScanResult::USER_ABORT + if (ScanResult::FAILURE == ScanForWalletTransactions(startBlock, nullptr, reserver, failedBlock, update)) { return failedBlock->GetBlockTimeMax() + TIMESTAMP_WINDOW + 1; } } @@ -1626,18 +1627,20 @@ int64_t CWallet::RescanFromTime(int64_t startTime, const WalletRescanReserver& r * from or to us. If fUpdate is true, found transactions that already * exist in the wallet will be updated. * - * 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 - * block that could not be scanned. + * @param[in] pindexStop if not a nullptr, the scan will stop at this block-index + * @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 - * defined by pindexStop + * @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. * - * Caller needs to make sure pindexStop (and the optional pindexStart) are on + * @pre 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. */ -const CBlockIndex* CWallet::ScanForWalletTransactions(const CBlockIndex* const pindexStart, const CBlockIndex* const pindexStop, const WalletRescanReserver& reserver, bool fUpdate) +CWallet::ScanResult CWallet::ScanForWalletTransactions(const CBlockIndex* const pindexStart, const CBlockIndex* const pindexStop, const WalletRescanReserver& reserver, const CBlockIndex*& failed_block, bool fUpdate) { int64_t nNow = GetTime(); const CChainParams& chainParams = Params(); @@ -1648,7 +1651,7 @@ const CBlockIndex* CWallet::ScanForWalletTransactions(const CBlockIndex* const p } const CBlockIndex* pindex = pindexStart; - const CBlockIndex* ret = nullptr; + failed_block = nullptr; if (pindex) WalletLogPrintf("Rescan started from block %d...\n", pindex->nHeight); @@ -1669,8 +1672,7 @@ const CBlockIndex* CWallet::ScanForWalletTransactions(const CBlockIndex* const p } } double progress_current = progress_begin; - while (pindex && !fAbortRescan && !ShutdownRequested()) - { + while (pindex && !fAbortRescan && !ShutdownRequested()) { if (pindex->nHeight % 100 == 0 && progress_end - progress_begin > 0.0) { ShowProgress(strprintf("%s " + _("Rescanning..."), GetDisplayName()), std::max(1, std::min(99, (int)((progress_current - progress_begin) / (progress_end - progress_begin) * 100)))); } @@ -1686,14 +1688,14 @@ const CBlockIndex* CWallet::ScanForWalletTransactions(const CBlockIndex* const p 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; + failed_block = pindex; break; } for (size_t posInBlock = 0; posInBlock < block.vtx.size(); ++posInBlock) { SyncTransaction(block.vtx[posInBlock], pindex, posInBlock, fUpdate); } } else { - ret = pindex; + failed_block = pindex; } if (pindex == pindexStop) { break; @@ -1709,14 +1711,20 @@ const CBlockIndex* CWallet::ScanForWalletTransactions(const CBlockIndex* const p } } } + ShowProgress(strprintf("%s " + _("Rescanning..."), GetDisplayName()), 100); // hide progress dialog in GUI if (pindex && fAbortRescan) { WalletLogPrintf("Rescan aborted at block %d. Progress=%f\n", pindex->nHeight, progress_current); + return ScanResult::USER_ABORT; } else if (pindex && ShutdownRequested()) { WalletLogPrintf("Rescan interrupted by shutdown request at block %d. Progress=%f\n", pindex->nHeight, progress_current); + return ScanResult::USER_ABORT; } - ShowProgress(strprintf("%s " + _("Rescanning..."), GetDisplayName()), 100); // hide progress dialog in GUI } - return ret; + if (failed_block) { + return ScanResult::FAILURE; + } else { + return ScanResult::SUCCESS; + } } void CWallet::ReacceptWalletTransactions() @@ -4166,11 +4174,11 @@ std::shared_ptr CWallet::CreateWalletFromFile(interfaces::Chain& chain, nStart = GetTimeMillis(); { 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(_("Failed to rescan the wallet during initialization")); return nullptr; } - walletInstance->ScanForWalletTransactions(pindexRescan, nullptr, reserver, true); } walletInstance->WalletLogPrintf("Rescan completed in %15dms\n", GetTimeMillis() - nStart); walletInstance->ChainStateFlushed(chainActive.GetLocator()); diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index dcd1ee687be31..08184bdc22d47 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -896,7 +896,13 @@ class CWallet final : public CCryptoKeyStore, public CValidationInterface void BlockConnected(const std::shared_ptr& pblock, const CBlockIndex *pindex, const std::vector& vtxConflicted) override; void BlockDisconnected(const std::shared_ptr& pblock) override; int64_t RescanFromTime(int64_t startTime, const WalletRescanReserver& reserver, bool update); - const CBlockIndex* ScanForWalletTransactions(const CBlockIndex* const pindexStart, const CBlockIndex* const pindexStop, const WalletRescanReserver& reserver, bool fUpdate = false); + + enum class ScanResult { + SUCCESS, + FAILURE, + USER_ABORT + }; + ScanResult ScanForWalletTransactions(const CBlockIndex* const pindexStart, const CBlockIndex* const pindexStop, const WalletRescanReserver& reserver, const CBlockIndex*& failed_block, bool fUpdate = false); void TransactionRemovedFromMempool(const CTransactionRef &ptx) override; void ReacceptWalletTransactions(); void ResendWalletTransactions(int64_t nBestBlockTime, CConnman* connman) override EXCLUSIVE_LOCKS_REQUIRED(cs_main); From bd3b0361d840bff95988a048abf70ade94d80524 Mon Sep 17 00:00:00 2001 From: Ben Woosley Date: Tue, 13 Nov 2018 04:57:10 +0000 Subject: [PATCH 3/3] Add stop_block out arg to ScanForWalletTransactions Accurately reports the last block successfully scanned, replacing a return of the chain tip, which represented possibly inaccurated data in a race condition. --- src/qt/test/wallettests.cpp | 7 ++++--- src/wallet/rpcwallet.cpp | 7 +++---- src/wallet/test/wallet_tests.cpp | 21 ++++++++++++--------- src/wallet/wallet.cpp | 19 ++++++++++++------- src/wallet/wallet.h | 2 +- 5 files changed, 32 insertions(+), 24 deletions(-) diff --git a/src/qt/test/wallettests.cpp b/src/qt/test/wallettests.cpp index 5646070a3ff29..610d83acb6fb9 100644 --- a/src/qt/test/wallettests.cpp +++ b/src/qt/test/wallettests.cpp @@ -147,11 +147,12 @@ void TestGUI() WalletRescanReserver reserver(wallet.get()); reserver.reserve(); const CBlockIndex* const null_block = nullptr; - const CBlockIndex* stop_block; + const CBlockIndex *stop_block, *failed_block; QCOMPARE( - wallet->ScanForWalletTransactions(chainActive.Genesis(), nullptr, reserver, stop_block, true /* fUpdate */), + wallet->ScanForWalletTransactions(chainActive.Genesis(), nullptr, reserver, failed_block, stop_block, true /* fUpdate */), CWallet::ScanResult::SUCCESS); - QCOMPARE(stop_block, null_block); + QCOMPARE(stop_block, chainActive.Tip()); + QCOMPARE(failed_block, null_block); } wallet->SetBroadcastTransactions(true); diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index c3f12f373d8f9..3c92eb31204c8 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -3332,13 +3332,12 @@ UniValue rescanblockchain(const JSONRPCRequest& request) } } - const CBlockIndex* stopBlock; + const CBlockIndex *failed_block, *stopBlock; CWallet::ScanResult result = - pwallet->ScanForWalletTransactions(pindexStart, pindexStop, reserver, stopBlock, true); + pwallet->ScanForWalletTransactions(pindexStart, pindexStop, reserver, failed_block, stopBlock, true); switch (result) { case CWallet::ScanResult::SUCCESS: - stopBlock = pindexStop ? pindexStop : pChainTip; - break; + break; // stopBlock set by ScanForWalletTransactions case CWallet::ScanResult::FAILURE: throw JSONRPCError(RPC_MISC_ERROR, "Rescan failed. Potentially corrupted data files."); case CWallet::ScanResult::USER_ABORT: diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp index dccda1acf1b33..46d9b5b238313 100644 --- a/src/wallet/test/wallet_tests.cpp +++ b/src/wallet/test/wallet_tests.cpp @@ -53,9 +53,10 @@ BOOST_FIXTURE_TEST_CASE(rescan, TestChain100Setup) AddKey(wallet, coinbaseKey); WalletRescanReserver reserver(&wallet); reserver.reserve(); - const CBlockIndex* stop_block; - BOOST_CHECK_EQUAL(wallet.ScanForWalletTransactions(oldTip, nullptr, reserver, stop_block), CWallet::ScanResult::SUCCESS); - BOOST_CHECK_EQUAL(stop_block, null_block); + const CBlockIndex *stop_block, *failed_block; + BOOST_CHECK_EQUAL(wallet.ScanForWalletTransactions(oldTip, nullptr, reserver, failed_block, stop_block), CWallet::ScanResult::SUCCESS); + BOOST_CHECK_EQUAL(failed_block, null_block); + BOOST_CHECK_EQUAL(stop_block, newTip); BOOST_CHECK_EQUAL(wallet.GetImmatureBalance(), 100 * COIN); } @@ -70,9 +71,10 @@ BOOST_FIXTURE_TEST_CASE(rescan, TestChain100Setup) AddKey(wallet, coinbaseKey); WalletRescanReserver reserver(&wallet); reserver.reserve(); - const CBlockIndex* stop_block; - BOOST_CHECK_EQUAL(wallet.ScanForWalletTransactions(oldTip, nullptr, reserver, stop_block), CWallet::ScanResult::FAILURE); - BOOST_CHECK_EQUAL(oldTip, stop_block); + const CBlockIndex *stop_block, *failed_block; + BOOST_CHECK_EQUAL(wallet.ScanForWalletTransactions(oldTip, nullptr, reserver, failed_block, stop_block), CWallet::ScanResult::FAILURE); + BOOST_CHECK_EQUAL(failed_block, oldTip); + BOOST_CHECK_EQUAL(stop_block, newTip); BOOST_CHECK_EQUAL(wallet.GetImmatureBalance(), 50 * COIN); } @@ -291,9 +293,10 @@ class ListCoinsTestingSetup : public TestChain100Setup WalletRescanReserver reserver(wallet.get()); reserver.reserve(); const CBlockIndex* const null_block = nullptr; - const CBlockIndex* stop_block; - BOOST_CHECK_EQUAL(wallet->ScanForWalletTransactions(chainActive.Genesis(), nullptr, reserver, stop_block), CWallet::ScanResult::SUCCESS); - BOOST_CHECK_EQUAL(stop_block, null_block); + const CBlockIndex *stop_block, *failed_block; + BOOST_CHECK_EQUAL(wallet->ScanForWalletTransactions(chainActive.Genesis(), nullptr, reserver, failed_block, stop_block), CWallet::ScanResult::SUCCESS); + BOOST_CHECK_EQUAL(stop_block, chainActive.Tip()); + BOOST_CHECK_EQUAL(failed_block, null_block); } ~ListCoinsTestingSetup() diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 28ee32b128bb6..3c25a67fd1484 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -1613,9 +1613,9 @@ int64_t CWallet::RescanFromTime(int64_t startTime, const WalletRescanReserver& r } if (startBlock) { - const CBlockIndex* failedBlock; + const CBlockIndex *failedBlock, *stop_block; // TODO: this should take into account failure by ScanResult::USER_ABORT - if (ScanResult::FAILURE == ScanForWalletTransactions(startBlock, nullptr, reserver, failedBlock, update)) { + if (ScanResult::FAILURE == ScanForWalletTransactions(startBlock, nullptr, reserver, failedBlock, stop_block, update)) { return failedBlock->GetBlockTimeMax() + TIMESTAMP_WINDOW + 1; } } @@ -1628,8 +1628,10 @@ int64_t CWallet::RescanFromTime(int64_t startTime, const WalletRescanReserver& r * exist in the wallet will be updated. * * @param[in] pindexStop if not a nullptr, the scan will stop at this block-index - * @param[out] failed_block if FAILURE is returned, will be set to the most - * recent block that could not be scanned, otherwise nullptr + * @param[out] failed_block if FAILURE is returned, the most recent block + * that could not be scanned, otherwise nullptr + * @param[out] stop_block the most recent block that could be scanned, + * otherwise nullptr if no block could be scanned * * @return ScanResult indicating success or failure of the scan. SUCCESS if * scan was successful. FAILURE if a complete rescan was not possible (due to @@ -1640,7 +1642,7 @@ int64_t CWallet::RescanFromTime(int64_t startTime, const WalletRescanReserver& r * the main chain after to the addition of any new keys you want to detect * transactions for. */ -CWallet::ScanResult CWallet::ScanForWalletTransactions(const CBlockIndex* const pindexStart, const CBlockIndex* const pindexStop, const WalletRescanReserver& reserver, const CBlockIndex*& failed_block, bool fUpdate) +CWallet::ScanResult CWallet::ScanForWalletTransactions(const CBlockIndex* const pindexStart, const CBlockIndex* const pindexStop, const WalletRescanReserver& reserver, const CBlockIndex*& failed_block, const CBlockIndex*& stop_block, bool fUpdate) { int64_t nNow = GetTime(); const CChainParams& chainParams = Params(); @@ -1694,7 +1696,10 @@ CWallet::ScanResult CWallet::ScanForWalletTransactions(const CBlockIndex* const for (size_t posInBlock = 0; posInBlock < block.vtx.size(); ++posInBlock) { SyncTransaction(block.vtx[posInBlock], pindex, posInBlock, fUpdate); } + // scan succeeded, record block as most recent successfully scanned + stop_block = pindex; } else { + // could not scan block, keep scanning but record this block as the most recent failure failed_block = pindex; } if (pindex == pindexStop) { @@ -4174,8 +4179,8 @@ std::shared_ptr CWallet::CreateWalletFromFile(interfaces::Chain& chain, nStart = GetTimeMillis(); { WalletRescanReserver reserver(walletInstance.get()); - const CBlockIndex* stop_block; - if (!reserver.reserve() || (ScanResult::SUCCESS != walletInstance->ScanForWalletTransactions(pindexRescan, nullptr, reserver, stop_block, true))) { + const CBlockIndex *stop_block, *failed_block; + if (!reserver.reserve() || (ScanResult::SUCCESS != walletInstance->ScanForWalletTransactions(pindexRescan, nullptr, reserver, failed_block, stop_block, true))) { InitError(_("Failed to rescan the wallet during initialization")); return nullptr; } diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 08184bdc22d47..5ba5514fc2b9d 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -902,7 +902,7 @@ class CWallet final : public CCryptoKeyStore, public CValidationInterface FAILURE, USER_ABORT }; - ScanResult ScanForWalletTransactions(const CBlockIndex* const pindexStart, const CBlockIndex* const pindexStop, const WalletRescanReserver& reserver, const CBlockIndex*& failed_block, bool fUpdate = false); + ScanResult ScanForWalletTransactions(const CBlockIndex* const pindexStart, const CBlockIndex* const pindexStop, const WalletRescanReserver& reserver, const CBlockIndex*& failed_block, const CBlockIndex*& stop_block, bool fUpdate = false); void TransactionRemovedFromMempool(const CTransactionRef &ptx) override; void ReacceptWalletTransactions(); void ResendWalletTransactions(int64_t nBestBlockTime, CConnman* connman) override EXCLUSIVE_LOCKS_REQUIRED(cs_main);