What changed, and why it matters
This commit only adds a new unit test to Bitcoin Core's wallet test suite. It verifies that the wallet's rescan-abort mechanism behaves correctly in two scenarios: an abort requested before any rescan starts should not accidentally cancel a later scan, and an abort requested after a reservation but before the scan begins should cancel the scan. There is no change to production code, no bug fix, and no security-relevant behavior introduced.
No security action needed. Treat as routine test coverage improvement.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The diff adds BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions_abort, TestChain100Setup) to src/wallet/test/wallet_tests.cpp. The test constructs a descriptor wallet, calls AbortRescan() with no active rescan, reserves a rescan, confirms IsAbortingRescan() is false, then calls AbortRescan() again before ScanForWalletTransactions() and asserts the scan returns USER_ABORT with no blocks scanned. No wallet implementation code is modified.
Changed components
src/wallet/test/wallet_tests.cppInspect captured patch +30 / −0
diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp
index 9d890c8f..51b18740 100644
--- a/src/wallet/test/wallet_tests.cpp
+++ b/src/wallet/test/wallet_tests.cpp
@@ -213,6 +213,36 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup)
}
}
+BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions_abort, TestChain100Setup)
+{
+ CWallet wallet(m_node.chain.get(), "", CreateMockableWalletDatabase());
+ uint256 genesis_hash;
+ {
+ LOCK(wallet.cs_wallet);
+ LOCK(Assert(m_node.chainman)->GetMutex());
+ wallet.SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
+ wallet.SetLastBlockProcessed(m_node.chainman->ActiveChain().Height(), m_node.chainman->ActiveChain().Tip()->GetBlockHash());
+ genesis_hash = m_node.chainman->ActiveChain().Genesis()->GetBlockHash();
+ }
+
+ // An abort requested while no rescan is held is stale and must
+ // not cancel a later scan.
+ wallet.AbortRescan();
+ WalletRescanReserver reserver(wallet);
+ BOOST_CHECK(reserver.reserve());
+ BOOST_CHECK(!wallet.IsAbortingRescan());
+
+ // An abort requested after the reservation but before the scan starts
+ // (e.g. while importdescriptors is still deriving keys) must cancel the
+ // scan.
+ wallet.AbortRescan();
+ CWallet::ScanResult result = wallet.ScanForWalletTransactions(genesis_hash, /*start_height=*/0, /*max_height=*/{}, reserver, /*save_progress=*/false);
+ BOOST_CHECK_EQUAL(result.status, CWallet::ScanResult::USER_ABORT);
+ BOOST_CHECK(result.last_scanned_block.IsNull());
+ BOOST_CHECK(!result.last_scanned_height);
+ BOOST_CHECK(result.last_failed_block.IsNull());
+}
+
// This test verifies that wallet settings can be added and removed
// concurrently, ensuring no race conditions occur during either process.
BOOST_FIXTURE_TEST_CASE(write_wallet_settings_concurrently, TestingSetup)
Why this scored 15/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.