Skip to content

Commit ca7162c

Browse files
committed
Merge bitcoin/bitcoin#35868: rpc, wallet: fix invalid JSON in HelpExampleRpc curl examples
21d4e0b rpc, wallet, test: fix invalid JSON in HelpExampleRpc curl examples (GuTS805) Pull request description: Several `HelpExampleRpc` call sites reused CLI-style argument strings verbatim instead of valid JSON — missing commas, bare unquoted words, or single backslashes that are not valid JSON escapes. As a result the documented `curl` command for 14 RPCs (`getblockfrompeer`, `addnode`, `addconnection`, `sendmsgtopeer`, `restorewallet`, `getmempoolcluster`, `importmempool`, `getindexinfo`, `listlabels`, `unloadwallet`, `createwalletdescriptor`, `addhdkey`, `loadwallet`, `listunspent`) fails to parse as JSON if copy-pasted as-is. Also fixes a stray trailing quote in the `restorewallet` named-argument examples. This was previously raised in #31275, which sipa confirmed at runtime by adding a `UniValue::read` check, but that PR was closed unmerged. Since then two more examples broke the same way (`getmempoolcluster`, `addhdkey`), which is why this adds a permanent regression check to `rpc_help.py::dump_help()` instead of just fixing the current list. Fixes #35864. ACKs for top commit: maflcko: review ACK 21d4e0b 🚝 sedited: ACK 21d4e0b Tree-SHA512: 2a8abc07d681b9dc81b8079a68421278da890049cea33a1561a48d53cbf919a30df588f559e9df94fa4a1ab7027f742f3b12c163afc25246a620340cb3522336
2 parents d0e777b + 21d4e0b commit ca7162c

9 files changed

Lines changed: 26 additions & 17 deletions

File tree

src/rpc/blockchain.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -540,7 +540,7 @@ static RPCMethod getblockfrompeer()
540540
RPCResult{RPCResult::Type::OBJ, "", /*optional=*/false, "", {}},
541541
RPCExamples{
542542
HelpExampleCli("getblockfrompeer", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\" 0")
543-
+ HelpExampleRpc("getblockfrompeer", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\" 0")
543+
+ HelpExampleRpc("getblockfrompeer", R"("00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09", 0)")
544544
},
545545
[](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue
546546
{

src/rpc/mempool.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -872,7 +872,7 @@ static RPCMethod getmempoolcluster()
872872
RPCResult::Type::OBJ, "", "", ClusterDescription()},
873873
RPCExamples{
874874
HelpExampleCli("getmempoolcluster", "txid")
875-
+ HelpExampleRpc("getmempoolcluster", "txid")
875+
+ HelpExampleRpc("getmempoolcluster", R"("txid")")
876876
},
877877
[](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue
878878
{
@@ -1169,7 +1169,7 @@ static RPCMethod importmempool()
11691169
RPCArgOptions{.oneline_description = "options"}},
11701170
},
11711171
RPCResult{RPCResult::Type::OBJ, "", "", std::vector<RPCResult>{}},
1172-
RPCExamples{HelpExampleCli("importmempool", "/path/to/mempool.dat") + HelpExampleRpc("importmempool", "/path/to/mempool.dat")},
1172+
RPCExamples{HelpExampleCli("importmempool", "/path/to/mempool.dat") + HelpExampleRpc("importmempool", R"("/path/to/mempool.dat")")},
11731173
[](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue {
11741174
const NodeContext& node{EnsureAnyNodeContext(request.context)};
11751175

src/rpc/net.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -335,7 +335,7 @@ static RPCMethod addnode()
335335
RPCResult{RPCResult::Type::NONE, "", ""},
336336
RPCExamples{
337337
HelpExampleCli("addnode", "\"192.168.0.6:8333\" \"onetry\" true")
338-
+ HelpExampleRpc("addnode", "\"192.168.0.6:8333\", \"onetry\" true")
338+
+ HelpExampleRpc("addnode", R"("192.168.0.6:8333", "onetry", true)")
339339
},
340340
[](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue
341341
{
@@ -410,7 +410,7 @@ static RPCMethod addconnection()
410410
}},
411411
RPCExamples{
412412
HelpExampleCli("addconnection", "\"192.168.0.6:8333\" \"outbound-full-relay\" true")
413-
+ HelpExampleRpc("addconnection", "\"192.168.0.6:8333\" \"outbound-full-relay\" true")
413+
+ HelpExampleRpc("addconnection", R"("192.168.0.6:8333", "outbound-full-relay", true)")
414414
},
415415
[](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue
416416
{
@@ -1083,7 +1083,7 @@ static RPCMethod sendmsgtopeer()
10831083
},
10841084
RPCResult{RPCResult::Type::OBJ, "", "", std::vector<RPCResult>{}},
10851085
RPCExamples{
1086-
HelpExampleCli("sendmsgtopeer", "0 \"addr\" \"ffffff\"") + HelpExampleRpc("sendmsgtopeer", "0 \"addr\" \"ffffff\"")},
1086+
HelpExampleCli("sendmsgtopeer", "0 \"addr\" \"ffffff\"") + HelpExampleRpc("sendmsgtopeer", R"(0, "addr", "ffffff")")},
10871087
[](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue {
10881088
const NodeId peer_id{request.params[0].getInt<int64_t>()};
10891089
const auto msg_type{self.Arg<std::string_view>("msg_type")};

src/rpc/node.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -378,7 +378,7 @@ static RPCMethod getindexinfo()
378378
HelpExampleCli("getindexinfo", "")
379379
+ HelpExampleRpc("getindexinfo", "")
380380
+ HelpExampleCli("getindexinfo", "txindex")
381-
+ HelpExampleRpc("getindexinfo", "txindex")
381+
+ HelpExampleRpc("getindexinfo", R"("txindex")")
382382
},
383383
[](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue
384384
{

src/wallet/rpc/addresses.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -642,7 +642,7 @@ RPCMethod listlabels()
642642
"\nList labels that have sending addresses\n"
643643
+ HelpExampleCli("listlabels", "send") +
644644
"\nAs a JSON-RPC call\n"
645-
+ HelpExampleRpc("listlabels", "receive")
645+
+ HelpExampleRpc("listlabels", R"("receive")")
646646
},
647647
[](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue
648648
{

src/wallet/rpc/backup.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -618,9 +618,9 @@ RPCMethod restorewallet()
618618
},
619619
RPCExamples{
620620
HelpExampleCli("restorewallet", "\"testwallet\" \"home\\backups\\backup-file.bak\"")
621-
+ HelpExampleRpc("restorewallet", "\"testwallet\" \"home\\backups\\backup-file.bak\"")
622-
+ HelpExampleCliNamed("restorewallet", {{"wallet_name", "testwallet"}, {"backup_file", "home\\backups\\backup-file.bak\""}, {"load_on_startup", true}})
623-
+ HelpExampleRpcNamed("restorewallet", {{"wallet_name", "testwallet"}, {"backup_file", "home\\backups\\backup-file.bak\""}, {"load_on_startup", true}})
621+
+ HelpExampleRpc("restorewallet", R"("testwallet", "home\\backups\\backup-file.bak")")
622+
+ HelpExampleCliNamed("restorewallet", {{"wallet_name", "testwallet"}, {"backup_file", "home\\backups\\backup-file.bak"}, {"load_on_startup", true}})
623+
+ HelpExampleRpcNamed("restorewallet", {{"wallet_name", "testwallet"}, {"backup_file", "home\\backups\\backup-file.bak"}, {"load_on_startup", true}})
624624
},
625625
[](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue
626626
{

src/wallet/rpc/coins.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -514,7 +514,7 @@ RPCMethod listunspent()
514514
RPCExamples{
515515
HelpExampleCli("listunspent", "")
516516
+ HelpExampleCli("listunspent", "6 9999999 \"[\\\"" + EXAMPLE_ADDRESS[0] + "\\\",\\\"" + EXAMPLE_ADDRESS[1] + "\\\"]\"")
517-
+ HelpExampleRpc("listunspent", "6, 9999999 \"[\\\"" + EXAMPLE_ADDRESS[0] + "\\\",\\\"" + EXAMPLE_ADDRESS[1] + "\\\"]\"")
517+
+ HelpExampleRpc("listunspent", strprintf(R"(6, 9999999, ["%s","%s"])", EXAMPLE_ADDRESS[0], EXAMPLE_ADDRESS[1]))
518518
+ HelpExampleCli("listunspent", "6 9999999 '[]' true '{ \"minimumAmount\": 0.005 }'")
519519
+ HelpExampleRpc("listunspent", "6, 9999999, [] , true, { \"minimumAmount\": 0.005 } ")
520520
},

src/wallet/rpc/wallet.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ static RPCMethod loadwallet()
249249
+ HelpExampleRpc("loadwallet", "\"/path/to/walletname/\"")
250250
+ "\nLoad wallet using absolute path (Windows):\n"
251251
+ HelpExampleCli("loadwallet", "\"DriveLetter:\\path\\to\\walletname\\\"")
252-
+ HelpExampleRpc("loadwallet", "\"DriveLetter:\\path\\to\\walletname\\\"")
252+
+ HelpExampleRpc("loadwallet", R"("DriveLetter:\\path\\to\\walletname")")
253253
},
254254
[](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue
255255
{
@@ -457,7 +457,7 @@ static RPCMethod unloadwallet()
457457
}},
458458
RPCExamples{
459459
HelpExampleCli("unloadwallet", "wallet_name")
460-
+ HelpExampleRpc("unloadwallet", "wallet_name")
460+
+ HelpExampleRpc("unloadwallet", R"("wallet_name")")
461461
},
462462
[](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue
463463
{
@@ -761,7 +761,7 @@ static RPCMethod createwalletdescriptor()
761761
},
762762
RPCExamples{
763763
HelpExampleCli("createwalletdescriptor", "bech32m")
764-
+ HelpExampleRpc("createwalletdescriptor", "bech32m")
764+
+ HelpExampleRpc("createwalletdescriptor", R"("bech32m")")
765765
},
766766
[](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue
767767
{
@@ -851,7 +851,7 @@ RPCMethod addhdkey()
851851
},
852852
},
853853
RPCExamples{
854-
HelpExampleCli("addhdkey", "xprv") + HelpExampleRpc("addhdkey", "xprv")
854+
HelpExampleCli("addhdkey", "xprv") + HelpExampleRpc("addhdkey", R"("xprv")")
855855
},
856856
[&](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue
857857
{

test/functional/rpc_help.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from test_framework.util import assert_equal, assert_raises_rpc_error
99

1010
from collections import defaultdict
11+
import json
1112
import os
1213
import re
1314

@@ -153,9 +154,17 @@ def dump_help(self):
153154
os.mkdir(dump_dir)
154155
calls = [line.split(' ', 1)[0] for line in self.nodes[0].help().splitlines() if line and not line.startswith('==')]
155156
for call in calls:
157+
help_text = self.nodes[0].help(call)
156158
with open(os.path.join(dump_dir, call), 'w') as f:
157159
# Make sure the node can generate the help at runtime without crashing
158-
f.write(self.nodes[0].help(call))
160+
f.write(help_text)
161+
# Make sure any curl examples have a JSON-RPC payload that is valid JSON
162+
for match in re.finditer(r"--data-binary '(.*)' -H", help_text):
163+
payload = match.group(1)
164+
try:
165+
json.loads(payload)
166+
except json.JSONDecodeError as e:
167+
raise AssertionError(f"HelpExampleRpc for '{call}' is not valid JSON: {payload!r}\n{e}")
159168

160169
def wallet_help(self):
161170
assert 'getnewaddress ( "label" "address_type" )' in self.nodes[0].help('getnewaddress')

0 commit comments

Comments
 (0)