Skip to content

Commit 555ea01

Browse files
committed
wallet/scan: combine block iteration and filtering in ReadNextBlocks
This commit refactors the block filtering logic from ShouldFetchBlock into a new ReadNextBlocks method that works with a queue of blocks (m_blocks). This prepares the code for parallel block filter checking while keeping the current single-threaded behaviour.
1 parent 881ebc4 commit 555ea01

File tree

2 files changed

+69
-39
lines changed

2 files changed

+69
-39
lines changed

src/wallet/scan.cpp

Lines changed: 56 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -130,19 +130,30 @@ std::optional<std::pair<uint256, int>> ChainScanner::ReadNextBlock(ScanResult& r
130130
return std::make_pair(block_hash, block_height);
131131
}
132132

133-
bool ChainScanner::ShouldFetchBlock(const std::unique_ptr<FastWalletRescanFilter>& filter, const uint256& block_hash, int block_height) {
133+
std::optional<std::pair<size_t, size_t>> ChainScanner::ReadNextBlocks(const std::unique_ptr<FastWalletRescanFilter>& filter, ScanResult& result) {
134+
auto next_block = ReadNextBlock(result);
135+
if (next_block) m_blocks.emplace_back(*next_block);
136+
else return std::nullopt;
137+
138+
if (!filter) {
139+
// Slow scan: scan all blocks.
140+
return std::make_pair<size_t, size_t>(0, 1);
141+
}
142+
143+
filter->UpdateIfNeeded();
144+
145+
const auto& [block_hash, block_height] = m_blocks[0];
134146
auto matches_block{filter->MatchesBlock(block_hash)};
135-
if (matches_block.has_value()) {
136-
if (*matches_block) {
137-
LogDebug(BCLog::SCAN, "Fast rescan: inspect block %d [%s] (filter matched)\n", block_height, block_hash.ToString());
138-
return true;
139-
} else {
140-
return false;
141-
}
142-
} else {
147+
148+
if (matches_block.has_value() && *matches_block) {
149+
LogDebug(BCLog::SCAN, "Fast rescan: inspect block %d [%s] (filter matched)\n", block_height, block_hash.ToString());
150+
return std::make_pair<size_t, size_t>(0, 1);
151+
} else if (!matches_block.has_value()) {
143152
LogDebug(BCLog::SCAN, "Fast rescan: inspect block %d [%s] (WARNING: block filter not found!)\n", block_height, block_hash.ToString());
144-
return true;
153+
return std::make_pair<size_t, size_t>(0, 1);
145154
}
155+
156+
return std::nullopt;
146157
}
147158

148159
void ChainScanner::UpdateProgress(int block_height) {
@@ -166,18 +177,13 @@ void ChainScanner::UpdateTipIfChanged() {
166177
}
167178
}
168179

169-
void ChainScanner::ProcessBlock(const uint256& block_hash, int block_height, bool fetch_block, bool next_interval, ScanResult& result) {
170-
if (fetch_block) {
171-
if (ScanBlock(block_hash, block_height, m_save_progress && next_interval)) {
172-
result.last_scanned_block = block_hash;
173-
result.last_scanned_height = block_height;
174-
} else {
175-
result.last_failed_block = block_hash;
176-
result.status = ScanResult::FAILURE;
177-
}
178-
} else {
180+
void ChainScanner::ProcessBlock(const uint256& block_hash, int block_height, bool next_interval, ScanResult& result) {
181+
if (ScanBlock(block_hash, block_height, m_save_progress && next_interval)) {
179182
result.last_scanned_block = block_hash;
180183
result.last_scanned_height = block_height;
184+
} else {
185+
result.last_failed_block = block_hash;
186+
result.status = ScanResult::FAILURE;
181187
}
182188
}
183189

@@ -239,26 +245,40 @@ ScanResult ChainScanner::Scan() {
239245
int block_height = m_start_height;
240246
m_next_block = {{m_start_block, m_start_height}};
241247

242-
while (!m_wallet.fAbortRescan && !chain.shutdownRequested()) {
243-
auto current_block = ReadNextBlock(result);
244-
if (!current_block) break;
245-
246-
const auto& [block_hash, block_height] = *current_block;
248+
while ((m_next_block || !m_blocks.empty()) && !m_wallet.fAbortRescan && !chain.shutdownRequested()) {
249+
uint256 block_hash;
250+
auto range = ReadNextBlocks(fast_rescan_filter, result);
251+
252+
// If no blocks to scan, mark current batch as scanned
253+
size_t start_index = range.has_value() ? range->first : m_blocks.size();
254+
size_t end_index = range.has_value() ? range->second : m_blocks.size();
255+
if (start_index > 0) {
256+
// Some blocks at the start of the batch were skipped.
257+
// Update last scanned block to indicate that these
258+
// blocks have been scanned.
259+
block_hash = m_blocks[start_index - 1].first;
260+
block_height = m_blocks[start_index - 1].second;
261+
result.last_scanned_block = block_hash;
262+
result.last_scanned_height = block_height;
263+
}
247264

248-
UpdateProgress(block_height);
265+
for (size_t i = start_index; i < end_index; ++i) {
266+
block_hash = m_blocks[i].first;
267+
block_height = m_blocks[i].second;
249268

250-
bool next_interval = m_reserver.now() >= current_time + INTERVAL_TIME;
251-
if (next_interval) {
252-
current_time = m_reserver.now();
253-
m_wallet.WalletLogPrintf("Still rescanning. At block %d. Progress=%f\n", block_height, m_progress_current);
254-
}
269+
UpdateProgress(block_height);
255270

256-
bool fetch_block = !fast_rescan_filter ||
257-
(fast_rescan_filter->UpdateIfNeeded(), ShouldFetchBlock(fast_rescan_filter, block_hash, block_height));
271+
bool next_interval = m_reserver.now() >= current_time + INTERVAL_TIME;
272+
if (next_interval) {
273+
current_time = m_reserver.now();
274+
m_wallet.WalletLogPrintf("Still rescanning. At block %d. Progress=%f\n", block_height, m_progress_current);
275+
}
258276

259-
ProcessBlock(block_hash, block_height, fetch_block, next_interval, result);
260-
m_progress_current = chain.guessVerificationProgress(block_hash);
261-
if (!m_max_height) UpdateTipIfChanged();
277+
ProcessBlock(block_hash, block_height, next_interval, result);
278+
m_progress_current = chain.guessVerificationProgress(block_hash);
279+
if (!m_max_height) UpdateTipIfChanged();
280+
}
281+
m_blocks.erase(m_blocks.begin(), m_blocks.begin() + end_index);
262282
}
263283
if (!m_max_height) {
264284
m_wallet.WalletLogPrintf("Scanning current mempool transactions.\n");

src/wallet/scan.h

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,20 @@ class ChainScanner {
3838
double m_progress_current{0};
3939
uint256 m_tip_hash;
4040

41+
/// Queued block hashes and heights to filter and scan
42+
std::vector<std::pair<uint256, int>> m_blocks;
43+
size_t m_max_blockqueue_size{1000};
44+
4145
std::optional<std::pair<uint256, int>> ReadNextBlock(ScanResult& result);
42-
bool ShouldFetchBlock(const std::unique_ptr<FastWalletRescanFilter>& filter, const uint256& block_hash, int block_height);
46+
/**
47+
* @return a pair of indexes into the m_blocks array that specify a range of blocks
48+
* to scan (end index excluded) or std::nullopt if no blocks should be scanned.
49+
*/
50+
std::optional<std::pair<size_t, size_t>> ReadNextBlocks(const std::unique_ptr<FastWalletRescanFilter>& filter, ScanResult& result);
4351
bool ScanBlock(const uint256& block_hash, int block_height, bool save_progress);
4452
void UpdateProgress(int block_height);
4553
void UpdateTipIfChanged();
46-
void ProcessBlock(const uint256& block_hash, int block_height, bool fetch_block, bool next_interval, ScanResult& result);
54+
void ProcessBlock(const uint256& block_hash, int block_height, bool next_interval, ScanResult& result);
4755

4856
public:
4957
ChainScanner(CWallet& wallet, const WalletRescanReserver& reserver, const uint256& start_block, int start_height,
@@ -54,7 +62,9 @@ class ChainScanner {
5462
m_start_height(start_height),
5563
m_max_height(max_height),
5664
m_fUpdate(fUpdate),
57-
m_save_progress(save_progress) {}
65+
m_save_progress(save_progress) {
66+
m_blocks.reserve(m_max_blockqueue_size);
67+
}
5868

5969
ScanResult Scan();
6070

0 commit comments

Comments
 (0)