diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 1b2543c77a6..301cfbfb25e 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -2383,27 +2383,28 @@ static RPCHelpMan scanblocks() ChainstateManager& chainman = EnsureChainman(node); // set the start-height - const CBlockIndex* block = nullptr; + const CBlockIndex* start_index = nullptr; const CBlockIndex* stop_block = nullptr; { LOCK(cs_main); CChain& active_chain = chainman.ActiveChain(); - block = active_chain.Genesis(); - stop_block = active_chain.Tip(); + start_index = active_chain.Genesis(); + stop_block = active_chain.Tip(); // If no stop block is provided, stop at the chain tip. if (!request.params[2].isNull()) { - block = active_chain[request.params[2].getInt()]; - if (!block) { + start_index = active_chain[request.params[2].getInt()]; + if (!start_index) { throw JSONRPCError(RPC_MISC_ERROR, "Invalid start_height"); } } if (!request.params[3].isNull()) { stop_block = active_chain[request.params[3].getInt()]; - if (!stop_block || stop_block->nHeight < block->nHeight) { + if (!stop_block || stop_block->nHeight < start_index->nHeight) { throw JSONRPCError(RPC_MISC_ERROR, "Invalid stop_height"); } } } - CHECK_NONFATAL(block); + CHECK_NONFATAL(start_index); + CHECK_NONFATAL(stop_block); // loop through the scan objects, add scripts to the needle_set GCSFilter::ElementSet needle_set; @@ -2416,63 +2417,62 @@ static RPCHelpMan scanblocks() } UniValue blocks(UniValue::VARR); const int amount_per_chunk = 10000; - const CBlockIndex* start_index = block; // for remembering the start of a blockfilter range std::vector filters; - const CBlockIndex* start_block = block; // for progress reporting - const int total_blocks_to_process = stop_block->nHeight - start_block->nHeight; + int start_block_height = start_index->nHeight; // for progress reporting + const int total_blocks_to_process = stop_block->nHeight - start_block_height; g_scanfilter_should_abort_scan = false; g_scanfilter_progress = 0; - g_scanfilter_progress_height = start_block->nHeight; + g_scanfilter_progress_height = start_block_height; - while (block) { + const CBlockIndex* end_range = nullptr; + do { node.rpc_interruption_point(); // allow a clean shutdown if (g_scanfilter_should_abort_scan) { - LogPrintf("scanblocks RPC aborted at height %d.\n", block->nHeight); + LogPrintf("scanblocks RPC aborted at height %d.\n", end_range->nHeight); break; } - const CBlockIndex* next = nullptr; - { - LOCK(cs_main); - CChain& active_chain = chainman.ActiveChain(); - next = active_chain.Next(block); - if (block == stop_block) next = nullptr; - } - if (start_index->nHeight + amount_per_chunk == block->nHeight || next == nullptr) { - LogPrint(BCLog::RPC, "Fetching blockfilters from height %d to height %d.\n", start_index->nHeight, block->nHeight); - if (index->LookupFilterRange(start_index->nHeight, block, filters)) { - for (const BlockFilter& filter : filters) { - // compare the elements-set with each filter - if (filter.GetFilter().MatchAny(needle_set)) { - if (filter_false_positives) { - // Double check the filter matches by scanning the block - const CBlockIndex& blockindex = *CHECK_NONFATAL(WITH_LOCK(cs_main, return chainman.m_blockman.LookupBlockIndex(filter.GetBlockHash()))); - if (!CheckBlockFilterMatches(chainman.m_blockman, blockindex, needle_set)) { - continue; - } + // split the lookup range in chunks if we are deeper than 'amount_per_chunk' blocks from the stopping block + int start_block = !end_range ? start_index->nHeight : start_index->nHeight + 1; // to not include the previous round 'end_range' block + end_range = (start_block + amount_per_chunk < stop_block->nHeight) ? + WITH_LOCK(::cs_main, return chainman.ActiveChain()[start_block + amount_per_chunk]) : + stop_block; + + if (index->LookupFilterRange(start_block, end_range, filters)) { + for (const BlockFilter& filter : filters) { + // compare the elements-set with each filter + if (filter.GetFilter().MatchAny(needle_set)) { + if (filter_false_positives) { + // Double check the filter matches by scanning the block + const CBlockIndex& blockindex = *CHECK_NONFATAL(WITH_LOCK(cs_main, return chainman.m_blockman.LookupBlockIndex(filter.GetBlockHash()))); + + if (!CheckBlockFilterMatches(chainman.m_blockman, blockindex, needle_set)) { + continue; } - - blocks.push_back(filter.GetBlockHash().GetHex()); - LogPrint(BCLog::RPC, "scanblocks: found match in %s\n", filter.GetBlockHash().GetHex()); } + + blocks.push_back(filter.GetBlockHash().GetHex()); + LogPrint(BCLog::RPC, "scanblocks: found match in %s\n", filter.GetBlockHash().GetHex()); } } - start_index = block; - - // update progress - int blocks_processed = block->nHeight - start_block->nHeight; - if (total_blocks_to_process > 0) { // avoid division by zero - g_scanfilter_progress = (int)(100.0 / total_blocks_to_process * blocks_processed); - } else { - g_scanfilter_progress = 100; - } - g_scanfilter_progress_height = block->nHeight; } - block = next; - } - ret.pushKV("from_height", start_block->nHeight); - ret.pushKV("to_height", g_scanfilter_progress_height.load()); + start_index = end_range; + + // update progress + int blocks_processed = end_range->nHeight - start_block_height; + if (total_blocks_to_process > 0) { // avoid division by zero + g_scanfilter_progress = (int)(100.0 / total_blocks_to_process * blocks_processed); + } else { + g_scanfilter_progress = 100; + } + g_scanfilter_progress_height = end_range->nHeight; + + // Finish if we reached the stop block + } while (start_index != stop_block); + + ret.pushKV("from_height", start_block_height); + ret.pushKV("to_height", stop_block->nHeight); ret.pushKV("relevant_blocks", blocks); } else {