Branch data Line data Source code
1 : : // Copyright (c) 2010 Satoshi Nakamoto
2 : : // Copyright (c) 2009-2022 The Bitcoin Core developers
3 : : // Distributed under the MIT software license, see the accompanying
4 : : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 : :
6 : : #include <chainparams.h>
7 : : #include <httpserver.h>
8 : : #include <index/blockfilterindex.h>
9 : : #include <index/coinstatsindex.h>
10 : : #include <index/txindex.h>
11 : : #include <interfaces/chain.h>
12 : : #include <interfaces/echo.h>
13 : : #include <interfaces/init.h>
14 : : #include <interfaces/ipc.h>
15 : : #include <kernel/cs_main.h>
16 : : #include <logging.h>
17 : : #include <node/context.h>
18 : : #include <rpc/server.h>
19 : : #include <rpc/server_util.h>
20 : : #include <rpc/util.h>
21 : : #include <scheduler.h>
22 : : #include <univalue.h>
23 : : #include <util/any.h>
24 : : #include <util/check.h>
25 : :
26 : : #include <stdint.h>
27 : 2 : #ifdef HAVE_MALLOC_INFO
28 : : #include <malloc.h>
29 : : #endif
30 : :
31 : : using node::NodeContext;
32 : :
33 : 0 : static RPCHelpMan setmocktime()
34 : : {
35 [ # # ][ # # ]: 0 : return RPCHelpMan{"setmocktime",
[ # # ]
36 [ # # ]: 0 : "\nSet the local time to given timestamp (-regtest only)\n",
37 [ # # ]: 0 : {
38 [ # # ][ # # ]: 0 : {"timestamp", RPCArg::Type::NUM, RPCArg::Optional::NO, UNIX_EPOCH_TIME + "\n"
[ # # ]
39 : : "Pass 0 to go back to using the system time."},
40 : : },
41 [ # # ][ # # ]: 0 : RPCResult{RPCResult::Type::NONE, "", ""},
[ # # ][ # # ]
42 [ # # ][ # # ]: 0 : RPCExamples{""},
43 : 0 : [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
44 : : {
45 [ # # ]: 0 : if (!Params().IsMockableChain()) {
46 [ # # ]: 0 : throw std::runtime_error("setmocktime is for regression testing (-regtest mode) only");
47 : : }
48 : :
49 : : // For now, don't change mocktime if we're in the middle of validation, as
50 : : // this could have an effect on mempool time-based eviction, as well as
51 : : // IsCurrentForFeeEstimation() and IsInitialBlockDownload().
52 : : // TODO: figure out the right way to synchronize around mocktime, and
53 : : // ensure all call sites of GetTime() are accessing this safely.
54 : 0 : LOCK(cs_main);
55 : :
56 [ # # ][ # # ]: 0 : const int64_t time{request.params[0].getInt<int64_t>()};
57 [ # # ]: 0 : if (time < 0) {
58 [ # # ][ # # ]: 0 : throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Mocktime cannot be negative: %s.", time));
[ # # ][ # # ]
59 : : }
60 [ # # ]: 0 : SetMockTime(time);
61 [ # # ]: 0 : const NodeContext& node_context{EnsureAnyNodeContext(request.context)};
62 [ # # ]: 0 : for (const auto& chain_client : node_context.chain_clients) {
63 [ # # ]: 0 : chain_client->setMockTime(time);
64 : : }
65 : :
66 [ # # ]: 0 : return UniValue::VNULL;
67 : 0 : },
68 : : };
69 : 0 : }
70 : :
71 : 0 : static RPCHelpMan mockscheduler()
72 : : {
73 [ # # ][ # # ]: 0 : return RPCHelpMan{"mockscheduler",
[ # # ]
74 [ # # ]: 0 : "\nBump the scheduler into the future (-regtest only)\n",
75 [ # # ]: 0 : {
76 [ # # ][ # # ]: 0 : {"delta_time", RPCArg::Type::NUM, RPCArg::Optional::NO, "Number of seconds to forward the scheduler into the future." },
[ # # ]
77 : : },
78 [ # # ][ # # ]: 0 : RPCResult{RPCResult::Type::NONE, "", ""},
[ # # ][ # # ]
79 [ # # ][ # # ]: 0 : RPCExamples{""},
80 : 0 : [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
81 : : {
82 [ # # ]: 0 : if (!Params().IsMockableChain()) {
83 [ # # ]: 0 : throw std::runtime_error("mockscheduler is for regression testing (-regtest mode) only");
84 : : }
85 : :
86 : 0 : int64_t delta_seconds = request.params[0].getInt<int64_t>();
87 [ # # ]: 0 : if (delta_seconds <= 0 || delta_seconds > 3600) {
88 [ # # ]: 0 : throw std::runtime_error("delta_time must be between 1 and 3600 seconds (1 hr)");
89 : : }
90 : :
91 : 0 : const NodeContext& node_context{EnsureAnyNodeContext(request.context)};
92 : 0 : CHECK_NONFATAL(node_context.scheduler)->MockForward(std::chrono::seconds{delta_seconds});
93 : 0 : SyncWithValidationInterfaceQueue();
94 [ # # ]: 0 : for (const auto& chain_client : node_context.chain_clients) {
95 : 0 : chain_client->schedulerMockForward(std::chrono::seconds(delta_seconds));
96 : : }
97 : :
98 [ # # ]: 0 : return UniValue::VNULL;
99 : 0 : },
100 : : };
101 : 0 : }
102 : :
103 : 0 : static UniValue RPCLockedMemoryInfo()
104 : : {
105 : 0 : LockedPool::Stats stats = LockedPoolManager::Instance().stats();
106 [ # # ]: 0 : UniValue obj(UniValue::VOBJ);
107 [ # # ][ # # ]: 0 : obj.pushKV("used", uint64_t(stats.used));
[ # # ]
108 [ # # ][ # # ]: 0 : obj.pushKV("free", uint64_t(stats.free));
[ # # ]
109 [ # # ][ # # ]: 0 : obj.pushKV("total", uint64_t(stats.total));
[ # # ]
110 [ # # ][ # # ]: 0 : obj.pushKV("locked", uint64_t(stats.locked));
[ # # ]
111 [ # # ][ # # ]: 0 : obj.pushKV("chunks_used", uint64_t(stats.chunks_used));
[ # # ]
112 [ # # ][ # # ]: 0 : obj.pushKV("chunks_free", uint64_t(stats.chunks_free));
[ # # ]
113 : 0 : return obj;
114 [ # # ]: 0 : }
115 : :
116 : : #ifdef HAVE_MALLOC_INFO
117 : 0 : static std::string RPCMallocInfo()
118 : : {
119 : 0 : char *ptr = nullptr;
120 : 0 : size_t size = 0;
121 : 0 : FILE *f = open_memstream(&ptr, &size);
122 [ # # ]: 0 : if (f) {
123 : 0 : malloc_info(0, f);
124 : 0 : fclose(f);
125 [ # # ]: 0 : if (ptr) {
126 [ # # ]: 0 : std::string rv(ptr, size);
127 : 0 : free(ptr);
128 : 0 : return rv;
129 [ # # ]: 0 : }
130 : 0 : }
131 [ # # ]: 0 : return "";
132 : 0 : }
133 : : #endif
134 : :
135 : 0 : static RPCHelpMan getmemoryinfo()
136 : : {
137 : : /* Please, avoid using the word "pool" here in the RPC interface or help,
138 : : * as users will undoubtedly confuse it with the other "memory pool"
139 : : */
140 [ # # ][ # # ]: 0 : return RPCHelpMan{"getmemoryinfo",
[ # # ][ # # ]
[ # # ][ # # ]
141 [ # # ]: 0 : "Returns an object containing information about memory usage.\n",
142 [ # # ]: 0 : {
143 [ # # ][ # # ]: 0 : {"mode", RPCArg::Type::STR, RPCArg::Default{"stats"}, "determines what kind of information is returned.\n"
[ # # ][ # # ]
144 : : " - \"stats\" returns general statistics about memory usage in the daemon.\n"
145 : : " - \"mallocinfo\" returns an XML string describing low-level heap state (only available if compiled with glibc)."},
146 : 0 : },
147 [ # # ]: 0 : {
148 [ # # ][ # # ]: 0 : RPCResult{"mode \"stats\"",
149 [ # # ][ # # ]: 0 : RPCResult::Type::OBJ, "", "",
150 [ # # ]: 0 : {
151 [ # # ][ # # ]: 0 : {RPCResult::Type::OBJ, "locked", "Information about locked memory manager",
[ # # ]
152 [ # # ]: 0 : {
153 [ # # ][ # # ]: 0 : {RPCResult::Type::NUM, "used", "Number of bytes used"},
[ # # ]
154 [ # # ][ # # ]: 0 : {RPCResult::Type::NUM, "free", "Number of bytes available in current arenas"},
[ # # ]
155 [ # # ][ # # ]: 0 : {RPCResult::Type::NUM, "total", "Total number of bytes managed"},
[ # # ]
156 [ # # ][ # # ]: 0 : {RPCResult::Type::NUM, "locked", "Amount of bytes that succeeded locking. If this number is smaller than total, locking pages failed at some point and key data could be swapped to disk."},
[ # # ]
157 [ # # ][ # # ]: 0 : {RPCResult::Type::NUM, "chunks_used", "Number allocated chunks"},
[ # # ]
158 [ # # ][ # # ]: 0 : {RPCResult::Type::NUM, "chunks_free", "Number unused chunks"},
[ # # ]
159 : : }},
160 : : }
161 : : },
162 [ # # ][ # # ]: 0 : RPCResult{"mode \"mallocinfo\"",
163 [ # # ][ # # ]: 0 : RPCResult::Type::STR, "", "\"<malloc version=\"1\">...\""
164 : : },
165 : : },
166 [ # # ]: 0 : RPCExamples{
167 [ # # ][ # # ]: 0 : HelpExampleCli("getmemoryinfo", "")
[ # # ]
168 [ # # ][ # # ]: 0 : + HelpExampleRpc("getmemoryinfo", "")
[ # # ][ # # ]
169 : : },
170 : 0 : [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
171 : : {
172 [ # # ][ # # ]: 0 : std::string mode = request.params[0].isNull() ? "stats" : request.params[0].get_str();
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
173 [ # # ][ # # ]: 0 : if (mode == "stats") {
174 [ # # ]: 0 : UniValue obj(UniValue::VOBJ);
175 [ # # ][ # # ]: 0 : obj.pushKV("locked", RPCLockedMemoryInfo());
[ # # ]
176 : 0 : return obj;
177 [ # # ][ # # ]: 0 : } else if (mode == "mallocinfo") {
[ # # ]
178 : : #ifdef HAVE_MALLOC_INFO
179 [ # # ][ # # ]: 0 : return RPCMallocInfo();
180 : : #else
181 : : throw JSONRPCError(RPC_INVALID_PARAMETER, "mallocinfo mode not available");
182 : : #endif
183 : : } else {
184 [ # # ][ # # ]: 0 : throw JSONRPCError(RPC_INVALID_PARAMETER, "unknown mode " + mode);
[ # # ][ # # ]
185 : : }
186 : 0 : },
187 : : };
188 : 0 : }
189 : :
190 : 0 : static void EnableOrDisableLogCategories(UniValue cats, bool enable) {
191 : 0 : cats = cats.get_array();
192 [ # # ]: 0 : for (unsigned int i = 0; i < cats.size(); ++i) {
193 : 0 : std::string cat = cats[i].get_str();
194 : :
195 : : bool success;
196 [ # # ]: 0 : if (enable) {
197 [ # # ][ # # ]: 0 : success = LogInstance().EnableCategory(cat);
198 : 0 : } else {
199 [ # # ][ # # ]: 0 : success = LogInstance().DisableCategory(cat);
200 : : }
201 : :
202 [ # # ]: 0 : if (!success) {
203 [ # # ][ # # ]: 0 : throw JSONRPCError(RPC_INVALID_PARAMETER, "unknown logging category " + cat);
[ # # ][ # # ]
204 : : }
205 : 0 : }
206 : 0 : }
207 : :
208 : 0 : static RPCHelpMan logging()
209 : : {
210 [ # # ][ # # ]: 0 : return RPCHelpMan{"logging",
[ # # ][ # # ]
[ # # ][ # # ]
211 : : "Gets and sets the logging configuration.\n"
212 : : "When called without an argument, returns the list of categories with status that are currently being debug logged or not.\n"
213 : : "When called with arguments, adds or removes categories from debug logging and return the lists above.\n"
214 : : "The arguments are evaluated in order \"include\", \"exclude\".\n"
215 : : "If an item is both included and excluded, it will thus end up being excluded.\n"
216 [ # # ][ # # ]: 0 : "The valid logging categories are: " + LogInstance().LogCategoriesString() + "\n"
[ # # ][ # # ]
217 : : "In addition, the following are available as category names with special meanings:\n"
218 : : " - \"all\", \"1\" : represent all logging categories.\n"
219 : : " - \"none\", \"0\" : even if other logging categories are specified, ignore all of them.\n"
220 : : ,
221 [ # # ]: 0 : {
222 [ # # ][ # # ]: 0 : {"include", RPCArg::Type::ARR, RPCArg::Optional::OMITTED, "The categories to add to debug logging",
[ # # ]
223 [ # # ]: 0 : {
224 [ # # ][ # # ]: 0 : {"include_category", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "the valid logging category"},
[ # # ]
225 : : }},
226 [ # # ][ # # ]: 0 : {"exclude", RPCArg::Type::ARR, RPCArg::Optional::OMITTED, "The categories to remove from debug logging",
[ # # ]
227 [ # # ]: 0 : {
228 [ # # ][ # # ]: 0 : {"exclude_category", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "the valid logging category"},
[ # # ]
229 : : }},
230 : : },
231 [ # # ][ # # ]: 0 : RPCResult{
232 [ # # ][ # # ]: 0 : RPCResult::Type::OBJ_DYN, "", "keys are the logging categories, and values indicates its status",
233 [ # # ]: 0 : {
234 [ # # ][ # # ]: 0 : {RPCResult::Type::BOOL, "category", "if being debug logged or not. false:inactive, true:active"},
[ # # ]
235 : : }
236 : : },
237 [ # # ]: 0 : RPCExamples{
238 [ # # ][ # # ]: 0 : HelpExampleCli("logging", "\"[\\\"all\\\"]\" \"[\\\"http\\\"]\"")
[ # # ]
239 [ # # ][ # # ]: 0 : + HelpExampleRpc("logging", "[\"all\"], [\"libevent\"]")
[ # # ][ # # ]
240 : : },
241 : 0 : [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
242 : : {
243 : 0 : uint32_t original_log_categories = LogInstance().GetCategoryMask();
244 [ # # ]: 0 : if (request.params[0].isArray()) {
245 [ # # ]: 0 : EnableOrDisableLogCategories(request.params[0], true);
246 : 0 : }
247 [ # # ]: 0 : if (request.params[1].isArray()) {
248 [ # # ]: 0 : EnableOrDisableLogCategories(request.params[1], false);
249 : 0 : }
250 : 0 : uint32_t updated_log_categories = LogInstance().GetCategoryMask();
251 : 0 : uint32_t changed_log_categories = original_log_categories ^ updated_log_categories;
252 : :
253 : : // Update libevent logging if BCLog::LIBEVENT has changed.
254 [ # # ]: 0 : if (changed_log_categories & BCLog::LIBEVENT) {
255 : 0 : UpdateHTTPServerLogging(LogInstance().WillLogCategory(BCLog::LIBEVENT));
256 : 0 : }
257 : :
258 [ # # ]: 0 : UniValue result(UniValue::VOBJ);
259 [ # # ][ # # ]: 0 : for (const auto& logCatActive : LogInstance().LogCategoriesList()) {
[ # # ]
260 [ # # ][ # # ]: 0 : result.pushKV(logCatActive.category, logCatActive.active);
[ # # ]
261 : : }
262 : :
263 : 0 : return result;
264 [ # # ]: 0 : },
265 : : };
266 : 0 : }
267 : :
268 : 0 : static RPCHelpMan echo(const std::string& name)
269 : : {
270 [ # # ][ # # ]: 0 : return RPCHelpMan{name,
271 [ # # ]: 0 : "\nSimply echo back the input arguments. This command is for testing.\n"
272 : : "\nIt will return an internal bug report when arg9='trigger_internal_bug' is passed.\n"
273 : : "\nThe difference between echo and echojson is that echojson has argument conversion enabled in the client-side table in "
274 : : "bitcoin-cli and the GUI. There is no server-side difference.",
275 [ # # ]: 0 : {
276 [ # # ][ # # ]: 0 : {"arg0", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "", RPCArgOptions{.skip_type_check = true}},
[ # # ][ # # ]
[ # # ]
277 [ # # ][ # # ]: 0 : {"arg1", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "", RPCArgOptions{.skip_type_check = true}},
[ # # ][ # # ]
[ # # ]
278 [ # # ][ # # ]: 0 : {"arg2", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "", RPCArgOptions{.skip_type_check = true}},
[ # # ][ # # ]
[ # # ]
279 [ # # ][ # # ]: 0 : {"arg3", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "", RPCArgOptions{.skip_type_check = true}},
[ # # ][ # # ]
[ # # ]
280 [ # # ][ # # ]: 0 : {"arg4", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "", RPCArgOptions{.skip_type_check = true}},
[ # # ][ # # ]
[ # # ]
281 [ # # ][ # # ]: 0 : {"arg5", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "", RPCArgOptions{.skip_type_check = true}},
[ # # ][ # # ]
[ # # ]
282 [ # # ][ # # ]: 0 : {"arg6", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "", RPCArgOptions{.skip_type_check = true}},
[ # # ][ # # ]
[ # # ]
283 [ # # ][ # # ]: 0 : {"arg7", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "", RPCArgOptions{.skip_type_check = true}},
[ # # ][ # # ]
[ # # ]
284 [ # # ][ # # ]: 0 : {"arg8", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "", RPCArgOptions{.skip_type_check = true}},
[ # # ][ # # ]
[ # # ]
285 [ # # ][ # # ]: 0 : {"arg9", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "", RPCArgOptions{.skip_type_check = true}},
[ # # ][ # # ]
[ # # ]
286 : : },
287 [ # # ][ # # ]: 0 : RPCResult{RPCResult::Type::ANY, "", "Returns whatever was passed in"},
[ # # ][ # # ]
288 [ # # ][ # # ]: 0 : RPCExamples{""},
289 : 0 : [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
290 : : {
291 [ # # ]: 0 : if (request.params[9].isStr()) {
292 : 0 : CHECK_NONFATAL(request.params[9].get_str() != "trigger_internal_bug");
293 : 0 : }
294 : :
295 : 0 : return request.params;
296 : : },
297 : : };
298 : 0 : }
299 : :
300 [ # # ][ # # ]: 0 : static RPCHelpMan echo() { return echo("echo"); }
301 [ # # ][ # # ]: 0 : static RPCHelpMan echojson() { return echo("echojson"); }
302 : :
303 : 0 : static RPCHelpMan echoipc()
304 : : {
305 [ # # ][ # # ]: 0 : return RPCHelpMan{
306 [ # # ]: 0 : "echoipc",
307 [ # # ]: 0 : "\nEcho back the input argument, passing it through a spawned process in a multiprocess build.\n"
308 : : "This command is for testing.\n",
309 [ # # ][ # # ]: 0 : {{"arg", RPCArg::Type::STR, RPCArg::Optional::NO, "The string to echo",}},
[ # # ][ # # ]
310 [ # # ][ # # ]: 0 : RPCResult{RPCResult::Type::STR, "echo", "The echoed string."},
[ # # ][ # # ]
311 [ # # ][ # # ]: 0 : RPCExamples{HelpExampleCli("echo", "\"Hello world\"") +
[ # # ][ # # ]
[ # # ]
312 [ # # ][ # # ]: 0 : HelpExampleRpc("echo", "\"Hello world\"")},
[ # # ]
313 : 0 : [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue {
314 : 0 : interfaces::Init& local_init = *EnsureAnyNodeContext(request.context).init;
315 : 0 : std::unique_ptr<interfaces::Echo> echo;
316 [ # # ][ # # ]: 0 : if (interfaces::Ipc* ipc = local_init.ipc()) {
317 : : // Spawn a new bitcoin-node process and call makeEcho to get a
318 : : // client pointer to a interfaces::Echo instance running in
319 : : // that process. This is just for testing. A slightly more
320 : : // realistic test spawning a different executable instead of
321 : : // the same executable would add a new bitcoin-echo executable,
322 : : // and spawn bitcoin-echo below instead of bitcoin-node. But
323 : : // using bitcoin-node avoids the need to build and install a
324 : : // new executable just for this one test.
325 [ # # ]: 0 : auto init = ipc->spawnProcess("bitcoin-node");
326 [ # # ]: 0 : echo = init->makeEcho();
327 [ # # ][ # # ]: 0 : ipc->addCleanup(*echo, [init = init.release()] { delete init; });
328 : 0 : } else {
329 : : // IPC support is not available because this is a bitcoind
330 : : // process not a bitcoind-node process, so just create a local
331 : : // interfaces::Echo object and return it so the `echoipc` RPC
332 : : // method will work, and the python test calling `echoipc`
333 : : // can expect the same result.
334 [ # # ]: 0 : echo = local_init.makeEcho();
335 : : }
336 [ # # ][ # # ]: 0 : return echo->echo(request.params[0].get_str());
[ # # ][ # # ]
337 : 0 : },
338 : : };
339 : 0 : }
340 : :
341 : 0 : static UniValue SummaryToJSON(const IndexSummary&& summary, std::string index_name)
342 : : {
343 [ # # ]: 0 : UniValue ret_summary(UniValue::VOBJ);
344 [ # # ][ # # ]: 0 : if (!index_name.empty() && index_name != summary.name) return ret_summary;
345 : :
346 [ # # ]: 0 : UniValue entry(UniValue::VOBJ);
347 [ # # ][ # # ]: 0 : entry.pushKV("synced", summary.synced);
[ # # ]
348 [ # # ][ # # ]: 0 : entry.pushKV("best_block_height", summary.best_block_height);
[ # # ]
349 [ # # ][ # # ]: 0 : ret_summary.pushKV(summary.name, entry);
[ # # ]
350 : 0 : return ret_summary;
351 [ # # ]: 0 : }
352 : :
353 : 0 : static RPCHelpMan getindexinfo()
354 : : {
355 [ # # ][ # # ]: 0 : return RPCHelpMan{"getindexinfo",
[ # # ][ # # ]
[ # # ]
356 [ # # ]: 0 : "\nReturns the status of one or all available indices currently running in the node.\n",
357 [ # # ]: 0 : {
358 [ # # ][ # # ]: 0 : {"index_name", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Filter results for an index with a specific name."},
[ # # ]
359 : : },
360 [ # # ][ # # ]: 0 : RPCResult{
361 [ # # ][ # # ]: 0 : RPCResult::Type::OBJ_DYN, "", "", {
[ # # ]
362 [ # # ]: 0 : {
363 [ # # ][ # # ]: 0 : RPCResult::Type::OBJ, "name", "The name of the index",
364 [ # # ]: 0 : {
365 [ # # ][ # # ]: 0 : {RPCResult::Type::BOOL, "synced", "Whether the index is synced or not"},
[ # # ]
366 [ # # ][ # # ]: 0 : {RPCResult::Type::NUM, "best_block_height", "The block height to which the index is synced"},
[ # # ]
367 : : }
368 : : },
369 : : },
370 : : },
371 [ # # ]: 0 : RPCExamples{
372 [ # # ][ # # ]: 0 : HelpExampleCli("getindexinfo", "")
[ # # ]
373 [ # # ][ # # ]: 0 : + HelpExampleRpc("getindexinfo", "")
[ # # ][ # # ]
374 [ # # ][ # # ]: 0 : + HelpExampleCli("getindexinfo", "txindex")
[ # # ][ # # ]
375 [ # # ][ # # ]: 0 : + HelpExampleRpc("getindexinfo", "txindex")
[ # # ][ # # ]
376 : : },
377 : 0 : [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
378 : : {
379 [ # # ]: 0 : UniValue result(UniValue::VOBJ);
380 [ # # ][ # # ]: 0 : const std::string index_name = request.params[0].isNull() ? "" : request.params[0].get_str();
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
381 : :
382 [ # # ]: 0 : if (g_txindex) {
383 [ # # ][ # # ]: 0 : result.pushKVs(SummaryToJSON(g_txindex->GetSummary(), index_name));
[ # # ][ # # ]
384 : 0 : }
385 : :
386 [ # # ]: 0 : if (g_coin_stats_index) {
387 [ # # ][ # # ]: 0 : result.pushKVs(SummaryToJSON(g_coin_stats_index->GetSummary(), index_name));
[ # # ][ # # ]
388 : 0 : }
389 : :
390 [ # # ]: 0 : ForEachBlockFilterIndex([&result, &index_name](const BlockFilterIndex& index) {
391 [ # # ][ # # ]: 0 : result.pushKVs(SummaryToJSON(index.GetSummary(), index_name));
[ # # ]
392 : 0 : });
393 : :
394 : 0 : return result;
395 [ # # ]: 0 : },
396 : : };
397 : 0 : }
398 : :
399 : 0 : void RegisterNodeRPCCommands(CRPCTable& t)
400 : : {
401 [ # # ][ # # ]: 0 : static const CRPCCommand commands[]{
[ # # ]
402 [ # # ][ # # ]: 0 : {"control", &getmemoryinfo},
403 [ # # ][ # # ]: 0 : {"control", &logging},
404 [ # # ][ # # ]: 0 : {"util", &getindexinfo},
405 [ # # ][ # # ]: 0 : {"hidden", &setmocktime},
406 [ # # ][ # # ]: 0 : {"hidden", &mockscheduler},
407 [ # # ][ # # ]: 0 : {"hidden", &echo},
408 [ # # ][ # # ]: 0 : {"hidden", &echojson},
409 [ # # ][ # # ]: 0 : {"hidden", &echoipc},
410 : : };
411 [ # # ]: 0 : for (const auto& c : commands) {
412 : 0 : t.appendCommand(c.name, &c);
413 : : }
414 : 0 : }
|