Coverage Report

Created: 2026-09-21 19:49

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
55.6k
{
54
55.6k
    std::vector<std::string> ret;
55
55.6k
    using U = std::underlying_type_t<TxoutType>;
56
667k
    for (U i = (U)TxoutType::NONSTANDARD; i <= (U)TxoutType::WITNESS_UNKNOWN; ++i) {
57
612k
        ret.emplace_back(GetTxnOutputType(static_cast<TxoutType>(i)));
58
612k
    }
59
55.6k
    return Join(ret, ", ");
60
55.6k
}
61
62
void RPCTypeCheckObj(const UniValue& o,
63
    const std::map<std::string, UniValueType>& typesExpected,
64
    bool fAllowNull,
65
    bool fStrict)
66
2.29k
{
67
22.7k
    for (const auto& t : typesExpected) {
68
22.7k
        const UniValue& v = o.find_value(t.first);
69
22.7k
        if (!fAllowNull && v.isNull())
70
11
            throw JSONRPCError(RPC_TYPE_ERROR, strprintf("Missing %s", t.first));
71
72
22.7k
        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.7k
    }
75
76
2.25k
    if (fStrict)
77
1.25k
    {
78
1.25k
        for (const std::string& k : o.getKeys())
79
2.49k
        {
80
2.49k
            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.49k
        }
86
1.25k
    }
87
2.25k
}
88
89
int ParseVerbosity(const UniValue& arg, int default_verbosity, bool allow_bool)
90
7.14k
{
91
7.14k
    if (!arg.isNull()) {
92
5.48k
        if (arg.isBool()) {
93
3.80k
            if (!allow_bool) {
94
2
                throw JSONRPCError(RPC_TYPE_ERROR, "Verbosity was boolean but only integer allowed");
95
2
            }
96
3.80k
            return arg.get_bool(); // true = 1
97
3.80k
        } else {
98
1.67k
            return arg.getInt<int>();
99
1.67k
        }
100
5.48k
    }
101
1.66k
    return default_verbosity;
102
7.14k
}
103
104
CAmount AmountFromValue(const UniValue& value, int decimals)
105
54.1k
{
106
54.1k
    if (!value.isNum() && !value.isStr())
107
12
        throw JSONRPCError(RPC_TYPE_ERROR, "Amount is not a number or string");
108
54.1k
    int64_t amount;
109
54.1k
    if (!ParseFixedPoint(value.getValStr(), decimals, &amount))
110
83
        throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount");
111
54.1k
    if (!MoneyRange(amount))
112
12
        throw JSONRPCError(RPC_TYPE_ERROR, "Amount out of range");
113
54.0k
    return amount;
114
54.1k
}
115
116
CFeeRate ParseFeeRate(const UniValue& json)
117
37.6k
{
118
37.6k
    CAmount val{AmountFromValue(json)};
119
37.6k
    if (val >= COIN) throw JSONRPCError(RPC_INVALID_PARAMETER, "Fee rates larger than or equal to 1BTC/kvB are not accepted");
120
37.6k
    return CFeeRate{val};
121
37.6k
}
122
123
uint256 ParseHashV(const UniValue& v, std::string_view name)
124
30.3k
{
125
30.3k
    const std::string& strHex(v.get_str());
126
30.3k
    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.57k
{
134
6.57k
    return ParseHashV(o.find_value(strKey), strKey);
135
6.57k
}
136
std::vector<unsigned char> ParseHexV(const UniValue& v, std::string_view name)
137
1.00k
{
138
1.00k
    std::string strHex;
139
1.00k
    if (v.isStr())
140
1.00k
        strHex = v.get_str();
141
1.00k
    if (!IsHex(strHex))
142
4
        throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("%s must be hexadecimal string (not '%s')", name, strHex));
143
997
    return ParseHex(strHex);
144
1.00k
}
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.55k
{
159
2.55k
    std::string result;
160
2.55k
    result.reserve(s.size() * 2);
161
219k
    for (const char ch: s) {
162
219k
        if (ch == '\'') {
163
1
            result += "'\''";
164
219k
        } else {
165
219k
            result += ch;
166
219k
        }
167
219k
    }
168
2.55k
    return "'" + result + "'";
169
2.55k
}
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
15.8k
{
178
104k
    for (const char ch: s) {
179
104k
        if (ch == ' ' || ch == '\'' || ch == '"') {
180
2.55k
            return ShellQuote(s);
181
2.55k
        }
182
104k
    }
183
184
13.2k
    return s;
185
15.8k
}
186
187
}
188
189
std::string HelpExampleCli(const std::string& methodname, const std::string& args)
190
744k
{
191
744k
    return "> bitcoin-cli " + methodname + " " + args + "\n";
192
744k
}
193
194
std::string HelpExampleCliNamed(const std::string& methodname, const RPCArgList& args)
195
6.72k
{
196
6.72k
    std::string result = "> bitcoin-cli -named " + methodname;
197
15.8k
    for (const auto& argpair: args) {
198
15.8k
        const auto& value = argpair.second.isStr()
199
15.8k
                ? argpair.second.get_str()
200
15.8k
                : argpair.second.write();
201
15.8k
        result += " " + argpair.first + "=" + ShellQuoteIfNeeded(value);
202
15.8k
    }
203
6.72k
    result += "\n";
204
6.72k
    return result;
205
6.72k
}
206
207
std::string HelpExampleRpc(const std::string& methodname, const std::string& args)
208
485k
{
209
485k
    return "> curl --user myusername --data-binary '{\"jsonrpc\": \"2.0\", \"id\": \"curltest\", "
210
485k
        "\"method\": \"" + methodname + "\", \"params\": [" + args + "]}' -H 'content-type: application/json' http://127.0.0.1:8332/\n";
211
485k
}
212
213
std::string HelpExampleRpcNamed(const std::string& methodname, const RPCArgList& args)
214
4.17k
{
215
4.17k
    UniValue params(UniValue::VOBJ);
216
10.7k
    for (const auto& param: args) {
217
10.7k
        params.pushKV(param.first, param.second);
218
10.7k
    }
219
220
4.17k
    return "> curl --user myusername --data-binary '{\"jsonrpc\": \"2.0\", \"id\": \"curltest\", "
221
4.17k
           "\"method\": \"" + methodname + "\", \"params\": " + params.write() + "}' -H 'content-type: application/json' http://127.0.0.1:8332/\n";
222
4.17k
}
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
129
    {
291
129
        UniValue obj(UniValue::VOBJ);
292
129
        obj.pushKV("isscript", false);
293
129
        obj.pushKV("iswitness", false);
294
129
        return obj;
295
129
    }
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
504
    {
307
504
        UniValue obj(UniValue::VOBJ);
308
504
        obj.pushKV("isscript", false);
309
504
        obj.pushKV("iswitness", true);
310
504
        obj.pushKV("witness_version", 0);
311
504
        obj.pushKV("witness_program", HexStr(id));
312
504
        return obj;
313
504
    }
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
127
    {
327
127
        UniValue obj(UniValue::VOBJ);
328
127
        obj.pushKV("isscript", true);
329
127
        obj.pushKV("iswitness", true);
330
127
        obj.pushKV("witness_version", 1);
331
127
        obj.pushKV("witness_program", HexStr(tap));
332
127
        return obj;
333
127
    }
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
935
{
355
935
    return std::visit(DescribeAddressVisitor(), dest);
356
935
}
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
991
        return std::nullopt;
367
991
    }
368
92
    const auto result{SighashFromStr(sighash.get_str())};
369
92
    if (!result) {
370
4
        throw JSONRPCError(RPC_INVALID_PARAMETER, util::ErrorString(result).original);
371
4
    }
372
88
    return result.value();
373
92
}
374
375
unsigned int ParseConfirmTarget(const UniValue& value, unsigned int max_target)
376
352
{
377
352
    const int target{value.getInt<int>()};
378
352
    const unsigned int unsigned_target{static_cast<unsigned int>(target)};
379
352
    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
321
    return unsigned_target;
383
352
}
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.48k
{
399
4.48k
    switch (terr) {
400
4.46k
        case TransactionError::MEMPOOL_REJECTED:
401
4.46k
            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.48k
    }
408
12
    return RPC_TRANSACTION_ERROR;
409
4.48k
}
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.48k
{
418
4.48k
    if (err_string.length() > 0) {
419
4.46k
        return JSONRPCError(RPCErrorFromTransactionError(terr), err_string);
420
4.46k
    } else {
421
15
        return JSONRPCError(RPCErrorFromTransactionError(terr), TransactionErrorString(terr).original);
422
15
    }
423
4.48k
}
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
20.9k
        : 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
18.9k
    {
446
18.9k
        m_max_pad = std::max(m_max_pad, s.m_left.size());
447
18.9k
        m_sections.push_back(s);
448
18.9k
    }
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.24k
    {
456
3.24k
        const auto indent = std::string(current_indent, ' ');
457
3.24k
        const auto indent_next = std::string(current_indent + 2, ' ');
458
3.24k
        const bool push_name{outer_type == OuterType::OBJ}; // Dictionary keys must have a name
459
3.24k
        const bool is_top_level_arg{outer_type == OuterType::NONE}; // True on the first recursion
460
461
3.24k
        switch (arg.m_type) {
462
486
        case RPCArg::Type::STR_HEX:
463
1.33k
        case RPCArg::Type::STR:
464
1.93k
        case RPCArg::Type::NUM:
465
2.08k
        case RPCArg::Type::AMOUNT:
466
2.14k
        case RPCArg::Type::RANGE:
467
2.62k
        case RPCArg::Type::BOOL:
468
2.69k
        case RPCArg::Type::OBJ_NAMED_PARAMS: {
469
2.69k
            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.69k
        }
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.24k
        } // no default case, so the compiler can warn about missing cases
507
3.24k
    }
508
509
    /**
510
     * Concatenate all sections with proper padding
511
     */
512
    std::string ToString() const
513
3.54k
    {
514
3.54k
        std::string ret;
515
3.54k
        const size_t pad = m_max_pad + 4;
516
20.9k
        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
20.9k
            CHECK_NONFATAL(s.m_left.find('\n') == std::string::npos);
520
20.9k
            if (s.m_right.empty()) {
521
5.57k
                ret += s.m_left;
522
5.57k
                ret += "\n";
523
5.57k
                continue;
524
5.57k
            }
525
526
15.3k
            std::string left = s.m_left;
527
15.3k
            left.resize(pad, ' ');
528
15.3k
            ret += left;
529
530
            // Properly pad after newlines
531
15.3k
            std::string right;
532
15.3k
            size_t begin = 0;
533
15.3k
            size_t new_line_pos = s.m_right.find_first_of('\n');
534
17.2k
            while (true) {
535
17.2k
                right += s.m_right.substr(begin, new_line_pos - begin);
536
17.2k
                if (new_line_pos == std::string::npos) {
537
15.1k
                    break; //No new line
538
15.1k
                }
539
2.05k
                right += "\n" + std::string(pad, ' ');
540
2.05k
                begin = s.m_right.find_first_not_of(' ', new_line_pos + 1);
541
2.05k
                if (begin == std::string::npos) {
542
159
                    break; // Empty line
543
159
                }
544
1.89k
                new_line_pos = s.m_right.find_first_of('\n', begin + 1);
545
1.89k
            }
546
15.3k
            ret += right;
547
15.3k
            ret += "\n";
548
15.3k
        }
549
3.54k
        return ret;
550
3.54k
    }
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
535k
    : m_name{std::move(name)},
558
535k
      m_fun{std::move(fun)},
559
535k
      m_description{std::move(description)},
560
535k
      m_args{std::move(args)},
561
535k
      m_results{std::move(results)},
562
535k
      m_examples{std::move(examples)}
563
535k
{
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
535k
    enum ParamType { POSITIONAL = 1, NAMED = 2, NAMED_ONLY = 4 };
568
535k
    std::map<std::string, int> param_names;
569
570
1.00M
    for (const auto& arg : m_args) {
571
1.00M
        std::vector<std::string> names = SplitString(arg.m_names, '|');
572
        // Should have unique named arguments
573
1.01M
        for (const std::string& name : names) {
574
1.01M
            auto& param_type = param_names[name];
575
1.01M
            CHECK_NONFATAL(!(param_type & POSITIONAL));
576
1.01M
            CHECK_NONFATAL(!(param_type & NAMED_ONLY));
577
1.01M
            param_type |= POSITIONAL;
578
1.01M
        }
579
1.00M
        if (arg.m_type == RPCArg::Type::OBJ_NAMED_PARAMS) {
580
119k
            for (const auto& inner : arg.m_inner) {
581
119k
                std::vector<std::string> inner_names = SplitString(inner.m_names, '|');
582
119k
                for (const std::string& inner_name : inner_names) {
583
119k
                    auto& param_type = param_names[inner_name];
584
119k
                    CHECK_NONFATAL(!(param_type & POSITIONAL) || inner.m_opts.also_positional);
585
119k
                    CHECK_NONFATAL(!(param_type & NAMED));
586
119k
                    CHECK_NONFATAL(!(param_type & NAMED_ONLY));
587
119k
                    param_type |= inner.m_opts.also_positional ? NAMED : NAMED_ONLY;
588
119k
                }
589
119k
            }
590
20.9k
        }
591
        // Default value type should match argument type only when defined
592
1.00M
        if (arg.m_fallback.index() == 2) {
593
347k
            const RPCArg::Type type = arg.m_type;
594
347k
            [&]() {
595
347k
                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.18k
                case UniValue::VARR:
600
2.18k
                    CHECK_NONFATAL(type == RPCArg::Type::ARR);
601
2.18k
                    return;
602
121k
                case UniValue::VSTR:
603
121k
                    CHECK_NONFATAL(type == RPCArg::Type::STR || type == RPCArg::Type::STR_HEX || type == RPCArg::Type::AMOUNT);
604
121k
                    return;
605
75.9k
                case UniValue::VNUM:
606
75.9k
                    CHECK_NONFATAL(type == RPCArg::Type::NUM || type == RPCArg::Type::AMOUNT || type == RPCArg::Type::RANGE);
607
75.9k
                    return;
608
147k
                case UniValue::VBOOL:
609
147k
                    CHECK_NONFATAL(type == RPCArg::Type::BOOL);
610
147k
                    return;
611
0
                case UniValue::VNULL:
612
                    // Null values are accepted in all arguments
613
0
                    return;
614
347k
                } // no default case, so the compiler can warn about missing cases
615
347k
                NONFATAL_UNREACHABLE();
616
347k
            }();
617
347k
        }
618
1.00M
    }
619
535k
}
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
983
            result += "\nResult:\n";
632
983
        } 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
200k
{
647
200k
    if (request.mode == JSONRPCRequest::GET_ARGS) {
648
350
        return GetArgMap();
649
350
    }
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
199k
    if (request.mode == JSONRPCRequest::GET_HELP || !IsValidNumArgs(request.params.size())) {
655
1.10k
        throw HelpResult{ToString()};
656
1.10k
    }
657
198k
    UniValue arg_mismatch{UniValue::VOBJ};
658
590k
    for (size_t i{0}; i < m_args.size(); ++i) {
659
391k
        const auto& arg{m_args.at(i)};
660
391k
        UniValue match{arg.MatchesType(request.params[i])};
661
391k
        if (!match.isTrue()) {
662
31
            arg_mismatch.pushKV(strprintf("Position %s (%s)", i + 1, arg.m_names), std::move(match));
663
31
        }
664
391k
    }
665
198k
    if (!arg_mismatch.empty()) {
666
29
        throw JSONRPCError(RPC_TYPE_ERROR, strprintf("Wrong type passed:\n%s", arg_mismatch.write(4)));
667
29
    }
668
198k
    CHECK_NONFATAL(m_req == nullptr);
669
198k
    m_req = &request;
670
198k
    UniValue ret = m_fun(*this, request);
671
198k
    m_req = nullptr;
672
198k
    if (gArgs.GetBoolArg("-rpcdoccheck", DEFAULT_RPC_DOC_CHECK)) {
673
192k
        UniValue mismatch{UniValue::VARR};
674
203k
        for (const auto& res : m_results.m_results) {
675
203k
            UniValue match{res.MatchesType(ret)};
676
203k
            if (match.isTrue()) {
677
192k
                mismatch.setNull();
678
192k
                break;
679
192k
            }
680
10.5k
            mismatch.push_back(std::move(match));
681
10.5k
        }
682
192k
        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
192k
    }
692
198k
    return ret;
693
198k
}
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
50.1k
{
698
50.1k
    CHECK_NONFATAL(i < params.size());
699
50.1k
    const UniValue& arg{CHECK_NONFATAL(req)->params[i]};
700
50.1k
    const RPCArg& param{params.at(i)};
701
50.1k
    if (check) check(param);
702
703
50.1k
    if (!arg.isNull()) return &arg;
704
23.3k
    if (!std::holds_alternative<RPCArg::Default>(param.m_fallback)) return nullptr;
705
20.8k
    return &std::get<RPCArg::Default>(param.m_fallback);
706
23.3k
}
707
708
static void CheckRequiredOrDefault(const RPCArg& param)
709
45.9k
{
710
    // Must use `Arg<Type>(key)` to get the argument or its default value.
711
45.9k
    const bool required{
712
45.9k
        std::holds_alternative<RPCArg::Optional>(param.m_fallback) && RPCArg::Optional::NO == std::get<RPCArg::Optional>(param.m_fallback),
713
45.9k
    };
714
45.9k
    CHECK_NONFATAL(required || std::holds_alternative<RPCArg::Default>(param.m_fallback));
715
45.9k
}
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
50.1k
    {                                                       \
721
50.1k
        const UniValue* maybe_arg{                          \
722
50.1k
            DetailMaybeArg(check_param, m_args, m_req, i),  \
723
50.1k
        };                                                  \
724
50.1k
        return return_code                                  \
725
50.1k
    }                                                       \
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
803
    {                                                       \
721
803
        const UniValue* maybe_arg{                          \
722
803
            DetailMaybeArg(check_param, m_args, m_req, i),  \
723
803
        };                                                  \
724
1.60k
        return return_code                                  \
725
803
    }                                                       \
std::optional<long> RPCMethod::ArgValue<std::optional<long>>(unsigned long) const
Line
Count
Source
720
105
    {                                                       \
721
105
        const UniValue* maybe_arg{                          \
722
105
            DetailMaybeArg(check_param, m_args, m_req, i),  \
723
105
        };                                                  \
724
210
        return return_code                                  \
725
105
    }                                                       \
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.27k
    {                                                       \
721
1.27k
        const UniValue* maybe_arg{                          \
722
1.27k
            DetailMaybeArg(check_param, m_args, m_req, i),  \
723
1.27k
        };                                                  \
724
2.55k
        return return_code                                  \
725
1.27k
    }                                                       \
UniValue const& RPCMethod::ArgValue<UniValue const&>(unsigned long) const
Line
Count
Source
720
37.6k
    {                                                       \
721
37.6k
        const UniValue* maybe_arg{                          \
722
37.6k
            DetailMaybeArg(check_param, m_args, m_req, i),  \
723
37.6k
        };                                                  \
724
37.6k
        return return_code                                  \
725
37.6k
    }                                                       \
bool RPCMethod::ArgValue<bool>(unsigned long) const
Line
Count
Source
720
893
    {                                                       \
721
893
        const UniValue* maybe_arg{                          \
722
893
            DetailMaybeArg(check_param, m_args, m_req, i),  \
723
893
        };                                                  \
724
893
        return return_code                                  \
725
893
    }                                                       \
int RPCMethod::ArgValue<int>(unsigned long) const
Line
Count
Source
720
1.42k
    {                                                       \
721
1.42k
        const UniValue* maybe_arg{                          \
722
1.42k
            DetailMaybeArg(check_param, m_args, m_req, i),  \
723
1.42k
        };                                                  \
724
1.42k
        return return_code                                  \
725
1.42k
    }                                                       \
unsigned long RPCMethod::ArgValue<unsigned long>(unsigned long) const
Line
Count
Source
720
832
    {                                                       \
721
832
        const UniValue* maybe_arg{                          \
722
832
            DetailMaybeArg(check_param, m_args, m_req, i),  \
723
832
        };                                                  \
724
832
        return return_code                                  \
725
832
    }                                                       \
unsigned int RPCMethod::ArgValue<unsigned int>(unsigned long) const
Line
Count
Source
720
1.01k
    {                                                       \
721
1.01k
        const UniValue* maybe_arg{                          \
722
1.01k
            DetailMaybeArg(check_param, m_args, m_req, i),  \
723
1.01k
        };                                                  \
724
1.01k
        return return_code                                  \
725
1.01k
    }                                                       \
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.16k
    {                                                       \
721
4.16k
        const UniValue* maybe_arg{                          \
722
4.16k
            DetailMaybeArg(check_param, m_args, m_req, i),  \
723
4.16k
        };                                                  \
724
4.16k
        return return_code                                  \
725
4.16k
    }                                                       \
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
198k
{
745
198k
    size_t num_required_args = 0;
746
421k
    for (size_t n = m_args.size(); n > 0; --n) {
747
351k
        if (!m_args.at(n - 1).IsOptional()) {
748
127k
            num_required_args = n;
749
127k
            break;
750
127k
        }
751
351k
    }
752
198k
    return num_required_args <= num_args && num_args <= m_args.size();
753
198k
}
754
755
std::vector<std::pair<std::string, bool>> RPCMethod::GetArgNames() const
756
167k
{
757
167k
    std::vector<std::pair<std::string, bool>> ret;
758
167k
    ret.reserve(m_args.size());
759
305k
    for (const auto& arg : m_args) {
760
305k
        if (arg.m_type == RPCArg::Type::OBJ_NAMED_PARAMS) {
761
49.6k
            for (const auto& inner : arg.m_inner) {
762
49.6k
                ret.emplace_back(inner.m_names, /*named_only=*/true);
763
49.6k
            }
764
9.50k
        }
765
305k
        ret.emplace_back(arg.m_names, /*named_only=*/false);
766
305k
    }
767
167k
    return ret;
768
167k
}
769
770
size_t RPCMethod::GetParamIndex(std::string_view key) const
771
50.1k
{
772
50.1k
    auto it{std::find_if(
773
103k
        m_args.begin(), m_args.end(), [&key](const auto& arg) { return arg.GetName() == key;}
774
50.1k
    )};
775
776
50.1k
    CHECK_NONFATAL(it != m_args.end());  // TODO: ideally this is checked at compile time
777
50.1k
    return std::distance(m_args.begin(), it);
778
50.1k
}
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.95k
    for (const auto& arg : m_args) {
788
1.95k
        if (arg.m_opts.hidden) break; // Any arg that follows is also hidden
789
1.94k
        const bool optional = arg.IsOptional();
790
1.94k
        ret += " ";
791
1.94k
        if (optional) {
792
1.09k
            if (!was_optional) ret += "( ";
793
1.09k
            was_optional = true;
794
1.09k
        } else {
795
853
            if (was_optional) ret += ") ";
796
853
            was_optional = false;
797
853
        }
798
1.94k
        ret += arg.ToString(/*oneline=*/true);
799
1.94k
    }
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.05k
    for (size_t i{0}; i < m_args.size(); ++i) {
810
1.95k
        const auto& arg = m_args.at(i);
811
1.95k
        if (arg.m_opts.hidden) break; // Any arg that follows is also hidden
812
813
        // Push named argument name and description
814
1.94k
        sections.m_sections.emplace_back(util::ToString(i + 1) + ". " + arg.GetFirstName(), arg.ToDescriptionString(/*is_named_arg=*/true));
815
1.94k
        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.94k
        sections.Push(arg);
819
820
        // Push named-only argument sections
821
1.94k
        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.94k
    }
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
350
{
845
350
    UniValue arr{UniValue::VARR};
846
847
906
    auto push_back_arg_info = [&arr](const std::string& rpc_name, int pos, const std::string& arg_name, const RPCArg::Type& type) {
848
906
        UniValue map{UniValue::VARR};
849
906
        map.push_back(rpc_name);
850
906
        map.push_back(pos);
851
906
        map.push_back(arg_name);
852
906
        map.push_back(type == RPCArg::Type::STR ||
853
906
                      type == RPCArg::Type::STR_HEX);
854
906
        arr.push_back(std::move(map));
855
906
    };
856
857
1.04k
    for (int i{0}; i < int(m_args.size()); ++i) {
858
696
        const auto& arg = m_args.at(i);
859
696
        std::vector<std::string> arg_names = SplitString(arg.m_names, '|');
860
700
        for (const auto& arg_name : arg_names) {
861
700
            push_back_arg_info(m_name, i, arg_name, arg.m_type);
862
700
            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
700
        }
871
696
    }
872
350
    return arr;
873
350
}
874
875
static std::optional<UniValue::VType> ExpectedType(RPCArg::Type type)
876
203k
{
877
203k
    using Type = RPCArg::Type;
878
203k
    switch (type) {
879
72.8k
    case Type::STR_HEX:
880
124k
    case Type::STR: {
881
124k
        return UniValue::VSTR;
882
72.8k
    }
883
46.6k
    case Type::NUM: {
884
46.6k
        return UniValue::VNUM;
885
72.8k
    }
886
21.5k
    case Type::AMOUNT: {
887
        // VNUM or VSTR, checked inside AmountFromValue()
888
21.5k
        return std::nullopt;
889
72.8k
    }
890
80
    case Type::RANGE: {
891
        // VNUM or VARR, checked inside ParseRange()
892
80
        return std::nullopt;
893
72.8k
    }
894
3.61k
    case Type::BOOL: {
895
3.61k
        return UniValue::VBOOL;
896
72.8k
    }
897
599
    case Type::OBJ:
898
1.52k
    case Type::OBJ_NAMED_PARAMS:
899
1.60k
    case Type::OBJ_USER_KEYS: {
900
1.60k
        return UniValue::VOBJ;
901
1.52k
    }
902
5.72k
    case Type::ARR: {
903
5.72k
        return UniValue::VARR;
904
1.52k
    }
905
203k
    } // no default case, so the compiler can warn about missing cases
906
203k
    NONFATAL_UNREACHABLE();
907
203k
}
908
909
UniValue RPCArg::MatchesType(const UniValue& request) const
910
391k
{
911
391k
    if (m_opts.skip_type_check) return true;
912
382k
    if (IsOptional() && request.isNull()) return true;
913
203k
    const auto exp_type{ExpectedType(m_type)};
914
203k
    if (!exp_type) return true; // nothing to check
915
916
181k
    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
181k
    return true;
920
181k
}
921
922
std::string RPCArg::GetFirstName() const
923
5.83k
{
924
5.83k
    return m_names.substr(0, m_names.find('|'));
925
5.83k
}
926
927
std::string RPCArg::GetName() const
928
103k
{
929
103k
    CHECK_NONFATAL(std::string::npos == m_names.find('|'));
930
103k
    return m_names;
931
103k
}
932
933
bool RPCArg::IsOptional() const
934
735k
{
935
735k
    if (m_fallback.index() != 0) {
936
409k
        return true;
937
409k
    } else {
938
326k
        return RPCArg::Optional::NO != std::get<RPCArg::Optional>(m_fallback);
939
326k
    }
940
735k
}
941
942
std::string RPCArg::ToDescriptionString(bool is_named_arg) const
943
3.24k
{
944
3.24k
    std::string ret;
945
3.24k
    ret += "(";
946
3.24k
    if (m_opts.type_str.size() != 0) {
947
32
        ret += m_opts.type_str.at(1);
948
3.20k
    } else {
949
3.20k
        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
572
        case Type::NUM: {
956
572
            ret += "numeric";
957
572
            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
481
        case Type::BOOL: {
968
481
            ret += "boolean";
969
481
            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.20k
        } // no default case, so the compiler can warn about missing cases
982
3.20k
    }
983
3.24k
    if (m_fallback.index() == 1) {
984
419
        ret += ", optional, default=" + std::get<RPCArg::DefaultHint>(m_fallback);
985
2.82k
    } else if (m_fallback.index() == 2) {
986
893
        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.24k
    ret += ")";
1001
3.24k
    if (m_type == Type::OBJ_NAMED_PARAMS) ret += " Options object that can be used to pass named arguments, listed below.";
1002
3.24k
    ret += m_description.empty() ? "" : " " + m_description;
1003
3.24k
    return ret;
1004
3.24k
}
1005
1006
// NOLINTNEXTLINE(misc-no-recursion)
1007
void RPCResult::ToSections(Sections& sections, const OuterType outer_type, const int current_indent) const
1008
13.1k
{
1009
    // Indentation
1010
13.1k
    const std::string indent(current_indent, ' ');
1011
13.1k
    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.1k
    const std::string maybe_separator{outer_type != OuterType::NONE ? "," : ""};
1015
1016
    // The key name if recursed into a dictionary
1017
13.1k
    const std::string maybe_key{
1018
13.1k
        outer_type == OuterType::OBJ ?
1019
10.5k
            "\"" + this->m_key_name + "\" : " :
1020
13.1k
            ""};
1021
1022
    // Format description with type
1023
13.1k
    const auto Description = [&](const std::string& type) {
1024
12.0k
        return "(" + type + (this->m_optional ? ", optional" : "") + ")" +
1025
12.0k
               (this->m_description.empty() ? "" : " " + this->m_description);
1026
12.0k
    };
1027
1028
    // Ensure at least one visible field exists when elision is used
1029
13.1k
    const auto elision_has_description{[](const std::vector<RPCResult>& inner) {
1030
3.06k
        return std::ranges::any_of(inner, [](const auto& res) {
1031
3.06k
            return !std::holds_alternative<HelpElisionSkip>(res.m_opts.print_elision);
1032
3.06k
        });
1033
3.00k
    }};
1034
1035
13.1k
    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.0k
    if (std::holds_alternative<HelpElisionSkip>(m_opts.print_elision)) {
1040
1.00k
        return;
1041
1.00k
    }
1042
1043
12.0k
    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.09k
    case Type::STR: {
1053
2.09k
        sections.PushSection({indent + maybe_key + "\"str\"" + maybe_separator, Description("string")});
1054
2.09k
        return;
1055
0
    }
1056
595
    case Type::STR_AMOUNT: {
1057
595
        sections.PushSection({indent + maybe_key + "n" + maybe_separator, Description("numeric")});
1058
595
        return;
1059
0
    }
1060
1.94k
    case Type::STR_HEX: {
1061
1.94k
        sections.PushSection({indent + maybe_key + "\"hex\"" + maybe_separator, Description("string")});
1062
1.94k
        return;
1063
0
    }
1064
3.10k
    case Type::NUM: {
1065
3.10k
        sections.PushSection({indent + maybe_key + "n" + maybe_separator, Description("numeric")});
1066
3.10k
        return;
1067
0
    }
1068
357
    case Type::NUM_TIME: {
1069
357
        sections.PushSection({indent + maybe_key + "xxx" + maybe_separator, Description("numeric")});
1070
357
        return;
1071
0
    }
1072
728
    case Type::BOOL: {
1073
728
        sections.PushSection({indent + maybe_key + "true|false" + maybe_separator, Description("boolean")});
1074
728
        return;
1075
0
    }
1076
17
    case Type::ARR_FIXED:
1077
1.13k
    case Type::ARR: {
1078
1.13k
        sections.PushSection({indent + maybe_key + "[", Description("json array")});
1079
1.20k
        for (const auto& i : m_inner) {
1080
1.20k
            i.ToSections(sections, OuterType::ARR, current_indent + 2);
1081
1.20k
        }
1082
1.13k
        CHECK_NONFATAL(!m_inner.empty());
1083
1.13k
        CHECK_NONFATAL(elision_has_description(m_inner));
1084
1.13k
        if (m_type == Type::ARR && !std::holds_alternative<std::string>(m_inner.back().m_opts.print_elision)) {
1085
1.11k
            sections.PushSection({indent_next + "...", ""});
1086
1.11k
        } else {
1087
            // Remove final comma, which would be invalid JSON
1088
20
            sections.m_sections.back().m_left.pop_back();
1089
20
        }
1090
1.13k
        sections.PushSection({indent + "]" + maybe_separator, ""});
1091
1.13k
        return;
1092
17
    }
1093
213
    case Type::OBJ_DYN:
1094
1.88k
    case Type::OBJ: {
1095
1.88k
        if (m_inner.empty()) {
1096
18
            sections.PushSection({indent + maybe_key + "{}", Description("empty JSON object")});
1097
18
            return;
1098
18
        }
1099
1.86k
        CHECK_NONFATAL(elision_has_description(m_inner));
1100
1.86k
        sections.PushSection({indent + maybe_key + "{", Description("json object")});
1101
10.5k
        for (const auto& i : m_inner) {
1102
10.5k
            i.ToSections(sections, OuterType::OBJ, current_indent + 2);
1103
10.5k
        }
1104
1.86k
        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.65k
        } else {
1108
            // Remove final comma, which would be invalid JSON
1109
1.65k
            sections.m_sections.back().m_left.pop_back();
1110
1.65k
        }
1111
1.86k
        sections.PushSection({indent + "}" + maybe_separator, ""});
1112
1.86k
        return;
1113
1.88k
    }
1114
12.0k
    } // no default case, so the compiler can warn about missing cases
1115
12.0k
    NONFATAL_UNREACHABLE();
1116
12.0k
}
1117
1118
static std::optional<UniValue::VType> ExpectedType(RPCResult::Type type)
1119
5.30M
{
1120
5.30M
    using Type = RPCResult::Type;
1121
5.30M
    switch (type) {
1122
126
    case Type::ANY: {
1123
126
        return std::nullopt;
1124
0
    }
1125
16.0k
    case Type::NONE: {
1126
16.0k
        return UniValue::VNULL;
1127
0
    }
1128
608k
    case Type::STR:
1129
2.10M
    case Type::STR_HEX: {
1130
2.10M
        return UniValue::VSTR;
1131
608k
    }
1132
1.50M
    case Type::NUM:
1133
1.81M
    case Type::STR_AMOUNT:
1134
2.02M
    case Type::NUM_TIME: {
1135
2.02M
        return UniValue::VNUM;
1136
1.81M
    }
1137
382k
    case Type::BOOL: {
1138
382k
        return UniValue::VBOOL;
1139
1.81M
    }
1140
1.63k
    case Type::ARR_FIXED:
1141
254k
    case Type::ARR: {
1142
254k
        return UniValue::VARR;
1143
1.63k
    }
1144
30.9k
    case Type::OBJ_DYN:
1145
514k
    case Type::OBJ: {
1146
514k
        return UniValue::VOBJ;
1147
30.9k
    }
1148
5.30M
    } // no default case, so the compiler can warn about missing cases
1149
5.30M
    NONFATAL_UNREACHABLE();
1150
5.30M
}
1151
1152
// NOLINTNEXTLINE(misc-no-recursion)
1153
UniValue RPCResult::MatchesType(const UniValue& result) const
1154
5.30M
{
1155
5.30M
    if (m_opts.skip_type_check) {
1156
467
        return true;
1157
467
    }
1158
1159
5.30M
    const auto exp_type = ExpectedType(m_type);
1160
5.30M
    if (!exp_type) return true; // can be any type, so nothing to check
1161
1162
5.30M
    if (*exp_type != result.getType()) {
1163
10.5k
        return strprintf("returned type is %s, but declared as %s in doc", uvTypeName(result.getType()), uvTypeName(*exp_type));
1164
10.5k
    }
1165
1166
5.29M
    if (UniValue::VARR == result.getType()) {
1167
252k
        UniValue errors(UniValue::VOBJ);
1168
1.25M
        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.00M
            const RPCResult& doc_inner{m_inner.at(std::min(m_inner.size() - 1, i))};
1171
1.00M
            UniValue match{doc_inner.MatchesType(result.get_array()[i])};
1172
1.00M
            if (!match.isTrue()) errors.pushKV(strprintf("%d", i), std::move(match));
1173
1.00M
        }
1174
252k
        if (errors.empty()) return true; // empty result array is valid
1175
406
        return errors;
1176
252k
    }
1177
1178
5.04M
    if (UniValue::VOBJ == result.getType()) {
1179
514k
        UniValue errors(UniValue::VOBJ);
1180
514k
        if (m_type == Type::OBJ_DYN) {
1181
30.9k
            const RPCResult& doc_inner{m_inner.at(0)}; // Assume all types are the same, randomly pick the first
1182
322k
            for (size_t i{0}; i < result.get_obj().size(); ++i) {
1183
291k
                UniValue match{doc_inner.MatchesType(result.get_obj()[i])};
1184
291k
                if (!match.isTrue()) errors.pushKV(result.getKeys()[i], std::move(match));
1185
291k
            }
1186
30.9k
            if (errors.empty()) return true; // empty result obj is valid
1187
5
            return errors;
1188
30.9k
        }
1189
483k
        std::set<std::string> doc_keys;
1190
4.12M
        for (const auto& doc_entry : m_inner) {
1191
4.12M
            doc_keys.insert(doc_entry.m_key_name);
1192
4.12M
        }
1193
483k
        std::map<std::string, UniValue> result_obj;
1194
483k
        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
31
                errors.pushKV(result_entry.first, "key returned that was not in doc");
1198
31
            }
1199
3.80M
        }
1200
1201
4.12M
        for (const auto& doc_entry : m_inner) {
1202
4.12M
            const auto result_it{result_obj.find(doc_entry.m_key_name)};
1203
4.12M
            if (result_it == result_obj.end()) {
1204
315k
                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
315k
                continue;
1208
315k
            }
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
483k
        if (errors.empty()) return true;
1213
389
        return errors;
1214
483k
    }
1215
1216
4.52M
    return true;
1217
5.04M
}
1218
1219
void RPCResult::CheckInnerDoc() const
1220
6.48M
{
1221
6.48M
    if (m_type == Type::OBJ) {
1222
        // May or may not be empty
1223
776k
        return;
1224
776k
    }
1225
    // Everything else must either be empty or not
1226
5.70M
    const bool inner_needed{m_type == Type::ARR || m_type == Type::ARR_FIXED || m_type == Type::OBJ_DYN};
1227
5.70M
    CHECK_NONFATAL(inner_needed != m_inner.empty());
1228
5.70M
}
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.40k
    switch (m_type) {
1283
408
    case Type::STR_HEX:
1284
1.22k
    case Type::STR: {
1285
1.22k
        return "\"" + GetFirstName() + "\"";
1286
408
    }
1287
398
    case Type::NUM:
1288
407
    case Type::RANGE:
1289
469
    case Type::AMOUNT:
1290
788
    case Type::BOOL: {
1291
788
        return GetFirstName();
1292
469
    }
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.40k
    } // no default case, so the compiler can warn about missing cases
1312
2.40k
    NONFATAL_UNREACHABLE();
1313
2.40k
}
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.53k
        range.first = 0;
1363
1.53k
        range.second = 0;
1364
1.53k
    }
1365
1.64k
    std::vector<CScript> ret;
1366
23.3k
    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
14
{
1393
14
    CHECK_NONFATAL(!bilingual_strings.empty());
1394
14
    UniValue result{UniValue::VARR};
1395
14
    for (const auto& s : bilingual_strings) {
1396
14
        result.push_back(s.original);
1397
14
    }
1398
14
    return result;
1399
14
}
1400
1401
void PushWarnings(const UniValue& warnings, UniValue& obj)
1402
840
{
1403
840
    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.17k
{
1409
1.17k
    if (warnings.empty()) return;
1410
14
    obj.pushKV("warnings", BilingualStringsToUniValue(warnings));
1411
14
}
1412
1413
53.1k
std::vector<RPCResult> ScriptPubKeyDoc() {
1414
53.1k
    return
1415
53.1k
         {
1416
53.1k
             {RPCResult::Type::STR, "asm", "Disassembly of the output script"},
1417
53.1k
             {RPCResult::Type::STR, "desc", "Inferred descriptor for the output"},
1418
53.1k
             {RPCResult::Type::STR_HEX, "hex", "The raw output script bytes, hex-encoded"},
1419
53.1k
             {RPCResult::Type::STR, "address", /*optional=*/true, "The Bitcoin address (only if a well-defined address exists)"},
1420
53.1k
             {RPCResult::Type::STR, "type", "The type (one of: " + GetAllOutputTypes() + ")"},
1421
53.1k
         };
1422
53.1k
}
1423
1424
uint256 GetTarget(const CBlockIndex& blockindex, const uint256 pow_limit)
1425
20.4k
{
1426
20.4k
    arith_uint256 target{*CHECK_NONFATAL(DeriveTarget(blockindex.nBits, pow_limit))};
1427
20.4k
    return ArithToUint256(target);
1428
20.4k
}
1429
1430
std::vector<RPCResult> ElideGroup(std::vector<RPCResult> fields, std::string summary)
1431
33.4k
{
1432
33.4k
    if (fields.empty()) return fields;
1433
33.4k
    std::vector<RPCResult> result;
1434
33.4k
    result.reserve(fields.size());
1435
261k
    for (size_t i = 0; i < fields.size(); ++i) {
1436
228k
        RPCResultOptions opts = fields[i].m_opts;
1437
228k
        if (i == 0) {
1438
33.4k
            opts.print_elision = summary;
1439
194k
        } else {
1440
194k
            opts.print_elision = HelpElisionSkip{};
1441
194k
        }
1442
228k
        result.emplace_back(fields[i], std::move(opts));
1443
228k
    }
1444
33.4k
    return result;
1445
33.4k
}