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