Skip to content

Commit bef02fb

Browse files
committed
Merge #10412: Improve wallet rescan API
deaf48b Handle TIMESTAMP_WINDOW within CWallet::RescanFromTime (Russell Yanofsky) 5b2be2b Make CWallet::RescanFromTime comment less ambiguous (Russell Yanofsky) 9bb66ab Add RescanFromTime method and use from rpcdump (Russell Yanofsky) ccf84bb Move birthday optimization out of ScanForWalletTransactions (Russell Yanofsky) Tree-SHA512: cd38433b8f5c5e44ecfba830a6a26bd9a9d0f4a22ae42bce17773d1a6fb25e1ee4289484996dad2d7acfa03059917ff062459f25030a761da7083ba5fbc87bc9
2 parents eee398f + deaf48b commit bef02fb

File tree

3 files changed

+51
-22
lines changed

3 files changed

+51
-22
lines changed

src/wallet/rpcdump.cpp

Lines changed: 9 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ UniValue importprivkey(const JSONRPCRequest& request)
148148
pwallet->UpdateTimeFirstKey(1);
149149

150150
if (fRescan) {
151-
pwallet->ScanForWalletTransactions(chainActive.Genesis(), true);
151+
pwallet->RescanFromTime(TIMESTAMP_MIN, true /* update */);
152152
}
153153
}
154154

@@ -278,7 +278,7 @@ UniValue importaddress(const JSONRPCRequest& request)
278278

279279
if (fRescan)
280280
{
281-
pwallet->ScanForWalletTransactions(chainActive.Genesis(), true);
281+
pwallet->RescanFromTime(TIMESTAMP_MIN, true /* update */);
282282
pwallet->ReacceptWalletTransactions();
283283
}
284284

@@ -436,7 +436,7 @@ UniValue importpubkey(const JSONRPCRequest& request)
436436

437437
if (fRescan)
438438
{
439-
pwallet->ScanForWalletTransactions(chainActive.Genesis(), true);
439+
pwallet->RescanFromTime(TIMESTAMP_MIN, true /* update */);
440440
pwallet->ReacceptWalletTransactions();
441441
}
442442

@@ -536,11 +536,7 @@ UniValue importwallet(const JSONRPCRequest& request)
536536
file.close();
537537
pwallet->ShowProgress("", 100); // hide progress dialog in GUI
538538
pwallet->UpdateTimeFirstKey(nTimeBegin);
539-
540-
CBlockIndex *pindex = chainActive.FindEarliestAtLeast(nTimeBegin - TIMESTAMP_WINDOW);
541-
542-
LogPrintf("Rescanning last %i blocks\n", pindex ? chainActive.Height() - pindex->nHeight + 1 : 0);
543-
pwallet->ScanForWalletTransactions(pindex);
539+
pwallet->RescanFromTime(nTimeBegin, false /* update */);
544540
pwallet->MarkDirty();
545541

546542
if (!fGood)
@@ -1126,14 +1122,10 @@ UniValue importmulti(const JSONRPCRequest& mainRequest)
11261122
}
11271123

11281124
if (fRescan && fRunScan && requests.size()) {
1129-
CBlockIndex* pindex = nLowestTimestamp > minimumTimestamp ? chainActive.FindEarliestAtLeast(std::max<int64_t>(nLowestTimestamp - TIMESTAMP_WINDOW, 0)) : chainActive.Genesis();
1130-
CBlockIndex* scanFailed = nullptr;
1131-
if (pindex) {
1132-
scanFailed = pwallet->ScanForWalletTransactions(pindex, true);
1133-
pwallet->ReacceptWalletTransactions();
1134-
}
1125+
int64_t scannedTime = pwallet->RescanFromTime(nLowestTimestamp, true /* update */);
1126+
pwallet->ReacceptWalletTransactions();
11351127

1136-
if (scanFailed) {
1128+
if (scannedTime > nLowestTimestamp) {
11371129
std::vector<UniValue> results = response.getValues();
11381130
response.clear();
11391131
response.setArray();
@@ -1143,7 +1135,7 @@ UniValue importmulti(const JSONRPCRequest& mainRequest)
11431135
// range, or if the import result already has an error set, let
11441136
// the result stand unmodified. Otherwise replace the result
11451137
// with an error message.
1146-
if (GetImportTimestamp(request, now) - TIMESTAMP_WINDOW > scanFailed->GetBlockTimeMax() || results.at(i).exists("error")) {
1138+
if (scannedTime <= GetImportTimestamp(request, now) || results.at(i).exists("error")) {
11471139
response.push_back(results.at(i));
11481140
} else {
11491141
UniValue result = UniValue(UniValue::VOBJ);
@@ -1159,7 +1151,7 @@ UniValue importmulti(const JSONRPCRequest& mainRequest)
11591151
"caused by pruning or data corruption (see bitcoind log for details) and could "
11601152
"be dealt with by downloading and rescanning the relevant blocks (see -reindex "
11611153
"and -rescan options).",
1162-
GetImportTimestamp(request, now), scanFailed->GetBlockTimeMax(), TIMESTAMP_WINDOW)));
1154+
GetImportTimestamp(request, now), scannedTime - TIMESTAMP_WINDOW - 1, TIMESTAMP_WINDOW)));
11631155
response.push_back(std::move(result));
11641156
}
11651157
++i;

src/wallet/wallet.cpp

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,10 @@ bool CWallet::LoadCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigne
220220
return CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret);
221221
}
222222

223+
/**
224+
* Update wallet first key creation time. This should be called whenever keys
225+
* are added to the wallet, with the oldest key creation time.
226+
*/
223227
void CWallet::UpdateTimeFirstKey(int64_t nCreateTime)
224228
{
225229
AssertLockHeld(cs_wallet);
@@ -1467,6 +1471,34 @@ void CWalletTx::GetAmounts(std::list<COutputEntry>& listReceived,
14671471

14681472
}
14691473

1474+
/**
1475+
* Scan active chain for relevant transactions after importing keys. This should
1476+
* be called whenever new keys are added to the wallet, with the oldest key
1477+
* creation time.
1478+
*
1479+
* @return Earliest timestamp that could be successfully scanned from. Timestamp
1480+
* returned will be higher than startTime if relevant blocks could not be read.
1481+
*/
1482+
int64_t CWallet::RescanFromTime(int64_t startTime, bool update)
1483+
{
1484+
AssertLockHeld(cs_main);
1485+
AssertLockHeld(cs_wallet);
1486+
1487+
// Find starting block. May be null if nCreateTime is greater than the
1488+
// highest blockchain timestamp, in which case there is nothing that needs
1489+
// to be scanned.
1490+
CBlockIndex* const startBlock = chainActive.FindEarliestAtLeast(startTime - TIMESTAMP_WINDOW);
1491+
LogPrintf("%s: Rescanning last %i blocks\n", __func__, startBlock ? chainActive.Height() - startBlock->nHeight + 1 : 0);
1492+
1493+
if (startBlock) {
1494+
const CBlockIndex* const failedBlock = ScanForWalletTransactions(startBlock, update);
1495+
if (failedBlock) {
1496+
return failedBlock->GetBlockTimeMax() + TIMESTAMP_WINDOW + 1;
1497+
}
1498+
}
1499+
return startTime;
1500+
}
1501+
14701502
/**
14711503
* Scan the block chain (starting in pindexStart) for transactions
14721504
* from or to us. If fUpdate is true, found transactions that already
@@ -1488,11 +1520,6 @@ CBlockIndex* CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool f
14881520
fAbortRescan = false;
14891521
fScanningWallet = true;
14901522

1491-
// no need to read and scan block, if block was created before
1492-
// our wallet birthday (as adjusted for block time variability)
1493-
while (pindex && nTimeFirstKey && (pindex->GetBlockTime() < (nTimeFirstKey - TIMESTAMP_WINDOW)))
1494-
pindex = chainActive.Next(pindex);
1495-
14961523
ShowProgress(_("Rescanning..."), 0); // show rescan progress in GUI as dialog or on splashscreen, if -rescan on startup
14971524
double dProgressStart = GuessVerificationProgress(chainParams.TxData(), pindex);
14981525
double dProgressTip = GuessVerificationProgress(chainParams.TxData(), chainActive.Tip());
@@ -3881,6 +3908,13 @@ CWallet* CWallet::CreateWalletFromFile(const std::string walletFile)
38813908

38823909
uiInterface.InitMessage(_("Rescanning..."));
38833910
LogPrintf("Rescanning last %i blocks (from block %i)...\n", chainActive.Height() - pindexRescan->nHeight, pindexRescan->nHeight);
3911+
3912+
// No need to read and scan block if block was created before
3913+
// our wallet birthday (as adjusted for block time variability)
3914+
while (pindexRescan && walletInstance->nTimeFirstKey && (pindexRescan->GetBlockTime() < (walletInstance->nTimeFirstKey - TIMESTAMP_WINDOW))) {
3915+
pindexRescan = chainActive.Next(pindexRescan);
3916+
}
3917+
38843918
nStart = GetTimeMillis();
38853919
walletInstance->ScanForWalletTransactions(pindexRescan, true);
38863920
LogPrintf(" rescan %15dms\n", GetTimeMillis() - nStart);

src/wallet/wallet.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ static const bool DEFAULT_USE_HD_WALLET = true;
6868

6969
extern const char * DEFAULT_WALLET_DAT;
7070

71+
static const int64_t TIMESTAMP_MIN = 0;
72+
7173
class CBlockIndex;
7274
class CCoinControl;
7375
class COutput;
@@ -919,6 +921,7 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface
919921
void BlockConnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex *pindex, const std::vector<CTransactionRef>& vtxConflicted) override;
920922
void BlockDisconnected(const std::shared_ptr<const CBlock>& pblock) override;
921923
bool AddToWalletIfInvolvingMe(const CTransactionRef& tx, const CBlockIndex* pIndex, int posInBlock, bool fUpdate);
924+
int64_t RescanFromTime(int64_t startTime, bool update);
922925
CBlockIndex* ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate = false);
923926
void ReacceptWalletTransactions();
924927
void ResendWalletTransactions(int64_t nBestBlockTime, CConnman* connman) override;

0 commit comments

Comments
 (0)