Skip to content

Commit 08d0390

Browse files
committed
Merge #10403: Fix importmulti failure to return rescan errors
4d2d604 Fix importmulti failure to return rescan errors (Russell Yanofsky) Tree-SHA512: e5e6d6c5a2bb7230e1bcac1903a4b766cd57bf781fade50c6c9cd5713cd3e768db0987cfda9699b57a53d3a0a60951b96dce5283b3d3ec1f954162c439bc932b
2 parents 0747d33 + 4d2d604 commit 08d0390

File tree

3 files changed

+34
-29
lines changed

3 files changed

+34
-29
lines changed

src/wallet/rpcdump.cpp

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1118,13 +1118,13 @@ UniValue importmulti(const JSONRPCRequest& mainRequest)
11181118

11191119
if (fRescan && fRunScan && requests.size()) {
11201120
CBlockIndex* pindex = nLowestTimestamp > minimumTimestamp ? chainActive.FindEarliestAtLeast(std::max<int64_t>(nLowestTimestamp - TIMESTAMP_WINDOW, 0)) : chainActive.Genesis();
1121-
CBlockIndex* scannedRange = nullptr;
1121+
CBlockIndex* scanFailed = nullptr;
11221122
if (pindex) {
1123-
scannedRange = pwallet->ScanForWalletTransactions(pindex, true);
1123+
scanFailed = pwallet->ScanForWalletTransactions(pindex, true);
11241124
pwallet->ReacceptWalletTransactions();
11251125
}
11261126

1127-
if (!scannedRange || scannedRange->nHeight > pindex->nHeight) {
1127+
if (scanFailed) {
11281128
std::vector<UniValue> results = response.getValues();
11291129
response.clear();
11301130
response.setArray();
@@ -1134,12 +1134,23 @@ UniValue importmulti(const JSONRPCRequest& mainRequest)
11341134
// range, or if the import result already has an error set, let
11351135
// the result stand unmodified. Otherwise replace the result
11361136
// with an error message.
1137-
if (GetImportTimestamp(request, now) - TIMESTAMP_WINDOW >= scannedRange->GetBlockTimeMax() || results.at(i).exists("error")) {
1137+
if (GetImportTimestamp(request, now) - TIMESTAMP_WINDOW > scanFailed->GetBlockTimeMax() || results.at(i).exists("error")) {
11381138
response.push_back(results.at(i));
11391139
} else {
11401140
UniValue result = UniValue(UniValue::VOBJ);
11411141
result.pushKV("success", UniValue(false));
1142-
result.pushKV("error", JSONRPCError(RPC_MISC_ERROR, strprintf("Failed to rescan before time %d, transactions may be missing.", scannedRange->GetBlockTimeMax())));
1142+
result.pushKV(
1143+
"error",
1144+
JSONRPCError(
1145+
RPC_MISC_ERROR,
1146+
strprintf("Rescan failed for key with creation timestamp %d. There was an error reading a "
1147+
"block from time %d, which is after or within %d seconds of key creation, and "
1148+
"could contain transactions pertaining to the key. As a result, transactions "
1149+
"and coins using this key may not appear in the wallet. This error could be "
1150+
"caused by pruning or data corruption (see bitcoind log for details) and could "
1151+
"be dealt with by downloading and rescanning the relevant blocks (see -reindex "
1152+
"and -rescan options).",
1153+
GetImportTimestamp(request, now), scanFailed->GetBlockTimeMax(), TIMESTAMP_WINDOW)));
11431154
response.push_back(std::move(result));
11441155
}
11451156
++i;

src/wallet/test/wallet_tests.cpp

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,7 @@ BOOST_FIXTURE_TEST_CASE(rescan, TestChain100Setup)
367367
LOCK(cs_main);
368368

369369
// Cap last block file size, and mine new block in a new block file.
370+
CBlockIndex* const nullBlock = nullptr;
370371
CBlockIndex* oldTip = chainActive.Tip();
371372
GetBlockFileInfo(oldTip->GetBlockPos().nFile)->nSize = MAX_BLOCKFILE_SIZE;
372373
CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey()));
@@ -378,7 +379,7 @@ BOOST_FIXTURE_TEST_CASE(rescan, TestChain100Setup)
378379
CWallet wallet;
379380
LOCK(wallet.cs_wallet);
380381
wallet.AddKeyPubKey(coinbaseKey, coinbaseKey.GetPubKey());
381-
BOOST_CHECK_EQUAL(oldTip, wallet.ScanForWalletTransactions(oldTip));
382+
BOOST_CHECK_EQUAL(nullBlock, wallet.ScanForWalletTransactions(oldTip));
382383
BOOST_CHECK_EQUAL(wallet.GetImmatureBalance(), 100 * COIN);
383384
}
384385

@@ -392,7 +393,7 @@ BOOST_FIXTURE_TEST_CASE(rescan, TestChain100Setup)
392393
CWallet wallet;
393394
LOCK(wallet.cs_wallet);
394395
wallet.AddKeyPubKey(coinbaseKey, coinbaseKey.GetPubKey());
395-
BOOST_CHECK_EQUAL(newTip, wallet.ScanForWalletTransactions(oldTip));
396+
BOOST_CHECK_EQUAL(oldTip, wallet.ScanForWalletTransactions(oldTip));
396397
BOOST_CHECK_EQUAL(wallet.GetImmatureBalance(), 50 * COIN);
397398
}
398399

@@ -416,28 +417,25 @@ BOOST_FIXTURE_TEST_CASE(rescan, TestChain100Setup)
416417
CKey futureKey;
417418
futureKey.MakeNewKey(true);
418419
key.pushKV("scriptPubKey", HexStr(GetScriptForRawPubKey(futureKey.GetPubKey())));
419-
key.pushKV("timestamp", newTip->GetBlockTimeMax() + TIMESTAMP_WINDOW);
420+
key.pushKV("timestamp", newTip->GetBlockTimeMax() + TIMESTAMP_WINDOW + 1);
420421
key.pushKV("internal", UniValue(true));
421422
keys.push_back(key);
422423
JSONRPCRequest request;
423424
request.params.setArray();
424425
request.params.push_back(keys);
425426

426427
UniValue response = importmulti(request);
427-
BOOST_CHECK_EQUAL(response.write(), strprintf("[{\"success\":false,\"error\":{\"code\":-1,\"message\":\"Failed to rescan before time %d, transactions may be missing.\"}},{\"success\":true}]", newTip->GetBlockTimeMax()));
428+
BOOST_CHECK_EQUAL(response.write(),
429+
strprintf("[{\"success\":false,\"error\":{\"code\":-1,\"message\":\"Rescan failed for key with creation "
430+
"timestamp %d. There was an error reading a block from time %d, which is after or within %d "
431+
"seconds of key creation, and could contain transactions pertaining to the key. As a result, "
432+
"transactions and coins using this key may not appear in the wallet. This error could be caused "
433+
"by pruning or data corruption (see bitcoind log for details) and could be dealt with by "
434+
"downloading and rescanning the relevant blocks (see -reindex and -rescan "
435+
"options).\"}},{\"success\":true}]",
436+
0, oldTip->GetBlockTimeMax(), TIMESTAMP_WINDOW));
428437
::pwalletMain = backup;
429438
}
430-
431-
// Verify ScanForWalletTransactions does not return null when the scan is
432-
// elided due to the nTimeFirstKey optimization.
433-
{
434-
CWallet wallet;
435-
{
436-
LOCK(wallet.cs_wallet);
437-
wallet.UpdateTimeFirstKey(newTip->GetBlockTime() + 7200 + 1);
438-
}
439-
BOOST_CHECK_EQUAL(newTip, wallet.ScanForWalletTransactions(newTip));
440-
}
441439
}
442440

443441
// Verify importwallet RPC starts rescan at earliest block with timestamp

src/wallet/wallet.cpp

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1463,18 +1463,17 @@ void CWalletTx::GetAmounts(std::list<COutputEntry>& listReceived,
14631463
* from or to us. If fUpdate is true, found transactions that already
14641464
* exist in the wallet will be updated.
14651465
*
1466-
* Returns pointer to the first block in the last contiguous range that was
1467-
* successfully scanned or elided (elided if pIndexStart points at a block
1468-
* before CWallet::nTimeFirstKey). Returns null if there is no such range, or
1469-
* the range doesn't include chainActive.Tip().
1466+
* Returns null if scan was successful. Otherwise, if a complete rescan was not
1467+
* possible (due to pruning or corruption), returns pointer to the most recent
1468+
* block that could not be scanned.
14701469
*/
14711470
CBlockIndex* CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate)
14721471
{
14731472
int64_t nNow = GetTime();
14741473
const CChainParams& chainParams = Params();
14751474

14761475
CBlockIndex* pindex = pindexStart;
1477-
CBlockIndex* ret = pindexStart;
1476+
CBlockIndex* ret = nullptr;
14781477
{
14791478
LOCK2(cs_main, cs_wallet);
14801479
fAbortRescan = false;
@@ -1502,11 +1501,8 @@ CBlockIndex* CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool f
15021501
for (size_t posInBlock = 0; posInBlock < block.vtx.size(); ++posInBlock) {
15031502
AddToWalletIfInvolvingMe(block.vtx[posInBlock], pindex, posInBlock, fUpdate);
15041503
}
1505-
if (!ret) {
1506-
ret = pindex;
1507-
}
15081504
} else {
1509-
ret = nullptr;
1505+
ret = pindex;
15101506
}
15111507
pindex = chainActive.Next(pindex);
15121508
}

0 commit comments

Comments
 (0)