Browse Source

Make sure WalletRescanReserver has successfully reserved the rescan

0.16
Jonas Schnelli 7 years ago
parent
commit
bc356b4268
No known key found for this signature in database
GPG Key ID: 1EB776BB03C7922D
  1. 4
      src/qt/test/wallettests.cpp
  2. 15
      src/wallet/rpcdump.cpp
  3. 2
      src/wallet/rpcwallet.cpp
  4. 12
      src/wallet/test/wallet_tests.cpp
  5. 20
      src/wallet/wallet.cpp
  6. 12
      src/wallet/wallet.h

4
src/qt/test/wallettests.cpp

@ -169,7 +169,9 @@ void TestGUI()
} }
{ {
LOCK(cs_main); LOCK(cs_main);
wallet.ScanForWalletTransactions(chainActive.Genesis(), nullptr, true); WalletRescanReserver reserver(&wallet);
reserver.reserve();
wallet.ScanForWalletTransactions(chainActive.Genesis(), nullptr, reserver, true);
} }
wallet.SetBroadcastTransactions(true); wallet.SetBroadcastTransactions(true);

15
src/wallet/rpcdump.cpp

@ -101,6 +101,7 @@ UniValue importprivkey(const JSONRPCRequest& request)
); );
WalletRescanReserver reserver(pwallet);
bool fRescan = true; bool fRescan = true;
{ {
LOCK2(cs_main, pwallet->cs_wallet); LOCK2(cs_main, pwallet->cs_wallet);
@ -119,6 +120,10 @@ UniValue importprivkey(const JSONRPCRequest& request)
if (fRescan && fPruneMode) if (fRescan && fPruneMode)
throw JSONRPCError(RPC_WALLET_ERROR, "Rescan is disabled in pruned mode"); 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; CBitcoinSecret vchSecret;
bool fGood = vchSecret.SetString(strSecret); bool fGood = vchSecret.SetString(strSecret);
@ -153,7 +158,7 @@ UniValue importprivkey(const JSONRPCRequest& request)
} }
} }
if (fRescan) { if (fRescan) {
pwallet->RescanFromTime(TIMESTAMP_MIN, true /* update */); pwallet->RescanFromTime(TIMESTAMP_MIN, reserver, true /* update */);
} }
return NullUniValue; return NullUniValue;
@ -290,7 +295,7 @@ UniValue importaddress(const JSONRPCRequest& request)
} }
if (fRescan) if (fRescan)
{ {
pwallet->RescanFromTime(TIMESTAMP_MIN, true /* update */); pwallet->RescanFromTime(TIMESTAMP_MIN, reserver, true /* update */);
pwallet->ReacceptWalletTransactions(); pwallet->ReacceptWalletTransactions();
} }
@ -457,7 +462,7 @@ UniValue importpubkey(const JSONRPCRequest& request)
} }
if (fRescan) if (fRescan)
{ {
pwallet->RescanFromTime(TIMESTAMP_MIN, true /* update */); pwallet->RescanFromTime(TIMESTAMP_MIN, reserver, true /* update */);
pwallet->ReacceptWalletTransactions(); pwallet->ReacceptWalletTransactions();
} }
@ -581,7 +586,7 @@ UniValue importwallet(const JSONRPCRequest& request)
pwallet->ShowProgress("", 100); // hide progress dialog in GUI pwallet->ShowProgress("", 100); // hide progress dialog in GUI
pwallet->UpdateTimeFirstKey(nTimeBegin); pwallet->UpdateTimeFirstKey(nTimeBegin);
} }
pwallet->RescanFromTime(nTimeBegin, false /* update */); pwallet->RescanFromTime(nTimeBegin, reserver, false /* update */);
pwallet->MarkDirty(); pwallet->MarkDirty();
if (!fGood) if (!fGood)
@ -1201,7 +1206,7 @@ UniValue importmulti(const JSONRPCRequest& mainRequest)
} }
} }
if (fRescan && fRunScan && requests.size()) { if (fRescan && fRunScan && requests.size()) {
int64_t scannedTime = pwallet->RescanFromTime(nLowestTimestamp, true /* update */); int64_t scannedTime = pwallet->RescanFromTime(nLowestTimestamp, reserver, true /* update */);
pwallet->ReacceptWalletTransactions(); pwallet->ReacceptWalletTransactions();
if (scannedTime > nLowestTimestamp) { if (scannedTime > nLowestTimestamp) {

2
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 (!stopBlock) {
if (pwallet->IsAbortingRescan()) { if (pwallet->IsAbortingRescan()) {
throw JSONRPCError(RPC_MISC_ERROR, "Rescan aborted."); throw JSONRPCError(RPC_MISC_ERROR, "Rescan aborted.");

12
src/wallet/test/wallet_tests.cpp

@ -384,7 +384,9 @@ BOOST_FIXTURE_TEST_CASE(rescan, TestChain100Setup)
{ {
CWallet wallet; CWallet wallet;
AddKey(wallet, coinbaseKey); 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); BOOST_CHECK_EQUAL(wallet.GetImmatureBalance(), 100 * COIN);
} }
@ -397,7 +399,9 @@ BOOST_FIXTURE_TEST_CASE(rescan, TestChain100Setup)
{ {
CWallet wallet; CWallet wallet;
AddKey(wallet, coinbaseKey); 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); BOOST_CHECK_EQUAL(wallet.GetImmatureBalance(), 50 * COIN);
} }
@ -608,7 +612,9 @@ public:
bool firstRun; bool firstRun;
wallet->LoadWallet(firstRun); wallet->LoadWallet(firstRun);
AddKey(*wallet, coinbaseKey); AddKey(*wallet, coinbaseKey);
wallet->ScanForWalletTransactions(chainActive.Genesis(), nullptr); WalletRescanReserver reserver(wallet.get());
reserver.reserve();
wallet->ScanForWalletTransactions(chainActive.Genesis(), nullptr, reserver);
} }
~ListCoinsTestingSetup() ~ListCoinsTestingSetup()

20
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 * @return Earliest timestamp that could be successfully scanned from. Timestamp
* returned will be higher than startTime if relevant blocks could not be read. * 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 // Find starting block. May be null if nCreateTime is greater than the
// highest blockchain timestamp, in which case there is nothing that needs // 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) { if (startBlock) {
const CBlockIndex* const failedBlock = ScanForWalletTransactions(startBlock, nullptr, update); const CBlockIndex* const failedBlock = ScanForWalletTransactions(startBlock, nullptr, reserver, update);
if (failedBlock) { if (failedBlock) {
return failedBlock->GetBlockTimeMax() + TIMESTAMP_WINDOW + 1; 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 * the main chain after to the addition of any new keys you want to detect
* transactions for. * 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(); int64_t nNow = GetTime();
const CChainParams& chainParams = Params(); const CChainParams& chainParams = Params();
assert(reserver.isReserved());
if (pindexStop) { if (pindexStop) {
assert(pindexStop->nHeight >= pindexStart->nHeight); assert(pindexStop->nHeight >= pindexStart->nHeight);
} }
@ -1662,8 +1663,6 @@ CBlockIndex* CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, CBlock
CBlockIndex* ret = nullptr; CBlockIndex* ret = nullptr;
{ {
fAbortRescan = false; fAbortRescan = false;
fScanningWallet = true;
ShowProgress(_("Rescanning..."), 0); // show rescan progress in GUI as dialog or on splashscreen, if -rescan on startup ShowProgress(_("Rescanning..."), 0); // show rescan progress in GUI as dialog or on splashscreen, if -rescan on startup
CBlockIndex* tip = nullptr; CBlockIndex* tip = nullptr;
double dProgressStart; 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)); LogPrintf("Rescan aborted at block %d. Progress=%f\n", pindex->nHeight, GuessVerificationProgress(chainParams.TxData(), pindex));
} }
ShowProgress(_("Rescanning..."), 100); // hide progress dialog in GUI ShowProgress(_("Rescanning..."), 100); // hide progress dialog in GUI
fScanningWallet = false;
} }
return ret; return ret;
} }
@ -4039,7 +4036,14 @@ CWallet* CWallet::CreateWalletFromFile(const std::string walletFile)
} }
nStart = GetTimeMillis(); 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); LogPrintf(" rescan %15dms\n", GetTimeMillis() - nStart);
walletInstance->SetBestChain(chainActive.GetLocator()); walletInstance->SetBestChain(chainActive.GetLocator());
walletInstance->dbw->IncrementUpdateCounter(); walletInstance->dbw->IncrementUpdateCounter();

12
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, * 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. * and provides the ability to create new transactions.
@ -668,7 +669,7 @@ class CWallet final : public CCryptoKeyStore, public CValidationInterface
private: private:
static std::atomic<bool> fFlushScheduled; static std::atomic<bool> fFlushScheduled;
std::atomic<bool> fAbortRescan; std::atomic<bool> fAbortRescan;
std::atomic<bool> fScanningWallet; std::atomic<bool> fScanningWallet; //controlled by WalletRescanReserver
std::mutex mutexScanning; std::mutex mutexScanning;
friend class WalletRescanReserver; 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 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; void BlockDisconnected(const std::shared_ptr<const CBlock>& pblock) override;
bool AddToWalletIfInvolvingMe(const CTransactionRef& tx, const CBlockIndex* pIndex, int posInBlock, bool fUpdate); bool AddToWalletIfInvolvingMe(const CTransactionRef& tx, const CBlockIndex* pIndex, int posInBlock, bool fUpdate);
int64_t RescanFromTime(int64_t startTime, bool update); int64_t RescanFromTime(int64_t startTime, const WalletRescanReserver& reserver, bool update);
CBlockIndex* ScanForWalletTransactions(CBlockIndex* pindexStart, CBlockIndex* pindexStop, bool fUpdate = false); CBlockIndex* ScanForWalletTransactions(CBlockIndex* pindexStart, CBlockIndex* pindexStop, const WalletRescanReserver& reserver, bool fUpdate = false);
void TransactionRemovedFromMempool(const CTransactionRef &ptx) override; void TransactionRemovedFromMempool(const CTransactionRef &ptx) override;
void ReacceptWalletTransactions(); void ReacceptWalletTransactions();
void ResendWalletTransactions(int64_t nBestBlockTime, CConnman* connman) override; void ResendWalletTransactions(int64_t nBestBlockTime, CConnman* connman) override;
@ -1287,6 +1288,11 @@ public:
return true; return true;
} }
bool isReserved() const
{
return (m_could_reserve && m_wallet->fScanningWallet);
}
~WalletRescanReserver() ~WalletRescanReserver()
{ {
std::lock_guard<std::mutex> lock(m_wallet->mutexScanning); std::lock_guard<std::mutex> lock(m_wallet->mutexScanning);

Loading…
Cancel
Save