Skip to content

Commit

Permalink
rpc: Add RPCHelpMan for machine-generated help
Browse files Browse the repository at this point in the history
  • Loading branch information
MarcoFalke committed Nov 12, 2018
1 parent fa0d36f commit fa483e1
Show file tree
Hide file tree
Showing 4 changed files with 327 additions and 10 deletions.
89 changes: 83 additions & 6 deletions src/rpc/rawtransaction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,16 @@ static UniValue gettxoutproof(const JSONRPCRequest& request)
{
if (request.fHelp || (request.params.size() != 1 && request.params.size() != 2))
throw std::runtime_error(
"gettxoutproof [\"txid\",...] ( blockhash )\n"
RPCHelpMan{"gettxoutproof",
{
{"txids", RPCArg::Type::ARR,
{
{"txid", RPCArg::Type::STR_HEX, false},
},
false},
{"blockhash", RPCArg::Type::STR_HEX, true},
}}
.ToString() +
"\nReturns a hex-encoded proof that \"txid\" was included in a block.\n"
"\nNOTE: By default this function only works sometimes. This is when there is an\n"
"unspent output in the utxo for this transaction. To make it always work,\n"
Expand Down Expand Up @@ -673,10 +682,17 @@ static void TxInErrorToJSON(const CTxIn& txin, UniValue& vErrorsRet, const std::

static UniValue combinerawtransaction(const JSONRPCRequest& request)
{

if (request.fHelp || request.params.size() != 1)
throw std::runtime_error(
"combinerawtransaction [\"hexstring\",...]\n"
RPCHelpMan{"combinerawtransaction",
{
{"txs", RPCArg::Type::ARR,
{
{"hexstring", RPCArg::Type::STR_HEX, false},
},
false},
}}
.ToString() +
"\nCombine multiple partially signed transactions into one transaction.\n"
"The combined transaction may be another partially signed transaction or a \n"
"fully signed transaction."
Expand Down Expand Up @@ -899,7 +915,30 @@ static UniValue signrawtransactionwithkey(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() < 2 || request.params.size() > 4)
throw std::runtime_error(
"signrawtransactionwithkey \"hexstring\" [\"privatekey1\",...] ( [{\"txid\":\"id\",\"vout\":n,\"scriptPubKey\":\"hex\",\"redeemScript\":\"hex\"},...] sighashtype )\n"
RPCHelpMan{"signrawtransactionwithkey",
{
{"hexstring", RPCArg::Type::STR, false},
{"privkyes", RPCArg::Type::ARR,
{
{"privatekey", RPCArg::Type::STR_HEX, false},
},
false},
{"prevtxs", RPCArg::Type::ARR,
{
{"", RPCArg::Type::OBJ,
{
{"txid", RPCArg::Type::STR_HEX, false},
{"vout", RPCArg::Type::NUM, false},
{"scriptPubKey", RPCArg::Type::STR_HEX, false},
{"redeemScript", RPCArg::Type::STR_HEX, false},
{"amount", RPCArg::Type::AMOUNT, false},
},
true},
},
true},
{"sighashtype", RPCArg::Type::STR, true},
}}
.ToString() +
"\nSign inputs for raw transaction (serialized, hex-encoded).\n"
"The second argument is an array of base58-encoded private\n"
"keys that will be the only keys used to sign the transaction.\n"
Expand Down Expand Up @@ -1454,7 +1493,15 @@ UniValue combinepsbt(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 1)
throw std::runtime_error(
"combinepsbt [\"psbt\",...]\n"
RPCHelpMan{"combinepsbt",
{
{"txs", RPCArg::Type::ARR,
{
{"psbt", RPCArg::Type::STR_HEX, false},
},
false},
}}
.ToString() +
"\nCombine multiple partially signed Bitcoin transactions into one transaction.\n"
"Implements the Combiner role.\n"
"\nArguments:\n"
Expand Down Expand Up @@ -1570,7 +1617,37 @@ UniValue createpsbt(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() < 2 || request.params.size() > 4)
throw std::runtime_error(
"createpsbt [{\"txid\":\"id\",\"vout\":n},...] [{\"address\":amount},{\"data\":\"hex\"},...] ( locktime ) ( replaceable )\n"
RPCHelpMan{"createpsbt",
{
{"inputs", RPCArg::Type::ARR,
{
{"", RPCArg::Type::OBJ,
{
{"txid", RPCArg::Type::STR_HEX, false},
{"vout", RPCArg::Type::NUM, false},
{"sequence", RPCArg::Type::NUM, true},
},
false},
},
false},
{"outputs", RPCArg::Type::ARR,
{
{"", RPCArg::Type::OBJ,
{
{"address", RPCArg::Type::AMOUNT, false},
},
true},
{"", RPCArg::Type::OBJ,
{
{"data", RPCArg::Type::STR_HEX, false},
},
true},
},
false},
{"locktime", RPCArg::Type::NUM, true},
{"replaceable", RPCArg::Type::BOOL, true},
}}
.ToString() +
"\nCreates a transaction in the Partially Signed Transaction format.\n"
"Implements the Creator role.\n"
"\nArguments:\n"
Expand Down
92 changes: 92 additions & 0 deletions src/rpc/util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,3 +128,95 @@ UniValue DescribeAddress(const CTxDestination& dest)
{
return boost::apply_visitor(DescribeAddressVisitor(), dest);
}

std::string RPCHelpMan::ToString() const
{
std::string ret;

ret += m_name;
bool is_optional{false};
for (const auto& arg : m_args) {
ret += " ";
if (arg.m_optional) {
if (!is_optional) ret += "( ";
is_optional = true;
} else {
// Currently we still support unnamed arguments, so any argument following an optional argument must also be optional
// If support for positional arguments is deprecated in the future, remove this line
assert(!is_optional);
}
ret += arg.ToString();
}
if (is_optional) ret += " )";
ret += "\n";

return ret;
}

std::string RPCArg::ToStringObj() const
{
std::string res = "\"" + m_name + "\":";
switch (m_type) {
case Type::STR:
return res + "\"str\"";
case Type::STR_HEX:
return res + "\"hex\"";
case Type::NUM:
return res + "n";
case Type::AMOUNT:
return res + "amount";
case Type::BOOL:
return res + "bool";
case Type::ARR:
res += "[";
for (const auto& i : m_inner) {
res += i.ToString() + ",";
}
return res + "...]";
case Type::OBJ:
case Type::OBJ_USER_KEYS:
// Currently unused, so avoid writing dead code
assert(false);

// no default case, so the compiler can warn about missing cases
}
assert(false);
}

std::string RPCArg::ToString() const
{
switch (m_type) {
case Type::STR_HEX:
case Type::STR: {
return "\"" + m_name + "\"";
}
case Type::NUM:
case Type::AMOUNT:
case Type::BOOL: {
return m_name;
}
case Type::OBJ:
case Type::OBJ_USER_KEYS: {
std::string res;
for (size_t i = 0; i < m_inner.size();) {
res += m_inner[i].ToStringObj();
if (++i < m_inner.size()) res += ",";
}
if (m_type == Type::OBJ) {
return "{" + res + "}";
} else {
return "{" + res + ",...}";
}
}
case Type::ARR: {
std::string res;
for (const auto& i : m_inner) {
res += i.ToString() + ",";
}
return "[" + res + "...]";
}

// no default case, so the compiler can warn about missing cases
}
assert(false);
}
49 changes: 49 additions & 0 deletions src/rpc/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,53 @@ CScript CreateMultisigRedeemscript(const int required, const std::vector<CPubKey

UniValue DescribeAddress(const CTxDestination& dest);

struct RPCArg {
enum class Type {
OBJ,
ARR,
STR,
NUM,
BOOL,
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
AMOUNT, //!< Special type representing a floating point amount (can be either NUM or STR)
STR_HEX, //!< Special type that is a STR with only hex chars
};
const std::string m_name; //!< The name of the arg (can be empty for inner args)
const Type m_type;
const std::vector<RPCArg> m_inner; //!< Only used for arrays or dicts
const bool m_optional;

RPCArg(const std::string& name, const Type& type, const bool optional)
: m_name{name}, m_type{type}, m_optional{optional}
{
assert(type != Type::ARR && type != Type::OBJ);
}

RPCArg(const std::string& name, const Type& type, const std::vector<RPCArg>& inner, const bool optional)
: m_name{name}, m_type{type}, m_inner{inner}, m_optional{optional}
{
assert(type == Type::ARR || type == Type::OBJ);
}

std::string ToString() const;

private:
std::string ToStringObj() const;
};

class RPCHelpMan
{
public:
RPCHelpMan(const std::string& name, const std::vector<RPCArg>& args)
: m_name{name}, m_args{args}
{
}

std::string ToString() const;

private:
const std::string m_name;
const std::vector<RPCArg> m_args;
};

#endif // BITCOIN_RPC_UTIL_H
Loading

0 comments on commit fa483e1

Please sign in to comment.