Bitcoin Core 30.99.0
P2P Digital Currency
node.cpp
Go to the documentation of this file.
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>
12#include <index/txindex.h>
13#include <interfaces/chain.h>
14#include <interfaces/echo.h>
15#include <interfaces/init.h>
16#include <interfaces/ipc.h>
17#include <kernel/cs_main.h>
18#include <logging.h>
19#include <node/context.h>
20#include <rpc/server.h>
21#include <rpc/server_util.h>
22#include <rpc/util.h>
23#include <scheduler.h>
24#include <tinyformat.h>
25#include <univalue.h>
26#include <util/any.h>
27#include <util/check.h>
28#include <util/time.h>
29
30#include <cstdint>
31#ifdef HAVE_MALLOC_INFO
32#include <malloc.h>
33#endif
34#include <string_view>
35
37
39{
40 return RPCHelpMan{
41 "setmocktime",
42 "Set the local time to given timestamp (-regtest only)\n",
43 {
45 "Pass 0 to go back to using the system time."},
46 },
48 RPCExamples{""},
49 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
50{
51 if (!Params().IsMockableChain()) {
52 throw std::runtime_error("setmocktime is for regression testing (-regtest mode) only");
53 }
54
55 // For now, don't change mocktime if we're in the middle of validation, as
56 // this could have an effect on mempool time-based eviction, as well as
57 // IsCurrentForFeeEstimation() and IsInitialBlockDownload().
58 // TODO: figure out the right way to synchronize around mocktime, and
59 // ensure all call sites of GetTime() are accessing this safely.
61
62 const int64_t time{request.params[0].getInt<int64_t>()};
63 constexpr int64_t max_time{Ticks<std::chrono::seconds>(std::chrono::nanoseconds::max())};
64 if (time < 0 || time > max_time) {
65 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Mocktime must be in the range [0, %s], not %s.", max_time, time));
66 }
67
68 SetMockTime(time);
69 const NodeContext& node_context{EnsureAnyNodeContext(request.context)};
70 for (const auto& chain_client : node_context.chain_clients) {
71 chain_client->setMockTime(time);
72 }
73
74 return UniValue::VNULL;
75},
76 };
77}
78
80{
81 return RPCHelpMan{
82 "mockscheduler",
83 "Bump the scheduler into the future (-regtest only)\n",
84 {
85 {"delta_time", RPCArg::Type::NUM, RPCArg::Optional::NO, "Number of seconds to forward the scheduler into the future." },
86 },
88 RPCExamples{""},
89 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
90{
91 if (!Params().IsMockableChain()) {
92 throw std::runtime_error("mockscheduler is for regression testing (-regtest mode) only");
93 }
94
95 int64_t delta_seconds = request.params[0].getInt<int64_t>();
96 if (delta_seconds <= 0 || delta_seconds > 3600) {
97 throw std::runtime_error("delta_time must be between 1 and 3600 seconds (1 hr)");
98 }
99
100 const NodeContext& node_context{EnsureAnyNodeContext(request.context)};
101 CHECK_NONFATAL(node_context.scheduler)->MockForward(std::chrono::seconds{delta_seconds});
102 CHECK_NONFATAL(node_context.validation_signals)->SyncWithValidationInterfaceQueue();
103 for (const auto& chain_client : node_context.chain_clients) {
104 chain_client->schedulerMockForward(std::chrono::seconds(delta_seconds));
105 }
106
107 return UniValue::VNULL;
108},
109 };
110}
111
113{
116 obj.pushKV("used", uint64_t(stats.used));
117 obj.pushKV("free", uint64_t(stats.free));
118 obj.pushKV("total", uint64_t(stats.total));
119 obj.pushKV("locked", uint64_t(stats.locked));
120 obj.pushKV("chunks_used", uint64_t(stats.chunks_used));
121 obj.pushKV("chunks_free", uint64_t(stats.chunks_free));
122 return obj;
123}
124
125#ifdef HAVE_MALLOC_INFO
126static std::string RPCMallocInfo()
127{
128 char *ptr = nullptr;
129 size_t size = 0;
130 FILE *f = open_memstream(&ptr, &size);
131 if (f) {
132 malloc_info(0, f);
133 fclose(f);
134 if (ptr) {
135 std::string rv(ptr, size);
136 free(ptr);
137 return rv;
138 }
139 }
140 return "";
141}
142#endif
143
145{
146 /* Please, avoid using the word "pool" here in the RPC interface or help,
147 * as users will undoubtedly confuse it with the other "memory pool"
148 */
149 return RPCHelpMan{"getmemoryinfo",
150 "Returns an object containing information about memory usage.\n",
151 {
152 {"mode", RPCArg::Type::STR, RPCArg::Default{"stats"}, "determines what kind of information is returned.\n"
153 " - \"stats\" returns general statistics about memory usage in the daemon.\n"
154 " - \"mallocinfo\" returns an XML string describing low-level heap state (only available if compiled with glibc)."},
155 },
156 {
157 RPCResult{"mode \"stats\"",
158 RPCResult::Type::OBJ, "", "",
159 {
160 {RPCResult::Type::OBJ, "locked", "Information about locked memory manager",
161 {
162 {RPCResult::Type::NUM, "used", "Number of bytes used"},
163 {RPCResult::Type::NUM, "free", "Number of bytes available in current arenas"},
164 {RPCResult::Type::NUM, "total", "Total number of bytes managed"},
165 {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."},
166 {RPCResult::Type::NUM, "chunks_used", "Number allocated chunks"},
167 {RPCResult::Type::NUM, "chunks_free", "Number unused chunks"},
168 }},
169 }
170 },
171 RPCResult{"mode \"mallocinfo\"",
172 RPCResult::Type::STR, "", "\"<malloc version=\"1\">...\""
173 },
174 },
176 HelpExampleCli("getmemoryinfo", "")
177 + HelpExampleRpc("getmemoryinfo", "")
178 },
179 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
180{
181 auto mode{self.Arg<std::string_view>("mode")};
182 if (mode == "stats") {
184 obj.pushKV("locked", RPCLockedMemoryInfo());
185 return obj;
186 } else if (mode == "mallocinfo") {
187#ifdef HAVE_MALLOC_INFO
188 return RPCMallocInfo();
189#else
190 throw JSONRPCError(RPC_INVALID_PARAMETER, "mallocinfo mode not available");
191#endif
192 } else {
193 throw JSONRPCError(RPC_INVALID_PARAMETER, tfm::format("unknown mode %s", mode));
194 }
195},
196 };
197}
198
199static void EnableOrDisableLogCategories(UniValue cats, bool enable) {
200 cats = cats.get_array();
201 for (unsigned int i = 0; i < cats.size(); ++i) {
202 std::string cat = cats[i].get_str();
203
204 bool success;
205 if (enable) {
206 success = LogInstance().EnableCategory(cat);
207 } else {
208 success = LogInstance().DisableCategory(cat);
209 }
210
211 if (!success) {
212 throw JSONRPCError(RPC_INVALID_PARAMETER, "unknown logging category " + cat);
213 }
214 }
215}
216
218{
219 return RPCHelpMan{"logging",
220 "Gets and sets the logging configuration.\n"
221 "When called without an argument, returns the list of categories with status that are currently being debug logged or not.\n"
222 "When called with arguments, adds or removes categories from debug logging and return the lists above.\n"
223 "The arguments are evaluated in order \"include\", \"exclude\".\n"
224 "If an item is both included and excluded, it will thus end up being excluded.\n"
225 "The valid logging categories are: " + LogInstance().LogCategoriesString() + "\n"
226 "In addition, the following are available as category names with special meanings:\n"
227 " - \"all\", \"1\" : represent all logging categories.\n"
228 ,
229 {
230 {"include", RPCArg::Type::ARR, RPCArg::Optional::OMITTED, "The categories to add to debug logging",
231 {
232 {"include_category", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "the valid logging category"},
233 }},
234 {"exclude", RPCArg::Type::ARR, RPCArg::Optional::OMITTED, "The categories to remove from debug logging",
235 {
236 {"exclude_category", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "the valid logging category"},
237 }},
238 },
239 RPCResult{
240 RPCResult::Type::OBJ_DYN, "", "keys are the logging categories, and values indicates its status",
241 {
242 {RPCResult::Type::BOOL, "category", "if being debug logged or not. false:inactive, true:active"},
243 }
244 },
246 HelpExampleCli("logging", "\"[\\\"all\\\"]\" \"[\\\"http\\\"]\"")
247 + HelpExampleRpc("logging", "[\"all\"], [\"libevent\"]")
248 },
249 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
250{
251 BCLog::CategoryMask original_log_categories = LogInstance().GetCategoryMask();
252 if (request.params[0].isArray()) {
253 EnableOrDisableLogCategories(request.params[0], true);
254 }
255 if (request.params[1].isArray()) {
256 EnableOrDisableLogCategories(request.params[1], false);
257 }
258 BCLog::CategoryMask updated_log_categories = LogInstance().GetCategoryMask();
259 BCLog::CategoryMask changed_log_categories = original_log_categories ^ updated_log_categories;
260
261 // Update libevent logging if BCLog::LIBEVENT has changed.
262 if (changed_log_categories & BCLog::LIBEVENT) {
264 }
265
266 UniValue result(UniValue::VOBJ);
267 for (const auto& logCatActive : LogInstance().LogCategoriesList()) {
268 result.pushKV(logCatActive.category, logCatActive.active);
269 }
270
271 return result;
272},
273 };
274}
275
276static RPCHelpMan echo(const std::string& name)
277{
278 return RPCHelpMan{
279 name,
280 "Simply echo back the input arguments. This command is for testing.\n"
281 "\nIt will return an internal bug report when arg9='trigger_internal_bug' is passed.\n"
282 "\nThe difference between echo and echojson is that echojson has argument conversion enabled in the client-side table in "
283 "bitcoin-cli and the GUI. There is no server-side difference.",
284 {
295 },
296 RPCResult{RPCResult::Type::ANY, "", "Returns whatever was passed in"},
297 RPCExamples{""},
298 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
299{
300 if (request.params[9].isStr()) {
301 CHECK_NONFATAL(request.params[9].get_str() != "trigger_internal_bug");
302 }
303
304 return request.params;
305},
306 };
307}
308
309static RPCHelpMan echo() { return echo("echo"); }
310static RPCHelpMan echojson() { return echo("echojson"); }
311
313{
314 return RPCHelpMan{
315 "echoipc",
316 "Echo back the input argument, passing it through a spawned process in a multiprocess build.\n"
317 "This command is for testing.\n",
318 {{"arg", RPCArg::Type::STR, RPCArg::Optional::NO, "The string to echo",}},
319 RPCResult{RPCResult::Type::STR, "echo", "The echoed string."},
320 RPCExamples{HelpExampleCli("echo", "\"Hello world\"") +
321 HelpExampleRpc("echo", "\"Hello world\"")},
322 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue {
323 interfaces::Init& local_init = *EnsureAnyNodeContext(request.context).init;
324 std::unique_ptr<interfaces::Echo> echo;
325 if (interfaces::Ipc* ipc = local_init.ipc()) {
326 // Spawn a new bitcoin-node process and call makeEcho to get a
327 // client pointer to a interfaces::Echo instance running in
328 // that process. This is just for testing. A slightly more
329 // realistic test spawning a different executable instead of
330 // the same executable would add a new bitcoin-echo executable,
331 // and spawn bitcoin-echo below instead of bitcoin-node. But
332 // using bitcoin-node avoids the need to build and install a
333 // new executable just for this one test.
334 auto init = ipc->spawnProcess("bitcoin-node");
335 echo = init->makeEcho();
336 ipc->addCleanup(*echo, [init = init.release()] { delete init; });
337 } else {
338 // IPC support is not available because this is a bitcoind
339 // process not a bitcoind-node process, so just create a local
340 // interfaces::Echo object and return it so the `echoipc` RPC
341 // method will work, and the python test calling `echoipc`
342 // can expect the same result.
343 echo = local_init.makeEcho();
344 }
345 return echo->echo(request.params[0].get_str());
346 },
347 };
348}
349
350static UniValue SummaryToJSON(const IndexSummary&& summary, std::string index_name)
351{
352 UniValue ret_summary(UniValue::VOBJ);
353 if (!index_name.empty() && index_name != summary.name) return ret_summary;
354
356 entry.pushKV("synced", summary.synced);
357 entry.pushKV("best_block_height", summary.best_block_height);
358 ret_summary.pushKV(summary.name, std::move(entry));
359 return ret_summary;
360}
361
363{
364 return RPCHelpMan{
365 "getindexinfo",
366 "Returns the status of one or all available indices currently running in the node.\n",
367 {
368 {"index_name", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Filter results for an index with a specific name."},
369 },
370 RPCResult{
371 RPCResult::Type::OBJ_DYN, "", "", {
372 {
373 RPCResult::Type::OBJ, "name", "The name of the index",
374 {
375 {RPCResult::Type::BOOL, "synced", "Whether the index is synced or not"},
376 {RPCResult::Type::NUM, "best_block_height", "The block height to which the index is synced"},
377 }
378 },
379 },
380 },
382 HelpExampleCli("getindexinfo", "")
383 + HelpExampleRpc("getindexinfo", "")
384 + HelpExampleCli("getindexinfo", "txindex")
385 + HelpExampleRpc("getindexinfo", "txindex")
386 },
387 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
388{
389 UniValue result(UniValue::VOBJ);
390 const std::string index_name{self.MaybeArg<std::string_view>("index_name").value_or("")};
391
392 if (g_txindex) {
393 result.pushKVs(SummaryToJSON(g_txindex->GetSummary(), index_name));
394 }
395
396 if (g_coin_stats_index) {
397 result.pushKVs(SummaryToJSON(g_coin_stats_index->GetSummary(), index_name));
398 }
399
400 ForEachBlockFilterIndex([&result, &index_name](const BlockFilterIndex& index) {
401 result.pushKVs(SummaryToJSON(index.GetSummary(), index_name));
402 });
403
404 return result;
405},
406 };
407}
408
410{
411 static const CRPCCommand commands[]{
412 {"control", &getmemoryinfo},
413 {"control", &logging},
414 {"util", &getindexinfo},
415 {"hidden", &setmocktime},
416 {"hidden", &mockscheduler},
417 {"hidden", &echo},
418 {"hidden", &echojson},
419 {"hidden", &echoipc},
420 };
421 for (const auto& c : commands) {
422 t.appendCommand(c.name, &c);
423 }
424}
void ForEachBlockFilterIndex(std::function< void(BlockFilterIndex &)> fn)
Iterate over all running block filter indexes, invoking fn on each.
const CChainParams & Params()
Return the currently selected parameters.
#define CHECK_NONFATAL(condition)
Identity function.
Definition: check.h:111
CategoryMask GetCategoryMask() const
Definition: logging.h:296
void EnableCategory(LogFlags flag)
Definition: logging.cpp:123
std::string LogCategoriesString() const
Returns a string with the log categories in alphabetical order.
Definition: logging.h:309
void DisableCategory(LogFlags flag)
Definition: logging.cpp:136
IndexSummary GetSummary() const
Get a summary of the index and its state.
Definition: base.cpp:473
BlockFilterIndex is used to store and retrieve block filters, hashes, and headers for a range of bloc...
bool IsMockableChain() const
If this chain allows time to be mocked.
Definition: chainparams.h:101
RPC command dispatcher.
Definition: server.h:87
Stats stats() const
Get pool usage statistics.
Definition: lockedpool.cpp:320
static LockedPoolManager & Instance()
Return the current instance, or create it once.
Definition: lockedpool.h:222
auto Arg(std::string_view key) const
Helper to get a required or default-valued request argument.
Definition: util.h:444
auto MaybeArg(std::string_view key) const
Helper to get an optional request argument.
Definition: util.h:476
const std::string & get_str() const
@ VNULL
Definition: univalue.h:24
@ VOBJ
Definition: univalue.h:24
size_t size() const
Definition: univalue.h:71
void pushKVs(UniValue obj)
Definition: univalue.cpp:137
const UniValue & get_array() const
void pushKV(std::string key, UniValue val)
Definition: univalue.cpp:126
Initial interface created when a process is first started, and used to give and get access to other i...
Definition: init.h:31
virtual std::unique_ptr< Echo > makeEcho()
Definition: init.h:38
virtual Ipc * ipc()
Definition: init.h:39
Interface providing access to interprocess-communication (IPC) functionality.
Definition: ipc.h:50
std::unique_ptr< CoinStatsIndex > g_coin_stats_index
The global UTXO set hash object.
RecursiveMutex cs_main
Mutex to guard access to validation specific variables, such as reading or changing the chainstate.
Definition: cs_main.cpp:8
void UpdateHTTPServerLogging(bool enable)
Change logging level for libevent.
Definition: httpserver.cpp:490
BCLog::Logger & LogInstance()
Definition: logging.cpp:26
uint64_t CategoryMask
Definition: logging.h:63
@ LIBEVENT
Definition: logging.h:83
Definition: ipc.h:12
void format(std::ostream &out, FormatStringCheck< sizeof...(Args)> fmt, const Args &... args)
Format list of arguments to the stream according to given format string.
Definition: tinyformat.h:1079
static RPCHelpMan logging()
Definition: node.cpp:217
static RPCHelpMan setmocktime()
Definition: node.cpp:38
void RegisterNodeRPCCommands(CRPCTable &t)
Definition: node.cpp:409
static void EnableOrDisableLogCategories(UniValue cats, bool enable)
Definition: node.cpp:199
static UniValue RPCLockedMemoryInfo()
Definition: node.cpp:112
static RPCHelpMan mockscheduler()
Definition: node.cpp:79
static RPCHelpMan getmemoryinfo()
Definition: node.cpp:144
static RPCHelpMan echo(const std::string &name)
Definition: node.cpp:276
static UniValue SummaryToJSON(const IndexSummary &&summary, std::string index_name)
Definition: node.cpp:350
static RPCHelpMan echojson()
Definition: node.cpp:310
static RPCHelpMan echoipc()
Definition: node.cpp:312
static RPCHelpMan getindexinfo()
Definition: node.cpp:362
UniValue JSONRPCError(int code, const std::string &message)
Definition: request.cpp:70
const char * name
Definition: rest.cpp:50
@ RPC_INVALID_PARAMETER
Invalid, missing or duplicate parameter.
Definition: protocol.h:44
std::string HelpExampleCli(const std::string &methodname, const std::string &args)
Definition: util.cpp:186
std::string HelpExampleRpc(const std::string &methodname, const std::string &args)
Definition: util.cpp:204
const std::string UNIX_EPOCH_TIME
String used to describe UNIX epoch time in documentation, factored out to a constant for consistency.
Definition: util.cpp:46
NodeContext & EnsureAnyNodeContext(const std::any &context)
Definition: server_util.cpp:25
Memory statistics.
Definition: lockedpool.h:146
@ OMITTED
Optional argument for which the default value is omitted from help text for one of two reasons:
@ NO
Required arg.
bool skip_type_check
Definition: util.h:170
@ ANY
Special type to disable type checks (for testing only)
@ OBJ_DYN
Special dictionary with keys that are not literals.
NodeContext struct containing references to chain state and connection state.
Definition: context.h:56
interfaces::Init * init
Init interface for initializing current process and connecting to other processes.
Definition: context.h:61
#define LOCK(cs)
Definition: sync.h:259
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1172
std::unique_ptr< TxIndex > g_txindex
The global transaction index, used in GetTransaction. May be null.
Definition: txindex.cpp:35
void SetMockTime(int64_t nMockTimeIn)
DEPRECATED Use SetMockTime with chrono type.
Definition: time.cpp:40