aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/qt/transactionrecord.cpp10
-rw-r--r--src/wallet/rpcdump.cpp27
-rw-r--r--src/wallet/rpcwallet.cpp2
-rw-r--r--src/wallet/test/wallet_tests.cpp11
-rw-r--r--src/wallet/wallet.cpp45
-rw-r--r--src/wallet/wallet.h15
6 files changed, 66 insertions, 44 deletions
diff --git a/src/qt/transactionrecord.cpp b/src/qt/transactionrecord.cpp
index a9d9b6887e..4bb260aa58 100644
--- a/src/qt/transactionrecord.cpp
+++ b/src/qt/transactionrecord.cpp
@@ -18,14 +18,8 @@
*/
bool TransactionRecord::showTransaction(const CWalletTx &wtx)
{
- if (wtx.IsCoinBase())
- {
- // Ensures we show generated coins / mined transactions at depth 1
- if (!wtx.IsInMainChain())
- {
- return false;
- }
- }
+ // There are currently no cases where we hide transactions, but
+ // we may want to use this in the future for things like RBF.
return true;
}
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