LCOV - code coverage report
Current view: top level - src/rpc - server.cpp (source / functions) Hit Total Coverage
Test: test_dash_coverage.info Lines: 181 362 50.0 %
Date: 2026-06-25 07:23:51 Functions: 34 61 55.7 %

          Line data    Source code
       1             : // Copyright (c) 2010 Satoshi Nakamoto
       2             : // Copyright (c) 2009-2021 The Bitcoin Core developers
       3             : // Copyright (c) 2014-2025 The Dash Core developers
       4             : // Distributed under the MIT software license, see the accompanying
       5             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       6             : 
       7             : #include <rpc/server.h>
       8             : 
       9             : #include <rpc/util.h>
      10             : #include <shutdown.h>
      11             : #include <sync.h>
      12             : #include <util/strencodings.h>
      13             : #include <util/string.h>
      14             : #include <util/system.h>
      15             : #include <util/time.h>
      16             : 
      17             : #include <boost/signals2/signal.hpp>
      18             : 
      19             : #include <atomic>
      20             : #include <cassert>
      21             : #include <chrono>
      22             : #include <memory>
      23             : #include <mutex>
      24             : #include <unordered_map>
      25             : 
      26             : static GlobalMutex g_rpc_warmup_mutex;
      27             : static std::atomic<bool> g_rpc_running{false};
      28             : static bool fRPCInWarmup GUARDED_BY(g_rpc_warmup_mutex) = true;
      29             : static std::string rpcWarmupStatus GUARDED_BY(g_rpc_warmup_mutex) = "RPC server started";
      30             : /* Timer-creating functions */
      31             : static RPCTimerInterface* timerInterface = nullptr;
      32             : /* Map of name to timer. */
      33             : static GlobalMutex g_deadline_timers_mutex;
      34         146 : static std::map<std::string, std::unique_ptr<RPCTimerBase> > deadlineTimers GUARDED_BY(g_deadline_timers_mutex);
      35             : static bool ExecuteCommand(const CRPCCommand& command, const JSONRPCRequest& request, UniValue& result, bool last_handler);
      36             : 
      37             : struct RPCCommandExecutionInfo
      38             : {
      39             :     std::string method;
      40             :     SteadyClock::time_point start;
      41             : };
      42             : 
      43             : struct RPCServerInfo
      44             : {
      45             :     Mutex mutex;
      46             :     std::list<RPCCommandExecutionInfo> active_commands GUARDED_BY(mutex);
      47             : };
      48             : 
      49         146 : static RPCServerInfo g_rpc_server_info;
      50             : 
      51             : struct RPCCommandExecution
      52             : {
      53             :     std::list<RPCCommandExecutionInfo>::iterator it;
      54         146 :     explicit RPCCommandExecution(const std::string& method)
      55          73 :     {
      56          73 :         LOCK(g_rpc_server_info.mutex);
      57          73 :         it = g_rpc_server_info.active_commands.insert(g_rpc_server_info.active_commands.end(), {method, SteadyClock::now()});
      58         146 :     }
      59         146 :     ~RPCCommandExecution()
      60          73 :     {
      61          73 :         LOCK(g_rpc_server_info.mutex);
      62          73 :         g_rpc_server_info.active_commands.erase(it);
      63         146 :     }
      64             : };
      65             : 
      66         146 : static struct CRPCSignals
      67             : {
      68             :     boost::signals2::signal<void ()> Started;
      69             :     boost::signals2::signal<void ()> Stopped;
      70         146 : } g_rpcSignals;
      71             : 
      72           0 : void RPCServer::OnStarted(std::function<void ()> slot)
      73             : {
      74           0 :     g_rpcSignals.Started.connect(slot);
      75           0 : }
      76             : 
      77           0 : void RPCServer::OnStopped(std::function<void ()> slot)
      78             : {
      79           0 :     g_rpcSignals.Stopped.connect(slot);
      80           0 : }
      81             : 
      82           0 : std::string CRPCTable::help(const std::string& strCommand, const JSONRPCRequest& helpreq) const
      83             : {
      84           0 :     std::string strRet;
      85           0 :     std::string category;
      86           0 :     std::set<intptr_t> setDone;
      87           0 :     std::vector<std::pair<std::string, const CRPCCommand*> > vCommands;
      88             : 
      89           0 :     for (const auto& entry : mapCommands)
      90           0 :         vCommands.emplace_back(entry.second.front()->category + entry.first, entry.second.front());
      91           0 :     sort(vCommands.begin(), vCommands.end());
      92             : 
      93           0 :     JSONRPCRequest jreq = helpreq;
      94           0 :     jreq.mode = JSONRPCRequest::GET_HELP;
      95           0 :     jreq.params = UniValue();
      96             : 
      97           0 :     for (const std::pair<std::string, const CRPCCommand*>& command : vCommands)
      98             :     {
      99           0 :         const CRPCCommand *pcmd = command.second;
     100           0 :         std::string strMethod = pcmd->name;
     101           0 :         if ((strCommand != "" || pcmd->category == "hidden") && strMethod != strCommand)
     102           0 :             continue;
     103             : 
     104           0 :         const auto pos_separator{strMethod.find(' ')};
     105           0 :         const bool is_composite{pos_separator != std::string::npos};
     106           0 :         if (strCommand.empty() && is_composite) continue;
     107             : 
     108           0 :         jreq.strMethod = strMethod;
     109             :         try
     110             :         {
     111           0 :             if (is_composite) {
     112           0 :                 jreq.params.setArray();
     113           0 :                 jreq.params.push_back(strCommand.substr(pos_separator + 1));
     114           0 :             }
     115           0 :             UniValue unused_result;
     116           0 :             if (setDone.insert(pcmd->unique_id).second)
     117           0 :                 pcmd->actor(jreq, unused_result, true /* last_handler */);
     118           0 :         }
     119             :         catch (const std::exception& e)
     120             :         {
     121             :             // Help text is returned in an exception
     122           0 :             std::string strHelp = std::string(e.what());
     123           0 :             if (strCommand == "")
     124             :             {
     125           0 :                 if (strHelp.find('\n') != std::string::npos)
     126           0 :                     strHelp = strHelp.substr(0, strHelp.find('\n'));
     127             : 
     128           0 :                 if (category != pcmd->category)
     129             :                 {
     130           0 :                     if (!category.empty())
     131           0 :                         strRet += "\n";
     132           0 :                     category = pcmd->category;
     133           0 :                     strRet += "== " + Capitalize(category) + " ==\n";
     134           0 :                 }
     135           0 :             }
     136           0 :             strRet += strHelp + "\n";
     137           0 :         }
     138           0 :     }
     139           0 :     if (strRet == "")
     140           0 :         strRet = strprintf("help: unknown command: %s\n", strCommand);
     141           0 :     strRet = strRet.substr(0,strRet.size()-1);
     142           0 :     return strRet;
     143           0 : }
     144             : 
     145         292 : static RPCHelpMan help()
     146             : {
     147         584 :     return RPCHelpMan{"help",
     148         292 :                 "\nList all commands, or get help for a specified command.\n",
     149         876 :                 {
     150         292 :                     {"command", RPCArg::Type::STR, RPCArg::DefaultHint{"all commands"}, "The command to get help on"},
     151         292 :                     {"subcommand", RPCArg::Type::STR, RPCArg::DefaultHint{"all subcommands"}, "The subcommand to get help on."},
     152             :                 },
     153         876 :                 {
     154         292 :                     RPCResult{RPCResult::Type::STR, "", "The help text"},
     155         292 :                     RPCResult{RPCResult::Type::ANY, "", ""},
     156             :                 },
     157         292 :                 RPCExamples{""},
     158         292 :         [&](const RPCHelpMan& self, const JSONRPCRequest& jsonRequest) -> UniValue
     159             : {
     160           0 :     std::string strCommand, strSubCommand;
     161           0 :     if (jsonRequest.params.size() > 0) {
     162           0 :         strCommand = jsonRequest.params[0].get_str();
     163           0 :     }
     164           0 :     if (jsonRequest.params.size() > 1) {
     165           0 :         strCommand += " " + jsonRequest.params[1].get_str();
     166           0 :     }
     167           0 :     if (strCommand == "dump_all_command_conversions") {
     168             :         // Used for testing only, undocumented
     169           0 :         return tableRPC.dumpArgMap(jsonRequest);
     170             :     }
     171             : 
     172           0 :     return tableRPC.help(strCommand, jsonRequest);
     173           0 : },
     174             :     };
     175           0 : }
     176             : 
     177         292 : static RPCHelpMan stop()
     178             : {
     179             :     static const std::string RESULT{PACKAGE_NAME " stopping"};
     180         584 :     return RPCHelpMan{"stop",
     181             :     // Also accept the hidden 'wait' integer argument (milliseconds)
     182             :     // For instance, 'stop 1000' makes the call wait 1 second before returning
     183             :     // to the client (intended for testing)
     184         292 :                 "\nRequest a graceful shutdown of " PACKAGE_NAME ".",
     185         584 :                 {
     186         292 :                     {"wait", RPCArg::Type::NUM, RPCArg::Optional::OMITTED_NAMED_ARG, "how long to wait in ms", "", {}, /*hidden=*/true},
     187             :                 },
     188         292 :                 RPCResult{RPCResult::Type::STR, "", "A string with the content '" + RESULT + "'"},
     189         292 :                 RPCExamples{""},
     190         292 :         [&](const RPCHelpMan& self, const JSONRPCRequest& jsonRequest) -> UniValue
     191             : {
     192             :     // Event loop will exit after current HTTP requests have been handled, so
     193             :     // this reply will get back to the client.
     194           0 :     StartShutdown();
     195           0 :     if (jsonRequest.params[0].isNum()) {
     196           0 :         UninterruptibleSleep(std::chrono::milliseconds{jsonRequest.params[0].getInt<int>()});
     197           0 :     }
     198           0 :     return RESULT;
     199             : },
     200             :     };
     201           0 : }
     202             : 
     203         292 : static RPCHelpMan uptime()
     204             : {
     205         584 :     return RPCHelpMan{"uptime",
     206         292 :                 "\nReturns the total uptime of the server.\n",
     207         292 :                             {},
     208         292 :                             RPCResult{
     209         292 :                                 RPCResult::Type::NUM, "", "The number of seconds that the server has been running"
     210             :                             },
     211         292 :                 RPCExamples{
     212         292 :                     HelpExampleCli("uptime", "")
     213         292 :                 + HelpExampleRpc("uptime", "")
     214             :                 },
     215         292 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
     216             : {
     217           0 :     return GetTime() - GetStartupTime();
     218             : }
     219             :     };
     220           0 : }
     221             : 
     222         292 : static RPCHelpMan getrpcinfo()
     223             : {
     224         584 :     return RPCHelpMan{"getrpcinfo",
     225         292 :                 "\nReturns details of the RPC server.\n",
     226         292 :                 {},
     227         292 :                 RPCResult{
     228         292 :                     RPCResult::Type::OBJ, "", "",
     229         876 :                     {
     230         584 :                         {RPCResult::Type::ARR, "active_commands", "All active commands",
     231         584 :                         {
     232         584 :                             {RPCResult::Type::OBJ, "", "Information about an active command",
     233         876 :                             {
     234         292 :                                  {RPCResult::Type::STR, "method", "The name of the RPC command"},
     235         292 :                                  {RPCResult::Type::NUM, "duration", "The running time in microseconds"},
     236             :                             }},
     237             :                         }},
     238         292 :                         {RPCResult::Type::STR, "logpath", "The complete file path to the debug log"},
     239             :                     }
     240             :                 },
     241         292 :                 RPCExamples{
     242         292 :                     HelpExampleCli("getrpcinfo", "")
     243         292 :                 + HelpExampleRpc("getrpcinfo", "")},
     244         292 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
     245             : {
     246           0 :     LOCK(g_rpc_server_info.mutex);
     247           0 :     UniValue active_commands(UniValue::VARR);
     248           0 :     for (const RPCCommandExecutionInfo& info : g_rpc_server_info.active_commands) {
     249           0 :         UniValue entry(UniValue::VOBJ);
     250           0 :         entry.pushKV("method", info.method);
     251           0 :         entry.pushKV("duration", int64_t{Ticks<std::chrono::microseconds>(SteadyClock::now() - info.start)});
     252           0 :         active_commands.push_back(entry);
     253           0 :     }
     254             : 
     255           0 :     UniValue result(UniValue::VOBJ);
     256           0 :     result.pushKV("active_commands", active_commands);
     257             : 
     258           0 :     const std::string path = LogInstance().m_file_path.utf8string();
     259           0 :     UniValue log_path(UniValue::VSTR, path);
     260           0 :     result.pushKV("logpath", log_path);
     261             : 
     262           0 :     return result;
     263           0 : }
     264             :     };
     265           0 : }
     266             : 
     267         730 : static const CRPCCommand vRPCCommands[]{
     268             :     /* Overall control/query calls */
     269         146 :     {"control", &getrpcinfo},
     270         146 :     {"control", &help},
     271         146 :     {"control", &stop},
     272         146 :     {"control", &uptime},
     273             : };
     274             : 
     275         306 : CRPCTable::CRPCTable()
     276         153 : {
     277         765 :     for (const auto& c : vRPCCommands) {
     278         612 :         appendCommand(c.name, &c);
     279             :     }
     280         306 : }
     281             : 
     282       30997 : void CRPCTable::appendCommand(const std::string& name, const CRPCCommand* pcmd)
     283             : {
     284       30997 :     CHECK_NONFATAL(!IsRPCRunning()); // Only add commands before rpc is running
     285             : 
     286       30997 :     mapCommands[name].push_back(pcmd);
     287       30997 : }
     288             : 
     289        1008 : bool CRPCTable::removeCommand(const std::string& name, const CRPCCommand* pcmd)
     290             : {
     291        1008 :     auto it = mapCommands.find(name);
     292        1008 :     if (it != mapCommands.end()) {
     293        1008 :         auto new_end = std::remove(it->second.begin(), it->second.end(), pcmd);
     294        1008 :         if (it->second.end() != new_end) {
     295        1008 :             it->second.erase(new_end, it->second.end());
     296        1008 :             return true;
     297             :         }
     298           0 :     }
     299           0 :     return false;
     300        1008 : }
     301             : 
     302           0 : void StartRPC()
     303             : {
     304           0 :     LogPrint(BCLog::RPC, "Starting RPC\n");
     305           0 :     g_rpc_running = true;
     306           0 :     g_rpcSignals.Started();
     307           0 : }
     308             : 
     309           0 : void InterruptRPC()
     310             : {
     311             :     static std::once_flag g_rpc_interrupt_flag;
     312             :     // This function could be called twice if the GUI has been started with -server=1.
     313           0 :     std::call_once(g_rpc_interrupt_flag, []() {
     314           0 :         LogPrint(BCLog::RPC, "Interrupting RPC\n");
     315             :         // Interrupt e.g. running longpolls
     316           0 :         g_rpc_running = false;
     317           0 :     });
     318           0 : }
     319             : 
     320           0 : void StopRPC()
     321             : {
     322             :     static std::once_flag g_rpc_stop_flag;
     323             :     // This function could be called twice if the GUI has been started with -server=1.
     324           0 :     assert(!g_rpc_running);
     325           0 :     std::call_once(g_rpc_stop_flag, []() {
     326           0 :         LogPrint(BCLog::RPC, "Stopping RPC\n");
     327           0 :         WITH_LOCK(g_deadline_timers_mutex, deadlineTimers.clear());
     328           0 :         DeleteAuthCookie();
     329           0 :         g_rpcSignals.Stopped();
     330           0 :     });
     331           0 : }
     332             : 
     333       30997 : bool IsRPCRunning()
     334             : {
     335       30997 :     return g_rpc_running;
     336             : }
     337             : 
     338           0 : void RpcInterruptionPoint()
     339             : {
     340           0 :     if (!IsRPCRunning()) throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, "Shutting down");
     341           0 : }
     342             : 
     343           0 : void SetRPCWarmupStatus(const std::string& newStatus)
     344             : {
     345           0 :     LOCK(g_rpc_warmup_mutex);
     346           0 :     rpcWarmupStatus = newStatus;
     347           0 : }
     348             : 
     349           1 : void SetRPCWarmupFinished()
     350             : {
     351           1 :     LOCK(g_rpc_warmup_mutex);
     352           1 :     assert(fRPCInWarmup);
     353           1 :     fRPCInWarmup = false;
     354           1 : }
     355             : 
     356          73 : bool RPCIsInWarmup(std::string *outStatus)
     357             : {
     358          73 :     LOCK(g_rpc_warmup_mutex);
     359          73 :     if (outStatus)
     360           0 :         *outStatus = rpcWarmupStatus;
     361          73 :     return fRPCInWarmup;
     362          73 : }
     363             : 
     364           2 : bool IsDeprecatedRPCEnabled(const std::string& method)
     365             : {
     366           2 :     const std::vector<std::string> enabled_methods = gArgs.GetArgs("-deprecatedrpc");
     367             : 
     368           2 :     return find(enabled_methods.begin(), enabled_methods.end(), method) != enabled_methods.end();
     369           2 : }
     370             : 
     371           0 : static UniValue JSONRPCExecOne(JSONRPCRequest jreq, const UniValue& req)
     372             : {
     373           0 :     UniValue rpc_result(UniValue::VOBJ);
     374             : 
     375             :     try {
     376           0 :         jreq.parse(req);
     377             : 
     378           0 :         UniValue result = tableRPC.execute(jreq);
     379           0 :         rpc_result = JSONRPCReplyObj(result, NullUniValue, jreq.id);
     380           0 :     }
     381             :     catch (const UniValue& objError)
     382             :     {
     383           0 :         rpc_result = JSONRPCReplyObj(NullUniValue, objError, jreq.id);
     384           0 :     }
     385             :     catch (const std::exception& e)
     386             :     {
     387           0 :         rpc_result = JSONRPCReplyObj(NullUniValue,
     388           0 :                                      JSONRPCError(RPC_PARSE_ERROR, e.what()), jreq.id);
     389           0 :     }
     390             : 
     391           0 :     return rpc_result;
     392           0 : }
     393             : 
     394           0 : std::string JSONRPCExecBatch(const JSONRPCRequest& jreq, const UniValue& vReq)
     395             : {
     396           0 :     UniValue ret(UniValue::VARR);
     397           0 :     for (unsigned int reqIdx = 0; reqIdx < vReq.size(); reqIdx++)
     398           0 :         ret.push_back(JSONRPCExecOne(jreq, vReq[reqIdx]));
     399             : 
     400           0 :     return ret.write() + "\n";
     401           0 : }
     402             : 
     403             : /**
     404             :  * Process named arguments into a vector of positional arguments, based on the
     405             :  * passed-in specification for the RPC call's arguments.
     406             :  */
     407           6 : static inline JSONRPCRequest transformNamedArguments(const JSONRPCRequest& in, const std::vector<std::string>& argNames)
     408             : {
     409           6 :     JSONRPCRequest out = in;
     410           6 :     out.params = UniValue(UniValue::VARR);
     411             :     // Build a map of parameters, and remove ones that have been processed, so that we can throw a focused error if
     412             :     // there is an unknown one.
     413           6 :     const std::vector<std::string>& keys = in.params.getKeys();
     414           6 :     const std::vector<UniValue>& values = in.params.getValues();
     415           6 :     std::unordered_map<std::string, const UniValue*> argsIn;
     416          18 :     for (size_t i=0; i<keys.size(); ++i) {
     417          13 :         auto [_, inserted] = argsIn.emplace(keys[i], &values[i]);
     418          13 :         if (!inserted) {
     419           1 :             throw JSONRPCError(RPC_INVALID_PARAMETER, "Parameter " + keys[i] + " specified multiple times");
     420             :         }
     421          12 :     }
     422             :     // Process expected parameters. If any parameters were left unspecified in
     423             :     // the request before a parameter that was specified, null values need to be
     424             :     // inserted at the unspecified parameter positions, and the "hole" variable
     425             :     // below tracks the number of null values that need to be inserted.
     426             :     // The "initial_hole_size" variable stores the size of the initial hole,
     427             :     // i.e. how many initial positional arguments were left unspecified. This is
     428             :     // used after the for-loop to add initial positional arguments from the
     429             :     // "args" parameter, if present.
     430           5 :     int hole = 0;
     431           5 :     int initial_hole_size = 0;
     432          30 :     for (const std::string &argNamePattern: argNames) {
     433          25 :         std::vector<std::string> vargNames = SplitString(argNamePattern, '|');
     434          25 :         auto fr = argsIn.end();
     435          43 :         for (const std::string & argName : vargNames) {
     436          25 :             fr = argsIn.find(argName);
     437          25 :             if (fr != argsIn.end()) {
     438           7 :                 break;
     439             :             }
     440             :         }
     441          25 :         if (fr != argsIn.end()) {
     442          15 :             for (int i = 0; i < hole; ++i) {
     443             :                 // Fill hole between specified parameters with JSON nulls,
     444             :                 // but not at the end (for backwards compatibility with calls
     445             :                 // that act based on number of specified parameters).
     446           8 :                 out.params.push_back(UniValue());
     447           8 :             }
     448           7 :             hole = 0;
     449           7 :             out.params.push_back(*fr->second);
     450           7 :             argsIn.erase(fr);
     451           7 :         } else {
     452          18 :             hole += 1;
     453          18 :             if (out.params.empty()) initial_hole_size = hole;
     454             :         }
     455          25 :     }
     456             :     // If leftover "args" param was found, use it as a source of positional
     457             :     // arguments and add named arguments after. This is a convenience for
     458             :     // clients that want to pass a combination of named and positional
     459             :     // arguments as described in doc/JSON-RPC-interface.md#parameter-passing
     460           5 :     auto positional_args{argsIn.extract("args")};
     461           5 :     if (positional_args && positional_args.mapped()->isArray()) {
     462           3 :         const bool has_named_arguments{initial_hole_size < (int)argNames.size()};
     463           3 :         if (initial_hole_size < (int)positional_args.mapped()->size() && has_named_arguments) {
     464           1 :             throw JSONRPCError(RPC_INVALID_PARAMETER, "Parameter " + argNames[initial_hole_size] + " specified twice both as positional and named argument");
     465             :         }
     466             :         // Assign positional_args to out.params and append named_args after.
     467           2 :         UniValue named_args{std::move(out.params)};
     468           2 :         out.params = *positional_args.mapped();
     469           5 :         for (size_t i{out.params.size()}; i < named_args.size(); ++i) {
     470           3 :             out.params.push_back(named_args[i]);
     471           3 :         }
     472           2 :     }
     473             :     // If there are still arguments in the argsIn map, this is an error.
     474           4 :     if (!argsIn.empty()) {
     475           1 :         throw JSONRPCError(RPC_INVALID_PARAMETER, "Unknown named parameter " + argsIn.begin()->first);
     476             :     }
     477             :     // Return request with named arguments transformed to positional arguments
     478           3 :     return out;
     479           9 : }
     480             : 
     481          49 : static bool ExecuteCommands(const std::vector<const CRPCCommand*>& commands, const JSONRPCRequest& request, UniValue& result)
     482             : {
     483          49 :     for (const auto& command : commands) {
     484          49 :         if (ExecuteCommand(*command, request, result, &command == &commands.back())) {
     485          49 :             return true;
     486             :         }
     487             :     }
     488           0 :     return false;
     489          49 : }
     490             : 
     491          73 : UniValue CRPCTable::execute(const JSONRPCRequest &request) const
     492             : {
     493             :     // Return immediately if in warmup
     494             :     {
     495          73 :         LOCK(g_rpc_warmup_mutex);
     496          73 :         if (fRPCInWarmup)
     497           0 :             throw JSONRPCError(RPC_IN_WARMUP, rpcWarmupStatus);
     498          97 :     }
     499             : 
     500          73 :     auto it = mapCommands.end();
     501             : 
     502          73 :     std::string subcommand;
     503          73 :     if (request.params.size() > 0 && request.params[0].isStr()) {
     504          32 :         subcommand = request.params[0].get_str();
     505          32 :         it = mapCommands.find(request.strMethod + " " + subcommand);
     506          32 :     }
     507             : 
     508             :     // Find method
     509          73 :     if (it == mapCommands.end()) {
     510          63 :         it = mapCommands.find(request.strMethod);
     511          63 :         subcommand.clear();
     512          63 :     }
     513          73 :     if (it != mapCommands.end()) {
     514          73 :         UniValue result;
     515          73 :         const JSONRPCRequest new_request{subcommand.empty() ? request : request.squashed() };
     516          73 :         if (ExecuteCommands(it->second, new_request, result)) {
     517          49 :             return result;
     518             :         }
     519          73 :     }
     520           0 :     throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found");
     521          97 : }
     522             : 
     523          73 : static bool ExecuteCommand(const CRPCCommand& command, const JSONRPCRequest& request, UniValue& result, bool last_handler)
     524             : {
     525             :     try {
     526          73 :         RPCCommandExecution execution(request.strMethod);
     527             :         // Execute, convert arguments to array if necessary
     528          73 :         if (request.params.isObject()) {
     529           6 :             return command.actor(transformNamedArguments(request, command.argNames), result, last_handler);
     530             :         } else {
     531          67 :             return command.actor(request, result, last_handler);
     532             :         }
     533          81 :     } catch (const UniValue::type_error& e) {
     534           0 :         throw JSONRPCError(RPC_TYPE_ERROR, e.what());
     535           0 :     } catch (const std::exception& e) {
     536           8 :         throw JSONRPCError(RPC_MISC_ERROR, e.what());
     537           8 :     }
     538          81 : }
     539             : 
     540           0 : std::vector<std::string> CRPCTable::listCommands() const
     541             : {
     542           0 :     std::vector<std::string> commandList;
     543           0 :     for (const auto& i : mapCommands) commandList.emplace_back(i.first);
     544           0 :     return commandList;
     545           0 : }
     546             : 
     547           0 : UniValue CRPCTable::dumpArgMap(const JSONRPCRequest& args_request) const
     548             : {
     549           0 :     JSONRPCRequest request(args_request);
     550           0 :     request.mode = JSONRPCRequest::GET_ARGS;
     551             : 
     552           0 :     UniValue ret{UniValue::VARR};
     553           0 :     for (const auto& cmd : mapCommands) {
     554             :         // TODO: implement mapping argument to type for composite commands
     555           0 :         if (cmd.first.find(' ') != std::string::npos) continue;
     556           0 :         UniValue result;
     557           0 :         if (ExecuteCommands(cmd.second, request, result)) {
     558           0 :             for (const auto& values : result.getValues()) {
     559           0 :                 ret.push_back(values);
     560             :             }
     561           0 :         }
     562           0 :     }
     563           0 :     return ret;
     564           0 : }
     565             : 
     566           0 : void RPCSetTimerInterfaceIfUnset(RPCTimerInterface *iface)
     567             : {
     568           0 :     if (!timerInterface)
     569           0 :         timerInterface = iface;
     570           0 : }
     571             : 
     572           0 : void RPCSetTimerInterface(RPCTimerInterface *iface)
     573             : {
     574           0 :     timerInterface = iface;
     575           0 : }
     576             : 
     577           0 : void RPCUnsetTimerInterface(RPCTimerInterface *iface)
     578             : {
     579           0 :     if (timerInterface == iface)
     580           0 :         timerInterface = nullptr;
     581           0 : }
     582             : 
     583           0 : void RPCRunLater(const std::string& name, std::function<void()> func, int64_t nSeconds)
     584             : {
     585           0 :     if (!timerInterface)
     586           0 :         throw JSONRPCError(RPC_INTERNAL_ERROR, "No timer handler registered for RPC");
     587           0 :     LOCK(g_deadline_timers_mutex);
     588           0 :     deadlineTimers.erase(name);
     589           0 :     LogPrint(BCLog::RPC, "queue run of timer %s in %i seconds (using %s)\n", name, nSeconds, timerInterface->Name());
     590           0 :     deadlineTimers.emplace(name, std::unique_ptr<RPCTimerBase>(timerInterface->NewTimer(func, nSeconds*1000)));
     591           0 : }
     592             : 
     593         146 : CRPCTable tableRPC;

Generated by: LCOV version 1.16