This introduces a manager for the RPC help generation and demonstrates its use of it in some RPCs.
It is the first non-exhaustive step toward #14378 and I will create pull requests for the next steps after this one is merged.
This introduces a manager for the RPC help generation and demonstrates its use of it in some RPCs.
It is the first non-exhaustive step toward #14378 and I will create pull requests for the next steps after this one is merged.
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.
Reviewers, this pull request conflicts with the following ones:
If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.
Is the plan to write down all objects in the first argument line like this?
For example, fundrawtransaction has a large object; is the plan to use that instead of “options” at the first line?
https://bitcoincore.org/en/doc/0.17.0/rpc/rawtransactions/fundrawtransaction/
If not, I would suggest to use an option to RPCArg, for example “m_writeFirstAsObject”; it could still then be printed as an object in the longer argument writedown.
(The idea is great though.)
Also the PR changes the RPC from
"scriptPubKey":"hex"
or "txid":"id"
or "amount": value
to
"scriptPubKey":"str"
or "txid":"str"
or "amount": n
Is that intentional? I think it decreases readability… "scriptPubKey":"hex"
tells me not just “this needs to be a string” but also “this needs to be a hex string”.
(On some places in RPC, bitcoin core uses notation "amount" : x.xxx
for amount, which is even better - it makes it clearer this is numeral that is in BTC and can contain decimal point.)
I think this should be kept - so there should be more subtypes than UniValue::VType
- for example, extra type for amount, type for hex. (Txid can be hex.)
There will also be support for “option object” - that is, something can be two different things - for example as in walletcreatefundedpsbt
object in outputs
- can be either {"address":amount}
or {"data":"hex"}
…that all leads me to think this shouldn’t use “univalue” types but its own types
enum class
with all the (sub)types I could find.
I am thinking, how to address this pattern (from sendmany)
02. "amounts" (string, required) A json object with addresses and amounts
1 {
2 "address":amount (numeric or string) The bitcoin address is the key, the numeric amount (can be string) in BTC is the value
3 ,...
4 }
It looks like "address"
is the string key in json object, but actually it isn’t; the string key in actual usage will be the actual address, not string "address"
.
So in this object, adding ,...
makes sense. But in other objects, adding ,...
doesn’t make sense (if it is an “options” object, for example).
Maybe there should be 2 kinds of object types, one where the list of keys is exhaustive and one where it isn’t (and the user should actually change the key to his own strings)?
I have played with your code and added functions for printing the whole argument table and got it working.
See this branch (I have just added new commits, no rebase)
https://github.com/karel-3d/bitcoin/commits/Mf1810-rpcHelpMan
I have moved the same functions as you did to this format. It works! But - I am not sure about the readability of the code and about the resulting RPC help. It needs some cleanup.
What I did not yet done is adding the “default” option, and adding “Result” (and “Examples”).
It needs to be rebased on top of your new branch with OBJ_USER_KEYS
.
Just a preparatory commit to add the header to the includes and run
clang-format to sort the include lists.
Splitting this up into a separate commit makes future scripted-diffs
easier.
Note that the generated doc can be easily compared against the previous one by running this weird hack:
0diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
1index f619857da1..188b2795c2 100644
2--- a/src/rpc/rawtransaction.cpp
3+++ b/src/rpc/rawtransaction.cpp
4@@ -1782,7 +1782,6 @@ static const CRPCCommand commands[] =
5 { "rawtransactions", "decodescript", &decodescript, {"hexstring"} },
6 { "rawtransactions", "sendrawtransaction", &sendrawtransaction, {"hexstring","allowhighfees"} },
7 { "rawtransactions", "combinerawtransaction", &combinerawtransaction, {"txs"} },
8- { "hidden", "signrawtransaction", &signrawtransaction, {"hexstring","prevtxs","privkeys","sighashtype"} },
9 { "rawtransactions", "signrawtransactionwithkey", &signrawtransactionwithkey, {"hexstring","privkeys","prevtxs","sighashtype"} },
10 { "rawtransactions", "testmempoolaccept", &testmempoolaccept, {"rawtxs","allowhighfees"} },
11 { "rawtransactions", "decodepsbt", &decodepsbt, {"psbt"} },
12diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp
13index dfd98bfc5f..4c08b6881b 100644
14--- a/src/rpc/server.cpp
15+++ b/src/rpc/server.cpp
16@@ -165,7 +165,7 @@ std::string CRPCTable::help(const std::string& strCommand, const JSONRPCRequest&
17 {
18 const CRPCCommand *pcmd = command.second;
19 std::string strMethod = pcmd->name;
20- if ((strCommand != "" || pcmd->category == "hidden") && strMethod != strCommand)
21+ if ((strCommand != "") && strMethod != strCommand)
22 continue;
23 jreq.strMethod = strMethod;
24 try
25diff --git a/test/functional/rpc_help.py b/test/functional/rpc_help.py
26index 78d6e78aed..c6e01d9cfc 100755
27--- a/test/functional/rpc_help.py
28+++ b/test/functional/rpc_help.py
29@@ -33,7 +33,7 @@ class HelpRpcTest(BitcoinTestFramework):
30 # command titles
31 titles = [line[3:-3] for line in node.help().splitlines() if line.startswith('==')]
32
33- components = ['Blockchain', 'Control', 'Generating', 'Mining', 'Network', 'Rawtransactions', 'Util']
34+ components = ['Blockchain', 'Control', 'Generating', 'Hidden', 'Mining', 'Network', 'Rawtransactions', 'Util']
35
36 if self.is_wallet_compiled():
37 components.append('Wallet')
38@@ -46,6 +46,7 @@ class HelpRpcTest(BitcoinTestFramework):
39 def dump_help(self):
40 dump_dir = os.path.join(self.options.tmpdir, 'rpc_help_dump')
41 os.mkdir(dump_dir)
42+ dump_dir = '/tmp/temp_git/' ##HACK
43 calls = [line.split(' ', 1)[0] for line in self.nodes[0].help().splitlines() if line and not line.startswith('==')]
44 for call in calls:
45 with open(os.path.join(dump_dir, call), 'w', encoding='utf-8') as f:
Which then gives the resulting diff for me:
0diff --git a/createpsbt b/createpsbt
1index 4b75e7f..6e2ec5c 100644
2--- a/createpsbt
3+++ b/createpsbt
4@@ -1,4 +1,4 @@
5-createpsbt [{"txid":"id","vout":n},...] [{"address":amount},{"data":"hex"},...] ( locktime ) ( replaceable )
6+createpsbt [{"txid":"hex","vout":n,"sequence":n},...] [{"address":amount},{"data":"hex"},...] ( locktime replacable )
7
8 Creates a transaction in the Partially Signed Transaction format.
9 Implements the Creator role.
10diff --git a/gettxoutproof b/gettxoutproof
11index 5ed7748..45ba17a 100644
12--- a/gettxoutproof
13+++ b/gettxoutproof
14@@ -1,4 +1,4 @@
15-gettxoutproof ["txid",...] ( blockhash )
16+gettxoutproof ["txid",...] ( "blockhash" )
17
18 Returns a hex-encoded proof that "txid" was included in a block.
19
20diff --git a/listunspent b/listunspent
21index 39772c9..bc3baf8 100644
22--- a/listunspent
23+++ b/listunspent
24@@ -1,4 +1,4 @@
25-listunspent ( minconf maxconf ["addresses",...] [include_unsafe] [query_options])
26+listunspent ( minconf maxconf ["address",...] include_unsafe {"minimumAmount":amount,"maximumAmount":amount,"maximumCount":n,"minimumSumAmount":amount} )
27
28 Returns array of unspent transaction outputs
29 with between minconf and maxconf (inclusive) confirmations.
30diff --git a/lockunspent b/lockunspent
31index e21df7a..9b26c69 100644
32--- a/lockunspent
33+++ b/lockunspent
34@@ -1,4 +1,4 @@
35-lockunspent unlock ([{"txid":"txid","vout":n},...])
36+lockunspent unlock ( [{"txid":"hex","vout":n},...] )
37
38 Updates list of temporarily unspendable outputs.
39 Temporarily lock (unlock=false) or unlock (unlock=true) specified transaction outputs.
40diff --git a/signrawtransactionwithkey b/signrawtransactionwithkey
41index 583b3d9..6113c66 100644
42--- a/signrawtransactionwithkey
43+++ b/signrawtransactionwithkey
44@@ -1,4 +1,4 @@
45-signrawtransactionwithkey "hexstring" ["privatekey1",...] ( [{"txid":"id","vout":n,"scriptPubKey":"hex","redeemScript":"hex"},...] sighashtype )
46+signrawtransactionwithkey "hexstring" ["privatekey",...] ( [{"txid":"hex","vout":n,"scriptPubKey":"hex","redeemScript":"hex","amount":amount},...] "sighashtype" )
47
48 Sign inputs for raw transaction (serialized, hex-encoded).
49 The second argument is an array of base58-encoded private
50diff --git a/signrawtransactionwithwallet b/signrawtransactionwithwallet
51index 5a70fa4..ad9ce09 100644
52--- a/signrawtransactionwithwallet
53+++ b/signrawtransactionwithwallet
54@@ -1,4 +1,4 @@
55-signrawtransactionwithwallet "hexstring" ( [{"txid":"id","vout":n,"scriptPubKey":"hex","redeemScript":"hex"},...] sighashtype )
56+signrawtransactionwithwallet "hexstring" ( [{"txid":"hex","vout":n,"scriptPubKey":"hex","redeemScript":"hex","amount":amount},...] "sighashtype" )
57
58 Sign inputs for raw transaction (serialized, hex-encoded).
59 The second optional argument (may be null) is an array of previous transaction outputs that
60diff --git a/walletcreatefundedpsbt b/walletcreatefundedpsbt
61index 81ba09b..25e77bd 100644
62--- a/walletcreatefundedpsbt
63+++ b/walletcreatefundedpsbt
64@@ -1,4 +1,4 @@
65-walletcreatefundedpsbt [{"txid":"id","vout":n},...] [{"address":amount},{"data":"hex"},...] ( locktime ) ( replaceable ) ( options bip32derivs )
66+walletcreatefundedpsbt [{"txid":"hex","vout":n,"sequence":n},...] [{"address":amount},{"data":"hex"},...] ( locktime {"changeAddress":"hex","changePosition":n,"change_type":"str","includeWatching":bool,"lockUnspents":bool,"feeRate":n,"subtractFeeFromOutputs":[int,...],"replaceable":bool,"conf_target":n,"estimate_mode":"str"} bip32derivs )
67
68 Creates and funds a transaction in the Partially Signed Transaction format. Inputs will be added if supplied inputs are not enough
69 Implements the Creator and Updater roles.
205@@ -206,7 +206,16 @@ static UniValue gettxoutproof(const JSONRPCRequest& request)
206 {
207 if (request.fHelp || (request.params.size() != 1 && request.params.size() != 2))
208 throw std::runtime_error(
209- "gettxoutproof [\"txid\",...] ( blockhash )\n"
210+ RPCHelpMan{"gettxoutproof",
211+ {
212+ RPCArg{"txids", RPCArg::Type::ARR,
RPCArg
throughout?
utACK fa483e13b387f244c1c72d4dbd709e669335618e. Changes all look good but I’m a surprised to see how incomplete this is. The other PR #14502 which was closed was much more ambitious and completely overhauled everything, while this is only printing the initial lines of a few RPC methods.
I will create pull requests for the next steps after this one is merged.
Curious how many PRs were you thinking of, and how would they be divided up.
Curious how many PRs were you thinking of, and how would they be divided up.
This is mostly refactoring, so I wouldn’t want to create a pull request that takes more than, say, 30 minutes to review.
Logically, I’d like to split them into auto-generating the summary line (1), description (2) and extended documentation about input and output variables (3).
This is the first part of (1). In the next step I will add a linter to make sure all the new documentation is autogenerated and maybe add a scripted diff to convert all remaining ones. Then create one or two pull requests for everything else. So 2-3 in total.
MarcoFalke
fanquake
DrahtBot
karelbilek
laanwj
promag
ryanofsky
Labels
Refactoring
RPC/REST/ZMQ
Milestone
0.18.0