aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMeshCollider <dobsonsa68@gmail.com>2018-12-12 18:00:20 +1300
committerMeshCollider <dobsonsa68@gmail.com>2018-12-12 18:00:42 +1300
commited2a2cebd36280be0b5e585a8c3c901c15e52f87 (patch)
treeda624fc441d58ed88dc6542962cfd7eb4258fb20
parent3fff1ab817e7995720c3aa0374807ed70d1a4d24 (diff)
parentbd3b0361d840bff95988a048abf70ade94d80524 (diff)
downloadbitcoin-ed2a2cebd36280be0b5e585a8c3c901c15e52f87.tar.xz
Merge #13076: Fix ScanForWalletTransactions to return an enum indicating scan result: success / failure / user_abort
bd3b0361d Add stop_block out arg to ScanForWalletTransactions (Ben Woosley) 3002d6cf3 Return a status enum from ScanForWalletTransactions (Ben Woosley) bb24d6865 Make CWallet::ScanForWalletTransactions args and return value const (Ben Woosley) Pull request description: Return the failed block as an out arg. Fixes #11450. /cc #12275 Tree-SHA512: 6a523e5425ebfe24e664a942ae21c797ccc1281c25b1bf8d02ad95c19dae343fd8051985ef11853474de7628fd6bed5f15190fbc087c3466ce6fdecab37d72a9
-rw-r--r--src/qt/test/wallettests.cpp8
-rw-r--r--src/test/test_bitcoin.h8
-rw-r--r--src/wallet/rpcwallet.cpp19
-rw-r--r--src/wallet/test/wallet_tests.cpp18
-rw-r--r--src/wallet/wallet.cpp51
-rw-r--r--src/wallet/wallet.h8
6 files changed, 78 insertions, 34 deletions
diff --git a/src/qt/test/wallettests.cpp b/src/qt/test/wallettests.cpp
index f02fd8aea7..610d83acb6 100644
--- a/src/qt/test/wallettests.cpp
+++ b/src/qt/test/wallettests.cpp
@@ -146,7 +146,13 @@ void TestGUI()
auto locked_chain = wallet->chain().lock();
WalletRescanReserver reserver(wallet.get());
reserver.reserve();
- wallet->ScanForWalletTransactions(chainActive.Genesis(), nullptr, reserver, true);
+ const CBlockIndex* const null_block = nullptr;
+ const CBlockIndex *stop_block, *failed_block;
+ QCOMPARE(
+ wallet->ScanForWalletTransactions(chainActive.Genesis(), nullptr, reserver, failed_block, stop_block, true /* fUpdate */),
+ CWallet::ScanResult::SUCCESS);
+ QCOMPARE(stop_block, chainActive.Tip());
+ QCOMPARE(failed_block, null_block);
}
wallet->SetBroadcastTransactions(true);
diff --git a/src/test/test_bitcoin.h b/src/test/test_bitcoin.h
index 3872767133..182571b004 100644
--- a/src/test/test_bitcoin.h
+++ b/src/test/test_bitcoin.h
@@ -15,9 +15,17 @@
#include <txmempool.h>
#include <memory>
+#include <type_traits>
#include <boost/thread.hpp>
+// Enable BOOST_CHECK_EQUAL for enum class types
+template <typename T>
+std::ostream& operator<<(typename std::enable_if<std::is_enum<T>::value, std::ostream>::type& stream, const T& e)
+{
+ return stream << static_cast<typename std::underlying_type<T>::type>(e);
+}
+
extern uint256 insecure_rand_seed;
extern FastRandomContext insecure_rand_ctx;
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index 977aa37e73..1d9ab54857 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -3422,16 +3422,17 @@ UniValue rescanblockchain(const JSONRPCRequest& request)
}
}
- CBlockIndex *stopBlock = pwallet->ScanForWalletTransactions(pindexStart, pindexStop, reserver, true);
- if (!stopBlock) {
- if (pwallet->IsAbortingRescan()) {
- throw JSONRPCError(RPC_MISC_ERROR, "Rescan aborted.");
- }
- // if we got a nullptr returned, ScanForWalletTransactions did rescan up to the requested stopindex
- stopBlock = pindexStop ? pindexStop : pChainTip;
- }
- else {
+ const CBlockIndex *failed_block, *stopBlock;
+ CWallet::ScanResult result =
+ pwallet->ScanForWalletTransactions(pindexStart, pindexStop, reserver, failed_block, stopBlock, true);
+ switch (result) {
+ case CWallet::ScanResult::SUCCESS:
+ break; // stopBlock set by ScanForWalletTransactions
+ case CWallet::ScanResult::FAILURE:
throw JSONRPCError(RPC_MISC_ERROR, "Rescan failed. Potentially corrupted data files.");
+ case CWallet::ScanResult::USER_ABORT:
+ throw JSONRPCError(RPC_MISC_ERROR, "Rescan aborted.");
+ // no default case, so the compiler can warn about missing cases
}
UniValue response(UniValue::VOBJ);
response.pushKV("start_height", pindexStart->nHeight);
diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp
index 623c5c39a2..5731a27e00 100644
--- a/src/wallet/test/wallet_tests.cpp
+++ b/src/wallet/test/wallet_tests.cpp
@@ -39,7 +39,7 @@ BOOST_FIXTURE_TEST_CASE(rescan, TestChain100Setup)
auto chain = interfaces::MakeChain();
// Cap last block file size, and mine new block in a new block file.
- CBlockIndex* const nullBlock = nullptr;
+ const CBlockIndex* const null_block = nullptr;
CBlockIndex* oldTip = chainActive.Tip();
GetBlockFileInfo(oldTip->GetBlockPos().nFile)->nSize = MAX_BLOCKFILE_SIZE;
CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey()));
@@ -54,7 +54,10 @@ BOOST_FIXTURE_TEST_CASE(rescan, TestChain100Setup)
AddKey(wallet, coinbaseKey);
WalletRescanReserver reserver(&wallet);
reserver.reserve();
- BOOST_CHECK_EQUAL(nullBlock, wallet.ScanForWalletTransactions(oldTip, nullptr, reserver));
+ const CBlockIndex *stop_block, *failed_block;
+ BOOST_CHECK_EQUAL(wallet.ScanForWalletTransactions(oldTip, nullptr, reserver, failed_block, stop_block), CWallet::ScanResult::SUCCESS);
+ BOOST_CHECK_EQUAL(failed_block, null_block);
+ BOOST_CHECK_EQUAL(stop_block, newTip);
BOOST_CHECK_EQUAL(wallet.GetImmatureBalance(), 100 * COIN);
}
@@ -69,7 +72,10 @@ BOOST_FIXTURE_TEST_CASE(rescan, TestChain100Setup)
AddKey(wallet, coinbaseKey);
WalletRescanReserver reserver(&wallet);
reserver.reserve();
- BOOST_CHECK_EQUAL(oldTip, wallet.ScanForWalletTransactions(oldTip, nullptr, reserver));
+ const CBlockIndex *stop_block, *failed_block;
+ BOOST_CHECK_EQUAL(wallet.ScanForWalletTransactions(oldTip, nullptr, reserver, failed_block, stop_block), CWallet::ScanResult::FAILURE);
+ BOOST_CHECK_EQUAL(failed_block, oldTip);
+ BOOST_CHECK_EQUAL(stop_block, newTip);
BOOST_CHECK_EQUAL(wallet.GetImmatureBalance(), 50 * COIN);
}
@@ -287,7 +293,11 @@ public:
AddKey(*wallet, coinbaseKey);
WalletRescanReserver reserver(wallet.get());
reserver.reserve();
- wallet->ScanForWalletTransactions(chainActive.Genesis(), nullptr, reserver);
+ const CBlockIndex* const null_block = nullptr;
+ const CBlockIndex *stop_block, *failed_block;
+ BOOST_CHECK_EQUAL(wallet->ScanForWalletTransactions(chainActive.Genesis(), nullptr, reserver, failed_block, stop_block), CWallet::ScanResult::SUCCESS);
+ BOOST_CHECK_EQUAL(stop_block, chainActive.Tip());
+ BOOST_CHECK_EQUAL(failed_block, null_block);
}
~ListCoinsTestingSetup()
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index d7798e005f..829a1a2478 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -1611,8 +1611,9 @@ int64_t CWallet::RescanFromTime(int64_t startTime, const WalletRescanReserver& r
}
if (startBlock) {
- const CBlockIndex* const failedBlock = ScanForWalletTransactions(startBlock, nullptr, reserver, update);
- if (failedBlock) {
+ const CBlockIndex *failedBlock, *stop_block;
+ // TODO: this should take into account failure by ScanResult::USER_ABORT
+ if (ScanResult::FAILURE == ScanForWalletTransactions(startBlock, nullptr, reserver, failedBlock, stop_block, update)) {
return failedBlock->GetBlockTimeMax() + TIMESTAMP_WINDOW + 1;
}
}
@@ -1624,18 +1625,22 @@ int64_t CWallet::RescanFromTime(int64_t startTime, const WalletRescanReserver& r
* from or to us. If fUpdate is true, found transactions that already
* exist in the wallet will be updated.
*
- * Returns null if scan was successful. Otherwise, if a complete rescan was not
- * possible (due to pruning or corruption), returns pointer to the most recent
- * block that could not be scanned.
+ * @param[in] pindexStop if not a nullptr, the scan will stop at this block-index
+ * @param[out] failed_block if FAILURE is returned, the most recent block
+ * that could not be scanned, otherwise nullptr
+ * @param[out] stop_block the most recent block that could be scanned,
+ * otherwise nullptr if no block could be scanned
*
- * If pindexStop is not a nullptr, the scan will stop at the block-index
- * defined by pindexStop
+ * @return ScanResult indicating success or failure of the scan. SUCCESS if
+ * scan was successful. FAILURE if a complete rescan was not possible (due to
+ * pruning or corruption). USER_ABORT if the rescan was aborted before it
+ * could complete.
*
- * Caller needs to make sure pindexStop (and the optional pindexStart) are on
+ * @pre Caller needs to make sure pindexStop (and the optional pindexStart) are on
* the main chain after to the addition of any new keys you want to detect
* transactions for.
*/
-CBlockIndex* CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, CBlockIndex* pindexStop, const WalletRescanReserver &reserver, bool fUpdate)
+CWallet::ScanResult CWallet::ScanForWalletTransactions(const CBlockIndex* const pindexStart, const CBlockIndex* const pindexStop, const WalletRescanReserver& reserver, const CBlockIndex*& failed_block, const CBlockIndex*& stop_block, bool fUpdate)
{
int64_t nNow = GetTime();
const CChainParams& chainParams = Params();
@@ -1645,8 +1650,8 @@ CBlockIndex* CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, CBlock
assert(pindexStop->nHeight >= pindexStart->nHeight);
}
- CBlockIndex* pindex = pindexStart;
- CBlockIndex* ret = nullptr;
+ const CBlockIndex* pindex = pindexStart;
+ failed_block = nullptr;
if (pindex) WalletLogPrintf("Rescan started from block %d...\n", pindex->nHeight);
@@ -1667,8 +1672,7 @@ CBlockIndex* CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, CBlock
}
}
double progress_current = progress_begin;
- while (pindex && !fAbortRescan && !ShutdownRequested())
- {
+ while (pindex && !fAbortRescan && !ShutdownRequested()) {
if (pindex->nHeight % 100 == 0 && progress_end - progress_begin > 0.0) {
ShowProgress(strprintf("%s " + _("Rescanning..."), GetDisplayName()), std::max(1, std::min(99, (int)((progress_current - progress_begin) / (progress_end - progress_begin) * 100))));
}
@@ -1684,14 +1688,17 @@ CBlockIndex* CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, CBlock
if (pindex && !chainActive.Contains(pindex)) {
// Abort scan if current block is no longer active, to prevent
// marking transactions as coming from the wrong block.
- ret = pindex;
+ failed_block = pindex;
break;
}
for (size_t posInBlock = 0; posInBlock < block.vtx.size(); ++posInBlock) {
SyncTransaction(block.vtx[posInBlock], pindex, posInBlock, fUpdate);
}
+ // scan succeeded, record block as most recent successfully scanned
+ stop_block = pindex;
} else {
- ret = pindex;
+ // could not scan block, keep scanning but record this block as the most recent failure
+ failed_block = pindex;
}
if (pindex == pindexStop) {
break;
@@ -1707,14 +1714,20 @@ CBlockIndex* CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, CBlock
}
}
}
+ ShowProgress(strprintf("%s " + _("Rescanning..."), GetDisplayName()), 100); // hide progress dialog in GUI
if (pindex && fAbortRescan) {
WalletLogPrintf("Rescan aborted at block %d. Progress=%f\n", pindex->nHeight, progress_current);
+ return ScanResult::USER_ABORT;
} else if (pindex && ShutdownRequested()) {
WalletLogPrintf("Rescan interrupted by shutdown request at block %d. Progress=%f\n", pindex->nHeight, progress_current);
+ return ScanResult::USER_ABORT;
}
- ShowProgress(strprintf("%s " + _("Rescanning..."), GetDisplayName()), 100); // hide progress dialog in GUI
}
- return ret;
+ if (failed_block) {
+ return ScanResult::FAILURE;
+ } else {
+ return ScanResult::SUCCESS;
+ }
}
void CWallet::ReacceptWalletTransactions()
@@ -4169,11 +4182,11 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
nStart = GetTimeMillis();
{
WalletRescanReserver reserver(walletInstance.get());
- if (!reserver.reserve()) {
+ const CBlockIndex *stop_block, *failed_block;
+ if (!reserver.reserve() || (ScanResult::SUCCESS != walletInstance->ScanForWalletTransactions(pindexRescan, nullptr, reserver, failed_block, stop_block, true))) {
InitError(_("Failed to rescan the wallet during initialization"));
return nullptr;
}
- walletInstance->ScanForWalletTransactions(pindexRescan, nullptr, reserver, true);
}
walletInstance->WalletLogPrintf("Rescan completed in %15dms\n", GetTimeMillis() - nStart);
walletInstance->ChainStateFlushed(chainActive.GetLocator());
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index 4291163bea..95a2c833f8 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -899,7 +899,13 @@ 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;
int64_t RescanFromTime(int64_t startTime, const WalletRescanReserver& reserver, bool update);
- CBlockIndex* ScanForWalletTransactions(CBlockIndex* pindexStart, CBlockIndex* pindexStop, const WalletRescanReserver& reserver, bool fUpdate = false);
+
+ enum class ScanResult {
+ SUCCESS,
+ FAILURE,
+ USER_ABORT
+ };
+ ScanResult ScanForWalletTransactions(const CBlockIndex* const pindexStart, const CBlockIndex* const pindexStop, const WalletRescanReserver& reserver, const CBlockIndex*& failed_block, const CBlockIndex*& stop_block, bool fUpdate = false);
void TransactionRemovedFromMempool(const CTransactionRef &ptx) override;
void ReacceptWalletTransactions();
void ResendWalletTransactions(int64_t nBestBlockTime, CConnman* connman) override EXCLUSIVE_LOCKS_REQUIRED(cs_main);