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