LCOV - code coverage report
Current view: top level - src/rpc - server.cpp (source / functions) Hit Total Coverage
Test: fuzz_coverage.info Lines: 76 371 20.5 %
Date: 2023-09-26 12:08:55 Functions: 23 60 38.3 %

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

Generated by: LCOV version 1.14