Skip to content

Commit 3002d6c

Browse files
committed
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.
1 parent bb24d68 commit 3002d6c

File tree

6 files changed

+68
-32
lines changed

6 files changed

+68
-32
lines changed

src/qt/test/wallettests.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,12 @@ void TestGUI()
146146
auto locked_chain = wallet->chain().lock();
147147
WalletRescanReserver reserver(wallet.get());
148148
reserver.reserve();
149-
wallet->ScanForWalletTransactions(chainActive.Genesis(), nullptr, reserver, true);
149+
const CBlockIndex* const null_block = nullptr;
150+
const CBlockIndex* stop_block;
151+
QCOMPARE(
152+
wallet->ScanForWalletTransactions(chainActive.Genesis(), nullptr, reserver, stop_block, true /* fUpdate */),
153+
CWallet::ScanResult::SUCCESS);
154+
QCOMPARE(stop_block, null_block);
150155
}
151156
wallet->SetBroadcastTransactions(true);
152157

src/test/test_bitcoin.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,17 @@
1515
#include <txmempool.h>
1616

1717
#include <memory>
18+
#include <type_traits>
1819

1920
#include <boost/thread.hpp>
2021

22+
// Enable BOOST_CHECK_EQUAL for enum class types
23+
template <typename T>
24+
std::ostream& operator<<(typename std::enable_if<std::is_enum<T>::value, std::ostream>::type& stream, const T& e)
25+
{
26+
return stream << static_cast<typename std::underlying_type<T>::type>(e);
27+
}
28+
2129
extern uint256 insecure_rand_seed;
2230
extern FastRandomContext insecure_rand_ctx;
2331

src/wallet/rpcwallet.cpp

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3332,16 +3332,18 @@ UniValue rescanblockchain(const JSONRPCRequest& request)
33323332
}
33333333
}
33343334

3335-
const CBlockIndex* stopBlock = pwallet->ScanForWalletTransactions(pindexStart, pindexStop, reserver, true);
3336-
if (!stopBlock) {
3337-
if (pwallet->IsAbortingRescan()) {
3338-
throw JSONRPCError(RPC_MISC_ERROR, "Rescan aborted.");
3339-
}
3340-
// if we got a nullptr returned, ScanForWalletTransactions did rescan up to the requested stopindex
3335+
const CBlockIndex* stopBlock;
3336+
CWallet::ScanResult result =
3337+
pwallet->ScanForWalletTransactions(pindexStart, pindexStop, reserver, stopBlock, true);
3338+
switch (result) {
3339+
case CWallet::ScanResult::SUCCESS:
33413340
stopBlock = pindexStop ? pindexStop : pChainTip;
3342-
}
3343-
else {
3341+
break;
3342+
case CWallet::ScanResult::FAILURE:
33443343
throw JSONRPCError(RPC_MISC_ERROR, "Rescan failed. Potentially corrupted data files.");
3344+
case CWallet::ScanResult::USER_ABORT:
3345+
throw JSONRPCError(RPC_MISC_ERROR, "Rescan aborted.");
3346+
// no default case, so the compiler can warn about missing cases
33453347
}
33463348
UniValue response(UniValue::VOBJ);
33473349
response.pushKV("start_height", pindexStart->nHeight);

src/wallet/test/wallet_tests.cpp

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ BOOST_FIXTURE_TEST_CASE(rescan, TestChain100Setup)
3838
auto chain = interfaces::MakeChain();
3939

4040
// Cap last block file size, and mine new block in a new block file.
41-
CBlockIndex* const nullBlock = nullptr;
41+
const CBlockIndex* const null_block = nullptr;
4242
CBlockIndex* oldTip = chainActive.Tip();
4343
GetBlockFileInfo(oldTip->GetBlockPos().nFile)->nSize = MAX_BLOCKFILE_SIZE;
4444
CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey()));
@@ -53,7 +53,9 @@ BOOST_FIXTURE_TEST_CASE(rescan, TestChain100Setup)
5353
AddKey(wallet, coinbaseKey);
5454
WalletRescanReserver reserver(&wallet);
5555
reserver.reserve();
56-
BOOST_CHECK_EQUAL(nullBlock, wallet.ScanForWalletTransactions(oldTip, nullptr, reserver));
56+
const CBlockIndex* stop_block;
57+
BOOST_CHECK_EQUAL(wallet.ScanForWalletTransactions(oldTip, nullptr, reserver, stop_block), CWallet::ScanResult::SUCCESS);
58+
BOOST_CHECK_EQUAL(stop_block, null_block);
5759
BOOST_CHECK_EQUAL(wallet.GetImmatureBalance(), 100 * COIN);
5860
}
5961

@@ -68,7 +70,9 @@ BOOST_FIXTURE_TEST_CASE(rescan, TestChain100Setup)
6870
AddKey(wallet, coinbaseKey);
6971
WalletRescanReserver reserver(&wallet);
7072
reserver.reserve();
71-
BOOST_CHECK_EQUAL(oldTip, wallet.ScanForWalletTransactions(oldTip, nullptr, reserver));
73+
const CBlockIndex* stop_block;
74+
BOOST_CHECK_EQUAL(wallet.ScanForWalletTransactions(oldTip, nullptr, reserver, stop_block), CWallet::ScanResult::FAILURE);
75+
BOOST_CHECK_EQUAL(oldTip, stop_block);
7276
BOOST_CHECK_EQUAL(wallet.GetImmatureBalance(), 50 * COIN);
7377
}
7478

@@ -286,7 +290,10 @@ class ListCoinsTestingSetup : public TestChain100Setup
286290
AddKey(*wallet, coinbaseKey);
287291
WalletRescanReserver reserver(wallet.get());
288292
reserver.reserve();
289-
wallet->ScanForWalletTransactions(chainActive.Genesis(), nullptr, reserver);
293+
const CBlockIndex* const null_block = nullptr;
294+
const CBlockIndex* stop_block;
295+
BOOST_CHECK_EQUAL(wallet->ScanForWalletTransactions(chainActive.Genesis(), nullptr, reserver, stop_block), CWallet::ScanResult::SUCCESS);
296+
BOOST_CHECK_EQUAL(stop_block, null_block);
290297
}
291298

292299
~ListCoinsTestingSetup()

src/wallet/wallet.cpp

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1613,8 +1613,9 @@ int64_t CWallet::RescanFromTime(int64_t startTime, const WalletRescanReserver& r
16131613
}
16141614

16151615
if (startBlock) {
1616-
const CBlockIndex* const failedBlock = ScanForWalletTransactions(startBlock, nullptr, reserver, update);
1617-
if (failedBlock) {
1616+
const CBlockIndex* failedBlock;
1617+
// TODO: this should take into account failure by ScanResult::USER_ABORT
1618+
if (ScanResult::FAILURE == ScanForWalletTransactions(startBlock, nullptr, reserver, failedBlock, update)) {
16181619
return failedBlock->GetBlockTimeMax() + TIMESTAMP_WINDOW + 1;
16191620
}
16201621
}
@@ -1626,18 +1627,20 @@ int64_t CWallet::RescanFromTime(int64_t startTime, const WalletRescanReserver& r
16261627
* from or to us. If fUpdate is true, found transactions that already
16271628
* exist in the wallet will be updated.
16281629
*
1629-
* Returns null if scan was successful. Otherwise, if a complete rescan was not
1630-
* possible (due to pruning or corruption), returns pointer to the most recent
1631-
* block that could not be scanned.
1630+
* @param[in] pindexStop if not a nullptr, the scan will stop at this block-index
1631+
* @param[out] failed_block if FAILURE is returned, will be set to the most
1632+
* recent block that could not be scanned, otherwise nullptr
16321633
*
1633-
* If pindexStop is not a nullptr, the scan will stop at the block-index
1634-
* defined by pindexStop
1634+
* @return ScanResult indicating success or failure of the scan. SUCCESS if
1635+
* scan was successful. FAILURE if a complete rescan was not possible (due to
1636+
* pruning or corruption). USER_ABORT if the rescan was aborted before it
1637+
* could complete.
16351638
*
1636-
* Caller needs to make sure pindexStop (and the optional pindexStart) are on
1639+
* @pre Caller needs to make sure pindexStop (and the optional pindexStart) are on
16371640
* the main chain after to the addition of any new keys you want to detect
16381641
* transactions for.
16391642
*/
1640-
const CBlockIndex* CWallet::ScanForWalletTransactions(const CBlockIndex* const pindexStart, const CBlockIndex* const pindexStop, const WalletRescanReserver& reserver, bool fUpdate)
1643+
CWallet::ScanResult CWallet::ScanForWalletTransactions(const CBlockIndex* const pindexStart, const CBlockIndex* const pindexStop, const WalletRescanReserver& reserver, const CBlockIndex*& failed_block, bool fUpdate)
16411644
{
16421645
int64_t nNow = GetTime();
16431646
const CChainParams& chainParams = Params();
@@ -1648,7 +1651,7 @@ const CBlockIndex* CWallet::ScanForWalletTransactions(const CBlockIndex* const p
16481651
}
16491652

16501653
const CBlockIndex* pindex = pindexStart;
1651-
const CBlockIndex* ret = nullptr;
1654+
failed_block = nullptr;
16521655

16531656
if (pindex) WalletLogPrintf("Rescan started from block %d...\n", pindex->nHeight);
16541657

@@ -1669,8 +1672,7 @@ const CBlockIndex* CWallet::ScanForWalletTransactions(const CBlockIndex* const p
16691672
}
16701673
}
16711674
double progress_current = progress_begin;
1672-
while (pindex && !fAbortRescan && !ShutdownRequested())
1673-
{
1675+
while (pindex && !fAbortRescan && !ShutdownRequested()) {
16741676
if (pindex->nHeight % 100 == 0 && progress_end - progress_begin > 0.0) {
16751677
ShowProgress(strprintf("%s " + _("Rescanning..."), GetDisplayName()), std::max(1, std::min(99, (int)((progress_current - progress_begin) / (progress_end - progress_begin) * 100))));
16761678
}
@@ -1686,14 +1688,14 @@ const CBlockIndex* CWallet::ScanForWalletTransactions(const CBlockIndex* const p
16861688
if (pindex && !chainActive.Contains(pindex)) {
16871689
// Abort scan if current block is no longer active, to prevent
16881690
// marking transactions as coming from the wrong block.
1689-
ret = pindex;
1691+
failed_block = pindex;
16901692
break;
16911693
}
16921694
for (size_t posInBlock = 0; posInBlock < block.vtx.size(); ++posInBlock) {
16931695
SyncTransaction(block.vtx[posInBlock], pindex, posInBlock, fUpdate);
16941696
}
16951697
} else {
1696-
ret = pindex;
1698+
failed_block = pindex;
16971699
}
16981700
if (pindex == pindexStop) {
16991701
break;
@@ -1709,14 +1711,20 @@ const CBlockIndex* CWallet::ScanForWalletTransactions(const CBlockIndex* const p
17091711
}
17101712
}
17111713
}
1714+
ShowProgress(strprintf("%s " + _("Rescanning..."), GetDisplayName()), 100); // hide progress dialog in GUI
17121715
if (pindex && fAbortRescan) {
17131716
WalletLogPrintf("Rescan aborted at block %d. Progress=%f\n", pindex->nHeight, progress_current);
1717+
return ScanResult::USER_ABORT;
17141718
} else if (pindex && ShutdownRequested()) {
17151719
WalletLogPrintf("Rescan interrupted by shutdown request at block %d. Progress=%f\n", pindex->nHeight, progress_current);
1720+
return ScanResult::USER_ABORT;
17161721
}
1717-
ShowProgress(strprintf("%s " + _("Rescanning..."), GetDisplayName()), 100); // hide progress dialog in GUI
17181722
}
1719-
return ret;
1723+
if (failed_block) {
1724+
return ScanResult::FAILURE;
1725+
} else {
1726+
return ScanResult::SUCCESS;
1727+
}
17201728
}
17211729

17221730
void CWallet::ReacceptWalletTransactions()
@@ -4166,11 +4174,11 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
41664174
nStart = GetTimeMillis();
41674175
{
41684176
WalletRescanReserver reserver(walletInstance.get());
4169-
if (!reserver.reserve()) {
4177+
const CBlockIndex* stop_block;
4178+
if (!reserver.reserve() || (ScanResult::SUCCESS != walletInstance->ScanForWalletTransactions(pindexRescan, nullptr, reserver, stop_block, true))) {
41704179
InitError(_("Failed to rescan the wallet during initialization"));
41714180
return nullptr;
41724181
}
4173-
walletInstance->ScanForWalletTransactions(pindexRescan, nullptr, reserver, true);
41744182
}
41754183
walletInstance->WalletLogPrintf("Rescan completed in %15dms\n", GetTimeMillis() - nStart);
41764184
walletInstance->ChainStateFlushed(chainActive.GetLocator());

src/wallet/wallet.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -896,7 +896,13 @@ class CWallet final : public CCryptoKeyStore, public CValidationInterface
896896
void BlockConnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex *pindex, const std::vector<CTransactionRef>& vtxConflicted) override;
897897
void BlockDisconnected(const std::shared_ptr<const CBlock>& pblock) override;
898898
int64_t RescanFromTime(int64_t startTime, const WalletRescanReserver& reserver, bool update);
899-
const CBlockIndex* ScanForWalletTransactions(const CBlockIndex* const pindexStart, const CBlockIndex* const pindexStop, const WalletRescanReserver& reserver, bool fUpdate = false);
899+
900+
enum class ScanResult {
901+
SUCCESS,
902+
FAILURE,
903+
USER_ABORT
904+
};
905+
ScanResult ScanForWalletTransactions(const CBlockIndex* const pindexStart, const CBlockIndex* const pindexStop, const WalletRescanReserver& reserver, const CBlockIndex*& failed_block, bool fUpdate = false);
900906
void TransactionRemovedFromMempool(const CTransactionRef &ptx) override;
901907
void ReacceptWalletTransactions();
902908
void ResendWalletTransactions(int64_t nBestBlockTime, CConnman* connman) override EXCLUSIVE_LOCKS_REQUIRED(cs_main);

0 commit comments

Comments
 (0)