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