@@ -2325,6 +2325,7 @@ static RPCHelpMan scanblocks()
23252325 {RPCResult::Type::ARR, " relevant_blocks" , " Blocks that may have matched a scanobject." , {
23262326 {RPCResult::Type::STR_HEX, " blockhash" , " A relevant blockhash" },
23272327 }},
2328+ {RPCResult::Type::BOOL, " completed" , " true if the scan process was not aborted" }
23282329 }},
23292330 RPCResult{" when action=='status' and a scan is currently in progress" , RPCResult::Type::OBJ, " " , " " , {
23302331 {RPCResult::Type::NUM, " progress" , " Approximate percent complete" },
@@ -2362,8 +2363,7 @@ static RPCHelpMan scanblocks()
23622363 // set the abort flag
23632364 g_scanfilter_should_abort_scan = true ;
23642365 return true ;
2365- }
2366- else if (request.params [0 ].get_str () == " start" ) {
2366+ } else if (request.params [0 ].get_str () == " start" ) {
23672367 BlockFiltersScanReserver reserver;
23682368 if (!reserver.reserve ()) {
23692369 throw JSONRPCError (RPC_INVALID_PARAMETER, " Scan already in progress, use action \" abort\" or \" status\" " );
@@ -2387,27 +2387,28 @@ static RPCHelpMan scanblocks()
23872387 ChainstateManager& chainman = EnsureChainman (node);
23882388
23892389 // set the start-height
2390- const CBlockIndex* block = nullptr ;
2390+ const CBlockIndex* start_index = nullptr ;
23912391 const CBlockIndex* stop_block = nullptr ;
23922392 {
23932393 LOCK (cs_main);
23942394 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.
23972397 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 ) {
24002400 throw JSONRPCError (RPC_MISC_ERROR, " Invalid start_height" );
24012401 }
24022402 }
24032403 if (!request.params [3 ].isNull ()) {
24042404 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 ) {
24062406 throw JSONRPCError (RPC_MISC_ERROR, " Invalid stop_height" );
24072407 }
24082408 }
24092409 }
2410- CHECK_NONFATAL (block);
2410+ CHECK_NONFATAL (start_index);
2411+ CHECK_NONFATAL (stop_block);
24112412
24122413 // loop through the scan objects, add scripts to the needle_set
24132414 GCSFilter::ElementSet needle_set;
@@ -2420,64 +2421,64 @@ static RPCHelpMan scanblocks()
24202421 }
24212422 UniValue blocks (UniValue::VARR);
24222423 const int amount_per_chunk = 10000 ;
2423- const CBlockIndex* start_index = block; // for remembering the start of a blockfilter range
24242424 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 ;
24272427
24282428 g_scanfilter_should_abort_scan = false ;
24292429 g_scanfilter_progress = 0 ;
2430- g_scanfilter_progress_height = start_block->nHeight ;
2430+ g_scanfilter_progress_height = start_block_height;
2431+ bool completed = true ;
24312432
2432- while (block) {
2433+ const CBlockIndex* end_range = nullptr ;
2434+ do {
24332435 node.rpc_interruption_point (); // allow a clean shutdown
24342436 if (g_scanfilter_should_abort_scan) {
2435- LogPrintf ( " scanblocks RPC aborted at height %d. \n " , block-> nHeight ) ;
2437+ completed = false ;
24362438 break ;
24372439 }
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- }
24592440
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+ }
24622458 }
2459+
2460+ blocks.push_back (filter.GetBlockHash ().GetHex ());
24632461 }
24642462 }
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 ;
24752463 }
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
24802480 ret.pushKV (" relevant_blocks" , blocks);
2481+ ret.pushKV (" completed" , completed);
24812482 }
24822483 else {
24832484 throw JSONRPCError (RPC_INVALID_PARAMETER, strprintf (" Invalid action '%s'" , request.params [0 ].get_str ()));
0 commit comments