util.cpp
1 // Copyright (c) 2017-2022 The Bitcoin Core developers 2 // Distributed under the MIT software license, see the accompanying 3 // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 5 #include <bitcoin-build-config.h> // IWYU pragma: keep 6 7 #include <chain.h> 8 #include <clientversion.h> 9 #include <common/args.h> 10 #include <common/messages.h> 11 #include <common/types.h> 12 #include <consensus/amount.h> 13 #include <core_io.h> 14 #include <key_io.h> 15 #include <node/types.h> 16 #include <outputtype.h> 17 #include <pow.h> 18 #include <rpc/util.h> 19 #include <script/descriptor.h> 20 #include <script/interpreter.h> 21 #include <script/signingprovider.h> 22 #include <script/solver.h> 23 #include <tinyformat.h> 24 #include <uint256.h> 25 #include <univalue.h> 26 #include <util/check.h> 27 #include <util/result.h> 28 #include <util/strencodings.h> 29 #include <util/string.h> 30 #include <util/translation.h> 31 32 #include <algorithm> 33 #include <iterator> 34 #include <string_view> 35 #include <tuple> 36 #include <utility> 37 38 using common::PSBTError; 39 using common::PSBTErrorString; 40 using common::TransactionErrorString; 41 using node::TransactionError; 42 using util::Join; 43 using util::SplitString; 44 using util::TrimString; 45 46 const std::string UNIX_EPOCH_TIME = "UNIX epoch time"; 47 const std::string EXAMPLE_ADDRESS[2] = {"bc1q09vm5lfy0j5reeulh4x5752q25uqqvz34hufdl", "bc1q02ad21edsxd23d32dfgqqsz4vv4nmtfzuklhy3"}; 48 49 std::string GetAllOutputTypes() 50 { 51 std::vector<std::string> ret; 52 using U = std::underlying_type_t<TxoutType>; 53 for (U i = (U)TxoutType::NONSTANDARD; i <= (U)TxoutType::WITNESS_UNKNOWN; ++i) { 54 ret.emplace_back(GetTxnOutputType(static_cast<TxoutType>(i))); 55 } 56 return Join(ret, ", "); 57 } 58 59 void RPCTypeCheckObj(const UniValue& o, 60 const std::map<std::string, UniValueType>& typesExpected, 61 bool fAllowNull, 62 bool fStrict) 63 { 64 for (const auto& t : typesExpected) { 65 const UniValue& v = o.find_value(t.first); 66 if (!fAllowNull && v.isNull()) 67 throw JSONRPCError(RPC_TYPE_ERROR, strprintf("Missing %s", t.first)); 68 69 if (!(t.second.typeAny || v.type() == t.second.type || (fAllowNull && v.isNull()))) 70 throw JSONRPCError(RPC_TYPE_ERROR, strprintf("JSON value of type %s for field %s is not of expected type %s", uvTypeName(v.type()), t.first, uvTypeName(t.second.type))); 71 } 72 73 if (fStrict) 74 { 75 for (const std::string& k : o.getKeys()) 76 { 77 if (typesExpected.count(k) == 0) 78 { 79 std::string err = strprintf("Unexpected key %s", k); 80 throw JSONRPCError(RPC_TYPE_ERROR, err); 81 } 82 } 83 } 84 } 85 86 int ParseVerbosity(const UniValue& arg, int default_verbosity, bool allow_bool) 87 { 88 if (!arg.isNull()) { 89 if (arg.isBool()) { 90 if (!allow_bool) { 91 throw JSONRPCError(RPC_TYPE_ERROR, "Verbosity was boolean but only integer allowed"); 92 } 93 return arg.get_bool(); // true = 1 94 } else { 95 return arg.getInt<int>(); 96 } 97 } 98 return default_verbosity; 99 } 100 101 CAmount AmountFromValue(const UniValue& value, int decimals) 102 { 103 if (!value.isNum() && !value.isStr()) 104 throw JSONRPCError(RPC_TYPE_ERROR, "Amount is not a number or string"); 105 CAmount amount; 106 if (!ParseFixedPoint(value.getValStr(), decimals, &amount)) 107 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount"); 108 if (!MoneyRange(amount)) 109 throw JSONRPCError(RPC_TYPE_ERROR, "Amount out of range"); 110 return amount; 111 } 112 113 CFeeRate ParseFeeRate(const UniValue& json) 114 { 115 CAmount val{AmountFromValue(json)}; 116 if (val >= COIN) throw JSONRPCError(RPC_INVALID_PARAMETER, "Fee rates larger than or equal to 1BTC/kvB are not accepted"); 117 return CFeeRate{val}; 118 } 119 120 uint256 ParseHashV(const UniValue& v, std::string_view name) 121 { 122 const std::string& strHex(v.get_str()); 123 if (auto rv{uint256::FromHex(strHex)}) return *rv; 124 if (auto expected_len{uint256::size() * 2}; strHex.length() != expected_len) { 125 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("%s must be of length %d (not %d, for '%s')", name, expected_len, strHex.length(), strHex)); 126 } 127 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("%s must be hexadecimal string (not '%s')", name, strHex)); 128 } 129 uint256 ParseHashO(const UniValue& o, std::string_view strKey) 130 { 131 return ParseHashV(o.find_value(strKey), strKey); 132 } 133 std::vector<unsigned char> ParseHexV(const UniValue& v, std::string_view name) 134 { 135 std::string strHex; 136 if (v.isStr()) 137 strHex = v.get_str(); 138 if (!IsHex(strHex)) 139 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("%s must be hexadecimal string (not '%s')", name, strHex)); 140 return ParseHex(strHex); 141 } 142 std::vector<unsigned char> ParseHexO(const UniValue& o, std::string_view strKey) 143 { 144 return ParseHexV(o.find_value(strKey), strKey); 145 } 146 147 namespace { 148 149 /** 150 * Quote an argument for shell. 151 * 152 * @note This is intended for help, not for security-sensitive purposes. 153 */ 154 std::string ShellQuote(const std::string& s) 155 { 156 std::string result; 157 result.reserve(s.size() * 2); 158 for (const char ch: s) { 159 if (ch == '\'') { 160 result += "'\''"; 161 } else { 162 result += ch; 163 } 164 } 165 return "'" + result + "'"; 166 } 167 168 /** 169 * Shell-quotes the argument if it needs quoting, else returns it literally, to save typing. 170 * 171 * @note This is intended for help, not for security-sensitive purposes. 172 */ 173 std::string ShellQuoteIfNeeded(const std::string& s) 174 { 175 for (const char ch: s) { 176 if (ch == ' ' || ch == '\'' || ch == '"') { 177 return ShellQuote(s); 178 } 179 } 180 181 return s; 182 } 183 184 } 185 186 std::string HelpExampleCli(const std::string& methodname, const std::string& args) 187 { 188 return "> bitcoin-cli " + methodname + " " + args + "\n"; 189 } 190 191 std::string HelpExampleCliNamed(const std::string& methodname, const RPCArgList& args) 192 { 193 std::string result = "> bitcoin-cli -named " + methodname; 194 for (const auto& argpair: args) { 195 const auto& value = argpair.second.isStr() 196 ? argpair.second.get_str() 197 : argpair.second.write(); 198 result += " " + argpair.first + "=" + ShellQuoteIfNeeded(value); 199 } 200 result += "\n"; 201 return result; 202 } 203 204 std::string HelpExampleRpc(const std::string& methodname, const std::string& args) 205 { 206 return "> curl --user myusername --data-binary '{\"jsonrpc\": \"2.0\", \"id\": \"curltest\", " 207 "\"method\": \"" + methodname + "\", \"params\": [" + args + "]}' -H 'content-type: application/json' http://127.0.0.1:8332/\n"; 208 } 209 210 std::string HelpExampleRpcNamed(const std::string& methodname, const RPCArgList& args) 211 { 212 UniValue params(UniValue::VOBJ); 213 for (const auto& param: args) { 214 params.pushKV(param.first, param.second); 215 } 216 217 return "> curl --user myusername --data-binary '{\"jsonrpc\": \"2.0\", \"id\": \"curltest\", " 218 "\"method\": \"" + methodname + "\", \"params\": " + params.write() + "}' -H 'content-type: application/json' http://127.0.0.1:8332/\n"; 219 } 220 221 // Converts a hex string to a public key if possible 222 CPubKey HexToPubKey(const std::string& hex_in) 223 { 224 if (!IsHex(hex_in)) { 225 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Pubkey \"" + hex_in + "\" must be a hex string"); 226 } 227 if (hex_in.length() != 66 && hex_in.length() != 130) { 228 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Pubkey \"" + hex_in + "\" must have a length of either 33 or 65 bytes"); 229 } 230 CPubKey vchPubKey(ParseHex(hex_in)); 231 if (!vchPubKey.IsFullyValid()) { 232 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Pubkey \"" + hex_in + "\" must be cryptographically valid."); 233 } 234 return vchPubKey; 235 } 236 237 // Retrieves a public key for an address from the given FillableSigningProvider 238 CPubKey AddrToPubKey(const FillableSigningProvider& keystore, const std::string& addr_in) 239 { 240 CTxDestination dest = DecodeDestination(addr_in); 241 if (!IsValidDestination(dest)) { 242 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address: " + addr_in); 243 } 244 CKeyID key = GetKeyForDestination(keystore, dest); 245 if (key.IsNull()) { 246 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("'%s' does not refer to a key", addr_in)); 247 } 248 CPubKey vchPubKey; 249 if (!keystore.GetPubKey(key, vchPubKey)) { 250 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("no full public key for address %s", addr_in)); 251 } 252 if (!vchPubKey.IsFullyValid()) { 253 throw JSONRPCError(RPC_INTERNAL_ERROR, "Wallet contains an invalid public key"); 254 } 255 return vchPubKey; 256 } 257 258 // Creates a multisig address from a given list of public keys, number of signatures required, and the address type 259 CTxDestination AddAndGetMultisigDestination(const int required, const std::vector<CPubKey>& pubkeys, OutputType type, FlatSigningProvider& keystore, CScript& script_out) 260 { 261 // Gather public keys 262 if (required < 1) { 263 throw JSONRPCError(RPC_INVALID_PARAMETER, "a multisignature address must require at least one key to redeem"); 264 } 265 if ((int)pubkeys.size() < required) { 266 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("not enough keys supplied (got %u keys, but need at least %d to redeem)", pubkeys.size(), required)); 267 } 268 if (pubkeys.size() > MAX_PUBKEYS_PER_MULTISIG) { 269 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Number of keys involved in the multisignature address creation > %d\nReduce the number", MAX_PUBKEYS_PER_MULTISIG)); 270 } 271 272 script_out = GetScriptForMultisig(required, pubkeys); 273 274 // Check if any keys are uncompressed. If so, the type is legacy 275 for (const CPubKey& pk : pubkeys) { 276 if (!pk.IsCompressed()) { 277 type = OutputType::LEGACY; 278 break; 279 } 280 } 281 282 if (type == OutputType::LEGACY && script_out.size() > MAX_SCRIPT_ELEMENT_SIZE) { 283 throw JSONRPCError(RPC_INVALID_PARAMETER, (strprintf("redeemScript exceeds size limit: %d > %d", script_out.size(), MAX_SCRIPT_ELEMENT_SIZE))); 284 } 285 286 // Make the address 287 CTxDestination dest = AddAndGetDestinationForScript(keystore, script_out, type); 288 289 return dest; 290 } 291 292 class DescribeAddressVisitor 293 { 294 public: 295 explicit DescribeAddressVisitor() = default; 296 297 UniValue operator()(const CNoDestination& dest) const 298 { 299 return UniValue(UniValue::VOBJ); 300 } 301 302 UniValue operator()(const PubKeyDestination& dest) const 303 { 304 return UniValue(UniValue::VOBJ); 305 } 306 307 UniValue operator()(const PKHash& keyID) const 308 { 309 UniValue obj(UniValue::VOBJ); 310 obj.pushKV("isscript", false); 311 obj.pushKV("iswitness", false); 312 return obj; 313 } 314 315 UniValue operator()(const ScriptHash& scriptID) const 316 { 317 UniValue obj(UniValue::VOBJ); 318 obj.pushKV("isscript", true); 319 obj.pushKV("iswitness", false); 320 return obj; 321 } 322 323 UniValue operator()(const WitnessV0KeyHash& id) const 324 { 325 UniValue obj(UniValue::VOBJ); 326 obj.pushKV("isscript", false); 327 obj.pushKV("iswitness", true); 328 obj.pushKV("witness_version", 0); 329 obj.pushKV("witness_program", HexStr(id)); 330 return obj; 331 } 332 333 UniValue operator()(const WitnessV0ScriptHash& id) const 334 { 335 UniValue obj(UniValue::VOBJ); 336 obj.pushKV("isscript", true); 337 obj.pushKV("iswitness", true); 338 obj.pushKV("witness_version", 0); 339 obj.pushKV("witness_program", HexStr(id)); 340 return obj; 341 } 342 343 UniValue operator()(const WitnessV1Taproot& tap) const 344 { 345 UniValue obj(UniValue::VOBJ); 346 obj.pushKV("isscript", true); 347 obj.pushKV("iswitness", true); 348 obj.pushKV("witness_version", 1); 349 obj.pushKV("witness_program", HexStr(tap)); 350 return obj; 351 } 352 353 UniValue operator()(const PayToAnchor& anchor) const 354 { 355 UniValue obj(UniValue::VOBJ); 356 obj.pushKV("isscript", true); 357 obj.pushKV("iswitness", true); 358 return obj; 359 } 360 361 UniValue operator()(const WitnessUnknown& id) const 362 { 363 UniValue obj(UniValue::VOBJ); 364 obj.pushKV("iswitness", true); 365 obj.pushKV("witness_version", id.GetWitnessVersion()); 366 obj.pushKV("witness_program", HexStr(id.GetWitnessProgram())); 367 return obj; 368 } 369 }; 370 371 UniValue DescribeAddress(const CTxDestination& dest) 372 { 373 return std::visit(DescribeAddressVisitor(), dest); 374 } 375 376 /** 377 * Returns a sighash value corresponding to the passed in argument. 378 * 379 * @pre The sighash argument should be string or null. 380 */ 381 int ParseSighashString(const UniValue& sighash) 382 { 383 if (sighash.isNull()) { 384 return SIGHASH_DEFAULT; 385 } 386 const auto result{SighashFromStr(sighash.get_str())}; 387 if (!result) { 388 throw JSONRPCError(RPC_INVALID_PARAMETER, util::ErrorString(result).original); 389 } 390 return result.value(); 391 } 392 393 unsigned int ParseConfirmTarget(const UniValue& value, unsigned int max_target) 394 { 395 const int target{value.getInt<int>()}; 396 const unsigned int unsigned_target{static_cast<unsigned int>(target)}; 397 if (target < 1 || unsigned_target > max_target) { 398 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid conf_target, must be between %u and %u", 1, max_target)); 399 } 400 return unsigned_target; 401 } 402 403 RPCErrorCode RPCErrorFromPSBTError(PSBTError err) 404 { 405 switch (err) { 406 case PSBTError::UNSUPPORTED: 407 return RPC_INVALID_PARAMETER; 408 case PSBTError::SIGHASH_MISMATCH: 409 return RPC_DESERIALIZATION_ERROR; 410 default: break; 411 } 412 return RPC_TRANSACTION_ERROR; 413 } 414 415 RPCErrorCode RPCErrorFromTransactionError(TransactionError terr) 416 { 417 switch (terr) { 418 case TransactionError::MEMPOOL_REJECTED: 419 return RPC_TRANSACTION_REJECTED; 420 case TransactionError::ALREADY_IN_UTXO_SET: 421 return RPC_VERIFY_ALREADY_IN_UTXO_SET; 422 default: break; 423 } 424 return RPC_TRANSACTION_ERROR; 425 } 426 427 UniValue JSONRPCPSBTError(PSBTError err) 428 { 429 return JSONRPCError(RPCErrorFromPSBTError(err), PSBTErrorString(err).original); 430 } 431 432 UniValue JSONRPCTransactionError(TransactionError terr, const std::string& err_string) 433 { 434 if (err_string.length() > 0) { 435 return JSONRPCError(RPCErrorFromTransactionError(terr), err_string); 436 } else { 437 return JSONRPCError(RPCErrorFromTransactionError(terr), TransactionErrorString(terr).original); 438 } 439 } 440 441 /** 442 * A pair of strings that can be aligned (through padding) with other Sections 443 * later on 444 */ 445 struct Section { 446 Section(const std::string& left, const std::string& right) 447 : m_left{left}, m_right{right} {} 448 std::string m_left; 449 const std::string m_right; 450 }; 451 452 /** 453 * Keeps track of RPCArgs by transforming them into sections for the purpose 454 * of serializing everything to a single string 455 */ 456 struct Sections { 457 std::vector<Section> m_sections; 458 size_t m_max_pad{0}; 459 460 void PushSection(const Section& s) 461 { 462 m_max_pad = std::max(m_max_pad, s.m_left.size()); 463 m_sections.push_back(s); 464 } 465 466 /** 467 * Recursive helper to translate an RPCArg into sections 468 */ 469 // NOLINTNEXTLINE(misc-no-recursion) 470 void Push(const RPCArg& arg, const size_t current_indent = 5, const OuterType outer_type = OuterType::NONE) 471 { 472 const auto indent = std::string(current_indent, ' '); 473 const auto indent_next = std::string(current_indent + 2, ' '); 474 const bool push_name{outer_type == OuterType::OBJ}; // Dictionary keys must have a name 475 const bool is_top_level_arg{outer_type == OuterType::NONE}; // True on the first recursion 476 477 switch (arg.m_type) { 478 case RPCArg::Type::STR_HEX: 479 case RPCArg::Type::STR: 480 case RPCArg::Type::NUM: 481 case RPCArg::Type::AMOUNT: 482 case RPCArg::Type::RANGE: 483 case RPCArg::Type::BOOL: 484 case RPCArg::Type::OBJ_NAMED_PARAMS: { 485 if (is_top_level_arg) return; // Nothing more to do for non-recursive types on first recursion 486 auto left = indent; 487 if (arg.m_opts.type_str.size() != 0 && push_name) { 488 left += "\"" + arg.GetName() + "\": " + arg.m_opts.type_str.at(0); 489 } else { 490 left += push_name ? arg.ToStringObj(/*oneline=*/false) : arg.ToString(/*oneline=*/false); 491 } 492 left += ","; 493 PushSection({left, arg.ToDescriptionString(/*is_named_arg=*/push_name)}); 494 break; 495 } 496 case RPCArg::Type::OBJ: 497 case RPCArg::Type::OBJ_USER_KEYS: { 498 const auto right = is_top_level_arg ? "" : arg.ToDescriptionString(/*is_named_arg=*/push_name); 499 PushSection({indent + (push_name ? "\"" + arg.GetName() + "\": " : "") + "{", right}); 500 for (const auto& arg_inner : arg.m_inner) { 501 Push(arg_inner, current_indent + 2, OuterType::OBJ); 502 } 503 if (arg.m_type != RPCArg::Type::OBJ) { 504 PushSection({indent_next + "...", ""}); 505 } 506 PushSection({indent + "}" + (is_top_level_arg ? "" : ","), ""}); 507 break; 508 } 509 case RPCArg::Type::ARR: { 510 auto left = indent; 511 left += push_name ? "\"" + arg.GetName() + "\": " : ""; 512 left += "["; 513 const auto right = is_top_level_arg ? "" : arg.ToDescriptionString(/*is_named_arg=*/push_name); 514 PushSection({left, right}); 515 for (const auto& arg_inner : arg.m_inner) { 516 Push(arg_inner, current_indent + 2, OuterType::ARR); 517 } 518 PushSection({indent_next + "...", ""}); 519 PushSection({indent + "]" + (is_top_level_arg ? "" : ","), ""}); 520 break; 521 } 522 } // no default case, so the compiler can warn about missing cases 523 } 524 525 /** 526 * Concatenate all sections with proper padding 527 */ 528 std::string ToString() const 529 { 530 std::string ret; 531 const size_t pad = m_max_pad + 4; 532 for (const auto& s : m_sections) { 533 // The left part of a section is assumed to be a single line, usually it is the name of the JSON struct or a 534 // brace like {, }, [, or ] 535 CHECK_NONFATAL(s.m_left.find('\n') == std::string::npos); 536 if (s.m_right.empty()) { 537 ret += s.m_left; 538 ret += "\n"; 539 continue; 540 } 541 542 std::string left = s.m_left; 543 left.resize(pad, ' '); 544 ret += left; 545 546 // Properly pad after newlines 547 std::string right; 548 size_t begin = 0; 549 size_t new_line_pos = s.m_right.find_first_of('\n'); 550 while (true) { 551 right += s.m_right.substr(begin, new_line_pos - begin); 552 if (new_line_pos == std::string::npos) { 553 break; //No new line 554 } 555 right += "\n" + std::string(pad, ' '); 556 begin = s.m_right.find_first_not_of(' ', new_line_pos + 1); 557 if (begin == std::string::npos) { 558 break; // Empty line 559 } 560 new_line_pos = s.m_right.find_first_of('\n', begin + 1); 561 } 562 ret += right; 563 ret += "\n"; 564 } 565 return ret; 566 } 567 }; 568 569 RPCHelpMan::RPCHelpMan(std::string name, std::string description, std::vector<RPCArg> args, RPCResults results, RPCExamples examples) 570 : RPCHelpMan{std::move(name), std::move(description), std::move(args), std::move(results), std::move(examples), nullptr} {} 571 572 RPCHelpMan::RPCHelpMan(std::string name, std::string description, std::vector<RPCArg> args, RPCResults results, RPCExamples examples, RPCMethodImpl fun) 573 : m_name{std::move(name)}, 574 m_fun{std::move(fun)}, 575 m_description{std::move(description)}, 576 m_args{std::move(args)}, 577 m_results{std::move(results)}, 578 m_examples{std::move(examples)} 579 { 580 // Map of parameter names and types just used to check whether the names are 581 // unique. Parameter names always need to be unique, with the exception that 582 // there can be pairs of POSITIONAL and NAMED parameters with the same name. 583 enum ParamType { POSITIONAL = 1, NAMED = 2, NAMED_ONLY = 4 }; 584 std::map<std::string, int> param_names; 585 586 for (const auto& arg : m_args) { 587 std::vector<std::string> names = SplitString(arg.m_names, '|'); 588 // Should have unique named arguments 589 for (const std::string& name : names) { 590 auto& param_type = param_names[name]; 591 CHECK_NONFATAL(!(param_type & POSITIONAL)); 592 CHECK_NONFATAL(!(param_type & NAMED_ONLY)); 593 param_type |= POSITIONAL; 594 } 595 if (arg.m_type == RPCArg::Type::OBJ_NAMED_PARAMS) { 596 for (const auto& inner : arg.m_inner) { 597 std::vector<std::string> inner_names = SplitString(inner.m_names, '|'); 598 for (const std::string& inner_name : inner_names) { 599 auto& param_type = param_names[inner_name]; 600 CHECK_NONFATAL(!(param_type & POSITIONAL) || inner.m_opts.also_positional); 601 CHECK_NONFATAL(!(param_type & NAMED)); 602 CHECK_NONFATAL(!(param_type & NAMED_ONLY)); 603 param_type |= inner.m_opts.also_positional ? NAMED : NAMED_ONLY; 604 } 605 } 606 } 607 // Default value type should match argument type only when defined 608 if (arg.m_fallback.index() == 2) { 609 const RPCArg::Type type = arg.m_type; 610 switch (std::get<RPCArg::Default>(arg.m_fallback).getType()) { 611 case UniValue::VOBJ: 612 CHECK_NONFATAL(type == RPCArg::Type::OBJ); 613 break; 614 case UniValue::VARR: 615 CHECK_NONFATAL(type == RPCArg::Type::ARR); 616 break; 617 case UniValue::VSTR: 618 CHECK_NONFATAL(type == RPCArg::Type::STR || type == RPCArg::Type::STR_HEX || type == RPCArg::Type::AMOUNT); 619 break; 620 case UniValue::VNUM: 621 CHECK_NONFATAL(type == RPCArg::Type::NUM || type == RPCArg::Type::AMOUNT || type == RPCArg::Type::RANGE); 622 break; 623 case UniValue::VBOOL: 624 CHECK_NONFATAL(type == RPCArg::Type::BOOL); 625 break; 626 case UniValue::VNULL: 627 // Null values are accepted in all arguments 628 break; 629 default: 630 NONFATAL_UNREACHABLE(); 631 break; 632 } 633 } 634 } 635 } 636 637 std::string RPCResults::ToDescriptionString() const 638 { 639 std::string result; 640 for (const auto& r : m_results) { 641 if (r.m_type == RPCResult::Type::ANY) continue; // for testing only 642 if (r.m_cond.empty()) { 643 result += "\nResult:\n"; 644 } else { 645 result += "\nResult (" + r.m_cond + "):\n"; 646 } 647 Sections sections; 648 r.ToSections(sections); 649 result += sections.ToString(); 650 } 651 return result; 652 } 653 654 std::string RPCExamples::ToDescriptionString() const 655 { 656 return m_examples.empty() ? m_examples : "\nExamples:\n" + m_examples; 657 } 658 659 UniValue RPCHelpMan::HandleRequest(const JSONRPCRequest& request) const 660 { 661 if (request.mode == JSONRPCRequest::GET_ARGS) { 662 return GetArgMap(); 663 } 664 /* 665 * Check if the given request is valid according to this command or if 666 * the user is asking for help information, and throw help when appropriate. 667 */ 668 if (request.mode == JSONRPCRequest::GET_HELP || !IsValidNumArgs(request.params.size())) { 669 throw std::runtime_error(ToString()); 670 } 671 UniValue arg_mismatch{UniValue::VOBJ}; 672 for (size_t i{0}; i < m_args.size(); ++i) { 673 const auto& arg{m_args.at(i)}; 674 UniValue match{arg.MatchesType(request.params[i])}; 675 if (!match.isTrue()) { 676 arg_mismatch.pushKV(strprintf("Position %s (%s)", i + 1, arg.m_names), std::move(match)); 677 } 678 } 679 if (!arg_mismatch.empty()) { 680 throw JSONRPCError(RPC_TYPE_ERROR, strprintf("Wrong type passed:\n%s", arg_mismatch.write(4))); 681 } 682 CHECK_NONFATAL(m_req == nullptr); 683 m_req = &request; 684 UniValue ret = m_fun(*this, request); 685 m_req = nullptr; 686 if (gArgs.GetBoolArg("-rpcdoccheck", DEFAULT_RPC_DOC_CHECK)) { 687 UniValue mismatch{UniValue::VARR}; 688 for (const auto& res : m_results.m_results) { 689 UniValue match{res.MatchesType(ret)}; 690 if (match.isTrue()) { 691 mismatch.setNull(); 692 break; 693 } 694 mismatch.push_back(std::move(match)); 695 } 696 if (!mismatch.isNull()) { 697 std::string explain{ 698 mismatch.empty() ? "no possible results defined" : 699 mismatch.size() == 1 ? mismatch[0].write(4) : 700 mismatch.write(4)}; 701 throw std::runtime_error{ 702 strprintf("Internal bug detected: RPC call \"%s\" returned incorrect type:\n%s\n%s %s\nPlease report this issue here: %s\n", 703 m_name, explain, 704 CLIENT_NAME, FormatFullVersion(), 705 CLIENT_BUGREPORT)}; 706 } 707 } 708 return ret; 709 } 710 711 using CheckFn = void(const RPCArg&); 712 static const UniValue* DetailMaybeArg(CheckFn* check, const std::vector<RPCArg>& params, const JSONRPCRequest* req, size_t i) 713 { 714 CHECK_NONFATAL(i < params.size()); 715 const UniValue& arg{CHECK_NONFATAL(req)->params[i]}; 716 const RPCArg& param{params.at(i)}; 717 if (check) check(param); 718 719 if (!arg.isNull()) return &arg; 720 if (!std::holds_alternative<RPCArg::Default>(param.m_fallback)) return nullptr; 721 return &std::get<RPCArg::Default>(param.m_fallback); 722 } 723 724 static void CheckRequiredOrDefault(const RPCArg& param) 725 { 726 // Must use `Arg<Type>(key)` to get the argument or its default value. 727 const bool required{ 728 std::holds_alternative<RPCArg::Optional>(param.m_fallback) && RPCArg::Optional::NO == std::get<RPCArg::Optional>(param.m_fallback), 729 }; 730 CHECK_NONFATAL(required || std::holds_alternative<RPCArg::Default>(param.m_fallback)); 731 } 732 733 #define TMPL_INST(check_param, ret_type, return_code) \ 734 template <> \ 735 ret_type RPCHelpMan::ArgValue<ret_type>(size_t i) const \ 736 { \ 737 const UniValue* maybe_arg{ \ 738 DetailMaybeArg(check_param, m_args, m_req, i), \ 739 }; \ 740 return return_code \ 741 } \ 742 void force_semicolon(ret_type) 743 744 // Optional arg (without default). Can also be called on required args, if needed. 745 TMPL_INST(nullptr, const UniValue*, maybe_arg;); 746 TMPL_INST(nullptr, std::optional<double>, maybe_arg ? std::optional{maybe_arg->get_real()} : std::nullopt;); 747 TMPL_INST(nullptr, std::optional<bool>, maybe_arg ? std::optional{maybe_arg->get_bool()} : std::nullopt;); 748 TMPL_INST(nullptr, const std::string*, maybe_arg ? &maybe_arg->get_str() : nullptr;); 749 750 // Required arg or optional arg with default value. 751 TMPL_INST(CheckRequiredOrDefault, const UniValue&, *CHECK_NONFATAL(maybe_arg);); 752 TMPL_INST(CheckRequiredOrDefault, bool, CHECK_NONFATAL(maybe_arg)->get_bool();); 753 TMPL_INST(CheckRequiredOrDefault, int, CHECK_NONFATAL(maybe_arg)->getInt<int>();); 754 TMPL_INST(CheckRequiredOrDefault, uint64_t, CHECK_NONFATAL(maybe_arg)->getInt<uint64_t>();); 755 TMPL_INST(CheckRequiredOrDefault, const std::string&, CHECK_NONFATAL(maybe_arg)->get_str();); 756 757 bool RPCHelpMan::IsValidNumArgs(size_t num_args) const 758 { 759 size_t num_required_args = 0; 760 for (size_t n = m_args.size(); n > 0; --n) { 761 if (!m_args.at(n - 1).IsOptional()) { 762 num_required_args = n; 763 break; 764 } 765 } 766 return num_required_args <= num_args && num_args <= m_args.size(); 767 } 768 769 std::vector<std::pair<std::string, bool>> RPCHelpMan::GetArgNames() const 770 { 771 std::vector<std::pair<std::string, bool>> ret; 772 ret.reserve(m_args.size()); 773 for (const auto& arg : m_args) { 774 if (arg.m_type == RPCArg::Type::OBJ_NAMED_PARAMS) { 775 for (const auto& inner : arg.m_inner) { 776 ret.emplace_back(inner.m_names, /*named_only=*/true); 777 } 778 } 779 ret.emplace_back(arg.m_names, /*named_only=*/false); 780 } 781 return ret; 782 } 783 784 size_t RPCHelpMan::GetParamIndex(std::string_view key) const 785 { 786 auto it{std::find_if( 787 m_args.begin(), m_args.end(), [&key](const auto& arg) { return arg.GetName() == key;} 788 )}; 789 790 CHECK_NONFATAL(it != m_args.end()); // TODO: ideally this is checked at compile time 791 return std::distance(m_args.begin(), it); 792 } 793 794 std::string RPCHelpMan::ToString() const 795 { 796 std::string ret; 797 798 // Oneline summary 799 ret += m_name; 800 bool was_optional{false}; 801 for (const auto& arg : m_args) { 802 if (arg.m_opts.hidden) break; // Any arg that follows is also hidden 803 const bool optional = arg.IsOptional(); 804 ret += " "; 805 if (optional) { 806 if (!was_optional) ret += "( "; 807 was_optional = true; 808 } else { 809 if (was_optional) ret += ") "; 810 was_optional = false; 811 } 812 ret += arg.ToString(/*oneline=*/true); 813 } 814 if (was_optional) ret += " )"; 815 816 // Description 817 ret += "\n\n" + TrimString(m_description) + "\n"; 818 819 // Arguments 820 Sections sections; 821 Sections named_only_sections; 822 for (size_t i{0}; i < m_args.size(); ++i) { 823 const auto& arg = m_args.at(i); 824 if (arg.m_opts.hidden) break; // Any arg that follows is also hidden 825 826 // Push named argument name and description 827 sections.m_sections.emplace_back(util::ToString(i + 1) + ". " + arg.GetFirstName(), arg.ToDescriptionString(/*is_named_arg=*/true)); 828 sections.m_max_pad = std::max(sections.m_max_pad, sections.m_sections.back().m_left.size()); 829 830 // Recursively push nested args 831 sections.Push(arg); 832 833 // Push named-only argument sections 834 if (arg.m_type == RPCArg::Type::OBJ_NAMED_PARAMS) { 835 for (const auto& arg_inner : arg.m_inner) { 836 named_only_sections.PushSection({arg_inner.GetFirstName(), arg_inner.ToDescriptionString(/*is_named_arg=*/true)}); 837 named_only_sections.Push(arg_inner); 838 } 839 } 840 } 841 842 if (!sections.m_sections.empty()) ret += "\nArguments:\n"; 843 ret += sections.ToString(); 844 if (!named_only_sections.m_sections.empty()) ret += "\nNamed Arguments:\n"; 845 ret += named_only_sections.ToString(); 846 847 // Result 848 ret += m_results.ToDescriptionString(); 849 850 // Examples 851 ret += m_examples.ToDescriptionString(); 852 853 return ret; 854 } 855 856 UniValue RPCHelpMan::GetArgMap() const 857 { 858 UniValue arr{UniValue::VARR}; 859 860 auto push_back_arg_info = [&arr](const std::string& rpc_name, int pos, const std::string& arg_name, const RPCArg::Type& type) { 861 UniValue map{UniValue::VARR}; 862 map.push_back(rpc_name); 863 map.push_back(pos); 864 map.push_back(arg_name); 865 map.push_back(type == RPCArg::Type::STR || 866 type == RPCArg::Type::STR_HEX); 867 arr.push_back(std::move(map)); 868 }; 869 870 for (int i{0}; i < int(m_args.size()); ++i) { 871 const auto& arg = m_args.at(i); 872 std::vector<std::string> arg_names = SplitString(arg.m_names, '|'); 873 for (const auto& arg_name : arg_names) { 874 push_back_arg_info(m_name, i, arg_name, arg.m_type); 875 if (arg.m_type == RPCArg::Type::OBJ_NAMED_PARAMS) { 876 for (const auto& inner : arg.m_inner) { 877 std::vector<std::string> inner_names = SplitString(inner.m_names, '|'); 878 for (const std::string& inner_name : inner_names) { 879 push_back_arg_info(m_name, i, inner_name, inner.m_type); 880 } 881 } 882 } 883 } 884 } 885 return arr; 886 } 887 888 static std::optional<UniValue::VType> ExpectedType(RPCArg::Type type) 889 { 890 using Type = RPCArg::Type; 891 switch (type) { 892 case Type::STR_HEX: 893 case Type::STR: { 894 return UniValue::VSTR; 895 } 896 case Type::NUM: { 897 return UniValue::VNUM; 898 } 899 case Type::AMOUNT: { 900 // VNUM or VSTR, checked inside AmountFromValue() 901 return std::nullopt; 902 } 903 case Type::RANGE: { 904 // VNUM or VARR, checked inside ParseRange() 905 return std::nullopt; 906 } 907 case Type::BOOL: { 908 return UniValue::VBOOL; 909 } 910 case Type::OBJ: 911 case Type::OBJ_NAMED_PARAMS: 912 case Type::OBJ_USER_KEYS: { 913 return UniValue::VOBJ; 914 } 915 case Type::ARR: { 916 return UniValue::VARR; 917 } 918 } // no default case, so the compiler can warn about missing cases 919 NONFATAL_UNREACHABLE(); 920 } 921 922 UniValue RPCArg::MatchesType(const UniValue& request) const 923 { 924 if (m_opts.skip_type_check) return true; 925 if (IsOptional() && request.isNull()) return true; 926 const auto exp_type{ExpectedType(m_type)}; 927 if (!exp_type) return true; // nothing to check 928 929 if (*exp_type != request.getType()) { 930 return strprintf("JSON value of type %s is not of expected type %s", uvTypeName(request.getType()), uvTypeName(*exp_type)); 931 } 932 return true; 933 } 934 935 std::string RPCArg::GetFirstName() const 936 { 937 return m_names.substr(0, m_names.find('|')); 938 } 939 940 std::string RPCArg::GetName() const 941 { 942 CHECK_NONFATAL(std::string::npos == m_names.find('|')); 943 return m_names; 944 } 945 946 bool RPCArg::IsOptional() const 947 { 948 if (m_fallback.index() != 0) { 949 return true; 950 } else { 951 return RPCArg::Optional::NO != std::get<RPCArg::Optional>(m_fallback); 952 } 953 } 954 955 std::string RPCArg::ToDescriptionString(bool is_named_arg) const 956 { 957 std::string ret; 958 ret += "("; 959 if (m_opts.type_str.size() != 0) { 960 ret += m_opts.type_str.at(1); 961 } else { 962 switch (m_type) { 963 case Type::STR_HEX: 964 case Type::STR: { 965 ret += "string"; 966 break; 967 } 968 case Type::NUM: { 969 ret += "numeric"; 970 break; 971 } 972 case Type::AMOUNT: { 973 ret += "numeric or string"; 974 break; 975 } 976 case Type::RANGE: { 977 ret += "numeric or array"; 978 break; 979 } 980 case Type::BOOL: { 981 ret += "boolean"; 982 break; 983 } 984 case Type::OBJ: 985 case Type::OBJ_NAMED_PARAMS: 986 case Type::OBJ_USER_KEYS: { 987 ret += "json object"; 988 break; 989 } 990 case Type::ARR: { 991 ret += "json array"; 992 break; 993 } 994 } // no default case, so the compiler can warn about missing cases 995 } 996 if (m_fallback.index() == 1) { 997 ret += ", optional, default=" + std::get<RPCArg::DefaultHint>(m_fallback); 998 } else if (m_fallback.index() == 2) { 999 ret += ", optional, default=" + std::get<RPCArg::Default>(m_fallback).write(); 1000 } else { 1001 switch (std::get<RPCArg::Optional>(m_fallback)) { 1002 case RPCArg::Optional::OMITTED: { 1003 if (is_named_arg) ret += ", optional"; // Default value is "null" in dicts. Otherwise, 1004 // nothing to do. Element is treated as if not present and has no default value 1005 break; 1006 } 1007 case RPCArg::Optional::NO: { 1008 ret += ", required"; 1009 break; 1010 } 1011 } // no default case, so the compiler can warn about missing cases 1012 } 1013 ret += ")"; 1014 if (m_type == Type::OBJ_NAMED_PARAMS) ret += " Options object that can be used to pass named arguments, listed below."; 1015 ret += m_description.empty() ? "" : " " + m_description; 1016 return ret; 1017 } 1018 1019 // NOLINTNEXTLINE(misc-no-recursion) 1020 void RPCResult::ToSections(Sections& sections, const OuterType outer_type, const int current_indent) const 1021 { 1022 // Indentation 1023 const std::string indent(current_indent, ' '); 1024 const std::string indent_next(current_indent + 2, ' '); 1025 1026 // Elements in a JSON structure (dictionary or array) are separated by a comma 1027 const std::string maybe_separator{outer_type != OuterType::NONE ? "," : ""}; 1028 1029 // The key name if recursed into a dictionary 1030 const std::string maybe_key{ 1031 outer_type == OuterType::OBJ ? 1032 "\"" + this->m_key_name + "\" : " : 1033 ""}; 1034 1035 // Format description with type 1036 const auto Description = [&](const std::string& type) { 1037 return "(" + type + (this->m_optional ? ", optional" : "") + ")" + 1038 (this->m_description.empty() ? "" : " " + this->m_description); 1039 }; 1040 1041 switch (m_type) { 1042 case Type::ELISION: { 1043 // If the inner result is empty, use three dots for elision 1044 sections.PushSection({indent + "..." + maybe_separator, m_description}); 1045 return; 1046 } 1047 case Type::ANY: { 1048 NONFATAL_UNREACHABLE(); // Only for testing 1049 } 1050 case Type::NONE: { 1051 sections.PushSection({indent + "null" + maybe_separator, Description("json null")}); 1052 return; 1053 } 1054 case Type::STR: { 1055 sections.PushSection({indent + maybe_key + "\"str\"" + maybe_separator, Description("string")}); 1056 return; 1057 } 1058 case Type::STR_AMOUNT: { 1059 sections.PushSection({indent + maybe_key + "n" + maybe_separator, Description("numeric")}); 1060 return; 1061 } 1062 case Type::STR_HEX: { 1063 sections.PushSection({indent + maybe_key + "\"hex\"" + maybe_separator, Description("string")}); 1064 return; 1065 } 1066 case Type::NUM: { 1067 sections.PushSection({indent + maybe_key + "n" + maybe_separator, Description("numeric")}); 1068 return; 1069 } 1070 case Type::NUM_TIME: { 1071 sections.PushSection({indent + maybe_key + "xxx" + maybe_separator, Description("numeric")}); 1072 return; 1073 } 1074 case Type::BOOL: { 1075 sections.PushSection({indent + maybe_key + "true|false" + maybe_separator, Description("boolean")}); 1076 return; 1077 } 1078 case Type::ARR_FIXED: 1079 case Type::ARR: { 1080 sections.PushSection({indent + maybe_key + "[", Description("json array")}); 1081 for (const auto& i : m_inner) { 1082 i.ToSections(sections, OuterType::ARR, current_indent + 2); 1083 } 1084 CHECK_NONFATAL(!m_inner.empty()); 1085 if (m_type == Type::ARR && m_inner.back().m_type != Type::ELISION) { 1086 sections.PushSection({indent_next + "...", ""}); 1087 } else { 1088 // Remove final comma, which would be invalid JSON 1089 sections.m_sections.back().m_left.pop_back(); 1090 } 1091 sections.PushSection({indent + "]" + maybe_separator, ""}); 1092 return; 1093 } 1094 case Type::OBJ_DYN: 1095 case Type::OBJ: { 1096 if (m_inner.empty()) { 1097 sections.PushSection({indent + maybe_key + "{}", Description("empty JSON object")}); 1098 return; 1099 } 1100 sections.PushSection({indent + maybe_key + "{", Description("json object")}); 1101 for (const auto& i : m_inner) { 1102 i.ToSections(sections, OuterType::OBJ, current_indent + 2); 1103 } 1104 if (m_type == Type::OBJ_DYN && m_inner.back().m_type != Type::ELISION) { 1105 // If the dictionary keys are dynamic, use three dots for continuation 1106 sections.PushSection({indent_next + "...", ""}); 1107 } else { 1108 // Remove final comma, which would be invalid JSON 1109 sections.m_sections.back().m_left.pop_back(); 1110 } 1111 sections.PushSection({indent + "}" + maybe_separator, ""}); 1112 return; 1113 } 1114 } // no default case, so the compiler can warn about missing cases 1115 NONFATAL_UNREACHABLE(); 1116 } 1117 1118 static std::optional<UniValue::VType> ExpectedType(RPCResult::Type type) 1119 { 1120 using Type = RPCResult::Type; 1121 switch (type) { 1122 case Type::ELISION: 1123 case Type::ANY: { 1124 return std::nullopt; 1125 } 1126 case Type::NONE: { 1127 return UniValue::VNULL; 1128 } 1129 case Type::STR: 1130 case Type::STR_HEX: { 1131 return UniValue::VSTR; 1132 } 1133 case Type::NUM: 1134 case Type::STR_AMOUNT: 1135 case Type::NUM_TIME: { 1136 return UniValue::VNUM; 1137 } 1138 case Type::BOOL: { 1139 return UniValue::VBOOL; 1140 } 1141 case Type::ARR_FIXED: 1142 case Type::ARR: { 1143 return UniValue::VARR; 1144 } 1145 case Type::OBJ_DYN: 1146 case Type::OBJ: { 1147 return UniValue::VOBJ; 1148 } 1149 } // no default case, so the compiler can warn about missing cases 1150 NONFATAL_UNREACHABLE(); 1151 } 1152 1153 // NOLINTNEXTLINE(misc-no-recursion) 1154 UniValue RPCResult::MatchesType(const UniValue& result) const 1155 { 1156 if (m_skip_type_check) { 1157 return true; 1158 } 1159 1160 const auto exp_type = ExpectedType(m_type); 1161 if (!exp_type) return true; // can be any type, so nothing to check 1162 1163 if (*exp_type != result.getType()) { 1164 return strprintf("returned type is %s, but declared as %s in doc", uvTypeName(result.getType()), uvTypeName(*exp_type)); 1165 } 1166 1167 if (UniValue::VARR == result.getType()) { 1168 UniValue errors(UniValue::VOBJ); 1169 for (size_t i{0}; i < result.get_array().size(); ++i) { 1170 // If there are more results than documented, reuse the last doc_inner. 1171 const RPCResult& doc_inner{m_inner.at(std::min(m_inner.size() - 1, i))}; 1172 UniValue match{doc_inner.MatchesType(result.get_array()[i])}; 1173 if (!match.isTrue()) errors.pushKV(strprintf("%d", i), std::move(match)); 1174 } 1175 if (errors.empty()) return true; // empty result array is valid 1176 return errors; 1177 } 1178 1179 if (UniValue::VOBJ == result.getType()) { 1180 if (!m_inner.empty() && m_inner.at(0).m_type == Type::ELISION) return true; 1181 UniValue errors(UniValue::VOBJ); 1182 if (m_type == Type::OBJ_DYN) { 1183 const RPCResult& doc_inner{m_inner.at(0)}; // Assume all types are the same, randomly pick the first 1184 for (size_t i{0}; i < result.get_obj().size(); ++i) { 1185 UniValue match{doc_inner.MatchesType(result.get_obj()[i])}; 1186 if (!match.isTrue()) errors.pushKV(result.getKeys()[i], std::move(match)); 1187 } 1188 if (errors.empty()) return true; // empty result obj is valid 1189 return errors; 1190 } 1191 std::set<std::string> doc_keys; 1192 for (const auto& doc_entry : m_inner) { 1193 doc_keys.insert(doc_entry.m_key_name); 1194 } 1195 std::map<std::string, UniValue> result_obj; 1196 result.getObjMap(result_obj); 1197 for (const auto& result_entry : result_obj) { 1198 if (doc_keys.find(result_entry.first) == doc_keys.end()) { 1199 errors.pushKV(result_entry.first, "key returned that was not in doc"); 1200 } 1201 } 1202 1203 for (const auto& doc_entry : m_inner) { 1204 const auto result_it{result_obj.find(doc_entry.m_key_name)}; 1205 if (result_it == result_obj.end()) { 1206 if (!doc_entry.m_optional) { 1207 errors.pushKV(doc_entry.m_key_name, "key missing, despite not being optional in doc"); 1208 } 1209 continue; 1210 } 1211 UniValue match{doc_entry.MatchesType(result_it->second)}; 1212 if (!match.isTrue()) errors.pushKV(doc_entry.m_key_name, std::move(match)); 1213 } 1214 if (errors.empty()) return true; 1215 return errors; 1216 } 1217 1218 return true; 1219 } 1220 1221 void RPCResult::CheckInnerDoc() const 1222 { 1223 if (m_type == Type::OBJ) { 1224 // May or may not be empty 1225 return; 1226 } 1227 // Everything else must either be empty or not 1228 const bool inner_needed{m_type == Type::ARR || m_type == Type::ARR_FIXED || m_type == Type::OBJ_DYN}; 1229 CHECK_NONFATAL(inner_needed != m_inner.empty()); 1230 } 1231 1232 // NOLINTNEXTLINE(misc-no-recursion) 1233 std::string RPCArg::ToStringObj(const bool oneline) const 1234 { 1235 std::string res; 1236 res += "\""; 1237 res += GetFirstName(); 1238 if (oneline) { 1239 res += "\":"; 1240 } else { 1241 res += "\": "; 1242 } 1243 switch (m_type) { 1244 case Type::STR: 1245 return res + "\"str\""; 1246 case Type::STR_HEX: 1247 return res + "\"hex\""; 1248 case Type::NUM: 1249 return res + "n"; 1250 case Type::RANGE: 1251 return res + "n or [n,n]"; 1252 case Type::AMOUNT: 1253 return res + "amount"; 1254 case Type::BOOL: 1255 return res + "bool"; 1256 case Type::ARR: 1257 res += "["; 1258 for (const auto& i : m_inner) { 1259 res += i.ToString(oneline) + ","; 1260 } 1261 return res + "...]"; 1262 case Type::OBJ: 1263 case Type::OBJ_NAMED_PARAMS: 1264 case Type::OBJ_USER_KEYS: 1265 // Currently unused, so avoid writing dead code 1266 NONFATAL_UNREACHABLE(); 1267 } // no default case, so the compiler can warn about missing cases 1268 NONFATAL_UNREACHABLE(); 1269 } 1270 1271 // NOLINTNEXTLINE(misc-no-recursion) 1272 std::string RPCArg::ToString(const bool oneline) const 1273 { 1274 if (oneline && !m_opts.oneline_description.empty()) { 1275 if (m_opts.oneline_description[0] == '\"' && m_type != Type::STR_HEX && m_type != Type::STR && gArgs.GetBoolArg("-rpcdoccheck", DEFAULT_RPC_DOC_CHECK)) { 1276 throw std::runtime_error{ 1277 STR_INTERNAL_BUG(strprintf("non-string RPC arg \"%s\" quotes oneline_description:\n%s", 1278 m_names, m_opts.oneline_description) 1279 )}; 1280 } 1281 return m_opts.oneline_description; 1282 } 1283 1284 switch (m_type) { 1285 case Type::STR_HEX: 1286 case Type::STR: { 1287 return "\"" + GetFirstName() + "\""; 1288 } 1289 case Type::NUM: 1290 case Type::RANGE: 1291 case Type::AMOUNT: 1292 case Type::BOOL: { 1293 return GetFirstName(); 1294 } 1295 case Type::OBJ: 1296 case Type::OBJ_NAMED_PARAMS: 1297 case Type::OBJ_USER_KEYS: { 1298 // NOLINTNEXTLINE(misc-no-recursion) 1299 const std::string res = Join(m_inner, ",", [&](const RPCArg& i) { return i.ToStringObj(oneline); }); 1300 if (m_type == Type::OBJ) { 1301 return "{" + res + "}"; 1302 } else { 1303 return "{" + res + ",...}"; 1304 } 1305 } 1306 case Type::ARR: { 1307 std::string res; 1308 for (const auto& i : m_inner) { 1309 res += i.ToString(oneline) + ","; 1310 } 1311 return "[" + res + "...]"; 1312 } 1313 } // no default case, so the compiler can warn about missing cases 1314 NONFATAL_UNREACHABLE(); 1315 } 1316 1317 static std::pair<int64_t, int64_t> ParseRange(const UniValue& value) 1318 { 1319 if (value.isNum()) { 1320 return {0, value.getInt<int64_t>()}; 1321 } 1322 if (value.isArray() && value.size() == 2 && value[0].isNum() && value[1].isNum()) { 1323 int64_t low = value[0].getInt<int64_t>(); 1324 int64_t high = value[1].getInt<int64_t>(); 1325 if (low > high) throw JSONRPCError(RPC_INVALID_PARAMETER, "Range specified as [begin,end] must not have begin after end"); 1326 return {low, high}; 1327 } 1328 throw JSONRPCError(RPC_INVALID_PARAMETER, "Range must be specified as end or as [begin,end]"); 1329 } 1330 1331 std::pair<int64_t, int64_t> ParseDescriptorRange(const UniValue& value) 1332 { 1333 int64_t low, high; 1334 std::tie(low, high) = ParseRange(value); 1335 if (low < 0) { 1336 throw JSONRPCError(RPC_INVALID_PARAMETER, "Range should be greater or equal than 0"); 1337 } 1338 if ((high >> 31) != 0) { 1339 throw JSONRPCError(RPC_INVALID_PARAMETER, "End of range is too high"); 1340 } 1341 if (high >= low + 1000000) { 1342 throw JSONRPCError(RPC_INVALID_PARAMETER, "Range is too large"); 1343 } 1344 return {low, high}; 1345 } 1346 1347 std::vector<CScript> EvalDescriptorStringOrObject(const UniValue& scanobject, FlatSigningProvider& provider, const bool expand_priv) 1348 { 1349 std::string desc_str; 1350 std::pair<int64_t, int64_t> range = {0, 1000}; 1351 if (scanobject.isStr()) { 1352 desc_str = scanobject.get_str(); 1353 } else if (scanobject.isObject()) { 1354 const UniValue& desc_uni{scanobject.find_value("desc")}; 1355 if (desc_uni.isNull()) throw JSONRPCError(RPC_INVALID_PARAMETER, "Descriptor needs to be provided in scan object"); 1356 desc_str = desc_uni.get_str(); 1357 const UniValue& range_uni{scanobject.find_value("range")}; 1358 if (!range_uni.isNull()) { 1359 range = ParseDescriptorRange(range_uni); 1360 } 1361 } else { 1362 throw JSONRPCError(RPC_INVALID_PARAMETER, "Scan object needs to be either a string or an object"); 1363 } 1364 1365 std::string error; 1366 auto descs = Parse(desc_str, provider, error); 1367 if (descs.empty()) { 1368 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, error); 1369 } 1370 if (!descs.at(0)->IsRange()) { 1371 range.first = 0; 1372 range.second = 0; 1373 } 1374 std::vector<CScript> ret; 1375 for (int i = range.first; i <= range.second; ++i) { 1376 for (const auto& desc : descs) { 1377 std::vector<CScript> scripts; 1378 if (!desc->Expand(i, provider, scripts, provider)) { 1379 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Cannot derive script without private keys: '%s'", desc_str)); 1380 } 1381 if (expand_priv) { 1382 desc->ExpandPrivate(/*pos=*/i, provider, /*out=*/provider); 1383 } 1384 std::move(scripts.begin(), scripts.end(), std::back_inserter(ret)); 1385 } 1386 } 1387 return ret; 1388 } 1389 1390 /** Convert a vector of bilingual strings to a UniValue::VARR containing their original untranslated values. */ 1391 [[nodiscard]] static UniValue BilingualStringsToUniValue(const std::vector<bilingual_str>& bilingual_strings) 1392 { 1393 CHECK_NONFATAL(!bilingual_strings.empty()); 1394 UniValue result{UniValue::VARR}; 1395 for (const auto& s : bilingual_strings) { 1396 result.push_back(s.original); 1397 } 1398 return result; 1399 } 1400 1401 void PushWarnings(const UniValue& warnings, UniValue& obj) 1402 { 1403 if (warnings.empty()) return; 1404 obj.pushKV("warnings", warnings); 1405 } 1406 1407 void PushWarnings(const std::vector<bilingual_str>& warnings, UniValue& obj) 1408 { 1409 if (warnings.empty()) return; 1410 obj.pushKV("warnings", BilingualStringsToUniValue(warnings)); 1411 } 1412 1413 std::vector<RPCResult> ScriptPubKeyDoc() { 1414 return 1415 { 1416 {RPCResult::Type::STR, "asm", "Disassembly of the output script"}, 1417 {RPCResult::Type::STR, "desc", "Inferred descriptor for the output"}, 1418 {RPCResult::Type::STR_HEX, "hex", "The raw output script bytes, hex-encoded"}, 1419 {RPCResult::Type::STR, "address", /*optional=*/true, "The Bitcoin address (only if a well-defined address exists)"}, 1420 {RPCResult::Type::STR, "type", "The type (one of: " + GetAllOutputTypes() + ")"}, 1421 }; 1422 } 1423 1424 uint256 GetTarget(const CBlockIndex& blockindex, const uint256 pow_limit) 1425 { 1426 arith_uint256 target{*CHECK_NONFATAL(DeriveTarget(blockindex.nBits, pow_limit))}; 1427 return ArithToUint256(target); 1428 }