Coverage Report

Created: 2026-10-07 13:27

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