Browse Source

Improve ScanForWalletTransactions return value

Change ScanForWalletTransactions return value so it is possible to distinguish
scans that skip reading every block (due to the nTimeFirstKey optimization)
from scans that fail while reading the chainActive.Tip() block. Return value is
now non-null in the non-failing case.

This change doesn't affect any user-visible behavior, it is only an internal
API improvement. The only code currently using the ScanForWalletTransactions
return value is in importmulti, and importmulti always calls
ScanForWalletTransactions with a pindex pointing to the first block in
chainActive whose block time is >= (nLowestTimestamp - 7200), while
ScanForWalletTransactions would only return null without reading blocks when
pindex and every block after it had a block time < (nTimeFirstKey - 7200).
These conditions could never happen at the same time because nTimeFirstKey <=

I'm planning to make a more substantial API improvement in the future (making
ScanForWalletTransactions private and exposing a higher level rescan method to
RPC code), but Matt Corallo <> pointed out this odd behavior
introduced by e2e2f4c "Return errors from importmulti if complete rescans are
not successful" yesterday, so I'm following up now to get rid of badness
introduced by that merge.
Russell Yanofsky 6 years ago
  1. 11
  2. 7


@ -426,6 +426,17 @@ BOOST_FIXTURE_TEST_CASE(rescan, TestChain100Setup) @@ -426,6 +426,17 @@ BOOST_FIXTURE_TEST_CASE(rescan, TestChain100Setup)
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()));
::pwalletMain = backup;
// Verify ScanForWalletTransactions does not return null when the scan is
// elided due to the nTimeFirstKey optimization.
CWallet wallet;
wallet.UpdateTimeFirstKey(newTip->GetBlockTime() + 7200 + 1);
BOOST_CHECK_EQUAL(newTip, wallet.ScanForWalletTransactions(newTip));


@ -1547,16 +1547,17 @@ void CWalletTx::GetAccountAmounts(const string& strAccount, CAmount& nReceived, @@ -1547,16 +1547,17 @@ void CWalletTx::GetAccountAmounts(const string& strAccount, CAmount& nReceived,
* exist in the wallet will be updated.
* Returns pointer to the first block in the last contiguous range that was
* successfully scanned.
* successfully scanned or elided (elided if pIndexStart points at a block
* before CWallet::nTimeFirstKey). Returns null if there is no such range, or
* the range doesn't include chainActive.Tip().
CBlockIndex* CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate)
CBlockIndex* ret = nullptr;
int64_t nNow = GetTime();
const CChainParams& chainParams = Params();
CBlockIndex* pindex = pindexStart;
CBlockIndex* ret = pindexStart;
LOCK2(cs_main, cs_wallet);