Line data Source code
1 : // Copyright (c) 2010 Satoshi Nakamoto
2 : // Copyright (c) 2009-2020 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 <httpserver.h>
7 : #include <index/blockfilterindex.h>
8 : #include <index/txindex.h>
9 : #include <interfaces/chain.h>
10 : #include <key_io.h>
11 : #include <node/context.h>
12 : #include <outputtype.h>
13 : #include <rpc/blockchain.h>
14 : #include <rpc/server.h>
15 : #include <rpc/util.h>
16 : #include <scheduler.h>
17 : #include <script/descriptor.h>
18 : #include <util/check.h>
19 : #include <util/message.h> // For MessageSign(), MessageVerify()
20 : #include <util/ref.h>
21 : #include <util/strencodings.h>
22 : #include <util/system.h>
23 :
24 : #include <stdint.h>
25 : #include <tuple>
26 : #ifdef HAVE_MALLOC_INFO
27 : #include <malloc.h>
28 : #endif
29 :
30 : #include <univalue.h>
31 :
32 2386 : static RPCHelpMan validateaddress()
33 : {
34 19088 : return RPCHelpMan{"validateaddress",
35 2386 : "\nReturn information about the given bitcoin address.\n",
36 4772 : {
37 2386 : {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The bitcoin address to validate"},
38 : },
39 2386 : RPCResult{
40 2386 : RPCResult::Type::OBJ, "", "",
41 19088 : {
42 2386 : {RPCResult::Type::BOOL, "isvalid", "If the address is valid or not. If not, this is the only property returned."},
43 2386 : {RPCResult::Type::STR, "address", "The bitcoin address validated"},
44 2386 : {RPCResult::Type::STR_HEX, "scriptPubKey", "The hex-encoded scriptPubKey generated by the address"},
45 2386 : {RPCResult::Type::BOOL, "isscript", "If the key is a script"},
46 2386 : {RPCResult::Type::BOOL, "iswitness", "If the address is a witness address"},
47 2386 : {RPCResult::Type::NUM, "witness_version", /* optional */ true, "The version number of the witness program"},
48 2386 : {RPCResult::Type::STR_HEX, "witness_program", /* optional */ true, "The hex value of the witness program"},
49 : }
50 : },
51 2386 : RPCExamples{
52 4772 : HelpExampleCli("validateaddress", "\"" + EXAMPLE_ADDRESS[0] + "\"") +
53 2386 : HelpExampleRpc("validateaddress", "\"" + EXAMPLE_ADDRESS[0] + "\"")
54 : },
55 2556 : [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
56 : {
57 170 : CTxDestination dest = DecodeDestination(request.params[0].get_str());
58 170 : bool isValid = IsValidDestination(dest);
59 :
60 170 : UniValue ret(UniValue::VOBJ);
61 170 : ret.pushKV("isvalid", isValid);
62 170 : if (isValid)
63 : {
64 169 : std::string currentAddress = EncodeDestination(dest);
65 169 : ret.pushKV("address", currentAddress);
66 :
67 169 : CScript scriptPubKey = GetScriptForDestination(dest);
68 169 : ret.pushKV("scriptPubKey", HexStr(scriptPubKey));
69 :
70 169 : UniValue detail = DescribeAddress(dest);
71 169 : ret.pushKVs(detail);
72 169 : }
73 : return ret;
74 170 : },
75 : };
76 0 : }
77 :
78 2313 : static RPCHelpMan createmultisig()
79 : {
80 13878 : return RPCHelpMan{"createmultisig",
81 2313 : "\nCreates a multi-signature address with n signature of m keys required.\n"
82 : "It returns a json object with the address and redeemScript.\n",
83 9252 : {
84 2313 : {"nrequired", RPCArg::Type::NUM, RPCArg::Optional::NO, "The number of required signatures out of the n keys."},
85 4626 : {"keys", RPCArg::Type::ARR, RPCArg::Optional::NO, "The hex-encoded public keys.",
86 4626 : {
87 2313 : {"key", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "The hex-encoded public key"},
88 : }},
89 2313 : {"address_type", RPCArg::Type::STR, /* default */ "legacy", "The address type to use. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."},
90 : },
91 2313 : RPCResult{
92 2313 : RPCResult::Type::OBJ, "", "",
93 9252 : {
94 2313 : {RPCResult::Type::STR, "address", "The value of the new multisig address."},
95 2313 : {RPCResult::Type::STR_HEX, "redeemScript", "The string value of the hex-encoded redemption script."},
96 2313 : {RPCResult::Type::STR, "descriptor", "The descriptor for this multisig"},
97 : }
98 : },
99 2313 : RPCExamples{
100 2313 : "\nCreate a multisig address from 2 public keys\n"
101 2313 : + HelpExampleCli("createmultisig", "2 \"[\\\"03789ed0bb717d88f7d321a368d905e7430207ebbd82bd342cf11ae157a7ace5fd\\\",\\\"03dbc6764b8884a92e871274b87583e6d5c2a58819473e17e107ef3f6aa5a61626\\\"]\"") +
102 : "\nAs a JSON-RPC call\n"
103 2313 : + HelpExampleRpc("createmultisig", "2, \"[\\\"03789ed0bb717d88f7d321a368d905e7430207ebbd82bd342cf11ae157a7ace5fd\\\",\\\"03dbc6764b8884a92e871274b87583e6d5c2a58819473e17e107ef3f6aa5a61626\\\"]\"")
104 : },
105 2410 : [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
106 : {
107 97 : int required = request.params[0].get_int();
108 :
109 : // Get the public keys
110 97 : const UniValue& keys = request.params[1].get_array();
111 97 : std::vector<CPubKey> pubkeys;
112 418 : for (unsigned int i = 0; i < keys.size(); ++i) {
113 321 : if (IsHex(keys[i].get_str()) && (keys[i].get_str().length() == 66 || keys[i].get_str().length() == 130)) {
114 319 : pubkeys.push_back(HexToPubKey(keys[i].get_str()));
115 : } else {
116 2 : throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Invalid public key: %s\n.", keys[i].get_str()));
117 : }
118 : }
119 :
120 : // Get the output type
121 95 : OutputType output_type = OutputType::LEGACY;
122 95 : if (!request.params[2].isNull()) {
123 93 : if (!ParseOutputType(request.params[2].get_str(), output_type)) {
124 0 : throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Unknown address type '%s'", request.params[2].get_str()));
125 : }
126 : }
127 :
128 : // Construct using pay-to-script-hash:
129 95 : FillableSigningProvider keystore;
130 95 : CScript inner;
131 95 : const CTxDestination dest = AddAndGetMultisigDestination(required, pubkeys, output_type, keystore, inner);
132 :
133 : // Make the descriptor
134 95 : std::unique_ptr<Descriptor> descriptor = InferDescriptor(GetScriptForDestination(dest), keystore);
135 :
136 95 : UniValue result(UniValue::VOBJ);
137 95 : result.pushKV("address", EncodeDestination(dest));
138 95 : result.pushKV("redeemScript", HexStr(inner));
139 95 : result.pushKV("descriptor", descriptor->ToString());
140 :
141 : return result;
142 99 : },
143 : };
144 0 : }
145 :
146 2505 : static RPCHelpMan getdescriptorinfo()
147 : {
148 15030 : return RPCHelpMan{"getdescriptorinfo",
149 2505 : {"\nAnalyses a descriptor.\n"},
150 5010 : {
151 2505 : {"descriptor", RPCArg::Type::STR, RPCArg::Optional::NO, "The descriptor."},
152 : },
153 2505 : RPCResult{
154 2505 : RPCResult::Type::OBJ, "", "",
155 15030 : {
156 2505 : {RPCResult::Type::STR, "descriptor", "The descriptor in canonical form, without private keys"},
157 2505 : {RPCResult::Type::STR, "checksum", "The checksum for the input descriptor"},
158 2505 : {RPCResult::Type::BOOL, "isrange", "Whether the descriptor is ranged"},
159 2505 : {RPCResult::Type::BOOL, "issolvable", "Whether the descriptor is solvable"},
160 2505 : {RPCResult::Type::BOOL, "hasprivatekeys", "Whether the input descriptor contained at least one private key"},
161 : }
162 : },
163 2505 : RPCExamples{
164 2505 : "Analyse a descriptor\n" +
165 2505 : HelpExampleCli("getdescriptorinfo", "\"wpkh([d34db33f/84h/0h/0h]0279be667ef9dcbbac55a06295Ce870b07029Bfcdb2dce28d959f2815b16f81798)\"")
166 : },
167 2793 : [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
168 : {
169 289 : RPCTypeCheck(request.params, {UniValue::VSTR});
170 :
171 287 : FlatSigningProvider provider;
172 287 : std::string error;
173 287 : auto desc = Parse(request.params[0].get_str(), provider, error);
174 287 : if (!desc) {
175 1 : throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, error);
176 : }
177 :
178 286 : UniValue result(UniValue::VOBJ);
179 286 : result.pushKV("descriptor", desc->ToString());
180 286 : result.pushKV("checksum", GetDescriptorChecksum(request.params[0].get_str()));
181 286 : result.pushKV("isrange", desc->IsRange());
182 286 : result.pushKV("issolvable", desc->IsSolvable());
183 286 : result.pushKV("hasprivatekeys", provider.keys.size() > 0);
184 : return result;
185 288 : },
186 : };
187 0 : }
188 :
189 2262 : static RPCHelpMan deriveaddresses()
190 : {
191 6786 : return RPCHelpMan{"deriveaddresses",
192 2262 : {"\nDerives one or more addresses corresponding to an output descriptor.\n"
193 : "Examples of output descriptors are:\n"
194 : " pkh(<pubkey>) P2PKH outputs for the given pubkey\n"
195 : " wpkh(<pubkey>) Native segwit P2PKH outputs for the given pubkey\n"
196 : " sh(multi(<n>,<pubkey>,<pubkey>,...)) P2SH-multisig outputs for the given threshold and pubkeys\n"
197 : " raw(<hex script>) Outputs whose scriptPubKey equals the specified hex scripts\n"
198 : "\nIn the above, <pubkey> either refers to a fixed public key in hexadecimal notation, or to an xpub/xprv optionally followed by one\n"
199 : "or more path elements separated by \"/\", where \"h\" represents a hardened child key.\n"
200 : "For more information on output descriptors, see the documentation in the doc/descriptors.md file.\n"},
201 6786 : {
202 2262 : {"descriptor", RPCArg::Type::STR, RPCArg::Optional::NO, "The descriptor."},
203 2262 : {"range", RPCArg::Type::RANGE, RPCArg::Optional::OMITTED_NAMED_ARG, "If a ranged descriptor is used, this specifies the end or the range (in [begin,end] notation) to derive."},
204 : },
205 2262 : RPCResult{
206 2262 : RPCResult::Type::ARR, "", "",
207 4524 : {
208 2262 : {RPCResult::Type::STR, "address", "the derived addresses"},
209 : }
210 : },
211 2262 : RPCExamples{
212 2262 : "First three native segwit receive addresses\n" +
213 2262 : HelpExampleCli("deriveaddresses", "\"wpkh([d34db33f/84h/0h/0h]xpub6DJ2dNUysrn5Vt36jH2KLBT2i1auw1tTSSomg8PhqNiUtx8QX2SvC9nrHu81fT41fvDUnhMjEzQgXnQjKEu3oaqMSzhSrHMxyyoEAmUHQbY/0/*)#cjjspncu\" \"[0,2]\"")
214 : },
215 2308 : [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
216 : {
217 66 : RPCTypeCheck(request.params, {UniValue::VSTR, UniValueType()}); // Range argument is checked later
218 46 : const std::string desc_str = request.params[0].get_str();
219 :
220 46 : int64_t range_begin = 0;
221 46 : int64_t range_end = 0;
222 :
223 46 : if (request.params.size() >= 2 && !request.params[1].isNull()) {
224 14 : std::tie(range_begin, range_end) = ParseDescriptorRange(request.params[1]);
225 6 : }
226 :
227 38 : FlatSigningProvider key_provider;
228 38 : std::string error;
229 38 : auto desc = Parse(desc_str, key_provider, error, /* require_checksum = */ true);
230 38 : if (!desc) {
231 4 : throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, error);
232 : }
233 :
234 34 : if (!desc->IsRange() && request.params.size() > 1) {
235 2 : throw JSONRPCError(RPC_INVALID_PARAMETER, "Range should not be specified for an un-ranged descriptor");
236 : }
237 :
238 32 : if (desc->IsRange() && request.params.size() == 1) {
239 2 : throw JSONRPCError(RPC_INVALID_PARAMETER, "Range must be specified for a ranged descriptor");
240 : }
241 :
242 30 : UniValue addresses(UniValue::VARR);
243 :
244 66 : for (int i = range_begin; i <= range_end; ++i) {
245 36 : FlatSigningProvider provider;
246 36 : std::vector<CScript> scripts;
247 36 : if (!desc->Expand(i, key_provider, scripts, provider)) {
248 2 : throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Cannot derive script without private keys"));
249 : }
250 :
251 74 : for (const CScript &script : scripts) {
252 40 : CTxDestination dest;
253 40 : if (!ExtractDestination(script, dest)) {
254 2 : throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Descriptor does not have a corresponding address"));
255 : }
256 :
257 38 : addresses.push_back(EncodeDestination(dest));
258 40 : }
259 36 : }
260 :
261 : // This should not be possible, but an assert seems overkill:
262 26 : if (addresses.empty()) {
263 0 : throw JSONRPCError(RPC_MISC_ERROR, "Unexpected empty result");
264 : }
265 :
266 : return addresses;
267 50 : },
268 : };
269 0 : }
270 :
271 2228 : static RPCHelpMan verifymessage()
272 : {
273 8912 : return RPCHelpMan{"verifymessage",
274 2228 : "\nVerify a signed message\n",
275 8912 : {
276 2228 : {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The bitcoin address to use for the signature."},
277 2228 : {"signature", RPCArg::Type::STR, RPCArg::Optional::NO, "The signature provided by the signer in base 64 encoding (see signmessage)."},
278 2228 : {"message", RPCArg::Type::STR, RPCArg::Optional::NO, "The message that was signed."},
279 : },
280 2228 : RPCResult{
281 2228 : RPCResult::Type::BOOL, "", "If the signature is verified or not."
282 : },
283 2228 : RPCExamples{
284 2228 : "\nUnlock the wallet for 30 seconds\n"
285 2228 : + HelpExampleCli("walletpassphrase", "\"mypassphrase\" 30") +
286 : "\nCreate the signature\n"
287 2228 : + HelpExampleCli("signmessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"my message\"") +
288 : "\nVerify the signature\n"
289 2228 : + HelpExampleCli("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"signature\" \"my message\"") +
290 : "\nAs a JSON-RPC call\n"
291 2228 : + HelpExampleRpc("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\", \"signature\", \"my message\"")
292 : },
293 2240 : [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
294 : {
295 12 : LOCK(cs_main);
296 :
297 12 : std::string strAddress = request.params[0].get_str();
298 12 : std::string strSign = request.params[1].get_str();
299 12 : std::string strMessage = request.params[2].get_str();
300 :
301 12 : switch (MessageVerify(strAddress, strSign, strMessage)) {
302 : case MessageVerificationResult::ERR_INVALID_ADDRESS:
303 0 : throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
304 : case MessageVerificationResult::ERR_ADDRESS_NO_KEY:
305 0 : throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
306 : case MessageVerificationResult::ERR_MALFORMED_SIGNATURE:
307 0 : throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Malformed base64 encoding");
308 : case MessageVerificationResult::ERR_PUBKEY_NOT_RECOVERED:
309 : case MessageVerificationResult::ERR_NOT_SIGNED:
310 2 : return false;
311 : case MessageVerificationResult::OK:
312 10 : return true;
313 : }
314 :
315 0 : return false;
316 12 : },
317 : };
318 0 : }
319 :
320 2217 : static RPCHelpMan signmessagewithprivkey()
321 : {
322 6651 : return RPCHelpMan{"signmessagewithprivkey",
323 2217 : "\nSign a message with the private key of an address\n",
324 6651 : {
325 2217 : {"privkey", RPCArg::Type::STR, RPCArg::Optional::NO, "The private key to sign the message with."},
326 2217 : {"message", RPCArg::Type::STR, RPCArg::Optional::NO, "The message to create a signature of."},
327 : },
328 2217 : RPCResult{
329 2217 : RPCResult::Type::STR, "signature", "The signature of the message encoded in base 64"
330 : },
331 2217 : RPCExamples{
332 2217 : "\nCreate the signature\n"
333 2217 : + HelpExampleCli("signmessagewithprivkey", "\"privkey\" \"my message\"") +
334 : "\nVerify the signature\n"
335 2217 : + HelpExampleCli("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"signature\" \"my message\"") +
336 : "\nAs a JSON-RPC call\n"
337 2217 : + HelpExampleRpc("signmessagewithprivkey", "\"privkey\", \"my message\"")
338 : },
339 2218 : [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
340 : {
341 1 : std::string strPrivkey = request.params[0].get_str();
342 1 : std::string strMessage = request.params[1].get_str();
343 :
344 1 : CKey key = DecodeSecret(strPrivkey);
345 1 : if (!key.IsValid()) {
346 0 : throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key");
347 : }
348 :
349 1 : std::string signature;
350 :
351 1 : if (!MessageSign(key, strMessage, signature)) {
352 0 : throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Sign failed");
353 : }
354 :
355 1 : return signature;
356 1 : },
357 : };
358 0 : }
359 :
360 2692 : static RPCHelpMan setmocktime()
361 : {
362 5384 : return RPCHelpMan{"setmocktime",
363 2692 : "\nSet the local time to given timestamp (-regtest only)\n",
364 5384 : {
365 2692 : {"timestamp", RPCArg::Type::NUM, RPCArg::Optional::NO, UNIX_EPOCH_TIME + "\n"
366 : " Pass 0 to go back to using the system time."},
367 : },
368 2692 : RPCResult{RPCResult::Type::NONE, "", ""},
369 2692 : RPCExamples{""},
370 3172 : [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
371 : {
372 480 : if (!Params().IsMockableChain()) {
373 0 : throw std::runtime_error("setmocktime is for regression testing (-regtest mode) only");
374 : }
375 :
376 : // For now, don't change mocktime if we're in the middle of validation, as
377 : // this could have an effect on mempool time-based eviction, as well as
378 : // IsCurrentForFeeEstimation() and IsInitialBlockDownload().
379 : // TODO: figure out the right way to synchronize around mocktime, and
380 : // ensure all call sites of GetTime() are accessing this safely.
381 480 : LOCK(cs_main);
382 :
383 480 : RPCTypeCheck(request.params, {UniValue::VNUM});
384 480 : int64_t time = request.params[0].get_int64();
385 480 : SetMockTime(time);
386 480 : if (request.context.Has<NodeContext>()) {
387 959 : for (const auto& chain_client : request.context.Get<NodeContext>().chain_clients) {
388 479 : chain_client->setMockTime(time);
389 : }
390 480 : }
391 :
392 480 : return NullUniValue;
393 480 : },
394 : };
395 0 : }
396 :
397 2215 : static RPCHelpMan mockscheduler()
398 : {
399 4430 : return RPCHelpMan{"mockscheduler",
400 2215 : "\nBump the scheduler into the future (-regtest only)\n",
401 4430 : {
402 2215 : {"delta_time", RPCArg::Type::NUM, RPCArg::Optional::NO, "Number of seconds to forward the scheduler into the future." },
403 : },
404 2215 : RPCResult{RPCResult::Type::NONE, "", ""},
405 2215 : RPCExamples{""},
406 2218 : [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
407 : {
408 3 : if (!Params().IsMockableChain()) {
409 0 : throw std::runtime_error("mockscheduler is for regression testing (-regtest mode) only");
410 : }
411 :
412 : // check params are valid values
413 3 : RPCTypeCheck(request.params, {UniValue::VNUM});
414 3 : int64_t delta_seconds = request.params[0].get_int64();
415 3 : if ((delta_seconds <= 0) || (delta_seconds > 3600)) {
416 0 : throw std::runtime_error("delta_time must be between 1 and 3600 seconds (1 hr)");
417 : }
418 :
419 : // protect against null pointer dereference
420 3 : CHECK_NONFATAL(request.context.Has<NodeContext>());
421 3 : NodeContext& node = request.context.Get<NodeContext>();
422 3 : CHECK_NONFATAL(node.scheduler);
423 3 : node.scheduler->MockForward(std::chrono::seconds(delta_seconds));
424 :
425 3 : return NullUniValue;
426 3 : },
427 : };
428 0 : }
429 :
430 1 : static UniValue RPCLockedMemoryInfo()
431 : {
432 1 : LockedPool::Stats stats = LockedPoolManager::Instance().stats();
433 1 : UniValue obj(UniValue::VOBJ);
434 1 : obj.pushKV("used", uint64_t(stats.used));
435 1 : obj.pushKV("free", uint64_t(stats.free));
436 1 : obj.pushKV("total", uint64_t(stats.total));
437 1 : obj.pushKV("locked", uint64_t(stats.locked));
438 1 : obj.pushKV("chunks_used", uint64_t(stats.chunks_used));
439 1 : obj.pushKV("chunks_free", uint64_t(stats.chunks_free));
440 : return obj;
441 1 : }
442 :
443 : #ifdef HAVE_MALLOC_INFO
444 : static std::string RPCMallocInfo()
445 : {
446 : char *ptr = nullptr;
447 : size_t size = 0;
448 : FILE *f = open_memstream(&ptr, &size);
449 : if (f) {
450 : malloc_info(0, f);
451 : fclose(f);
452 : if (ptr) {
453 : std::string rv(ptr, size);
454 : free(ptr);
455 : return rv;
456 : }
457 : }
458 : return "";
459 : }
460 : #endif
461 :
462 2220 : static RPCHelpMan getmemoryinfo()
463 : {
464 : /* Please, avoid using the word "pool" here in the RPC interface or help,
465 : * as users will undoubtedly confuse it with the other "memory pool"
466 : */
467 17760 : return RPCHelpMan{"getmemoryinfo",
468 2220 : "Returns an object containing information about memory usage.\n",
469 4440 : {
470 2220 : {"mode", RPCArg::Type::STR, /* default */ "\"stats\"", "determines what kind of information is returned.\n"
471 : " - \"stats\" returns general statistics about memory usage in the daemon.\n"
472 : " - \"mallocinfo\" returns an XML string describing low-level heap state (only available if compiled with glibc 2.10+)."},
473 : },
474 6660 : {
475 4440 : RPCResult{"mode \"stats\"",
476 2220 : RPCResult::Type::OBJ, "", "",
477 4440 : {
478 4440 : {RPCResult::Type::OBJ, "locked", "Information about locked memory manager",
479 15540 : {
480 2220 : {RPCResult::Type::NUM, "used", "Number of bytes used"},
481 2220 : {RPCResult::Type::NUM, "free", "Number of bytes available in current arenas"},
482 2220 : {RPCResult::Type::NUM, "total", "Total number of bytes managed"},
483 2220 : {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."},
484 2220 : {RPCResult::Type::NUM, "chunks_used", "Number allocated chunks"},
485 2220 : {RPCResult::Type::NUM, "chunks_free", "Number unused chunks"},
486 : }},
487 : }
488 : },
489 4440 : RPCResult{"mode \"mallocinfo\"",
490 2220 : RPCResult::Type::STR, "", "\"<malloc version=\"1\">...\""
491 : },
492 : },
493 2220 : RPCExamples{
494 2220 : HelpExampleCli("getmemoryinfo", "")
495 2220 : + HelpExampleRpc("getmemoryinfo", "")
496 : },
497 2224 : [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
498 : {
499 4 : std::string mode = request.params[0].isNull() ? "stats" : request.params[0].get_str();
500 4 : if (mode == "stats") {
501 1 : UniValue obj(UniValue::VOBJ);
502 1 : obj.pushKV("locked", RPCLockedMemoryInfo());
503 : return obj;
504 4 : } else if (mode == "mallocinfo") {
505 : #ifdef HAVE_MALLOC_INFO
506 : return RPCMallocInfo();
507 : #else
508 2 : throw JSONRPCError(RPC_INVALID_PARAMETER, "mallocinfo is only available when compiled with glibc 2.10+");
509 : #endif
510 : } else {
511 1 : throw JSONRPCError(RPC_INVALID_PARAMETER, "unknown mode " + mode);
512 : }
513 4 : },
514 : };
515 0 : }
516 :
517 2 : static void EnableOrDisableLogCategories(UniValue cats, bool enable) {
518 2 : cats = cats.get_array();
519 4 : for (unsigned int i = 0; i < cats.size(); ++i) {
520 2 : std::string cat = cats[i].get_str();
521 :
522 : bool success;
523 2 : if (enable) {
524 1 : success = LogInstance().EnableCategory(cat);
525 1 : } else {
526 1 : success = LogInstance().DisableCategory(cat);
527 : }
528 :
529 2 : if (!success) {
530 0 : throw JSONRPCError(RPC_INVALID_PARAMETER, "unknown logging category " + cat);
531 : }
532 2 : }
533 2 : }
534 :
535 2221 : static RPCHelpMan logging()
536 : {
537 6663 : return RPCHelpMan{"logging",
538 2221 : "Gets and sets the logging configuration.\n"
539 : "When called without an argument, returns the list of categories with status that are currently being debug logged or not.\n"
540 : "When called with arguments, adds or removes categories from debug logging and return the lists above.\n"
541 : "The arguments are evaluated in order \"include\", \"exclude\".\n"
542 : "If an item is both included and excluded, it will thus end up being excluded.\n"
543 2221 : "The valid logging categories are: " + LogInstance().LogCategoriesString() + "\n"
544 : "In addition, the following are available as category names with special meanings:\n"
545 : " - \"all\", \"1\" : represent all logging categories.\n"
546 : " - \"none\", \"0\" : even if other logging categories are specified, ignore all of them.\n"
547 : ,
548 6663 : {
549 4442 : {"include", RPCArg::Type::ARR, RPCArg::Optional::OMITTED_NAMED_ARG, "The categories to add to debug logging",
550 4442 : {
551 2221 : {"include_category", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "the valid logging category"},
552 : }},
553 4442 : {"exclude", RPCArg::Type::ARR, RPCArg::Optional::OMITTED_NAMED_ARG, "The categories to remove from debug logging",
554 4442 : {
555 2221 : {"exclude_category", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "the valid logging category"},
556 : }},
557 : },
558 2221 : RPCResult{
559 2221 : RPCResult::Type::OBJ_DYN, "", "keys are the logging categories, and values indicates its status",
560 4442 : {
561 2221 : {RPCResult::Type::BOOL, "category", "if being debug logged or not. false:inactive, true:active"},
562 : }
563 : },
564 2221 : RPCExamples{
565 2221 : HelpExampleCli("logging", "\"[\\\"all\\\"]\" \"[\\\"http\\\"]\"")
566 2221 : + HelpExampleRpc("logging", "[\"all\"], [\"libevent\"]")
567 : },
568 2226 : [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
569 : {
570 5 : uint32_t original_log_categories = LogInstance().GetCategoryMask();
571 5 : if (request.params[0].isArray()) {
572 1 : EnableOrDisableLogCategories(request.params[0], true);
573 1 : }
574 5 : if (request.params[1].isArray()) {
575 1 : EnableOrDisableLogCategories(request.params[1], false);
576 1 : }
577 5 : uint32_t updated_log_categories = LogInstance().GetCategoryMask();
578 5 : uint32_t changed_log_categories = original_log_categories ^ updated_log_categories;
579 :
580 : // Update libevent logging if BCLog::LIBEVENT has changed.
581 : // If the library version doesn't allow it, UpdateHTTPServerLogging() returns false,
582 : // in which case we should clear the BCLog::LIBEVENT flag.
583 : // Throw an error if the user has explicitly asked to change only the libevent
584 : // flag and it failed.
585 5 : if (changed_log_categories & BCLog::LIBEVENT) {
586 0 : if (!UpdateHTTPServerLogging(LogInstance().WillLogCategory(BCLog::LIBEVENT))) {
587 0 : LogInstance().DisableCategory(BCLog::LIBEVENT);
588 0 : if (changed_log_categories == BCLog::LIBEVENT) {
589 0 : throw JSONRPCError(RPC_INVALID_PARAMETER, "libevent logging cannot be updated when using libevent before v2.1.1.");
590 : }
591 : }
592 : }
593 :
594 5 : UniValue result(UniValue::VOBJ);
595 115 : for (const auto& logCatActive : LogInstance().LogCategoriesList()) {
596 110 : result.pushKV(logCatActive.category, logCatActive.active);
597 : }
598 :
599 : return result;
600 5 : },
601 : };
602 0 : }
603 :
604 4431 : static RPCHelpMan echo(const std::string& name)
605 : {
606 48741 : return RPCHelpMan{name,
607 4431 : "\nSimply echo back the input arguments. This command is for testing.\n"
608 : "\nIt will return an internal bug report when arg9='trigger_internal_bug' is passed.\n"
609 : "\nThe difference between echo and echojson is that echojson has argument conversion enabled in the client-side table in "
610 : "bitcoin-cli and the GUI. There is no server-side difference.",
611 48741 : {
612 4431 : {"arg0", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, ""},
613 4431 : {"arg1", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, ""},
614 4431 : {"arg2", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, ""},
615 4431 : {"arg3", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, ""},
616 4431 : {"arg4", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, ""},
617 4431 : {"arg5", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, ""},
618 4431 : {"arg6", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, ""},
619 4431 : {"arg7", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, ""},
620 4431 : {"arg8", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, ""},
621 4431 : {"arg9", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, ""},
622 : },
623 4431 : RPCResult{RPCResult::Type::NONE, "", "Returns whatever was passed in"},
624 4431 : RPCExamples{""},
625 4438 : [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
626 : {
627 8 : if (request.fHelp) throw std::runtime_error(self.ToString());
628 :
629 7 : if (request.params[9].isStr()) {
630 1 : CHECK_NONFATAL(request.params[9].get_str() != "trigger_internal_bug");
631 : }
632 :
633 6 : return request.params;
634 1 : },
635 : };
636 0 : }
637 :
638 2219 : static RPCHelpMan echo() { return echo("echo"); }
639 2212 : static RPCHelpMan echojson() { return echo("echojson"); }
640 :
641 16 : static UniValue SummaryToJSON(const IndexSummary&& summary, std::string index_name)
642 : {
643 16 : UniValue ret_summary(UniValue::VOBJ);
644 16 : if (!index_name.empty() && index_name != summary.name) return ret_summary;
645 :
646 13 : UniValue entry(UniValue::VOBJ);
647 13 : entry.pushKV("synced", summary.synced);
648 13 : entry.pushKV("best_block_height", summary.best_block_height);
649 13 : ret_summary.pushKV(summary.name, entry);
650 : return ret_summary;
651 16 : }
652 :
653 2225 : static RPCHelpMan getindexinfo()
654 : {
655 6675 : return RPCHelpMan{"getindexinfo",
656 2225 : "\nReturns the status of one or all available indices currently running in the node.\n",
657 4450 : {
658 2225 : {"index_name", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "Filter results for an index with a specific name."},
659 : },
660 2225 : RPCResult{
661 4450 : RPCResult::Type::OBJ, "", "", {
662 2225 : {
663 2225 : RPCResult::Type::OBJ, "name", "The name of the index",
664 6675 : {
665 2225 : {RPCResult::Type::BOOL, "synced", "Whether the index is synced or not"},
666 2225 : {RPCResult::Type::NUM, "best_block_height", "The block height to which the index is synced"},
667 : }
668 : },
669 : },
670 : },
671 2225 : RPCExamples{
672 2225 : HelpExampleCli("getindexinfo", "")
673 2225 : + HelpExampleRpc("getindexinfo", "")
674 2225 : + HelpExampleCli("getindexinfo", "txindex")
675 2225 : + HelpExampleRpc("getindexinfo", "txindex")
676 : },
677 2234 : [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
678 : {
679 9 : UniValue result(UniValue::VOBJ);
680 9 : const std::string index_name = request.params[0].isNull() ? "" : request.params[0].get_str();
681 :
682 9 : if (g_txindex) {
683 8 : result.pushKVs(SummaryToJSON(g_txindex->GetSummary(), index_name));
684 8 : }
685 :
686 17 : ForEachBlockFilterIndex([&result, &index_name](const BlockFilterIndex& index) {
687 8 : result.pushKVs(SummaryToJSON(index.GetSummary(), index_name));
688 8 : });
689 :
690 : return result;
691 9 : },
692 : };
693 0 : }
694 :
695 626 : void RegisterMiscRPCCommands(CRPCTable &t)
696 : {
697 : // clang-format off
698 1179 : static const CRPCCommand commands[] =
699 14378 : { // category name actor (function) argNames
700 : // --------------------- ------------------------ ----------------------- ----------
701 553 : { "control", "getmemoryinfo", &getmemoryinfo, {"mode"} },
702 553 : { "control", "logging", &logging, {"include", "exclude"}},
703 553 : { "util", "validateaddress", &validateaddress, {"address"} },
704 553 : { "util", "createmultisig", &createmultisig, {"nrequired","keys","address_type"} },
705 553 : { "util", "deriveaddresses", &deriveaddresses, {"descriptor", "range"} },
706 553 : { "util", "getdescriptorinfo", &getdescriptorinfo, {"descriptor"} },
707 553 : { "util", "verifymessage", &verifymessage, {"address","signature","message"} },
708 553 : { "util", "signmessagewithprivkey", &signmessagewithprivkey, {"privkey","message"} },
709 553 : { "util", "getindexinfo", &getindexinfo, {"index_name"} },
710 :
711 : /* Not shown in help */
712 553 : { "hidden", "setmocktime", &setmocktime, {"timestamp"}},
713 553 : { "hidden", "mockscheduler", &mockscheduler, {"delta_time"}},
714 553 : { "hidden", "echo", &echo, {"arg0","arg1","arg2","arg3","arg4","arg5","arg6","arg7","arg8","arg9"}},
715 553 : { "hidden", "echojson", &echojson, {"arg0","arg1","arg2","arg3","arg4","arg5","arg6","arg7","arg8","arg9"}},
716 : };
717 : // clang-format on
718 8764 : for (const auto& c : commands) {
719 8138 : t.appendCommand(c.name, &c);
720 : }
721 7815 : }
|