Skip to content

Commit 27eeb03

Browse files
committed
Merge #19550: rpc: Add getindexinfo RPC
124e1ee doc: Add release notes for getindexinfo RPC (Fabian Jahr) c447b09 test: Add tests for getindexinfo RPC (Fabian Jahr) 667bc7a rpc: Add getindexinfo RPC (Fabian Jahr) Pull request description: As I was playing with indices a I was missing an RPC that gives information about the active indices in the node. I think this can be helpful for many users, especially since there are some new index candidates coming up (#14053, #18000) that can give a quick overview without the user having to parse the logs. Feature summary: - Adds new RPC `listindices` (placed in Util section) - That RPC only lists the actively running indices - For each index it gives the name, whether it is synced and up to which block height it is synced ACKs for top commit: laanwj: Re-ACK 124e1ee jonatack: Code review re-ACK 124e1ee per `git range-diff a57af89 47a5372 124e1ee` no change since my last re-ACK, rebase only Tree-SHA512: 3b7174c87951e6457fef099f530337803906baf32fb64261410b8def2c0917853d6a1bf3059cd590b1cc1523608f8916dafb327a431d27ecbf8d7454406b5b35
2 parents 70d7ddb + 124e1ee commit 27eeb03

File tree

5 files changed

+107
-0
lines changed

5 files changed

+107
-0
lines changed

doc/release-notes.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,10 @@ Changes to Wallet or GUI related RPCs can be found in the GUI or Wallet section
115115
New RPCs
116116
--------
117117

118+
- The `getindexinfo` RPC returns the actively running indices of the node,
119+
including their current sync status and height. It also accepts an `index_name`
120+
to specify returning only the status of that index. (#19550)
121+
118122
Build System
119123
------------
120124

src/index/base.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,3 +319,12 @@ void BaseIndex::Stop()
319319
m_thread_sync.join();
320320
}
321321
}
322+
323+
IndexSummary BaseIndex::GetSummary() const
324+
{
325+
IndexSummary summary{};
326+
summary.name = GetName();
327+
summary.synced = m_synced;
328+
summary.best_block_height = m_best_block_index.load()->nHeight;
329+
return summary;
330+
}

src/index/base.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,12 @@
1313

1414
class CBlockIndex;
1515

16+
struct IndexSummary {
17+
std::string name;
18+
bool synced{false};
19+
int best_block_height{0};
20+
};
21+
1622
/**
1723
* Base class for indices of blockchain data. This implements
1824
* CValidationInterface and ensures blocks are indexed sequentially according
@@ -106,6 +112,9 @@ class BaseIndex : public CValidationInterface
106112

107113
/// Stops the instance from staying in sync with blockchain updates.
108114
void Stop();
115+
116+
/// Get a summary of the index and its state.
117+
IndexSummary GetSummary() const;
109118
};
110119

111120
#endif // BITCOIN_INDEX_BASE_H

src/rpc/misc.cpp

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
55

66
#include <httpserver.h>
7+
#include <index/blockfilterindex.h>
8+
#include <index/txindex.h>
79
#include <interfaces/chain.h>
810
#include <key_io.h>
911
#include <node/context.h>
@@ -636,6 +638,60 @@ static RPCHelpMan echo(const std::string& name)
636638
static RPCHelpMan echo() { return echo("echo"); }
637639
static RPCHelpMan echojson() { return echo("echojson"); }
638640

641+
static UniValue SummaryToJSON(const IndexSummary&& summary, std::string index_name)
642+
{
643+
UniValue ret_summary(UniValue::VOBJ);
644+
if (!index_name.empty() && index_name != summary.name) return ret_summary;
645+
646+
UniValue entry(UniValue::VOBJ);
647+
entry.pushKV("synced", summary.synced);
648+
entry.pushKV("best_block_height", summary.best_block_height);
649+
ret_summary.pushKV(summary.name, entry);
650+
return ret_summary;
651+
}
652+
653+
static RPCHelpMan getindexinfo()
654+
{
655+
return RPCHelpMan{"getindexinfo",
656+
"\nReturns the status of one or all available indices currently running in the node.\n",
657+
{
658+
{"index_name", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "Filter results for an index with a specific name."},
659+
},
660+
RPCResult{
661+
RPCResult::Type::OBJ, "", "", {
662+
{
663+
RPCResult::Type::OBJ, "name", "The name of the index",
664+
{
665+
{RPCResult::Type::BOOL, "synced", "Whether the index is synced or not"},
666+
{RPCResult::Type::NUM, "best_block_height", "The block height to which the index is synced"},
667+
}
668+
},
669+
},
670+
},
671+
RPCExamples{
672+
HelpExampleCli("getindexinfo", "")
673+
+ HelpExampleRpc("getindexinfo", "")
674+
+ HelpExampleCli("getindexinfo", "txindex")
675+
+ HelpExampleRpc("getindexinfo", "txindex")
676+
},
677+
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
678+
{
679+
UniValue result(UniValue::VOBJ);
680+
const std::string index_name = request.params[0].isNull() ? "" : request.params[0].get_str();
681+
682+
if (g_txindex) {
683+
result.pushKVs(SummaryToJSON(g_txindex->GetSummary(), index_name));
684+
}
685+
686+
ForEachBlockFilterIndex([&result, &index_name](const BlockFilterIndex& index) {
687+
result.pushKVs(SummaryToJSON(index.GetSummary(), index_name));
688+
});
689+
690+
return result;
691+
},
692+
};
693+
}
694+
639695
void RegisterMiscRPCCommands(CRPCTable &t)
640696
{
641697
// clang-format off
@@ -650,6 +706,7 @@ static const CRPCCommand commands[] =
650706
{ "util", "getdescriptorinfo", &getdescriptorinfo, {"descriptor"} },
651707
{ "util", "verifymessage", &verifymessage, {"address","signature","message"} },
652708
{ "util", "signmessagewithprivkey", &signmessagewithprivkey, {"privkey","message"} },
709+
{ "util", "getindexinfo", &getindexinfo, {"index_name"} },
653710

654711
/* Not shown in help */
655712
{ "hidden", "setmocktime", &setmocktime, {"timestamp"}},

test/functional/rpc_misc.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,34 @@ def run_test(self):
6161
node.logging(include=['qt'])
6262
assert_equal(node.logging()['qt'], True)
6363

64+
self.log.info("test getindexinfo")
65+
# Without any indices running the RPC returns an empty object
66+
assert_equal(node.getindexinfo(), {})
67+
68+
# Restart the node with indices and wait for them to sync
69+
self.restart_node(0, ["-txindex", "-blockfilterindex"])
70+
self.wait_until(lambda: all(i["synced"] for i in node.getindexinfo().values()))
71+
72+
# Returns a list of all running indices by default
73+
assert_equal(
74+
node.getindexinfo(),
75+
{
76+
"txindex": {"synced": True, "best_block_height": 200},
77+
"basic block filter index": {"synced": True, "best_block_height": 200}
78+
}
79+
)
80+
81+
# Specifying an index by name returns only the status of that index
82+
assert_equal(
83+
node.getindexinfo("txindex"),
84+
{
85+
"txindex": {"synced": True, "best_block_height": 200},
86+
}
87+
)
88+
89+
# Specifying an unknown index name returns an empty result
90+
assert_equal(node.getindexinfo("foo"), {})
91+
6492

6593
if __name__ == '__main__':
6694
RpcMiscTest().main()

0 commit comments

Comments
 (0)