Skip to content

Commit 5c9b06d

Browse files
committed
Merge #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
2 parents 824eea5 + 5039e0e commit 5c9b06d

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
@@ -113,17 +113,80 @@ std::vector<unsigned char> ParseHexO(const UniValue& o, std::string strKey)
113113
return ParseHexV(find_value(o, strKey), strKey);
114114
}
115115

116+
namespace {
117+
118+
/**
119+
* Quote an argument for shell.
120+
*
121+
* @note This is intended for help, not for security-sensitive purposes.
122+
*/
123+
std::string ShellQuote(const std::string& s)
124+
{
125+
std::string result;
126+
result.reserve(s.size() * 2);
127+
for (const char ch: s) {
128+
if (ch == '\'') {
129+
result += "'\''";
130+
} else {
131+
result += ch;
132+
}
133+
}
134+
return "'" + result + "'";
135+
}
136+
137+
/**
138+
* Shell-quotes the argument if it needs quoting, else returns it literally, to save typing.
139+
*
140+
* @note This is intended for help, not for security-sensitive purposes.
141+
*/
142+
std::string ShellQuoteIfNeeded(const std::string& s)
143+
{
144+
for (const char ch: s) {
145+
if (ch == ' ' || ch == '\'' || ch == '"') {
146+
return ShellQuote(s);
147+
}
148+
}
149+
150+
return s;
151+
}
152+
153+
}
154+
116155
std::string HelpExampleCli(const std::string& methodname, const std::string& args)
117156
{
118157
return "> bitcoin-cli " + methodname + " " + args + "\n";
119158
}
120159

160+
std::string HelpExampleCliNamed(const std::string& methodname, const RPCArgList& args)
161+
{
162+
std::string result = "> bitcoin-cli -named " + methodname;
163+
for (const auto& argpair: args) {
164+
const auto& value = argpair.second.isStr()
165+
? argpair.second.get_str()
166+
: argpair.second.write();
167+
result += " " + argpair.first + "=" + ShellQuoteIfNeeded(value);
168+
}
169+
result += "\n";
170+
return result;
171+
}
172+
121173
std::string HelpExampleRpc(const std::string& methodname, const std::string& args)
122174
{
123175
return "> curl --user myusername --data-binary '{\"jsonrpc\": \"1.0\", \"id\": \"curltest\", "
124176
"\"method\": \"" + methodname + "\", \"params\": [" + args + "]}' -H 'content-type: text/plain;' http://127.0.0.1:8332/\n";
125177
}
126178

179+
std::string HelpExampleRpcNamed(const std::string& methodname, const RPCArgList& args)
180+
{
181+
UniValue params(UniValue::VOBJ);
182+
for (const auto& param: args) {
183+
params.pushKV(param.first, param.second);
184+
}
185+
186+
return "> curl --user myusername --data-binary '{\"jsonrpc\": \"1.0\", \"id\": \"curltest\", "
187+
"\"method\": \"" + methodname + "\", \"params\": " + params.write() + "}' -H 'content-type: text/plain;' http://127.0.0.1:8332/\n";
188+
}
189+
127190
// Converts a hex string to a public key if possible
128191
CPubKey HexToPubKey(const std::string& hex_in)
129192
{

src/rpc/util.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,12 @@ extern std::vector<unsigned char> ParseHexV(const UniValue& v, std::string strNa
7878
extern std::vector<unsigned char> ParseHexO(const UniValue& o, std::string strKey);
7979

8080
extern CAmount AmountFromValue(const UniValue& value);
81+
82+
using RPCArgList = std::vector<std::pair<std::string, UniValue>>;
8183
extern std::string HelpExampleCli(const std::string& methodname, const std::string& args);
84+
extern std::string HelpExampleCliNamed(const std::string& methodname, const RPCArgList& args);
8285
extern std::string HelpExampleRpc(const std::string& methodname, const std::string& args);
86+
extern std::string HelpExampleRpcNamed(const std::string& methodname, const RPCArgList& args);
8387

8488
CPubKey HexToPubKey(const std::string& hex_in);
8589
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
@@ -431,4 +431,39 @@ BOOST_AUTO_TEST_CASE(rpc_getblockstats_calculate_percentiles_by_weight)
431431
}
432432
}
433433

434+
BOOST_AUTO_TEST_CASE(help_example)
435+
{
436+
// test different argument types
437+
const RPCArgList& args = {{"foo", "bar"}, {"b", true}, {"n", 1}};
438+
BOOST_CHECK_EQUAL(HelpExampleCliNamed("test", args), "> bitcoin-cli -named test foo=bar b=true n=1\n");
439+
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");
440+
441+
// test shell escape
442+
BOOST_CHECK_EQUAL(HelpExampleCliNamed("test", {{"foo", "b'ar"}}), "> bitcoin-cli -named test foo='b'''ar'\n");
443+
BOOST_CHECK_EQUAL(HelpExampleCliNamed("test", {{"foo", "b\"ar"}}), "> bitcoin-cli -named test foo='b\"ar'\n");
444+
BOOST_CHECK_EQUAL(HelpExampleCliNamed("test", {{"foo", "b ar"}}), "> bitcoin-cli -named test foo='b ar'\n");
445+
446+
// test object params
447+
UniValue obj_value(UniValue::VOBJ);
448+
obj_value.pushKV("foo", "bar");
449+
obj_value.pushKV("b", false);
450+
obj_value.pushKV("n", 1);
451+
BOOST_CHECK_EQUAL(HelpExampleCliNamed("test", {{"name", obj_value}}), "> bitcoin-cli -named test name='{\"foo\":\"bar\",\"b\":false,\"n\":1}'\n");
452+
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");
453+
454+
// test array params
455+
UniValue arr_value(UniValue::VARR);
456+
arr_value.push_back("bar");
457+
arr_value.push_back(false);
458+
arr_value.push_back(1);
459+
BOOST_CHECK_EQUAL(HelpExampleCliNamed("test", {{"name", arr_value}}), "> bitcoin-cli -named test name='[\"bar\",false,1]'\n");
460+
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");
461+
462+
// test types don't matter for shell
463+
BOOST_CHECK_EQUAL(HelpExampleCliNamed("foo", {{"arg", true}}), HelpExampleCliNamed("foo", {{"arg", "true"}}));
464+
465+
// test types matter for Rpc
466+
BOOST_CHECK_NE(HelpExampleRpcNamed("foo", {{"arg", true}}), HelpExampleRpcNamed("foo", {{"arg", "true"}}));
467+
}
468+
434469
BOOST_AUTO_TEST_SUITE_END()

src/wallet/rpcwallet.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2711,6 +2711,8 @@ static RPCHelpMan createwallet()
27112711
RPCExamples{
27122712
HelpExampleCli("createwallet", "\"testwallet\"")
27132713
+ HelpExampleRpc("createwallet", "\"testwallet\"")
2714+
+ HelpExampleCliNamed("createwallet", {{"wallet_name", "descriptors"}, {"avoid_reuse", true}, {"descriptors", true}, {"load_on_startup", true}})
2715+
+ HelpExampleRpcNamed("createwallet", {{"wallet_name", "descriptors"}, {"avoid_reuse", true}, {"descriptors", true}, {"load_on_startup", true}})
27142716
},
27152717
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
27162718
{

0 commit comments

Comments
 (0)