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

Generated by: LCOV version 1.16