1 // Copyright (c) 2017-2021 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 <key_io.h>
6 #include <outputtype.h>
7 #include <rpc/util.h>
8 #include <script/descriptor.h>
9 #include <script/signingprovider.h>
10 #include <tinyformat.h>
11 #include <util/strencodings.h>
12 #include <util/string.h>
13 #include <util/translation.h>
14
15 #include <tuple>
16
17 #include <boost/algorithm/string/classification.hpp>
18 #include <boost/algorithm/string/split.hpp>
19
20 const std::string UNIX_EPOCH_TIME = "UNIX epoch time";
21 const std::string EXAMPLE_ADDRESS[2] = {"bc1q09vm5lfy0j5reeulh4x5752q25uqqvz34hufdl", "bc1q02ad21edsxd23d32dfgqqsz4vv4nmtfzuklhy3"};
22
RPCTypeCheck(const UniValue & params,const std::list<UniValueType> & typesExpected,bool fAllowNull)23 void RPCTypeCheck(const UniValue& params,
24 const std::list<UniValueType>& typesExpected,
25 bool fAllowNull)
26 {
27 unsigned int i = 0;
28 for (const UniValueType& t : typesExpected) {
29 if (params.size() <= i)
30 break;
31
32 const UniValue& v = params[i];
33 if (!(fAllowNull && v.isNull())) {
34 RPCTypeCheckArgument(v, t);
35 }
36 i++;
37 }
38 }
39
RPCTypeCheckArgument(const UniValue & value,const UniValueType & typeExpected)40 void RPCTypeCheckArgument(const UniValue& value, const UniValueType& typeExpected)
41 {
42 if (!typeExpected.typeAny && value.type() != typeExpected.type) {
43 throw JSONRPCError(RPC_TYPE_ERROR, strprintf("Expected type %s, got %s", uvTypeName(typeExpected.type), uvTypeName(value.type())));
44 }
45 }
46
RPCTypeCheckObj(const UniValue & o,const std::map<std::string,UniValueType> & typesExpected,bool fAllowNull,bool fStrict)47 void RPCTypeCheckObj(const UniValue& o,
48 const std::map<std::string, UniValueType>& typesExpected,
49 bool fAllowNull,
50 bool fStrict)
51 {
52 for (const auto& t : typesExpected) {
53 const UniValue& v = find_value(o, t.first);
54 if (!fAllowNull && v.isNull())
55 throw JSONRPCError(RPC_TYPE_ERROR, strprintf("Missing %s", t.first));
56
57 if (!(t.second.typeAny || v.type() == t.second.type || (fAllowNull && v.isNull()))) {
58 std::string err = strprintf("Expected type %s for %s, got %s",
59 uvTypeName(t.second.type), t.first, uvTypeName(v.type()));
60 throw JSONRPCError(RPC_TYPE_ERROR, err);
61 }
62 }
63
64 if (fStrict)
65 {
66 for (const std::string& k : o.getKeys())
67 {
68 if (typesExpected.count(k) == 0)
69 {
70 std::string err = strprintf("Unexpected key %s", k);
71 throw JSONRPCError(RPC_TYPE_ERROR, err);
72 }
73 }
74 }
75 }
76
AmountFromValue(const UniValue & value,int decimals)77 CAmount AmountFromValue(const UniValue& value, int decimals)
78 {
79 if (!value.isNum() && !value.isStr())
80 throw JSONRPCError(RPC_TYPE_ERROR, "Amount is not a number or string");
81 CAmount amount;
82 if (!ParseFixedPoint(value.getValStr(), decimals, &amount))
83 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount");
84 if (!MoneyRange(amount))
85 throw JSONRPCError(RPC_TYPE_ERROR, "Amount out of range");
86 return amount;
87 }
88
ParseHashV(const UniValue & v,std::string strName)89 uint256 ParseHashV(const UniValue& v, std::string strName)
90 {
91 std::string strHex(v.get_str());
92 if (64 != strHex.length())
93 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("%s must be of length %d (not %d, for '%s')", strName, 64, strHex.length(), strHex));
94 if (!IsHex(strHex)) // Note: IsHex("") is false
95 throw JSONRPCError(RPC_INVALID_PARAMETER, strName+" must be hexadecimal string (not '"+strHex+"')");
96 return uint256S(strHex);
97 }
ParseHashO(const UniValue & o,std::string strKey)98 uint256 ParseHashO(const UniValue& o, std::string strKey)
99 {
100 return ParseHashV(find_value(o, strKey), strKey);
101 }
ParseHexV(const UniValue & v,std::string strName)102 std::vector<unsigned char> ParseHexV(const UniValue& v, std::string strName)
103 {
104 std::string strHex;
105 if (v.isStr())
106 strHex = v.get_str();
107 if (!IsHex(strHex))
108 throw JSONRPCError(RPC_INVALID_PARAMETER, strName+" must be hexadecimal string (not '"+strHex+"')");
109 return ParseHex(strHex);
110 }
ParseHexO(const UniValue & o,std::string strKey)111 std::vector<unsigned char> ParseHexO(const UniValue& o, std::string strKey)
112 {
113 return ParseHexV(find_value(o, strKey), strKey);
114 }
115
116 namespace {
117
118 /**
119 * Quote an argument for shell.
120 *
121 * @note This is intended for help, not for security-sensitive purposes.
122 */
ShellQuote(const std::string & s)123 std::string ShellQuote(const std::string& s)
124 {
125 std::string result;
126 result.reserve(s.size() * 2);
127 for (const char ch: s) {
128 if (ch == '\'') {
129 result += "'\''";
130 } else {
131 result += ch;
132 }
133 }
134 return "'" + result + "'";
135 }
136
137 /**
138 * Shell-quotes the argument if it needs quoting, else returns it literally, to save typing.
139 *
140 * @note This is intended for help, not for security-sensitive purposes.
141 */
ShellQuoteIfNeeded(const std::string & s)142 std::string ShellQuoteIfNeeded(const std::string& s)
143 {
144 for (const char ch: s) {
145 if (ch == ' ' || ch == '\'' || ch == '"') {
146 return ShellQuote(s);
147 }
148 }
149
150 return s;
151 }
152
153 }
154
HelpExampleCli(const std::string & methodname,const std::string & args)155 std::string HelpExampleCli(const std::string& methodname, const std::string& args)
156 {
157 return "> bitcoin-cli " + methodname + " " + args + "\n";
158 }
159
HelpExampleCliNamed(const std::string & methodname,const RPCArgList & args)160 std::string HelpExampleCliNamed(const std::string& methodname, const RPCArgList& args)
161 {
162 std::string result = "> bitcoin-cli -named " + methodname;
163 for (const auto& argpair: args) {
164 const auto& value = argpair.second.isStr()
165 ? argpair.second.get_str()
166 : argpair.second.write();
167 result += " " + argpair.first + "=" + ShellQuoteIfNeeded(value);
168 }
169 result += "\n";
170 return result;
171 }
172
HelpExampleRpc(const std::string & methodname,const std::string & args)173 std::string HelpExampleRpc(const std::string& methodname, const std::string& args)
174 {
175 return "> curl --user myusername --data-binary '{\"jsonrpc\": \"1.0\", \"id\": \"curltest\", "
176 "\"method\": \"" + methodname + "\", \"params\": [" + args + "]}' -H 'content-type: text/plain;' http://127.0.0.1:8332/\n";
177 }
178
HelpExampleRpcNamed(const std::string & methodname,const RPCArgList & args)179 std::string HelpExampleRpcNamed(const std::string& methodname, const RPCArgList& args)
180 {
181 UniValue params(UniValue::VOBJ);
182 for (const auto& param: args) {
183 params.pushKV(param.first, param.second);
184 }
185
186 return "> curl --user myusername --data-binary '{\"jsonrpc\": \"1.0\", \"id\": \"curltest\", "
187 "\"method\": \"" + methodname + "\", \"params\": " + params.write() + "}' -H 'content-type: text/plain;' http://127.0.0.1:8332/\n";
188 }
189
190 // Converts a hex string to a public key if possible
HexToPubKey(const std::string & hex_in)191 CPubKey HexToPubKey(const std::string& hex_in)
192 {
193 if (!IsHex(hex_in)) {
194 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid public key: " + hex_in);
195 }
196 CPubKey vchPubKey(ParseHex(hex_in));
197 if (!vchPubKey.IsFullyValid()) {
198 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid public key: " + hex_in);
199 }
200 return vchPubKey;
201 }
202
203 // Retrieves a public key for an address from the given FillableSigningProvider
AddrToPubKey(const FillableSigningProvider & keystore,const std::string & addr_in)204 CPubKey AddrToPubKey(const FillableSigningProvider& keystore, const std::string& addr_in)
205 {
206 CTxDestination dest = DecodeDestination(addr_in);
207 if (!IsValidDestination(dest)) {
208 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address: " + addr_in);
209 }
210 CKeyID key = GetKeyForDestination(keystore, dest);
211 if (key.IsNull()) {
212 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("%s does not refer to a key", addr_in));
213 }
214 CPubKey vchPubKey;
215 if (!keystore.GetPubKey(key, vchPubKey)) {
216 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("no full public key for address %s", addr_in));
217 }
218 if (!vchPubKey.IsFullyValid()) {
219 throw JSONRPCError(RPC_INTERNAL_ERROR, "Wallet contains an invalid public key");
220 }
221 return vchPubKey;
222 }
223
224 // Creates a multisig address from a given list of public keys, number of signatures required, and the address type
AddAndGetMultisigDestination(const int required,const std::vector<CPubKey> & pubkeys,OutputType type,FillableSigningProvider & keystore,CScript & script_out)225 CTxDestination AddAndGetMultisigDestination(const int required, const std::vector<CPubKey>& pubkeys, OutputType type, FillableSigningProvider& keystore, CScript& script_out)
226 {
227 // Gather public keys
228 if (required < 1) {
229 throw JSONRPCError(RPC_INVALID_PARAMETER, "a multisignature address must require at least one key to redeem");
230 }
231 if ((int)pubkeys.size() < required) {
232 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("not enough keys supplied (got %u keys, but need at least %d to redeem)", pubkeys.size(), required));
233 }
234 if (pubkeys.size() > MAX_PUBKEYS_PER_MULTISIG) {
235 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Number of keys involved in the multisignature address creation > %d\nReduce the number", MAX_PUBKEYS_PER_MULTISIG));
236 }
237
238 script_out = GetScriptForMultisig(required, pubkeys);
239
240 // Check if any keys are uncompressed. If so, the type is legacy
241 for (const CPubKey& pk : pubkeys) {
242 if (!pk.IsCompressed()) {
243 type = OutputType::LEGACY;
244 break;
245 }
246 }
247
248 if (type == OutputType::LEGACY && script_out.size() > MAX_SCRIPT_ELEMENT_SIZE) {
249 throw JSONRPCError(RPC_INVALID_PARAMETER, (strprintf("redeemScript exceeds size limit: %d > %d", script_out.size(), MAX_SCRIPT_ELEMENT_SIZE)));
250 }
251
252 // Make the address
253 CTxDestination dest = AddAndGetDestinationForScript(keystore, script_out, type);
254
255 return dest;
256 }
257
258 class DescribeAddressVisitor
259 {
260 public:
DescribeAddressVisitor()261 explicit DescribeAddressVisitor() {}
262
operator ()(const CNoDestination & dest) const263 UniValue operator()(const CNoDestination& dest) const
264 {
265 return UniValue(UniValue::VOBJ);
266 }
267
operator ()(const PKHash & keyID) const268 UniValue operator()(const PKHash& keyID) const
269 {
270 UniValue obj(UniValue::VOBJ);
271 obj.pushKV("isscript", false);
272 obj.pushKV("iswitness", false);
273 return obj;
274 }
275
operator ()(const ScriptHash & scriptID) const276 UniValue operator()(const ScriptHash& scriptID) const
277 {
278 UniValue obj(UniValue::VOBJ);
279 obj.pushKV("isscript", true);
280 obj.pushKV("iswitness", false);
281 return obj;
282 }
283
operator ()(const WitnessV0KeyHash & id) const284 UniValue operator()(const WitnessV0KeyHash& id) const
285 {
286 UniValue obj(UniValue::VOBJ);
287 obj.pushKV("isscript", false);
288 obj.pushKV("iswitness", true);
289 obj.pushKV("witness_version", 0);
290 obj.pushKV("witness_program", HexStr(id));
291 return obj;
292 }
293
operator ()(const WitnessV0ScriptHash & id) const294 UniValue operator()(const WitnessV0ScriptHash& id) const
295 {
296 UniValue obj(UniValue::VOBJ);
297 obj.pushKV("isscript", true);
298 obj.pushKV("iswitness", true);
299 obj.pushKV("witness_version", 0);
300 obj.pushKV("witness_program", HexStr(id));
301 return obj;
302 }
303
operator ()(const WitnessV1Taproot & tap) const304 UniValue operator()(const WitnessV1Taproot& tap) const
305 {
306 UniValue obj(UniValue::VOBJ);
307 obj.pushKV("isscript", true);
308 obj.pushKV("iswitness", true);
309 obj.pushKV("witness_version", 1);
310 obj.pushKV("witness_program", HexStr(tap));
311 return obj;
312 }
313
operator ()(const WitnessUnknown & id) const314 UniValue operator()(const WitnessUnknown& id) const
315 {
316 UniValue obj(UniValue::VOBJ);
317 obj.pushKV("iswitness", true);
318 obj.pushKV("witness_version", (int)id.version);
319 obj.pushKV("witness_program", HexStr(Span<const unsigned char>(id.program, id.length)));
320 return obj;
321 }
322 };
323
DescribeAddress(const CTxDestination & dest)324 UniValue DescribeAddress(const CTxDestination& dest)
325 {
326 return std::visit(DescribeAddressVisitor(), dest);
327 }
328
ParseConfirmTarget(const UniValue & value,unsigned int max_target)329 unsigned int ParseConfirmTarget(const UniValue& value, unsigned int max_target)
330 {
331 const int target{value.get_int()};
332 const unsigned int unsigned_target{static_cast<unsigned int>(target)};
333 if (target < 1 || unsigned_target > max_target) {
334 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid conf_target, must be between %u and %u", 1, max_target));
335 }
336 return unsigned_target;
337 }
338
RPCErrorFromTransactionError(TransactionError terr)339 RPCErrorCode RPCErrorFromTransactionError(TransactionError terr)
340 {
341 switch (terr) {
342 case TransactionError::MEMPOOL_REJECTED:
343 return RPC_TRANSACTION_REJECTED;
344 case TransactionError::ALREADY_IN_CHAIN:
345 return RPC_TRANSACTION_ALREADY_IN_CHAIN;
346 case TransactionError::P2P_DISABLED:
347 return RPC_CLIENT_P2P_DISABLED;
348 case TransactionError::INVALID_PSBT:
349 case TransactionError::PSBT_MISMATCH:
350 return RPC_INVALID_PARAMETER;
351 case TransactionError::SIGHASH_MISMATCH:
352 return RPC_DESERIALIZATION_ERROR;
353 default: break;
354 }
355 return RPC_TRANSACTION_ERROR;
356 }
357
JSONRPCTransactionError(TransactionError terr,const std::string & err_string)358 UniValue JSONRPCTransactionError(TransactionError terr, const std::string& err_string)
359 {
360 if (err_string.length() > 0) {
361 return JSONRPCError(RPCErrorFromTransactionError(terr), err_string);
362 } else {
363 return JSONRPCError(RPCErrorFromTransactionError(terr), TransactionErrorString(terr).original);
364 }
365 }
366
367 /**
368 * A pair of strings that can be aligned (through padding) with other Sections
369 * later on
370 */
371 struct Section {
SectionSection372 Section(const std::string& left, const std::string& right)
373 : m_left{left}, m_right{right} {}
374 std::string m_left;
375 const std::string m_right;
376 };
377
378 /**
379 * Keeps track of RPCArgs by transforming them into sections for the purpose
380 * of serializing everything to a single string
381 */
382 struct Sections {
383 std::vector<Section> m_sections;
384 size_t m_max_pad{0};
385
PushSectionSections386 void PushSection(const Section& s)
387 {
388 m_max_pad = std::max(m_max_pad, s.m_left.size());
389 m_sections.push_back(s);
390 }
391
392 /**
393 * Recursive helper to translate an RPCArg into sections
394 */
PushSections395 void Push(const RPCArg& arg, const size_t current_indent = 5, const OuterType outer_type = OuterType::NONE)
396 {
397 const auto indent = std::string(current_indent, ' ');
398 const auto indent_next = std::string(current_indent + 2, ' ');
399 const bool push_name{outer_type == OuterType::OBJ}; // Dictionary keys must have a name
400
401 switch (arg.m_type) {
402 case RPCArg::Type::STR_HEX:
403 case RPCArg::Type::STR:
404 case RPCArg::Type::NUM:
405 case RPCArg::Type::AMOUNT:
406 case RPCArg::Type::RANGE:
407 case RPCArg::Type::BOOL: {
408 if (outer_type == OuterType::NONE) return; // Nothing more to do for non-recursive types on first recursion
409 auto left = indent;
410 if (arg.m_type_str.size() != 0 && push_name) {
411 left += "\"" + arg.GetName() + "\": " + arg.m_type_str.at(0);
412 } else {
413 left += push_name ? arg.ToStringObj(/* oneline */ false) : arg.ToString(/* oneline */ false);
414 }
415 left += ",";
416 PushSection({left, arg.ToDescriptionString()});
417 break;
418 }
419 case RPCArg::Type::OBJ:
420 case RPCArg::Type::OBJ_USER_KEYS: {
421 const auto right = outer_type == OuterType::NONE ? "" : arg.ToDescriptionString();
422 PushSection({indent + (push_name ? "\"" + arg.GetName() + "\": " : "") + "{", right});
423 for (const auto& arg_inner : arg.m_inner) {
424 Push(arg_inner, current_indent + 2, OuterType::OBJ);
425 }
426 if (arg.m_type != RPCArg::Type::OBJ) {
427 PushSection({indent_next + "...", ""});
428 }
429 PushSection({indent + "}" + (outer_type != OuterType::NONE ? "," : ""), ""});
430 break;
431 }
432 case RPCArg::Type::ARR: {
433 auto left = indent;
434 left += push_name ? "\"" + arg.GetName() + "\": " : "";
435 left += "[";
436 const auto right = outer_type == OuterType::NONE ? "" : arg.ToDescriptionString();
437 PushSection({left, right});
438 for (const auto& arg_inner : arg.m_inner) {
439 Push(arg_inner, current_indent + 2, OuterType::ARR);
440 }
441 PushSection({indent_next + "...", ""});
442 PushSection({indent + "]" + (outer_type != OuterType::NONE ? "," : ""), ""});
443 break;
444 }
445 } // no default case, so the compiler can warn about missing cases
446 }
447
448 /**
449 * Concatenate all sections with proper padding
450 */
ToStringSections451 std::string ToString() const
452 {
453 std::string ret;
454 const size_t pad = m_max_pad + 4;
455 for (const auto& s : m_sections) {
456 // The left part of a section is assumed to be a single line, usually it is the name of the JSON struct or a
457 // brace like {, }, [, or ]
458 CHECK_NONFATAL(s.m_left.find('\n') == std::string::npos);
459 if (s.m_right.empty()) {
460 ret += s.m_left;
461 ret += "\n";
462 continue;
463 }
464
465 std::string left = s.m_left;
466 left.resize(pad, ' ');
467 ret += left;
468
469 // Properly pad after newlines
470 std::string right;
471 size_t begin = 0;
472 size_t new_line_pos = s.m_right.find_first_of('\n');
473 while (true) {
474 right += s.m_right.substr(begin, new_line_pos - begin);
475 if (new_line_pos == std::string::npos) {
476 break; //No new line
477 }
478 right += "\n" + std::string(pad, ' ');
479 begin = s.m_right.find_first_not_of(' ', new_line_pos + 1);
480 if (begin == std::string::npos) {
481 break; // Empty line
482 }
483 new_line_pos = s.m_right.find_first_of('\n', begin + 1);
484 }
485 ret += right;
486 ret += "\n";
487 }
488 return ret;
489 }
490 };
491
RPCHelpMan(std::string name,std::string description,std::vector<RPCArg> args,RPCResults results,RPCExamples examples)492 RPCHelpMan::RPCHelpMan(std::string name, std::string description, std::vector<RPCArg> args, RPCResults results, RPCExamples examples)
493 : RPCHelpMan{std::move(name), std::move(description), std::move(args), std::move(results), std::move(examples), nullptr} {}
494
RPCHelpMan(std::string name,std::string description,std::vector<RPCArg> args,RPCResults results,RPCExamples examples,RPCMethodImpl fun)495 RPCHelpMan::RPCHelpMan(std::string name, std::string description, std::vector<RPCArg> args, RPCResults results, RPCExamples examples, RPCMethodImpl fun)
496 : m_name{std::move(name)},
497 m_fun{std::move(fun)},
498 m_description{std::move(description)},
499 m_args{std::move(args)},
500 m_results{std::move(results)},
501 m_examples{std::move(examples)}
502 {
503 std::set<std::string> named_args;
504 for (const auto& arg : m_args) {
505 std::vector<std::string> names;
506 boost::split(names, arg.m_names, boost::is_any_of("|"));
507 // Should have unique named arguments
508 for (const std::string& name : names) {
509 CHECK_NONFATAL(named_args.insert(name).second);
510 }
511 // Default value type should match argument type only when defined
512 if (arg.m_fallback.index() == 2) {
513 const RPCArg::Type type = arg.m_type;
514 switch (std::get<RPCArg::Default>(arg.m_fallback).getType()) {
515 case UniValue::VOBJ:
516 CHECK_NONFATAL(type == RPCArg::Type::OBJ);
517 break;
518 case UniValue::VARR:
519 CHECK_NONFATAL(type == RPCArg::Type::ARR);
520 break;
521 case UniValue::VSTR:
522 CHECK_NONFATAL(type == RPCArg::Type::STR || type == RPCArg::Type::STR_HEX || type == RPCArg::Type::AMOUNT);
523 break;
524 case UniValue::VNUM:
525 CHECK_NONFATAL(type == RPCArg::Type::NUM || type == RPCArg::Type::AMOUNT || type == RPCArg::Type::RANGE);
526 break;
527 case UniValue::VBOOL:
528 CHECK_NONFATAL(type == RPCArg::Type::BOOL);
529 break;
530 case UniValue::VNULL:
531 // Null values are accepted in all arguments
532 break;
533 default:
534 CHECK_NONFATAL(false);
535 break;
536 }
537 }
538 }
539 }
540
ToDescriptionString() const541 std::string RPCResults::ToDescriptionString() const
542 {
543 std::string result;
544 for (const auto& r : m_results) {
545 if (r.m_type == RPCResult::Type::ANY) continue; // for testing only
546 if (r.m_cond.empty()) {
547 result += "\nResult:\n";
548 } else {
549 result += "\nResult (" + r.m_cond + "):\n";
550 }
551 Sections sections;
552 r.ToSections(sections);
553 result += sections.ToString();
554 }
555 return result;
556 }
557
ToDescriptionString() const558 std::string RPCExamples::ToDescriptionString() const
559 {
560 return m_examples.empty() ? m_examples : "\nExamples:\n" + m_examples;
561 }
562
HandleRequest(const JSONRPCRequest & request) const563 UniValue RPCHelpMan::HandleRequest(const JSONRPCRequest& request) const
564 {
565 if (request.mode == JSONRPCRequest::GET_ARGS) {
566 return GetArgMap();
567 }
568 /*
569 * Check if the given request is valid according to this command or if
570 * the user is asking for help information, and throw help when appropriate.
571 */
572 if (request.mode == JSONRPCRequest::GET_HELP || !IsValidNumArgs(request.params.size())) {
573 throw std::runtime_error(ToString());
574 }
575 const UniValue ret = m_fun(*this, request);
576 CHECK_NONFATAL(std::any_of(m_results.m_results.begin(), m_results.m_results.end(), [ret](const RPCResult& res) { return res.MatchesType(ret); }));
577 return ret;
578 }
579
IsValidNumArgs(size_t num_args) const580 bool RPCHelpMan::IsValidNumArgs(size_t num_args) const
581 {
582 size_t num_required_args = 0;
583 for (size_t n = m_args.size(); n > 0; --n) {
584 if (!m_args.at(n - 1).IsOptional()) {
585 num_required_args = n;
586 break;
587 }
588 }
589 return num_required_args <= num_args && num_args <= m_args.size();
590 }
591
GetArgNames() const592 std::vector<std::string> RPCHelpMan::GetArgNames() const
593 {
594 std::vector<std::string> ret;
595 for (const auto& arg : m_args) {
596 ret.emplace_back(arg.m_names);
597 }
598 return ret;
599 }
600
ToString() const601 std::string RPCHelpMan::ToString() const
602 {
603 std::string ret;
604
605 // Oneline summary
606 ret += m_name;
607 bool was_optional{false};
608 for (const auto& arg : m_args) {
609 if (arg.m_hidden) break; // Any arg that follows is also hidden
610 const bool optional = arg.IsOptional();
611 ret += " ";
612 if (optional) {
613 if (!was_optional) ret += "( ";
614 was_optional = true;
615 } else {
616 if (was_optional) ret += ") ";
617 was_optional = false;
618 }
619 ret += arg.ToString(/* oneline */ true);
620 }
621 if (was_optional) ret += " )";
622 ret += "\n";
623
624 // Description
625 ret += m_description;
626
627 // Arguments
628 Sections sections;
629 for (size_t i{0}; i < m_args.size(); ++i) {
630 const auto& arg = m_args.at(i);
631 if (arg.m_hidden) break; // Any arg that follows is also hidden
632
633 if (i == 0) ret += "\nArguments:\n";
634
635 // Push named argument name and description
636 sections.m_sections.emplace_back(::ToString(i + 1) + ". " + arg.GetFirstName(), arg.ToDescriptionString());
637 sections.m_max_pad = std::max(sections.m_max_pad, sections.m_sections.back().m_left.size());
638
639 // Recursively push nested args
640 sections.Push(arg);
641 }
642 ret += sections.ToString();
643
644 // Result
645 ret += m_results.ToDescriptionString();
646
647 // Examples
648 ret += m_examples.ToDescriptionString();
649
650 return ret;
651 }
652
GetArgMap() const653 UniValue RPCHelpMan::GetArgMap() const
654 {
655 UniValue arr{UniValue::VARR};
656 for (int i{0}; i < int(m_args.size()); ++i) {
657 const auto& arg = m_args.at(i);
658 std::vector<std::string> arg_names;
659 boost::split(arg_names, arg.m_names, boost::is_any_of("|"));
660 for (const auto& arg_name : arg_names) {
661 UniValue map{UniValue::VARR};
662 map.push_back(m_name);
663 map.push_back(i);
664 map.push_back(arg_name);
665 map.push_back(arg.m_type == RPCArg::Type::STR ||
666 arg.m_type == RPCArg::Type::STR_HEX);
667 arr.push_back(map);
668 }
669 }
670 return arr;
671 }
672
GetFirstName() const673 std::string RPCArg::GetFirstName() const
674 {
675 return m_names.substr(0, m_names.find("|"));
676 }
677
GetName() const678 std::string RPCArg::GetName() const
679 {
680 CHECK_NONFATAL(std::string::npos == m_names.find("|"));
681 return m_names;
682 }
683
IsOptional() const684 bool RPCArg::IsOptional() const
685 {
686 if (m_fallback.index() != 0) {
687 return true;
688 } else {
689 return RPCArg::Optional::NO != std::get<RPCArg::Optional>(m_fallback);
690 }
691 }
692
ToDescriptionString() const693 std::string RPCArg::ToDescriptionString() const
694 {
695 std::string ret;
696 ret += "(";
697 if (m_type_str.size() != 0) {
698 ret += m_type_str.at(1);
699 } else {
700 switch (m_type) {
701 case Type::STR_HEX:
702 case Type::STR: {
703 ret += "string";
704 break;
705 }
706 case Type::NUM: {
707 ret += "numeric";
708 break;
709 }
710 case Type::AMOUNT: {
711 ret += "numeric or string";
712 break;
713 }
714 case Type::RANGE: {
715 ret += "numeric or array";
716 break;
717 }
718 case Type::BOOL: {
719 ret += "boolean";
720 break;
721 }
722 case Type::OBJ:
723 case Type::OBJ_USER_KEYS: {
724 ret += "json object";
725 break;
726 }
727 case Type::ARR: {
728 ret += "json array";
729 break;
730 }
731 } // no default case, so the compiler can warn about missing cases
732 }
733 if (m_fallback.index() == 1) {
734 ret += ", optional, default=" + std::get<RPCArg::DefaultHint>(m_fallback);
735 } else if (m_fallback.index() == 2) {
736 ret += ", optional, default=" + std::get<RPCArg::Default>(m_fallback).write();
737 } else {
738 switch (std::get<RPCArg::Optional>(m_fallback)) {
739 case RPCArg::Optional::OMITTED: {
740 // nothing to do. Element is treated as if not present and has no default value
741 break;
742 }
743 case RPCArg::Optional::OMITTED_NAMED_ARG: {
744 ret += ", optional"; // Default value is "null"
745 break;
746 }
747 case RPCArg::Optional::NO: {
748 ret += ", required";
749 break;
750 }
751 } // no default case, so the compiler can warn about missing cases
752 }
753 ret += ")";
754 ret += m_description.empty() ? "" : " " + m_description;
755 return ret;
756 }
757
ToSections(Sections & sections,const OuterType outer_type,const int current_indent) const758 void RPCResult::ToSections(Sections& sections, const OuterType outer_type, const int current_indent) const
759 {
760 // Indentation
761 const std::string indent(current_indent, ' ');
762 const std::string indent_next(current_indent + 2, ' ');
763
764 // Elements in a JSON structure (dictionary or array) are separated by a comma
765 const std::string maybe_separator{outer_type != OuterType::NONE ? "," : ""};
766
767 // The key name if recursed into an dictionary
768 const std::string maybe_key{
769 outer_type == OuterType::OBJ ?
770 "\"" + this->m_key_name + "\" : " :
771 ""};
772
773 // Format description with type
774 const auto Description = [&](const std::string& type) {
775 return "(" + type + (this->m_optional ? ", optional" : "") + ")" +
776 (this->m_description.empty() ? "" : " " + this->m_description);
777 };
778
779 switch (m_type) {
780 case Type::ELISION: {
781 // If the inner result is empty, use three dots for elision
782 sections.PushSection({indent + "..." + maybe_separator, m_description});
783 return;
784 }
785 case Type::ANY: {
786 CHECK_NONFATAL(false); // Only for testing
787 }
788 case Type::NONE: {
789 sections.PushSection({indent + "null" + maybe_separator, Description("json null")});
790 return;
791 }
792 case Type::STR: {
793 sections.PushSection({indent + maybe_key + "\"str\"" + maybe_separator, Description("string")});
794 return;
795 }
796 case Type::STR_AMOUNT: {
797 sections.PushSection({indent + maybe_key + "n" + maybe_separator, Description("numeric")});
798 return;
799 }
800 case Type::STR_HEX: {
801 sections.PushSection({indent + maybe_key + "\"hex\"" + maybe_separator, Description("string")});
802 return;
803 }
804 case Type::NUM: {
805 sections.PushSection({indent + maybe_key + "n" + maybe_separator, Description("numeric")});
806 return;
807 }
808 case Type::NUM_TIME: {
809 sections.PushSection({indent + maybe_key + "xxx" + maybe_separator, Description("numeric")});
810 return;
811 }
812 case Type::BOOL: {
813 sections.PushSection({indent + maybe_key + "true|false" + maybe_separator, Description("boolean")});
814 return;
815 }
816 case Type::ARR_FIXED:
817 case Type::ARR: {
818 sections.PushSection({indent + maybe_key + "[", Description("json array")});
819 for (const auto& i : m_inner) {
820 i.ToSections(sections, OuterType::ARR, current_indent + 2);
821 }
822 CHECK_NONFATAL(!m_inner.empty());
823 if (m_type == Type::ARR && m_inner.back().m_type != Type::ELISION) {
824 sections.PushSection({indent_next + "...", ""});
825 } else {
826 // Remove final comma, which would be invalid JSON
827 sections.m_sections.back().m_left.pop_back();
828 }
829 sections.PushSection({indent + "]" + maybe_separator, ""});
830 return;
831 }
832 case Type::OBJ_DYN:
833 case Type::OBJ: {
834 sections.PushSection({indent + maybe_key + "{", Description("json object")});
835 for (const auto& i : m_inner) {
836 i.ToSections(sections, OuterType::OBJ, current_indent + 2);
837 }
838 CHECK_NONFATAL(!m_inner.empty());
839 if (m_type == Type::OBJ_DYN && m_inner.back().m_type != Type::ELISION) {
840 // If the dictionary keys are dynamic, use three dots for continuation
841 sections.PushSection({indent_next + "...", ""});
842 } else {
843 // Remove final comma, which would be invalid JSON
844 sections.m_sections.back().m_left.pop_back();
845 }
846 sections.PushSection({indent + "}" + maybe_separator, ""});
847 return;
848 }
849 } // no default case, so the compiler can warn about missing cases
850 CHECK_NONFATAL(false);
851 }
852
MatchesType(const UniValue & result) const853 bool RPCResult::MatchesType(const UniValue& result) const
854 {
855 switch (m_type) {
856 case Type::ELISION: {
857 return false;
858 }
859 case Type::ANY: {
860 return true;
861 }
862 case Type::NONE: {
863 return UniValue::VNULL == result.getType();
864 }
865 case Type::STR:
866 case Type::STR_HEX: {
867 return UniValue::VSTR == result.getType();
868 }
869 case Type::NUM:
870 case Type::STR_AMOUNT:
871 case Type::NUM_TIME: {
872 return UniValue::VNUM == result.getType();
873 }
874 case Type::BOOL: {
875 return UniValue::VBOOL == result.getType();
876 }
877 case Type::ARR_FIXED:
878 case Type::ARR: {
879 return UniValue::VARR == result.getType();
880 }
881 case Type::OBJ_DYN:
882 case Type::OBJ: {
883 return UniValue::VOBJ == result.getType();
884 }
885 } // no default case, so the compiler can warn about missing cases
886 CHECK_NONFATAL(false);
887 }
888
ToStringObj(const bool oneline) const889 std::string RPCArg::ToStringObj(const bool oneline) const
890 {
891 std::string res;
892 res += "\"";
893 res += GetFirstName();
894 if (oneline) {
895 res += "\":";
896 } else {
897 res += "\": ";
898 }
899 switch (m_type) {
900 case Type::STR:
901 return res + "\"str\"";
902 case Type::STR_HEX:
903 return res + "\"hex\"";
904 case Type::NUM:
905 return res + "n";
906 case Type::RANGE:
907 return res + "n or [n,n]";
908 case Type::AMOUNT:
909 return res + "amount";
910 case Type::BOOL:
911 return res + "bool";
912 case Type::ARR:
913 res += "[";
914 for (const auto& i : m_inner) {
915 res += i.ToString(oneline) + ",";
916 }
917 return res + "...]";
918 case Type::OBJ:
919 case Type::OBJ_USER_KEYS:
920 // Currently unused, so avoid writing dead code
921 CHECK_NONFATAL(false);
922 } // no default case, so the compiler can warn about missing cases
923 CHECK_NONFATAL(false);
924 }
925
ToString(const bool oneline) const926 std::string RPCArg::ToString(const bool oneline) const
927 {
928 if (oneline && !m_oneline_description.empty()) return m_oneline_description;
929
930 switch (m_type) {
931 case Type::STR_HEX:
932 case Type::STR: {
933 return "\"" + GetFirstName() + "\"";
934 }
935 case Type::NUM:
936 case Type::RANGE:
937 case Type::AMOUNT:
938 case Type::BOOL: {
939 return GetFirstName();
940 }
941 case Type::OBJ:
942 case Type::OBJ_USER_KEYS: {
943 const std::string res = Join(m_inner, ",", [&](const RPCArg& i) { return i.ToStringObj(oneline); });
944 if (m_type == Type::OBJ) {
945 return "{" + res + "}";
946 } else {
947 return "{" + res + ",...}";
948 }
949 }
950 case Type::ARR: {
951 std::string res;
952 for (const auto& i : m_inner) {
953 res += i.ToString(oneline) + ",";
954 }
955 return "[" + res + "...]";
956 }
957 } // no default case, so the compiler can warn about missing cases
958 CHECK_NONFATAL(false);
959 }
960
ParseRange(const UniValue & value)961 static std::pair<int64_t, int64_t> ParseRange(const UniValue& value)
962 {
963 if (value.isNum()) {
964 return {0, value.get_int64()};
965 }
966 if (value.isArray() && value.size() == 2 && value[0].isNum() && value[1].isNum()) {
967 int64_t low = value[0].get_int64();
968 int64_t high = value[1].get_int64();
969 if (low > high) throw JSONRPCError(RPC_INVALID_PARAMETER, "Range specified as [begin,end] must not have begin after end");
970 return {low, high};
971 }
972 throw JSONRPCError(RPC_INVALID_PARAMETER, "Range must be specified as end or as [begin,end]");
973 }
974
ParseDescriptorRange(const UniValue & value)975 std::pair<int64_t, int64_t> ParseDescriptorRange(const UniValue& value)
976 {
977 int64_t low, high;
978 std::tie(low, high) = ParseRange(value);
979 if (low < 0) {
980 throw JSONRPCError(RPC_INVALID_PARAMETER, "Range should be greater or equal than 0");
981 }
982 if ((high >> 31) != 0) {
983 throw JSONRPCError(RPC_INVALID_PARAMETER, "End of range is too high");
984 }
985 if (high >= low + 1000000) {
986 throw JSONRPCError(RPC_INVALID_PARAMETER, "Range is too large");
987 }
988 return {low, high};
989 }
990
EvalDescriptorStringOrObject(const UniValue & scanobject,FlatSigningProvider & provider)991 std::vector<CScript> EvalDescriptorStringOrObject(const UniValue& scanobject, FlatSigningProvider& provider)
992 {
993 std::string desc_str;
994 std::pair<int64_t, int64_t> range = {0, 1000};
995 if (scanobject.isStr()) {
996 desc_str = scanobject.get_str();
997 } else if (scanobject.isObject()) {
998 UniValue desc_uni = find_value(scanobject, "desc");
999 if (desc_uni.isNull()) throw JSONRPCError(RPC_INVALID_PARAMETER, "Descriptor needs to be provided in scan object");
1000 desc_str = desc_uni.get_str();
1001 UniValue range_uni = find_value(scanobject, "range");
1002 if (!range_uni.isNull()) {
1003 range = ParseDescriptorRange(range_uni);
1004 }
1005 } else {
1006 throw JSONRPCError(RPC_INVALID_PARAMETER, "Scan object needs to be either a string or an object");
1007 }
1008
1009 std::string error;
1010 auto desc = Parse(desc_str, provider, error);
1011 if (!desc) {
1012 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, error);
1013 }
1014 if (!desc->IsRange()) {
1015 range.first = 0;
1016 range.second = 0;
1017 }
1018 std::vector<CScript> ret;
1019 for (int i = range.first; i <= range.second; ++i) {
1020 std::vector<CScript> scripts;
1021 if (!desc->Expand(i, provider, scripts, provider)) {
1022 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Cannot derive script without private keys: '%s'", desc_str));
1023 }
1024 std::move(scripts.begin(), scripts.end(), std::back_inserter(ret));
1025 }
1026 return ret;
1027 }
1028
GetServicesNames(ServiceFlags services)1029 UniValue GetServicesNames(ServiceFlags services)
1030 {
1031 UniValue servicesNames(UniValue::VARR);
1032
1033 for (const auto& flag : serviceFlagsToStr(services)) {
1034 servicesNames.push_back(flag);
1035 }
1036
1037 return servicesNames;
1038 }
1039