Skip to content

Commit ce50acc

Browse files
committed
rpc: scanblocks, do not traverse the whole chain block by block
The current flow walks-through every block in the active chain until hits the chain tip or processes 10k blocks, then calls `lookupFilterRange()` to obtain all the filters from that particular range. This is only done to obtain the heights range to look up the block filters. Which is unneeded. As `scanblocks` only lookup block filters in the active chain, we can directly calculate the lookup range heights, by using the chain tip, without requiring to traverse the chain block by block.
1 parent 3ce7b27 commit ce50acc

File tree

1 file changed

+50
-50
lines changed

1 file changed

+50
-50
lines changed

src/rpc/blockchain.cpp

Lines changed: 50 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -2383,27 +2383,28 @@ static RPCHelpMan scanblocks()
23832383
ChainstateManager& chainman = EnsureChainman(node);
23842384

23852385
// set the start-height
2386-
const CBlockIndex* block = nullptr;
2386+
const CBlockIndex* start_index = nullptr;
23872387
const CBlockIndex* stop_block = nullptr;
23882388
{
23892389
LOCK(cs_main);
23902390
CChain& active_chain = chainman.ActiveChain();
2391-
block = active_chain.Genesis();
2392-
stop_block = active_chain.Tip();
2391+
start_index = active_chain.Genesis();
2392+
stop_block = active_chain.Tip(); // If no stop block is provided, stop at the chain tip.
23932393
if (!request.params[2].isNull()) {
2394-
block = active_chain[request.params[2].getInt<int>()];
2395-
if (!block) {
2394+
start_index = active_chain[request.params[2].getInt<int>()];
2395+
if (!start_index) {
23962396
throw JSONRPCError(RPC_MISC_ERROR, "Invalid start_height");
23972397
}
23982398
}
23992399
if (!request.params[3].isNull()) {
24002400
stop_block = active_chain[request.params[3].getInt<int>()];
2401-
if (!stop_block || stop_block->nHeight < block->nHeight) {
2401+
if (!stop_block || stop_block->nHeight < start_index->nHeight) {
24022402
throw JSONRPCError(RPC_MISC_ERROR, "Invalid stop_height");
24032403
}
24042404
}
24052405
}
2406-
CHECK_NONFATAL(block);
2406+
CHECK_NONFATAL(start_index);
2407+
CHECK_NONFATAL(stop_block);
24072408

24082409
// loop through the scan objects, add scripts to the needle_set
24092410
GCSFilter::ElementSet needle_set;
@@ -2416,63 +2417,62 @@ static RPCHelpMan scanblocks()
24162417
}
24172418
UniValue blocks(UniValue::VARR);
24182419
const int amount_per_chunk = 10000;
2419-
const CBlockIndex* start_index = block; // for remembering the start of a blockfilter range
24202420
std::vector<BlockFilter> filters;
2421-
const CBlockIndex* start_block = block; // for progress reporting
2422-
const int total_blocks_to_process = stop_block->nHeight - start_block->nHeight;
2421+
int start_block_height = start_index->nHeight; // for progress reporting
2422+
const int total_blocks_to_process = stop_block->nHeight - start_block_height;
24232423

24242424
g_scanfilter_should_abort_scan = false;
24252425
g_scanfilter_progress = 0;
2426-
g_scanfilter_progress_height = start_block->nHeight;
2426+
g_scanfilter_progress_height = start_block_height;
24272427

2428-
while (block) {
2428+
const CBlockIndex* end_range = nullptr;
2429+
do {
24292430
node.rpc_interruption_point(); // allow a clean shutdown
24302431
if (g_scanfilter_should_abort_scan) {
2431-
LogPrintf("scanblocks RPC aborted at height %d.\n", block->nHeight);
2432+
LogPrintf("scanblocks RPC aborted at height %d.\n", end_range->nHeight);
24322433
break;
24332434
}
2434-
const CBlockIndex* next = nullptr;
2435-
{
2436-
LOCK(cs_main);
2437-
CChain& active_chain = chainman.ActiveChain();
2438-
next = active_chain.Next(block);
2439-
if (block == stop_block) next = nullptr;
2440-
}
2441-
if (start_index->nHeight + amount_per_chunk == block->nHeight || next == nullptr) {
2442-
LogPrint(BCLog::RPC, "Fetching blockfilters from height %d to height %d.\n", start_index->nHeight, block->nHeight);
2443-
if (index->LookupFilterRange(start_index->nHeight, block, filters)) {
2444-
for (const BlockFilter& filter : filters) {
2445-
// compare the elements-set with each filter
2446-
if (filter.GetFilter().MatchAny(needle_set)) {
2447-
if (filter_false_positives) {
2448-
// Double check the filter matches by scanning the block
2449-
const CBlockIndex& blockindex = *CHECK_NONFATAL(WITH_LOCK(cs_main, return chainman.m_blockman.LookupBlockIndex(filter.GetBlockHash())));
2450-
2451-
if (!CheckBlockFilterMatches(chainman.m_blockman, blockindex, needle_set)) {
2452-
continue;
2453-
}
2454-
}
24552435

2456-
blocks.push_back(filter.GetBlockHash().GetHex());
2457-
LogPrint(BCLog::RPC, "scanblocks: found match in %s\n", filter.GetBlockHash().GetHex());
2436+
// split the lookup range in chunks if we are deeper than 'amount_per_chunk' blocks from the stopping block
2437+
int start_block = !end_range ? start_index->nHeight : start_index->nHeight + 1; // to not include the previous round 'end_range' block
2438+
end_range = (start_block + amount_per_chunk < stop_block->nHeight) ?
2439+
WITH_LOCK(::cs_main, return chainman.ActiveChain()[start_block + amount_per_chunk]) :
2440+
stop_block;
2441+
2442+
if (index->LookupFilterRange(start_block, end_range, filters)) {
2443+
for (const BlockFilter& filter : filters) {
2444+
// compare the elements-set with each filter
2445+
if (filter.GetFilter().MatchAny(needle_set)) {
2446+
if (filter_false_positives) {
2447+
// Double check the filter matches by scanning the block
2448+
const CBlockIndex& blockindex = *CHECK_NONFATAL(WITH_LOCK(cs_main, return chainman.m_blockman.LookupBlockIndex(filter.GetBlockHash())));
2449+
2450+
if (!CheckBlockFilterMatches(chainman.m_blockman, blockindex, needle_set)) {
2451+
continue;
2452+
}
24582453
}
2454+
2455+
blocks.push_back(filter.GetBlockHash().GetHex());
2456+
LogPrint(BCLog::RPC, "scanblocks: found match in %s\n", filter.GetBlockHash().GetHex());
24592457
}
24602458
}
2461-
start_index = block;
2462-
2463-
// update progress
2464-
int blocks_processed = block->nHeight - start_block->nHeight;
2465-
if (total_blocks_to_process > 0) { // avoid division by zero
2466-
g_scanfilter_progress = (int)(100.0 / total_blocks_to_process * blocks_processed);
2467-
} else {
2468-
g_scanfilter_progress = 100;
2469-
}
2470-
g_scanfilter_progress_height = block->nHeight;
24712459
}
2472-
block = next;
2473-
}
2474-
ret.pushKV("from_height", start_block->nHeight);
2475-
ret.pushKV("to_height", g_scanfilter_progress_height.load());
2460+
start_index = end_range;
2461+
2462+
// update progress
2463+
int blocks_processed = end_range->nHeight - start_block_height;
2464+
if (total_blocks_to_process > 0) { // avoid division by zero
2465+
g_scanfilter_progress = (int)(100.0 / total_blocks_to_process * blocks_processed);
2466+
} else {
2467+
g_scanfilter_progress = 100;
2468+
}
2469+
g_scanfilter_progress_height = end_range->nHeight;
2470+
2471+
// Finish if we reached the stop block
2472+
} while (start_index != stop_block);
2473+
2474+
ret.pushKV("from_height", start_block_height);
2475+
ret.pushKV("to_height", stop_block->nHeight);
24762476
ret.pushKV("relevant_blocks", blocks);
24772477
}
24782478
else {

0 commit comments

Comments
 (0)