aboutsummaryrefslogtreecommitdiff
path: root/src/wallet
diff options
context:
space:
mode:
authorJonas Schnelli <dev@jonasschnelli.ch>2017-12-12 13:13:58 -1000
committerJonas Schnelli <dev@jonasschnelli.ch>2018-01-23 20:24:18 -1000
commitbc356b4268e222ac57d9e9297d2a986bb6e09de8 (patch)
tree994c99623c3b7aa10e367d5d3e02451da2025d38 /src/wallet
parentdbf8556b4d6a2484ad4c03d0b4e41c1db0133997 (diff)
Make sure WalletRescanReserver has successfully reserved the rescan
Diffstat (limited to 'src/wallet')
-rw-r--r--src/wallet/rpcdump.cpp15
-rw-r--r--src/wallet/rpcwallet.cpp2
-rw-r--r--src/wallet/test/wallet_tests.cpp12
-rw-r--r--src/wallet/wallet.cpp20
-rw-r--r--src/wallet/wallet.h12
5 files changed, 41 insertions, 20 deletions
diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp
index a0b57ecd22..936432bacb 100644
--- a/src/wallet/rpcdump.cpp
+++ b/src/wallet/rpcdump.cpp
@@ -101,6 +101,7 @@ UniValue importprivkey(const JSONRPCRequest& request)
);
+ WalletRescanReserver reserver(pwallet);
bool fRescan = true;
{
LOCK2(cs_main, pwallet->cs_wallet);
@@ -119,6 +120,10 @@ UniValue importprivkey(const JSONRPCRequest& request)
if (fRescan && fPruneMode)
throw JSONRPCError(RPC_WALLET_ERROR, "Rescan is disabled in pruned mode");
+ if (fRescan && !reserver.reserve()) {
+ throw JSONRPCError(RPC_WALLET_ERROR, "Wallet is currently rescanning. Abort existing rescan or wait.");
+ }
+
CBitcoinSecret vchSecret;
bool fGood = vchSecret.SetString(strSecret);
@@ -153,7 +158,7 @@ UniValue importprivkey(const JSONRPCRequest& request)
}
}
if (fRescan) {
- pwallet->RescanFromTime(TIMESTAMP_MIN, true /* update */);
+ pwallet->RescanFromTime(TIMESTAMP_MIN, reserver, true /* update */);
}
return NullUniValue;
@@ -290,7 +295,7 @@ UniValue importaddress(const JSONRPCRequest& request)
}
if (fRescan)
{
- pwallet->RescanFromTime(TIMESTAMP_MIN, true /* update */);
+ pwallet->RescanFromTime(TIMESTAMP_MIN, reserver, true /* update */);
pwallet->ReacceptWalletTransactions();
}
@@ -457,7 +462,7 @@ UniValue importpubkey(const JSONRPCRequest& request)
}
if (fRescan)
{
- pwallet->RescanFromTime(TIMESTAMP_MIN, true /* update */);
+ pwallet->RescanFromTime(TIMESTAMP_MIN, reserver, true /* update */);
pwallet->ReacceptWalletTransactions();
}
@@ -581,7 +586,7 @@ UniValue importwallet(const JSONRPCRequest& request)
pwallet->ShowProgress("", 100); // hide progress dialog in GUI
pwallet->UpdateTimeFirstKey(nTimeBegin);
}
- pwallet->RescanFromTime(nTimeBegin, false /* update */);
+ pwallet->RescanFromTime(nTimeBegin, reserver, false /* update */);
pwallet->MarkDirty();
if (!fGood)
@@ -1201,7 +1206,7 @@ UniValue importmulti(const JSONRPCRequest& mainRequest)
}
}
if (fRescan && fRunScan && requests.size()) {
- int64_t scannedTime = pwallet->RescanFromTime(nLowestTimestamp, true /* update */);
+ int64_t scannedTime = pwallet->RescanFromTime(nLowestTimestamp, reserver, true /* update */);
pwallet->ReacceptWalletTransactions();
if (scannedTime > nLowestTimestamp) {
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index 50642e6b8a..7188bb40bc 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -3441,7 +3441,7 @@ UniValue rescanblockchain(const JSONRPCRequest& request)
}
}
- CBlockIndex *stopBlock = pwallet->ScanForWalletTransactions(pindexStart, pindexStop, true);
+ CBlockIndex *stopBlock = pwallet->ScanForWalletTransactions(pindexStart, pindexStop, reserver, true);
if (!stopBlock) {
if (pwallet->IsAbortingRescan()) {
throw JSONRPCError(RPC_MISC_ERROR, "Rescan aborted.");
diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp
index 7b3c283f37..7e0881afd7 100644
--- a/src/wallet/test/wallet_tests.cpp
+++ b/src/wallet/test/wallet_tests.cpp
@@ -384,7 +384,9 @@ BOOST_FIXTURE_TEST_CASE(rescan, TestChain100Setup)
{
CWallet wallet;
AddKey(wallet, coinbaseKey);
- BOOST_CHECK_EQUAL(nullBlock, wallet.ScanForWalletTransactions(oldTip, nullptr));
+ WalletRescanReserver reserver(&wallet);
+ reserver.reserve();
+ BOOST_CHECK_EQUAL(nullBlock, wallet.ScanForWalletTransactions(oldTip, nullptr, reserver));
BOOST_CHECK_EQUAL(wallet.GetImmatureBalance(), 100 * COIN);
}
@@ -397,7 +399,9 @@ BOOST_FIXTURE_TEST_CASE(rescan, TestChain100Setup)
{
CWallet wallet;
AddKey(wallet, coinbaseKey);
- BOOST_CHECK_EQUAL(oldTip, wallet.ScanForWalletTransactions(oldTip, nullptr));
+ WalletRescanReserver reserver(&wallet);
+ reserver.reserve();
+ BOOST_CHECK_EQUAL(oldTip, wallet.ScanForWalletTransactions(oldTip, nullptr, reserver));
BOOST_CHECK_EQUAL(wallet.GetImmatureBalance(), 50 * COIN);
}
@@ -608,7 +612,9 @@ public:
bool firstRun;
wallet->LoadWallet(firstRun);
AddKey(*wallet, coinbaseKey);
- wallet->ScanForWalletTransactions(chainActive.Genesis(), nullptr);
+ WalletRescanReserver reserver(wallet.get());
+ reserver.reserve();
+ wallet->ScanForWalletTransactions(chainActive.Genesis(), nullptr, reserver);
}
~ListCoinsTestingSetup()
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 450ef4c49c..3bf649f266 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -1612,7 +1612,7 @@ void CWalletTx::GetAmounts(std::list<COutputEntry>& listReceived,
* @return Earliest timestamp that could be successfully scanned from. Timestamp
* returned will be higher than startTime if relevant blocks could not be read.
*/
-int64_t CWallet::RescanFromTime(int64_t startTime, bool update)
+int64_t CWallet::RescanFromTime(int64_t startTime, const WalletRescanReserver& reserver, bool update)
{
// Find starting block. May be null if nCreateTime is greater than the
// highest blockchain timestamp, in which case there is nothing that needs
@@ -1625,7 +1625,7 @@ int64_t CWallet::RescanFromTime(int64_t startTime, bool update)
}
if (startBlock) {
- const CBlockIndex* const failedBlock = ScanForWalletTransactions(startBlock, nullptr, update);
+ const CBlockIndex* const failedBlock = ScanForWalletTransactions(startBlock, nullptr, reserver, update);
if (failedBlock) {
return failedBlock->GetBlockTimeMax() + TIMESTAMP_WINDOW + 1;
}
@@ -1649,11 +1649,12 @@ int64_t CWallet::RescanFromTime(int64_t startTime, bool update)
* the main chain after to the addition of any new keys you want to detect
* transactions for.
*/
-CBlockIndex* CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, CBlockIndex* pindexStop, bool fUpdate)
+CBlockIndex* CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, CBlockIndex* pindexStop, const WalletRescanReserver &reserver, bool fUpdate)
{
int64_t nNow = GetTime();
const CChainParams& chainParams = Params();
+ assert(reserver.isReserved());
if (pindexStop) {
assert(pindexStop->nHeight >= pindexStart->nHeight);
}
@@ -1662,8 +1663,6 @@ CBlockIndex* CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, CBlock
CBlockIndex* ret = nullptr;
{
fAbortRescan = false;
- fScanningWallet = true;
-
ShowProgress(_("Rescanning..."), 0); // show rescan progress in GUI as dialog or on splashscreen, if -rescan on startup
CBlockIndex* tip = nullptr;
double dProgressStart;
@@ -1727,8 +1726,6 @@ CBlockIndex* CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, CBlock
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;
}
@@ -4039,7 +4036,14 @@ CWallet* CWallet::CreateWalletFromFile(const std::string walletFile)
}
nStart = GetTimeMillis();
- walletInstance->ScanForWalletTransactions(pindexRescan, nullptr, true);
+ {
+ WalletRescanReserver reserver(walletInstance);
+ if (!reserver.reserve()) {
+ InitError(_("Failed to rescan the wallet during initialization"));
+ return nullptr;
+ }
+ walletInstance->ScanForWalletTransactions(pindexRescan, nullptr, reserver, true);
+ }
LogPrintf(" rescan %15dms\n", GetTimeMillis() - nStart);
walletInstance->SetBestChain(chainActive.GetLocator());
walletInstance->dbw->IncrementUpdateCounter();
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index 5d782faa60..70ced30e45 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -659,6 +659,7 @@ private:
};
+class WalletRescanReserver; //forward declarations for ScanForWalletTransactions/RescanFromTime
/**
* A CWallet is an extension of a keystore, which also maintains a set of transactions and balances,
* and provides the ability to create new transactions.
@@ -668,7 +669,7 @@ class CWallet final : public CCryptoKeyStore, public CValidationInterface
private:
static std::atomic<bool> fFlushScheduled;
std::atomic<bool> fAbortRescan;
- std::atomic<bool> fScanningWallet;
+ std::atomic<bool> fScanningWallet; //controlled by WalletRescanReserver
std::mutex mutexScanning;
friend class WalletRescanReserver;
@@ -948,8 +949,8 @@ public:
void BlockConnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex *pindex, const std::vector<CTransactionRef>& vtxConflicted) override;
void BlockDisconnected(const std::shared_ptr<const CBlock>& pblock) override;
bool AddToWalletIfInvolvingMe(const CTransactionRef& tx, const CBlockIndex* pIndex, int posInBlock, bool fUpdate);
- int64_t RescanFromTime(int64_t startTime, bool update);
- CBlockIndex* ScanForWalletTransactions(CBlockIndex* pindexStart, CBlockIndex* pindexStop, bool fUpdate = false);
+ int64_t RescanFromTime(int64_t startTime, const WalletRescanReserver& reserver, bool update);
+ CBlockIndex* ScanForWalletTransactions(CBlockIndex* pindexStart, CBlockIndex* pindexStop, const WalletRescanReserver& reserver, bool fUpdate = false);
void TransactionRemovedFromMempool(const CTransactionRef &ptx) override;
void ReacceptWalletTransactions();
void ResendWalletTransactions(int64_t nBestBlockTime, CConnman* connman) override;
@@ -1287,6 +1288,11 @@ public:
return true;
}
+ bool isReserved() const
+ {
+ return (m_could_reserve && m_wallet->fScanningWallet);
+ }
+
~WalletRescanReserver()
{
std::lock_guard<std::mutex> lock(m_wallet->mutexScanning);