Line data Source code
1 : // Copyright (c) 2010 Satoshi Nakamoto
2 : // Copyright (c) 2009-2014 The Bitcoin developers
3 : // Copyright (c) 2014-2015 The Dash developers
4 : // Copyright (c) 2015-2022 The PIVX Core developers
5 : // Distributed under the MIT software license, see the accompanying
6 : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
7 :
8 : #include "rpc/client.h"
9 :
10 : #include <set>
11 : #include <stdint.h>
12 :
13 :
14 : class CRPCConvertParam
15 : {
16 : public:
17 : std::string methodName; //! method whose params want conversion
18 : int paramIdx; //! 0-based idx of param to convert
19 : std::string paramName; //!< parameter name
20 : };
21 :
22 : // clang-format off
23 : /**
24 : * Specify a (method, idx, name) here if the argument is a non-string RPC
25 : * argument and needs to be converted from JSON.
26 : *
27 : * @note Parameter indexes start from 0.
28 : */
29 : static const CRPCConvertParam vRPCConvertParams[] = {
30 : { "addmultisigaddress", 0, "nrequired" },
31 : { "addmultisigaddress", 1, "keys" },
32 : { "addpeeraddress", 1, "port" },
33 : { "cleanbudget", 0, "try_sync" },
34 : { "createmultisig", 0, "nrequired" },
35 : { "createmultisig", 1, "keys" },
36 : { "createrawtransaction", 0, "inputs" },
37 : { "createrawtransaction", 1, "outputs" },
38 : { "createrawtransaction", 2, "locktime" },
39 : { "createrawmnfinalbudget", 1, "blockstart" },
40 : { "createrawmnfinalbudget", 2, "proposals" },
41 : { "delegatestake", 1, "amount" },
42 : { "delegatestake", 3, "ext_owner" },
43 : { "delegatestake", 4, "include_delegated" },
44 : { "delegatestake", 5, "from_shield" },
45 : { "estimatefee", 0, "nblocks" },
46 : { "estimatesmartfee", 0, "nblocks" },
47 : { "fundrawtransaction", 1, "options" },
48 : { "generate", 0, "nblocks" },
49 : { "generatetoaddress", 0, "nblocks" },
50 : { "getaddednodeinfo", 0, "dummy" },
51 : { "getbalance", 0, "minconf" },
52 : { "getbalance", 1, "include_watchonly" },
53 : { "getbalance", 2, "include_delegated" },
54 : { "getbalance", 3, "include_shield" },
55 : { "getblock", 1, "verbosity" },
56 : { "getblock", 1, "verbose" },
57 : { "getblockhash", 0, "height" },
58 : { "getblockheader", 1, "verbose" },
59 : { "getblockindexstats", 0, "height" },
60 : { "getblockindexstats", 1, "range" },
61 : { "getblocktemplate", 0, "template_request" },
62 : { "getfeeinfo", 0, "blocks" },
63 : { "getshieldbalance", 1, "minconf" },
64 : { "getshieldbalance", 2, "include_watchonly" },
65 : { "getminedcommitment", 0, "llmq_type" },
66 : { "getnetworkhashps", 0, "nblocks" },
67 : { "getnetworkhashps", 1, "height" },
68 : { "getnodeaddresses", 0, "count" },
69 : { "getquorummembers", 0, "llmq_type" },
70 : { "getrawmempool", 0, "verbose" },
71 : { "getrawtransaction", 1, "verbose" },
72 : { "getreceivedbyaddress", 1, "minconf" },
73 : { "getreceivedbylabel", 1, "minconf" },
74 : { "getsaplingnotescount", 0, "minconf" },
75 : { "getsupplyinfo", 0, "force_update" },
76 : { "gettransaction", 1, "include_watchonly" },
77 : { "gettxout", 1, "n" },
78 : { "gettxout", 2, "include_mempool" },
79 : { "importaddress", 2, "rescan" },
80 : { "importaddress", 3, "p2sh" },
81 : { "importmulti", 0, "requests" },
82 : { "importmulti", 1, "options" },
83 : { "importprivkey", 2, "rescan" },
84 : { "importprivkey", 3, "is_staking_address" },
85 : { "importpubkey", 2, "rescan" },
86 : { "importsaplingkey", 1, "rescan" },
87 : { "importsaplingkey", 2, "height" },
88 : { "importsaplingviewingkey", 1, "rescan" },
89 : { "importsaplingviewingkey", 2, "height" },
90 : { "initmasternode", 2, "deterministic" },
91 : { "keypoolrefill", 0, "newsize" },
92 : { "listcoldutxos", 0, "not_whitelisted" },
93 : { "listdelegators", 0, "blacklist" },
94 : { "listreceivedbyaddress", 0, "minconf" },
95 : { "listreceivedbyaddress", 1, "include_empty" },
96 : { "listreceivedbyaddress", 2, "include_watchonly" },
97 : { "listreceivedbylabel", 0, "minconf" },
98 : { "listreceivedbylabel", 1, "include_empty" },
99 : { "listreceivedbylabel", 2, "include_watchonly" },
100 : { "listreceivedbyshieldaddress", 1, "minconf" },
101 : { "listshieldunspent", 0, "minconf" },
102 : { "listshieldunspent", 1, "maxconf" },
103 : { "listshieldunspent", 2, "include_watchonly" },
104 : { "listshieldunspent", 3, "addresses" },
105 : { "listsinceblock", 1, "target_confirmations" },
106 : { "listsinceblock", 2, "include_watchonly" },
107 : { "listtransactions", 1, "count" },
108 : { "listtransactions", 2, "from" },
109 : { "listtransactions", 3, "include_watchonly" },
110 : { "listtransactions", 4, "include_delegated" },
111 : { "listtransactions", 5, "include_cold" },
112 : { "listunspent", 0, "minconf" },
113 : { "listunspent", 1, "maxconf" },
114 : { "listunspent", 2, "addresses" },
115 : { "listunspent", 3, "watchonly_config" },
116 : { "listunspent", 4, "query_options" },
117 : { "listunspent", 5, "include_unsafe" },
118 : { "lockunspent", 0, "unlock" },
119 : { "lockunspent", 1, "transparent" },
120 : { "lockunspent", 2, "transactions" },
121 : { "logging", 0, "include" },
122 : { "logging", 1, "exclude" },
123 : { "mnbudgetvote", 4, "legacy" },
124 : { "mnbudgetrawvote", 1, "collat_vout" },
125 : { "mnbudgetrawvote", 4, "time" },
126 : { "preparebudget", 2, "npayments" },
127 : { "preparebudget", 3, "start" },
128 : { "preparebudget", 5, "montly_payment" },
129 : { "prioritisetransaction", 1, "fee_delta" },
130 : { "quorumdkgsimerror", 1, "rate" },
131 : { "quorumdkgstatus", 0, "detail_level" },
132 : { "listquorums", 0, "count" },
133 : { "getquoruminfo", 0, "llmqType" },
134 : { "getquoruminfo", 2, "includeSkShare" },
135 : { "signsession", 0, "llmqType"},
136 : { "hasrecoverysignature", 0, "llmqType" },
137 : { "issessionconflicting", 0, "llmqType" },
138 : { "rawdelegatestake", 1, "amount" },
139 : { "rawdelegatestake", 3, "ext_owner" },
140 : { "rawdelegatestake", 4, "include_delegated" },
141 : { "rawdelegatestake", 5, "from_shield" },
142 : { "rawdelegatestake", 6, "force" },
143 : { "rawshieldsendmany", 1, "amounts" },
144 : { "rawshieldsendmany", 2, "minconf" },
145 : { "rawshieldsendmany", 3, "fee" },
146 : { "rescanblockchain", 0, "start_height"},
147 : { "rescanblockchain", 1, "stop_height"},
148 : { "sendmany", 1, "amounts" },
149 : { "sendmany", 2, "minconf" },
150 : { "sendmany", 4, "include_delegated" },
151 : { "sendmany", 5, "subtract_fee_from" },
152 : { "scantxoutset", 1, "scanobjects" },
153 : { "sendrawtransaction", 1, "allowhighfees" },
154 : { "sendtoaddress", 1, "amount" },
155 : { "sendtoaddress", 4, "subtract_fee" },
156 : { "setautocombinethreshold", 0, "enable" },
157 : { "setautocombinethreshold", 1, "threshold" },
158 : { "setautocombinethreshold", 2, "frequency"},
159 : { "setnetworkactive", 0, "active" },
160 : { "setban", 2, "bantime" },
161 : { "setban", 3, "absolute" },
162 : { "setgenerate", 0, "generate" },
163 : { "setgenerate", 1, "genproclimit" },
164 : { "sethdseed", 0, "newkeypool" },
165 : { "setmocktime", 0, "timestamp" },
166 : { "setstakesplitthreshold", 0, "value" },
167 : { "settxfee", 0, "amount" },
168 : { "shieldsendmany", 1, "amounts" },
169 : { "shieldsendmany", 2, "minconf" },
170 : { "shieldsendmany", 3, "fee" },
171 : { "shieldsendmany", 4, "subtract_fee_from" },
172 : { "signrawtransaction", 1, "prevtxs" },
173 : { "signrawtransaction", 2, "privkeys" },
174 : { "spork", 1, "value" },
175 : { "startmasternode", 1, "lock_wallet" },
176 : { "startmasternode", 3, "reload_conf" },
177 : { "stop", 0, "wait" },
178 : { "submitbudget", 2, "npayments" },
179 : { "submitbudget", 3, "start" },
180 : { "submitbudget", 5, "montly_payment" },
181 : { "verifychain", 0, "nblocks" },
182 : { "waitforblock", 1, "timeout" },
183 : { "waitforblockheight", 0, "height" },
184 : { "waitforblockheight", 1, "timeout" },
185 : { "waitfornewblock", 0, "timeout" },
186 : { "walletpassphrase", 1, "timeout" },
187 : { "walletpassphrase", 2, "staking_only" },
188 : { "mnconnect", 1, "mn_list" },
189 : { "mnconnect", 2, "llmq_type" },
190 : // Echo with conversion (For testing only)
191 : { "echojson", 0, "arg0" },
192 : { "echojson", 1, "arg1" },
193 : { "echojson", 2, "arg2" },
194 : { "echojson", 3, "arg3" },
195 : { "echojson", 4, "arg4" },
196 : { "echojson", 5, "arg5" },
197 : { "echojson", 6, "arg6" },
198 : { "echojson", 7, "arg7" },
199 : { "echojson", 8, "arg8" },
200 : { "echojson", 9, "arg9" },
201 : };
202 : // clang-format on
203 :
204 : class CRPCConvertTable
205 : {
206 : private:
207 : std::set<std::pair<std::string, int>> members;
208 : std::set<std::pair<std::string, std::string>> membersByName;
209 :
210 : public:
211 : CRPCConvertTable();
212 :
213 2178 : bool convert(const std::string& method, int idx)
214 : {
215 4356 : return (members.count(std::make_pair(method, idx)) > 0);
216 : }
217 0 : bool convert(const std::string& method, const std::string& name)
218 : {
219 0 : return (membersByName.count(std::make_pair(method, name)) > 0);
220 : }
221 : };
222 :
223 91 : CRPCConvertTable::CRPCConvertTable()
224 : {
225 91 : const unsigned int n_elem =
226 : (sizeof(vRPCConvertParams) / sizeof(vRPCConvertParams[0]));
227 :
228 15561 : for (unsigned int i = 0; i < n_elem; i++) {
229 15470 : members.insert(std::make_pair(vRPCConvertParams[i].methodName,
230 30940 : vRPCConvertParams[i].paramIdx));
231 30940 : membersByName.insert(std::make_pair(vRPCConvertParams[i].methodName,
232 30940 : vRPCConvertParams[i].paramName));
233 : }
234 91 : }
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 101 : UniValue ParseNonRFCJSONValue(const std::string& strVal)
242 : {
243 177 : UniValue jVal;
244 227 : if (!jVal.read(std::string("[")+strVal+std::string("]")) ||
245 202 : !jVal.isArray() || jVal.size()!=1)
246 50 : throw std::runtime_error(std::string("Error parsing JSON:")+strVal);
247 152 : return jVal[0];
248 : }
249 :
250 2120 : UniValue RPCConvertValues(const std::string &strMethod, const std::vector<std::string> &strParams)
251 : {
252 2120 : UniValue params(UniValue::VARR);
253 :
254 4279 : for (unsigned int idx = 0; idx < strParams.size(); idx++) {
255 2178 : const std::string& strVal = strParams[idx];
256 :
257 2178 : if (!rpcCvtTable.convert(strMethod, idx)) {
258 : // insert string value directly
259 2086 : params.push_back(strVal);
260 : } else {
261 : // parse string as JSON, insert bool/number/object/etc. value
262 92 : params.push_back(ParseNonRFCJSONValue(strVal));
263 : }
264 : }
265 :
266 2101 : return params;
267 : }
268 :
269 0 : UniValue RPCConvertNamedValues(const std::string &strMethod, const std::vector<std::string> &strParams)
270 : {
271 0 : UniValue params(UniValue::VOBJ);
272 :
273 0 : for (const std::string &s: strParams) {
274 0 : size_t pos = s.find('=');
275 0 : 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 : }
278 :
279 0 : std::string name = s.substr(0, pos);
280 0 : std::string value = s.substr(pos+1);
281 :
282 0 : if (!rpcCvtTable.convert(strMethod, name)) {
283 : // insert string value directly
284 0 : params.pushKV(name, value);
285 : } else {
286 : // parse string as JSON, insert bool/number/object/etc. value
287 0 : params.pushKV(name, ParseNonRFCJSONValue(value));
288 : }
289 : }
290 :
291 0 : return params;
292 : }
|