LCOV - code coverage report
Current view: top level - src/rpc - misc.cpp (source / functions) Hit Total Coverage
Test: coverage.lcov Lines: 600 621 96.6 %
Date: 2022-04-21 14:51:19 Functions: 33 34 97.1 %
Legend: Modified by patch:
Lines: hit not hit | Branches: + taken - not taken # not executed

Not modified by patch:
Lines: hit not hit | Branches: + taken - not taken # not executed
Branches: 110 128 85.9 %

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

Generated by: LCOV version 0-eol-96201-ge66f56f4af6a