diff --git a/src/rpc/server.h b/src/rpc/server.h --- a/src/rpc/server.h +++ b/src/rpc/server.h @@ -148,26 +148,44 @@ public: std::string category; std::string name; - rpcfn_type actor; bool okSafeMode; + +private: + union { + rpcfn_type fn; + const_rpcfn_type cfn; + } actor; + bool useConstConfig; + +public: std::vector argNames; CRPCCommand(std::string _category, std::string _name, rpcfn_type _actor, bool _okSafeMode, std::vector _argNames) - : category{std::move(_category)}, name{std::move(_name)}, actor{_actor}, - okSafeMode{_okSafeMode}, argNames{std::move(_argNames)} {} + : category{std::move(_category)}, name{std::move(_name)}, + okSafeMode{_okSafeMode}, argNames{std::move(_argNames)} { + actor.fn = _actor; + useConstConfig = false; + } - /** - * It is safe to cast from void(const int*) to void(int*) but C++ do not - * understand type variance. As a result, we need to do the dirty job - * ourselves. + /* + * There are 2 constructors depending Config is const or not, so we can + * call the command through the proper pointer. Casting constness on + * parameters of function is undefined behavior. */ CRPCCommand(std::string _category, std::string _name, const_rpcfn_type _actor, bool _okSafeMode, std::vector _argNames) : category{std::move(_category)}, name{std::move(_name)}, - actor{reinterpret_cast(_actor)}, - okSafeMode{_okSafeMode}, argNames{std::move(_argNames)} {} + okSafeMode{_okSafeMode}, argNames{std::move(_argNames)} { + actor.cfn = _actor; + useConstConfig = true; + } + + UniValue call(Config &config, const JSONRPCRequest &jsonRequest) const { + return useConstConfig ? (*actor.cfn)(config, jsonRequest) + : (*actor.fn)(config, jsonRequest); + }; }; /** diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -172,7 +172,7 @@ const JSONRPCRequest &helpreq) const { std::string strRet; std::string category; - std::set setDone; + std::set setDone; std::vector> vCommands; for (std::map::const_iterator mi = @@ -204,8 +204,9 @@ try { JSONRPCRequest jreq; jreq.fHelp = true; - rpcfn_type pfn = pcmd->actor; - if (setDone.insert(pfn).second) pfn(config, jreq); + if (setDone.insert(pcmd).second) { + pcmd->call(config, jreq); + } } catch (const std::exception &e) { // Help text is returned in an exception std::string strHelp = std::string(e.what()); @@ -483,10 +484,10 @@ try { // Execute, convert arguments to array if necessary if (request.params.isObject()) { - return pcmd->actor( - config, transformNamedArguments(request, pcmd->argNames)); + return pcmd->call(config, + transformNamedArguments(request, pcmd->argNames)); } else { - return pcmd->actor(config, request); + return pcmd->call(config, request); } } catch (const std::exception &e) { throw JSONRPCError(RPC_MISC_ERROR, e.what()); diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp --- a/src/test/rpc_tests.cpp +++ b/src/test/rpc_tests.cpp @@ -27,9 +27,8 @@ request.params = RPCConvertValues(strMethod, vArgs); request.fHelp = false; BOOST_CHECK(tableRPC[strMethod]); - rpcfn_type method = tableRPC[strMethod]->actor; try { - UniValue result = (*method)(config, request); + UniValue result = tableRPC[strMethod]->call(config, request); return result; } catch (const UniValue &objError) { throw std::runtime_error(find_value(objError, "message").get_str());