wallet: move fAbortRescan reset into WalletRescanReserver reserve()
What changed, and why it matters
This Bitcoin Core wallet patch fixes a small but real timing bug: if a user clicked 'abort rescan' at exactly the wrong moment, the abort signal could be ignored and the rescan would keep running. The fix moves the 'clear any old abort signal' step to the moment the rescan reservation is taken, so a fresh abort request is always honored. It is a reliability/usability bug, not a theft-of-funds vulnerability.
Treat as a normal bug-fix patch. No urgent security response required. Users who trigger wallet rescans and rely on the abort button will get more reliable behavior. Backporting to maintained release branches is reasonable if the affected code path is present.
Security signals we found
Race condition in abort handling
State not reset at correct lifecycle boundary
User-initiated abort could be ignored
No cryptographic or network attack surface
Evidence from the diff
The commit moves the reset of CWallet::fAbortRescan from the start of ScanForWalletTransactions() into WalletRescanReserver::reserve(). Previously, fAbortRescan was reset after the rescan had already begun looping; an abort request arriving between reservation and loop start could set fAbortRescan=true, then be cleared by the reset, causing the abort to be lost. The patch also removes the block_height truthiness guards on the abort/shutdown branches so the result status is set even when no blocks were scanned. This is a correctness fix for a race condition in wallet rescan lifecycle management.
Changed components
src/wallet/wallet.cppsrc/wallet/wallet.hWalletRescanReserverCWallet::ScanForWalletTransactionsInspect captured patch +6 / −3
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index bb79dd47..8d502049 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -1884,7 +1884,6 @@ CWallet::ScanResult CWallet::ScanForWalletTransactions(const uint256& start_bloc
WalletLogPrintf("Rescan started from block %s... (%s)\n", start_block.ToString(),
fast_rescan_filter ? "fast variant using block filters" : "slow variant inspecting all blocks");
- fAbortRescan = false;
ShowProgress(strprintf("[%s] %s", DisplayName(), _("Rescanning…")), 0); // show rescan progress in GUI as dialog or on splashscreen, if rescan required on startup (e.g. due to corruption)
uint256 tip_hash = WITH_LOCK(cs_wallet, return GetLastBlockHash());
uint256 end_hash = tip_hash;
@@ -2006,10 +2005,10 @@ CWallet::ScanResult CWallet::ScanForWalletTransactions(const uint256& start_bloc
WITH_LOCK(cs_wallet, chain().requestMempoolTransactions(*this));
}
ShowProgress(strprintf("[%s] %s", DisplayName(), _("Rescanning…")), 100); // hide progress dialog in GUI
- if (block_height && fAbortRescan) {
+ if (fAbortRescan) {
WalletLogPrintf("Rescan aborted at block %d. Progress=%f\n", block_height, progress_current);
result.status = ScanResult::USER_ABORT;
- } else if (block_height && chain().shutdownRequested()) {
+ } else if (chain().shutdownRequested()) {
WalletLogPrintf("Rescan interrupted by shutdown request at block %d. Progress=%f\n", block_height, progress_current);
result.status = ScanResult::USER_ABORT;
} else {
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index 54bc60f5..62fba7b4 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -1103,6 +1103,10 @@ public:
if (m_wallet.fScanningWallet.exchange(true)) {
return false;
}
+ // Discard any abort request left over from previous reservation, so
+ // that an abort requested while the reservation is held always applies
+ // to abort this rescan, even if it arrives before the scan loop starts.
+ m_wallet.fAbortRescan = false;
m_wallet.m_scanning_with_passphrase.exchange(with_passphrase);
m_wallet.m_scanning_start = SteadyClock::now();
m_wallet.m_scanning_progress = 0;
Why this scored 33/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.