Return a status enum from ScanForWalletTransactions
Return the failed block as an out var. This clarifies the outcome as the prior return value could be null due to user abort or failure.
This commit is contained in:
parent
bb24d68650
commit
3002d6cf31
6 changed files with 68 additions and 32 deletions
|
@ -146,7 +146,12 @@ void TestGUI()
|
||||||
auto locked_chain = wallet->chain().lock();
|
auto locked_chain = wallet->chain().lock();
|
||||||
WalletRescanReserver reserver(wallet.get());
|
WalletRescanReserver reserver(wallet.get());
|
||||||
reserver.reserve();
|
reserver.reserve();
|
||||||
wallet->ScanForWalletTransactions(chainActive.Genesis(), nullptr, reserver, true);
|
const CBlockIndex* const null_block = nullptr;
|
||||||
|
const CBlockIndex* stop_block;
|
||||||
|
QCOMPARE(
|
||||||
|
wallet->ScanForWalletTransactions(chainActive.Genesis(), nullptr, reserver, stop_block, true /* fUpdate */),
|
||||||
|
CWallet::ScanResult::SUCCESS);
|
||||||
|
QCOMPARE(stop_block, null_block);
|
||||||
}
|
}
|
||||||
wallet->SetBroadcastTransactions(true);
|
wallet->SetBroadcastTransactions(true);
|
||||||
|
|
||||||
|
|
|
@ -15,9 +15,17 @@
|
||||||
#include <txmempool.h>
|
#include <txmempool.h>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
#include <boost/thread.hpp>
|
#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 uint256 insecure_rand_seed;
|
||||||
extern FastRandomContext insecure_rand_ctx;
|
extern FastRandomContext insecure_rand_ctx;
|
||||||
|
|
||||||
|
|
|
@ -3332,16 +3332,18 @@ UniValue rescanblockchain(const JSONRPCRequest& request)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const CBlockIndex* stopBlock = pwallet->ScanForWalletTransactions(pindexStart, pindexStop, reserver, true);
|
const CBlockIndex* stopBlock;
|
||||||
if (!stopBlock) {
|
CWallet::ScanResult result =
|
||||||
if (pwallet->IsAbortingRescan()) {
|
pwallet->ScanForWalletTransactions(pindexStart, pindexStop, reserver, stopBlock, true);
|
||||||
throw JSONRPCError(RPC_MISC_ERROR, "Rescan aborted.");
|
switch (result) {
|
||||||
}
|
case CWallet::ScanResult::SUCCESS:
|
||||||
// if we got a nullptr returned, ScanForWalletTransactions did rescan up to the requested stopindex
|
|
||||||
stopBlock = pindexStop ? pindexStop : pChainTip;
|
stopBlock = pindexStop ? pindexStop : pChainTip;
|
||||||
}
|
break;
|
||||||
else {
|
case CWallet::ScanResult::FAILURE:
|
||||||
throw JSONRPCError(RPC_MISC_ERROR, "Rescan failed. Potentially corrupted data files.");
|
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);
|
UniValue response(UniValue::VOBJ);
|
||||||
response.pushKV("start_height", pindexStart->nHeight);
|
response.pushKV("start_height", pindexStart->nHeight);
|
||||||
|
|
|
@ -38,7 +38,7 @@ BOOST_FIXTURE_TEST_CASE(rescan, TestChain100Setup)
|
||||||
auto chain = interfaces::MakeChain();
|
auto chain = interfaces::MakeChain();
|
||||||
|
|
||||||
// Cap last block file size, and mine new block in a new block file.
|
// 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();
|
CBlockIndex* oldTip = chainActive.Tip();
|
||||||
GetBlockFileInfo(oldTip->GetBlockPos().nFile)->nSize = MAX_BLOCKFILE_SIZE;
|
GetBlockFileInfo(oldTip->GetBlockPos().nFile)->nSize = MAX_BLOCKFILE_SIZE;
|
||||||
CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey()));
|
CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey()));
|
||||||
|
@ -53,7 +53,9 @@ BOOST_FIXTURE_TEST_CASE(rescan, TestChain100Setup)
|
||||||
AddKey(wallet, coinbaseKey);
|
AddKey(wallet, coinbaseKey);
|
||||||
WalletRescanReserver reserver(&wallet);
|
WalletRescanReserver reserver(&wallet);
|
||||||
reserver.reserve();
|
reserver.reserve();
|
||||||
BOOST_CHECK_EQUAL(nullBlock, wallet.ScanForWalletTransactions(oldTip, nullptr, reserver));
|
const CBlockIndex* stop_block;
|
||||||
|
BOOST_CHECK_EQUAL(wallet.ScanForWalletTransactions(oldTip, nullptr, reserver, stop_block), CWallet::ScanResult::SUCCESS);
|
||||||
|
BOOST_CHECK_EQUAL(stop_block, null_block);
|
||||||
BOOST_CHECK_EQUAL(wallet.GetImmatureBalance(), 100 * COIN);
|
BOOST_CHECK_EQUAL(wallet.GetImmatureBalance(), 100 * COIN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,7 +70,9 @@ BOOST_FIXTURE_TEST_CASE(rescan, TestChain100Setup)
|
||||||
AddKey(wallet, coinbaseKey);
|
AddKey(wallet, coinbaseKey);
|
||||||
WalletRescanReserver reserver(&wallet);
|
WalletRescanReserver reserver(&wallet);
|
||||||
reserver.reserve();
|
reserver.reserve();
|
||||||
BOOST_CHECK_EQUAL(oldTip, wallet.ScanForWalletTransactions(oldTip, nullptr, reserver));
|
const CBlockIndex* stop_block;
|
||||||
|
BOOST_CHECK_EQUAL(wallet.ScanForWalletTransactions(oldTip, nullptr, reserver, stop_block), CWallet::ScanResult::FAILURE);
|
||||||
|
BOOST_CHECK_EQUAL(oldTip, stop_block);
|
||||||
BOOST_CHECK_EQUAL(wallet.GetImmatureBalance(), 50 * COIN);
|
BOOST_CHECK_EQUAL(wallet.GetImmatureBalance(), 50 * COIN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -286,7 +290,10 @@ public:
|
||||||
AddKey(*wallet, coinbaseKey);
|
AddKey(*wallet, coinbaseKey);
|
||||||
WalletRescanReserver reserver(wallet.get());
|
WalletRescanReserver reserver(wallet.get());
|
||||||
reserver.reserve();
|
reserver.reserve();
|
||||||
wallet->ScanForWalletTransactions(chainActive.Genesis(), nullptr, reserver);
|
const CBlockIndex* const null_block = nullptr;
|
||||||
|
const CBlockIndex* stop_block;
|
||||||
|
BOOST_CHECK_EQUAL(wallet->ScanForWalletTransactions(chainActive.Genesis(), nullptr, reserver, stop_block), CWallet::ScanResult::SUCCESS);
|
||||||
|
BOOST_CHECK_EQUAL(stop_block, null_block);
|
||||||
}
|
}
|
||||||
|
|
||||||
~ListCoinsTestingSetup()
|
~ListCoinsTestingSetup()
|
||||||
|
|
|
@ -1613,8 +1613,9 @@ int64_t CWallet::RescanFromTime(int64_t startTime, const WalletRescanReserver& r
|
||||||
}
|
}
|
||||||
|
|
||||||
if (startBlock) {
|
if (startBlock) {
|
||||||
const CBlockIndex* const failedBlock = ScanForWalletTransactions(startBlock, nullptr, reserver, update);
|
const CBlockIndex* failedBlock;
|
||||||
if (failedBlock) {
|
// TODO: this should take into account failure by ScanResult::USER_ABORT
|
||||||
|
if (ScanResult::FAILURE == ScanForWalletTransactions(startBlock, nullptr, reserver, failedBlock, update)) {
|
||||||
return failedBlock->GetBlockTimeMax() + TIMESTAMP_WINDOW + 1;
|
return failedBlock->GetBlockTimeMax() + TIMESTAMP_WINDOW + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1626,18 +1627,20 @@ int64_t CWallet::RescanFromTime(int64_t startTime, const WalletRescanReserver& r
|
||||||
* from or to us. If fUpdate is true, found transactions that already
|
* from or to us. If fUpdate is true, found transactions that already
|
||||||
* exist in the wallet will be updated.
|
* exist in the wallet will be updated.
|
||||||
*
|
*
|
||||||
* Returns null if scan was successful. Otherwise, if a complete rescan was not
|
* @param[in] pindexStop if not a nullptr, the scan will stop at this block-index
|
||||||
* possible (due to pruning or corruption), returns pointer to the most recent
|
* @param[out] failed_block if FAILURE is returned, will be set to the most
|
||||||
* block that could not be scanned.
|
* recent block that could not be scanned, otherwise nullptr
|
||||||
*
|
*
|
||||||
* If pindexStop is not a nullptr, the scan will stop at the block-index
|
* @return ScanResult indicating success or failure of the scan. SUCCESS if
|
||||||
* defined by pindexStop
|
* 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
|
* the main chain after to the addition of any new keys you want to detect
|
||||||
* transactions for.
|
* transactions for.
|
||||||
*/
|
*/
|
||||||
const CBlockIndex* CWallet::ScanForWalletTransactions(const CBlockIndex* const pindexStart, const CBlockIndex* const 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, bool fUpdate)
|
||||||
{
|
{
|
||||||
int64_t nNow = GetTime();
|
int64_t nNow = GetTime();
|
||||||
const CChainParams& chainParams = Params();
|
const CChainParams& chainParams = Params();
|
||||||
|
@ -1648,7 +1651,7 @@ const CBlockIndex* CWallet::ScanForWalletTransactions(const CBlockIndex* const p
|
||||||
}
|
}
|
||||||
|
|
||||||
const CBlockIndex* pindex = pindexStart;
|
const CBlockIndex* pindex = pindexStart;
|
||||||
const CBlockIndex* ret = nullptr;
|
failed_block = nullptr;
|
||||||
|
|
||||||
if (pindex) WalletLogPrintf("Rescan started from block %d...\n", pindex->nHeight);
|
if (pindex) WalletLogPrintf("Rescan started from block %d...\n", pindex->nHeight);
|
||||||
|
|
||||||
|
@ -1669,8 +1672,7 @@ const CBlockIndex* CWallet::ScanForWalletTransactions(const CBlockIndex* const p
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
double progress_current = progress_begin;
|
double progress_current = progress_begin;
|
||||||
while (pindex && !fAbortRescan && !ShutdownRequested())
|
while (pindex && !fAbortRescan && !ShutdownRequested()) {
|
||||||
{
|
|
||||||
if (pindex->nHeight % 100 == 0 && progress_end - progress_begin > 0.0) {
|
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))));
|
ShowProgress(strprintf("%s " + _("Rescanning..."), GetDisplayName()), std::max(1, std::min(99, (int)((progress_current - progress_begin) / (progress_end - progress_begin) * 100))));
|
||||||
}
|
}
|
||||||
|
@ -1686,14 +1688,14 @@ const CBlockIndex* CWallet::ScanForWalletTransactions(const CBlockIndex* const p
|
||||||
if (pindex && !chainActive.Contains(pindex)) {
|
if (pindex && !chainActive.Contains(pindex)) {
|
||||||
// Abort scan if current block is no longer active, to prevent
|
// Abort scan if current block is no longer active, to prevent
|
||||||
// marking transactions as coming from the wrong block.
|
// marking transactions as coming from the wrong block.
|
||||||
ret = pindex;
|
failed_block = pindex;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
for (size_t posInBlock = 0; posInBlock < block.vtx.size(); ++posInBlock) {
|
for (size_t posInBlock = 0; posInBlock < block.vtx.size(); ++posInBlock) {
|
||||||
SyncTransaction(block.vtx[posInBlock], pindex, posInBlock, fUpdate);
|
SyncTransaction(block.vtx[posInBlock], pindex, posInBlock, fUpdate);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ret = pindex;
|
failed_block = pindex;
|
||||||
}
|
}
|
||||||
if (pindex == pindexStop) {
|
if (pindex == pindexStop) {
|
||||||
break;
|
break;
|
||||||
|
@ -1709,14 +1711,20 @@ const CBlockIndex* CWallet::ScanForWalletTransactions(const CBlockIndex* const p
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ShowProgress(strprintf("%s " + _("Rescanning..."), GetDisplayName()), 100); // hide progress dialog in GUI
|
||||||
if (pindex && fAbortRescan) {
|
if (pindex && fAbortRescan) {
|
||||||
WalletLogPrintf("Rescan aborted at block %d. Progress=%f\n", pindex->nHeight, progress_current);
|
WalletLogPrintf("Rescan aborted at block %d. Progress=%f\n", pindex->nHeight, progress_current);
|
||||||
|
return ScanResult::USER_ABORT;
|
||||||
} else if (pindex && ShutdownRequested()) {
|
} else if (pindex && ShutdownRequested()) {
|
||||||
WalletLogPrintf("Rescan interrupted by shutdown request at block %d. Progress=%f\n", pindex->nHeight, progress_current);
|
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()
|
void CWallet::ReacceptWalletTransactions()
|
||||||
|
@ -4166,11 +4174,11 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
|
||||||
nStart = GetTimeMillis();
|
nStart = GetTimeMillis();
|
||||||
{
|
{
|
||||||
WalletRescanReserver reserver(walletInstance.get());
|
WalletRescanReserver reserver(walletInstance.get());
|
||||||
if (!reserver.reserve()) {
|
const CBlockIndex* stop_block;
|
||||||
|
if (!reserver.reserve() || (ScanResult::SUCCESS != walletInstance->ScanForWalletTransactions(pindexRescan, nullptr, reserver, stop_block, true))) {
|
||||||
InitError(_("Failed to rescan the wallet during initialization"));
|
InitError(_("Failed to rescan the wallet during initialization"));
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
walletInstance->ScanForWalletTransactions(pindexRescan, nullptr, reserver, true);
|
|
||||||
}
|
}
|
||||||
walletInstance->WalletLogPrintf("Rescan completed in %15dms\n", GetTimeMillis() - nStart);
|
walletInstance->WalletLogPrintf("Rescan completed in %15dms\n", GetTimeMillis() - nStart);
|
||||||
walletInstance->ChainStateFlushed(chainActive.GetLocator());
|
walletInstance->ChainStateFlushed(chainActive.GetLocator());
|
||||||
|
|
|
@ -896,7 +896,13 @@ 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;
|
||||||
int64_t RescanFromTime(int64_t startTime, const WalletRescanReserver& reserver, bool update);
|
int64_t RescanFromTime(int64_t startTime, const WalletRescanReserver& reserver, bool update);
|
||||||
const CBlockIndex* ScanForWalletTransactions(const CBlockIndex* const pindexStart, const CBlockIndex* const 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, 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 EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
void ResendWalletTransactions(int64_t nBestBlockTime, CConnman* connman) override EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||||
|
|
Loading…
Reference in a new issue