diff options
-rw-r--r-- | doc/release-notes.md | 4 | ||||
-rw-r--r-- | src/index/base.cpp | 9 | ||||
-rw-r--r-- | src/index/base.h | 9 | ||||
-rw-r--r-- | src/rpc/misc.cpp | 57 | ||||
-rwxr-xr-x | test/functional/rpc_misc.py | 28 |
5 files changed, 107 insertions, 0 deletions
diff --git a/doc/release-notes.md b/doc/release-notes.md index 23983dcd7b..4656963f5a 100644 --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -115,6 +115,10 @@ Changes to Wallet or GUI related RPCs can be found in the GUI or Wallet section New RPCs -------- +- The `getindexinfo` RPC returns the actively running indices of the node, + including their current sync status and height. It also accepts an `index_name` + to specify returning only the status of that index. (#19550) + Build System ------------ diff --git a/src/index/base.cpp b/src/index/base.cpp index f587205a28..e67b813763 100644 --- a/src/index/base.cpp +++ b/src/index/base.cpp @@ -319,3 +319,12 @@ void BaseIndex::Stop() m_thread_sync.join(); } } + +IndexSummary BaseIndex::GetSummary() const +{ + IndexSummary summary{}; + summary.name = GetName(); + summary.synced = m_synced; + summary.best_block_height = m_best_block_index.load()->nHeight; + return summary; +} diff --git a/src/index/base.h b/src/index/base.h index 3fab810bb2..74bc1ebfd2 100644 --- a/src/index/base.h +++ b/src/index/base.h @@ -13,6 +13,12 @@ class CBlockIndex; +struct IndexSummary { + std::string name; + bool synced{false}; + int best_block_height{0}; +}; + /** * Base class for indices of blockchain data. This implements * CValidationInterface and ensures blocks are indexed sequentially according @@ -106,6 +112,9 @@ public: /// Stops the instance from staying in sync with blockchain updates. void Stop(); + + /// Get a summary of the index and its state. + IndexSummary GetSummary() const; }; #endif // BITCOIN_INDEX_BASE_H diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp index ff31bee1e3..0c982317f5 100644 --- a/src/rpc/misc.cpp +++ b/src/rpc/misc.cpp @@ -4,6 +4,8 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include <httpserver.h> +#include <index/blockfilterindex.h> +#include <index/txindex.h> #include <interfaces/chain.h> #include <key_io.h> #include <node/context.h> @@ -636,6 +638,60 @@ static RPCHelpMan echo(const std::string& name) static RPCHelpMan echo() { return echo("echo"); } static RPCHelpMan echojson() { return echo("echojson"); } +static UniValue SummaryToJSON(const IndexSummary&& summary, std::string index_name) +{ + UniValue ret_summary(UniValue::VOBJ); + if (!index_name.empty() && index_name != summary.name) return ret_summary; + + UniValue entry(UniValue::VOBJ); + entry.pushKV("synced", summary.synced); + entry.pushKV("best_block_height", summary.best_block_height); + ret_summary.pushKV(summary.name, entry); + return ret_summary; +} + +static RPCHelpMan getindexinfo() +{ + return RPCHelpMan{"getindexinfo", + "\nReturns the status of one or all available indices currently running in the node.\n", + { + {"index_name", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "Filter results for an index with a specific name."}, + }, + RPCResult{ + RPCResult::Type::OBJ, "", "", { + { + RPCResult::Type::OBJ, "name", "The name of the index", + { + {RPCResult::Type::BOOL, "synced", "Whether the index is synced or not"}, + {RPCResult::Type::NUM, "best_block_height", "The block height to which the index is synced"}, + } + }, + }, + }, + RPCExamples{ + HelpExampleCli("getindexinfo", "") + + HelpExampleRpc("getindexinfo", "") + + HelpExampleCli("getindexinfo", "txindex") + + HelpExampleRpc("getindexinfo", "txindex") + }, + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ + UniValue result(UniValue::VOBJ); + const std::string index_name = request.params[0].isNull() ? "" : request.params[0].get_str(); + + if (g_txindex) { + result.pushKVs(SummaryToJSON(g_txindex->GetSummary(), index_name)); + } + + ForEachBlockFilterIndex([&result, &index_name](const BlockFilterIndex& index) { + result.pushKVs(SummaryToJSON(index.GetSummary(), index_name)); + }); + + return result; +}, + }; +} + void RegisterMiscRPCCommands(CRPCTable &t) { // clang-format off @@ -650,6 +706,7 @@ static const CRPCCommand commands[] = { "util", "getdescriptorinfo", &getdescriptorinfo, {"descriptor"} }, { "util", "verifymessage", &verifymessage, {"address","signature","message"} }, { "util", "signmessagewithprivkey", &signmessagewithprivkey, {"privkey","message"} }, + { "util", "getindexinfo", &getindexinfo, {"index_name"} }, /* Not shown in help */ { "hidden", "setmocktime", &setmocktime, {"timestamp"}}, diff --git a/test/functional/rpc_misc.py b/test/functional/rpc_misc.py index cc5a264adb..0493ceeb64 100755 --- a/test/functional/rpc_misc.py +++ b/test/functional/rpc_misc.py @@ -61,6 +61,34 @@ class RpcMiscTest(BitcoinTestFramework): node.logging(include=['qt']) assert_equal(node.logging()['qt'], True) + self.log.info("test getindexinfo") + # Without any indices running the RPC returns an empty object + assert_equal(node.getindexinfo(), {}) + + # Restart the node with indices and wait for them to sync + self.restart_node(0, ["-txindex", "-blockfilterindex"]) + self.wait_until(lambda: all(i["synced"] for i in node.getindexinfo().values())) + + # Returns a list of all running indices by default + assert_equal( + node.getindexinfo(), + { + "txindex": {"synced": True, "best_block_height": 200}, + "basic block filter index": {"synced": True, "best_block_height": 200} + } + ) + + # Specifying an index by name returns only the status of that index + assert_equal( + node.getindexinfo("txindex"), + { + "txindex": {"synced": True, "best_block_height": 200}, + } + ) + + # Specifying an unknown index name returns an empty result + assert_equal(node.getindexinfo("foo"), {}) + if __name__ == '__main__': RpcMiscTest().main() |