Skip to content

Commit bd3b036

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

File tree

5 files changed

+32
-24
lines changed

5 files changed

+32
-24
lines changed

src/qt/test/wallettests.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -147,11 +147,12 @@ void TestGUI()
147147
WalletRescanReserver reserver(wallet.get());
148148
reserver.reserve();
149149
const CBlockIndex* const null_block = nullptr;
150-
const CBlockIndex* stop_block;
150+
const CBlockIndex *stop_block, *failed_block;
151151
QCOMPARE(
152-
wallet->ScanForWalletTransactions(chainActive.Genesis(), nullptr, reserver, stop_block, true /* fUpdate */),
152+
wallet->ScanForWalletTransactions(chainActive.Genesis(), nullptr, reserver, failed_block, stop_block, true /* fUpdate */),
153153
CWallet::ScanResult::SUCCESS);
154-
QCOMPARE(stop_block, null_block);
154+
QCOMPARE(stop_block, chainActive.Tip());
155+
QCOMPARE(failed_block, null_block);
155156
}
156157
wallet->SetBroadcastTransactions(true);
157158

src/wallet/rpcwallet.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3332,13 +3332,12 @@ UniValue rescanblockchain(const JSONRPCRequest& request)
33323332
}
33333333
}
33343334

3335-
const CBlockIndex* stopBlock;
3335+
const CBlockIndex *failed_block, *stopBlock;
33363336
CWallet::ScanResult result =
3337-
pwallet->ScanForWalletTransactions(pindexStart, pindexStop, reserver, stopBlock, true);
3337+
pwallet->ScanForWalletTransactions(pindexStart, pindexStop, reserver, failed_block, stopBlock, true);
33383338
switch (result) {
33393339
case CWallet::ScanResult::SUCCESS:
3340-
stopBlock = pindexStop ? pindexStop : pChainTip;
3341-
break;
3340+
break; // stopBlock set by ScanForWalletTransactions
33423341
case CWallet::ScanResult::FAILURE:
33433342
throw JSONRPCError(RPC_MISC_ERROR, "Rescan failed. Potentially corrupted data files.");
33443343
case CWallet::ScanResult::USER_ABORT:

src/wallet/test/wallet_tests.cpp

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,10 @@ BOOST_FIXTURE_TEST_CASE(rescan, TestChain100Setup)
5353
AddKey(wallet, coinbaseKey);
5454
WalletRescanReserver reserver(&wallet);
5555
reserver.reserve();
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);
56+
const CBlockIndex *stop_block, *failed_block;
57+
BOOST_CHECK_EQUAL(wallet.ScanForWalletTransactions(oldTip, nullptr, reserver, failed_block, stop_block), CWallet::ScanResult::SUCCESS);
58+
BOOST_CHECK_EQUAL(failed_block, null_block);
59+
BOOST_CHECK_EQUAL(stop_block, newTip);
5960
BOOST_CHECK_EQUAL(wallet.GetImmatureBalance(), 100 * COIN);
6061
}
6162

@@ -70,9 +71,10 @@ BOOST_FIXTURE_TEST_CASE(rescan, TestChain100Setup)
7071
AddKey(wallet, coinbaseKey);
7172
WalletRescanReserver reserver(&wallet);
7273
reserver.reserve();
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);
74+
const CBlockIndex *stop_block, *failed_block;
75+
BOOST_CHECK_EQUAL(wallet.ScanForWalletTransactions(oldTip, nullptr, reserver, failed_block, stop_block), CWallet::ScanResult::FAILURE);
76+
BOOST_CHECK_EQUAL(failed_block, oldTip);
77+
BOOST_CHECK_EQUAL(stop_block, newTip);
7678
BOOST_CHECK_EQUAL(wallet.GetImmatureBalance(), 50 * COIN);
7779
}
7880

@@ -291,9 +293,10 @@ class ListCoinsTestingSetup : public TestChain100Setup
291293
WalletRescanReserver reserver(wallet.get());
292294
reserver.reserve();
293295
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);
296+
const CBlockIndex *stop_block, *failed_block;
297+
BOOST_CHECK_EQUAL(wallet->ScanForWalletTransactions(chainActive.Genesis(), nullptr, reserver, failed_block, stop_block), CWallet::ScanResult::SUCCESS);
298+
BOOST_CHECK_EQUAL(stop_block, chainActive.Tip());
299+
BOOST_CHECK_EQUAL(failed_block, null_block);
297300
}
298301

299302
~ListCoinsTestingSetup()

src/wallet/wallet.cpp

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

16151615
if (startBlock) {
1616-
const CBlockIndex* failedBlock;
1616+
const CBlockIndex *failedBlock, *stop_block;
16171617
// TODO: this should take into account failure by ScanResult::USER_ABORT
1618-
if (ScanResult::FAILURE == ScanForWalletTransactions(startBlock, nullptr, reserver, failedBlock, update)) {
1618+
if (ScanResult::FAILURE == ScanForWalletTransactions(startBlock, nullptr, reserver, failedBlock, stop_block, update)) {
16191619
return failedBlock->GetBlockTimeMax() + TIMESTAMP_WINDOW + 1;
16201620
}
16211621
}
@@ -1628,8 +1628,10 @@ int64_t CWallet::RescanFromTime(int64_t startTime, const WalletRescanReserver& r
16281628
* exist in the wallet will be updated.
16291629
*
16301630
* @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
1631+
* @param[out] failed_block if FAILURE is returned, the most recent block
1632+
* that could not be scanned, otherwise nullptr
1633+
* @param[out] stop_block the most recent block that could be scanned,
1634+
* otherwise nullptr if no block could be scanned
16331635
*
16341636
* @return ScanResult indicating success or failure of the scan. SUCCESS if
16351637
* 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
16401642
* the main chain after to the addition of any new keys you want to detect
16411643
* transactions for.
16421644
*/
1643-
CWallet::ScanResult CWallet::ScanForWalletTransactions(const CBlockIndex* const pindexStart, const CBlockIndex* const pindexStop, const WalletRescanReserver& reserver, const CBlockIndex*& failed_block, bool fUpdate)
1645+
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)
16441646
{
16451647
int64_t nNow = GetTime();
16461648
const CChainParams& chainParams = Params();
@@ -1694,7 +1696,10 @@ CWallet::ScanResult CWallet::ScanForWalletTransactions(const CBlockIndex* const
16941696
for (size_t posInBlock = 0; posInBlock < block.vtx.size(); ++posInBlock) {
16951697
SyncTransaction(block.vtx[posInBlock], pindex, posInBlock, fUpdate);
16961698
}
1699+
// scan succeeded, record block as most recent successfully scanned
1700+
stop_block = pindex;
16971701
} else {
1702+
// could not scan block, keep scanning but record this block as the most recent failure
16981703
failed_block = pindex;
16991704
}
17001705
if (pindex == pindexStop) {
@@ -4174,8 +4179,8 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
41744179
nStart = GetTimeMillis();
41754180
{
41764181
WalletRescanReserver reserver(walletInstance.get());
4177-
const CBlockIndex* stop_block;
4178-
if (!reserver.reserve() || (ScanResult::SUCCESS != walletInstance->ScanForWalletTransactions(pindexRescan, nullptr, reserver, stop_block, true))) {
4182+
const CBlockIndex *stop_block, *failed_block;
4183+
if (!reserver.reserve() || (ScanResult::SUCCESS != walletInstance->ScanForWalletTransactions(pindexRescan, nullptr, reserver, failed_block, stop_block, true))) {
41794184
InitError(_("Failed to rescan the wallet during initialization"));
41804185
return nullptr;
41814186
}

src/wallet/wallet.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -902,7 +902,7 @@ class CWallet final : public CCryptoKeyStore, public CValidationInterface
902902
FAILURE,
903903
USER_ABORT
904904
};
905-
ScanResult ScanForWalletTransactions(const CBlockIndex* const pindexStart, const CBlockIndex* const pindexStop, const WalletRescanReserver& reserver, const CBlockIndex*& failed_block, bool fUpdate = false);
905+
ScanResult ScanForWalletTransactions(const CBlockIndex* const pindexStart, const CBlockIndex* const pindexStop, const WalletRescanReserver& reserver, const CBlockIndex*& failed_block, const CBlockIndex*& stop_block, bool fUpdate = false);
906906
void TransactionRemovedFromMempool(const CTransactionRef &ptx) override;
907907
void ReacceptWalletTransactions();
908908
void ResendWalletTransactions(int64_t nBestBlockTime, CConnman* connman) override EXCLUSIVE_LOCKS_REQUIRED(cs_main);

0 commit comments

Comments
 (0)