LCOV - code coverage report
Current view: top level - src/rpc - client.cpp (source / functions) Hit Total Coverage
Test: fuzz_coverage.info Lines: 278 315 88.3 %
Date: 2023-09-26 12:08:55 Functions: 6 11 54.5 %

          Line data    Source code
       1             : // Copyright (c) 2010 Satoshi Nakamoto
       2             : // Copyright (c) 2009-2022 The Bitcoin Core developers
       3             : // Distributed under the MIT software license, see the accompanying
       4             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       5             : 
       6             : #include <common/args.h>
       7             : #include <rpc/client.h>
       8             : #include <tinyformat.h>
       9             : 
      10             : #include <set>
      11             : #include <stdint.h>
      12             : #include <string>
      13             : #include <string_view>
      14             : 
      15             : class CRPCConvertParam
      16             : {
      17             : public:
      18             :     std::string methodName; //!< method whose params want conversion
      19             :     int paramIdx;           //!< 0-based idx of param to convert
      20             :     std::string paramName;  //!< parameter name
      21             : };
      22             : 
      23             : // clang-format off
      24             : /**
      25             :  * Specify a (method, idx, name) here if the argument is a non-string RPC
      26             :  * argument and needs to be converted from JSON.
      27             :  *
      28             :  * @note Parameter indexes start from 0.
      29             :  */
      30           0 : static const CRPCConvertParam vRPCConvertParams[] =
      31         544 : {
      32           2 :     { "setmocktime", 0, "timestamp" },
      33           2 :     { "mockscheduler", 0, "delta_time" },
      34           2 :     { "utxoupdatepsbt", 1, "descriptors" },
      35           2 :     { "generatetoaddress", 0, "nblocks" },
      36           2 :     { "generatetoaddress", 2, "maxtries" },
      37           2 :     { "generatetodescriptor", 0, "num_blocks" },
      38           2 :     { "generatetodescriptor", 2, "maxtries" },
      39           2 :     { "generateblock", 1, "transactions" },
      40           2 :     { "generateblock", 2, "submit" },
      41           2 :     { "getnetworkhashps", 0, "nblocks" },
      42           2 :     { "getnetworkhashps", 1, "height" },
      43           2 :     { "sendtoaddress", 1, "amount" },
      44           2 :     { "sendtoaddress", 4, "subtractfeefromamount" },
      45           2 :     { "sendtoaddress", 5 , "replaceable" },
      46           2 :     { "sendtoaddress", 6 , "conf_target" },
      47           2 :     { "sendtoaddress", 8, "avoid_reuse" },
      48           2 :     { "sendtoaddress", 9, "fee_rate"},
      49           2 :     { "sendtoaddress", 10, "verbose"},
      50           2 :     { "settxfee", 0, "amount" },
      51           2 :     { "sethdseed", 0, "newkeypool" },
      52           2 :     { "getreceivedbyaddress", 1, "minconf" },
      53           2 :     { "getreceivedbyaddress", 2, "include_immature_coinbase" },
      54           2 :     { "getreceivedbylabel", 1, "minconf" },
      55           2 :     { "getreceivedbylabel", 2, "include_immature_coinbase" },
      56           2 :     { "listreceivedbyaddress", 0, "minconf" },
      57           2 :     { "listreceivedbyaddress", 1, "include_empty" },
      58           2 :     { "listreceivedbyaddress", 2, "include_watchonly" },
      59           2 :     { "listreceivedbyaddress", 4, "include_immature_coinbase" },
      60           2 :     { "listreceivedbylabel", 0, "minconf" },
      61           2 :     { "listreceivedbylabel", 1, "include_empty" },
      62           2 :     { "listreceivedbylabel", 2, "include_watchonly" },
      63           2 :     { "listreceivedbylabel", 3, "include_immature_coinbase" },
      64           2 :     { "getbalance", 1, "minconf" },
      65           2 :     { "getbalance", 2, "include_watchonly" },
      66           2 :     { "getbalance", 3, "avoid_reuse" },
      67           2 :     { "getblockfrompeer", 1, "peer_id" },
      68           2 :     { "getblockhash", 0, "height" },
      69           2 :     { "waitforblockheight", 0, "height" },
      70           2 :     { "waitforblockheight", 1, "timeout" },
      71           2 :     { "waitforblock", 1, "timeout" },
      72           2 :     { "waitfornewblock", 0, "timeout" },
      73           2 :     { "listtransactions", 1, "count" },
      74           4 :     { "listtransactions", 2, "skip" },
      75           2 :     { "listtransactions", 3, "include_watchonly" },
      76           2 :     { "walletpassphrase", 1, "timeout" },
      77           2 :     { "getblocktemplate", 0, "template_request" },
      78           2 :     { "listsinceblock", 1, "target_confirmations" },
      79           2 :     { "listsinceblock", 2, "include_watchonly" },
      80           2 :     { "listsinceblock", 3, "include_removed" },
      81           2 :     { "listsinceblock", 4, "include_change" },
      82           2 :     { "sendmany", 1, "amounts" },
      83           2 :     { "sendmany", 2, "minconf" },
      84           2 :     { "sendmany", 4, "subtractfeefrom" },
      85           2 :     { "sendmany", 5 , "replaceable" },
      86           2 :     { "sendmany", 6 , "conf_target" },
      87           2 :     { "sendmany", 8, "fee_rate"},
      88           2 :     { "sendmany", 9, "verbose" },
      89           2 :     { "deriveaddresses", 1, "range" },
      90           2 :     { "scanblocks", 1, "scanobjects" },
      91           2 :     { "scanblocks", 2, "start_height" },
      92           2 :     { "scanblocks", 3, "stop_height" },
      93           2 :     { "scanblocks", 5, "options" },
      94           2 :     { "scantxoutset", 1, "scanobjects" },
      95           2 :     { "addmultisigaddress", 0, "nrequired" },
      96           2 :     { "addmultisigaddress", 1, "keys" },
      97           2 :     { "createmultisig", 0, "nrequired" },
      98           2 :     { "createmultisig", 1, "keys" },
      99           2 :     { "listunspent", 0, "minconf" },
     100           2 :     { "listunspent", 1, "maxconf" },
     101           2 :     { "listunspent", 2, "addresses" },
     102           2 :     { "listunspent", 3, "include_unsafe" },
     103           2 :     { "listunspent", 4, "query_options" },
     104           2 :     { "listunspent", 4, "minimumAmount" },
     105           2 :     { "listunspent", 4, "maximumAmount" },
     106           2 :     { "listunspent", 4, "maximumCount" },
     107           2 :     { "listunspent", 4, "minimumSumAmount" },
     108           2 :     { "listunspent", 4, "include_immature_coinbase" },
     109           2 :     { "getblock", 1, "verbosity" },
     110           2 :     { "getblock", 1, "verbose" },
     111           2 :     { "getblockheader", 1, "verbose" },
     112           2 :     { "getchaintxstats", 0, "nblocks" },
     113           2 :     { "gettransaction", 1, "include_watchonly" },
     114           2 :     { "gettransaction", 2, "verbose" },
     115           2 :     { "getrawtransaction", 1, "verbosity" },
     116           2 :     { "getrawtransaction", 1, "verbose" },
     117           2 :     { "createrawtransaction", 0, "inputs" },
     118           2 :     { "createrawtransaction", 1, "outputs" },
     119           2 :     { "createrawtransaction", 2, "locktime" },
     120           2 :     { "createrawtransaction", 3, "replaceable" },
     121           2 :     { "decoderawtransaction", 1, "iswitness" },
     122           2 :     { "signrawtransactionwithkey", 1, "privkeys" },
     123           2 :     { "signrawtransactionwithkey", 2, "prevtxs" },
     124           2 :     { "signrawtransactionwithwallet", 1, "prevtxs" },
     125           2 :     { "sendrawtransaction", 1, "maxfeerate" },
     126           2 :     { "sendrawtransaction", 2, "maxburnamount" },
     127           2 :     { "testmempoolaccept", 0, "rawtxs" },
     128           2 :     { "testmempoolaccept", 1, "maxfeerate" },
     129           2 :     { "submitpackage", 0, "package" },
     130           2 :     { "combinerawtransaction", 0, "txs" },
     131           2 :     { "fundrawtransaction", 1, "options" },
     132           2 :     { "fundrawtransaction", 1, "add_inputs"},
     133           2 :     { "fundrawtransaction", 1, "include_unsafe"},
     134           2 :     { "fundrawtransaction", 1, "minconf"},
     135           2 :     { "fundrawtransaction", 1, "maxconf"},
     136           2 :     { "fundrawtransaction", 1, "changePosition"},
     137           2 :     { "fundrawtransaction", 1, "includeWatching"},
     138           2 :     { "fundrawtransaction", 1, "lockUnspents"},
     139           2 :     { "fundrawtransaction", 1, "fee_rate"},
     140           2 :     { "fundrawtransaction", 1, "feeRate"},
     141           2 :     { "fundrawtransaction", 1, "subtractFeeFromOutputs"},
     142           2 :     { "fundrawtransaction", 1, "input_weights"},
     143           2 :     { "fundrawtransaction", 1, "conf_target"},
     144           2 :     { "fundrawtransaction", 1, "replaceable"},
     145           2 :     { "fundrawtransaction", 1, "solving_data"},
     146           2 :     { "fundrawtransaction", 2, "iswitness" },
     147           2 :     { "walletcreatefundedpsbt", 0, "inputs" },
     148           2 :     { "walletcreatefundedpsbt", 1, "outputs" },
     149           2 :     { "walletcreatefundedpsbt", 2, "locktime" },
     150           2 :     { "walletcreatefundedpsbt", 3, "options" },
     151           2 :     { "walletcreatefundedpsbt", 3, "add_inputs"},
     152           2 :     { "walletcreatefundedpsbt", 3, "include_unsafe"},
     153           2 :     { "walletcreatefundedpsbt", 3, "minconf"},
     154           2 :     { "walletcreatefundedpsbt", 3, "maxconf"},
     155           2 :     { "walletcreatefundedpsbt", 3, "changePosition"},
     156           2 :     { "walletcreatefundedpsbt", 3, "includeWatching"},
     157           2 :     { "walletcreatefundedpsbt", 3, "lockUnspents"},
     158           2 :     { "walletcreatefundedpsbt", 3, "fee_rate"},
     159           2 :     { "walletcreatefundedpsbt", 3, "feeRate"},
     160           2 :     { "walletcreatefundedpsbt", 3, "subtractFeeFromOutputs"},
     161           2 :     { "walletcreatefundedpsbt", 3, "conf_target"},
     162           2 :     { "walletcreatefundedpsbt", 3, "replaceable"},
     163           2 :     { "walletcreatefundedpsbt", 3, "solving_data"},
     164           2 :     { "walletcreatefundedpsbt", 4, "bip32derivs" },
     165           2 :     { "walletprocesspsbt", 1, "sign" },
     166           2 :     { "walletprocesspsbt", 3, "bip32derivs" },
     167           2 :     { "walletprocesspsbt", 4, "finalize" },
     168           2 :     { "descriptorprocesspsbt", 1, "descriptors"},
     169           2 :     { "descriptorprocesspsbt", 3, "bip32derivs" },
     170           2 :     { "descriptorprocesspsbt", 4, "finalize" },
     171           2 :     { "createpsbt", 0, "inputs" },
     172           2 :     { "createpsbt", 1, "outputs" },
     173           2 :     { "createpsbt", 2, "locktime" },
     174           2 :     { "createpsbt", 3, "replaceable" },
     175           2 :     { "combinepsbt", 0, "txs"},
     176           2 :     { "joinpsbts", 0, "txs"},
     177           2 :     { "finalizepsbt", 1, "extract"},
     178           2 :     { "converttopsbt", 1, "permitsigdata"},
     179           2 :     { "converttopsbt", 2, "iswitness"},
     180           2 :     { "gettxout", 1, "n" },
     181           2 :     { "gettxout", 2, "include_mempool" },
     182           2 :     { "gettxoutproof", 0, "txids" },
     183           2 :     { "gettxoutsetinfo", 1, "hash_or_height" },
     184           2 :     { "gettxoutsetinfo", 2, "use_index"},
     185           2 :     { "lockunspent", 0, "unlock" },
     186           2 :     { "lockunspent", 1, "transactions" },
     187           2 :     { "lockunspent", 2, "persistent" },
     188           2 :     { "send", 0, "outputs" },
     189           2 :     { "send", 1, "conf_target" },
     190           2 :     { "send", 3, "fee_rate"},
     191           2 :     { "send", 4, "options" },
     192           2 :     { "send", 4, "add_inputs"},
     193           2 :     { "send", 4, "include_unsafe"},
     194           2 :     { "send", 4, "minconf"},
     195           2 :     { "send", 4, "maxconf"},
     196           2 :     { "send", 4, "add_to_wallet"},
     197           2 :     { "send", 4, "change_position"},
     198           2 :     { "send", 4, "fee_rate"},
     199           2 :     { "send", 4, "include_watching"},
     200           2 :     { "send", 4, "inputs"},
     201           2 :     { "send", 4, "locktime"},
     202           2 :     { "send", 4, "lock_unspents"},
     203           2 :     { "send", 4, "psbt"},
     204           2 :     { "send", 4, "subtract_fee_from_outputs"},
     205           2 :     { "send", 4, "conf_target"},
     206           2 :     { "send", 4, "replaceable"},
     207           2 :     { "send", 4, "solving_data"},
     208           2 :     { "sendall", 0, "recipients" },
     209           2 :     { "sendall", 1, "conf_target" },
     210           2 :     { "sendall", 3, "fee_rate"},
     211           2 :     { "sendall", 4, "options" },
     212           2 :     { "sendall", 4, "add_to_wallet"},
     213           2 :     { "sendall", 4, "fee_rate"},
     214           2 :     { "sendall", 4, "include_watching"},
     215           2 :     { "sendall", 4, "inputs"},
     216           2 :     { "sendall", 4, "locktime"},
     217           2 :     { "sendall", 4, "lock_unspents"},
     218           2 :     { "sendall", 4, "psbt"},
     219           2 :     { "sendall", 4, "send_max"},
     220           2 :     { "sendall", 4, "minconf"},
     221           2 :     { "sendall", 4, "maxconf"},
     222           2 :     { "sendall", 4, "conf_target"},
     223           2 :     { "sendall", 4, "replaceable"},
     224           2 :     { "sendall", 4, "solving_data"},
     225           2 :     { "simulaterawtransaction", 0, "rawtxs" },
     226           2 :     { "simulaterawtransaction", 1, "options" },
     227           2 :     { "simulaterawtransaction", 1, "include_watchonly"},
     228           2 :     { "importprivkey", 2, "rescan" },
     229           2 :     { "importaddress", 2, "rescan" },
     230           2 :     { "importaddress", 3, "p2sh" },
     231           2 :     { "importpubkey", 2, "rescan" },
     232           2 :     { "importmempool", 1, "options" },
     233           2 :     { "importmempool", 1, "apply_fee_delta_priority" },
     234           2 :     { "importmempool", 1, "use_current_time" },
     235           2 :     { "importmempool", 1, "apply_unbroadcast_set" },
     236           2 :     { "importmulti", 0, "requests" },
     237           2 :     { "importmulti", 1, "options" },
     238           2 :     { "importmulti", 1, "rescan" },
     239           2 :     { "importdescriptors", 0, "requests" },
     240           2 :     { "listdescriptors", 0, "private" },
     241           2 :     { "verifychain", 0, "checklevel" },
     242           2 :     { "verifychain", 1, "nblocks" },
     243           2 :     { "getblockstats", 0, "hash_or_height" },
     244           2 :     { "getblockstats", 1, "stats" },
     245           2 :     { "pruneblockchain", 0, "height" },
     246           2 :     { "keypoolrefill", 0, "newsize" },
     247           2 :     { "getrawmempool", 0, "verbose" },
     248           2 :     { "getrawmempool", 1, "mempool_sequence" },
     249           2 :     { "estimatesmartfee", 0, "conf_target" },
     250           2 :     { "estimaterawfee", 0, "conf_target" },
     251           2 :     { "estimaterawfee", 1, "threshold" },
     252           2 :     { "prioritisetransaction", 1, "dummy" },
     253           2 :     { "prioritisetransaction", 2, "fee_delta" },
     254           2 :     { "setban", 2, "bantime" },
     255           2 :     { "setban", 3, "absolute" },
     256           2 :     { "setnetworkactive", 0, "state" },
     257           2 :     { "setwalletflag", 1, "value" },
     258           2 :     { "getmempoolancestors", 1, "verbose" },
     259           2 :     { "getmempooldescendants", 1, "verbose" },
     260           2 :     { "gettxspendingprevout", 0, "outputs" },
     261           2 :     { "bumpfee", 1, "options" },
     262           2 :     { "bumpfee", 1, "conf_target"},
     263           2 :     { "bumpfee", 1, "fee_rate"},
     264           2 :     { "bumpfee", 1, "replaceable"},
     265           2 :     { "bumpfee", 1, "outputs"},
     266           2 :     { "bumpfee", 1, "reduce_output"},
     267           2 :     { "psbtbumpfee", 1, "options" },
     268           2 :     { "psbtbumpfee", 1, "conf_target"},
     269           2 :     { "psbtbumpfee", 1, "fee_rate"},
     270           2 :     { "psbtbumpfee", 1, "replaceable"},
     271           2 :     { "psbtbumpfee", 1, "outputs"},
     272           2 :     { "psbtbumpfee", 1, "reduce_output"},
     273           2 :     { "logging", 0, "include" },
     274           2 :     { "logging", 1, "exclude" },
     275           2 :     { "disconnectnode", 1, "nodeid" },
     276           2 :     { "upgradewallet", 0, "version" },
     277             :     // Echo with conversion (For testing only)
     278           2 :     { "echojson", 0, "arg0" },
     279           2 :     { "echojson", 1, "arg1" },
     280           2 :     { "echojson", 2, "arg2" },
     281           2 :     { "echojson", 3, "arg3" },
     282           2 :     { "echojson", 4, "arg4" },
     283           2 :     { "echojson", 5, "arg5" },
     284           2 :     { "echojson", 6, "arg6" },
     285           2 :     { "echojson", 7, "arg7" },
     286           2 :     { "echojson", 8, "arg8" },
     287           2 :     { "echojson", 9, "arg9" },
     288           2 :     { "rescanblockchain", 0, "start_height"},
     289           2 :     { "rescanblockchain", 1, "stop_height"},
     290           2 :     { "createwallet", 1, "disable_private_keys"},
     291           2 :     { "createwallet", 2, "blank"},
     292           2 :     { "createwallet", 4, "avoid_reuse"},
     293           2 :     { "createwallet", 5, "descriptors"},
     294           2 :     { "createwallet", 6, "load_on_startup"},
     295           2 :     { "createwallet", 7, "external_signer"},
     296           2 :     { "restorewallet", 2, "load_on_startup"},
     297           2 :     { "loadwallet", 1, "load_on_startup"},
     298           2 :     { "unloadwallet", 1, "load_on_startup"},
     299           2 :     { "getnodeaddresses", 0, "count"},
     300           2 :     { "addpeeraddress", 1, "port"},
     301           2 :     { "addpeeraddress", 2, "tried"},
     302           2 :     { "sendmsgtopeer", 0, "peer_id" },
     303           2 :     { "stop", 0, "wait" },
     304             : };
     305             : // clang-format on
     306             : 
     307             : /** Parse string to UniValue or throw runtime_error if string contains invalid JSON */
     308           0 : static UniValue Parse(std::string_view raw)
     309             : {
     310           0 :     UniValue parsed;
     311           0 :     if (!parsed.read(raw)) throw std::runtime_error(tfm::format("Error parsing JSON: %s", raw));
     312           0 :     return parsed;
     313           0 : }
     314             : 
     315             : class CRPCConvertTable
     316             : {
     317             : private:
     318             :     std::set<std::pair<std::string, int>> members;
     319             :     std::set<std::pair<std::string, std::string>> membersByName;
     320             : 
     321             : public:
     322             :     CRPCConvertTable();
     323             : 
     324             :     /** Return arg_value as UniValue, and first parse it if it is a non-string parameter */
     325           0 :     UniValue ArgToUniValue(std::string_view arg_value, const std::string& method, int param_idx)
     326             :     {
     327           0 :         return members.count({method, param_idx}) > 0 ? Parse(arg_value) : arg_value;
     328           0 :     }
     329             : 
     330             :     /** Return arg_value as UniValue, and first parse it if it is a non-string parameter */
     331           0 :     UniValue ArgToUniValue(std::string_view arg_value, const std::string& method, const std::string& param_name)
     332             :     {
     333           0 :         return membersByName.count({method, param_name}) > 0 ? Parse(arg_value) : arg_value;
     334           0 :     }
     335             : };
     336             : 
     337           2 : CRPCConvertTable::CRPCConvertTable()
     338             : {
     339         544 :     for (const auto& cp : vRPCConvertParams) {
     340         542 :         members.emplace(cp.methodName, cp.paramIdx);
     341         542 :         membersByName.emplace(cp.methodName, cp.paramName);
     342             :     }
     343           2 : }
     344             : 
     345           2 : static CRPCConvertTable rpcCvtTable;
     346             : 
     347           0 : UniValue RPCConvertValues(const std::string &strMethod, const std::vector<std::string> &strParams)
     348             : {
     349           0 :     UniValue params(UniValue::VARR);
     350             : 
     351           0 :     for (unsigned int idx = 0; idx < strParams.size(); idx++) {
     352           0 :         std::string_view value{strParams[idx]};
     353           0 :         params.push_back(rpcCvtTable.ArgToUniValue(value, strMethod, idx));
     354           0 :     }
     355             : 
     356           0 :     return params;
     357           0 : }
     358             : 
     359           0 : UniValue RPCConvertNamedValues(const std::string &strMethod, const std::vector<std::string> &strParams)
     360             : {
     361           0 :     UniValue params(UniValue::VOBJ);
     362           0 :     UniValue positional_args{UniValue::VARR};
     363             : 
     364           0 :     for (std::string_view s: strParams) {
     365           0 :         size_t pos = s.find('=');
     366           0 :         if (pos == std::string::npos) {
     367           0 :             positional_args.push_back(rpcCvtTable.ArgToUniValue(s, strMethod, positional_args.size()));
     368           0 :             continue;
     369             :         }
     370             : 
     371           0 :         std::string name{s.substr(0, pos)};
     372           0 :         std::string_view value{s.substr(pos+1)};
     373             : 
     374             :         // Intentionally overwrite earlier named values with later ones as a
     375             :         // convenience for scripts and command line users that want to merge
     376             :         // options.
     377           0 :         params.pushKV(name, rpcCvtTable.ArgToUniValue(value, strMethod, name));
     378           0 :     }
     379             : 
     380           0 :     if (!positional_args.empty()) {
     381             :         // Use pushKVEnd instead of pushKV to avoid overwriting an explicit
     382             :         // "args" value with an implicit one. Let the RPC server handle the
     383             :         // request as given.
     384           0 :         params.pushKVEnd("args", positional_args);
     385           0 :     }
     386             : 
     387           0 :     return params;
     388           0 : }

Generated by: LCOV version 1.14