Skip to content

Commit 9623314

Browse files
ryanofskyachow101
andcommitted
RPC: Allow RPC methods accepting options to take named parameters
Co-authored-by: Andrew Chow <github@achow101.com>
1 parent 702b56d commit 9623314

File tree

7 files changed

+97
-10
lines changed

7 files changed

+97
-10
lines changed

doc/release-notes-26485.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
JSON-RPC
2+
---
3+
4+
For RPC methods which accept `options` parameters ((`importmulti`, `listunspent`, `fundrawtransaction`, `bumpfee`, `send`, `sendall`, `walletcreatefundedpsbt`, `simulaterawtransaction`), it is now possible to pass the options as named parameters without the need for a nested object. (#26485)
5+
6+
This means it is possible make calls like:
7+
8+
```sh
9+
src/bitcoin-cli -named bumpfee txid fee_rate=100
10+
```
11+
12+
instead of
13+
14+
```sh
15+
src/bitcoin-cli -named bumpfee txid options='{"fee_rate": 100}'
16+
```

src/rpc/client.cpp

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,11 @@ static const CRPCConvertParam vRPCConvertParams[] =
101101
{ "listunspent", 2, "addresses" },
102102
{ "listunspent", 3, "include_unsafe" },
103103
{ "listunspent", 4, "query_options" },
104+
{ "listunspent", 4, "minimumAmount" },
105+
{ "listunspent", 4, "maximumAmount" },
106+
{ "listunspent", 4, "maximumCount" },
107+
{ "listunspent", 4, "minimumSumAmount" },
108+
{ "listunspent", 4, "include_immature_coinbase" },
104109
{ "getblock", 1, "verbosity" },
105110
{ "getblock", 1, "verbose" },
106111
{ "getblockheader", 1, "verbose" },
@@ -124,11 +129,38 @@ static const CRPCConvertParam vRPCConvertParams[] =
124129
{ "submitpackage", 0, "package" },
125130
{ "combinerawtransaction", 0, "txs" },
126131
{ "fundrawtransaction", 1, "options" },
132+
{ "fundrawtransaction", 1, "add_inputs"},
133+
{ "fundrawtransaction", 1, "include_unsafe"},
134+
{ "fundrawtransaction", 1, "minconf"},
135+
{ "fundrawtransaction", 1, "maxconf"},
136+
{ "fundrawtransaction", 1, "changePosition"},
137+
{ "fundrawtransaction", 1, "includeWatching"},
138+
{ "fundrawtransaction", 1, "lockUnspents"},
139+
{ "fundrawtransaction", 1, "fee_rate"},
140+
{ "fundrawtransaction", 1, "feeRate"},
141+
{ "fundrawtransaction", 1, "subtractFeeFromOutputs"},
142+
{ "fundrawtransaction", 1, "input_weights"},
143+
{ "fundrawtransaction", 1, "conf_target"},
144+
{ "fundrawtransaction", 1, "replaceable"},
145+
{ "fundrawtransaction", 1, "solving_data"},
127146
{ "fundrawtransaction", 2, "iswitness" },
128147
{ "walletcreatefundedpsbt", 0, "inputs" },
129148
{ "walletcreatefundedpsbt", 1, "outputs" },
130149
{ "walletcreatefundedpsbt", 2, "locktime" },
131150
{ "walletcreatefundedpsbt", 3, "options" },
151+
{ "walletcreatefundedpsbt", 3, "add_inputs"},
152+
{ "walletcreatefundedpsbt", 3, "include_unsafe"},
153+
{ "walletcreatefundedpsbt", 3, "minconf"},
154+
{ "walletcreatefundedpsbt", 3, "maxconf"},
155+
{ "walletcreatefundedpsbt", 3, "changePosition"},
156+
{ "walletcreatefundedpsbt", 3, "includeWatching"},
157+
{ "walletcreatefundedpsbt", 3, "lockUnspents"},
158+
{ "walletcreatefundedpsbt", 3, "fee_rate"},
159+
{ "walletcreatefundedpsbt", 3, "feeRate"},
160+
{ "walletcreatefundedpsbt", 3, "subtractFeeFromOutputs"},
161+
{ "walletcreatefundedpsbt", 3, "conf_target"},
162+
{ "walletcreatefundedpsbt", 3, "replaceable"},
163+
{ "walletcreatefundedpsbt", 3, "solving_data"},
132164
{ "walletcreatefundedpsbt", 4, "bip32derivs" },
133165
{ "walletprocesspsbt", 1, "sign" },
134166
{ "walletprocesspsbt", 3, "bip32derivs" },
@@ -154,18 +186,49 @@ static const CRPCConvertParam vRPCConvertParams[] =
154186
{ "send", 1, "conf_target" },
155187
{ "send", 3, "fee_rate"},
156188
{ "send", 4, "options" },
189+
{ "send", 4, "add_inputs"},
190+
{ "send", 4, "include_unsafe"},
191+
{ "send", 4, "minconf"},
192+
{ "send", 4, "maxconf"},
193+
{ "send", 4, "add_to_wallet"},
194+
{ "send", 4, "change_position"},
195+
{ "send", 4, "fee_rate"},
196+
{ "send", 4, "include_watching"},
197+
{ "send", 4, "inputs"},
198+
{ "send", 4, "locktime"},
199+
{ "send", 4, "lock_unspents"},
200+
{ "send", 4, "psbt"},
201+
{ "send", 4, "subtract_fee_from_outputs"},
202+
{ "send", 4, "conf_target"},
203+
{ "send", 4, "replaceable"},
204+
{ "send", 4, "solving_data"},
157205
{ "sendall", 0, "recipients" },
158206
{ "sendall", 1, "conf_target" },
159207
{ "sendall", 3, "fee_rate"},
160208
{ "sendall", 4, "options" },
209+
{ "sendall", 4, "add_to_wallet"},
210+
{ "sendall", 4, "fee_rate"},
211+
{ "sendall", 4, "include_watching"},
212+
{ "sendall", 4, "inputs"},
213+
{ "sendall", 4, "locktime"},
214+
{ "sendall", 4, "lock_unspents"},
215+
{ "sendall", 4, "psbt"},
216+
{ "sendall", 4, "send_max"},
217+
{ "sendall", 4, "minconf"},
218+
{ "sendall", 4, "maxconf"},
219+
{ "sendall", 4, "conf_target"},
220+
{ "sendall", 4, "replaceable"},
221+
{ "sendall", 4, "solving_data"},
161222
{ "simulaterawtransaction", 0, "rawtxs" },
162223
{ "simulaterawtransaction", 1, "options" },
224+
{ "simulaterawtransaction", 1, "include_watchonly"},
163225
{ "importprivkey", 2, "rescan" },
164226
{ "importaddress", 2, "rescan" },
165227
{ "importaddress", 3, "p2sh" },
166228
{ "importpubkey", 2, "rescan" },
167229
{ "importmulti", 0, "requests" },
168230
{ "importmulti", 1, "options" },
231+
{ "importmulti", 1, "rescan" },
169232
{ "importdescriptors", 0, "requests" },
170233
{ "listdescriptors", 0, "private" },
171234
{ "verifychain", 0, "checklevel" },
@@ -189,7 +252,15 @@ static const CRPCConvertParam vRPCConvertParams[] =
189252
{ "getmempooldescendants", 1, "verbose" },
190253
{ "gettxspendingprevout", 0, "outputs" },
191254
{ "bumpfee", 1, "options" },
255+
{ "bumpfee", 1, "conf_target"},
256+
{ "bumpfee", 1, "fee_rate"},
257+
{ "bumpfee", 1, "replaceable"},
258+
{ "bumpfee", 1, "outputs"},
192259
{ "psbtbumpfee", 1, "options" },
260+
{ "psbtbumpfee", 1, "conf_target"},
261+
{ "psbtbumpfee", 1, "fee_rate"},
262+
{ "psbtbumpfee", 1, "replaceable"},
263+
{ "psbtbumpfee", 1, "outputs"},
193264
{ "logging", 0, "include" },
194265
{ "logging", 1, "exclude" },
195266
{ "disconnectnode", 1, "nodeid" },

src/wallet/rpc/backup.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1298,7 +1298,7 @@ RPCHelpMan importmulti()
12981298
},
12991299
},
13001300
RPCArgOptions{.oneline_description="\"requests\""}},
1301-
{"options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
1301+
{"options", RPCArg::Type::OBJ_NAMED_PARAMS, RPCArg::Optional::OMITTED, "",
13021302
{
13031303
{"rescan", RPCArg::Type::BOOL, RPCArg::Default{true}, "Scan the chain and mempool for wallet transactions after all imports."},
13041304
},

src/wallet/rpc/coins.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -513,7 +513,7 @@ RPCHelpMan listunspent()
513513
},
514514
{"include_unsafe", RPCArg::Type::BOOL, RPCArg::Default{true}, "Include outputs that are not safe to spend\n"
515515
"See description of \"safe\" attribute below."},
516-
{"query_options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "JSON with query options",
516+
{"query_options", RPCArg::Type::OBJ_NAMED_PARAMS, RPCArg::Optional::OMITTED, "",
517517
{
518518
{"minimumAmount", RPCArg::Type::AMOUNT, RPCArg::Default{FormatMoney(0)}, "Minimum value of each UTXO in " + CURRENCY_UNIT + ""},
519519
{"maximumAmount", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"unlimited"}, "Maximum value of each UTXO in " + CURRENCY_UNIT + ""},

src/wallet/rpc/spend.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -758,7 +758,7 @@ RPCHelpMan fundrawtransaction()
758758
"Only pay-to-pubkey, multisig, and P2SH versions thereof are currently supported for watch-only\n",
759759
{
760760
{"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hex string of the raw transaction"},
761-
{"options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "for backward compatibility: passing in a true instead of an object will result in {\"includeWatching\":true}",
761+
{"options", RPCArg::Type::OBJ_NAMED_PARAMS, RPCArg::Optional::OMITTED, "For backward compatibility: passing in a true instead of an object will result in {\"includeWatching\":true}",
762762
Cat<std::vector<RPCArg>>(
763763
{
764764
{"add_inputs", RPCArg::Type::BOOL, RPCArg::Default{true}, "For a transaction with existing inputs, automatically include more if they are not enough."},
@@ -997,7 +997,7 @@ static RPCHelpMan bumpfee_helper(std::string method_name)
997997
"* WARNING: before version 0.21, fee_rate was in " + CURRENCY_UNIT + "/kvB. As of 0.21, fee_rate is in " + CURRENCY_ATOM + "/vB. *\n",
998998
{
999999
{"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The txid to be bumped"},
1000-
{"options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
1000+
{"options", RPCArg::Type::OBJ_NAMED_PARAMS, RPCArg::Optional::OMITTED, "",
10011001
{
10021002
{"conf_target", RPCArg::Type::NUM, RPCArg::DefaultHint{"wallet -txconfirmtarget"}, "Confirmation target in blocks\n"},
10031003
{"fee_rate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"},
@@ -1187,7 +1187,7 @@ RPCHelpMan send()
11871187
{"estimate_mode", RPCArg::Type::STR, RPCArg::Default{"unset"}, "The fee estimate mode, must be one of (case insensitive):\n"
11881188
"\"" + FeeModes("\"\n\"") + "\""},
11891189
{"fee_rate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_ATOM + "/vB."},
1190-
{"options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
1190+
{"options", RPCArg::Type::OBJ_NAMED_PARAMS, RPCArg::Optional::OMITTED, "",
11911191
Cat<std::vector<RPCArg>>(
11921192
{
11931193
{"add_inputs", RPCArg::Type::BOOL, RPCArg::DefaultHint{"false when \"inputs\" are specified, true otherwise"},"Automatically include coins from the wallet to cover the target amount.\n"},
@@ -1302,7 +1302,7 @@ RPCHelpMan sendall()
13021302
"\"" + FeeModes("\"\n\"") + "\""},
13031303
{"fee_rate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_ATOM + "/vB."},
13041304
{
1305-
"options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
1305+
"options", RPCArg::Type::OBJ_NAMED_PARAMS, RPCArg::Optional::OMITTED, "",
13061306
Cat<std::vector<RPCArg>>(
13071307
{
13081308
{"add_to_wallet", RPCArg::Type::BOOL, RPCArg::Default{true}, "When false, returns the serialized transaction without broadcasting or adding it to the wallet"},
@@ -1635,7 +1635,7 @@ RPCHelpMan walletcreatefundedpsbt()
16351635
OutputsDoc(),
16361636
RPCArgOptions{.skip_type_check = true}},
16371637
{"locktime", RPCArg::Type::NUM, RPCArg::Default{0}, "Raw locktime. Non-0 value also locktime-activates inputs"},
1638-
{"options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
1638+
{"options", RPCArg::Type::OBJ_NAMED_PARAMS, RPCArg::Optional::OMITTED, "",
16391639
Cat<std::vector<RPCArg>>(
16401640
{
16411641
{"add_inputs", RPCArg::Type::BOOL, RPCArg::DefaultHint{"false when \"inputs\" are specified, true otherwise"}, "Automatically include coins from the wallet to cover the target amount.\n"},

src/wallet/rpc/wallet.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -645,7 +645,7 @@ RPCHelpMan simulaterawtransaction()
645645
{"rawtx", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, ""},
646646
},
647647
},
648-
{"options", RPCArg::Type::OBJ_USER_KEYS, RPCArg::Optional::OMITTED, "Options",
648+
{"options", RPCArg::Type::OBJ_NAMED_PARAMS, RPCArg::Optional::OMITTED, "",
649649
{
650650
{"include_watchonly", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for watch-only wallets, otherwise false"}, "Whether to include watch-only addresses (see RPC importaddress)"},
651651
},

test/functional/rpc_help.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,8 @@ def test_client_conversion_table(self):
8585

8686
for argname, convert in converts_by_argname.items():
8787
if all(convert) != any(convert):
88-
# Only allow dummy to fail consistency check
89-
assert argname == 'dummy', ('WARNING: conversion mismatch for argument named %s (%s)' % (argname, list(zip(all_methods_by_argname[argname], converts_by_argname[argname]))))
88+
# Only allow dummy and psbt to fail consistency check
89+
assert argname in ['dummy', "psbt"], ('WARNING: conversion mismatch for argument named %s (%s)' % (argname, list(zip(all_methods_by_argname[argname], converts_by_argname[argname]))))
9090

9191
def test_categories(self):
9292
node = self.nodes[0]

0 commit comments

Comments
 (0)