Skip to content

Commit e76a392

Browse files
committed
Merge #10410: Fix importwallet edge case rescan bug
2a8e35a Fix importwallet edge case rescan bug (Russell Yanofsky) Tree-SHA512: 59522c962290f9ef64436349d11183dd1fd829e515d1f5ec802b63dd813d04303e28d4f3ba38df77a6c151ee4c14f3ca5d3d82204c57456ac94054de62ae4bc7
2 parents e477516 + 2a8e35a commit e76a392

File tree

2 files changed

+65
-6
lines changed

2 files changed

+65
-6
lines changed

src/wallet/rpcdump.cpp

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -536,14 +536,11 @@ UniValue importwallet(const JSONRPCRequest& request)
536536
}
537537
file.close();
538538
pwallet->ShowProgress("", 100); // hide progress dialog in GUI
539-
540-
CBlockIndex *pindex = chainActive.Tip();
541-
while (pindex && pindex->pprev && pindex->GetBlockTime() > nTimeBegin - TIMESTAMP_WINDOW)
542-
pindex = pindex->pprev;
543-
544539
pwallet->UpdateTimeFirstKey(nTimeBegin);
545540

546-
LogPrintf("Rescanning last %i blocks\n", chainActive.Height() - pindex->nHeight + 1);
541+
CBlockIndex *pindex = chainActive.FindEarliestAtLeast(nTimeBegin - TIMESTAMP_WINDOW);
542+
543+
LogPrintf("Rescanning last %i blocks\n", pindex ? chainActive.Height() - pindex->nHeight + 1 : 0);
547544
pwallet->ScanForWalletTransactions(pindex);
548545
pwallet->MarkDirty();
549546

src/wallet/test/wallet_tests.cpp

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
#include <univalue.h>
2020

2121
extern UniValue importmulti(const JSONRPCRequest& request);
22+
extern UniValue dumpwallet(const JSONRPCRequest& request);
23+
extern UniValue importwallet(const JSONRPCRequest& request);
2224

2325
// how many times to run all the tests to have a chance to catch errors that only show up with particular random shuffles
2426
#define RUN_TESTS 100
@@ -437,6 +439,66 @@ BOOST_FIXTURE_TEST_CASE(rescan, TestChain100Setup)
437439
}
438440
}
439441

442+
// Verify importwallet RPC starts rescan at earliest block with timestamp
443+
// greater or equal than key birthday. Previously there was a bug where
444+
// importwallet RPC would start the scan at the latest block with timestamp less
445+
// than or equal to key birthday.
446+
BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup)
447+
{
448+
CWallet *pwalletMainBackup = ::pwalletMain;
449+
LOCK(cs_main);
450+
451+
// Create two blocks with same timestamp to verify that importwallet rescan
452+
// will pick up both blocks, not just the first.
453+
const int64_t BLOCK_TIME = chainActive.Tip()->GetBlockTimeMax() + 5;
454+
SetMockTime(BLOCK_TIME);
455+
coinbaseTxns.emplace_back(*CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())).vtx[0]);
456+
coinbaseTxns.emplace_back(*CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())).vtx[0]);
457+
458+
// Set key birthday to block time increased by the timestamp window, so
459+
// rescan will start at the block time.
460+
const int64_t KEY_TIME = BLOCK_TIME + TIMESTAMP_WINDOW;
461+
SetMockTime(KEY_TIME);
462+
coinbaseTxns.emplace_back(*CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())).vtx[0]);
463+
464+
// Import key into wallet and call dumpwallet to create backup file.
465+
{
466+
CWallet wallet;
467+
LOCK(wallet.cs_wallet);
468+
wallet.mapKeyMetadata[coinbaseKey.GetPubKey().GetID()].nCreateTime = KEY_TIME;
469+
wallet.AddKeyPubKey(coinbaseKey, coinbaseKey.GetPubKey());
470+
471+
JSONRPCRequest request;
472+
request.params.setArray();
473+
request.params.push_back("wallet.backup");
474+
::pwalletMain = &wallet;
475+
::dumpwallet(request);
476+
}
477+
478+
// Call importwallet RPC and verify all blocks with timestamps >= BLOCK_TIME
479+
// were scanned, and no prior blocks were scanned.
480+
{
481+
CWallet wallet;
482+
483+
JSONRPCRequest request;
484+
request.params.setArray();
485+
request.params.push_back("wallet.backup");
486+
::pwalletMain = &wallet;
487+
::importwallet(request);
488+
489+
BOOST_CHECK_EQUAL(wallet.mapWallet.size(), 3);
490+
BOOST_CHECK_EQUAL(coinbaseTxns.size(), 103);
491+
for (size_t i = 0; i < coinbaseTxns.size(); ++i) {
492+
bool found = wallet.GetWalletTx(coinbaseTxns[i].GetHash());
493+
bool expected = i >= 100;
494+
BOOST_CHECK_EQUAL(found, expected);
495+
}
496+
}
497+
498+
SetMockTime(0);
499+
::pwalletMain = pwalletMainBackup;
500+
}
501+
440502
// Check that GetImmatureCredit() returns a newly calculated value instead of
441503
// the cached value after a MarkDirty() call.
442504
//

0 commit comments

Comments
 (0)