Skip to content

Commit fa483e1

Browse files
author
MarcoFalke
committed
rpc: Add RPCHelpMan for machine-generated help
1 parent fa0d36f commit fa483e1

File tree

4 files changed

+327
-10
lines changed

4 files changed

+327
-10
lines changed

src/rpc/rawtransaction.cpp

Lines changed: 83 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,16 @@ static UniValue gettxoutproof(const JSONRPCRequest& request)
206206
{
207207
if (request.fHelp || (request.params.size() != 1 && request.params.size() != 2))
208208
throw std::runtime_error(
209-
"gettxoutproof [\"txid\",...] ( blockhash )\n"
209+
RPCHelpMan{"gettxoutproof",
210+
{
211+
{"txids", RPCArg::Type::ARR,
212+
{
213+
{"txid", RPCArg::Type::STR_HEX, false},
214+
},
215+
false},
216+
{"blockhash", RPCArg::Type::STR_HEX, true},
217+
}}
218+
.ToString() +
210219
"\nReturns a hex-encoded proof that \"txid\" was included in a block.\n"
211220
"\nNOTE: By default this function only works sometimes. This is when there is an\n"
212221
"unspent output in the utxo for this transaction. To make it always work,\n"
@@ -673,10 +682,17 @@ static void TxInErrorToJSON(const CTxIn& txin, UniValue& vErrorsRet, const std::
673682

674683
static UniValue combinerawtransaction(const JSONRPCRequest& request)
675684
{
676-
677685
if (request.fHelp || request.params.size() != 1)
678686
throw std::runtime_error(
679-
"combinerawtransaction [\"hexstring\",...]\n"
687+
RPCHelpMan{"combinerawtransaction",
688+
{
689+
{"txs", RPCArg::Type::ARR,
690+
{
691+
{"hexstring", RPCArg::Type::STR_HEX, false},
692+
},
693+
false},
694+
}}
695+
.ToString() +
680696
"\nCombine multiple partially signed transactions into one transaction.\n"
681697
"The combined transaction may be another partially signed transaction or a \n"
682698
"fully signed transaction."
@@ -899,7 +915,30 @@ static UniValue signrawtransactionwithkey(const JSONRPCRequest& request)
899915
{
900916
if (request.fHelp || request.params.size() < 2 || request.params.size() > 4)
901917
throw std::runtime_error(
902-
"signrawtransactionwithkey \"hexstring\" [\"privatekey1\",...] ( [{\"txid\":\"id\",\"vout\":n,\"scriptPubKey\":\"hex\",\"redeemScript\":\"hex\"},...] sighashtype )\n"
918+
RPCHelpMan{"signrawtransactionwithkey",
919+
{
920+
{"hexstring", RPCArg::Type::STR, false},
921+
{"privkyes", RPCArg::Type::ARR,
922+
{
923+
{"privatekey", RPCArg::Type::STR_HEX, false},
924+
},
925+
false},
926+
{"prevtxs", RPCArg::Type::ARR,
927+
{
928+
{"", RPCArg::Type::OBJ,
929+
{
930+
{"txid", RPCArg::Type::STR_HEX, false},
931+
{"vout", RPCArg::Type::NUM, false},
932+
{"scriptPubKey", RPCArg::Type::STR_HEX, false},
933+
{"redeemScript", RPCArg::Type::STR_HEX, false},
934+
{"amount", RPCArg::Type::AMOUNT, false},
935+
},
936+
true},
937+
},
938+
true},
939+
{"sighashtype", RPCArg::Type::STR, true},
940+
}}
941+
.ToString() +
903942
"\nSign inputs for raw transaction (serialized, hex-encoded).\n"
904943
"The second argument is an array of base58-encoded private\n"
905944
"keys that will be the only keys used to sign the transaction.\n"
@@ -1454,7 +1493,15 @@ UniValue combinepsbt(const JSONRPCRequest& request)
14541493
{
14551494
if (request.fHelp || request.params.size() != 1)
14561495
throw std::runtime_error(
1457-
"combinepsbt [\"psbt\",...]\n"
1496+
RPCHelpMan{"combinepsbt",
1497+
{
1498+
{"txs", RPCArg::Type::ARR,
1499+
{
1500+
{"psbt", RPCArg::Type::STR_HEX, false},
1501+
},
1502+
false},
1503+
}}
1504+
.ToString() +
14581505
"\nCombine multiple partially signed Bitcoin transactions into one transaction.\n"
14591506
"Implements the Combiner role.\n"
14601507
"\nArguments:\n"
@@ -1570,7 +1617,37 @@ UniValue createpsbt(const JSONRPCRequest& request)
15701617
{
15711618
if (request.fHelp || request.params.size() < 2 || request.params.size() > 4)
15721619
throw std::runtime_error(
1573-
"createpsbt [{\"txid\":\"id\",\"vout\":n},...] [{\"address\":amount},{\"data\":\"hex\"},...] ( locktime ) ( replaceable )\n"
1620+
RPCHelpMan{"createpsbt",
1621+
{
1622+
{"inputs", RPCArg::Type::ARR,
1623+
{
1624+
{"", RPCArg::Type::OBJ,
1625+
{
1626+
{"txid", RPCArg::Type::STR_HEX, false},
1627+
{"vout", RPCArg::Type::NUM, false},
1628+
{"sequence", RPCArg::Type::NUM, true},
1629+
},
1630+
false},
1631+
},
1632+
false},
1633+
{"outputs", RPCArg::Type::ARR,
1634+
{
1635+
{"", RPCArg::Type::OBJ,
1636+
{
1637+
{"address", RPCArg::Type::AMOUNT, false},
1638+
},
1639+
true},
1640+
{"", RPCArg::Type::OBJ,
1641+
{
1642+
{"data", RPCArg::Type::STR_HEX, false},
1643+
},
1644+
true},
1645+
},
1646+
false},
1647+
{"locktime", RPCArg::Type::NUM, true},
1648+
{"replaceable", RPCArg::Type::BOOL, true},
1649+
}}
1650+
.ToString() +
15741651
"\nCreates a transaction in the Partially Signed Transaction format.\n"
15751652
"Implements the Creator role.\n"
15761653
"\nArguments:\n"

src/rpc/util.cpp

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,3 +128,95 @@ UniValue DescribeAddress(const CTxDestination& dest)
128128
{
129129
return boost::apply_visitor(DescribeAddressVisitor(), dest);
130130
}
131+
132+
std::string RPCHelpMan::ToString() const
133+
{
134+
std::string ret;
135+
136+
ret += m_name;
137+
bool is_optional{false};
138+
for (const auto& arg : m_args) {
139+
ret += " ";
140+
if (arg.m_optional) {
141+
if (!is_optional) ret += "( ";
142+
is_optional = true;
143+
} else {
144+
// Currently we still support unnamed arguments, so any argument following an optional argument must also be optional
145+
// If support for positional arguments is deprecated in the future, remove this line
146+
assert(!is_optional);
147+
}
148+
ret += arg.ToString();
149+
}
150+
if (is_optional) ret += " )";
151+
ret += "\n";
152+
153+
return ret;
154+
}
155+
156+
std::string RPCArg::ToStringObj() const
157+
{
158+
std::string res = "\"" + m_name + "\":";
159+
switch (m_type) {
160+
case Type::STR:
161+
return res + "\"str\"";
162+
case Type::STR_HEX:
163+
return res + "\"hex\"";
164+
case Type::NUM:
165+
return res + "n";
166+
case Type::AMOUNT:
167+
return res + "amount";
168+
case Type::BOOL:
169+
return res + "bool";
170+
case Type::ARR:
171+
res += "[";
172+
for (const auto& i : m_inner) {
173+
res += i.ToString() + ",";
174+
}
175+
return res + "...]";
176+
case Type::OBJ:
177+
case Type::OBJ_USER_KEYS:
178+
// Currently unused, so avoid writing dead code
179+
assert(false);
180+
181+
// no default case, so the compiler can warn about missing cases
182+
}
183+
assert(false);
184+
}
185+
186+
std::string RPCArg::ToString() const
187+
{
188+
switch (m_type) {
189+
case Type::STR_HEX:
190+
case Type::STR: {
191+
return "\"" + m_name + "\"";
192+
}
193+
case Type::NUM:
194+
case Type::AMOUNT:
195+
case Type::BOOL: {
196+
return m_name;
197+
}
198+
case Type::OBJ:
199+
case Type::OBJ_USER_KEYS: {
200+
std::string res;
201+
for (size_t i = 0; i < m_inner.size();) {
202+
res += m_inner[i].ToStringObj();
203+
if (++i < m_inner.size()) res += ",";
204+
}
205+
if (m_type == Type::OBJ) {
206+
return "{" + res + "}";
207+
} else {
208+
return "{" + res + ",...}";
209+
}
210+
}
211+
case Type::ARR: {
212+
std::string res;
213+
for (const auto& i : m_inner) {
214+
res += i.ToString() + ",";
215+
}
216+
return "[" + res + "...]";
217+
}
218+
219+
// no default case, so the compiler can warn about missing cases
220+
}
221+
assert(false);
222+
}

src/rpc/util.h

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,53 @@ CScript CreateMultisigRedeemscript(const int required, const std::vector<CPubKey
3030

3131
UniValue DescribeAddress(const CTxDestination& dest);
3232

33+
struct RPCArg {
34+
enum class Type {
35+
OBJ,
36+
ARR,
37+
STR,
38+
NUM,
39+
BOOL,
40+
OBJ_USER_KEYS, //!< Special type where the user must set the keys e.g. to define multiple addresses; as opposed to e.g. an options object where the keys are predefined
41+
AMOUNT, //!< Special type representing a floating point amount (can be either NUM or STR)
42+
STR_HEX, //!< Special type that is a STR with only hex chars
43+
};
44+
const std::string m_name; //!< The name of the arg (can be empty for inner args)
45+
const Type m_type;
46+
const std::vector<RPCArg> m_inner; //!< Only used for arrays or dicts
47+
const bool m_optional;
48+
49+
RPCArg(const std::string& name, const Type& type, const bool optional)
50+
: m_name{name}, m_type{type}, m_optional{optional}
51+
{
52+
assert(type != Type::ARR && type != Type::OBJ);
53+
}
54+
55+
RPCArg(const std::string& name, const Type& type, const std::vector<RPCArg>& inner, const bool optional)
56+
: m_name{name}, m_type{type}, m_inner{inner}, m_optional{optional}
57+
{
58+
assert(type == Type::ARR || type == Type::OBJ);
59+
}
60+
61+
std::string ToString() const;
62+
63+
private:
64+
std::string ToStringObj() const;
65+
};
66+
67+
class RPCHelpMan
68+
{
69+
public:
70+
RPCHelpMan(const std::string& name, const std::vector<RPCArg>& args)
71+
: m_name{name}, m_args{args}
72+
{
73+
}
74+
75+
std::string ToString() const;
76+
77+
private:
78+
const std::string m_name;
79+
const std::vector<RPCArg> m_args;
80+
};
81+
3382
#endif // BITCOIN_RPC_UTIL_H

0 commit comments

Comments
 (0)