Skip to content

Commit a89ddfb

Browse files
w0xltfurszyjonatackryanofsky
committed
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 <[email protected]> Co-authored-by: Jon Atack <[email protected]> Co-authored-by: Ryan Ofsky <[email protected]>
1 parent d4d9daf commit a89ddfb

File tree

8 files changed

+41
-18
lines changed

8 files changed

+41
-18
lines changed

src/interfaces/chain.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,10 @@ class Chain
111111
//! Get locator for the current chain tip.
112112
virtual CBlockLocator getTipLocator() = 0;
113113

114+
//! Return a locator that refers to a block in the active chain.
115+
//! If specified block is not in the active chain, return locator for the latest ancestor that is in the chain.
116+
virtual CBlockLocator getActiveChainLocator(const uint256& block_hash) = 0;
117+
114118
//! Return height of the highest block on chain in common with the locator,
115119
//! which will either be the original block used to create the locator,
116120
//! or one of its ancestors.

src/node/interfaces.cpp

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -516,20 +516,27 @@ class ChainImpl : public Chain
516516
}
517517
bool haveBlockOnDisk(int height) override
518518
{
519-
LOCK(cs_main);
519+
LOCK(::cs_main);
520520
const CChain& active = Assert(m_node.chainman)->ActiveChain();
521521
CBlockIndex* block = active[height];
522522
return block && ((block->nStatus & BLOCK_HAVE_DATA) != 0) && block->nTx > 0;
523523
}
524524
CBlockLocator getTipLocator() override
525525
{
526-
LOCK(cs_main);
526+
LOCK(::cs_main);
527527
const CChain& active = Assert(m_node.chainman)->ActiveChain();
528528
return active.GetLocator();
529529
}
530+
CBlockLocator getActiveChainLocator(const uint256& block_hash) override
531+
{
532+
LOCK(::cs_main);
533+
const CBlockIndex* index = chainman().m_blockman.LookupBlockIndex(block_hash);
534+
if (!index) return {};
535+
return chainman().ActiveChain().GetLocator(index);
536+
}
530537
std::optional<int> findLocatorFork(const CBlockLocator& locator) override
531538
{
532-
LOCK(cs_main);
539+
LOCK(::cs_main);
533540
const CChainState& active = Assert(m_node.chainman)->ActiveChainstate();
534541
if (const CBlockIndex* fork = active.FindForkInGlobalIndex(locator)) {
535542
return fork->nHeight;
@@ -585,7 +592,7 @@ class ChainImpl : public Chain
585592
void findCoins(std::map<COutPoint, Coin>& coins) override { return FindCoins(m_node, coins); }
586593
double guessVerificationProgress(const uint256& block_hash) override
587594
{
588-
LOCK(cs_main);
595+
LOCK(::cs_main);
589596
return GuessVerificationProgress(chainman().GetParams().TxData(), chainman().m_blockman.LookupBlockIndex(block_hash));
590597
}
591598
bool hasBlocks(const uint256& block_hash, int min_height, std::optional<int> max_height) override
@@ -684,7 +691,7 @@ class ChainImpl : public Chain
684691
CFeeRate relayDustFee() override { return ::dustRelayFee; }
685692
bool havePruned() override
686693
{
687-
LOCK(cs_main);
694+
LOCK(::cs_main);
688695
return m_node.chainman->m_blockman.m_have_pruned;
689696
}
690697
bool isReadyToBroadcast() override { return !node::fImporting && !node::fReindex && !isInitialBlockDownload(); }

src/qt/test/wallettests.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ void TestGUI(interfaces::Node& node)
173173
{
174174
WalletRescanReserver reserver(*wallet);
175175
reserver.reserve();
176-
CWallet::ScanResult result = wallet->ScanForWalletTransactions(Params().GetConsensus().hashGenesisBlock, 0 /* block height */, {} /* max height */, reserver, true /* fUpdate */);
176+
CWallet::ScanResult result = wallet->ScanForWalletTransactions(Params().GetConsensus().hashGenesisBlock, /*start_height=*/0, /*max_height=*/{}, reserver, /*fUpdate=*/true, /*save_progress=*/false);
177177
QCOMPARE(result.status, CWallet::ScanResult::SUCCESS);
178178
QCOMPARE(result.last_scanned_block, node.context()->chainman->ActiveChain().Tip()->GetBlockHash());
179179
QVERIFY(result.last_failed_block.IsNull());

src/wallet/rpc/transactions.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -908,7 +908,7 @@ RPCHelpMan rescanblockchain()
908908
}
909909

910910
CWallet::ScanResult result =
911-
pwallet->ScanForWalletTransactions(start_block, start_height, stop_height, reserver, true /* fUpdate */);
911+
pwallet->ScanForWalletTransactions(start_block, start_height, stop_height, reserver, /*fUpdate=*/true, /*save_progress=*/false);
912912
switch (result.status) {
913913
case CWallet::ScanResult::SUCCESS:
914914
break;

src/wallet/test/util.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ std::unique_ptr<CWallet> CreateSyncedWallet(interfaces::Chain& chain, CChain& cc
3838
}
3939
WalletRescanReserver reserver(*wallet);
4040
reserver.reserve();
41-
CWallet::ScanResult result = wallet->ScanForWalletTransactions(cchain.Genesis()->GetBlockHash(), 0 /* start_height */, {} /* max_height */, reserver, false /* update */);
41+
CWallet::ScanResult result = wallet->ScanForWalletTransactions(cchain.Genesis()->GetBlockHash(), /*start_height=*/0, /*max_height=*/{}, reserver, /*fUpdate=*/false, /*save_progress=*/false);
4242
BOOST_CHECK_EQUAL(result.status, CWallet::ScanResult::SUCCESS);
4343
BOOST_CHECK_EQUAL(result.last_scanned_block, cchain.Tip()->GetBlockHash());
4444
BOOST_CHECK_EQUAL(*result.last_scanned_height, cchain.Height());

src/wallet/test/wallet_tests.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup)
112112
AddKey(wallet, coinbaseKey);
113113
WalletRescanReserver reserver(wallet);
114114
reserver.reserve();
115-
CWallet::ScanResult result = wallet.ScanForWalletTransactions({} /* start_block */, 0 /* start_height */, {} /* max_height */, reserver, false /* update */);
115+
CWallet::ScanResult result = wallet.ScanForWalletTransactions(/*start_block=*/{}, /*start_height=*/0, /*max_height=*/{}, reserver, /*fUpdate=*/false, /*save_progress=*/false);
116116
BOOST_CHECK_EQUAL(result.status, CWallet::ScanResult::FAILURE);
117117
BOOST_CHECK(result.last_failed_block.IsNull());
118118
BOOST_CHECK(result.last_scanned_block.IsNull());
@@ -132,7 +132,7 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup)
132132
AddKey(wallet, coinbaseKey);
133133
WalletRescanReserver reserver(wallet);
134134
reserver.reserve();
135-
CWallet::ScanResult result = wallet.ScanForWalletTransactions(oldTip->GetBlockHash(), oldTip->nHeight, {} /* max_height */, reserver, false /* update */);
135+
CWallet::ScanResult result = wallet.ScanForWalletTransactions(/*start_block=*/oldTip->GetBlockHash(), /*start_height=*/oldTip->nHeight, /*max_height=*/{}, reserver, /*fUpdate=*/false, /*save_progress=*/false);
136136
BOOST_CHECK_EQUAL(result.status, CWallet::ScanResult::SUCCESS);
137137
BOOST_CHECK(result.last_failed_block.IsNull());
138138
BOOST_CHECK_EQUAL(result.last_scanned_block, newTip->GetBlockHash());
@@ -161,7 +161,7 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup)
161161
AddKey(wallet, coinbaseKey);
162162
WalletRescanReserver reserver(wallet);
163163
reserver.reserve();
164-
CWallet::ScanResult result = wallet.ScanForWalletTransactions(oldTip->GetBlockHash(), oldTip->nHeight, {} /* max_height */, reserver, false /* update */);
164+
CWallet::ScanResult result = wallet.ScanForWalletTransactions(/*start_block=*/oldTip->GetBlockHash(), /*start_height=*/oldTip->nHeight, /*max_height=*/{}, reserver, /*fUpdate=*/false, /*save_progress=*/false);
165165
BOOST_CHECK_EQUAL(result.status, CWallet::ScanResult::FAILURE);
166166
BOOST_CHECK_EQUAL(result.last_failed_block, oldTip->GetBlockHash());
167167
BOOST_CHECK_EQUAL(result.last_scanned_block, newTip->GetBlockHash());
@@ -188,7 +188,7 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup)
188188
AddKey(wallet, coinbaseKey);
189189
WalletRescanReserver reserver(wallet);
190190
reserver.reserve();
191-
CWallet::ScanResult result = wallet.ScanForWalletTransactions(oldTip->GetBlockHash(), oldTip->nHeight, {} /* max_height */, reserver, false /* update */);
191+
CWallet::ScanResult result = wallet.ScanForWalletTransactions(/*start_block=*/oldTip->GetBlockHash(), /*start_height=*/oldTip->nHeight, /*max_height=*/{}, reserver, /*fUpdate=*/false, /*save_progress=*/false);
192192
BOOST_CHECK_EQUAL(result.status, CWallet::ScanResult::FAILURE);
193193
BOOST_CHECK_EQUAL(result.last_failed_block, newTip->GetBlockHash());
194194
BOOST_CHECK(result.last_scanned_block.IsNull());

src/wallet/wallet.cpp

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1674,7 +1674,7 @@ int64_t CWallet::RescanFromTime(int64_t startTime, const WalletRescanReserver& r
16741674

16751675
if (start) {
16761676
// TODO: this should take into account failure by ScanResult::USER_ABORT
1677-
ScanResult result = ScanForWalletTransactions(start_block, start_height, {} /* max_height */, reserver, update);
1677+
ScanResult result = ScanForWalletTransactions(start_block, start_height, /*max_height=*/{}, reserver, /*fUpdate=*/update, /*save_progress=*/false);
16781678
if (result.status == ScanResult::FAILURE) {
16791679
int64_t time_max;
16801680
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
17051705
* the main chain after to the addition of any new keys you want to detect
17061706
* transactions for.
17071707
*/
1708-
CWallet::ScanResult CWallet::ScanForWalletTransactions(const uint256& start_block, int start_height, std::optional<int> max_height, const WalletRescanReserver& reserver, bool fUpdate)
1708+
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)
17091709
{
17101710
using Clock = std::chrono::steady_clock;
1711-
constexpr auto LOG_INTERVAL{60s};
1711+
constexpr auto INTERVAL_TIME{60s};
17121712
auto current_time{Clock::now()};
17131713
auto start_time{Clock::now()};
17141714

@@ -1737,7 +1737,9 @@ CWallet::ScanResult CWallet::ScanForWalletTransactions(const uint256& start_bloc
17371737
if (block_height % 100 == 0 && progress_end - progress_begin > 0.0) {
17381738
ShowProgress(strprintf("%s " + _("Rescanning…").translated, GetDisplayName()), std::max(1, std::min(99, (int)(m_scanning_progress * 100))));
17391739
}
1740-
if (Clock::now() >= current_time + LOG_INTERVAL) {
1740+
1741+
bool next_interval = Clock::now() >= current_time + INTERVAL_TIME;
1742+
if (next_interval) {
17411743
current_time = Clock::now();
17421744
WalletLogPrintf("Still rescanning. At block %d. Progress=%f\n", block_height, progress_current);
17431745
}
@@ -1768,6 +1770,16 @@ CWallet::ScanResult CWallet::ScanForWalletTransactions(const uint256& start_bloc
17681770
// scan succeeded, record block as most recent successfully scanned
17691771
result.last_scanned_block = block_hash;
17701772
result.last_scanned_height = block_height;
1773+
1774+
if (save_progress && next_interval) {
1775+
CBlockLocator loc = m_chain->getActiveChainLocator(block_hash);
1776+
1777+
if (!loc.IsNull()) {
1778+
WalletLogPrintf("Saving scan progress %d.\n", block_height);
1779+
WalletBatch batch(GetDatabase());
1780+
batch.WriteBestBlock(loc);
1781+
}
1782+
}
17711783
} else {
17721784
// could not scan block, keep scanning but record this block as the most recent failure
17731785
result.last_failed_block = block_hash;
@@ -3026,7 +3038,7 @@ bool CWallet::AttachChain(const std::shared_ptr<CWallet>& walletInstance, interf
30263038

30273039
{
30283040
WalletRescanReserver reserver(*walletInstance);
3029-
if (!reserver.reserve() || (ScanResult::SUCCESS != walletInstance->ScanForWalletTransactions(chain.getBlockHash(rescan_height), rescan_height, {} /* max height */, reserver, true /* update */).status)) {
3041+
if (!reserver.reserve() || (ScanResult::SUCCESS != walletInstance->ScanForWalletTransactions(chain.getBlockHash(rescan_height), rescan_height, /*max_height=*/{}, reserver, /*fUpdate=*/true, /*save_progress=*/true).status)) {
30303042
error = _("Failed to rescan the wallet during initialization");
30313043
return false;
30323044
}

src/wallet/wallet.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -528,7 +528,7 @@ class CWallet final : public WalletStorage, public interfaces::Chain::Notificati
528528
//! USER_ABORT.
529529
uint256 last_failed_block;
530530
};
531-
ScanResult ScanForWalletTransactions(const uint256& start_block, int start_height, std::optional<int> max_height, const WalletRescanReserver& reserver, bool fUpdate);
531+
ScanResult ScanForWalletTransactions(const uint256& start_block, int start_height, std::optional<int> max_height, const WalletRescanReserver& reserver, bool fUpdate, const bool save_progress);
532532
void transactionRemovedFromMempool(const CTransactionRef& tx, MemPoolRemovalReason reason, uint64_t mempool_sequence) override;
533533
void ReacceptWalletTransactions() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
534534
void ResendWalletTransactions();

0 commit comments

Comments
 (0)