LCOV - code coverage report
Current view: top level - src/rpc - misc.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 392 420 93.3 %
Date: 2020-09-26 01:30:44 Functions: 32 32 100.0 %

          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 : }

Generated by: LCOV version 1.15