@@ -2325,6 +2325,7 @@ static RPCHelpMan scanblocks()
2325
2325
{RPCResult::Type::ARR, " relevant_blocks" , " Blocks that may have matched a scanobject." , {
2326
2326
{RPCResult::Type::STR_HEX, " blockhash" , " A relevant blockhash" },
2327
2327
}},
2328
+ {RPCResult::Type::BOOL, " completed" , " true if the scan process was not aborted" }
2328
2329
}},
2329
2330
RPCResult{" when action=='status' and a scan is currently in progress" , RPCResult::Type::OBJ, " " , " " , {
2330
2331
{RPCResult::Type::NUM, " progress" , " Approximate percent complete" },
@@ -2362,8 +2363,7 @@ static RPCHelpMan scanblocks()
2362
2363
// set the abort flag
2363
2364
g_scanfilter_should_abort_scan = true ;
2364
2365
return true ;
2365
- }
2366
- else if (request.params [0 ].get_str () == " start" ) {
2366
+ } else if (request.params [0 ].get_str () == " start" ) {
2367
2367
BlockFiltersScanReserver reserver;
2368
2368
if (!reserver.reserve ()) {
2369
2369
throw JSONRPCError (RPC_INVALID_PARAMETER, " Scan already in progress, use action \" abort\" or \" status\" " );
@@ -2387,27 +2387,28 @@ static RPCHelpMan scanblocks()
2387
2387
ChainstateManager& chainman = EnsureChainman (node);
2388
2388
2389
2389
// set the start-height
2390
- const CBlockIndex* block = nullptr ;
2390
+ const CBlockIndex* start_index = nullptr ;
2391
2391
const CBlockIndex* stop_block = nullptr ;
2392
2392
{
2393
2393
LOCK (cs_main);
2394
2394
CChain& active_chain = chainman.ActiveChain ();
2395
- block = active_chain.Genesis ();
2396
- stop_block = active_chain.Tip ();
2395
+ start_index = active_chain.Genesis ();
2396
+ stop_block = active_chain.Tip (); // If no stop block is provided, stop at the chain tip.
2397
2397
if (!request.params [2 ].isNull ()) {
2398
- block = active_chain[request.params [2 ].getInt <int >()];
2399
- if (!block ) {
2398
+ start_index = active_chain[request.params [2 ].getInt <int >()];
2399
+ if (!start_index ) {
2400
2400
throw JSONRPCError (RPC_MISC_ERROR, " Invalid start_height" );
2401
2401
}
2402
2402
}
2403
2403
if (!request.params [3 ].isNull ()) {
2404
2404
stop_block = active_chain[request.params [3 ].getInt <int >()];
2405
- if (!stop_block || stop_block->nHeight < block ->nHeight ) {
2405
+ if (!stop_block || stop_block->nHeight < start_index ->nHeight ) {
2406
2406
throw JSONRPCError (RPC_MISC_ERROR, " Invalid stop_height" );
2407
2407
}
2408
2408
}
2409
2409
}
2410
- CHECK_NONFATAL (block);
2410
+ CHECK_NONFATAL (start_index);
2411
+ CHECK_NONFATAL (stop_block);
2411
2412
2412
2413
// loop through the scan objects, add scripts to the needle_set
2413
2414
GCSFilter::ElementSet needle_set;
@@ -2420,64 +2421,64 @@ static RPCHelpMan scanblocks()
2420
2421
}
2421
2422
UniValue blocks (UniValue::VARR);
2422
2423
const int amount_per_chunk = 10000 ;
2423
- const CBlockIndex* start_index = block; // for remembering the start of a blockfilter range
2424
2424
std::vector<BlockFilter> filters;
2425
- const CBlockIndex* start_block = block ; // for progress reporting
2426
- const int total_blocks_to_process = stop_block->nHeight - start_block-> nHeight ;
2425
+ int start_block_height = start_index-> nHeight ; // for progress reporting
2426
+ const int total_blocks_to_process = stop_block->nHeight - start_block_height ;
2427
2427
2428
2428
g_scanfilter_should_abort_scan = false ;
2429
2429
g_scanfilter_progress = 0 ;
2430
- g_scanfilter_progress_height = start_block->nHeight ;
2430
+ g_scanfilter_progress_height = start_block_height;
2431
+ bool completed = true ;
2431
2432
2432
- while (block) {
2433
+ const CBlockIndex* end_range = nullptr ;
2434
+ do {
2433
2435
node.rpc_interruption_point (); // allow a clean shutdown
2434
2436
if (g_scanfilter_should_abort_scan) {
2435
- LogPrintf ( " scanblocks RPC aborted at height %d. \n " , block-> nHeight ) ;
2437
+ completed = false ;
2436
2438
break ;
2437
2439
}
2438
- const CBlockIndex* next = nullptr ;
2439
- {
2440
- LOCK (cs_main);
2441
- CChain& active_chain = chainman.ActiveChain ();
2442
- next = active_chain.Next (block);
2443
- if (block == stop_block) next = nullptr ;
2444
- }
2445
- if (start_index->nHeight + amount_per_chunk == block->nHeight || next == nullptr ) {
2446
- LogPrint (BCLog::RPC, " Fetching blockfilters from height %d to height %d.\n " , start_index->nHeight , block->nHeight );
2447
- if (index->LookupFilterRange (start_index->nHeight , block, filters)) {
2448
- for (const BlockFilter& filter : filters) {
2449
- // compare the elements-set with each filter
2450
- if (filter.GetFilter ().MatchAny (needle_set)) {
2451
- if (filter_false_positives) {
2452
- // Double check the filter matches by scanning the block
2453
- const CBlockIndex& blockindex = *CHECK_NONFATAL (WITH_LOCK (cs_main, return chainman.m_blockman .LookupBlockIndex (filter.GetBlockHash ())));
2454
-
2455
- if (!CheckBlockFilterMatches (chainman.m_blockman , blockindex, needle_set)) {
2456
- continue ;
2457
- }
2458
- }
2459
2440
2460
- blocks.push_back (filter.GetBlockHash ().GetHex ());
2461
- LogPrint (BCLog::RPC, " scanblocks: found match in %s\n " , filter.GetBlockHash ().GetHex ());
2441
+ // split the lookup range in chunks if we are deeper than 'amount_per_chunk' blocks from the stopping block
2442
+ int start_block = !end_range ? start_index->nHeight : start_index->nHeight + 1 ; // to not include the previous round 'end_range' block
2443
+ end_range = (start_block + amount_per_chunk < stop_block->nHeight ) ?
2444
+ WITH_LOCK (::cs_main, return chainman.ActiveChain ()[start_block + amount_per_chunk]) :
2445
+ stop_block;
2446
+
2447
+ if (index->LookupFilterRange (start_block, end_range, filters)) {
2448
+ for (const BlockFilter& filter : filters) {
2449
+ // compare the elements-set with each filter
2450
+ if (filter.GetFilter ().MatchAny (needle_set)) {
2451
+ if (filter_false_positives) {
2452
+ // Double check the filter matches by scanning the block
2453
+ const CBlockIndex& blockindex = *CHECK_NONFATAL (WITH_LOCK (cs_main, return chainman.m_blockman .LookupBlockIndex (filter.GetBlockHash ())));
2454
+
2455
+ if (!CheckBlockFilterMatches (chainman.m_blockman , blockindex, needle_set)) {
2456
+ continue ;
2457
+ }
2462
2458
}
2459
+
2460
+ blocks.push_back (filter.GetBlockHash ().GetHex ());
2463
2461
}
2464
2462
}
2465
- start_index = block;
2466
-
2467
- // update progress
2468
- int blocks_processed = block->nHeight - start_block->nHeight ;
2469
- if (total_blocks_to_process > 0 ) { // avoid division by zero
2470
- g_scanfilter_progress = (int )(100.0 / total_blocks_to_process * blocks_processed);
2471
- } else {
2472
- g_scanfilter_progress = 100 ;
2473
- }
2474
- g_scanfilter_progress_height = block->nHeight ;
2475
2463
}
2476
- block = next;
2477
- }
2478
- ret.pushKV (" from_height" , start_block->nHeight );
2479
- ret.pushKV (" to_height" , g_scanfilter_progress_height.load ());
2464
+ start_index = end_range;
2465
+
2466
+ // update progress
2467
+ int blocks_processed = end_range->nHeight - start_block_height;
2468
+ if (total_blocks_to_process > 0 ) { // avoid division by zero
2469
+ g_scanfilter_progress = (int )(100.0 / total_blocks_to_process * blocks_processed);
2470
+ } else {
2471
+ g_scanfilter_progress = 100 ;
2472
+ }
2473
+ g_scanfilter_progress_height = end_range->nHeight ;
2474
+
2475
+ // Finish if we reached the stop block
2476
+ } while (start_index != stop_block);
2477
+
2478
+ ret.pushKV (" from_height" , start_block_height);
2479
+ ret.pushKV (" to_height" , start_index->nHeight ); // start_index is always the last scanned block here
2480
2480
ret.pushKV (" relevant_blocks" , blocks);
2481
+ ret.pushKV (" completed" , completed);
2481
2482
}
2482
2483
else {
2483
2484
throw JSONRPCError (RPC_INVALID_PARAMETER, strprintf (" Invalid action '%s'" , request.params [0 ].get_str ()));
0 commit comments