Created
November 18, 2021 21:55
-
-
Save jamesob/aa4a975344209f0316444b8de2ec1d18 to your computer and use it in GitHub Desktop.
git range-diff --color=never upstream/master jonasschnelli/2020/12/filterblocks_rpc HEAD
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-: ---------- > 1: 608d8b4a62 rpc: move-only: consolidate blockchain scan args | |
1: 6a69dd267e ! 2: d836ce3f2f Add scanblocks RPC call - scan for relevant blocks with descriptors | |
@@ Metadata | |
Author: Jonas Schnelli <dev@jonasschnelli.ch> | |
## Commit message ## | |
- Add scanblocks RPC call - scan for relevant blocks with descriptors | |
+ rpc: add scanblocks - scan for relevant blocks with descriptors | |
+ | |
+ Co-authored-by: James O'Beirne <james.obeirne@gmail.com> | |
## src/rpc/blockchain.cpp ## | |
@@ src/rpc/blockchain.cpp: static RPCHelpMan scantxoutset() | |
@@ src/rpc/blockchain.cpp: static RPCHelpMan scantxoutset() | |
+static RPCHelpMan scanblocks() | |
+{ | |
+ return RPCHelpMan{"scanblocks", | |
-+ "\nReturn relevant blockhashes for given descriptors.\n" | |
-+ "This call may take serval minutes. Make sure to use no RPC timeout (bitcoin-cli -rpcclienttimeout=0)", | |
-+ { | |
-+ {"action", RPCArg::Type::STR, RPCArg::Optional::NO, "The action to execute\n" | |
-+ " \"start\" for starting a scan\n" | |
-+ " \"abort\" for aborting the current scan (returns true when abort was successful)\n" | |
-+ " \"status\" for progress report (in %) of the current scan (returns Null if there is no ongoing scan)"}, | |
-+ {"scanobjects", RPCArg::Type::ARR, RPCArg::Optional::OMITTED, "Array of scan objects.\n" | |
-+ " Every scan object is either a string descriptor or an object:", | |
-+ { | |
-+ {"descriptor", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "An output descriptor"}, | |
-+ {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "An object with output descriptor and metadata", | |
-+ { | |
-+ {"desc", RPCArg::Type::STR, RPCArg::Optional::NO, "An output descriptor"}, | |
-+ {"range", RPCArg::Type::RANGE, /* default */ "1000", "The range of HD chain indexes to explore (either end or [begin,end])"}, | |
-+ }, | |
-+ }, | |
-+ }, | |
-+ "[scanobjects,...]"}, | |
-+ {"start_height", RPCArg::Type::NUM, /*default*/ "0", "height to start to filter from"}, | |
-+ {"stop_height", RPCArg::Type::NUM, /*default*/ "<tip>", "height to stop to scan"}, | |
-+ {"filtertype", RPCArg::Type::STR, /*default*/ "basic", "The type name of the filter"} | |
-+ }, | |
-+ RPCResult{ | |
-+ RPCResult::Type::ARR, "", "", | |
-+ { | |
-+ {RPCResult::Type::STR_HEX, "", "The blockhash"}, | |
-+ }}, | |
-+ RPCExamples{ | |
-+ HelpExampleCli("scanblocks", "\"[\"addr(bcrt1q4u4nsgk6ug0sqz7r3rj9tykjxrsl0yy4d0wwte)\"]\" 300000") + | |
-+ HelpExampleRpc("scanblocks", "\"[\"addr(bcrt1q4u4nsgk6ug0sqz7r3rj9tykjxrsl0yy4d0wwte)\"]\" 300000") | |
++ "\nReturn relevant blockhashes for given descriptors.\n" | |
++ "This call may take several minutes. Make sure to use no RPC timeout (bitcoin-cli -rpcclienttimeout=0)", | |
++ { | |
++ scan_action_arg_desc, | |
++ scan_objects_arg_desc, | |
++ RPCArg{"start_height", RPCArg::Type::NUM, RPCArg::DefaultHint{"0"}, "Height to start to scan from"}, | |
++ RPCArg{"stop_height", RPCArg::Type::NUM, RPCArg::DefaultHint{"chain tip"}, "Height to stop to scan"}, | |
++ RPCArg{"filtertype", RPCArg::Type::STR, RPCArg::DefaultHint{"basic"}, "The type name of the filter"} | |
++ }, | |
++ { | |
++ scan_result_abort, | |
++ scan_result_status_none, | |
++ scan_result_status_some, | |
++ RPCResult{"When action=='start'", RPCResult::Type::OBJ, "", "", { | |
++ {RPCResult::Type::NUM, "from_height", "The height we started the scan from"}, | |
++ {RPCResult::Type::NUM, "to_height", "The height we ended the scan at"}, | |
++ {RPCResult::Type::ARR, "relevant_blocks", "", {{RPCResult::Type::STR_HEX, "blockhash", "A relevant blockhash"},}}, | |
+ }, | |
++ }, | |
++ }, | |
++ RPCExamples{ | |
++ HelpExampleCli("scanblocks", "\"[\"addr(bcrt1q4u4nsgk6ug0sqz7r3rj9tykjxrsl0yy4d0wwte)\"]\" 300000") + | |
++ HelpExampleRpc("scanblocks", "\"[\"addr(bcrt1q4u4nsgk6ug0sqz7r3rj9tykjxrsl0yy4d0wwte)\"]\" 300000") | |
++ }, | |
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue | |
+{ | |
+ UniValue ret(UniValue::VOBJ); | |
@@ src/rpc/blockchain.cpp: static RPCHelpMan scantxoutset() | |
+ throw JSONRPCError(RPC_MISC_ERROR, "Index is not enabled for filtertype " + filtertype_name); | |
+ } | |
+ | |
++ NodeContext& node = EnsureAnyNodeContext(request.context); | |
++ ChainstateManager& chainman = EnsureChainman(node); | |
++ | |
+ // set the start-height | |
+ const CBlockIndex* block = nullptr; | |
+ const CBlockIndex* stop_block = nullptr; | |
+ { | |
+ LOCK(cs_main); | |
-+ block = ::ChainActive().Genesis(); | |
-+ stop_block = ::ChainActive().Tip(); | |
++ CChain& active_chain = chainman.ActiveChain(); | |
++ block = active_chain.Genesis(); | |
++ stop_block = active_chain.Tip(); | |
+ if (!request.params[2].isNull()) { | |
-+ block = ::ChainActive()[request.params[2].get_int()]; | |
++ block = active_chain[request.params[2].get_int()]; | |
+ if (!block) { | |
+ throw JSONRPCError(RPC_MISC_ERROR, "Invalid start_height"); | |
+ } | |
+ } | |
+ if (!request.params[3].isNull()) { | |
-+ stop_block = ::ChainActive()[request.params[3].get_int()]; | |
++ stop_block = active_chain[request.params[3].get_int()]; | |
+ if (!stop_block || stop_block->nHeight < block->nHeight) { | |
+ throw JSONRPCError(RPC_MISC_ERROR, "Invalid stop_height"); | |
+ } | |
@@ src/rpc/blockchain.cpp: static RPCHelpMan scantxoutset() | |
+ needle_set.emplace(script.begin(), script.end()); | |
+ } | |
+ } | |
-+ NodeContext& node = EnsureNodeContext(request.context); | |
+ 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<BlockFilter> filters; | |
+ const CBlockIndex* start_block = block; // for progress reporting | |
-+ const CBlockIndex* last_scanned_block = block; | |
++ const int total_blocks_to_process = stop_block->nHeight - start_block->nHeight; | |
++ | |
+ g_scanfilter_should_abort_scan = false; | |
+ g_scanfilter_progress = 0; | |
+ g_scanfilter_progress_height = start_block->nHeight; | |
++ | |
+ while (block) { | |
+ node.rpc_interruption_point(); // allow a clean shutdown | |
+ if (g_scanfilter_should_abort_scan) { | |
++ LogPrintf("scanblocks RPC aborted at height %d.\n", block->nHeight); | |
+ break; | |
+ } | |
+ const CBlockIndex* next = nullptr; | |
+ { | |
+ LOCK(cs_main); | |
-+ next = ChainActive().Next(block); | |
++ 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) { | |
@@ src/rpc/blockchain.cpp: static RPCHelpMan scantxoutset() | |
+ | |
+ // update progress | |
+ int blocks_processed = block->nHeight - start_block->nHeight; | |
-+ int total_blocks_to_process = stop_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 { | |
@@ src/rpc/blockchain.cpp: static RPCHelpMan scantxoutset() | |
+ } | |
+ g_scanfilter_progress_height = block->nHeight; | |
+ } | |
-+ last_scanned_block = block; | |
+ block = next; | |
+ } | |
+ ret.pushKV("from_height", start_block->nHeight); | |
-+ ret.pushKV("to_height", last_scanned_block->nHeight); | |
++ ret.pushKV("to_height", g_scanfilter_progress_height); | |
+ ret.pushKV("relevant_blocks", blocks); | |
+ } | |
+ else { | |
2: 4c8ac1c6c5 = 3: a4da6ee6a1 Unify "invalid action argument" error (fix scantxoutset) | |
3: 71b7cdb460 < -: ---------- Add scanblock functional test | |
-: ---------- > 4: c0c2115a14 test: rpc: add scanblocks functional test |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
https://gist.github.com/jamesob/aa4a975344209f0316444b8de2ec1d18.js