LCOV - code coverage report
Current view: top level - src/rpc - server.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 338 362 93.4 %
Date: 2026-06-25 07:23:43 Functions: 55 61 90.2 %

          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        3308 : 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        3308 : static RPCServerInfo g_rpc_server_info;
      50             : 
      51             : struct RPCCommandExecution
      52             : {
      53             :     std::list<RPCCommandExecutionInfo>::iterator it;
      54      992336 :     explicit RPCCommandExecution(const std::string& method)
      55      496168 :     {
      56      496168 :         LOCK(g_rpc_server_info.mutex);
      57      496168 :         it = g_rpc_server_info.active_commands.insert(g_rpc_server_info.active_commands.end(), {method, SteadyClock::now()});
      58      992336 :     }
      59      992336 :     ~RPCCommandExecution()
      60      496168 :     {
      61      496168 :         LOCK(g_rpc_server_info.mutex);
      62      496168 :         g_rpc_server_info.active_commands.erase(it);
      63      992336 :     }
      64             : };
      65             : 
      66        3308 : static struct CRPCSignals
      67             : {
      68             :     boost::signals2::signal<void ()> Started;
      69             :     boost::signals2::signal<void ()> Stopped;
      70        3308 : } g_rpcSignals;
      71             : 
      72        3019 : void RPCServer::OnStarted(std::function<void ()> slot)
      73             : {
      74        3019 :     g_rpcSignals.Started.connect(slot);
      75        3019 : }
      76             : 
      77        3019 : void RPCServer::OnStopped(std::function<void ()> slot)
      78             : {
      79        3019 :     g_rpcSignals.Stopped.connect(slot);
      80        3019 : }
      81             : 
      82         410 : std::string CRPCTable::help(const std::string& strCommand, const JSONRPCRequest& helpreq) const
      83             : {
      84         410 :     std::string strRet;
      85         410 :     std::string category;
      86         410 :     std::set<intptr_t> setDone;
      87         410 :     std::vector<std::pair<std::string, const CRPCCommand*> > vCommands;
      88             : 
      89      111330 :     for (const auto& entry : mapCommands)
      90      110920 :         vCommands.emplace_back(entry.second.front()->category + entry.first, entry.second.front());
      91         410 :     sort(vCommands.begin(), vCommands.end());
      92             : 
      93         410 :     JSONRPCRequest jreq = helpreq;
      94         410 :     jreq.mode = JSONRPCRequest::GET_HELP;
      95         410 :     jreq.params = UniValue();
      96             : 
      97      111330 :     for (const std::pair<std::string, const CRPCCommand*>& command : vCommands)
      98             :     {
      99      110920 :         const CRPCCommand *pcmd = command.second;
     100      110920 :         std::string strMethod = pcmd->name;
     101      110920 :         if ((strCommand != "" || pcmd->category == "hidden") && strMethod != strCommand)
     102      107336 :             continue;
     103             : 
     104        3584 :         const auto pos_separator{strMethod.find(' ')};
     105        3584 :         const bool is_composite{pos_separator != std::string::npos};
     106        3584 :         if (strCommand.empty() && is_composite) continue;
     107             : 
     108        2804 :         jreq.strMethod = strMethod;
     109             :         try
     110             :         {
     111        2804 :             if (is_composite) {
     112           0 :                 jreq.params.setArray();
     113           0 :                 jreq.params.push_back(strCommand.substr(pos_separator + 1));
     114           0 :             }
     115        2804 :             UniValue unused_result;
     116        2804 :             if (setDone.insert(pcmd->unique_id).second)
     117        2804 :                 pcmd->actor(jreq, unused_result, true /* last_handler */);
     118        2804 :         }
     119             :         catch (const std::exception& e)
     120             :         {
     121             :             // Help text is returned in an exception
     122        2804 :             std::string strHelp = std::string(e.what());
     123        2804 :             if (strCommand == "")
     124             :             {
     125        2414 :                 if (strHelp.find('\n') != std::string::npos)
     126        2414 :                     strHelp = strHelp.substr(0, strHelp.find('\n'));
     127             : 
     128        2414 :                 if (category != pcmd->category)
     129             :                 {
     130         152 :                     if (!category.empty())
     131         138 :                         strRet += "\n";
     132         152 :                     category = pcmd->category;
     133         152 :                     strRet += "== " + Capitalize(category) + " ==\n";
     134         152 :                 }
     135        2414 :             }
     136        2804 :             strRet += strHelp + "\n";
     137        2804 :         }
     138      110920 :     }
     139         410 :     if (strRet == "")
     140           6 :         strRet = strprintf("help: unknown command: %s\n", strCommand);
     141         410 :     strRet = strRet.substr(0,strRet.size()-1);
     142         410 :     return strRet;
     143        3214 : }
     144             : 
     145        7050 : static RPCHelpMan help()
     146             : {
     147       14100 :     return RPCHelpMan{"help",
     148        7050 :                 "\nList all commands, or get help for a specified command.\n",
     149       21150 :                 {
     150        7050 :                     {"command", RPCArg::Type::STR, RPCArg::DefaultHint{"all commands"}, "The command to get help on"},
     151        7050 :                     {"subcommand", RPCArg::Type::STR, RPCArg::DefaultHint{"all subcommands"}, "The subcommand to get help on."},
     152             :                 },
     153       21150 :                 {
     154        7050 :                     RPCResult{RPCResult::Type::STR, "", "The help text"},
     155        7050 :                     RPCResult{RPCResult::Type::ANY, "", ""},
     156             :                 },
     157        7050 :                 RPCExamples{""},
     158        7464 :         [&](const RPCHelpMan& self, const JSONRPCRequest& jsonRequest) -> UniValue
     159             : {
     160         414 :     std::string strCommand, strSubCommand;
     161         414 :     if (jsonRequest.params.size() > 0) {
     162         400 :         strCommand = jsonRequest.params[0].get_str();
     163         398 :     }
     164         412 :     if (jsonRequest.params.size() > 1) {
     165           0 :         strCommand += " " + jsonRequest.params[1].get_str();
     166           0 :     }
     167         412 :     if (strCommand == "dump_all_command_conversions") {
     168             :         // Used for testing only, undocumented
     169           2 :         return tableRPC.dumpArgMap(jsonRequest);
     170             :     }
     171             : 
     172         410 :     return tableRPC.help(strCommand, jsonRequest);
     173         414 : },
     174             :     };
     175           0 : }
     176             : 
     177        9433 : static RPCHelpMan stop()
     178             : {
     179             :     static const std::string RESULT{PACKAGE_NAME " stopping"};
     180       18866 :     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        9433 :                 "\nRequest a graceful shutdown of " PACKAGE_NAME ".",
     185       18866 :                 {
     186        9433 :                     {"wait", RPCArg::Type::NUM, RPCArg::Optional::OMITTED_NAMED_ARG, "how long to wait in ms", "", {}, /*hidden=*/true},
     187             :                 },
     188        9433 :                 RPCResult{RPCResult::Type::STR, "", "A string with the content '" + RESULT + "'"},
     189        9433 :                 RPCExamples{""},
     190       12232 :         [&](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        2799 :     StartShutdown();
     195        2799 :     if (jsonRequest.params[0].isNum()) {
     196        2791 :         UninterruptibleSleep(std::chrono::milliseconds{jsonRequest.params[0].getInt<int>()});
     197        2791 :     }
     198        2799 :     return RESULT;
     199             : },
     200             :     };
     201           0 : }
     202             : 
     203        6636 : static RPCHelpMan uptime()
     204             : {
     205       13272 :     return RPCHelpMan{"uptime",
     206        6636 :                 "\nReturns the total uptime of the server.\n",
     207        6636 :                             {},
     208        6636 :                             RPCResult{
     209        6636 :                                 RPCResult::Type::NUM, "", "The number of seconds that the server has been running"
     210             :                             },
     211        6636 :                 RPCExamples{
     212        6636 :                     HelpExampleCli("uptime", "")
     213        6636 :                 + HelpExampleRpc("uptime", "")
     214             :                 },
     215        6638 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
     216             : {
     217           2 :     return GetTime() - GetStartupTime();
     218             : }
     219             :     };
     220           0 : }
     221             : 
     222        6783 : static RPCHelpMan getrpcinfo()
     223             : {
     224       13566 :     return RPCHelpMan{"getrpcinfo",
     225        6783 :                 "\nReturns details of the RPC server.\n",
     226        6783 :                 {},
     227        6783 :                 RPCResult{
     228        6783 :                     RPCResult::Type::OBJ, "", "",
     229       20349 :                     {
     230       13566 :                         {RPCResult::Type::ARR, "active_commands", "All active commands",
     231       13566 :                         {
     232       13566 :                             {RPCResult::Type::OBJ, "", "Information about an active command",
     233       20349 :                             {
     234        6783 :                                  {RPCResult::Type::STR, "method", "The name of the RPC command"},
     235        6783 :                                  {RPCResult::Type::NUM, "duration", "The running time in microseconds"},
     236             :                             }},
     237             :                         }},
     238        6783 :                         {RPCResult::Type::STR, "logpath", "The complete file path to the debug log"},
     239             :                     }
     240             :                 },
     241        6783 :                 RPCExamples{
     242        6783 :                     HelpExampleCli("getrpcinfo", "")
     243        6783 :                 + HelpExampleRpc("getrpcinfo", "")},
     244        6932 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
     245             : {
     246         149 :     LOCK(g_rpc_server_info.mutex);
     247         149 :     UniValue active_commands(UniValue::VARR);
     248         300 :     for (const RPCCommandExecutionInfo& info : g_rpc_server_info.active_commands) {
     249         151 :         UniValue entry(UniValue::VOBJ);
     250         151 :         entry.pushKV("method", info.method);
     251         151 :         entry.pushKV("duration", int64_t{Ticks<std::chrono::microseconds>(SteadyClock::now() - info.start)});
     252         151 :         active_commands.push_back(entry);
     253         151 :     }
     254             : 
     255         149 :     UniValue result(UniValue::VOBJ);
     256         149 :     result.pushKV("active_commands", active_commands);
     257             : 
     258         149 :     const std::string path = LogInstance().m_file_path.utf8string();
     259         149 :     UniValue log_path(UniValue::VSTR, path);
     260         149 :     result.pushKV("logpath", log_path);
     261             : 
     262         149 :     return result;
     263         149 : }
     264             :     };
     265           0 : }
     266             : 
     267       16540 : static const CRPCCommand vRPCCommands[]{
     268             :     /* Overall control/query calls */
     269        3308 :     {"control", &getrpcinfo},
     270        3308 :     {"control", &help},
     271        3308 :     {"control", &stop},
     272        3308 :     {"control", &uptime},
     273             : };
     274             : 
     275        6630 : CRPCTable::CRPCTable()
     276        3315 : {
     277       16575 :     for (const auto& c : vRPCCommands) {
     278       13260 :         appendCommand(c.name, &c);
     279             :     }
     280        6630 : }
     281             : 
     282      696545 : void CRPCTable::appendCommand(const std::string& name, const CRPCCommand* pcmd)
     283             : {
     284      696545 :     CHECK_NONFATAL(!IsRPCRunning()); // Only add commands before rpc is running
     285             : 
     286      696545 :     mapCommands[name].push_back(pcmd);
     287      696545 : }
     288             : 
     289      150352 : bool CRPCTable::removeCommand(const std::string& name, const CRPCCommand* pcmd)
     290             : {
     291      150352 :     auto it = mapCommands.find(name);
     292      150352 :     if (it != mapCommands.end()) {
     293      150352 :         auto new_end = std::remove(it->second.begin(), it->second.end(), pcmd);
     294      150352 :         if (it->second.end() != new_end) {
     295      150352 :             it->second.erase(new_end, it->second.end());
     296      150352 :             return true;
     297             :         }
     298           0 :     }
     299           0 :     return false;
     300      150352 : }
     301             : 
     302        3019 : void StartRPC()
     303             : {
     304        3019 :     LogPrint(BCLog::RPC, "Starting RPC\n");
     305        3019 :     g_rpc_running = true;
     306        3019 :     g_rpcSignals.Started();
     307        3019 : }
     308             : 
     309        3030 : 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        6060 :     std::call_once(g_rpc_interrupt_flag, []() {
     314        3030 :         LogPrint(BCLog::RPC, "Interrupting RPC\n");
     315             :         // Interrupt e.g. running longpolls
     316        3030 :         g_rpc_running = false;
     317        3030 :     });
     318        3030 : }
     319             : 
     320        3030 : 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        3030 :     assert(!g_rpc_running);
     325        6060 :     std::call_once(g_rpc_stop_flag, []() {
     326        3030 :         LogPrint(BCLog::RPC, "Stopping RPC\n");
     327        6060 :         WITH_LOCK(g_deadline_timers_mutex, deadlineTimers.clear());
     328        3030 :         DeleteAuthCookie();
     329        3030 :         g_rpcSignals.Stopped();
     330        3030 :     });
     331        3030 : }
     332             : 
     333      721546 : bool IsRPCRunning()
     334             : {
     335      721546 :     return g_rpc_running;
     336             : }
     337             : 
     338       24907 : void RpcInterruptionPoint()
     339             : {
     340       24907 :     if (!IsRPCRunning()) throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, "Shutting down");
     341       24907 : }
     342             : 
     343       21228 : void SetRPCWarmupStatus(const std::string& newStatus)
     344             : {
     345       21228 :     LOCK(g_rpc_warmup_mutex);
     346       21228 :     rpcWarmupStatus = newStatus;
     347       21228 : }
     348             : 
     349        2822 : void SetRPCWarmupFinished()
     350             : {
     351        2822 :     LOCK(g_rpc_warmup_mutex);
     352        2822 :     assert(fRPCInWarmup);
     353        2822 :     fRPCInWarmup = false;
     354        2822 : }
     355             : 
     356         185 : bool RPCIsInWarmup(std::string *outStatus)
     357             : {
     358         185 :     LOCK(g_rpc_warmup_mutex);
     359         185 :     if (outStatus)
     360         112 :         *outStatus = rpcWarmupStatus;
     361         185 :     return fRPCInWarmup;
     362         185 : }
     363             : 
     364      104227 : bool IsDeprecatedRPCEnabled(const std::string& method)
     365             : {
     366      104227 :     const std::vector<std::string> enabled_methods = gArgs.GetArgs("-deprecatedrpc");
     367             : 
     368      104227 :     return find(enabled_methods.begin(), enabled_methods.end(), method) != enabled_methods.end();
     369      104227 : }
     370             : 
     371         440 : static UniValue JSONRPCExecOne(JSONRPCRequest jreq, const UniValue& req)
     372             : {
     373         440 :     UniValue rpc_result(UniValue::VOBJ);
     374             : 
     375             :     try {
     376         440 :         jreq.parse(req);
     377             : 
     378         440 :         UniValue result = tableRPC.execute(jreq);
     379         382 :         rpc_result = JSONRPCReplyObj(result, NullUniValue, jreq.id);
     380         440 :     }
     381             :     catch (const UniValue& objError)
     382             :     {
     383          58 :         rpc_result = JSONRPCReplyObj(NullUniValue, objError, jreq.id);
     384          58 :     }
     385             :     catch (const std::exception& e)
     386             :     {
     387           0 :         rpc_result = JSONRPCReplyObj(NullUniValue,
     388           0 :                                      JSONRPCError(RPC_PARSE_ERROR, e.what()), jreq.id);
     389          58 :     }
     390             : 
     391         440 :     return rpc_result;
     392         498 : }
     393             : 
     394          64 : std::string JSONRPCExecBatch(const JSONRPCRequest& jreq, const UniValue& vReq)
     395             : {
     396          64 :     UniValue ret(UniValue::VARR);
     397         504 :     for (unsigned int reqIdx = 0; reqIdx < vReq.size(); reqIdx++)
     398         440 :         ret.push_back(JSONRPCExecOne(jreq, vReq[reqIdx]));
     399             : 
     400          64 :     return ret.write() + "\n";
     401          64 : }
     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       32200 : static inline JSONRPCRequest transformNamedArguments(const JSONRPCRequest& in, const std::vector<std::string>& argNames)
     408             : {
     409       32200 :     JSONRPCRequest out = in;
     410       32200 :     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       32200 :     const std::vector<std::string>& keys = in.params.getKeys();
     414       32200 :     const std::vector<UniValue>& values = in.params.getValues();
     415       32200 :     std::unordered_map<std::string, const UniValue*> argsIn;
     416      101470 :     for (size_t i=0; i<keys.size(); ++i) {
     417       69275 :         auto [_, inserted] = argsIn.emplace(keys[i], &values[i]);
     418       69275 :         if (!inserted) {
     419           5 :             throw JSONRPCError(RPC_INVALID_PARAMETER, "Parameter " + keys[i] + " specified multiple times");
     420             :         }
     421       69270 :     }
     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       32195 :     int hole = 0;
     431       32195 :     int initial_hole_size = 0;
     432      136293 :     for (const std::string &argNamePattern: argNames) {
     433      104098 :         std::vector<std::string> vargNames = SplitString(argNamePattern, '|');
     434      104098 :         auto fr = argsIn.end();
     435      139051 :         for (const std::string & argName : vargNames) {
     436      104154 :             fr = argsIn.find(argName);
     437      104154 :             if (fr != argsIn.end()) {
     438       69201 :                 break;
     439             :             }
     440             :         }
     441      104098 :         if (fr != argsIn.end()) {
     442       74690 :             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        5489 :                 out.params.push_back(UniValue());
     447        5489 :             }
     448       69201 :             hole = 0;
     449       69201 :             out.params.push_back(*fr->second);
     450       69201 :             argsIn.erase(fr);
     451       69201 :         } else {
     452       34897 :             hole += 1;
     453       34897 :             if (out.params.empty()) initial_hole_size = hole;
     454             :         }
     455      104098 :     }
     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       32195 :     auto positional_args{argsIn.extract("args")};
     461       32195 :     if (positional_args && positional_args.mapped()->isArray()) {
     462          55 :         const bool has_named_arguments{initial_hole_size < (int)argNames.size()};
     463          55 :         if (initial_hole_size < (int)positional_args.mapped()->size() && has_named_arguments) {
     464          13 :             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          42 :         UniValue named_args{std::move(out.params)};
     468          42 :         out.params = *positional_args.mapped();
     469         103 :         for (size_t i{out.params.size()}; i < named_args.size(); ++i) {
     470          61 :             out.params.push_back(named_args[i]);
     471          61 :         }
     472          42 :     }
     473             :     // If there are still arguments in the argsIn map, this is an error.
     474       32182 :     if (!argsIn.empty()) {
     475           9 :         throw JSONRPCError(RPC_INVALID_PARAMETER, "Unknown named parameter " + argsIn.begin()->first);
     476             :     }
     477             :     // Return request with named arguments transformed to positional arguments
     478       32173 :     return out;
     479       32227 : }
     480             : 
     481      491224 : static bool ExecuteCommands(const std::vector<const CRPCCommand*>& commands, const JSONRPCRequest& request, UniValue& result)
     482             : {
     483      491224 :     for (const auto& command : commands) {
     484      491224 :         if (ExecuteCommand(*command, request, result, &command == &commands.back())) {
     485      491224 :             return true;
     486             :         }
     487             :     }
     488           0 :     return false;
     489      491224 : }
     490             : 
     491      500480 : UniValue CRPCTable::execute(const JSONRPCRequest &request) const
     492             : {
     493             :     // Return immediately if in warmup
     494             :     {
     495      500480 :         LOCK(g_rpc_warmup_mutex);
     496      500480 :         if (fRPCInWarmup)
     497        4722 :             throw JSONRPCError(RPC_IN_WARMUP, rpcWarmupStatus);
     498      505430 :     }
     499             : 
     500      495758 :     auto it = mapCommands.end();
     501             : 
     502      495758 :     std::string subcommand;
     503      495758 :     if (request.params.size() > 0 && request.params[0].isStr()) {
     504      181918 :         subcommand = request.params[0].get_str();
     505      181918 :         it = mapCommands.find(request.strMethod + " " + subcommand);
     506      181918 :     }
     507             : 
     508             :     // Find method
     509      495758 :     if (it == mapCommands.end()) {
     510      460024 :         it = mapCommands.find(request.strMethod);
     511      460024 :         subcommand.clear();
     512      460024 :     }
     513      495758 :     if (it != mapCommands.end()) {
     514      495752 :         UniValue result;
     515      495752 :         const JSONRPCRequest new_request{subcommand.empty() ? request : request.squashed() };
     516      495752 :         if (ExecuteCommands(it->second, new_request, result)) {
     517      490808 :             return result;
     518             :         }
     519      495752 :     }
     520           6 :     throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found");
     521      505430 : }
     522             : 
     523      496168 : static bool ExecuteCommand(const CRPCCommand& command, const JSONRPCRequest& request, UniValue& result, bool last_handler)
     524             : {
     525             :     try {
     526      496168 :         RPCCommandExecution execution(request.strMethod);
     527             :         // Execute, convert arguments to array if necessary
     528      496168 :         if (request.params.isObject()) {
     529       32200 :             return command.actor(transformNamedArguments(request, command.argNames), result, last_handler);
     530             :         } else {
     531      463968 :             return command.actor(request, result, last_handler);
     532             :         }
     533      496356 :     } catch (const UniValue::type_error& e) {
     534          68 :         throw JSONRPCError(RPC_TYPE_ERROR, e.what());
     535          68 :     } catch (const std::exception& e) {
     536         120 :         throw JSONRPCError(RPC_MISC_ERROR, e.what());
     537         188 :     }
     538      496356 : }
     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           2 : UniValue CRPCTable::dumpArgMap(const JSONRPCRequest& args_request) const
     548             : {
     549           2 :     JSONRPCRequest request(args_request);
     550           2 :     request.mode = JSONRPCRequest::GET_ARGS;
     551             : 
     552           2 :     UniValue ret{UniValue::VARR};
     553         548 :     for (const auto& cmd : mapCommands) {
     554             :         // TODO: implement mapping argument to type for composite commands
     555         546 :         if (cmd.first.find(' ') != std::string::npos) continue;
     556         416 :         UniValue result;
     557         416 :         if (ExecuteCommands(cmd.second, request, result)) {
     558        1208 :             for (const auto& values : result.getValues()) {
     559         792 :                 ret.push_back(values);
     560             :             }
     561         416 :         }
     562         416 :     }
     563           2 :     return ret;
     564           2 : }
     565             : 
     566           0 : void RPCSetTimerInterfaceIfUnset(RPCTimerInterface *iface)
     567             : {
     568           0 :     if (!timerInterface)
     569           0 :         timerInterface = iface;
     570           0 : }
     571             : 
     572        3007 : void RPCSetTimerInterface(RPCTimerInterface *iface)
     573             : {
     574        3007 :     timerInterface = iface;
     575        3007 : }
     576             : 
     577        3007 : void RPCUnsetTimerInterface(RPCTimerInterface *iface)
     578             : {
     579        3007 :     if (timerInterface == iface)
     580        3007 :         timerInterface = nullptr;
     581        3007 : }
     582             : 
     583         140 : void RPCRunLater(const std::string& name, std::function<void()> func, int64_t nSeconds)
     584             : {
     585         140 :     if (!timerInterface)
     586           0 :         throw JSONRPCError(RPC_INTERNAL_ERROR, "No timer handler registered for RPC");
     587         140 :     LOCK(g_deadline_timers_mutex);
     588         140 :     deadlineTimers.erase(name);
     589         140 :     LogPrint(BCLog::RPC, "queue run of timer %s in %i seconds (using %s)\n", name, nSeconds, timerInterface->Name());
     590         140 :     deadlineTimers.emplace(name, std::unique_ptr<RPCTimerBase>(timerInterface->NewTimer(func, nSeconds*1000)));
     591         140 : }
     592             : 
     593        3308 : CRPCTable tableRPC;

Generated by: LCOV version 1.16