Skip to content

Commit bc356b4

Browse files
committed
Make sure WalletRescanReserver has successfully reserved the rescan
1 parent dbf8556 commit bc356b4

File tree

6 files changed

+44
-21
lines changed

6 files changed

+44
-21
lines changed

src/qt/test/wallettests.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,9 @@ void TestGUI()
169169
}
170170
{
171171
LOCK(cs_main);
172-
wallet.ScanForWalletTransactions(chainActive.Genesis(), nullptr, true);
172+
WalletRescanReserver reserver(&wallet);
173+
reserver.reserve();
174+
wallet.ScanForWalletTransactions(chainActive.Genesis(), nullptr, reserver, true);
173175
}
174176
wallet.SetBroadcastTransactions(true);
175177

src/wallet/rpcdump.cpp

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ UniValue importprivkey(const JSONRPCRequest& request)
101101
);
102102

103103

104+
WalletRescanReserver reserver(pwallet);
104105
bool fRescan = true;
105106
{
106107
LOCK2(cs_main, pwallet->cs_wallet);
@@ -119,6 +120,10 @@ UniValue importprivkey(const JSONRPCRequest& request)
119120
if (fRescan && fPruneMode)
120121
throw JSONRPCError(RPC_WALLET_ERROR, "Rescan is disabled in pruned mode");
121122

123+
if (fRescan && !reserver.reserve()) {
124+
throw JSONRPCError(RPC_WALLET_ERROR, "Wallet is currently rescanning. Abort existing rescan or wait.");
125+
}
126+
122127
CBitcoinSecret vchSecret;
123128
bool fGood = vchSecret.SetString(strSecret);
124129

@@ -153,7 +158,7 @@ UniValue importprivkey(const JSONRPCRequest& request)
153158
}
154159
}
155160
if (fRescan) {
156-
pwallet->RescanFromTime(TIMESTAMP_MIN, true /* update */);
161+
pwallet->RescanFromTime(TIMESTAMP_MIN, reserver, true /* update */);
157162
}
158163

159164
return NullUniValue;
@@ -290,7 +295,7 @@ UniValue importaddress(const JSONRPCRequest& request)
290295
}
291296
if (fRescan)
292297
{
293-
pwallet->RescanFromTime(TIMESTAMP_MIN, true /* update */);
298+
pwallet->RescanFromTime(TIMESTAMP_MIN, reserver, true /* update */);
294299
pwallet->ReacceptWalletTransactions();
295300
}
296301

@@ -457,7 +462,7 @@ UniValue importpubkey(const JSONRPCRequest& request)
457462
}
458463
if (fRescan)
459464
{
460-
pwallet->RescanFromTime(TIMESTAMP_MIN, true /* update */);
465+
pwallet->RescanFromTime(TIMESTAMP_MIN, reserver, true /* update */);
461466
pwallet->ReacceptWalletTransactions();
462467
}
463468

@@ -581,7 +586,7 @@ UniValue importwallet(const JSONRPCRequest& request)
581586
pwallet->ShowProgress("", 100); // hide progress dialog in GUI
582587
pwallet->UpdateTimeFirstKey(nTimeBegin);
583588
}
584-
pwallet->RescanFromTime(nTimeBegin, false /* update */);
589+
pwallet->RescanFromTime(nTimeBegin, reserver, false /* update */);
585590
pwallet->MarkDirty();
586591

587592
if (!fGood)
@@ -1201,7 +1206,7 @@ UniValue importmulti(const JSONRPCRequest& mainRequest)
12011206
}
12021207
}
12031208
if (fRescan && fRunScan && requests.size()) {
1204-
int64_t scannedTime = pwallet->RescanFromTime(nLowestTimestamp, true /* update */);
1209+
int64_t scannedTime = pwallet->RescanFromTime(nLowestTimestamp, reserver, true /* update */);
12051210
pwallet->ReacceptWalletTransactions();
12061211

12071212
if (scannedTime > nLowestTimestamp) {

src/wallet/rpcwallet.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3441,7 +3441,7 @@ UniValue rescanblockchain(const JSONRPCRequest& request)
34413441
}
34423442
}
34433443

3444-
CBlockIndex *stopBlock = pwallet->ScanForWalletTransactions(pindexStart, pindexStop, true);
3444+
CBlockIndex *stopBlock = pwallet->ScanForWalletTransactions(pindexStart, pindexStop, reserver, true);
34453445
if (!stopBlock) {
34463446
if (pwallet->IsAbortingRescan()) {
34473447
throw JSONRPCError(RPC_MISC_ERROR, "Rescan aborted.");

src/wallet/test/wallet_tests.cpp

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -384,7 +384,9 @@ BOOST_FIXTURE_TEST_CASE(rescan, TestChain100Setup)
384384
{
385385
CWallet wallet;
386386
AddKey(wallet, coinbaseKey);
387-
BOOST_CHECK_EQUAL(nullBlock, wallet.ScanForWalletTransactions(oldTip, nullptr));
387+
WalletRescanReserver reserver(&wallet);
388+
reserver.reserve();
389+
BOOST_CHECK_EQUAL(nullBlock, wallet.ScanForWalletTransactions(oldTip, nullptr, reserver));
388390
BOOST_CHECK_EQUAL(wallet.GetImmatureBalance(), 100 * COIN);
389391
}
390392

@@ -397,7 +399,9 @@ BOOST_FIXTURE_TEST_CASE(rescan, TestChain100Setup)
397399
{
398400
CWallet wallet;
399401
AddKey(wallet, coinbaseKey);
400-
BOOST_CHECK_EQUAL(oldTip, wallet.ScanForWalletTransactions(oldTip, nullptr));
402+
WalletRescanReserver reserver(&wallet);
403+
reserver.reserve();
404+
BOOST_CHECK_EQUAL(oldTip, wallet.ScanForWalletTransactions(oldTip, nullptr, reserver));
401405
BOOST_CHECK_EQUAL(wallet.GetImmatureBalance(), 50 * COIN);
402406
}
403407

@@ -608,7 +612,9 @@ class ListCoinsTestingSetup : public TestChain100Setup
608612
bool firstRun;
609613
wallet->LoadWallet(firstRun);
610614
AddKey(*wallet, coinbaseKey);
611-
wallet->ScanForWalletTransactions(chainActive.Genesis(), nullptr);
615+
WalletRescanReserver reserver(wallet.get());
616+
reserver.reserve();
617+
wallet->ScanForWalletTransactions(chainActive.Genesis(), nullptr, reserver);
612618
}
613619

614620
~ListCoinsTestingSetup()

src/wallet/wallet.cpp

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1612,7 +1612,7 @@ void CWalletTx::GetAmounts(std::list<COutputEntry>& listReceived,
16121612
* @return Earliest timestamp that could be successfully scanned from. Timestamp
16131613
* returned will be higher than startTime if relevant blocks could not be read.
16141614
*/
1615-
int64_t CWallet::RescanFromTime(int64_t startTime, bool update)
1615+
int64_t CWallet::RescanFromTime(int64_t startTime, const WalletRescanReserver& reserver, bool update)
16161616
{
16171617
// Find starting block. May be null if nCreateTime is greater than the
16181618
// highest blockchain timestamp, in which case there is nothing that needs
@@ -1625,7 +1625,7 @@ int64_t CWallet::RescanFromTime(int64_t startTime, bool update)
16251625
}
16261626

16271627
if (startBlock) {
1628-
const CBlockIndex* const failedBlock = ScanForWalletTransactions(startBlock, nullptr, update);
1628+
const CBlockIndex* const failedBlock = ScanForWalletTransactions(startBlock, nullptr, reserver, update);
16291629
if (failedBlock) {
16301630
return failedBlock->GetBlockTimeMax() + TIMESTAMP_WINDOW + 1;
16311631
}
@@ -1649,11 +1649,12 @@ int64_t CWallet::RescanFromTime(int64_t startTime, bool update)
16491649
* the main chain after to the addition of any new keys you want to detect
16501650
* transactions for.
16511651
*/
1652-
CBlockIndex* CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, CBlockIndex* pindexStop, bool fUpdate)
1652+
CBlockIndex* CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, CBlockIndex* pindexStop, const WalletRescanReserver &reserver, bool fUpdate)
16531653
{
16541654
int64_t nNow = GetTime();
16551655
const CChainParams& chainParams = Params();
16561656

1657+
assert(reserver.isReserved());
16571658
if (pindexStop) {
16581659
assert(pindexStop->nHeight >= pindexStart->nHeight);
16591660
}
@@ -1662,8 +1663,6 @@ CBlockIndex* CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, CBlock
16621663
CBlockIndex* ret = nullptr;
16631664
{
16641665
fAbortRescan = false;
1665-
fScanningWallet = true;
1666-
16671666
ShowProgress(_("Rescanning..."), 0); // show rescan progress in GUI as dialog or on splashscreen, if -rescan on startup
16681667
CBlockIndex* tip = nullptr;
16691668
double dProgressStart;
@@ -1727,8 +1726,6 @@ CBlockIndex* CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, CBlock
17271726
LogPrintf("Rescan aborted at block %d. Progress=%f\n", pindex->nHeight, GuessVerificationProgress(chainParams.TxData(), pindex));
17281727
}
17291728
ShowProgress(_("Rescanning..."), 100); // hide progress dialog in GUI
1730-
1731-
fScanningWallet = false;
17321729
}
17331730
return ret;
17341731
}
@@ -4039,7 +4036,14 @@ CWallet* CWallet::CreateWalletFromFile(const std::string walletFile)
40394036
}
40404037

40414038
nStart = GetTimeMillis();
4042-
walletInstance->ScanForWalletTransactions(pindexRescan, nullptr, true);
4039+
{
4040+
WalletRescanReserver reserver(walletInstance);
4041+
if (!reserver.reserve()) {
4042+
InitError(_("Failed to rescan the wallet during initialization"));
4043+
return nullptr;
4044+
}
4045+
walletInstance->ScanForWalletTransactions(pindexRescan, nullptr, reserver, true);
4046+
}
40434047
LogPrintf(" rescan %15dms\n", GetTimeMillis() - nStart);
40444048
walletInstance->SetBestChain(chainActive.GetLocator());
40454049
walletInstance->dbw->IncrementUpdateCounter();

src/wallet/wallet.h

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -659,6 +659,7 @@ class CAccountingEntry
659659
};
660660

661661

662+
class WalletRescanReserver; //forward declarations for ScanForWalletTransactions/RescanFromTime
662663
/**
663664
* A CWallet is an extension of a keystore, which also maintains a set of transactions and balances,
664665
* and provides the ability to create new transactions.
@@ -668,7 +669,7 @@ class CWallet final : public CCryptoKeyStore, public CValidationInterface
668669
private:
669670
static std::atomic<bool> fFlushScheduled;
670671
std::atomic<bool> fAbortRescan;
671-
std::atomic<bool> fScanningWallet;
672+
std::atomic<bool> fScanningWallet; //controlled by WalletRescanReserver
672673
std::mutex mutexScanning;
673674
friend class WalletRescanReserver;
674675

@@ -948,8 +949,8 @@ class CWallet final : public CCryptoKeyStore, public CValidationInterface
948949
void BlockConnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex *pindex, const std::vector<CTransactionRef>& vtxConflicted) override;
949950
void BlockDisconnected(const std::shared_ptr<const CBlock>& pblock) override;
950951
bool AddToWalletIfInvolvingMe(const CTransactionRef& tx, const CBlockIndex* pIndex, int posInBlock, bool fUpdate);
951-
int64_t RescanFromTime(int64_t startTime, bool update);
952-
CBlockIndex* ScanForWalletTransactions(CBlockIndex* pindexStart, CBlockIndex* pindexStop, bool fUpdate = false);
952+
int64_t RescanFromTime(int64_t startTime, const WalletRescanReserver& reserver, bool update);
953+
CBlockIndex* ScanForWalletTransactions(CBlockIndex* pindexStart, CBlockIndex* pindexStop, const WalletRescanReserver& reserver, bool fUpdate = false);
953954
void TransactionRemovedFromMempool(const CTransactionRef &ptx) override;
954955
void ReacceptWalletTransactions();
955956
void ResendWalletTransactions(int64_t nBestBlockTime, CConnman* connman) override;
@@ -1287,6 +1288,11 @@ class WalletRescanReserver
12871288
return true;
12881289
}
12891290

1291+
bool isReserved() const
1292+
{
1293+
return (m_could_reserve && m_wallet->fScanningWallet);
1294+
}
1295+
12901296
~WalletRescanReserver()
12911297
{
12921298
std::lock_guard<std::mutex> lock(m_wallet->mutexScanning);

0 commit comments

Comments
 (0)