Skip to content

Commit 655146d

Browse files
laanwjknst
authored andcommitted
Merge bitcoin#21302: wallet: createwallet examples for descriptor wallets
5039e0e test: HelpExampleCliNamed and HelpExampleRpcNamed (Ivan Metlushko) 591735e rpc: Add HelpExampleCliNamed and use it for `createwallet` doc (Wladimir J. van der Laan) 5d5a90e rpc: Add HelpExampleRpcNamed (Ivan Metlushko) Pull request description: Rationale: make descriptor wallets more visible and just a bit easier to setup `bitcoin-cli help createwallet` **Before**: ``` Examples: > bitcoin-cli createwallet "testwallet" > curl --user myusername --data-binary '{"jsonrpc": "1.0", "id": "curltest", "method": "createwallet", "params": ["testwallet"]}' -H 'content-type: text/plain;' http://127.0.0.1:8332/ ``` **After** ``` Examples: > bitcoin-cli createwallet "testwallet" > curl --user myusername --data-binary '{"jsonrpc": "1.0", "id": "curltest", "method": "createwallet", "params": ["testwallet"]}' -H 'content-type: text/plain;' http://127.0.0.1:8332/ > bitcoin-cli createwallet "descriptors" false false "" true true true > curl --user myusername --data-binary '{"jsonrpc": "1.0", "id": "curltest", "method": "createwallet", "params": ["descriptors", false, false, "", true, true, true]}' -H 'content-type: text/plain;' http://127.0.0.1:8332/ ``` ACKs for top commit: laanwj: Tested ACK 5039e0e Tree-SHA512: d37210e6ce639addee881377092d8f6fb2a537a60a259c561899e24cf68a0254d7ff45a213573c938f626677e46770cd21113aae5974f26c66b9a2e137699c14
1 parent 99a8b60 commit 655146d

File tree

4 files changed

+104
-0
lines changed

4 files changed

+104
-0
lines changed

src/rpc/util.cpp

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,18 +158,81 @@ bool ParseBoolV(const UniValue& v, const std::string &strName)
158158
throw JSONRPCError(RPC_INVALID_PARAMETER, strName+" must be true, false, yes, no, 1 or 0 (not '"+strBool+"')");
159159
}
160160

161+
namespace {
162+
163+
/**
164+
* Quote an argument for shell.
165+
*
166+
* @note This is intended for help, not for security-sensitive purposes.
167+
*/
168+
std::string ShellQuote(const std::string& s)
169+
{
170+
std::string result;
171+
result.reserve(s.size() * 2);
172+
for (const char ch: s) {
173+
if (ch == '\'') {
174+
result += "'\''";
175+
} else {
176+
result += ch;
177+
}
178+
}
179+
return "'" + result + "'";
180+
}
181+
182+
/**
183+
* Shell-quotes the argument if it needs quoting, else returns it literally, to save typing.
184+
*
185+
* @note This is intended for help, not for security-sensitive purposes.
186+
*/
187+
std::string ShellQuoteIfNeeded(const std::string& s)
188+
{
189+
for (const char ch: s) {
190+
if (ch == ' ' || ch == '\'' || ch == '"') {
191+
return ShellQuote(s);
192+
}
193+
}
194+
195+
return s;
196+
}
197+
198+
}
199+
161200
std::string HelpExampleCli(const std::string& methodname, const std::string& args)
162201
{
163202
return "> dash-cli " + methodname + " " + args + "\n";
164203
}
165204

205+
std::string HelpExampleCliNamed(const std::string& methodname, const RPCArgList& args)
206+
{
207+
std::string result = "> dash-cli -named " + methodname;
208+
for (const auto& argpair: args) {
209+
const auto& value = argpair.second.isStr()
210+
? argpair.second.get_str()
211+
: argpair.second.write();
212+
result += " " + argpair.first + "=" + ShellQuoteIfNeeded(value);
213+
}
214+
result += "\n";
215+
return result;
216+
}
217+
166218
std::string HelpExampleRpc(const std::string& methodname, const std::string& args)
167219
{
168220
return "> curl --user myusername --data-binary '{\"jsonrpc\": \"1.0\", \"id\": \"curltest\", "
169221
"\"method\": \"" + methodname + "\", \"params\": [" + args + "]}' -H 'content-type: text/plain;'"
170222
" http://127.0.0.1:9998/\n";
171223
}
172224

225+
std::string HelpExampleRpcNamed(const std::string& methodname, const RPCArgList& args)
226+
{
227+
UniValue params(UniValue::VOBJ);
228+
for (const auto& param: args) {
229+
params.pushKV(param.first, param.second);
230+
}
231+
232+
return "> curl --user myusername --data-binary '{\"jsonrpc\": \"1.0\", \"id\": \"curltest\", "
233+
"\"method\": \"" + methodname + "\", \"params\": " + params.write() + "}' -H 'content-type: text/plain;' http://127.0.0.1:8332/\n";
234+
}
235+
173236
// Converts a hex string to a public key if possible
174237
CPubKey HexToPubKey(const std::string& hex_in)
175238
{

src/rpc/util.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,12 @@ extern double ParseDoubleV(const UniValue& v, const std::string &strName);
8585
extern bool ParseBoolV(const UniValue& v, const std::string &strName);
8686

8787
extern CAmount AmountFromValue(const UniValue& value);
88+
89+
using RPCArgList = std::vector<std::pair<std::string, UniValue>>;
8890
extern std::string HelpExampleCli(const std::string& methodname, const std::string& args);
91+
extern std::string HelpExampleCliNamed(const std::string& methodname, const RPCArgList& args);
8992
extern std::string HelpExampleRpc(const std::string& methodname, const std::string& args);
93+
extern std::string HelpExampleRpcNamed(const std::string& methodname, const RPCArgList& args);
9094

9195
CPubKey HexToPubKey(const std::string& hex_in);
9296
CPubKey AddrToPubKey(const FillableSigningProvider& keystore, const std::string& addr_in);

src/test/rpc_tests.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -481,6 +481,41 @@ BOOST_AUTO_TEST_CASE(rpc_getblockstats_calculate_percentiles_by_size)
481481
}
482482
}
483483

484+
BOOST_AUTO_TEST_CASE(help_example)
485+
{
486+
// test different argument types
487+
const RPCArgList& args = {{"foo", "bar"}, {"b", true}, {"n", 1}};
488+
BOOST_CHECK_EQUAL(HelpExampleCliNamed("test", args), "> dash-cli -named test foo=bar b=true n=1\n");
489+
BOOST_CHECK_EQUAL(HelpExampleRpcNamed("test", args), "> curl --user myusername --data-binary '{\"jsonrpc\": \"1.0\", \"id\": \"curltest\", \"method\": \"test\", \"params\": {\"foo\":\"bar\",\"b\":true,\"n\":1}}' -H 'content-type: text/plain;' http://127.0.0.1:8332/\n");
490+
491+
// test shell escape
492+
BOOST_CHECK_EQUAL(HelpExampleCliNamed("test", {{"foo", "b'ar"}}), "> dash-cli -named test foo='b'''ar'\n");
493+
BOOST_CHECK_EQUAL(HelpExampleCliNamed("test", {{"foo", "b\"ar"}}), "> dash-cli -named test foo='b\"ar'\n");
494+
BOOST_CHECK_EQUAL(HelpExampleCliNamed("test", {{"foo", "b ar"}}), "> dash-cli -named test foo='b ar'\n");
495+
496+
// test object params
497+
UniValue obj_value(UniValue::VOBJ);
498+
obj_value.pushKV("foo", "bar");
499+
obj_value.pushKV("b", false);
500+
obj_value.pushKV("n", 1);
501+
BOOST_CHECK_EQUAL(HelpExampleCliNamed("test", {{"name", obj_value}}), "> dash-cli -named test name='{\"foo\":\"bar\",\"b\":false,\"n\":1}'\n");
502+
BOOST_CHECK_EQUAL(HelpExampleRpcNamed("test", {{"name", obj_value}}), "> curl --user myusername --data-binary '{\"jsonrpc\": \"1.0\", \"id\": \"curltest\", \"method\": \"test\", \"params\": {\"name\":{\"foo\":\"bar\",\"b\":false,\"n\":1}}}' -H 'content-type: text/plain;' http://127.0.0.1:8332/\n");
503+
504+
// test array params
505+
UniValue arr_value(UniValue::VARR);
506+
arr_value.push_back("bar");
507+
arr_value.push_back(false);
508+
arr_value.push_back(1);
509+
BOOST_CHECK_EQUAL(HelpExampleCliNamed("test", {{"name", arr_value}}), "> dash-cli -named test name='[\"bar\",false,1]'\n");
510+
BOOST_CHECK_EQUAL(HelpExampleRpcNamed("test", {{"name", arr_value}}), "> curl --user myusername --data-binary '{\"jsonrpc\": \"1.0\", \"id\": \"curltest\", \"method\": \"test\", \"params\": {\"name\":[\"bar\",false,1]}}' -H 'content-type: text/plain;' http://127.0.0.1:8332/\n");
511+
512+
// test types don't matter for shell
513+
BOOST_CHECK_EQUAL(HelpExampleCliNamed("foo", {{"arg", true}}), HelpExampleCliNamed("foo", {{"arg", "true"}}));
514+
515+
// test types matter for Rpc
516+
BOOST_CHECK_NE(HelpExampleRpcNamed("foo", {{"arg", true}}), HelpExampleRpcNamed("foo", {{"arg", "true"}}));
517+
}
518+
484519
BOOST_AUTO_TEST_CASE(rpc_bls)
485520
{
486521
UniValue r;

src/wallet/rpcwallet.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2992,6 +2992,8 @@ static RPCHelpMan createwallet()
29922992
RPCExamples{
29932993
HelpExampleCli("createwallet", "\"testwallet\"")
29942994
+ HelpExampleRpc("createwallet", "\"testwallet\"")
2995+
+ HelpExampleCliNamed("createwallet", {{"wallet_name", "descriptors"}, {"avoid_reuse", true}, {"descriptors", true}, {"load_on_startup", true}})
2996+
+ HelpExampleRpcNamed("createwallet", {{"wallet_name", "descriptors"}, {"avoid_reuse", true}, {"descriptors", true}, {"load_on_startup", true}})
29952997
},
29962998
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
29972999
{

0 commit comments

Comments
 (0)