diff options
author | MarcoFalke <falke.marco@gmail.com> | 2021-03-15 10:13:10 +0100 |
---|---|---|
committer | MarcoFalke <falke.marco@gmail.com> | 2021-03-15 10:13:58 +0100 |
commit | 1e57d14d96ebe485deec6d024bf5017ea2fb8608 (patch) | |
tree | e204bcdf5baecc141d6a23d019427ff905b3c674 /src | |
parent | 6bc51af5c2f29882055dbbb917bbc42ab313164a (diff) | |
parent | 9048c58e10841d9e1d709c0a325dd14684cec325 (diff) |
Merge #21035: Remove pointer cast in CRPCTable::dumpArgMap
9048c58e10841d9e1d709c0a325dd14684cec325 Remove pointer cast in CRPCTable::dumpArgMap (Russell Yanofsky)
14f3d9b908ed9e78997bfaad3d8a06357a89d46e refactor: Add RPC server ExecuteCommands function (Russell Yanofsky)
6158a6d3978a18d5ac4166ca2f59056d8ef71c3d 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`](https://github.com/bitcoin/bitcoin/blob/16b784d953365bb2d7ae65acd2b20a79ef8ba7b6/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-ACK 9048c58e10841d9e1d709c0a325dd14684cec325 👑
Tree-SHA512: cd1a01c1daa5bde2c2455b63548371ee4cf39688313969ad2016d9a0fd4344102e3fd43034058f253364518e9632d57cf21abffad0d6a2c0c94b7a6921cbe615
Diffstat (limited to 'src')
-rw-r--r-- | src/rpc/request.h | 6 | ||||
-rw-r--r-- | src/rpc/server.cpp | 33 | ||||
-rw-r--r-- | src/rpc/server.h | 2 | ||||
-rw-r--r-- | src/rpc/util.cpp | 19 | ||||
-rw-r--r-- | src/rpc/util.h | 20 | ||||
-rw-r--r-- | src/test/rpc_tests.cpp | 1 | ||||
-rw-r--r-- | src/wallet/rpcwallet.cpp | 2 |
7 files changed, 49 insertions, 34 deletions
diff --git a/src/rpc/request.h b/src/rpc/request.h index de3a4ae840..27d06f3c92 100644 --- a/src/rpc/request.h +++ b/src/rpc/request.h @@ -34,19 +34,19 @@ public: UniValue id; std::string strMethod; UniValue params; - bool fHelp; + enum Mode { EXECUTE, GET_HELP, GET_ARGS } mode = EXECUTE; std::string URI; std::string authUser; std::string peerAddr; 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 //! given context. The implementation should be updated if any members are //! added or removed above. 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) { } diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index 9a9b3713f3..39938f4eb9 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -88,7 +88,7 @@ std::string CRPCTable::help(const std::string& strCommand, const JSONRPCRequest& sort(vCommands.begin(), vCommands.end()); JSONRPCRequest jreq(helpreq); - jreq.fHelp = true; + jreq.mode = JSONRPCRequest::GET_HELP; jreq.params = UniValue(); for (const std::pair<std::string, const CRPCCommand*>& command : vCommands) @@ -149,7 +149,7 @@ static RPCHelpMan help() } if (strCommand == "dump_all_command_conversions") { // Used for testing only, undocumented - return tableRPC.dumpArgMap(); + return tableRPC.dumpArgMap(jsonRequest); } return tableRPC.help(strCommand, jsonRequest); @@ -437,6 +437,16 @@ static inline JSONRPCRequest transformNamedArguments(const JSONRPCRequest& in, c 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 { // Return immediately if in warmup @@ -450,10 +460,8 @@ UniValue CRPCTable::execute(const JSONRPCRequest &request) const auto it = mapCommands.find(request.strMethod); if (it != mapCommands.end()) { UniValue result; - for (const auto& command : it->second) { - if (ExecuteCommand(*command, request, result, &command == &it->second.back())) { - return result; - } + if (ExecuteCommands(it->second, request, result)) { + return result; } } throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found"); @@ -484,13 +492,18 @@ std::vector<std::string> CRPCTable::listCommands() const 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}; for (const auto& cmd : mapCommands) { - for (const auto& c : cmd.second) { - const auto help = RpcMethodFnType(c->unique_id)(); - help.AppendArgMap(ret); + UniValue result; + if (ExecuteCommands(cmd.second, request, result)) { + for (const auto& values : result.getValues()) { + ret.push_back(values); + } } } return ret; diff --git a/src/rpc/server.h b/src/rpc/server.h index fe5a791e1e..03967020c2 100644 --- a/src/rpc/server.h +++ b/src/rpc/server.h @@ -148,7 +148,7 @@ public: /** * 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. diff --git a/src/rpc/util.cpp b/src/rpc/util.cpp index e890c0108a..44e58cb75f 100644 --- a/src/rpc/util.cpp +++ b/src/rpc/util.cpp @@ -459,6 +459,21 @@ std::string RPCExamples::ToDescriptionString() const 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 { size_t num_required_args = 0; @@ -532,8 +547,9 @@ std::string RPCHelpMan::ToString() const 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) { const auto& arg = m_args.at(i); std::vector<std::string> arg_names; @@ -548,6 +564,7 @@ void RPCHelpMan::AppendArgMap(UniValue& arr) const arr.push_back(map); } } + return arr; } std::string RPCArg::GetFirstName() const diff --git a/src/rpc/util.h b/src/rpc/util.h index c54ce85f60..94c2d2d626 100644 --- a/src/rpc/util.h +++ b/src/rpc/util.h @@ -333,26 +333,12 @@ public: 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); + UniValue HandleRequest(const JSONRPCRequest& request); std::string ToString() const; - /** Append the named args that need to be converted from string to another JSON type */ - void AppendArgMap(UniValue& arr) const; - UniValue HandleRequest(const JSONRPCRequest& request) - { - Check(request); - return m_fun(*this, request); - } + /** Return the named args that need to be converted from string to another JSON type */ + UniValue GetArgMap() const; /** If the supplied number of args is neither too small nor too high */ 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; const std::string m_name; diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp index 810665877d..2e0fc7e48f 100644 --- a/src/test/rpc_tests.cpp +++ b/src/test/rpc_tests.cpp @@ -36,7 +36,6 @@ UniValue RPCTestingSetup::CallRPC(std::string args) JSONRPCRequest request(context); request.strMethod = strMethod; request.params = RPCConvertValues(strMethod, vArgs); - request.fHelp = false; if (RPCIsInWarmup(nullptr)) SetRPCWarmupFinished(); try { UniValue result = tableRPC.execute(request); diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 8b0962f9ee..1b9071a712 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -96,7 +96,7 @@ bool GetWalletNameFromJSONRPCRequest(const JSONRPCRequest& request, std::string& std::shared_ptr<CWallet> GetWalletForJSONRPCRequest(const JSONRPCRequest& request) { - CHECK_NONFATAL(!request.fHelp); + CHECK_NONFATAL(request.mode == JSONRPCRequest::EXECUTE); std::string wallet_name; if (GetWalletNameFromJSONRPCRequest(request, wallet_name)) { std::shared_ptr<CWallet> pwallet = GetWallet(wallet_name); |