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