LCOV - code coverage report
Current view: top level - src/rpc - server.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 250 298 83.9 %
Date: 2025-02-23 09:33:43 Functions: 36 41 87.8 %

          Line data    Source code
       1             : // Copyright (c) 2010 Satoshi Nakamoto
       2             : // Copyright (c) 2009-2014 The Bitcoin developers
       3             : // Copyright (c) 2014-2015 The Dash developers
       4             : // Copyright (c) 2015-2022 The PIVX Core developers
       5             : // Distributed under the MIT software license, see the accompanying
       6             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       7             : 
       8             : #include "rpc/server.h"
       9             : 
      10             : #include "fs.h"
      11             : #include "key_io.h"
      12             : #include "random.h"
      13             : #include "shutdown.h"
      14             : #include "sync.h"
      15             : #include "guiinterface.h"
      16             : #include "util/system.h"
      17             : #include "utilstrencodings.h"
      18             : 
      19             : #ifdef ENABLE_WALLET
      20             : #include "wallet/wallet.h"
      21             : #endif // ENABLE_WALLET
      22             : 
      23             : #include <boost/signals2/signal.hpp>
      24             : #include <boost/thread.hpp>
      25             : #include <boost/algorithm/string/classification.hpp>
      26             : #include <boost/algorithm/string/split.hpp>
      27             : 
      28             : #include <memory> // for unique_ptr
      29             : #include <unordered_map>
      30             : 
      31             : static std::atomic<bool> g_rpc_running{false};
      32             : static bool fRPCInWarmup = true;
      33             : static std::string rpcWarmupStatus("RPC server started");
      34             : static RecursiveMutex cs_rpcWarmup;
      35             : 
      36             : /* Timer-creating functions */
      37             : static RPCTimerInterface* timerInterface = nullptr;
      38             : /* Map of name to timer. */
      39             : static std::map<std::string, std::unique_ptr<RPCTimerBase>> deadlineTimers;
      40             : 
      41             : static struct CRPCSignals
      42             : {
      43             :     boost::signals2::signal<void ()> Started;
      44             :     boost::signals2::signal<void ()> Stopped;
      45             :     boost::signals2::signal<void (const CRPCCommand&)> PreCommand;
      46             : } g_rpcSignals;
      47             : 
      48         375 : void RPCServer::OnStarted(std::function<void ()> slot)
      49             : {
      50         750 :     g_rpcSignals.Started.connect(slot);
      51         375 : }
      52             : 
      53         375 : void RPCServer::OnStopped(std::function<void ()> slot)
      54             : {
      55         750 :     g_rpcSignals.Stopped.connect(slot);
      56         375 : }
      57             : 
      58         375 : void RPCServer::OnPreCommand(std::function<void (const CRPCCommand&)> slot)
      59             : {
      60         750 :     g_rpcSignals.PreCommand.connect(std::bind(slot, std::placeholders::_1));
      61         375 : }
      62             : 
      63      224873 : void RPCTypeCheck(const UniValue& params,
      64             :                   const std::list<UniValue::VType>& typesExpected,
      65             :                   bool fAllowNull)
      66             : {
      67      224873 :     unsigned int i = 0;
      68      458485 :     for (UniValue::VType t : typesExpected) {
      69      441675 :         if (params.size() <= i)
      70             :             break;
      71             : 
      72      233618 :         const UniValue& v = params[i];
      73      233618 :         if (!((v.type() == t) || (fAllowNull && (v.isNull())))) {
      74           6 :             std::string err = strprintf("Expected type %s, got %s",
      75           6 :                                    uvTypeName(t), uvTypeName(v.type()));
      76           6 :             throw JSONRPCError(RPC_TYPE_ERROR, err);
      77             :         }
      78      233612 :         i++;
      79             :     }
      80      224867 : }
      81             : 
      82         156 : void RPCTypeCheckArgument(const UniValue& value, const UniValueType& typeExpected)
      83             : {
      84         156 :     if (!typeExpected.typeAny && value.type() != typeExpected.type) {
      85           0 :         throw JSONRPCError(RPC_TYPE_ERROR, strprintf("Expected type %s, got %s", uvTypeName(typeExpected.type), uvTypeName(value.type())));
      86             :     }
      87         156 : }
      88             : 
      89          83 : void RPCTypeCheckObj(const UniValue& o,
      90             :     const std::map<std::string, UniValueType>& typesExpected,
      91             :     bool fAllowNull,
      92             :     bool fStrict)
      93             : {
      94         380 :     for (const auto& t : typesExpected) {
      95         300 :         const UniValue& v = find_value(o, t.first);
      96         300 :         if (!fAllowNull && v.isNull())
      97           6 :             throw JSONRPCError(RPC_TYPE_ERROR, strprintf("Missing %s", t.first));
      98             : 
      99         297 :         if (!(t.second.typeAny || v.type() == t.second.type || (fAllowNull && v.isNull()))) {
     100           0 :             std::string err = strprintf("Expected type %s for %s, got %s",
     101           0 :                                         uvTypeName(t.second.type), t.first, uvTypeName(v.type()));
     102           0 :             throw JSONRPCError(RPC_TYPE_ERROR, err);
     103             :         }
     104             :     }
     105             : 
     106          80 :     if (fStrict) {
     107         100 :         for (const std::string& k : o.getKeys()) {
     108         113 :             if (typesExpected.count(k) == 0) {
     109           1 :                 std::string err = strprintf("Unexpected key %s", k);
     110           1 :                 throw JSONRPCError(RPC_TYPE_ERROR, err);
     111             :             }
     112             :         }
     113             :     }
     114          79 : }
     115             : 
     116        7986 : CAmount AmountFromValue(const UniValue& value)
     117             : {
     118        7986 :     if (!value.isNum() && !value.isStr())
     119           0 :         throw JSONRPCError(RPC_TYPE_ERROR,"Amount is not a number or string");
     120        7986 :     CAmount nAmount;
     121        7986 :     if (!ParseFixedPoint(value.getValStr(), 8, &nAmount))
     122          14 :         throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount");
     123        7979 :     if (!Params().GetConsensus().MoneyRange(nAmount))
     124           2 :         throw JSONRPCError(RPC_TYPE_ERROR, "Amount out of range");
     125        7978 :     return nAmount;
     126             : }
     127             : 
     128     1975876 : UniValue ValueFromAmount(const CAmount& amount)
     129             : {
     130     1975876 :     bool sign = amount < 0;
     131     1975876 :     int64_t n_abs = (sign ? -amount : amount);
     132     1975876 :     int64_t quotient = n_abs / COIN;
     133     1975876 :     int64_t remainder = n_abs % COIN;
     134     1975876 :     return UniValue(UniValue::VNUM,
     135     5927236 :             strprintf("%s%d.%08d", sign ? "-" : "", quotient, remainder));
     136             : }
     137             : 
     138        7146 : uint256 ParseHashV(const UniValue& v, std::string strName)
     139             : {
     140        7146 :     std::string strHex(v.get_str());
     141        7144 :     if (64 != strHex.length())
     142          10 :         throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("%s must be of length %d (not %d, for '%s')", strName, 64, strHex.length(), strHex));
     143        7139 :     if (!IsHex(strHex)) // Note: IsHex("") is false
     144           4 :         throw JSONRPCError(RPC_INVALID_PARAMETER, strName + " must be hexadecimal string (not '" + strHex + "')");
     145       21411 :     return uint256S(strHex);
     146             : }
     147        2730 : uint256 ParseHashO(const UniValue& o, std::string strKey)
     148             : {
     149        5457 :     return ParseHashV(find_value(o, strKey), strKey);
     150             : }
     151      102803 : std::vector<unsigned char> ParseHexV(const UniValue& v, std::string strName)
     152             : {
     153      102803 :     std::string strHex;
     154      102803 :     if (v.isStr())
     155      102803 :         strHex = v.get_str();
     156      102803 :     if (!IsHex(strHex))
     157           2 :         throw JSONRPCError(RPC_INVALID_PARAMETER, strName + " must be hexadecimal string (not '" + strHex + "')");
     158      205604 :     return ParseHex(strHex);
     159             : }
     160          14 : std::vector<unsigned char> ParseHexO(const UniValue& o, std::string strKey)
     161             : {
     162          28 :     return ParseHexV(find_value(o, strKey), strKey);
     163             : }
     164             : 
     165           0 : int ParseInt(const UniValue& o, std::string strKey)
     166             : {
     167           0 :     const UniValue& v = find_value(o, strKey);
     168           0 :     if (v.isNum())
     169           0 :         throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, " + strKey + "is not an int");
     170             : 
     171           0 :     return v.get_int();
     172             : }
     173             : 
     174          61 : double ParseDoubleV(const UniValue& v, const std::string &strName)
     175             : {
     176          61 :     std::string strNum = v.getValStr();
     177          61 :     double num;
     178          61 :     if (!ParseDouble(strNum, &num))
     179           0 :         throw JSONRPCError(RPC_INVALID_PARAMETER, strName+" must be a be number (not '"+strNum+"')");
     180          61 :     return num;
     181             : }
     182             : 
     183           0 : bool ParseBool(const UniValue& o, std::string strKey)
     184             : {
     185           0 :     const UniValue& v = find_value(o, strKey);
     186           0 :     if (v.isBool())
     187           0 :         throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, " + strKey + "is not a bool");
     188             : 
     189           0 :     return v.get_bool();
     190             : }
     191             : 
     192             : 
     193             : /**
     194             :  * Note: This interface may still be subject to change.
     195             :  */
     196             : 
     197           1 : std::string CRPCTable::help(const std::string& strCommand, const JSONRPCRequest& helpreq) const
     198             : {
     199           1 :     std::string strRet;
     200           0 :     std::string category;
     201           2 :     std::set<rpcfn_type> setDone;
     202           2 :     std::vector<std::pair<std::string, const CRPCCommand*> > vCommands;
     203             : 
     204         190 :     for (const auto& entry : mapCommands)
     205         378 :         vCommands.emplace_back(entry.second->category + entry.first, entry.second);
     206           1 :     std::sort(vCommands.begin(), vCommands.end());
     207             : 
     208           1 :     JSONRPCRequest jreq(helpreq);
     209           1 :     jreq.fHelp = true;
     210           1 :     jreq.params = UniValue();
     211             : 
     212         190 :     for (const std::pair<std::string, const CRPCCommand*>& command : vCommands) {
     213         189 :         const CRPCCommand* pcmd = command.second;
     214         190 :         std::string strMethod = pcmd->name;
     215         189 :         if ((strCommand != "" || pcmd->category == "hidden") && strMethod != strCommand)
     216         272 :             continue;
     217           1 :         jreq.strMethod = strMethod;
     218           1 :         try {
     219           1 :             rpcfn_type pfn = pcmd->actor;
     220           1 :             if (setDone.insert(pfn).second)
     221           1 :                 (*pfn)(jreq);
     222           1 :         } catch (const std::exception& e) {
     223             :             // Help text is returned in an exception
     224           2 :             std::string strHelp = std::string(e.what());
     225           1 :             if (strCommand == "") {
     226           0 :                 if (strHelp.find('\n') != std::string::npos)
     227           0 :                     strHelp = strHelp.substr(0, strHelp.find('\n'));
     228             : 
     229           0 :                 if (category != pcmd->category) {
     230           0 :                     if (!category.empty())
     231           0 :                         strRet += "\n";
     232           0 :                     category = pcmd->category;
     233           0 :                     strRet += "== " + Capitalize(category) + " ==\n";
     234             :                 }
     235             :             }
     236           3 :             strRet += strHelp + "\n";
     237             :         }
     238             :     }
     239           1 :     if (strRet == "")
     240           0 :         strRet = strprintf("help: unknown command: %s\n", strCommand);
     241           1 :     strRet = strRet.substr(0, strRet.size() - 1);
     242           2 :     return strRet;
     243             : }
     244             : 
     245           1 : UniValue help(const JSONRPCRequest& jsonRequest)
     246             : {
     247           1 :     if (jsonRequest.fHelp || jsonRequest.params.size() > 1)
     248           0 :         throw std::runtime_error(
     249             :             "help ( \"command\" )\n"
     250             :             "\nList all commands, or get help for a specified command.\n"
     251             :             "\nArguments:\n"
     252             :             "1. \"command\"     (string, optional) The command to get help on\n"
     253             :             "\nResult:\n"
     254           0 :             "\"text\"     (string) The help text\n");
     255             : 
     256           1 :     std::string strCommand;
     257           1 :     if (jsonRequest.params.size() > 0)
     258           1 :         strCommand = jsonRequest.params[0].get_str();
     259             : 
     260           3 :     return tableRPC.help(strCommand, jsonRequest);
     261             : }
     262             : 
     263             : 
     264         354 : UniValue stop(const JSONRPCRequest& jsonRequest)
     265             : {
     266             :     // Accept the hidden 'wait' integer argument (milliseconds)
     267             :     // For instance, 'stop 1000' makes the call wait 1 second before returning
     268             :     // to the client (intended for testing)
     269         354 :     if (jsonRequest.fHelp || jsonRequest.params.size() > 1)
     270           0 :         throw std::runtime_error(
     271             :             "stop\n"
     272           0 :             "\nStop PIVX server.");
     273             :     // Event loop will exit after current HTTP requests have been handled, so
     274             :     // this reply will get back to the client.
     275         354 :     StartShutdown();
     276         354 :     if (jsonRequest.params[0].isNum()) {
     277         354 :         MilliSleep(jsonRequest.params[0].get_int());
     278             :     }
     279         354 :     return "PIVX server stopping";
     280             : }
     281             : 
     282             : 
     283             : /**
     284             :  * Call Table
     285             :  */
     286             : static const CRPCCommand vRPCCommands[] =
     287             :     {
     288             :   //  category              name                      actor (function)         okSafe argNames
     289             :   //  --------------------- ------------------------  -----------------------  ------ ----------
     290             :     /* Overall control/query calls */
     291             :     { "control",            "help",                   &help,                   true,  {"command"}  },
     292             :     { "control",            "stop",                   &stop,                   true,  {"wait"}  },
     293             : };
     294             : 
     295         479 : CRPCTable::CRPCTable()
     296             : {
     297         479 :     unsigned int vcidx;
     298        1437 :     for (vcidx = 0; vcidx < (sizeof(vRPCCommands) / sizeof(vRPCCommands[0])); vcidx++) {
     299         958 :         const CRPCCommand* pcmd;
     300             : 
     301         958 :         pcmd = &vRPCCommands[vcidx];
     302         958 :         mapCommands[pcmd->name] = pcmd;
     303             :     }
     304         479 : }
     305             : 
     306      302249 : const CRPCCommand *CRPCTable::operator[](const std::string &name) const
     307             : {
     308      302249 :     std::map<std::string, const CRPCCommand*>::const_iterator it = mapCommands.find(name);
     309      302249 :     if (it == mapCommands.end())
     310             :         return nullptr;
     311      302248 :     return (*it).second;
     312             : }
     313             : 
     314       85234 : bool CRPCTable::appendCommand(const std::string& name, const CRPCCommand* pcmd)
     315             : {
     316       85234 :     if (IsRPCRunning())
     317             :         return false;
     318             : 
     319             :     // don't allow overwriting for now
     320       85234 :     std::map<std::string, const CRPCCommand*>::const_iterator it = mapCommands.find(name);
     321       85234 :     if (it != mapCommands.end())
     322             :         return false;
     323             : 
     324       73671 :     mapCommands[name] = pcmd;
     325       73671 :     return true;
     326             : }
     327             : 
     328         375 : bool StartRPC()
     329             : {
     330         375 :     LogPrint(BCLog::RPC, "Starting RPC\n");
     331         375 :     g_rpc_running = true;
     332         375 :     g_rpcSignals.Started();
     333         375 :     return true;
     334             : }
     335             : 
     336         378 : void InterruptRPC()
     337             : {
     338         378 :     LogPrint(BCLog::RPC, "Interrupting RPC\n");
     339             :     // Interrupt e.g. running longpolls
     340         378 :     g_rpc_running = false;
     341         378 : }
     342             : 
     343         378 : void StopRPC()
     344             : {
     345         378 :     LogPrint(BCLog::RPC, "Stopping RPC\n");
     346         378 :     deadlineTimers.clear();
     347         378 :     DeleteAuthCookie();
     348         378 :     g_rpcSignals.Stopped();
     349         378 : }
     350             : 
     351       85236 : bool IsRPCRunning()
     352             : {
     353       85236 :     return g_rpc_running;
     354             : }
     355             : 
     356        5624 : void SetRPCWarmupStatus(const std::string& newStatus)
     357             : {
     358        5624 :     LOCK(cs_rpcWarmup);
     359        5624 :     rpcWarmupStatus = newStatus;
     360        5624 : }
     361             : 
     362         355 : void SetRPCWarmupFinished()
     363             : {
     364         355 :     LOCK(cs_rpcWarmup);
     365         355 :     assert(fRPCInWarmup);
     366         355 :     fRPCInWarmup = false;
     367         355 : }
     368             : 
     369      298179 : bool RPCIsInWarmup(std::string* outStatus)
     370             : {
     371      298179 :     LOCK(cs_rpcWarmup);
     372      298179 :     if (outStatus)
     373      298179 :         *outStatus = rpcWarmupStatus;
     374      596358 :     return fRPCInWarmup;
     375             : }
     376             : 
     377      298152 : void JSONRPCRequest::parse(const UniValue& valRequest)
     378             : {
     379             :     // Parse request
     380      298152 :     if (!valRequest.isObject())
     381           0 :         throw JSONRPCError(RPC_INVALID_REQUEST, "Invalid Request object");
     382      298152 :     const UniValue& request = valRequest.get_obj();
     383             : 
     384             :     // Parse id now so errors from here on will have the id
     385      298152 :     id = find_value(request, "id");
     386             : 
     387             :     // Parse method
     388      596304 :     UniValue valMethod = find_value(request, "method");
     389      298152 :     if (valMethod.isNull())
     390           0 :         throw JSONRPCError(RPC_INVALID_REQUEST, "Missing method");
     391      298152 :     if (!valMethod.isStr())
     392           0 :         throw JSONRPCError(RPC_INVALID_REQUEST, "Method must be a string");
     393      298152 :     strMethod = valMethod.get_str();
     394      298152 :     if (strMethod != "getblocktemplate")
     395      595099 :         LogPrint(BCLog::RPC, "ThreadRPCServer method=%s\n", SanitizeString(strMethod));
     396             : 
     397             :     // Parse params
     398      596304 :     UniValue valParams = find_value(request, "params");
     399      298152 :     if (valParams.isArray() || valParams.isObject())
     400      298140 :         params = valParams;
     401          12 :     else if (valParams.isNull())
     402          12 :         params = UniValue(UniValue::VARR);
     403             :     else
     404           0 :         throw JSONRPCError(RPC_INVALID_REQUEST, "Params must be an array or object");
     405      298152 : }
     406             : 
     407           0 : bool IsDeprecatedRPCEnabled(const std::string& method)
     408             : {
     409           0 :     const std::vector<std::string> enabled_methods = gArgs.GetArgs("-deprecatedrpc");
     410             : 
     411           0 :     return find(enabled_methods.begin(), enabled_methods.end(), method) != enabled_methods.end();
     412             : }
     413             : 
     414           2 : static UniValue JSONRPCExecOne(const UniValue& req)
     415             : {
     416           2 :     UniValue rpc_result(UniValue::VOBJ);
     417             : 
     418           2 :     JSONRPCRequest jreq;
     419           2 :     try {
     420           2 :         jreq.parse(req);
     421             : 
     422           2 :         UniValue result = tableRPC.execute(jreq);
     423           1 :         rpc_result = JSONRPCReplyObj(result, NullUniValue, jreq.id);
     424           1 :     } catch (const UniValue& objError) {
     425           1 :         rpc_result = JSONRPCReplyObj(NullUniValue, objError, jreq.id);
     426           0 :     } catch (const std::exception& e) {
     427           0 :         rpc_result = JSONRPCReplyObj(NullUniValue,
     428           0 :             JSONRPCError(RPC_PARSE_ERROR, e.what()), jreq.id);
     429             :     }
     430             : 
     431           2 :     return rpc_result;
     432             : }
     433             : 
     434           1 : std::string JSONRPCExecBatch(const UniValue& vReq)
     435             : {
     436           1 :     UniValue ret(UniValue::VARR);
     437           3 :     for (unsigned int reqIdx = 0; reqIdx < vReq.size(); reqIdx++)
     438           2 :         ret.push_back(JSONRPCExecOne(vReq[reqIdx]));
     439             : 
     440           2 :     return ret.write() + "\n";
     441             : }
     442             : 
     443             : /**
     444             :  * Process named arguments into a vector of positional arguments, based on the
     445             :  * passed-in specification for the RPC call's arguments.
     446             :  */
     447       47973 : static inline JSONRPCRequest transformNamedArguments(const JSONRPCRequest& in, const std::vector<std::string>& argNames)
     448             : {
     449       47973 :     JSONRPCRequest out = in;
     450       47973 :     out.params = UniValue(UniValue::VARR);
     451             :     // Build a map of parameters, and remove ones that have been processed, so that we can throw a focused error if
     452             :     // there is an unknown one.
     453       47973 :     const std::vector<std::string>& keys = in.params.getKeys();
     454       47973 :     const std::vector<UniValue>& values = in.params.getValues();
     455       47974 :     std::unordered_map<std::string, const UniValue*> argsIn;
     456       48348 :     for (size_t i=0; i<keys.size(); ++i) {
     457         375 :         argsIn[keys[i]] = &values[i];
     458             :     }
     459             :     // Process expected parameters.
     460       47973 :     int hole = 0;
     461       63658 :     for (const std::string &argNamePattern: argNames) {
     462       31370 :         std::vector<std::string> vargNames;
     463       15685 :         boost::algorithm::split(vargNames, argNamePattern, boost::algorithm::is_any_of("|"));
     464       15685 :         auto fr = argsIn.end();
     465       30998 :         for (const std::string & argName : vargNames) {
     466       15687 :             fr = argsIn.find(argName);
     467       15687 :             if (fr != argsIn.end()) {
     468             :                 break;
     469             :             }
     470             :         }
     471       15685 :         if (fr != argsIn.end()) {
     472         400 :             for (int i = 0; i < hole; ++i) {
     473             :                 // Fill hole between specified parameters with JSON nulls,
     474             :                 // but not at the end (for backwards compatibility with calls
     475             :                 // that act based on number of specified parameters).
     476          26 :                 out.params.push_back(UniValue());
     477             :             }
     478         374 :             hole = 0;
     479         374 :             out.params.push_back(*fr->second);
     480         374 :             argsIn.erase(fr);
     481             :         } else {
     482       15311 :             hole += 1;
     483             :         }
     484             :     }
     485             :     // If there are still arguments in the argsIn map, this is an error.
     486       47973 :     if (!argsIn.empty()) {
     487           2 :         throw JSONRPCError(RPC_INVALID_PARAMETER, "Unknown named parameter " + argsIn.begin()->first);
     488             :     }
     489             :     // Return request with named arguments transformed to positional arguments
     490       47972 :     return out;
     491             : }
     492             : 
     493      298152 : UniValue CRPCTable::execute(const JSONRPCRequest &request) const
     494             : {
     495             :     // Return immediately if in warmup
     496      596016 :     std::string strWarmupStatus;
     497      298152 :     if (RPCIsInWarmup(&strWarmupStatus)) {
     498         198 :         throw JSONRPCError(RPC_IN_WARMUP, "RPC in warm-up: " + strWarmupStatus);
     499             :     }
     500             : 
     501             :     // Find method
     502      298053 :     const CRPCCommand* pcmd = tableRPC[request.strMethod];
     503      298053 :     if (!pcmd)
     504           2 :         throw JSONRPCError(RPC_METHOD_NOT_FOUND, strprintf("Method not found: %s", request.strMethod));
     505             : 
     506      298052 :     g_rpcSignals.PreCommand(*pcmd);
     507             : 
     508      298052 :     try {
     509             :         // Execute, convert arguments to array if necessary
     510      298052 :         if (request.params.isObject()) {
     511       48160 :             return pcmd->actor(transformNamedArguments(request, pcmd->argNames));
     512             :         } else {
     513      250079 :             return pcmd->actor(request);
     514             :         }
     515          22 :     } catch (const std::exception& e) {
     516          22 :         throw JSONRPCError(RPC_MISC_ERROR, e.what());
     517             :     }
     518             : }
     519             : 
     520           0 : std::vector<std::string> CRPCTable::listCommands() const
     521             : {
     522           0 :     std::vector<std::string> commandList;
     523           0 :     for (const auto& i : mapCommands) commandList.emplace_back(i.first);
     524           0 :     return commandList;
     525             : }
     526             : 
     527          35 : std::string HelpExampleCli(std::string methodname, std::string args)
     528             : {
     529          70 :     return "> pivx-cli " + methodname + " " + args + "\n";
     530             : }
     531             : 
     532          21 : std::string HelpExampleRpc(std::string methodname, std::string args)
     533             : {
     534          21 :     return "> curl --user myusername --data-binary '{\"jsonrpc\": \"1.0\", \"id\":\"curltest\", "
     535          21 :            "\"method\": \"" +
     536          42 :            methodname + "\", \"params\": [" + args + "] }' -H 'content-type: text/plain;' http://127.0.0.1:51473/\n";
     537             : }
     538             : 
     539           0 : void RPCSetTimerInterfaceIfUnset(RPCTimerInterface *iface)
     540             : {
     541           0 :     if (!timerInterface)
     542           0 :         timerInterface = iface;
     543           0 : }
     544             : 
     545         375 : void RPCSetTimerInterface(RPCTimerInterface *iface)
     546             : {
     547         375 :     timerInterface = iface;
     548         375 : }
     549             : 
     550         375 : void RPCUnsetTimerInterface(RPCTimerInterface *iface)
     551             : {
     552         375 :     if (timerInterface == iface)
     553         375 :         timerInterface = nullptr;
     554         375 : }
     555             : 
     556          14 : void RPCRunLater(const std::string& name, std::function<void(void)> func, int64_t nSeconds)
     557             : {
     558          14 :     if (!timerInterface)
     559           0 :         throw JSONRPCError(RPC_INTERNAL_ERROR, "No timer handler registered for RPC");
     560          14 :     deadlineTimers.erase(name);
     561          14 :     LogPrint(BCLog::RPC, "queue run of timer %s in %i seconds (using %s)\n", name, nSeconds, timerInterface->Name());
     562          14 :     deadlineTimers.emplace(name, std::unique_ptr<RPCTimerBase>(timerInterface->NewTimer(func, nSeconds*1000)));
     563          14 : }
     564             : 
     565             : CRPCTable tableRPC;

Generated by: LCOV version 1.14