Branch data Line data Source code
# 1 : : // Copyright (c) 2010 Satoshi Nakamoto
# 2 : : // Copyright (c) 2009-2021 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 <rpc/client.h>
# 7 : : #include <util/system.h>
# 8 : :
# 9 : : #include <set>
# 10 : : #include <stdint.h>
# 11 : :
# 12 : : class CRPCConvertParam
# 13 : : {
# 14 : : public:
# 15 : : std::string methodName; //!< method whose params want conversion
# 16 : : int paramIdx; //!< 0-based idx of param to convert
# 17 : : std::string paramName; //!< parameter name
# 18 : : };
# 19 : :
# 20 : : // clang-format off
# 21 : : /**
# 22 : : * Specify a (method, idx, name) here if the argument is a non-string RPC
# 23 : : * argument and needs to be converted from JSON.
# 24 : : *
# 25 : : * @note Parameter indexes start from 0.
# 26 : : */
# 27 : : static const CRPCConvertParam vRPCConvertParams[] =
# 28 : : {
# 29 : : { "setmocktime", 0, "timestamp" },
# 30 : : { "mockscheduler", 0, "delta_time" },
# 31 : : { "utxoupdatepsbt", 1, "descriptors" },
# 32 : : { "generatetoaddress", 0, "nblocks" },
# 33 : : { "generatetoaddress", 2, "maxtries" },
# 34 : : { "generatetodescriptor", 0, "num_blocks" },
# 35 : : { "generatetodescriptor", 2, "maxtries" },
# 36 : : { "generateblock", 1, "transactions" },
# 37 : : { "getnetworkhashps", 0, "nblocks" },
# 38 : : { "getnetworkhashps", 1, "height" },
# 39 : : { "sendtoaddress", 1, "amount" },
# 40 : : { "sendtoaddress", 4, "subtractfeefromamount" },
# 41 : : { "sendtoaddress", 5 , "replaceable" },
# 42 : : { "sendtoaddress", 6 , "conf_target" },
# 43 : : { "sendtoaddress", 8, "avoid_reuse" },
# 44 : : { "sendtoaddress", 9, "fee_rate"},
# 45 : : { "sendtoaddress", 10, "verbose"},
# 46 : : { "settxfee", 0, "amount" },
# 47 : : { "sethdseed", 0, "newkeypool" },
# 48 : : { "getreceivedbyaddress", 1, "minconf" },
# 49 : : { "getreceivedbyaddress", 2, "include_immature_coinbase" },
# 50 : : { "getreceivedbylabel", 1, "minconf" },
# 51 : : { "getreceivedbylabel", 2, "include_immature_coinbase" },
# 52 : : { "listreceivedbyaddress", 0, "minconf" },
# 53 : : { "listreceivedbyaddress", 1, "include_empty" },
# 54 : : { "listreceivedbyaddress", 2, "include_watchonly" },
# 55 : : { "listreceivedbyaddress", 4, "include_immature_coinbase" },
# 56 : : { "listreceivedbylabel", 0, "minconf" },
# 57 : : { "listreceivedbylabel", 1, "include_empty" },
# 58 : : { "listreceivedbylabel", 2, "include_watchonly" },
# 59 : : { "listreceivedbylabel", 3, "include_immature_coinbase" },
# 60 : : { "getbalance", 1, "minconf" },
# 61 : : { "getbalance", 2, "include_watchonly" },
# 62 : : { "getbalance", 3, "avoid_reuse" },
# 63 : : { "getblockfrompeer", 1, "peer_id" },
# 64 : : { "getblockhash", 0, "height" },
# 65 : : { "waitforblockheight", 0, "height" },
# 66 : : { "waitforblockheight", 1, "timeout" },
# 67 : : { "waitforblock", 1, "timeout" },
# 68 : : { "waitfornewblock", 0, "timeout" },
# 69 : : { "listtransactions", 1, "count" },
# 70 : : { "listtransactions", 2, "skip" },
# 71 : : { "listtransactions", 3, "include_watchonly" },
# 72 : : { "walletpassphrase", 1, "timeout" },
# 73 : : { "getblocktemplate", 0, "template_request" },
# 74 : : { "listsinceblock", 1, "target_confirmations" },
# 75 : : { "listsinceblock", 2, "include_watchonly" },
# 76 : : { "listsinceblock", 3, "include_removed" },
# 77 : : { "sendmany", 1, "amounts" },
# 78 : : { "sendmany", 2, "minconf" },
# 79 : : { "sendmany", 4, "subtractfeefrom" },
# 80 : : { "sendmany", 5 , "replaceable" },
# 81 : : { "sendmany", 6 , "conf_target" },
# 82 : : { "sendmany", 8, "fee_rate"},
# 83 : : { "sendmany", 9, "verbose" },
# 84 : : { "deriveaddresses", 1, "range" },
# 85 : : { "scantxoutset", 1, "scanobjects" },
# 86 : : { "addmultisigaddress", 0, "nrequired" },
# 87 : : { "addmultisigaddress", 1, "keys" },
# 88 : : { "createmultisig", 0, "nrequired" },
# 89 : : { "createmultisig", 1, "keys" },
# 90 : : { "listunspent", 0, "minconf" },
# 91 : : { "listunspent", 1, "maxconf" },
# 92 : : { "listunspent", 2, "addresses" },
# 93 : : { "listunspent", 3, "include_unsafe" },
# 94 : : { "listunspent", 4, "query_options" },
# 95 : : { "getblock", 1, "verbosity" },
# 96 : : { "getblock", 1, "verbose" },
# 97 : : { "getblockheader", 1, "verbose" },
# 98 : : { "getchaintxstats", 0, "nblocks" },
# 99 : : { "gettransaction", 1, "include_watchonly" },
# 100 : : { "gettransaction", 2, "verbose" },
# 101 : : { "getrawtransaction", 1, "verbose" },
# 102 : : { "createrawtransaction", 0, "inputs" },
# 103 : : { "createrawtransaction", 1, "outputs" },
# 104 : : { "createrawtransaction", 2, "locktime" },
# 105 : : { "createrawtransaction", 3, "replaceable" },
# 106 : : { "decoderawtransaction", 1, "iswitness" },
# 107 : : { "signrawtransactionwithkey", 1, "privkeys" },
# 108 : : { "signrawtransactionwithkey", 2, "prevtxs" },
# 109 : : { "signrawtransactionwithwallet", 1, "prevtxs" },
# 110 : : { "sendrawtransaction", 1, "maxfeerate" },
# 111 : : { "testmempoolaccept", 0, "rawtxs" },
# 112 : : { "testmempoolaccept", 1, "maxfeerate" },
# 113 : : { "combinerawtransaction", 0, "txs" },
# 114 : : { "fundrawtransaction", 1, "options" },
# 115 : : { "fundrawtransaction", 2, "iswitness" },
# 116 : : { "walletcreatefundedpsbt", 0, "inputs" },
# 117 : : { "walletcreatefundedpsbt", 1, "outputs" },
# 118 : : { "walletcreatefundedpsbt", 2, "locktime" },
# 119 : : { "walletcreatefundedpsbt", 3, "options" },
# 120 : : { "walletcreatefundedpsbt", 4, "bip32derivs" },
# 121 : : { "walletprocesspsbt", 1, "sign" },
# 122 : : { "walletprocesspsbt", 3, "bip32derivs" },
# 123 : : { "walletprocesspsbt", 4, "finalize" },
# 124 : : { "createpsbt", 0, "inputs" },
# 125 : : { "createpsbt", 1, "outputs" },
# 126 : : { "createpsbt", 2, "locktime" },
# 127 : : { "createpsbt", 3, "replaceable" },
# 128 : : { "combinepsbt", 0, "txs"},
# 129 : : { "joinpsbts", 0, "txs"},
# 130 : : { "finalizepsbt", 1, "extract"},
# 131 : : { "converttopsbt", 1, "permitsigdata"},
# 132 : : { "converttopsbt", 2, "iswitness"},
# 133 : : { "gettxout", 1, "n" },
# 134 : : { "gettxout", 2, "include_mempool" },
# 135 : : { "gettxoutproof", 0, "txids" },
# 136 : : { "gettxoutsetinfo", 1, "hash_or_height" },
# 137 : : { "gettxoutsetinfo", 2, "use_index"},
# 138 : : { "lockunspent", 0, "unlock" },
# 139 : : { "lockunspent", 1, "transactions" },
# 140 : : { "lockunspent", 2, "persistent" },
# 141 : : { "send", 0, "outputs" },
# 142 : : { "send", 1, "conf_target" },
# 143 : : { "send", 3, "fee_rate"},
# 144 : : { "send", 4, "options" },
# 145 : : { "sendall", 0, "recipients" },
# 146 : : { "sendall", 1, "conf_target" },
# 147 : : { "sendall", 3, "fee_rate"},
# 148 : : { "sendall", 4, "options" },
# 149 : : { "importprivkey", 2, "rescan" },
# 150 : : { "importaddress", 2, "rescan" },
# 151 : : { "importaddress", 3, "p2sh" },
# 152 : : { "importpubkey", 2, "rescan" },
# 153 : : { "importmulti", 0, "requests" },
# 154 : : { "importmulti", 1, "options" },
# 155 : : { "importdescriptors", 0, "requests" },
# 156 : : { "listdescriptors", 0, "private" },
# 157 : : { "verifychain", 0, "checklevel" },
# 158 : : { "verifychain", 1, "nblocks" },
# 159 : : { "getblockstats", 0, "hash_or_height" },
# 160 : : { "getblockstats", 1, "stats" },
# 161 : : { "pruneblockchain", 0, "height" },
# 162 : : { "keypoolrefill", 0, "newsize" },
# 163 : : { "getrawmempool", 0, "verbose" },
# 164 : : { "getrawmempool", 1, "mempool_sequence" },
# 165 : : { "estimatesmartfee", 0, "conf_target" },
# 166 : : { "estimaterawfee", 0, "conf_target" },
# 167 : : { "estimaterawfee", 1, "threshold" },
# 168 : : { "prioritisetransaction", 1, "dummy" },
# 169 : : { "prioritisetransaction", 2, "fee_delta" },
# 170 : : { "setban", 2, "bantime" },
# 171 : : { "setban", 3, "absolute" },
# 172 : : { "setnetworkactive", 0, "state" },
# 173 : : { "setwalletflag", 1, "value" },
# 174 : : { "getmempoolancestors", 1, "verbose" },
# 175 : : { "getmempooldescendants", 1, "verbose" },
# 176 : : { "bumpfee", 1, "options" },
# 177 : : { "psbtbumpfee", 1, "options" },
# 178 : : { "logging", 0, "include" },
# 179 : : { "logging", 1, "exclude" },
# 180 : : { "disconnectnode", 1, "nodeid" },
# 181 : : { "upgradewallet", 0, "version" },
# 182 : : // Echo with conversion (For testing only)
# 183 : : { "echojson", 0, "arg0" },
# 184 : : { "echojson", 1, "arg1" },
# 185 : : { "echojson", 2, "arg2" },
# 186 : : { "echojson", 3, "arg3" },
# 187 : : { "echojson", 4, "arg4" },
# 188 : : { "echojson", 5, "arg5" },
# 189 : : { "echojson", 6, "arg6" },
# 190 : : { "echojson", 7, "arg7" },
# 191 : : { "echojson", 8, "arg8" },
# 192 : : { "echojson", 9, "arg9" },
# 193 : : { "rescanblockchain", 0, "start_height"},
# 194 : : { "rescanblockchain", 1, "stop_height"},
# 195 : : { "createwallet", 1, "disable_private_keys"},
# 196 : : { "createwallet", 2, "blank"},
# 197 : : { "createwallet", 4, "avoid_reuse"},
# 198 : : { "createwallet", 5, "descriptors"},
# 199 : : { "createwallet", 6, "load_on_startup"},
# 200 : : { "createwallet", 7, "external_signer"},
# 201 : : { "restorewallet", 2, "load_on_startup"},
# 202 : : { "loadwallet", 1, "load_on_startup"},
# 203 : : { "unloadwallet", 1, "load_on_startup"},
# 204 : : { "getnodeaddresses", 0, "count"},
# 205 : : { "addpeeraddress", 1, "port"},
# 206 : : { "addpeeraddress", 2, "tried"},
# 207 : : { "stop", 0, "wait" },
# 208 : : };
# 209 : : // clang-format on
# 210 : :
# 211 : : class CRPCConvertTable
# 212 : : {
# 213 : : private:
# 214 : : std::set<std::pair<std::string, int>> members;
# 215 : : std::set<std::pair<std::string, std::string>> membersByName;
# 216 : :
# 217 : : public:
# 218 : : CRPCConvertTable();
# 219 : :
# 220 : 792 : bool convert(const std::string& method, int idx) {
# 221 : 792 : return (members.count(std::make_pair(method, idx)) > 0);
# 222 : 792 : }
# 223 : 59 : bool convert(const std::string& method, const std::string& name) {
# 224 : 59 : return (membersByName.count(std::make_pair(method, name)) > 0);
# 225 : 59 : }
# 226 : : };
# 227 : :
# 228 : : CRPCConvertTable::CRPCConvertTable()
# 229 : 1378 : {
# 230 [ + + ]: 245284 : for (const auto& cp : vRPCConvertParams) {
# 231 : 245284 : members.emplace(cp.methodName, cp.paramIdx);
# 232 : 245284 : membersByName.emplace(cp.methodName, cp.paramName);
# 233 : 245284 : }
# 234 : 1378 : }
# 235 : :
# 236 : : static CRPCConvertTable rpcCvtTable;
# 237 : :
# 238 : : /** Non-RFC4627 JSON parser, accepts internal values (such as numbers, true, false, null)
# 239 : : * as well as objects and arrays.
# 240 : : */
# 241 : : UniValue ParseNonRFCJSONValue(const std::string& strVal)
# 242 : 453 : {
# 243 : 453 : UniValue jVal;
# 244 [ + + ][ + + ]: 453 : if (!jVal.read(std::string("[")+strVal+std::string("]")) ||
# 245 [ - + ][ - + ]: 453 : !jVal.isArray() || jVal.size()!=1)
# 246 : 28 : throw std::runtime_error(std::string("Error parsing JSON: ") + strVal);
# 247 : 425 : return jVal[0];
# 248 : 453 : }
# 249 : :
# 250 : : UniValue RPCConvertValues(const std::string &strMethod, const std::vector<std::string> &strParams)
# 251 : 1515 : {
# 252 : 1515 : UniValue params(UniValue::VARR);
# 253 : :
# 254 [ + + ]: 2307 : for (unsigned int idx = 0; idx < strParams.size(); idx++) {
# 255 : 792 : const std::string& strVal = strParams[idx];
# 256 : :
# 257 [ + + ]: 792 : if (!rpcCvtTable.convert(strMethod, idx)) {
# 258 : : // insert string value directly
# 259 : 406 : params.push_back(strVal);
# 260 : 406 : } else {
# 261 : : // parse string as JSON, insert bool/number/object/etc. value
# 262 : 386 : params.push_back(ParseNonRFCJSONValue(strVal));
# 263 : 386 : }
# 264 : 792 : }
# 265 : :
# 266 : 1515 : return params;
# 267 : 1515 : }
# 268 : :
# 269 : : UniValue RPCConvertNamedValues(const std::string &strMethod, const std::vector<std::string> &strParams)
# 270 : 37 : {
# 271 : 37 : UniValue params(UniValue::VOBJ);
# 272 : :
# 273 [ + + ]: 59 : for (const std::string &s: strParams) {
# 274 : 59 : size_t pos = s.find('=');
# 275 [ - + ]: 59 : if (pos == std::string::npos) {
# 276 : 0 : throw(std::runtime_error("No '=' in named argument '"+s+"', this needs to be present for every argument (even if it is empty)"));
# 277 : 0 : }
# 278 : :
# 279 : 59 : std::string name = s.substr(0, pos);
# 280 : 59 : std::string value = s.substr(pos+1);
# 281 : :
# 282 [ + + ]: 59 : if (!rpcCvtTable.convert(strMethod, name)) {
# 283 : : // insert string value directly
# 284 : 14 : params.pushKV(name, value);
# 285 : 45 : } else {
# 286 : : // parse string as JSON, insert bool/number/object/etc. value
# 287 : 45 : params.pushKV(name, ParseNonRFCJSONValue(value));
# 288 : 45 : }
# 289 : 59 : }
# 290 : :
# 291 : 37 : return params;
# 292 : 37 : }
|