wallet: Save wallet scan progress
Currently, the wallet scan progress is not saved. If it is interrupted, it will be necessary to start from scratch on the next load. With this change, progress is saved every 60 seconds. Co-authored-by: furszy <matiasfurszyfer@protonmail.com> Co-authored-by: Jon Atack <jon@atack.com> Co-authored-by: Ryan Ofsky <ryan@ofsky.org>
This commit is contained in:
1 parent
d4d9daff7a
commit
a89ddfbe22
8 files changed
+41
-18
No files matched your search
@@ -111,6 +111,10 @@ public:
|
|||||||
//! Get locator for the current chain tip.
|
//! Get locator for the current chain tip.
|
||||||
virtual CBlockLocator getTipLocator() = 0;
|
virtual CBlockLocator getTipLocator() = 0;
|
||||||
|
|
||||||
|
//! Return a locator that refers to a block in the active chain.
|
||||||
|
//! If specified block is not in the active chain, return locator for the latest ancestor that is in the chain.
|
||||||
|
virtual CBlockLocator getActiveChainLocator(const uint256& block_hash) = 0;
|
||||||
|
|
||||||
//! Return height of the highest block on chain in common with the locator,
|
//! Return height of the highest block on chain in common with the locator,
|
||||||
//! which will either be the original block used to create the locator,
|
//! which will either be the original block used to create the locator,
|
||||||
//! or one of its ancestors.
|
//! or one of its ancestors.
|
||||||
|
|||||||
+12
-5
@@ -516,20 +516,27 @@ public:
|
|||||||
}
|
}
|
||||||
bool haveBlockOnDisk(int height) override
|
bool haveBlockOnDisk(int height) override
|
||||||
{
|
{
|
||||||
LOCK(cs_main);
|
LOCK(::cs_main);
|
||||||
const CChain& active = Assert(m_node.chainman)->ActiveChain();
|
const CChain& active = Assert(m_node.chainman)->ActiveChain();
|
||||||
CBlockIndex* block = active[height];
|
CBlockIndex* block = active[height];
|
||||||
return block && ((block->nStatus & BLOCK_HAVE_DATA) != 0) && block->nTx > 0;
|
return block && ((block->nStatus & BLOCK_HAVE_DATA) != 0) && block->nTx > 0;
|
||||||
}
|
}
|
||||||
CBlockLocator getTipLocator() override
|
CBlockLocator getTipLocator() override
|
||||||
{
|
{
|
||||||
LOCK(cs_main);
|
LOCK(::cs_main);
|
||||||
const CChain& active = Assert(m_node.chainman)->ActiveChain();
|
const CChain& active = Assert(m_node.chainman)->ActiveChain();
|
||||||
return active.GetLocator();
|
return active.GetLocator();
|
||||||
}
|
}
|
||||||
|
CBlockLocator getActiveChainLocator(const uint256& block_hash) override
|
||||||
|
{
|
||||||
|
LOCK(::cs_main);
|
||||||
|
const CBlockIndex* index = chainman().m_blockman.LookupBlockIndex(block_hash);
|
||||||
|
if (!index) return {};
|
||||||
|
return chainman().ActiveChain().GetLocator(index);
|
||||||
|
}
|
||||||
std::optional<int> findLocatorFork(const CBlockLocator& locator) override
|
std::optional<int> findLocatorFork(const CBlockLocator& locator) override
|
||||||
{
|
{
|
||||||
LOCK(cs_main);
|
LOCK(::cs_main);
|
||||||
const CChainState& active = Assert(m_node.chainman)->ActiveChainstate();
|
const CChainState& active = Assert(m_node.chainman)->ActiveChainstate();
|
||||||
if (const CBlockIndex* fork = active.FindForkInGlobalIndex(locator)) {
|
if (const CBlockIndex* fork = active.FindForkInGlobalIndex(locator)) {
|
||||||
return fork->nHeight;
|
return fork->nHeight;
|
||||||
@@ -585,7 +592,7 @@ public:
|
|||||||
void findCoins(std::map<COutPoint, Coin>& coins) override { return FindCoins(m_node, coins); }
|
void findCoins(std::map<COutPoint, Coin>& coins) override { return FindCoins(m_node, coins); }
|
||||||
double guessVerificationProgress(const uint256& block_hash) override
|
double guessVerificationProgress(const uint256& block_hash) override
|
||||||
{
|
{
|
||||||
LOCK(cs_main);
|
LOCK(::cs_main);
|
||||||
return GuessVerificationProgress(chainman().GetParams().TxData(), chainman().m_blockman.LookupBlockIndex(block_hash));
|
return GuessVerificationProgress(chainman().GetParams().TxData(), chainman().m_blockman.LookupBlockIndex(block_hash));
|
||||||
}
|
}
|
||||||
bool hasBlocks(const uint256& block_hash, int min_height, std::optional<int> max_height) override
|
bool hasBlocks(const uint256& block_hash, int min_height, std::optional<int> max_height) override
|
||||||
@@ -684,7 +691,7 @@ public:
|
|||||||
CFeeRate relayDustFee() override { return ::dustRelayFee; }
|
CFeeRate relayDustFee() override { return ::dustRelayFee; }
|
||||||
bool havePruned() override
|
bool havePruned() override
|
||||||
{
|
{
|
||||||
LOCK(cs_main);
|
LOCK(::cs_main);
|
||||||
return m_node.chainman->m_blockman.m_have_pruned;
|
return m_node.chainman->m_blockman.m_have_pruned;
|
||||||
}
|
}
|
||||||
bool isReadyToBroadcast() override { return !node::fImporting && !node::fReindex && !isInitialBlockDownload(); }
|
bool isReadyToBroadcast() override { return !node::fImporting && !node::fReindex && !isInitialBlockDownload(); }
|
||||||
|
|||||||
@@ -173,7 +173,7 @@ void TestGUI(interfaces::Node& node)
|
|||||||
{
|
{
|
||||||
WalletRescanReserver reserver(*wallet);
|
WalletRescanReserver reserver(*wallet);
|
||||||
reserver.reserve();
|
reserver.reserve();
|
||||||
CWallet::ScanResult result = wallet->ScanForWalletTransactions(Params().GetConsensus().hashGenesisBlock, 0 /* block height */, {} /* max height */, reserver, true /* fUpdate */);
|
CWallet::ScanResult result = wallet->ScanForWalletTransactions(Params().GetConsensus().hashGenesisBlock, /*start_height=*/0, /*max_height=*/{}, reserver, /*fUpdate=*/true, /*save_progress=*/false);
|
||||||
QCOMPARE(result.status, CWallet::ScanResult::SUCCESS);
|
QCOMPARE(result.status, CWallet::ScanResult::SUCCESS);
|
||||||
QCOMPARE(result.last_scanned_block, node.context()->chainman->ActiveChain().Tip()->GetBlockHash());
|
QCOMPARE(result.last_scanned_block, node.context()->chainman->ActiveChain().Tip()->GetBlockHash());
|
||||||
QVERIFY(result.last_failed_block.IsNull());
|
QVERIFY(result.last_failed_block.IsNull());
|
||||||
|
|||||||
@@ -908,7 +908,7 @@ RPCHelpMan rescanblockchain()
|
|||||||
}
|
}
|
||||||
|
|
||||||
CWallet::ScanResult result =
|
CWallet::ScanResult result =
|
||||||
pwallet->ScanForWalletTransactions(start_block, start_height, stop_height, reserver, true /* fUpdate */);
|
pwallet->ScanForWalletTransactions(start_block, start_height, stop_height, reserver, /*fUpdate=*/true, /*save_progress=*/false);
|
||||||
switch (result.status) {
|
switch (result.status) {
|
||||||
case CWallet::ScanResult::SUCCESS:
|
case CWallet::ScanResult::SUCCESS:
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ std::unique_ptr<CWallet> CreateSyncedWallet(interfaces::Chain& chain, CChain& cc
|
|||||||
}
|
}
|
||||||
WalletRescanReserver reserver(*wallet);
|
WalletRescanReserver reserver(*wallet);
|
||||||
reserver.reserve();
|
reserver.reserve();
|
||||||
CWallet::ScanResult result = wallet->ScanForWalletTransactions(cchain.Genesis()->GetBlockHash(), 0 /* start_height */, {} /* max_height */, reserver, false /* update */);
|
CWallet::ScanResult result = wallet->ScanForWalletTransactions(cchain.Genesis()->GetBlockHash(), /*start_height=*/0, /*max_height=*/{}, reserver, /*fUpdate=*/false, /*save_progress=*/false);
|
||||||
BOOST_CHECK_EQUAL(result.status, CWallet::ScanResult::SUCCESS);
|
BOOST_CHECK_EQUAL(result.status, CWallet::ScanResult::SUCCESS);
|
||||||
BOOST_CHECK_EQUAL(result.last_scanned_block, cchain.Tip()->GetBlockHash());
|
BOOST_CHECK_EQUAL(result.last_scanned_block, cchain.Tip()->GetBlockHash());
|
||||||
BOOST_CHECK_EQUAL(*result.last_scanned_height, cchain.Height());
|
BOOST_CHECK_EQUAL(*result.last_scanned_height, cchain.Height());
|
||||||
|
|||||||
@@ -112,7 +112,7 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup)
|
|||||||
AddKey(wallet, coinbaseKey);
|
AddKey(wallet, coinbaseKey);
|
||||||
WalletRescanReserver reserver(wallet);
|
WalletRescanReserver reserver(wallet);
|
||||||
reserver.reserve();
|
reserver.reserve();
|
||||||
CWallet::ScanResult result = wallet.ScanForWalletTransactions({} /* start_block */, 0 /* start_height */, {} /* max_height */, reserver, false /* update */);
|
CWallet::ScanResult result = wallet.ScanForWalletTransactions(/*start_block=*/{}, /*start_height=*/0, /*max_height=*/{}, reserver, /*fUpdate=*/false, /*save_progress=*/false);
|
||||||
BOOST_CHECK_EQUAL(result.status, CWallet::ScanResult::FAILURE);
|
BOOST_CHECK_EQUAL(result.status, CWallet::ScanResult::FAILURE);
|
||||||
BOOST_CHECK(result.last_failed_block.IsNull());
|
BOOST_CHECK(result.last_failed_block.IsNull());
|
||||||
BOOST_CHECK(result.last_scanned_block.IsNull());
|
BOOST_CHECK(result.last_scanned_block.IsNull());
|
||||||
@@ -132,7 +132,7 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup)
|
|||||||
AddKey(wallet, coinbaseKey);
|
AddKey(wallet, coinbaseKey);
|
||||||
WalletRescanReserver reserver(wallet);
|
WalletRescanReserver reserver(wallet);
|
||||||
reserver.reserve();
|
reserver.reserve();
|
||||||
CWallet::ScanResult result = wallet.ScanForWalletTransactions(oldTip->GetBlockHash(), oldTip->nHeight, {} /* max_height */, reserver, false /* update */);
|
CWallet::ScanResult result = wallet.ScanForWalletTransactions(/*start_block=*/oldTip->GetBlockHash(), /*start_height=*/oldTip->nHeight, /*max_height=*/{}, reserver, /*fUpdate=*/false, /*save_progress=*/false);
|
||||||
BOOST_CHECK_EQUAL(result.status, CWallet::ScanResult::SUCCESS);
|
BOOST_CHECK_EQUAL(result.status, CWallet::ScanResult::SUCCESS);
|
||||||
BOOST_CHECK(result.last_failed_block.IsNull());
|
BOOST_CHECK(result.last_failed_block.IsNull());
|
||||||
BOOST_CHECK_EQUAL(result.last_scanned_block, newTip->GetBlockHash());
|
BOOST_CHECK_EQUAL(result.last_scanned_block, newTip->GetBlockHash());
|
||||||
@@ -161,7 +161,7 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup)
|
|||||||
AddKey(wallet, coinbaseKey);
|
AddKey(wallet, coinbaseKey);
|
||||||
WalletRescanReserver reserver(wallet);
|
WalletRescanReserver reserver(wallet);
|
||||||
reserver.reserve();
|
reserver.reserve();
|
||||||
CWallet::ScanResult result = wallet.ScanForWalletTransactions(oldTip->GetBlockHash(), oldTip->nHeight, {} /* max_height */, reserver, false /* update */);
|
CWallet::ScanResult result = wallet.ScanForWalletTransactions(/*start_block=*/oldTip->GetBlockHash(), /*start_height=*/oldTip->nHeight, /*max_height=*/{}, reserver, /*fUpdate=*/false, /*save_progress=*/false);
|
||||||
BOOST_CHECK_EQUAL(result.status, CWallet::ScanResult::FAILURE);
|
BOOST_CHECK_EQUAL(result.status, CWallet::ScanResult::FAILURE);
|
||||||
BOOST_CHECK_EQUAL(result.last_failed_block, oldTip->GetBlockHash());
|
BOOST_CHECK_EQUAL(result.last_failed_block, oldTip->GetBlockHash());
|
||||||
BOOST_CHECK_EQUAL(result.last_scanned_block, newTip->GetBlockHash());
|
BOOST_CHECK_EQUAL(result.last_scanned_block, newTip->GetBlockHash());
|
||||||
@@ -188,7 +188,7 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup)
|
|||||||
AddKey(wallet, coinbaseKey);
|
AddKey(wallet, coinbaseKey);
|
||||||
WalletRescanReserver reserver(wallet);
|
WalletRescanReserver reserver(wallet);
|
||||||
reserver.reserve();
|
reserver.reserve();
|
||||||
CWallet::ScanResult result = wallet.ScanForWalletTransactions(oldTip->GetBlockHash(), oldTip->nHeight, {} /* max_height */, reserver, false /* update */);
|
CWallet::ScanResult result = wallet.ScanForWalletTransactions(/*start_block=*/oldTip->GetBlockHash(), /*start_height=*/oldTip->nHeight, /*max_height=*/{}, reserver, /*fUpdate=*/false, /*save_progress=*/false);
|
||||||
BOOST_CHECK_EQUAL(result.status, CWallet::ScanResult::FAILURE);
|
BOOST_CHECK_EQUAL(result.status, CWallet::ScanResult::FAILURE);
|
||||||
BOOST_CHECK_EQUAL(result.last_failed_block, newTip->GetBlockHash());
|
BOOST_CHECK_EQUAL(result.last_failed_block, newTip->GetBlockHash());
|
||||||
BOOST_CHECK(result.last_scanned_block.IsNull());
|
BOOST_CHECK(result.last_scanned_block.IsNull());
|
||||||
|
|||||||
+17
-5
@@ -1674,7 +1674,7 @@ int64_t CWallet::RescanFromTime(int64_t startTime, const WalletRescanReserver& r
|
|||||||
|
|
||||||
if (start) {
|
if (start) {
|
||||||
// TODO: this should take into account failure by ScanResult::USER_ABORT
|
// TODO: this should take into account failure by ScanResult::USER_ABORT
|
||||||
ScanResult result = ScanForWalletTransactions(start_block, start_height, {} /* max_height */, reserver, update);
|
ScanResult result = ScanForWalletTransactions(start_block, start_height, /*max_height=*/{}, reserver, /*fUpdate=*/update, /*save_progress=*/false);
|
||||||
if (result.status == ScanResult::FAILURE) {
|
if (result.status == ScanResult::FAILURE) {
|
||||||
int64_t time_max;
|
int64_t time_max;
|
||||||
CHECK_NONFATAL(chain().findBlock(result.last_failed_block, FoundBlock().maxTime(time_max)));
|
CHECK_NONFATAL(chain().findBlock(result.last_failed_block, FoundBlock().maxTime(time_max)));
|
||||||
@@ -1705,10 +1705,10 @@ int64_t CWallet::RescanFromTime(int64_t startTime, const WalletRescanReserver& r
|
|||||||
* 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.
|
||||||
*/
|
*/
|
||||||
CWallet::ScanResult CWallet::ScanForWalletTransactions(const uint256& start_block, int start_height, std::optional<int> max_height, const WalletRescanReserver& reserver, bool fUpdate)
|
CWallet::ScanResult CWallet::ScanForWalletTransactions(const uint256& start_block, int start_height, std::optional<int> max_height, const WalletRescanReserver& reserver, bool fUpdate, const bool save_progress)
|
||||||
{
|
{
|
||||||
using Clock = std::chrono::steady_clock;
|
using Clock = std::chrono::steady_clock;
|
||||||
constexpr auto LOG_INTERVAL{60s};
|
constexpr auto INTERVAL_TIME{60s};
|
||||||
auto current_time{Clock::now()};
|
auto current_time{Clock::now()};
|
||||||
auto start_time{Clock::now()};
|
auto start_time{Clock::now()};
|
||||||
|
|
||||||
@@ -1737,7 +1737,9 @@ CWallet::ScanResult CWallet::ScanForWalletTransactions(const uint256& start_bloc
|
|||||||
if (block_height % 100 == 0 && progress_end - progress_begin > 0.0) {
|
if (block_height % 100 == 0 && progress_end - progress_begin > 0.0) {
|
||||||
ShowProgress(strprintf("%s " + _("Rescanning…").translated, GetDisplayName()), std::max(1, std::min(99, (int)(m_scanning_progress * 100))));
|
ShowProgress(strprintf("%s " + _("Rescanning…").translated, GetDisplayName()), std::max(1, std::min(99, (int)(m_scanning_progress * 100))));
|
||||||
}
|
}
|
||||||
if (Clock::now() >= current_time + LOG_INTERVAL) {
|
|
||||||
|
bool next_interval = Clock::now() >= current_time + INTERVAL_TIME;
|
||||||
|
if (next_interval) {
|
||||||
current_time = Clock::now();
|
current_time = Clock::now();
|
||||||
WalletLogPrintf("Still rescanning. At block %d. Progress=%f\n", block_height, progress_current);
|
WalletLogPrintf("Still rescanning. At block %d. Progress=%f\n", block_height, progress_current);
|
||||||
}
|
}
|
||||||
@@ -1768,6 +1770,16 @@ CWallet::ScanResult CWallet::ScanForWalletTransactions(const uint256& start_bloc
|
|||||||
// scan succeeded, record block as most recent successfully scanned
|
// scan succeeded, record block as most recent successfully scanned
|
||||||
result.last_scanned_block = block_hash;
|
result.last_scanned_block = block_hash;
|
||||||
result.last_scanned_height = block_height;
|
result.last_scanned_height = block_height;
|
||||||
|
|
||||||
|
if (save_progress && next_interval) {
|
||||||
|
CBlockLocator loc = m_chain->getActiveChainLocator(block_hash);
|
||||||
|
|
||||||
|
if (!loc.IsNull()) {
|
||||||
|
WalletLogPrintf("Saving scan progress %d.\n", block_height);
|
||||||
|
WalletBatch batch(GetDatabase());
|
||||||
|
batch.WriteBestBlock(loc);
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// could not scan block, keep scanning but record this block as the most recent failure
|
// could not scan block, keep scanning but record this block as the most recent failure
|
||||||
result.last_failed_block = block_hash;
|
result.last_failed_block = block_hash;
|
||||||
@@ -3026,7 +3038,7 @@ bool CWallet::AttachChain(const std::shared_ptr<CWallet>& walletInstance, interf
|
|||||||
|
|
||||||
{
|
{
|
||||||
WalletRescanReserver reserver(*walletInstance);
|
WalletRescanReserver reserver(*walletInstance);
|
||||||
if (!reserver.reserve() || (ScanResult::SUCCESS != walletInstance->ScanForWalletTransactions(chain.getBlockHash(rescan_height), rescan_height, {} /* max height */, reserver, true /* update */).status)) {
|
if (!reserver.reserve() || (ScanResult::SUCCESS != walletInstance->ScanForWalletTransactions(chain.getBlockHash(rescan_height), rescan_height, /*max_height=*/{}, reserver, /*fUpdate=*/true, /*save_progress=*/true).status)) {
|
||||||
error = _("Failed to rescan the wallet during initialization");
|
error = _("Failed to rescan the wallet during initialization");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -528,7 +528,7 @@ public:
|
|||||||
//! USER_ABORT.
|
//! USER_ABORT.
|
||||||
uint256 last_failed_block;
|
uint256 last_failed_block;
|
||||||
};
|
};
|
||||||
ScanResult ScanForWalletTransactions(const uint256& start_block, int start_height, std::optional<int> max_height, const WalletRescanReserver& reserver, bool fUpdate);
|
ScanResult ScanForWalletTransactions(const uint256& start_block, int start_height, std::optional<int> max_height, const WalletRescanReserver& reserver, bool fUpdate, const bool save_progress);
|
||||||
void transactionRemovedFromMempool(const CTransactionRef& tx, MemPoolRemovalReason reason, uint64_t mempool_sequence) override;
|
void transactionRemovedFromMempool(const CTransactionRef& tx, MemPoolRemovalReason reason, uint64_t mempool_sequence) override;
|
||||||
void ReacceptWalletTransactions() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
void ReacceptWalletTransactions() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||||
void ResendWalletTransactions();
|
void ResendWalletTransactions();
|
||||||
|
|||||||
Reference in new issue
Block a user