diff --git a/doc/release-notes.md b/doc/release-notes.md --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -3,4 +3,5 @@ This release includes the following features and fixes: + - Backport abortrescan RPC call from bitcoin core. diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -168,6 +168,33 @@ return NullUniValue; } +UniValue abortrescan(const Config &config, const JSONRPCRequest &request) { + CWallet *const pwallet = GetWalletForJSONRPCRequest(request); + if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { + return NullUniValue; + } + + if (request.fHelp || request.params.size() > 0) { + throw std::runtime_error("abortrescan\n" + "\nStops current wallet rescan triggered e.g. " + "by an importprivkey call.\n" + "\nExamples:\n" + "\nImport a private key\n" + + HelpExampleCli("importprivkey", "\"mykey\"") + + "\nAbort the running wallet rescan\n" + + HelpExampleCli("abortrescan", "") + + "\nAs a JSON-RPC call\n" + + HelpExampleRpc("abortrescan", "")); + } + + if (!pwallet->IsScanning() || pwallet->IsAbortingRescan()) { + return false; + } + + pwallet->AbortRescan(); + return true; +} + void ImportAddress(CWallet *, const CTxDestination &dest, const std::string &strLabel); void ImportScript(CWallet *const pwallet, const CScript &script, @@ -1351,6 +1378,7 @@ static const ContextFreeRPCCommand commands[] = { // category name actor (function) okSafeMode // ------------------- ------------------------ ---------------------- ---------- + { "wallet", "abortrescan", abortrescan, false, {} }, { "wallet", "dumpprivkey", dumpprivkey, true, {"address"} }, { "wallet", "dumpwallet", dumpwallet, true, {"filename"} }, { "wallet", "importmulti", importmulti, true, {"requests","options"} }, diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -594,6 +594,8 @@ class CWallet final : public CCryptoKeyStore, public CValidationInterface { private: static std::atomic fFlushScheduled; + std::atomic fAbortRescan; + std::atomic fScanningWallet; /** * Select a set of coins such that nValueRet >= nTargetValue and at least @@ -737,6 +739,8 @@ m_max_keypool_index = 0; nTimeFirstKey = 0; fBroadcastTransactions = false; + fAbortRescan = false; + fScanningWallet = false; } std::map mapWallet; @@ -790,6 +794,13 @@ void UnlockAllCoins(); void ListLockedCoins(std::vector &vOutpts); + /* + * Rescan abort properties + */ + void AbortRescan() { fAbortRescan = true; } + bool IsAbortingRescan() { return fAbortRescan; } + bool IsScanning() { return fScanningWallet; } + /** * keystore implementation * Generate a new key diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -1712,6 +1712,8 @@ CBlockIndex *ret = nullptr; LOCK2(cs_main, cs_wallet); + fAbortRescan = false; + fScanningWallet = true; // No need to read and scan block, if block was created before our wallet // birthday (as adjusted for block time variability) @@ -1727,16 +1729,16 @@ GuessVerificationProgress(chainParams.TxData(), pindex); double dProgressTip = GuessVerificationProgress(chainParams.TxData(), chainActive.Tip()); - while (pindex) { + while (pindex && !fAbortRescan) { if (pindex->nHeight % 100 == 0 && dProgressTip - dProgressStart > 0.0) { ShowProgress( _("Rescanning..."), - std::max(1, - std::min(99, (int)((GuessVerificationProgress( - chainParams.TxData(), pindex) - - dProgressStart) / - (dProgressTip - dProgressStart) * - 100)))); + std::max(1, std::min(99, + (GuessVerificationProgress( + chainParams.TxData(), pindex) - + dProgressStart) / + (dProgressTip - dProgressStart) * + 100))); } CBlock block; @@ -1759,8 +1761,14 @@ } } + if (pindex && fAbortRescan) { + LogPrintf("Rescan aborted at block %d. Progress=%f\n", pindex->nHeight, + GuessVerificationProgress(chainParams.TxData(), pindex)); + } + // Hide progress dialog in GUI. ShowProgress(_("Rescanning..."), 100); + fScanningWallet = false; return ret; }