LCOV - code coverage report
Current view: top level - src/rpc - client.cpp (source / functions) Hit Total Coverage
Test: test_dash_coverage.info Lines: 374 376 99.5 %
Date: 2026-06-25 07:23:51 Functions: 16 20 80.0 %

          Line data    Source code
       1             : // Copyright (c) 2010 Satoshi Nakamoto
       2             : // Copyright (c) 2009-2021 The Bitcoin Core developers
       3             : // Copyright (c) 2014-2025 The Dash Core developers
       4             : // Distributed under the MIT software license, see the accompanying
       5             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       6             : 
       7             : #include <rpc/client.h>
       8             : #include <tinyformat.h>
       9             : #include <util/system.h>
      10             : 
      11             : #include <map>
      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             :     bool preserve_str{false}; //!< only parse if array or object
      22             : };
      23             : 
      24             : // clang-format off
      25             : /**
      26             :  * Specify a (method, idx, name) here if the argument is a non-string RPC
      27             :  * argument and needs to be converted from JSON.
      28             :  *
      29             :  * @note Parameter indexes start from 0.
      30             :  */
      31           0 : static const CRPCConvertParam vRPCConvertParams[] =
      32       43946 : {
      33         146 :     { "setmocktime", 0, "timestamp" },
      34         146 :     { "mockscheduler", 0, "delta_time" },
      35         146 :     { "utxoupdatepsbt", 1, "descriptors" },
      36             : #if ENABLE_MINER
      37         146 :     { "generatetoaddress", 0, "nblocks" },
      38         146 :     { "generatetoaddress", 2, "maxtries" },
      39         146 :     { "generatetodescriptor", 0, "num_blocks" },
      40         146 :     { "generatetodescriptor", 2, "maxtries" },
      41         146 :     { "generateblock", 1, "transactions" },
      42             : #endif // ENABLE_MINER
      43         146 :     { "getnetworkhashps", 0, "nblocks" },
      44         146 :     { "getnetworkhashps", 1, "height" },
      45         146 :     { "sendtoaddress", 1, "amount" },
      46         146 :     { "sendtoaddress", 4, "subtractfeefromamount" },
      47         146 :     { "sendtoaddress", 5, "use_is" },
      48         146 :     { "sendtoaddress", 6, "use_cj" },
      49         146 :     { "sendtoaddress", 7, "conf_target" },
      50         146 :     { "sendtoaddress", 9, "avoid_reuse" },
      51         146 :     { "sendtoaddress", 10, "fee_rate"},
      52         146 :     { "sendtoaddress", 11, "verbose"},
      53         146 :     { "settxfee", 0, "amount" },
      54         146 :     { "sethdseed", 0, "newkeypool" },
      55         146 :     { "getreceivedbyaddress", 1, "minconf" },
      56         146 :     { "getreceivedbyaddress", 2, "addlocked" },
      57         146 :     { "getreceivedbyaddress", 3, "include_immature_coinbase" },
      58         146 :     { "getreceivedbylabel", 1, "minconf" },
      59         146 :     { "getreceivedbylabel", 2, "addlocked" },
      60         146 :     { "getreceivedbylabel", 3, "include_immature_coinbase" },
      61         146 :     { "listaddressbalances", 0, "minamount" },
      62         146 :     { "listreceivedbyaddress", 0, "minconf" },
      63         146 :     { "listreceivedbyaddress", 1, "addlocked" },
      64         146 :     { "listreceivedbyaddress", 2, "include_empty" },
      65         146 :     { "listreceivedbyaddress", 3, "include_watchonly" },
      66         146 :     { "listreceivedbyaddress", 5, "include_immature_coinbase" },
      67         146 :     { "listreceivedbylabel", 0, "minconf" },
      68         146 :     { "listreceivedbylabel", 1, "addlocked" },
      69         146 :     { "listreceivedbylabel", 2, "include_empty" },
      70         146 :     { "listreceivedbylabel", 3, "include_watchonly" },
      71         146 :     { "listreceivedbylabel", 4, "include_immature_coinbase" },
      72         146 :     { "getassetunlockstatuses", 0, "indexes" },
      73         146 :     { "getassetunlockstatuses", 1, "height" },
      74         146 :     { "getbalance", 1, "minconf" },
      75         146 :     { "getbalance", 2, "addlocked" },
      76         146 :     { "getbalance", 3, "include_watchonly" },
      77         146 :     { "getbalance", 4, "avoid_reuse" },
      78         146 :     { "getblockfrompeer", 1, "peer_id" },
      79         146 :     { "getchaintips", 0, "count" },
      80         146 :     { "getchaintips", 1, "branchlen" },
      81         146 :     { "getblockhash", 0, "height" },
      82         146 :     { "getsuperblockbudget", 0, "index" },
      83         146 :     { "waitforblockheight", 0, "height" },
      84         146 :     { "waitforblockheight", 1, "timeout" },
      85         146 :     { "waitforblock", 1, "timeout" },
      86         146 :     { "reconsiderblock", 1, "ignore_chainlocks" },
      87         146 :     { "waitfornewblock", 0, "timeout" },
      88         146 :     { "listtransactions", 1, "count" },
      89         146 :     { "listtransactions", 2, "skip" },
      90         146 :     { "listtransactions", 3, "include_watchonly" },
      91         146 :     { "walletpassphrase", 1, "timeout" },
      92         146 :     { "walletpassphrase", 2, "mixingonly" },
      93         146 :     { "getblocktemplate", 0, "template_request" },
      94         146 :     { "listsinceblock", 1, "target_confirmations" },
      95         146 :     { "listsinceblock", 2, "include_watchonly" },
      96         146 :     { "listsinceblock", 3, "include_removed" },
      97         146 :     { "sendmany", 1, "amounts" },
      98         146 :     { "sendmany", 2, "minconf" },
      99         146 :     { "sendmany", 3, "addlocked" },
     100         146 :     { "sendmany", 5, "subtractfeefrom" },
     101         146 :     { "sendmany", 6, "use_is" },
     102         146 :     { "sendmany", 7, "use_cj" },
     103         146 :     { "sendmany", 8, "conf_target" },
     104         146 :     { "sendmany", 10, "fee_rate" },
     105         146 :     { "sendmany", 11, "verbose" },
     106         146 :     { "deriveaddresses", 1, "range" },
     107         146 :     { "scantxoutset", 1, "scanobjects" },
     108         146 :     { "addmultisigaddress", 0, "nrequired" },
     109         146 :     { "addmultisigaddress", 1, "keys" },
     110         146 :     { "createmultisig", 0, "nrequired" },
     111         146 :     { "createmultisig", 1, "keys" },
     112         146 :     { "listunspent", 0, "minconf" },
     113         146 :     { "listunspent", 1, "maxconf" },
     114         146 :     { "listunspent", 2, "addresses" },
     115         146 :     { "listunspent", 3, "include_unsafe" },
     116         146 :     { "listunspent", 4, "query_options" },
     117         146 :     { "getblock", 1, "verbosity" },
     118         146 :     { "getblock", 1, "verbose" },
     119         146 :     { "getblockheader", 1, "verbose" },
     120         146 :     { "getblockheaders", 1, "count" },
     121         146 :     { "getblockheaders", 2, "verbose" },
     122         146 :     { "getchaintxstats", 0, "nblocks" },
     123         146 :     { "getmerkleblocks", 2, "count" },
     124         146 :     { "gettransaction", 1, "include_watchonly" },
     125         146 :     { "gettransaction", 2, "verbose" },
     126         146 :     { "getrawtransaction", 1, "verbose" },
     127         146 :     { "getislocks", 0, "txids" },
     128         146 :     { "getrawtransactionmulti", 0, "transactions" },
     129         146 :     { "getrawtransactionmulti", 1, "verbose" },
     130         146 :     { "gettxchainlocks", 0, "txids" },
     131         146 :     { "createrawtransaction", 0, "inputs" },
     132         146 :     { "createrawtransaction", 1, "outputs" },
     133         146 :     { "createrawtransaction", 2, "locktime" },
     134         146 :     { "signrawtransactionwithkey", 1, "privkeys" },
     135         146 :     { "signrawtransactionwithkey", 2, "prevtxs" },
     136         146 :     { "signrawtransactionwithwallet", 1, "prevtxs" },
     137         146 :     { "sendrawtransaction", 1, "maxfeerate" },
     138         146 :     { "sendrawtransaction", 2, "instantsend" },
     139         146 :     { "sendrawtransaction", 3, "bypasslimits" },
     140         146 :     { "testmempoolaccept", 0, "rawtxs" },
     141         146 :     { "testmempoolaccept", 1, "maxfeerate" },
     142         146 :     { "submitpackage", 0, "package" },
     143         146 :     { "combinerawtransaction", 0, "txs" },
     144         146 :     { "fundrawtransaction", 1, "options" },
     145         146 :     { "walletcreatefundedpsbt", 0, "inputs" },
     146         146 :     { "walletcreatefundedpsbt", 1, "outputs" },
     147         146 :     { "walletcreatefundedpsbt", 2, "locktime" },
     148         146 :     { "walletcreatefundedpsbt", 3, "options" },
     149         146 :     { "walletcreatefundedpsbt", 4, "bip32derivs" },
     150         146 :     { "walletprocesspsbt", 1, "sign" },
     151         146 :     { "walletprocesspsbt", 3, "bip32derivs" },
     152         146 :     { "walletprocesspsbt", 4, "finalize" },
     153         146 :     { "createpsbt", 0, "inputs" },
     154         146 :     { "createpsbt", 1, "outputs" },
     155         146 :     { "createpsbt", 2, "locktime" },
     156         146 :     { "combinepsbt", 0, "txs"},
     157         146 :     { "joinpsbts", 0, "txs"},
     158         146 :     { "finalizepsbt", 1, "extract"},
     159         146 :     { "converttopsbt", 1, "permitsigdata"},
     160         146 :     { "gettxout", 1, "n" },
     161         146 :     { "gettxout", 2, "include_mempool" },
     162         146 :     { "gettxoutproof", 0, "txids" },
     163         146 :     { "gettxoutsetinfo", 1, "hash_or_height" },
     164         146 :     { "gettxoutsetinfo", 2, "use_index"},
     165         146 :     { "lockunspent", 0, "unlock" },
     166         146 :     { "lockunspent", 1, "transactions" },
     167         146 :     { "lockunspent", 2, "persistent" },
     168         146 :     { "send", 0, "outputs" },
     169         146 :     { "send", 1, "conf_target" },
     170         146 :     { "send", 3, "fee_rate"},
     171         146 :     { "send", 4, "options" },
     172         146 :     { "sendall", 0, "recipients" },
     173         146 :     { "sendall", 1, "conf_target" },
     174         146 :     { "sendall", 3, "fee_rate"},
     175         146 :     { "sendall", 4, "options" },
     176         146 :     { "simulaterawtransaction", 0, "rawtxs" },
     177         146 :     { "simulaterawtransaction", 1, "options" },
     178         146 :     { "importprivkey", 2, "rescan" },
     179         146 :     { "importelectrumwallet", 1, "index" },
     180         146 :     { "importaddress", 2, "rescan" },
     181         146 :     { "importaddress", 3, "p2sh" },
     182         146 :     { "importpubkey", 2, "rescan" },
     183         146 :     { "importmulti", 0, "requests" },
     184         146 :     { "importmulti", 1, "options" },
     185         146 :     { "importdescriptors", 0, "requests" },
     186         146 :     { "listdescriptors", 0, "private" },
     187         146 :     { "verifychain", 0, "checklevel" },
     188         146 :     { "verifychain", 1, "nblocks" },
     189         146 :     { "getblockstats", 0, "hash_or_height" },
     190         146 :     { "getblockstats", 1, "stats" },
     191         146 :     { "pruneblockchain", 0, "height" },
     192         146 :     { "keypoolrefill", 0, "newsize" },
     193         146 :     { "getrawmempool", 0, "verbose" },
     194         146 :     { "getrawmempool", 1, "mempool_sequence" },
     195         146 :     { "estimatesmartfee", 0, "conf_target" },
     196         146 :     { "estimaterawfee", 0, "conf_target" },
     197         146 :     { "estimaterawfee", 1, "threshold" },
     198         146 :     { "prioritisetransaction", 1, "fee_delta" },
     199         146 :     { "setban", 2, "bantime" },
     200         146 :     { "setban", 3, "absolute" },
     201         146 :     { "setmnthreadactive", 0, "state" },
     202         146 :     { "setnetworkactive", 0, "state" },
     203         146 :     { "setcoinjoinrounds", 0, "rounds" },
     204         146 :     { "setcoinjoinamount", 0, "amount" },
     205         146 :     { "setwalletflag", 1, "value" },
     206         146 :     { "getmempoolancestors", 1, "verbose" },
     207         146 :     { "getmempooldescendants", 1, "verbose" },
     208         146 :     { "gettxspendingprevout", 0, "outputs" },
     209         146 :     { "logging", 0, "include" },
     210         146 :     { "logging", 1, "exclude" },
     211         146 :     { "sporkupdate", 1, "value" },
     212         146 :     { "voteraw", 1, "mn-collateral-tx-index" },
     213         146 :     { "voteraw", 5, "time" },
     214         146 :     { "getblockhashes", 0, "high"},
     215         146 :     { "getblockhashes", 1, "low" },
     216         146 :     { "getspentinfo", 0, "request" },
     217         146 :     { "getaddresstxids", 0, "addresses" },
     218         146 :     { "getaddressbalance", 0, "addresses" },
     219         146 :     { "getaddressdeltas", 0, "addresses" },
     220         146 :     { "getaddressutxos", 0, "addresses" },
     221         146 :     { "getaddressmempool", 0, "addresses" },
     222         146 :     { "getspecialtxes", 1, "type" },
     223         146 :     { "getspecialtxes", 2, "count" },
     224         146 :     { "getspecialtxes", 3, "skip" },
     225         146 :     { "getspecialtxes", 4, "verbosity" },
     226         146 :     { "disconnectnode", 1, "nodeid" },
     227         146 :     { "upgradewallet", 0, "version" },
     228             :     // Echo with conversion (For testing only)
     229         146 :     { "echojson", 0, "arg0" },
     230         146 :     { "echojson", 1, "arg1" },
     231         146 :     { "echojson", 2, "arg2" },
     232         146 :     { "echojson", 3, "arg3" },
     233         146 :     { "echojson", 4, "arg4" },
     234         146 :     { "echojson", 5, "arg5" },
     235         146 :     { "echojson", 6, "arg6" },
     236         146 :     { "echojson", 7, "arg7" },
     237         146 :     { "echojson", 8, "arg8" },
     238         146 :     { "echojson", 9, "arg9" },
     239         146 :     { "rescanblockchain", 0, "start_height"},
     240         146 :     { "rescanblockchain", 1, "stop_height"},
     241         146 :     { "wipewallettxes", 0, "keep_confirmed"},
     242         146 :     { "createwallet", 1, "disable_private_keys"},
     243         146 :     { "createwallet", 2, "blank"},
     244         146 :     { "createwallet", 4, "avoid_reuse"},
     245         146 :     { "createwallet", 5, "descriptors"},
     246         146 :     { "createwallet", 6, "load_on_startup"},
     247         146 :     { "createwallet", 7, "external_signer"},
     248         146 :     { "restorewallet", 2, "load_on_startup"},
     249         146 :     { "loadwallet", 1, "load_on_startup"},
     250         146 :     { "unloadwallet", 1, "load_on_startup"},
     251         146 :     { "upgradetohd", 3, "rescan"},
     252         146 :     { "getnodeaddresses", 0, "count"},
     253         146 :     { "addpeeraddress", 1, "port"},
     254         146 :     { "addpeeraddress", 2, "tried"},
     255         146 :     { "sendmsgtopeer", 0, "peer_id" },
     256         146 :     { "stop", 0, "wait" },
     257         146 :     { "addnode", 2, "v2transport" },
     258         146 :     { "addconnection", 2, "v2transport" },
     259         146 :     { "verifychainlock", 2, "blockHeight" },
     260         146 :     { "verifyislock", 3, "maxHeight" },
     261         146 :     { "submitchainlock", 2, "blockHeight" },
     262         146 :     { "mnauth", 0, "nodeId" },
     263             :     // Compound RPCs (note: index position is offset by one to account for subcommand)
     264         146 :     { "bls generate", 1, "legacy" },
     265         146 :     { "bls fromsecret", 2, "legacy" },
     266         146 :     { "coinjoinsalt generate", 1, "overwrite" },
     267         146 :     { "coinjoinsalt set", 2, "overwrite" },
     268         146 :     { "gobject list-prepared", 1, "count" },
     269         146 :     { "gobject prepare", 2, "revision" },
     270         146 :     { "gobject prepare", 3, "time" },
     271         146 :     { "gobject prepare", 7, "outputIndex" },
     272         146 :     { "gobject submit", 2, "revision" },
     273         146 :     { "gobject submit", 3, "time" },
     274         146 :     { "masternode connect", 2, "v2transport" },
     275         146 :     { "masternode payments", 2, "count" },
     276         146 :     { "masternode winners", 1, "count" },
     277         146 :     { "protx diff", 3, "extended" },
     278         146 :     { "protx list", 2, "detailed" },
     279         146 :     { "protx list", 3, "height" },
     280         146 :     { "protx register", 2, "collateralIndex" },
     281         146 :     { "protx register", 3, "coreP2PAddrs", true },
     282         146 :     { "protx register", 10, "submit" },
     283         146 :     { "protx register_legacy", 2, "collateralIndex" },
     284         146 :     { "protx register_legacy", 3, "coreP2PAddrs", true },
     285         146 :     { "protx register_legacy", 10, "submit" },
     286         146 :     { "protx register_evo", 2, "collateralIndex" },
     287         146 :     { "protx register_evo", 3, "coreP2PAddrs", true },
     288         146 :     { "protx register_evo", 10, "platformP2PAddrs", true },
     289         146 :     { "protx register_evo", 11, "platformHTTPSAddrs", true },
     290         146 :     { "protx register_evo", 13, "submit" },
     291         146 :     { "protx register_fund", 2, "coreP2PAddrs", true },
     292         146 :     { "protx register_fund", 9, "submit" },
     293         146 :     { "protx register_fund_legacy", 2, "coreP2PAddrs", true },
     294         146 :     { "protx register_fund_legacy", 9, "submit" },
     295         146 :     { "protx register_fund_evo", 2, "coreP2PAddrs", true },
     296         146 :     { "protx register_fund_evo", 9, "platformP2PAddrs", true },
     297         146 :     { "protx register_fund_evo", 10, "platformHTTPSAddrs", true },
     298         146 :     { "protx register_fund_evo", 12, "submit" },
     299         146 :     { "protx register_prepare", 2, "collateralIndex" },
     300         146 :     { "protx register_prepare", 3, "coreP2PAddrs", true },
     301         146 :     { "protx register_prepare_legacy", 2, "collateralIndex" },
     302         146 :     { "protx register_prepare_legacy", 3, "coreP2PAddrs", true },
     303         146 :     { "protx register_prepare_evo", 2, "collateralIndex" },
     304         146 :     { "protx register_prepare_evo", 3, "coreP2PAddrs", true },
     305         146 :     { "protx register_prepare_evo", 10, "platformP2PAddrs", true },
     306         146 :     { "protx register_prepare_evo", 11, "platformHTTPSAddrs", true },
     307         146 :     { "protx revoke", 3, "reason" },
     308         146 :     { "protx revoke", 5, "submit" },
     309         146 :     { "protx update_registrar", 6, "submit" },
     310         146 :     { "protx update_registrar_legacy", 6, "submit" },
     311         146 :     { "protx update_service", 2, "coreP2PAddrs", true },
     312         146 :     { "protx update_service", 6, "submit" },
     313         146 :     { "protx update_service_evo", 2, "coreP2PAddrs", true },
     314         146 :     { "protx update_service_evo", 5, "platformP2PAddrs", true },
     315         146 :     { "protx update_service_evo", 6, "platformHTTPSAddrs", true },
     316         146 :     { "protx update_service_evo", 9, "submit" },
     317         146 :     { "quorum dkgsimerror", 2, "rate" },
     318         146 :     { "quorum dkgstatus", 1, "detail_level" },
     319         146 :     { "quorum getdata", 1, "nodeId" },
     320         146 :     { "quorum getdata", 2, "llmqType" },
     321         146 :     { "quorum getdata", 4, "dataMask" },
     322         146 :     { "quorum getrecsig", 1, "llmqType" },
     323         146 :     { "quorum hasrecsig", 1, "llmqType" },
     324         146 :     { "quorum info", 1, "llmqType" },
     325         146 :     { "quorum info", 3, "includeSkShare" },
     326         146 :     { "quorum isconflicting", 1, "llmqType" },
     327         146 :     { "quorum listextended", 1, "height" },
     328         146 :     { "quorum list", 1, "count" },
     329         146 :     { "quorum memberof", 2, "scanQuorumsCount" },
     330         146 :     { "quorum platformsign", 4, "submit" },
     331         146 :     { "quorum rotationinfo", 2, "extraShare" },
     332         146 :     { "quorum rotationinfo", 3, "baseBlockHashes" },
     333         146 :     { "quorum selectquorum", 1, "llmqType" },
     334         146 :     { "quorum sign", 1, "llmqType" },
     335         146 :     { "quorum sign", 5, "submit" },
     336         146 :     { "quorum verify", 1, "llmqType" },
     337         146 :     { "quorum verify", 6, "signHeight" },
     338             : };
     339             : // clang-format on
     340             : 
     341             : /** Parse string to UniValue or throw runtime_error if string contains invalid JSON */
     342          66 : static UniValue Parse(std::string_view raw)
     343             : {
     344          66 :     UniValue parsed;
     345          66 :     if (!parsed.read(raw)) throw std::runtime_error(tfm::format("Error parsing JSON: %s", raw));
     346          61 :     return parsed;
     347          71 : }
     348             : 
     349             : class CRPCConvertTable
     350             : {
     351             : private:
     352             :     std::map<std::pair<std::string, int>, bool> members;
     353             :     std::map<std::pair<std::string, std::string>, bool> membersByName;
     354             : 
     355          76 :     std::string_view MaybeUnquoteString(std::string_view arg_value)
     356             :     {
     357          76 :         if (arg_value.size() >= 2 && ((arg_value.front() == '\'' && arg_value.back() == '\'') || (arg_value.front() == '\"' && arg_value.back() == '\"'))) {
     358           4 :             return arg_value.substr(1, arg_value.size() - 2);
     359             :         }
     360          72 :         return arg_value;
     361          76 :     }
     362             : 
     363          10 :     bool LikelyJSONType(std::string_view arg_value)
     364             :     {
     365          10 :         arg_value = MaybeUnquoteString(arg_value);
     366          19 :         return arg_value.size() >= 2 && ((arg_value.front() == '[' && arg_value.back() == ']') || (arg_value.front() == '{' && arg_value.back() == '}'));
     367             :     }
     368             : 
     369             : public:
     370             :     CRPCConvertTable();
     371             : 
     372             :     /** Return arg_value as UniValue, and first parse it if it is a non-string parameter */
     373         155 :     UniValue ArgToUniValue(std::string_view arg_value, const std::string& method, int param_idx)
     374             :     {
     375         222 :         if (const auto it = members.find({method, param_idx}); it != members.end() && (!it->second || (it->second && LikelyJSONType(arg_value)))) {
     376          65 :             return Parse(MaybeUnquoteString(arg_value));
     377             :         }
     378          90 :         return arg_value;
     379         155 :     }
     380             : 
     381             :     /** Return arg_value as UniValue, and first parse it if it is a non-string parameter */
     382           2 :     UniValue ArgToUniValue(std::string_view arg_value, const std::string& method, const std::string& param_name)
     383             :     {
     384           3 :         if (const auto it = membersByName.find({method, param_name}); it != membersByName.end() && (!it->second || (it->second && LikelyJSONType(arg_value)))) {
     385           1 :             return Parse(MaybeUnquoteString(arg_value));
     386             :         }
     387           1 :         return arg_value;
     388           2 :     }
     389             : 
     390             :     /** Check if we have any conversion rules for this method */
     391          62 :     bool IsDefined(const std::string& method, bool named) const
     392             :     {
     393          62 :         return named ?
     394         183 :                   std::find_if(membersByName.begin(), membersByName.end(), [&method](const auto& kv) { return kv.first.first == method; }) != membersByName.end()
     395       14585 :                 : std::find_if(members.begin(), members.end(), [&method](const auto& kv) { return kv.first.first == method; }) != members.end();
     396             :     }
     397             : };
     398             : 
     399         292 : CRPCConvertTable::CRPCConvertTable()
     400         146 : {
     401       44092 :     for (const auto& cp : vRPCConvertParams) {
     402       43946 :         members.try_emplace({cp.methodName, cp.paramIdx}, cp.preserve_str);
     403       43946 :         membersByName.try_emplace({cp.methodName, cp.paramName}, cp.preserve_str);
     404             :     }
     405         292 : }
     406             : 
     407         146 : static CRPCConvertTable rpcCvtTable;
     408             : 
     409          83 : UniValue RPCConvertValues(std::string strMethod, const std::vector<std::string> &strParams)
     410             : {
     411          88 :     UniValue params(UniValue::VARR);
     412             : 
     413             :     // If we are using a subcommand that is in the table, update the method name
     414         166 :     strMethod = [&strMethod, &strParams]() {
     415          83 :         if (!strParams.empty() && strMethod.find(' ') == std::string::npos) {
     416          61 :             std::string candidate{strMethod + " " + strParams[0]};
     417          61 :             return rpcCvtTable.IsDefined(candidate, /*named=*/false) ? candidate : strMethod;
     418          61 :         }
     419          22 :         return strMethod;
     420          83 :     }();
     421             : 
     422         230 :     for (unsigned int idx = 0; idx < strParams.size(); idx++) {
     423         152 :         std::string_view value{strParams[idx]};
     424         152 :         params.push_back(rpcCvtTable.ArgToUniValue(value, strMethod, idx));
     425         147 :     }
     426             : 
     427          78 :     return params;
     428          83 : }
     429             : 
     430           1 : UniValue RPCConvertNamedValues(std::string strMethod, const std::vector<std::string> &strParams)
     431             : {
     432           1 :     UniValue params(UniValue::VOBJ);
     433           1 :     UniValue positional_args{UniValue::VARR};
     434             : 
     435             :     // If we are using a subcommand that is in the table, update the method name
     436           2 :     strMethod = [&strMethod, &strParams]() {
     437           1 :         if (strMethod.find(' ') == std::string::npos && !strParams.empty() && strParams[0].find('=') == std::string::npos) {
     438           1 :             std::string candidate{strMethod + " " + strParams[0]};
     439           1 :             return rpcCvtTable.IsDefined(candidate, /*named=*/true) ? candidate : strMethod;
     440           1 :         }
     441           0 :         return strMethod;
     442           1 :     }();
     443             : 
     444           6 :     for (std::string_view s: strParams) {
     445           5 :         size_t pos = s.find('=');
     446           5 :         if (pos == std::string::npos) {
     447           3 :             positional_args.push_back(rpcCvtTable.ArgToUniValue(s, strMethod, positional_args.size()));
     448           3 :             continue;
     449             :         }
     450             : 
     451           2 :         std::string name{s.substr(0, pos)};
     452           2 :         std::string_view value{s.substr(pos+1)};
     453             : 
     454             :         // Intentionally overwrite earlier named values with later ones as a
     455             :         // convenience for scripts and command line users that want to merge
     456             :         // options.
     457           2 :         params.pushKV(name, rpcCvtTable.ArgToUniValue(value, strMethod, name));
     458           2 :     }
     459             : 
     460           1 :     if (!positional_args.empty()) {
     461             :         // Use __pushKV instead of pushKV to avoid overwriting an explicit
     462             :         // "args" value with an implicit one. Let the RPC server handle the
     463             :         // request as given.
     464           1 :         params.__pushKV("args", positional_args);
     465           1 :     }
     466             : 
     467           1 :     return params;
     468           1 : }

Generated by: LCOV version 1.16