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