LCOV - code coverage report
Current view: top level - src/rpc - util.cpp (source / functions) Hit Total Coverage
Test: coverage.lcov Lines: 699 790 88.5 %
Date: 2021-06-29 14:35:33 Functions: 52 55 94.5 %
Legend: Modified by patch:
Lines: hit not hit | Branches: + taken - not taken # not executed

Not modified by patch:
Lines: hit not hit | Branches: + taken - not taken # not executed
Branches: 406 468 86.8 %

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

Generated by: LCOV version 1.14