Line data Source code
1 : // Copyright (c) 2017-2020 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 650 : const std::string UNIX_EPOCH_TIME = "UNIX epoch time";
21 1950 : const std::string EXAMPLE_ADDRESS[2] = {"bc1q09vm5lfy0j5reeulh4x5752q25uqqvz34hufdl", "bc1q02ad21edsxd23d32dfgqqsz4vv4nmtfzuklhy3"};
22 :
23 13350 : void RPCTypeCheck(const UniValue& params,
24 : const std::list<UniValueType>& typesExpected,
25 : bool fAllowNull)
26 : {
27 36572 : unsigned int i = 0;
28 41188 : for (const UniValueType& t : typesExpected) {
29 27848 : if (params.size() <= i)
30 4616 : break;
31 :
32 23232 : const UniValue& v = params[i];
33 23232 : if (!(fAllowNull && v.isNull())) {
34 22927 : RPCTypeCheckArgument(v, t);
35 22927 : }
36 23222 : i++;
37 23222 : }
38 13340 : }
39 :
40 23412 : void RPCTypeCheckArgument(const UniValue& value, const UniValueType& typeExpected)
41 : {
42 23412 : if (!typeExpected.typeAny && value.type() != typeExpected.type) {
43 10 : throw JSONRPCError(RPC_TYPE_ERROR, strprintf("Expected type %s, got %s", uvTypeName(typeExpected.type), uvTypeName(value.type())));
44 : }
45 23412 : }
46 :
47 654 : void RPCTypeCheckObj(const UniValue& o,
48 : const std::map<std::string, UniValueType>& typesExpected,
49 : bool fAllowNull,
50 : bool fStrict)
51 : {
52 4311 : for (const auto& t : typesExpected) {
53 3654 : const UniValue& v = find_value(o, t.first);
54 3654 : if (!fAllowNull && v.isNull())
55 9 : throw JSONRPCError(RPC_TYPE_ERROR, strprintf("Missing %s", t.first));
56 :
57 3645 : if (!(t.second.typeAny || v.type() == t.second.type || (fAllowNull && v.isNull()))) {
58 4 : std::string err = strprintf("Expected type %s for %s, got %s",
59 2 : uvTypeName(t.second.type), t.first, uvTypeName(v.type()));
60 2 : throw JSONRPCError(RPC_TYPE_ERROR, err);
61 2 : }
62 : }
63 :
64 643 : if (fStrict)
65 : {
66 508 : for (const std::string& k : o.getKeys())
67 : {
68 302 : if (typesExpected.count(k) == 0)
69 : {
70 3 : std::string err = strprintf("Unexpected key %s", k);
71 3 : throw JSONRPCError(RPC_TYPE_ERROR, err);
72 3 : }
73 : }
74 203 : }
75 654 : }
76 :
77 18948 : CAmount AmountFromValue(const UniValue& value)
78 : {
79 18948 : if (!value.isNum() && !value.isStr())
80 22 : throw JSONRPCError(RPC_TYPE_ERROR, "Amount is not a number or string");
81 18948 : CAmount amount;
82 18948 : if (!ParseFixedPoint(value.getValStr(), 8, &amount))
83 10 : throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount");
84 18938 : if (!MoneyRange(amount))
85 12 : throw JSONRPCError(RPC_TYPE_ERROR, "Amount out of range");
86 37852 : return amount;
87 18948 : }
88 :
89 19310 : uint256 ParseHashV(const UniValue& v, std::string strName)
90 : {
91 19310 : std::string strHex(v.get_str());
92 19310 : if (64 != strHex.length())
93 12 : throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("%s must be of length %d (not %d, for '%s')", strName, 64, strHex.length(), strHex));
94 19295 : if (!IsHex(strHex)) // Note: IsHex("") is false
95 10 : throw JSONRPCError(RPC_INVALID_PARAMETER, strName+" must be hexadecimal string (not '"+strHex+"')");
96 19285 : return uint256S(strHex);
97 19307 : }
98 6247 : uint256 ParseHashO(const UniValue& o, std::string strKey)
99 : {
100 6247 : return ParseHashV(find_value(o, strKey), strKey);
101 7 : }
102 466 : std::vector<unsigned char> ParseHexV(const UniValue& v, std::string strName)
103 : {
104 466 : std::string strHex;
105 466 : if (v.isStr())
106 466 : strHex = v.get_str();
107 466 : if (!IsHex(strHex))
108 4 : throw JSONRPCError(RPC_INVALID_PARAMETER, strName+" must be hexadecimal string (not '"+strHex+"')");
109 462 : return ParseHex(strHex);
110 466 : }
111 217 : std::vector<unsigned char> ParseHexO(const UniValue& o, std::string strKey)
112 : {
113 217 : return ParseHexV(find_value(o, strKey), strKey);
114 0 : }
115 :
116 6 : CoinStatsHashType ParseHashType(const UniValue& param, const CoinStatsHashType default_type)
117 : {
118 6 : if (param.isNull()) {
119 4 : return default_type;
120 : } else {
121 2 : std::string hash_type_input = param.get_str();
122 :
123 2 : if (hash_type_input == "hash_serialized_2") {
124 1 : return CoinStatsHashType::HASH_SERIALIZED;
125 1 : } else if (hash_type_input == "none") {
126 1 : return CoinStatsHashType::NONE;
127 : } else {
128 0 : throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("%d is not a valid hash_type", hash_type_input));
129 : }
130 2 : }
131 6 : }
132 :
133 222307 : std::string HelpExampleCli(const std::string& methodname, const std::string& args)
134 : {
135 222307 : return "> bitcoin-cli " + methodname + " " + args + "\n";
136 0 : }
137 :
138 131592 : std::string HelpExampleRpc(const std::string& methodname, const std::string& args)
139 : {
140 263184 : return "> curl --user myusername --data-binary '{\"jsonrpc\": \"1.0\", \"id\": \"curltest\", "
141 131592 : "\"method\": \"" + methodname + "\", \"params\": [" + args + "]}' -H 'content-type: text/plain;' http://127.0.0.1:8332/\n";
142 0 : }
143 :
144 : // Converts a hex string to a public key if possible
145 490 : CPubKey HexToPubKey(const std::string& hex_in)
146 : {
147 490 : if (!IsHex(hex_in)) {
148 0 : throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid public key: " + hex_in);
149 : }
150 490 : CPubKey vchPubKey(ParseHex(hex_in));
151 490 : if (!vchPubKey.IsFullyValid()) {
152 0 : throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid public key: " + hex_in);
153 : }
154 490 : return vchPubKey;
155 0 : }
156 :
157 : // Retrieves a public key for an address from the given FillableSigningProvider
158 142 : CPubKey AddrToPubKey(const FillableSigningProvider& keystore, const std::string& addr_in)
159 : {
160 142 : CTxDestination dest = DecodeDestination(addr_in);
161 142 : if (!IsValidDestination(dest)) {
162 0 : throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address: " + addr_in);
163 : }
164 142 : CKeyID key = GetKeyForDestination(keystore, dest);
165 142 : if (key.IsNull()) {
166 0 : throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("%s does not refer to a key", addr_in));
167 : }
168 142 : CPubKey vchPubKey;
169 142 : if (!keystore.GetPubKey(key, vchPubKey)) {
170 2 : throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("no full public key for address %s", addr_in));
171 : }
172 140 : if (!vchPubKey.IsFullyValid()) {
173 0 : throw JSONRPCError(RPC_INTERNAL_ERROR, "Wallet contains an invalid public key");
174 : }
175 : return vchPubKey;
176 142 : }
177 :
178 : // Creates a multisig address from a given list of public keys, number of signatures required, and the address type
179 210 : CTxDestination AddAndGetMultisigDestination(const int required, const std::vector<CPubKey>& pubkeys, OutputType type, FillableSigningProvider& keystore, CScript& script_out)
180 : {
181 : // Gather public keys
182 210 : if (required < 1) {
183 0 : throw JSONRPCError(RPC_INVALID_PARAMETER, "a multisignature address must require at least one key to redeem");
184 : }
185 210 : if ((int)pubkeys.size() < required) {
186 0 : throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("not enough keys supplied (got %u keys, but need at least %d to redeem)", pubkeys.size(), required));
187 : }
188 210 : if (pubkeys.size() > 16) {
189 0 : throw JSONRPCError(RPC_INVALID_PARAMETER, "Number of keys involved in the multisignature address creation > 16\nReduce the number");
190 : }
191 :
192 210 : script_out = GetScriptForMultisig(required, pubkeys);
193 :
194 210 : if (script_out.size() > MAX_SCRIPT_ELEMENT_SIZE) {
195 0 : throw JSONRPCError(RPC_INVALID_PARAMETER, (strprintf("redeemScript exceeds size limit: %d > %d", script_out.size(), MAX_SCRIPT_ELEMENT_SIZE)));
196 : }
197 :
198 : // Check if any keys are uncompressed. If so, the type is legacy
199 753 : for (const CPubKey& pk : pubkeys) {
200 543 : if (!pk.IsCompressed()) {
201 : type = OutputType::LEGACY;
202 90 : break;
203 : }
204 453 : }
205 :
206 : // Make the address
207 210 : CTxDestination dest = AddAndGetDestinationForScript(keystore, script_out, type);
208 :
209 : return dest;
210 210 : }
211 :
212 : class DescribeAddressVisitor : public boost::static_visitor<UniValue>
213 : {
214 : public:
215 2558 : explicit DescribeAddressVisitor() {}
216 :
217 0 : UniValue operator()(const CNoDestination& dest) const
218 : {
219 0 : return UniValue(UniValue::VOBJ);
220 0 : }
221 :
222 214 : UniValue operator()(const PKHash& keyID) const
223 : {
224 214 : UniValue obj(UniValue::VOBJ);
225 214 : obj.pushKV("isscript", false);
226 214 : obj.pushKV("iswitness", false);
227 : return obj;
228 214 : }
229 :
230 321 : UniValue operator()(const ScriptHash& scriptID) const
231 : {
232 321 : UniValue obj(UniValue::VOBJ);
233 321 : obj.pushKV("isscript", true);
234 321 : obj.pushKV("iswitness", false);
235 : return obj;
236 321 : }
237 :
238 627 : UniValue operator()(const WitnessV0KeyHash& id) const
239 : {
240 627 : UniValue obj(UniValue::VOBJ);
241 627 : obj.pushKV("isscript", false);
242 627 : obj.pushKV("iswitness", true);
243 627 : obj.pushKV("witness_version", 0);
244 627 : obj.pushKV("witness_program", HexStr(id));
245 : return obj;
246 627 : }
247 :
248 117 : UniValue operator()(const WitnessV0ScriptHash& id) const
249 : {
250 117 : UniValue obj(UniValue::VOBJ);
251 117 : obj.pushKV("isscript", true);
252 117 : obj.pushKV("iswitness", true);
253 117 : obj.pushKV("witness_version", 0);
254 117 : obj.pushKV("witness_program", HexStr(id));
255 : return obj;
256 117 : }
257 :
258 0 : UniValue operator()(const WitnessUnknown& id) const
259 : {
260 0 : UniValue obj(UniValue::VOBJ);
261 0 : obj.pushKV("iswitness", true);
262 0 : obj.pushKV("witness_version", (int)id.version);
263 0 : obj.pushKV("witness_program", HexStr(Span<const unsigned char>(id.program, id.length)));
264 : return obj;
265 0 : }
266 : };
267 :
268 1279 : UniValue DescribeAddress(const CTxDestination& dest)
269 : {
270 1279 : return boost::apply_visitor(DescribeAddressVisitor(), dest);
271 : }
272 :
273 258 : unsigned int ParseConfirmTarget(const UniValue& value, unsigned int max_target)
274 : {
275 258 : int target = value.get_int();
276 258 : if (target < 1 || (unsigned int)target > max_target) {
277 0 : throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid conf_target, must be between %u - %u", 1, max_target));
278 : }
279 258 : return (unsigned int)target;
280 0 : }
281 :
282 415 : RPCErrorCode RPCErrorFromTransactionError(TransactionError terr)
283 : {
284 415 : switch (terr) {
285 : case TransactionError::MEMPOOL_REJECTED:
286 412 : return RPC_TRANSACTION_REJECTED;
287 : case TransactionError::ALREADY_IN_CHAIN:
288 0 : return RPC_TRANSACTION_ALREADY_IN_CHAIN;
289 : case TransactionError::P2P_DISABLED:
290 0 : return RPC_CLIENT_P2P_DISABLED;
291 : case TransactionError::INVALID_PSBT:
292 : case TransactionError::PSBT_MISMATCH:
293 0 : return RPC_INVALID_PARAMETER;
294 : case TransactionError::SIGHASH_MISMATCH:
295 0 : return RPC_DESERIALIZATION_ERROR;
296 : default: break;
297 : }
298 3 : return RPC_TRANSACTION_ERROR;
299 415 : }
300 :
301 415 : UniValue JSONRPCTransactionError(TransactionError terr, const std::string& err_string)
302 : {
303 415 : if (err_string.length() > 0) {
304 413 : return JSONRPCError(RPCErrorFromTransactionError(terr), err_string);
305 : } else {
306 2 : return JSONRPCError(RPCErrorFromTransactionError(terr), TransactionErrorString(terr).original);
307 : }
308 415 : }
309 :
310 : /**
311 : * A pair of strings that can be aligned (through padding) with other Sections
312 : * later on
313 : */
314 83656 : struct Section {
315 15792 : Section(const std::string& left, const std::string& right)
316 15792 : : m_left{left}, m_right{right} {}
317 : std::string m_left;
318 : const std::string m_right;
319 : };
320 :
321 : /**
322 : * Keeps track of RPCArgs by transforming them into sections for the purpose
323 : * of serializing everything to a single string
324 : */
325 5955 : struct Sections {
326 : std::vector<Section> m_sections;
327 1191 : size_t m_max_pad{0};
328 :
329 6857 : void PushSection(const Section& s)
330 : {
331 6857 : m_max_pad = std::max(m_max_pad, s.m_left.size());
332 6857 : m_sections.push_back(s);
333 6857 : }
334 :
335 : /**
336 : * Recursive helper to translate an RPCArg into sections
337 : */
338 1687 : void Push(const RPCArg& arg, const size_t current_indent = 5, const OuterType outer_type = OuterType::NONE)
339 : {
340 1687 : const auto indent = std::string(current_indent, ' ');
341 1687 : const auto indent_next = std::string(current_indent + 2, ' ');
342 1687 : const bool push_name{outer_type == OuterType::OBJ}; // Dictionary keys must have a name
343 :
344 1687 : switch (arg.m_type) {
345 : case RPCArg::Type::STR_HEX:
346 : case RPCArg::Type::STR:
347 : case RPCArg::Type::NUM:
348 : case RPCArg::Type::AMOUNT:
349 : case RPCArg::Type::RANGE:
350 : case RPCArg::Type::BOOL: {
351 1413 : if (outer_type == OuterType::NONE) return; // Nothing more to do for non-recursive types on first recursion
352 532 : auto left = indent;
353 532 : if (arg.m_type_str.size() != 0 && push_name) {
354 12 : left += "\"" + arg.GetName() + "\": " + arg.m_type_str.at(0);
355 12 : } else {
356 520 : left += push_name ? arg.ToStringObj(/* oneline */ false) : arg.ToString(/* oneline */ false);
357 : }
358 532 : left += ",";
359 532 : PushSection({left, arg.ToDescriptionString()});
360 : break;
361 532 : }
362 : case RPCArg::Type::OBJ:
363 : case RPCArg::Type::OBJ_USER_KEYS: {
364 120 : const auto right = outer_type == OuterType::NONE ? "" : arg.ToDescriptionString();
365 120 : PushSection({indent + (push_name ? "\"" + arg.GetName() + "\": " : "") + "{", right});
366 568 : for (const auto& arg_inner : arg.m_inner) {
367 448 : Push(arg_inner, current_indent + 2, OuterType::OBJ);
368 : }
369 120 : if (arg.m_type != RPCArg::Type::OBJ) {
370 0 : PushSection({indent_next + "...", ""});
371 0 : }
372 120 : PushSection({indent + "}" + (outer_type != OuterType::NONE ? "," : ""), ""});
373 : break;
374 120 : }
375 : case RPCArg::Type::ARR: {
376 154 : auto left = indent;
377 154 : left += push_name ? "\"" + arg.GetName() + "\": " : "";
378 154 : left += "[";
379 154 : const auto right = outer_type == OuterType::NONE ? "" : arg.ToDescriptionString();
380 154 : PushSection({left, right});
381 354 : for (const auto& arg_inner : arg.m_inner) {
382 200 : Push(arg_inner, current_indent + 2, OuterType::ARR);
383 : }
384 154 : PushSection({indent_next + "...", ""});
385 154 : PushSection({indent + "]" + (outer_type != OuterType::NONE ? "," : ""), ""});
386 : break;
387 154 : }
388 : } // no default case, so the compiler can warn about missing cases
389 1687 : }
390 :
391 : /**
392 : * Concatenate all sections with proper padding
393 : */
394 1191 : std::string ToString() const
395 : {
396 1191 : std::string ret;
397 1191 : const size_t pad = m_max_pad + 4;
398 9087 : for (const auto& s : m_sections) {
399 : // The left part of a section is assumed to be a single line, usually it is the name of the JSON struct or a
400 : // brace like {, }, [, or ]
401 7896 : CHECK_NONFATAL(s.m_left.find('\n') == std::string::npos);
402 7896 : if (s.m_right.empty()) {
403 1957 : ret += s.m_left;
404 1957 : ret += "\n";
405 1957 : continue;
406 : }
407 :
408 5939 : std::string left = s.m_left;
409 5939 : left.resize(pad, ' ');
410 5939 : ret += left;
411 :
412 : // Properly pad after newlines
413 5939 : std::string right;
414 : size_t begin = 0;
415 5939 : size_t new_line_pos = s.m_right.find_first_of('\n');
416 6922 : while (true) {
417 6922 : right += s.m_right.substr(begin, new_line_pos - begin);
418 6922 : if (new_line_pos == std::string::npos) {
419 : break; //No new line
420 : }
421 1004 : right += "\n" + std::string(pad, ' ');
422 1004 : begin = s.m_right.find_first_not_of(' ', new_line_pos + 1);
423 1004 : if (begin == std::string::npos) {
424 : break; // Empty line
425 : }
426 983 : new_line_pos = s.m_right.find_first_of('\n', begin + 1);
427 : }
428 5939 : ret += right;
429 5939 : ret += "\n";
430 5939 : }
431 : return ret;
432 1191 : }
433 : };
434 :
435 73572 : RPCHelpMan::RPCHelpMan(std::string name, std::string description, std::vector<RPCArg> args, RPCResults results, RPCExamples examples)
436 73572 : : RPCHelpMan{std::move(name), std::move(description), std::move(args), std::move(results), std::move(examples), nullptr} {}
437 :
438 344102 : RPCHelpMan::RPCHelpMan(std::string name, std::string description, std::vector<RPCArg> args, RPCResults results, RPCExamples examples, RPCMethodImpl fun)
439 172051 : : m_name{std::move(name)},
440 172051 : m_fun{std::move(fun)},
441 172051 : m_description{std::move(description)},
442 172051 : m_args{std::move(args)},
443 172051 : m_results{std::move(results)},
444 172051 : m_examples{std::move(examples)}
445 172051 : {
446 172051 : std::set<std::string> named_args;
447 495678 : for (const auto& arg : m_args) {
448 323627 : std::vector<std::string> names;
449 323627 : boost::split(names, arg.m_names, boost::is_any_of("|"));
450 : // Should have unique named arguments
451 651707 : for (const std::string& name : names) {
452 328080 : CHECK_NONFATAL(named_args.insert(name).second);
453 : }
454 323627 : }
455 344102 : }
456 :
457 582 : std::string RPCResults::ToDescriptionString() const
458 : {
459 582 : std::string result;
460 1191 : for (const auto& r : m_results) {
461 609 : if (r.m_cond.empty()) {
462 547 : result += "\nResult:\n";
463 : } else {
464 62 : result += "\nResult (" + r.m_cond + "):\n";
465 : }
466 609 : Sections sections;
467 609 : r.ToSections(sections);
468 609 : result += sections.ToString();
469 609 : }
470 : return result;
471 582 : }
472 :
473 582 : std::string RPCExamples::ToDescriptionString() const
474 : {
475 582 : return m_examples.empty() ? m_examples : "\nExamples:\n" + m_examples;
476 : }
477 :
478 78195 : bool RPCHelpMan::IsValidNumArgs(size_t num_args) const
479 : {
480 : size_t num_required_args = 0;
481 151395 : for (size_t n = m_args.size(); n > 0; --n) {
482 119155 : if (!m_args.at(n - 1).IsOptional()) {
483 : num_required_args = n;
484 45955 : break;
485 : }
486 : }
487 78195 : return num_required_args <= num_args && num_args <= m_args.size();
488 : }
489 :
490 46650 : std::vector<std::string> RPCHelpMan::GetArgNames() const
491 : {
492 46650 : std::vector<std::string> ret;
493 138614 : for (const auto& arg : m_args) {
494 91964 : ret.emplace_back(arg.m_names);
495 : }
496 : return ret;
497 46650 : }
498 :
499 582 : std::string RPCHelpMan::ToString() const
500 : {
501 582 : std::string ret;
502 :
503 : // Oneline summary
504 582 : ret += m_name;
505 2203 : bool was_optional{false};
506 1625 : for (const auto& arg : m_args) {
507 1043 : if (arg.m_hidden) break; // Any arg that follows is also hidden
508 1039 : const bool optional = arg.IsOptional();
509 1039 : ret += " ";
510 1039 : if (optional) {
511 590 : if (!was_optional) ret += "( ";
512 : was_optional = true;
513 590 : } else {
514 449 : if (was_optional) ret += ") ";
515 : was_optional = false;
516 : }
517 1039 : ret += arg.ToString(/* oneline */ true);
518 1039 : }
519 582 : if (was_optional) ret += " )";
520 582 : ret += "\n";
521 :
522 : // Description
523 582 : ret += m_description;
524 :
525 : // Arguments
526 582 : Sections sections;
527 1621 : for (size_t i{0}; i < m_args.size(); ++i) {
528 1043 : const auto& arg = m_args.at(i);
529 1043 : if (arg.m_hidden) break; // Any arg that follows is also hidden
530 :
531 1039 : if (i == 0) ret += "\nArguments:\n";
532 :
533 : // Push named argument name and description
534 1039 : sections.m_sections.emplace_back(::ToString(i + 1) + ". " + arg.GetFirstName(), arg.ToDescriptionString());
535 1039 : sections.m_max_pad = std::max(sections.m_max_pad, sections.m_sections.back().m_left.size());
536 :
537 : // Recursively push nested args
538 1039 : sections.Push(arg);
539 1039 : }
540 582 : ret += sections.ToString();
541 :
542 : // Result
543 582 : ret += m_results.ToDescriptionString();
544 :
545 : // Examples
546 582 : ret += m_examples.ToDescriptionString();
547 :
548 : return ret;
549 582 : }
550 :
551 2648 : std::string RPCArg::GetFirstName() const
552 : {
553 2648 : return m_names.substr(0, m_names.find("|"));
554 : }
555 :
556 44 : std::string RPCArg::GetName() const
557 : {
558 44 : CHECK_NONFATAL(std::string::npos == m_names.find("|"));
559 44 : return m_names;
560 0 : }
561 :
562 120194 : bool RPCArg::IsOptional() const
563 : {
564 120194 : if (m_fallback.which() == 1) {
565 65534 : return true;
566 : } else {
567 54660 : return RPCArg::Optional::NO != boost::get<RPCArg::Optional>(m_fallback);
568 : }
569 120194 : }
570 :
571 1687 : std::string RPCArg::ToDescriptionString() const
572 : {
573 1687 : std::string ret;
574 1687 : ret += "(";
575 1687 : if (m_type_str.size() != 0) {
576 18 : ret += m_type_str.at(1);
577 : } else {
578 1669 : switch (m_type) {
579 : case Type::STR_HEX:
580 : case Type::STR: {
581 709 : ret += "string";
582 : break;
583 : }
584 : case Type::NUM: {
585 308 : ret += "numeric";
586 : break;
587 : }
588 : case Type::AMOUNT: {
589 69 : ret += "numeric or string";
590 : break;
591 : }
592 : case Type::RANGE: {
593 20 : ret += "numeric or array";
594 : break;
595 : }
596 : case Type::BOOL: {
597 289 : ret += "boolean";
598 : break;
599 : }
600 : case Type::OBJ:
601 : case Type::OBJ_USER_KEYS: {
602 120 : ret += "json object";
603 : break;
604 : }
605 : case Type::ARR: {
606 154 : ret += "json array";
607 : break;
608 : }
609 : } // no default case, so the compiler can warn about missing cases
610 : }
611 1687 : if (m_fallback.which() == 1) {
612 713 : ret += ", optional, default=" + boost::get<std::string>(m_fallback);
613 713 : } else {
614 974 : switch (boost::get<RPCArg::Optional>(m_fallback)) {
615 : case RPCArg::Optional::OMITTED: {
616 : // nothing to do. Element is treated as if not present and has no default value
617 : break;
618 : }
619 : case RPCArg::Optional::OMITTED_NAMED_ARG: {
620 133 : ret += ", optional"; // Default value is "null"
621 : break;
622 : }
623 : case RPCArg::Optional::NO: {
624 605 : ret += ", required";
625 : break;
626 : }
627 : } // no default case, so the compiler can warn about missing cases
628 : }
629 1687 : ret += ")";
630 1687 : ret += m_description.empty() ? "" : " " + m_description;
631 : return ret;
632 1687 : }
633 :
634 4266 : void RPCResult::ToSections(Sections& sections, const OuterType outer_type, const int current_indent) const
635 : {
636 : // Indentation
637 4266 : const std::string indent(current_indent, ' ');
638 4266 : const std::string indent_next(current_indent + 2, ' ');
639 :
640 : // Elements in a JSON structure (dictionary or array) are separated by a comma
641 4266 : const std::string maybe_separator{outer_type != OuterType::NONE ? "," : ""};
642 :
643 : // The key name if recursed into an dictionary
644 8532 : const std::string maybe_key{
645 4266 : outer_type == OuterType::OBJ ?
646 3267 : "\"" + this->m_key_name + "\" : " :
647 999 : ""};
648 :
649 : // Format description with type
650 8486 : const auto Description = [&](const std::string& type) {
651 8440 : return "(" + type + (this->m_optional ? ", optional" : "") + ")" +
652 4220 : (this->m_description.empty() ? "" : " " + this->m_description);
653 0 : };
654 :
655 4266 : switch (m_type) {
656 : case Type::ELISION: {
657 : // If the inner result is empty, use three dots for elision
658 46 : sections.PushSection({indent + "..." + maybe_separator, m_description});
659 46 : return;
660 : }
661 : case Type::NONE: {
662 94 : sections.PushSection({indent + "null" + maybe_separator, Description("json null")});
663 94 : return;
664 : }
665 : case Type::STR: {
666 687 : sections.PushSection({indent + maybe_key + "\"str\"" + maybe_separator, Description("string")});
667 687 : return;
668 : }
669 : case Type::STR_AMOUNT: {
670 292 : sections.PushSection({indent + maybe_key + "n" + maybe_separator, Description("numeric")});
671 292 : return;
672 : }
673 : case Type::STR_HEX: {
674 546 : sections.PushSection({indent + maybe_key + "\"hex\"" + maybe_separator, Description("string")});
675 546 : return;
676 : }
677 : case Type::NUM: {
678 1133 : sections.PushSection({indent + maybe_key + "n" + maybe_separator, Description("numeric")});
679 1133 : return;
680 : }
681 : case Type::NUM_TIME: {
682 159 : sections.PushSection({indent + maybe_key + "xxx" + maybe_separator, Description("numeric")});
683 159 : return;
684 : }
685 : case Type::BOOL: {
686 355 : sections.PushSection({indent + maybe_key + "true|false" + maybe_separator, Description("boolean")});
687 355 : return;
688 : }
689 : case Type::ARR_FIXED:
690 : case Type::ARR: {
691 358 : sections.PushSection({indent + maybe_key + "[", Description("json array")});
692 748 : for (const auto& i : m_inner) {
693 390 : i.ToSections(sections, OuterType::ARR, current_indent + 2);
694 : }
695 358 : CHECK_NONFATAL(!m_inner.empty());
696 358 : if (m_type == Type::ARR && m_inner.back().m_type != Type::ELISION) {
697 348 : sections.PushSection({indent_next + "...", ""});
698 348 : } else {
699 : // Remove final comma, which would be invalid JSON
700 10 : sections.m_sections.back().m_left.pop_back();
701 : }
702 358 : sections.PushSection({indent + "]" + maybe_separator, ""});
703 358 : return;
704 : }
705 : case Type::OBJ_DYN:
706 : case Type::OBJ: {
707 596 : sections.PushSection({indent + maybe_key + "{", Description("json object")});
708 3863 : for (const auto& i : m_inner) {
709 3267 : i.ToSections(sections, OuterType::OBJ, current_indent + 2);
710 : }
711 596 : CHECK_NONFATAL(!m_inner.empty());
712 596 : if (m_type == Type::OBJ_DYN && m_inner.back().m_type != Type::ELISION) {
713 : // If the dictionary keys are dynamic, use three dots for continuation
714 55 : sections.PushSection({indent_next + "...", ""});
715 55 : } else {
716 : // Remove final comma, which would be invalid JSON
717 541 : sections.m_sections.back().m_left.pop_back();
718 : }
719 596 : sections.PushSection({indent + "}" + maybe_separator, ""});
720 596 : return;
721 : }
722 : } // no default case, so the compiler can warn about missing cases
723 0 : CHECK_NONFATAL(false);
724 4266 : }
725 :
726 560 : std::string RPCArg::ToStringObj(const bool oneline) const
727 : {
728 560 : std::string res;
729 560 : res += "\"";
730 560 : res += GetFirstName();
731 560 : if (oneline) {
732 156 : res += "\":";
733 : } else {
734 404 : res += "\": ";
735 : }
736 560 : switch (m_type) {
737 : case Type::STR:
738 76 : return res + "\"str\"";
739 : case Type::STR_HEX:
740 152 : return res + "\"hex\"";
741 : case Type::NUM:
742 140 : return res + "n";
743 : case Type::RANGE:
744 20 : return res + "n or [n,n]";
745 : case Type::AMOUNT:
746 84 : return res + "amount";
747 : case Type::BOOL:
748 88 : return res + "bool";
749 : case Type::ARR:
750 0 : res += "[";
751 0 : for (const auto& i : m_inner) {
752 0 : res += i.ToString(oneline) + ",";
753 : }
754 0 : return res + "...]";
755 : case Type::OBJ:
756 : case Type::OBJ_USER_KEYS:
757 : // Currently unused, so avoid writing dead code
758 0 : CHECK_NONFATAL(false);
759 : } // no default case, so the compiler can warn about missing cases
760 0 : CHECK_NONFATAL(false);
761 560 : }
762 :
763 1283 : std::string RPCArg::ToString(const bool oneline) const
764 : {
765 1283 : if (oneline && !m_oneline_description.empty()) return m_oneline_description;
766 :
767 1229 : switch (m_type) {
768 : case Type::STR_HEX:
769 : case Type::STR: {
770 609 : return "\"" + GetFirstName() + "\"";
771 : }
772 : case Type::NUM:
773 : case Type::RANGE:
774 : case Type::AMOUNT:
775 : case Type::BOOL: {
776 440 : return GetFirstName();
777 : }
778 : case Type::OBJ:
779 : case Type::OBJ_USER_KEYS: {
780 232 : const std::string res = Join(m_inner, ",", [&](const RPCArg& i) { return i.ToStringObj(oneline); });
781 76 : if (m_type == Type::OBJ) {
782 76 : return "{" + res + "}";
783 : } else {
784 0 : return "{" + res + ",...}";
785 : }
786 76 : }
787 : case Type::ARR: {
788 104 : std::string res;
789 232 : for (const auto& i : m_inner) {
790 128 : res += i.ToString(oneline) + ",";
791 : }
792 104 : return "[" + res + "...]";
793 104 : }
794 : } // no default case, so the compiler can warn about missing cases
795 0 : CHECK_NONFATAL(false);
796 1283 : }
797 :
798 72 : static std::pair<int64_t, int64_t> ParseRange(const UniValue& value)
799 : {
800 72 : if (value.isNum()) {
801 31 : return {0, value.get_int64()};
802 : }
803 41 : if (value.isArray() && value.size() == 2 && value[0].isNum() && value[1].isNum()) {
804 41 : int64_t low = value[0].get_int64();
805 41 : int64_t high = value[1].get_int64();
806 41 : if (low > high) throw JSONRPCError(RPC_INVALID_PARAMETER, "Range specified as [begin,end] must not have begin after end");
807 36 : return {low, high};
808 41 : }
809 0 : throw JSONRPCError(RPC_INVALID_PARAMETER, "Range must be specified as end or as [begin,end]");
810 72 : }
811 :
812 72 : std::pair<int64_t, int64_t> ParseDescriptorRange(const UniValue& value)
813 : {
814 72 : int64_t low, high;
815 72 : std::tie(low, high) = ParseRange(value);
816 72 : if (low < 0) {
817 5 : throw JSONRPCError(RPC_INVALID_PARAMETER, "Range should be greater or equal than 0");
818 : }
819 62 : if ((high >> 31) != 0) {
820 8 : throw JSONRPCError(RPC_INVALID_PARAMETER, "End of range is too high");
821 : }
822 54 : if (high >= low + 1000000) {
823 5 : throw JSONRPCError(RPC_INVALID_PARAMETER, "Range is too large");
824 : }
825 49 : return {low, high};
826 67 : }
827 :
828 58 : std::vector<CScript> EvalDescriptorStringOrObject(const UniValue& scanobject, FlatSigningProvider& provider)
829 : {
830 58 : std::string desc_str;
831 58 : std::pair<int64_t, int64_t> range = {0, 1000};
832 58 : if (scanobject.isStr()) {
833 40 : desc_str = scanobject.get_str();
834 18 : } else if (scanobject.isObject()) {
835 18 : UniValue desc_uni = find_value(scanobject, "desc");
836 18 : if (desc_uni.isNull()) throw JSONRPCError(RPC_INVALID_PARAMETER, "Descriptor needs to be provided in scan object");
837 18 : desc_str = desc_uni.get_str();
838 18 : UniValue range_uni = find_value(scanobject, "range");
839 18 : if (!range_uni.isNull()) {
840 18 : range = ParseDescriptorRange(range_uni);
841 13 : }
842 18 : } else {
843 0 : throw JSONRPCError(RPC_INVALID_PARAMETER, "Scan object needs to be either a string or an object");
844 : }
845 :
846 53 : std::string error;
847 53 : auto desc = Parse(desc_str, provider, error);
848 53 : if (!desc) {
849 0 : throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, error);
850 : }
851 53 : if (!desc->IsRange()) {
852 40 : range.first = 0;
853 40 : range.second = 0;
854 40 : }
855 53 : std::vector<CScript> ret;
856 18100 : for (int i = range.first; i <= range.second; ++i) {
857 18047 : std::vector<CScript> scripts;
858 18047 : if (!desc->Expand(i, provider, scripts, provider)) {
859 0 : throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Cannot derive script without private keys: '%s'", desc_str));
860 : }
861 18047 : std::move(scripts.begin(), scripts.end(), std::back_inserter(ret));
862 18047 : }
863 : return ret;
864 63 : }
865 :
866 8679 : UniValue GetServicesNames(ServiceFlags services)
867 : {
868 8679 : UniValue servicesNames(UniValue::VARR);
869 :
870 33484 : for (const auto& flag : serviceFlagsToStr(services)) {
871 24805 : servicesNames.push_back(flag);
872 : }
873 :
874 : return servicesNames;
875 8679 : }
|