diff options
Diffstat (limited to 'src/wallet')
-rw-r--r-- | src/wallet/rpcdump.cpp | 27 | ||||
-rw-r--r-- | src/wallet/rpcwallet.cpp | 2 | ||||
-rw-r--r-- | src/wallet/test/wallet_tests.cpp | 11 | ||||
-rw-r--r-- | src/wallet/wallet.cpp | 45 | ||||
-rw-r--r-- | src/wallet/wallet.h | 15 |
5 files changed, 64 insertions, 36 deletions
diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index 7ff9e7ae58..82708dab26 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -95,6 +95,8 @@ UniValue importprivkey(const JSONRPCRequest& request) + HelpExampleCli("importprivkey", "\"mykey\"") + "\nImport using a label and without rescan\n" + HelpExampleCli("importprivkey", "\"mykey\" \"testing\" false") + + "\nImport using default blank label and without rescan\n" + + HelpExampleCli("importprivkey", "\"mykey\" \"\" false") + "\nAs a JSON-RPC call\n" + HelpExampleRpc("importprivkey", "\"mykey\", \"testing\", false") ); @@ -154,6 +156,31 @@ UniValue importprivkey(const JSONRPCRequest& request) return NullUniValue; } +UniValue abortrescan(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 CBitcoinAddress& address, const std::string& strLabel); void ImportScript(CWallet* const pwallet, const CScript& script, const std::string& strLabel, bool isRedeemScript) { diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 2cc3072c16..665d856df5 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -2914,6 +2914,7 @@ UniValue bumpfee(const JSONRPCRequest& request) return result; } +extern UniValue abortrescan(const JSONRPCRequest& request); // in rpcdump.cpp extern UniValue dumpprivkey(const JSONRPCRequest& request); // in rpcdump.cpp extern UniValue importprivkey(const JSONRPCRequest& request); extern UniValue importaddress(const JSONRPCRequest& request); @@ -2930,6 +2931,7 @@ static const CRPCCommand commands[] = { "rawtransactions", "fundrawtransaction", &fundrawtransaction, false, {"hexstring","options"} }, { "hidden", "resendwallettransactions", &resendwallettransactions, true, {} }, { "wallet", "abandontransaction", &abandontransaction, false, {"txid"} }, + { "wallet", "abortrescan", &abortrescan, false, {} }, { "wallet", "addmultisigaddress", &addmultisigaddress, true, {"nrequired","keys","account"} }, { "wallet", "addwitnessaddress", &addwitnessaddress, true, {"address"} }, { "wallet", "backupwallet", &backupwallet, true, {"destination"} }, diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp index 0335361921..8eeba72a06 100644 --- a/src/wallet/test/wallet_tests.cpp +++ b/src/wallet/test/wallet_tests.cpp @@ -424,6 +424,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; + { + LOCK(wallet.cs_wallet); + wallet.UpdateTimeFirstKey(newTip->GetBlockTime() + 7200 + 1); + } + BOOST_CHECK_EQUAL(newTip, wallet.ScanForWalletTransactions(newTip)); + } } // Check that GetImmatureCredit() returns a newly calculated value instead of diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index e9e18603b3..b5e26e26d3 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -1155,33 +1155,6 @@ void CWallet::BlockConnected(const std::shared_ptr<const CBlock>& pblock, const for (size_t i = 0; i < pblock->vtx.size(); i++) { SyncTransaction(pblock->vtx[i], pindex, i); } - - // The GUI expects a NotifyTransactionChanged when a coinbase tx - // which is in our wallet moves from in-the-best-block to - // 2-confirmations (as it only displays them at that time). - // We do that here. - if (hashPrevBestCoinbase.IsNull()) { - // Immediately after restart we have no idea what the coinbase - // transaction from the previous block is. - // For correctness we scan over the entire wallet, looking for - // the previous block's coinbase, just in case it is ours, so - // that we can notify the UI that it should now be displayed. - if (pindex->pprev) { - for (const std::pair<uint256, CWalletTx>& p : mapWallet) { - if (p.second.IsCoinBase() && p.second.hashBlock == pindex->pprev->GetBlockHash()) { - NotifyTransactionChanged(this, p.first, CT_UPDATED); - break; - } - } - } - } else { - std::map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(hashPrevBestCoinbase); - if (mi != mapWallet.end()) { - NotifyTransactionChanged(this, hashPrevBestCoinbase, CT_UPDATED); - } - } - - hashPrevBestCoinbase = pblock->vtx[0]->GetHash(); } void CWallet::BlockDisconnected(const std::shared_ptr<const CBlock>& pblock) { @@ -1542,18 +1515,21 @@ void CWalletTx::GetAccountAmounts(const std::string& strAccount, CAmount& nRecei * 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); + 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) @@ -1563,7 +1539,7 @@ CBlockIndex* CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool f ShowProgress(_("Rescanning..."), 0); // show rescan progress in GUI as dialog or on splashscreen, if -rescan on startup double dProgressStart = 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)))); @@ -1585,7 +1561,12 @@ CBlockIndex* CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool f LogPrintf("Still rescanning. At block %d. Progress=%f\n", pindex->nHeight, GuessVerificationProgress(chainParams.TxData(), pindex)); } } + if (pindex && fAbortRescan) { + LogPrintf("Rescan aborted at block %d. Progress=%f\n", pindex->nHeight, GuessVerificationProgress(chainParams.TxData(), pindex)); + } ShowProgress(_("Rescanning..."), 100); // hide progress dialog in GUI + + fScanningWallet = false; } return ret; } @@ -3880,7 +3861,7 @@ bool CWallet::InitLoadWallet() std::string walletFile = GetArg("-wallet", DEFAULT_WALLET_DAT); - if (walletFile.find_first_of("/\\") != std::string::npos) { + if (boost::filesystem::path(walletFile).filename() != walletFile) { return InitError(_("-wallet parameter must only specify a filename (not a path)")); } else if (SanitizeString(walletFile, SAFE_CHARS_FILENAME) != walletFile) { return InitError(_("Invalid characters in -wallet filename")); diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 2eb6bd9504..06e7e14990 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -651,6 +651,8 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface { private: static std::atomic<bool> fFlushScheduled; + std::atomic<bool> fAbortRescan; + std::atomic<bool> fScanningWallet; /** * Select a set of coins such that nValueRet >= nTargetValue and at least @@ -713,10 +715,6 @@ private: */ bool AddWatchOnly(const CScript& dest) override; - // Used to NotifyTransactionChanged of the previous block's coinbase when - // the next block comes in - uint256 hashPrevBestCoinbase; - public: /* * Main wallet lock. @@ -779,6 +777,8 @@ public: nTimeFirstKey = 0; fBroadcastTransactions = false; nRelockTime = 0; + fAbortRescan = false; + fScanningWallet = false; } std::map<uint256, CWalletTx> mapWallet; @@ -823,6 +823,13 @@ public: void UnlockAllCoins(); void ListLockedCoins(std::vector<COutPoint>& vOutpts); + /* + * Rescan abort properties + */ + void AbortRescan() { fAbortRescan = true; } + bool IsAbortingRescan() { return fAbortRescan; } + bool IsScanning() { return fScanningWallet; } + /** * keystore implementation * Generate a new key |