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