mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-03-06 14:19:59 -05:00
Merge #21035: Remove pointer cast in CRPCTable::dumpArgMap
9048c58e10
Remove pointer cast in CRPCTable::dumpArgMap (Russell Yanofsky)14f3d9b908
refactor: Add RPC server ExecuteCommands function (Russell Yanofsky)6158a6d397
refactor: Replace JSONRPCRequest fHelp field with mode field (Russell Yanofsky) Pull request description: This change is needed to fix the `rpc_help.py` test failing in #10102: https://cirrus-ci.com/task/5469433013469184?command=ci#L2275 The [`CRPCTable::dumpArgMap`](16b784d953/src/rpc/server.cpp (L492)
) method currently works by casting RPC `unique_id` integer field to a function pointer, and then calling it. The `unique_id` field wasn't supposed to be used this way (it's meant to be used to detect RPC aliases) and as a result, this code segfaults in the `rpc_help.py` test in multiprocess PR #10102 because wallet RPC functions aren't directly accessible from the node process. Fix this by adding a new `GET_ARGS` RPC request mode to retrieve argument information similar to the way the `GET_HELP` mode retrieves help information. --- This PR is part of the [process separation project](https://github.com/bitcoin/bitcoin/projects/10). ACKs for top commit: MarcoFalke: re-ACK9048c58e10
👑 Tree-SHA512: cd1a01c1daa5bde2c2455b63548371ee4cf39688313969ad2016d9a0fd4344102e3fd43034058f253364518e9632d57cf21abffad0d6a2c0c94b7a6921cbe615
This commit is contained in:
commit
1e57d14d96
7 changed files with 49 additions and 34 deletions
|
@ -34,19 +34,19 @@ public:
|
||||||
UniValue id;
|
UniValue id;
|
||||||
std::string strMethod;
|
std::string strMethod;
|
||||||
UniValue params;
|
UniValue params;
|
||||||
bool fHelp;
|
enum Mode { EXECUTE, GET_HELP, GET_ARGS } mode = EXECUTE;
|
||||||
std::string URI;
|
std::string URI;
|
||||||
std::string authUser;
|
std::string authUser;
|
||||||
std::string peerAddr;
|
std::string peerAddr;
|
||||||
const util::Ref& context;
|
const util::Ref& context;
|
||||||
|
|
||||||
explicit JSONRPCRequest(const util::Ref& context) : id(NullUniValue), params(NullUniValue), fHelp(false), context(context) {}
|
explicit JSONRPCRequest(const util::Ref& context) : id(NullUniValue), params(NullUniValue), context(context) {}
|
||||||
|
|
||||||
//! Initializes request information from another request object and the
|
//! Initializes request information from another request object and the
|
||||||
//! given context. The implementation should be updated if any members are
|
//! given context. The implementation should be updated if any members are
|
||||||
//! added or removed above.
|
//! added or removed above.
|
||||||
JSONRPCRequest(const JSONRPCRequest& other, const util::Ref& context)
|
JSONRPCRequest(const JSONRPCRequest& other, const util::Ref& context)
|
||||||
: id(other.id), strMethod(other.strMethod), params(other.params), fHelp(other.fHelp), URI(other.URI),
|
: id(other.id), strMethod(other.strMethod), params(other.params), mode(other.mode), URI(other.URI),
|
||||||
authUser(other.authUser), peerAddr(other.peerAddr), context(context)
|
authUser(other.authUser), peerAddr(other.peerAddr), context(context)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,7 +88,7 @@ std::string CRPCTable::help(const std::string& strCommand, const JSONRPCRequest&
|
||||||
sort(vCommands.begin(), vCommands.end());
|
sort(vCommands.begin(), vCommands.end());
|
||||||
|
|
||||||
JSONRPCRequest jreq(helpreq);
|
JSONRPCRequest jreq(helpreq);
|
||||||
jreq.fHelp = true;
|
jreq.mode = JSONRPCRequest::GET_HELP;
|
||||||
jreq.params = UniValue();
|
jreq.params = UniValue();
|
||||||
|
|
||||||
for (const std::pair<std::string, const CRPCCommand*>& command : vCommands)
|
for (const std::pair<std::string, const CRPCCommand*>& command : vCommands)
|
||||||
|
@ -149,7 +149,7 @@ static RPCHelpMan help()
|
||||||
}
|
}
|
||||||
if (strCommand == "dump_all_command_conversions") {
|
if (strCommand == "dump_all_command_conversions") {
|
||||||
// Used for testing only, undocumented
|
// Used for testing only, undocumented
|
||||||
return tableRPC.dumpArgMap();
|
return tableRPC.dumpArgMap(jsonRequest);
|
||||||
}
|
}
|
||||||
|
|
||||||
return tableRPC.help(strCommand, jsonRequest);
|
return tableRPC.help(strCommand, jsonRequest);
|
||||||
|
@ -437,6 +437,16 @@ static inline JSONRPCRequest transformNamedArguments(const JSONRPCRequest& in, c
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool ExecuteCommands(const std::vector<const CRPCCommand*>& commands, const JSONRPCRequest& request, UniValue& result)
|
||||||
|
{
|
||||||
|
for (const auto& command : commands) {
|
||||||
|
if (ExecuteCommand(*command, request, result, &command == &commands.back())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
UniValue CRPCTable::execute(const JSONRPCRequest &request) const
|
UniValue CRPCTable::execute(const JSONRPCRequest &request) const
|
||||||
{
|
{
|
||||||
// Return immediately if in warmup
|
// Return immediately if in warmup
|
||||||
|
@ -450,10 +460,8 @@ UniValue CRPCTable::execute(const JSONRPCRequest &request) const
|
||||||
auto it = mapCommands.find(request.strMethod);
|
auto it = mapCommands.find(request.strMethod);
|
||||||
if (it != mapCommands.end()) {
|
if (it != mapCommands.end()) {
|
||||||
UniValue result;
|
UniValue result;
|
||||||
for (const auto& command : it->second) {
|
if (ExecuteCommands(it->second, request, result)) {
|
||||||
if (ExecuteCommand(*command, request, result, &command == &it->second.back())) {
|
return result;
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found");
|
throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found");
|
||||||
|
@ -484,13 +492,18 @@ std::vector<std::string> CRPCTable::listCommands() const
|
||||||
return commandList;
|
return commandList;
|
||||||
}
|
}
|
||||||
|
|
||||||
UniValue CRPCTable::dumpArgMap() const
|
UniValue CRPCTable::dumpArgMap(const JSONRPCRequest& args_request) const
|
||||||
{
|
{
|
||||||
|
JSONRPCRequest request(args_request);
|
||||||
|
request.mode = JSONRPCRequest::GET_ARGS;
|
||||||
|
|
||||||
UniValue ret{UniValue::VARR};
|
UniValue ret{UniValue::VARR};
|
||||||
for (const auto& cmd : mapCommands) {
|
for (const auto& cmd : mapCommands) {
|
||||||
for (const auto& c : cmd.second) {
|
UniValue result;
|
||||||
const auto help = RpcMethodFnType(c->unique_id)();
|
if (ExecuteCommands(cmd.second, request, result)) {
|
||||||
help.AppendArgMap(ret);
|
for (const auto& values : result.getValues()) {
|
||||||
|
ret.push_back(values);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -148,7 +148,7 @@ public:
|
||||||
/**
|
/**
|
||||||
* Return all named arguments that need to be converted by the client from string to another JSON type
|
* Return all named arguments that need to be converted by the client from string to another JSON type
|
||||||
*/
|
*/
|
||||||
UniValue dumpArgMap() const;
|
UniValue dumpArgMap(const JSONRPCRequest& request) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Appends a CRPCCommand to the dispatch table.
|
* Appends a CRPCCommand to the dispatch table.
|
||||||
|
|
|
@ -459,6 +459,21 @@ std::string RPCExamples::ToDescriptionString() const
|
||||||
return m_examples.empty() ? m_examples : "\nExamples:\n" + m_examples;
|
return m_examples.empty() ? m_examples : "\nExamples:\n" + m_examples;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UniValue RPCHelpMan::HandleRequest(const JSONRPCRequest& request)
|
||||||
|
{
|
||||||
|
if (request.mode == JSONRPCRequest::GET_ARGS) {
|
||||||
|
return GetArgMap();
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Check if the given request is valid according to this command or if
|
||||||
|
* the user is asking for help information, and throw help when appropriate.
|
||||||
|
*/
|
||||||
|
if (request.mode == JSONRPCRequest::GET_HELP || !IsValidNumArgs(request.params.size())) {
|
||||||
|
throw std::runtime_error(ToString());
|
||||||
|
}
|
||||||
|
return m_fun(*this, request);
|
||||||
|
}
|
||||||
|
|
||||||
bool RPCHelpMan::IsValidNumArgs(size_t num_args) const
|
bool RPCHelpMan::IsValidNumArgs(size_t num_args) const
|
||||||
{
|
{
|
||||||
size_t num_required_args = 0;
|
size_t num_required_args = 0;
|
||||||
|
@ -532,8 +547,9 @@ std::string RPCHelpMan::ToString() const
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RPCHelpMan::AppendArgMap(UniValue& arr) const
|
UniValue RPCHelpMan::GetArgMap() const
|
||||||
{
|
{
|
||||||
|
UniValue arr{UniValue::VARR};
|
||||||
for (int i{0}; i < int(m_args.size()); ++i) {
|
for (int i{0}; i < int(m_args.size()); ++i) {
|
||||||
const auto& arg = m_args.at(i);
|
const auto& arg = m_args.at(i);
|
||||||
std::vector<std::string> arg_names;
|
std::vector<std::string> arg_names;
|
||||||
|
@ -548,6 +564,7 @@ void RPCHelpMan::AppendArgMap(UniValue& arr) const
|
||||||
arr.push_back(map);
|
arr.push_back(map);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return arr;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string RPCArg::GetFirstName() const
|
std::string RPCArg::GetFirstName() const
|
||||||
|
|
|
@ -333,26 +333,12 @@ public:
|
||||||
using RPCMethodImpl = std::function<UniValue(const RPCHelpMan&, const JSONRPCRequest&)>;
|
using RPCMethodImpl = std::function<UniValue(const RPCHelpMan&, const JSONRPCRequest&)>;
|
||||||
RPCHelpMan(std::string name, std::string description, std::vector<RPCArg> args, RPCResults results, RPCExamples examples, RPCMethodImpl fun);
|
RPCHelpMan(std::string name, std::string description, std::vector<RPCArg> args, RPCResults results, RPCExamples examples, RPCMethodImpl fun);
|
||||||
|
|
||||||
|
UniValue HandleRequest(const JSONRPCRequest& request);
|
||||||
std::string ToString() const;
|
std::string ToString() const;
|
||||||
/** Append the named args that need to be converted from string to another JSON type */
|
/** Return the named args that need to be converted from string to another JSON type */
|
||||||
void AppendArgMap(UniValue& arr) const;
|
UniValue GetArgMap() const;
|
||||||
UniValue HandleRequest(const JSONRPCRequest& request)
|
|
||||||
{
|
|
||||||
Check(request);
|
|
||||||
return m_fun(*this, request);
|
|
||||||
}
|
|
||||||
/** If the supplied number of args is neither too small nor too high */
|
/** If the supplied number of args is neither too small nor too high */
|
||||||
bool IsValidNumArgs(size_t num_args) const;
|
bool IsValidNumArgs(size_t num_args) const;
|
||||||
/**
|
|
||||||
* Check if the given request is valid according to this command or if
|
|
||||||
* the user is asking for help information, and throw help when appropriate.
|
|
||||||
*/
|
|
||||||
inline void Check(const JSONRPCRequest& request) const {
|
|
||||||
if (request.fHelp || !IsValidNumArgs(request.params.size())) {
|
|
||||||
throw std::runtime_error(ToString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::string> GetArgNames() const;
|
std::vector<std::string> GetArgNames() const;
|
||||||
|
|
||||||
const std::string m_name;
|
const std::string m_name;
|
||||||
|
|
|
@ -36,7 +36,6 @@ UniValue RPCTestingSetup::CallRPC(std::string args)
|
||||||
JSONRPCRequest request(context);
|
JSONRPCRequest request(context);
|
||||||
request.strMethod = strMethod;
|
request.strMethod = strMethod;
|
||||||
request.params = RPCConvertValues(strMethod, vArgs);
|
request.params = RPCConvertValues(strMethod, vArgs);
|
||||||
request.fHelp = false;
|
|
||||||
if (RPCIsInWarmup(nullptr)) SetRPCWarmupFinished();
|
if (RPCIsInWarmup(nullptr)) SetRPCWarmupFinished();
|
||||||
try {
|
try {
|
||||||
UniValue result = tableRPC.execute(request);
|
UniValue result = tableRPC.execute(request);
|
||||||
|
|
|
@ -96,7 +96,7 @@ bool GetWalletNameFromJSONRPCRequest(const JSONRPCRequest& request, std::string&
|
||||||
|
|
||||||
std::shared_ptr<CWallet> GetWalletForJSONRPCRequest(const JSONRPCRequest& request)
|
std::shared_ptr<CWallet> GetWalletForJSONRPCRequest(const JSONRPCRequest& request)
|
||||||
{
|
{
|
||||||
CHECK_NONFATAL(!request.fHelp);
|
CHECK_NONFATAL(request.mode == JSONRPCRequest::EXECUTE);
|
||||||
std::string wallet_name;
|
std::string wallet_name;
|
||||||
if (GetWalletNameFromJSONRPCRequest(request, wallet_name)) {
|
if (GetWalletNameFromJSONRPCRequest(request, wallet_name)) {
|
||||||
std::shared_ptr<CWallet> pwallet = GetWallet(wallet_name);
|
std::shared_ptr<CWallet> pwallet = GetWallet(wallet_name);
|
||||||
|
|
Loading…
Add table
Reference in a new issue