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