LCOV - code coverage report
Current view: top level - src/rpc - misc.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 283 382 74.1 %
Date: 2025-02-23 09:33:43 Functions: 18 22 81.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 "clientversion.h"
       9             : #include "httpserver.h"
      10             : #include "key_io.h"
      11             : #include "sapling/key_io_sapling.h"
      12             : #include "masternode-sync.h"
      13             : #include "messagesigner.h"
      14             : #include "net.h"
      15             : #include "netbase.h"
      16             : #include "tiertwo/net_masternodes.h"
      17             : #include "rpc/server.h"
      18             : #include "spork.h"
      19             : #include "timedata.h"
      20             : #include "tiertwo/tiertwo_sync_state.h"
      21             : #include "util/system.h"
      22             : #ifdef ENABLE_WALLET
      23             : #include "wallet/rpcwallet.h"
      24             : #include "wallet/wallet.h"
      25             : #endif
      26             : #include "warnings.h"
      27             : 
      28             : #include <stdint.h>
      29             : 
      30             : #include <univalue.h>
      31             : 
      32             : extern std::vector<CSporkDef> sporkDefs;
      33             : 
      34             : /** getinfo depends on getsupplyinfo defined in rpc/blockchain.cpp */
      35             : UniValue getsupplyinfo(const JSONRPCRequest& request);
      36             : 
      37             : /**
      38             :  * @note Do not add or change anything in the information returned by this
      39             :  * method. `getinfo` exists for backwards-compatibility only. It combines
      40             :  * information from wildly different sources in the program, which is a mess,
      41             :  * and is thus planned to be deprecated eventually.
      42             :  *
      43             :  * Based on the source of the information, new information should be added to:
      44             :  * - `getblockchaininfo`,
      45             :  * - `getnetworkinfo` or
      46             :  * - `getwalletinfo`
      47             :  *
      48             :  * Or alternatively, create a specific query method for the information.
      49             :  **/
      50           1 : UniValue getinfo(const JSONRPCRequest& request)
      51             : {
      52           1 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
      53             : 
      54           1 :     if (request.fHelp || request.params.size() != 0)
      55           0 :         throw std::runtime_error(
      56             :             "getinfo\n"
      57             :             "\nReturns an object containing various state info.\n"
      58             : 
      59             :             "\nResult:\n"
      60             :             "{\n"
      61             :             "  \"version\": xxxxx,             (numeric) the server version\n"
      62             :             "  \"protocolversion\": xxxxx,     (numeric) the protocol version\n"
      63             :             "  \"services\": \"xxxx\",         (string) The network services provided by this client\n"
      64             :             "  \"walletversion\": xxxxx,       (numeric) the wallet version\n"
      65             :             "  \"balance\": xxxxxxx,           (numeric) the total pivx balance of the wallet\n"
      66             :             "  \"staking status\": true|false, (boolean) if the wallet is staking or not\n"
      67             :             "  \"blocks\": xxxxxx,             (numeric) the current number of blocks processed in the server\n"
      68             :             "  \"timeoffset\": xxxxx,          (numeric) the time offset\n"
      69             :             "  \"connections\": xxxxx,         (numeric) the number of connections\n"
      70             :             "  \"proxy\": \"host:port\",       (string, optional) the proxy used by the server\n"
      71             :             "  \"difficulty\": xxxxxx,         (numeric) the current difficulty\n"
      72             :             "  \"testnet\": true|false,        (boolean) if the server is using testnet or not\n"
      73             :             "  \"moneysupply\": n              (numeric) The sum of transparentsupply and shieldedsupply\n"
      74             :             "  \"transparentsupply\" : n       (numeric) The sum of the value of all unspent outputs when the chainstate was\n"
      75             :             "                                            last flushed to disk (use getsupplyinfo to know the update-height, or\n"
      76             :             "                                            to trigger the money supply update/recalculation)"
      77             :             "  \"shieldsupply\": n             (numeric) Chain tip shield pool value\n"
      78             :             "  \"keypoololdest\": xxxxxx,      (numeric) the timestamp (seconds since GMT epoch) of the oldest pre-generated key in the key pool\n"
      79             :             "  \"keypoolsize\": xxxx,          (numeric) how many new keys are pre-generated\n"
      80             :             "  \"unlocked_until\": ttt,        (numeric) the timestamp in seconds since epoch (midnight Jan 1 1970 GMT) that the wallet is unlocked for transfers, or 0 if the wallet is locked\n"
      81           0 :             "  \"paytxfee\": x.xxxx,           (numeric) the transaction fee set in " + CURRENCY_UNIT + "/kB\n"
      82           0 :             "  \"relayfee\": x.xxxx,           (numeric) minimum relay fee for transactions in " + CURRENCY_UNIT + "/kB\n"
      83             :             "  \"errors\": \"...\"             (string) any error messages\n"
      84             :             "}\n"
      85             : 
      86           0 :             "\nExamples:\n" +
      87           0 :             HelpExampleCli("getinfo", "") + HelpExampleRpc("getinfo", ""));
      88             : 
      89             : #ifdef ENABLE_WALLET
      90           2 :     LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : nullptr);
      91             : #else
      92             :     LOCK(cs_main);
      93             : #endif
      94             : 
      95           2 :     std::string services;
      96           9 :     for (int i = 0; i < 8; i++) {
      97           8 :         uint64_t check = 1 << i;
      98           8 :         if (g_connman->GetLocalServices() & check) {
      99           2 :             switch (check) {
     100           1 :                 case NODE_NETWORK:
     101           1 :                     services+= "NETWORK/";
     102             :                     break;
     103           1 :                 case NODE_BLOOM:
     104           1 :                 case NODE_BLOOM_WITHOUT_MN:
     105           1 :                     services+= "BLOOM/";
     106             :                     break;
     107           0 :                 default:
     108           8 :                     services+= "UNKNOWN/";
     109             :             }
     110             :         }
     111             :     }
     112             : 
     113           2 :     proxyType proxy;
     114           1 :     GetProxy(NET_IPV4, proxy);
     115             : 
     116           1 :     UniValue obj(UniValue::VOBJ);
     117           1 :     obj.pushKV("version", CLIENT_VERSION);
     118           1 :     obj.pushKV("protocolversion", PROTOCOL_VERSION);
     119           1 :     obj.pushKV("services", services);
     120             : #ifdef ENABLE_WALLET
     121           1 :     if (pwallet) {
     122           1 :         obj.pushKV("walletversion", pwallet->GetVersion());
     123           2 :         obj.pushKV("balance", ValueFromAmount(pwallet->GetAvailableBalance()));
     124           3 :         obj.pushKV("staking status", (pwallet->pStakerStatus->IsActive() ? "Staking Active" : "Staking Not Active"));
     125             :     }
     126             : #endif
     127           1 :     obj.pushKV("blocks", (int)chainActive.Height());
     128           1 :     obj.pushKV("timeoffset", GetTimeOffset());
     129           1 :     if(g_connman) {
     130           2 :         obj.pushKV("connections", (int)g_connman->GetNodeCount(CConnman::CONNECTIONS_ALL));
     131             :     }
     132           3 :     obj.pushKV("proxy", (proxy.IsValid() ? proxy.proxy.ToStringIPPort() : std::string()));
     133           1 :     obj.pushKV("difficulty", (double)GetDifficulty());
     134           1 :     obj.pushKV("testnet", Params().IsTestnet());
     135             : 
     136             :     // Add (cached) money supply via getsupplyinfo RPC
     137           2 :     UniValue supply_info = getsupplyinfo(JSONRPCRequest());
     138           2 :     obj.pushKV("moneysupply", supply_info["totalsupply"]);
     139           2 :     obj.pushKV("transparentsupply", supply_info["transparentsupply"]);
     140           2 :     obj.pushKV("shieldsupply", supply_info["shieldsupply"]);
     141             : 
     142             : #ifdef ENABLE_WALLET
     143           1 :     if (pwallet) {
     144           1 :         obj.pushKV("keypoololdest", pwallet->GetOldestKeyPoolTime());
     145           1 :         size_t kpExternalSize = pwallet->KeypoolCountExternalKeys();
     146           2 :         obj.pushKV("keypoolsize", (int64_t)kpExternalSize);
     147             :     }
     148           1 :     if (pwallet && pwallet->IsCrypted())
     149           0 :         obj.pushKV("unlocked_until", pwallet->nRelockTime);
     150           2 :     obj.pushKV("paytxfee", ValueFromAmount(payTxFee.GetFeePerK()));
     151             : #endif
     152           2 :     obj.pushKV("relayfee", ValueFromAmount(::minRelayTxFee.GetFeePerK()));
     153           3 :     obj.pushKV("errors", GetWarnings("statusbar"));
     154           2 :     return obj;
     155             : }
     156             : 
     157         245 : UniValue mnsync(const JSONRPCRequest& request)
     158             : {
     159         490 :     std::string strMode;
     160         245 :     if (request.params.size() == 1)
     161         245 :         strMode = request.params[0].get_str();
     162             : 
     163         490 :     if (request.fHelp || request.params.size() != 1 || (strMode != "status" && strMode != "reset")) {
     164           0 :         throw std::runtime_error(
     165             :             "mnsync \"status|reset\"\n"
     166             :             "\nReturns the sync status or resets sync.\n"
     167             : 
     168             :             "\nArguments:\n"
     169             :             "1. \"mode\"    (string, required) either 'status' or 'reset'\n"
     170             : 
     171             :             "\nResult ('status' mode):\n"
     172             :             "{\n"
     173             :             "  \"IsBlockchainSynced\": true|false,    (boolean) 'true' if blockchain is synced\n"
     174             :             "  \"lastMasternodeList\": xxxx,        (numeric) Timestamp of last MN list message\n"
     175             :             "  \"lastMasternodeWinner\": xxxx,      (numeric) Timestamp of last MN winner message\n"
     176             :             "  \"lastBudgetItem\": xxxx,            (numeric) Timestamp of last MN budget message\n"
     177             :             "  \"lastFailure\": xxxx,           (numeric) Timestamp of last failed sync\n"
     178             :             "  \"nCountFailures\": n,           (numeric) Number of failed syncs (total)\n"
     179             :             "  \"sumMasternodeList\": n,        (numeric) Number of MN list messages (total)\n"
     180             :             "  \"sumMasternodeWinner\": n,      (numeric) Number of MN winner messages (total)\n"
     181             :             "  \"sumBudgetItemProp\": n,        (numeric) Number of MN budget messages (total)\n"
     182             :             "  \"sumBudgetItemFin\": n,         (numeric) Number of MN budget finalization messages (total)\n"
     183             :             "  \"countMasternodeList\": n,      (numeric) Number of MN list messages (local)\n"
     184             :             "  \"countMasternodeWinner\": n,    (numeric) Number of MN winner messages (local)\n"
     185             :             "  \"countBudgetItemProp\": n,      (numeric) Number of MN budget messages (local)\n"
     186             :             "  \"countBudgetItemFin\": n,       (numeric) Number of MN budget finalization messages (local)\n"
     187             :             "  \"RequestedMasternodeAssets\": n, (numeric) Status code of last sync phase\n"
     188             :             "  \"RequestedMasternodeAttempt\": n, (numeric) Status code of last sync attempt\n"
     189             :             "}\n"
     190             : 
     191             :             "\nResult ('reset' mode):\n"
     192             :             "\"status\"     (string) 'success'\n"
     193             : 
     194           0 :             "\nExamples:\n" +
     195           0 :             HelpExampleCli("mnsync", "\"status\"") + HelpExampleRpc("mnsync", "\"status\""));
     196             :     }
     197             : 
     198         245 :     if (strMode == "status") {
     199         490 :         UniValue obj(UniValue::VOBJ);
     200             : 
     201         245 :         obj.pushKV("IsBlockchainSynced", g_tiertwo_sync_state.IsBlockchainSynced());
     202         245 :         obj.pushKV("lastMasternodeList", g_tiertwo_sync_state.GetlastMasternodeList());
     203         245 :         obj.pushKV("lastMasternodeWinner", g_tiertwo_sync_state.GetlastMasternodeWinner());
     204         245 :         obj.pushKV("lastBudgetItem", g_tiertwo_sync_state.GetlastBudgetItem());
     205         245 :         obj.pushKV("lastFailure", masternodeSync.lastFailure);
     206         245 :         obj.pushKV("nCountFailures", masternodeSync.nCountFailures);
     207         245 :         obj.pushKV("sumMasternodeList", masternodeSync.sumMasternodeList);
     208         245 :         obj.pushKV("sumMasternodeWinner", masternodeSync.sumMasternodeWinner);
     209         245 :         obj.pushKV("sumBudgetItemProp", masternodeSync.sumBudgetItemProp);
     210         245 :         obj.pushKV("sumBudgetItemFin", masternodeSync.sumBudgetItemFin);
     211         245 :         obj.pushKV("countMasternodeList", masternodeSync.countMasternodeList);
     212         245 :         obj.pushKV("countMasternodeWinner", masternodeSync.countMasternodeWinner);
     213         245 :         obj.pushKV("countBudgetItemProp", masternodeSync.countBudgetItemProp);
     214         245 :         obj.pushKV("countBudgetItemFin", masternodeSync.countBudgetItemFin);
     215         245 :         obj.pushKV("RequestedMasternodeAssets", g_tiertwo_sync_state.GetSyncPhase());
     216         245 :         obj.pushKV("RequestedMasternodeAttempt", masternodeSync.RequestedMasternodeAttempt);
     217             : 
     218         245 :         return obj;
     219             :     }
     220             : 
     221           0 :     if (strMode == "reset") {
     222           0 :         masternodeSync.Reset();
     223           0 :         return "success";
     224             :     }
     225           0 :     return "failure";
     226             : }
     227             : 
     228             : #ifdef ENABLE_WALLET
     229             : class DescribeAddressVisitor : public boost::static_visitor<UniValue>
     230             : {
     231             : public:
     232             :     CWallet * const pwallet;
     233             : 
     234          96 :     explicit DescribeAddressVisitor(CWallet *_pwallet) : pwallet(_pwallet) {}
     235             : 
     236           0 :     UniValue operator()(const CNoDestination &dest) const { return UniValue(UniValue::VOBJ); }
     237             : 
     238          91 :     UniValue operator()(const CKeyID &keyID) const {
     239          91 :         UniValue obj(UniValue::VOBJ);
     240          91 :         CPubKey vchPubKey;
     241          91 :         obj.pushKV("isscript", false);
     242          91 :         if (pwallet && pwallet->GetPubKey(keyID, vchPubKey)) {
     243         144 :             obj.pushKV("pubkey", HexStr(vchPubKey));
     244         144 :             obj.pushKV("iscompressed", vchPubKey.IsCompressed());
     245             :         }
     246          91 :         return obj;
     247             :     }
     248             : 
     249           1 :     UniValue operator()(const CExchangeKeyID &keyID) const {
     250           1 :         UniValue obj(UniValue::VOBJ);
     251           1 :         CPubKey vchPubKey;
     252           1 :         obj.pushKV("isscript", false);
     253           1 :         if (pwallet && pwallet->GetPubKey(keyID, vchPubKey)) {
     254           0 :             obj.pushKV("exchangepubkey", HexStr(vchPubKey));
     255           0 :             obj.pushKV("iscompressed", vchPubKey.IsCompressed());
     256             :         }
     257           1 :         return obj;
     258             :     }
     259             : 
     260           4 :     UniValue operator()(const CScriptID &scriptID) const {
     261           4 :         UniValue obj(UniValue::VOBJ);
     262           4 :         obj.pushKV("isscript", true);
     263           4 :         CScript subscript;
     264           4 :         if (pwallet && pwallet->GetCScript(scriptID, subscript)) {
     265           6 :             std::vector<CTxDestination> addresses;
     266           3 :             txnouttype whichType;
     267           3 :             int nRequired;
     268           3 :             ExtractDestinations(subscript, whichType, addresses, nRequired);
     269           3 :             obj.pushKV("script", GetTxnOutputType(whichType));
     270           9 :             obj.pushKV("hex", HexStr(subscript));
     271           6 :             UniValue a(UniValue::VARR);
     272          11 :             for (const CTxDestination& addr : addresses)
     273          16 :                 a.push_back(EncodeDestination(addr));
     274           3 :             obj.pushKV("addresses", a);
     275           3 :             if (whichType == TX_MULTISIG)
     276           6 :                 obj.pushKV("sigsrequired", nRequired);
     277             :         }
     278           7 :         return obj;
     279             :     }
     280             : };
     281             : #endif
     282             : 
     283             : /*
     284             :     Used for updating/reading spork settings on the network
     285             : */
     286         169 : UniValue spork(const JSONRPCRequest& request)
     287             : {
     288         169 :     if (request.params.size() == 1 && request.params[0].get_str() == "show") {
     289         184 :         UniValue ret(UniValue::VOBJ);
     290        1012 :         for (const auto& sporkDef : sporkDefs) {
     291         920 :             ret.pushKV(sporkDef.name, sporkManager.GetSporkValue(sporkDef.sporkId));
     292             :         }
     293          92 :         return ret;
     294          77 :     } else if (request.params.size() == 1 && request.params[0].get_str() == "active") {
     295          72 :         UniValue ret(UniValue::VOBJ);
     296         396 :         for (const auto& sporkDef : sporkDefs) {
     297         360 :             ret.pushKV(sporkDef.name, sporkManager.IsSporkActive(sporkDef.sporkId));
     298             :         }
     299          36 :         return ret;
     300          41 :     } else if (request.params.size() == 2) {
     301             :         // advanced mode, update spork values
     302          41 :         SporkId nSporkID = sporkManager.GetSporkIDByName(request.params[0].get_str());
     303          41 :         if (nSporkID == SPORK_INVALID) {
     304           0 :             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid spork name");
     305             :         }
     306             : 
     307             :         // SPORK VALUE
     308          41 :         int64_t nValue = request.params[1].get_int64();
     309             : 
     310             :         //broadcast new spork
     311          41 :         if (sporkManager.UpdateSpork(nSporkID, nValue)) {
     312          41 :             return "success";
     313             :         } else {
     314           0 :             return "failure";
     315             :         }
     316             :     }
     317             : 
     318           0 :     throw std::runtime_error(
     319             :         "spork \"name\" ( value )\n"
     320             :         "\nReturn spork values or their active state.\n"
     321             : 
     322             :         "\nArguments:\n"
     323             :         "1. \"name\"        (string, required)  \"show\" to show values, \"active\" to show active state.\n"
     324             :         "                       When set up as a spork signer, the name of the spork can be used to update it's value.\n"
     325             :         "2. value           (numeric, required when updating a spork) The new value for the spork.\n"
     326             : 
     327             :         "\nResult (show):\n"
     328             :         "{\n"
     329             :         "  \"spork_name\": nnn      (key/value) Key is the spork name, value is it's current value.\n"
     330             :         "  ,...\n"
     331             :         "}\n"
     332             : 
     333             :         "\nResult (active):\n"
     334             :         "{\n"
     335             :         "  \"spork_name\": true|false      (key/value) Key is the spork name, value is a boolean for it's active state.\n"
     336             :         "  ,...\n"
     337             :         "}\n"
     338             : 
     339             :         "\nResult (name):\n"
     340             :         " \"success|failure\"       (string) Whether or not the update succeeded.\n"
     341             : 
     342           0 :         "\nExamples:\n" +
     343           0 :         HelpExampleCli("spork", "show") + HelpExampleRpc("spork", "show"));
     344             : }
     345             : 
     346             : // Every possibly address
     347             : typedef boost::variant<libzcash::InvalidEncoding, libzcash::SaplingPaymentAddress, CTxDestination> PPaymentAddress;
     348             : 
     349             : class DescribePaymentAddressVisitor : public boost::static_visitor<UniValue>
     350             : {
     351             : public:
     352          98 :     explicit DescribePaymentAddressVisitor(CWallet *_pwallet, bool _isStaking) : pwallet(_pwallet), isStaking(_isStaking) {}
     353           0 :     UniValue operator()(const libzcash::InvalidEncoding &zaddr) const { return UniValue(UniValue::VOBJ); }
     354             : 
     355           2 :     UniValue operator()(const libzcash::SaplingPaymentAddress &zaddr) const {
     356           2 :         UniValue obj(UniValue::VOBJ);
     357           4 :         obj.pushKV("diversifier", HexStr(zaddr.d));
     358           4 :         obj.pushKV("diversifiedtransmissionkey", zaddr.pk_d.GetHex());
     359             : #ifdef ENABLE_WALLET
     360           2 :         if (pwallet) {
     361           4 :             obj.pushKV("ismine", pwallet->HaveSpendingKeyForPaymentAddress(zaddr));
     362             :         }
     363             : #endif
     364           2 :         return obj;
     365             :     }
     366             : 
     367          96 :     UniValue operator()(const CTxDestination &dest) const {
     368          96 :         UniValue ret(UniValue::VOBJ);
     369          96 :         CScript scriptPubKey = GetScriptForDestination(dest);
     370         288 :         ret.pushKV("scriptPubKey", HexStr(scriptPubKey));
     371             : 
     372             : #ifdef ENABLE_WALLET
     373          96 :         isminetype mine = pwallet ? IsMine(*pwallet, dest) : ISMINE_NO;
     374          96 :         ret.pushKV("ismine", bool(mine & (ISMINE_SPENDABLE_ALL | ISMINE_COLD)));
     375          96 :         ret.pushKV("isstaking", isStaking);
     376          96 :         ret.pushKV("iswatchonly", bool(mine & ISMINE_WATCH_ONLY));
     377         288 :         UniValue detail = boost::apply_visitor(DescribeAddressVisitor(pwallet), dest);
     378          96 :         ret.pushKVs(detail);
     379         191 :         if (pwallet && pwallet->HasAddressBook(dest))
     380         186 :             ret.pushKV("label", pwallet->GetNameForAddressBookEntry(dest));
     381             : #endif
     382         192 :         return ret;
     383             :     }
     384             : 
     385             : private:
     386             :     CWallet * const pwallet;
     387             :     bool isStaking{false};
     388             : };
     389             : 
     390         102 : UniValue validateaddress(const JSONRPCRequest& request)
     391             : {
     392         102 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
     393             : 
     394         102 :     if (request.fHelp || request.params.size() != 1)
     395           2 :         throw std::runtime_error(
     396             :             "validateaddress \"pivxaddress\"\n"
     397             :             "\nReturn information about the given pivx address.\n"
     398             : 
     399             :             "\nArguments:\n"
     400             :             "1. \"pivxaddress\"     (string, required) The pivx address to validate\n"
     401             : 
     402             :             "\nResult:\n"
     403             :             "{\n"
     404             :             "  \"isvalid\" : true|false,         (boolean) If the address is valid or not. If not, this is the only property returned.\n"
     405             :             "  \"address\" : \"pivxaddress\",    (string) The pivx address validated\n"
     406             :             "  \"scriptPubKey\" : \"hex\",       (string) The hex encoded scriptPubKey generated by the address -only if is standard address-\n"
     407             :             "  \"ismine\" : true|false,          (boolean) If the address is yours or not\n"
     408             :             "  \"isstaking\" : true|false,       (boolean) If the address is a staking address for PIVX cold staking -only if is standard address-\n"
     409             :             "  \"iswatchonly\" : true|false,     (boolean) If the address is watchonly -only if standard address-\n"
     410             :             "  \"isscript\" : true|false,        (boolean) If the key is a script -only if standard address-\n"
     411             :             "  \"hex\" : \"hex\",                (string, optional) The redeemscript for the P2SH address -only if standard address-\n"
     412             :             "  \"pubkey\" : \"publickeyhex\",    (string) The hex value of the raw public key -only if standard address-\n"
     413             :             "  \"iscompressed\" : true|false,    (boolean) If the address is compressed -only if standard address-\n"
     414             :             "  \"label\" : \"label\"             (string) The label associated with the address, \"\" is the default label\n"
     415             :             // Sapling
     416             :             "  \"diversifier\" : \"hex\",       (string) [sapling] The hex value of the diversifier, d -only if is sapling address-\n"
     417             :             "  \"diversifiedtransmissionkey\" : \"hex\", (string) [sapling] The hex value of pk_d -only if is sapling address-\n"
     418             :             "}\n"
     419             : 
     420           4 :             "\nExamples:\n" +
     421          10 :             HelpExampleCli("validateaddress", "\"DMJRSsuU9zfyrvxVaAEFQqK4MxZg6vgeS6\"") +
     422          10 :             HelpExampleCli("validateaddress", "\"ps1ra969yfhvhp73rw5ak2xvtcm9fkuqsnmad7qln79mphhdrst3lwu9vvv03yuyqlh42p42st47qd\"") +
     423           8 :             HelpExampleRpc("validateaddress", "\"DMJRSsuU9zfyrvxVaAEFQqK4MxZg6vgeS6\""));
     424             : 
     425             : #ifdef ENABLE_WALLET
     426         200 :     LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : nullptr);
     427             : #else
     428             :     LOCK(cs_main);
     429             : #endif
     430             : 
     431         200 :     std::string strAddress = request.params[0].get_str();
     432             : 
     433             :     // First check if it's a regular address
     434         100 :     bool isStaking = false;
     435         100 :     bool isExchange = false;
     436         200 :     CTxDestination dest = DecodeDestination(strAddress, isStaking, isExchange);
     437         100 :     bool isValid = IsValidDestination(dest);
     438             : 
     439         200 :     PPaymentAddress finalAddress;
     440         100 :     if (!isValid) {
     441           4 :         isValid = KeyIO::IsValidPaymentAddressString(strAddress);
     442           6 :         if (isValid) finalAddress = KeyIO::DecodePaymentAddress(strAddress);
     443             :     } else {
     444          96 :         finalAddress = dest;
     445             :     }
     446             : 
     447         100 :     UniValue ret(UniValue::VOBJ);
     448         100 :     ret.pushKV("isvalid", isValid);
     449         100 :     if (isValid) {
     450          98 :         ret.pushKV("address", strAddress);
     451         196 :         UniValue detail = boost::apply_visitor(DescribePaymentAddressVisitor(pwallet, isStaking), finalAddress);
     452          98 :         ret.pushKVs(detail);
     453             :     }
     454             : 
     455         200 :     return ret;
     456             : }
     457             : 
     458             : /**
     459             :  * Used by addmultisigaddress / createmultisig:
     460             :  */
     461          20 : CScript _createmultisig_redeemScript(CWallet * const pwallet, const UniValue& params)
     462             : {
     463          20 :     int nRequired = params[0].get_int();
     464          20 :     const UniValue& keys = params[1].get_array();
     465             : 
     466             :     // Gather public keys
     467          20 :     if (nRequired < 1)
     468           0 :         throw std::runtime_error("a multisignature address must require at least one key to redeem");
     469          20 :     if ((int)keys.size() < nRequired)
     470           0 :         throw std::runtime_error(
     471           0 :             strprintf("not enough keys supplied "
     472             :                       "(got %u keys, but need at least %d to redeem)",
     473           0 :                 keys.size(), nRequired));
     474          20 :     if (keys.size() > 16)
     475           0 :         throw std::runtime_error("Number of addresses involved in the multisignature address creation > 16\nReduce the number");
     476          20 :     std::vector<CPubKey> pubkeys;
     477          20 :     pubkeys.resize(keys.size());
     478         104 :     for (unsigned int i = 0; i < keys.size(); i++) {
     479          86 :         const std::string& ks = keys[i].get_str();
     480             : #ifdef ENABLE_WALLET
     481             :         // Case 1: PIVX address and we have full public key:
     482         172 :         CTxDestination dest = DecodeDestination(ks);
     483          86 :         if (pwallet && IsValidDestination(dest)) {
     484          62 :             const CKeyID* keyID = boost::get<CKeyID>(&dest);
     485          62 :             if (!keyID) {
     486           0 :                 throw std::runtime_error(
     487           0 :                         strprintf("%s does not refer to a key", ks));
     488             :             }
     489          62 :             CPubKey vchPubKey;
     490          62 :             if (!pwallet->GetPubKey(*keyID, vchPubKey))
     491           1 :                 throw std::runtime_error(
     492           2 :                     strprintf("no full public key for address %s", ks));
     493          61 :             if (!vchPubKey.IsFullyValid())
     494           0 :                 throw std::runtime_error(" Invalid public key: " + ks);
     495          61 :             pubkeys[i] = vchPubKey;
     496             :         }
     497             : 
     498             :         // Case 2: hex public key
     499             :         else
     500             : #endif
     501          24 :             if (IsHex(ks)) {
     502          24 :             CPubKey vchPubKey(ParseHex(ks));
     503          24 :             if (!vchPubKey.IsFullyValid())
     504           2 :                 throw std::runtime_error(" Invalid public key: " + ks);
     505          23 :             pubkeys[i] = vchPubKey;
     506             :         } else {
     507           0 :             throw std::runtime_error(" Invalid public key: " + ks);
     508             :         }
     509             :     }
     510          18 :     CScript result = GetScriptForMultisig(nRequired, pubkeys);
     511             : 
     512          36 :     if (result.size() > MAX_SCRIPT_ELEMENT_SIZE)
     513           0 :         throw std::runtime_error(
     514           0 :             strprintf("redeemScript exceeds size limit: %d > %d", result.size(), MAX_SCRIPT_ELEMENT_SIZE));
     515             : 
     516          36 :     return result;
     517             : }
     518             : 
     519           8 : UniValue createmultisig(const JSONRPCRequest& request)
     520             : {
     521           8 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
     522             : 
     523           8 :     if (request.fHelp || request.params.size() < 2 || request.params.size() > 2)
     524           0 :         throw std::runtime_error(
     525             :             "createmultisig nrequired [\"key\",...]\n"
     526             :             "\nCreates a multi-signature address with n signature of m keys required.\n"
     527             :             "It returns a json object with the address and redeemScript.\n"
     528             : 
     529             :             "\nArguments:\n"
     530             :             "1. nrequired      (numeric, required) The number of required signatures out of the n keys or addresses.\n"
     531             :             "2. \"keys\"       (string, required) A json array of keys which are pivx addresses or hex-encoded public keys\n"
     532             :             "     [\n"
     533             :             "       \"key\"    (string) pivx address or hex-encoded public key\n"
     534             :             "       ,...\n"
     535             :             "     ]\n"
     536             : 
     537             :             "\nResult:\n"
     538             :             "{\n"
     539             :             "  \"address\":\"multisigaddress\",  (string) The value of the new multisig address.\n"
     540             :             "  \"redeemScript\":\"script\"       (string) The string value of the hex-encoded redemption script.\n"
     541             :             "}\n"
     542             : 
     543             :             "\nExamples:\n"
     544           0 :             "\nCreate a multisig address from 2 addresses\n" +
     545           0 :             HelpExampleCli("createmultisig", "2 \"[\\\"DMJRSsuU9zfyrvxVaAEFQqK4MxZg6vgeS6\\\",\\\"DAD3Y6ivr8nPQLT1NEPX84DxGCw9jz9Jvg\\\"]\"") +
     546           0 :             "\nAs a json rpc call\n" +
     547           0 :             HelpExampleRpc("createmultisig", "2, \"[\\\"DMJRSsuU9zfyrvxVaAEFQqK4MxZg6vgeS6\\\",\\\"DAD3Y6ivr8nPQLT1NEPX84DxGCw9jz9Jvg\\\"]\""));
     548             : 
     549             :     // Construct using pay-to-script-hash:
     550           8 :     CScript inner = _createmultisig_redeemScript(pwallet, request.params);
     551           6 :     CScriptID innerID(inner);
     552             : 
     553           6 :     UniValue result(UniValue::VOBJ);
     554          18 :     result.pushKV("address", EncodeDestination(innerID));
     555          18 :     result.pushKV("redeemScript", HexStr(inner));
     556             : 
     557          12 :     return result;
     558             : }
     559             : 
     560           3 : UniValue verifymessage(const JSONRPCRequest& request)
     561             : {
     562           3 :     if (request.fHelp || request.params.size() != 3)
     563           0 :         throw std::runtime_error(
     564             :             "verifymessage \"pivxaddress\" \"signature\" \"message\"\n"
     565             :             "\nVerify a signed message\n"
     566             : 
     567             :             "\nArguments:\n"
     568             :             "1. \"pivxaddress\"  (string, required) The pivx address to use for the signature.\n"
     569             :             "2. \"signature\"    (string, required) The signature provided by the signer in base 64 encoding (see signmessage).\n"
     570             :             "3. \"message\"      (string, required) The message that was signed.\n"
     571             : 
     572             :             "\nResult:\n"
     573             :             "true|false   (boolean) If the signature is verified or not.\n"
     574             : 
     575             :             "\nExamples:\n"
     576           0 :             "\nUnlock the wallet for 30 seconds\n" +
     577           0 :             HelpExampleCli("walletpassphrase", "\"mypassphrase\" 30") +
     578           0 :             "\nCreate the signature\n" +
     579           0 :             HelpExampleCli("signmessage", "\"DAD3Y6ivr8nPQLT1NEPX84DxGCw9jz9Jvg\" \"my message\"") +
     580           0 :             "\nVerify the signature\n" +
     581           0 :             HelpExampleCli("verifymessage", "\"DAD3Y6ivr8nPQLT1NEPX84DxGCw9jz9Jvg\" \"signature\" \"my message\"") +
     582           0 :             "\nAs json rpc\n" +
     583           0 :             HelpExampleRpc("verifymessage", "\"DAD3Y6ivr8nPQLT1NEPX84DxGCw9jz9Jvg\", \"signature\", \"my message\""));
     584             : 
     585           3 :     LOCK(cs_main);
     586             : 
     587           6 :     std::string strAddress = request.params[0].get_str();
     588           6 :     std::string strSign = request.params[1].get_str();
     589           6 :     std::string strMessage = request.params[2].get_str();
     590             : 
     591           6 :     CTxDestination destination = DecodeDestination(strAddress);
     592           3 :     if (!IsValidDestination(destination))
     593           0 :         throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
     594             : 
     595           3 :     const CKeyID* keyID = boost::get<CKeyID>(&destination);
     596           3 :     if (!keyID) {
     597           0 :         throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
     598             :     }
     599             : 
     600           3 :     bool fInvalid = false;
     601           6 :     std::vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
     602             : 
     603           3 :     if (fInvalid)
     604           0 :         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Malformed base64 encoding");
     605             : 
     606           6 :     std::string strError;
     607           6 :     return CMessageSigner::VerifyMessage(*keyID, vchSig, strMessage, strError);
     608             : }
     609             : 
     610       10439 : UniValue setmocktime(const JSONRPCRequest& request)
     611             : {
     612       10439 :     if (request.fHelp || request.params.size() != 1)
     613           0 :         throw std::runtime_error(
     614             :             "setmocktime timestamp\n"
     615             :             "\nSet the local time to given timestamp (-regtest only)\n"
     616             : 
     617             :             "\nArguments:\n"
     618             :             "1. timestamp  (numeric, required) Unix seconds-since-epoch timestamp\n"
     619           0 :             "   Pass 0 to go back to using the system time.");
     620             : 
     621       10439 :     if (!Params().IsRegTestNet())
     622           0 :         throw std::runtime_error("setmocktime for regression testing (-regtest mode) only");
     623             : 
     624             :     // For now, don't change mocktime if we're in the middle of validation, as
     625             :     // this could have an effect on mempool time-based eviction, as well as
     626             :     // IsCurrentForFeeEstimation() and IsInitialBlockDownload().
     627             :     // TODO: figure out the right way to synchronize around mocktime, and
     628             :     // ensure all callsites of GetTime() are accessing this safely.
     629       10439 :     LOCK(cs_main);
     630             : 
     631       10439 :     RPCTypeCheck(request.params, {UniValue::VNUM});
     632       10439 :     SetMockTime(request.params[0].get_int64());
     633             : 
     634       20878 :     return NullUniValue;
     635             : }
     636             : 
     637           0 : void EnableOrDisableLogCategories(UniValue cats, bool enable) {
     638           0 :     cats = cats.get_array();
     639           0 :     for (unsigned int i = 0; i < cats.size(); ++i) {
     640           0 :         std::string cat = cats[i].get_str();
     641             : 
     642           0 :         bool success;
     643           0 :         if (enable) {
     644           0 :             success = g_logger->EnableCategory(cat);
     645             :         } else {
     646           0 :             success = g_logger->DisableCategory(cat);
     647             :         }
     648             : 
     649           0 :         if (!success)
     650           0 :             throw JSONRPCError(RPC_INVALID_PARAMETER, "unknown logging category " + cat);
     651             :     }
     652           0 : }
     653             : 
     654           0 : UniValue logging(const JSONRPCRequest& request)
     655             : {
     656           0 :     if (request.fHelp || request.params.size() > 2) {
     657           0 :         throw std::runtime_error(
     658             :             "logging [include,...] ( [exclude,...] )\n"
     659             :             "Gets and sets the logging configuration.\n"
     660             :             "When called without an argument, returns the list of categories that are currently being debug logged.\n"
     661             :             "When called with arguments, adds or removes categories from debug logging.\n"
     662           0 :             "The valid logging categories are: " + ListLogCategories() + "\n"
     663             :             "libevent logging is configured on startup and cannot be modified by this RPC during runtime."
     664             : 
     665             :             "Arguments:\n"
     666             :             "1. \"include\" (array of strings) add debug logging for these categories.\n"
     667             :             "2. \"exclude\" (array of strings) remove debug logging for these categories.\n"
     668             : 
     669             :             "\nResult:\n"
     670             :             "{                            (object): a JSON object of the logging categories that are active.\n"
     671             :             "  \"category\": fEnabled,    (key/value) Key is the category name, value is a boolean of it's active state.\n"
     672             :             "  ...,\n"
     673             :             "}\n"
     674             : 
     675             :             "\nExamples:\n"
     676           0 :             + HelpExampleCli("logging", "\"[\\\"all\\\"]\" \"[\\\"http\\\"]\"")
     677           0 :             + HelpExampleRpc("logging", "[\"all\"], \"[libevent]\"")
     678           0 :         );
     679             :     }
     680             : 
     681           0 :     uint32_t original_log_categories = g_logger->GetCategoryMask();
     682           0 :     if (request.params.size() > 0 && request.params[0].isArray()) {
     683           0 :         EnableOrDisableLogCategories(request.params[0], true);
     684             :     }
     685             : 
     686           0 :     if (request.params.size() > 1 && request.params[1].isArray()) {
     687           0 :         EnableOrDisableLogCategories(request.params[1], false);
     688             :     }
     689           0 :     uint32_t updated_log_categories = g_logger->GetCategoryMask();
     690           0 :     uint32_t changed_log_categories = original_log_categories ^ updated_log_categories;
     691             : 
     692             :     // Update libevent logging if BCLog::LIBEVENT has changed.
     693             :     // If the library version doesn't allow it, UpdateHTTPServerLogging() returns false,
     694             :     // in which case we should clear the BCLog::LIBEVENT flag.
     695             :     // Throw an error if the user has explicitly asked to change only the libevent
     696             :     // flag and it failed.
     697           0 :     if (changed_log_categories & BCLog::LIBEVENT) {
     698           0 :         if (!UpdateHTTPServerLogging(g_logger->WillLogCategory(BCLog::LIBEVENT))) {
     699           0 :             g_logger->DisableCategory(BCLog::LIBEVENT);
     700           0 :             if (changed_log_categories == BCLog::LIBEVENT) {
     701           0 :             throw JSONRPCError(RPC_INVALID_PARAMETER, "libevent logging cannot be updated when using libevent before v2.1.1.");
     702             :             }
     703             :         }
     704             :     }
     705             : 
     706           0 :     UniValue result(UniValue::VOBJ);
     707           0 :     std::vector<CLogCategoryActive> vLogCatActive = ListActiveLogCategories();
     708           0 :     for (const auto& logCatActive : vLogCatActive) {
     709           0 :         result.pushKV(logCatActive.category, logCatActive.active);
     710             :     }
     711             : 
     712           0 :     return result;
     713             : }
     714             : 
     715           2 : static UniValue RPCLockedMemoryInfo()
     716             : {
     717           2 :     LockedPool::Stats stats = LockedPoolManager::Instance().stats();
     718           2 :     UniValue obj(UniValue::VOBJ);
     719           2 :     obj.pushKV("used", uint64_t(stats.used));
     720           2 :     obj.pushKV("free", uint64_t(stats.free));
     721           2 :     obj.pushKV("total", uint64_t(stats.total));
     722           2 :     obj.pushKV("locked", uint64_t(stats.locked));
     723           2 :     obj.pushKV("chunks_used", uint64_t(stats.chunks_used));
     724           2 :     obj.pushKV("chunks_free", uint64_t(stats.chunks_free));
     725           2 :     return obj;
     726             : }
     727             : 
     728           2 : UniValue getmemoryinfo(const JSONRPCRequest& request)
     729             : {
     730             :     /* Please, avoid using the word "pool" here in the RPC interface or help,
     731             :      * as users will undoubtedly confuse it with the other "memory pool"
     732             :      */
     733           2 :     if (request.fHelp || request.params.size() != 0)
     734           0 :         throw std::runtime_error(
     735             :             "getmemoryinfo\n"
     736             :             "Returns an object containing information about memory usage.\n"
     737             :             "\nResult:\n"
     738             :             "{\n"
     739             :             "  \"locked\": {               (json object) Information about locked memory manager\n"
     740             :             "    \"used\": xxxxx,          (numeric) Number of bytes used\n"
     741             :             "    \"free\": xxxxx,          (numeric) Number of bytes available in current arenas\n"
     742             :             "    \"total\": xxxxxxx,       (numeric) Total number of bytes managed\n"
     743             :             "    \"locked\": xxxxxx,       (numeric) Amount of bytes that succeeded locking. If this number is smaller than total, locking pages failed at some point and key data could be swapped to disk.\n"
     744             :             "    \"chunks_used\": xxxxx,   (numeric) Number allocated chunks\n"
     745             :             "    \"chunks_free\": xxxxx,   (numeric) Number unused chunks\n"
     746             :             "  }\n"
     747             :             "}\n"
     748             :             "\nExamples:\n"
     749           0 :             + HelpExampleCli("getmemoryinfo", "")
     750           0 :             + HelpExampleRpc("getmemoryinfo", "")
     751           0 :         );
     752           2 :     UniValue obj(UniValue::VOBJ);
     753           4 :     obj.pushKV("locked", RPCLockedMemoryInfo());
     754           2 :     return obj;
     755             : }
     756             : 
     757           5 : UniValue echo(const JSONRPCRequest& request)
     758             : {
     759           5 :     if (request.fHelp)
     760           0 :         throw std::runtime_error(
     761             :             "echo|echojson \"message\" ...\n"
     762             :             "\nSimply echo back the input arguments. This command is for testing.\n"
     763             :             "\nThe difference between echo and echojson is that echojson has argument conversion enabled in the client-side table in"
     764             :             "pivx-cli and the GUI. There is no server-side difference."
     765           0 :         );
     766             : 
     767           5 :     return request.params;
     768             : }
     769             : 
     770             : // mnconnect command operation types
     771             : const char* SINGLE_CONN = "single_conn";
     772             : const char* QUORUM_MEMBERS_CONN = "quorum_members_conn";
     773             : const char* IQR_MEMBERS_CONN = "iqr_members_conn";
     774             : const char* PROBE_CONN = "probe_conn";
     775             : const char* CLEAR_CONN = "clear_conn";
     776             : 
     777             : /* What essentially does is add a pending MN connection
     778             :  * Can be in the following forms:
     779             :  * 1) Direct single DMN connection.
     780             :  * 2) Quorum members connection (set of DMNs to connect).
     781             :  * 3) Quorum relay members connections (set of DMNs to connect and relay intra-quorum messages).
     782             :  * 4) Probe DMN connection.
     783             :  * 5) Clear tier two net connections cache
     784             : **/
     785          13 : UniValue mnconnect(const JSONRPCRequest& request)
     786             : {
     787          13 :     if (request.fHelp || request.params.empty() || request.params.size() > 4) {
     788           0 :         throw std::runtime_error(
     789             :                 "mnconnect \"op_type\" (\"[pro_tx_hash, pro_tx_hash,..]\" llmq_type \"quorum_hash\")\n"
     790             :                 "\nAdd manual quorum members connections for internal testing purposes of the tier two p2p network layer\n"
     791           0 :         );
     792             :     }
     793             : 
     794          13 :     const auto& chainparams = Params();
     795          13 :     if (!chainparams.IsRegTestNet())
     796           0 :         throw std::runtime_error("mnconnect for regression testing (-regtest mode) only");
     797             : 
     798             :     // Connection type
     799          13 :     RPCTypeCheck(request.params, {UniValue::VSTR});
     800          13 :     const std::string& op_type = request.params[0].get_str();
     801             : 
     802             :     // DMNs pro_tx list
     803          26 :     std::set<uint256> set_dmn_protxhash;
     804          13 :     if (request.params.size() > 1) {
     805          11 :         RPCTypeCheckArgument(request.params[1], UniValue::VARR);
     806          11 :         const auto& array{request.params[1].get_array()};
     807          46 :         for (unsigned int i = 0; i < array.size(); i++) {
     808         105 :             set_dmn_protxhash.emplace(ParseHashV(array[i], strprintf("pro_tx_hash (index %d)", i)));
     809             :         }
     810             :     }
     811             : 
     812          13 :     Consensus::LLMQType llmq_type = Consensus::LLMQ_NONE;
     813          13 :     if (request.params.size() > 2) {
     814           9 :         RPCTypeCheckArgument(request.params[2], UniValue::VNUM);
     815           9 :         llmq_type = (Consensus::LLMQType)request.params[2].get_int();
     816             :     }
     817             : 
     818          13 :     uint256 quorum_hash;
     819          13 :     if (request.params.size() > 3) {
     820          18 :         quorum_hash = ParseHashV(request.params[3], "quorum_hash");
     821             :     }
     822             : 
     823          13 :     const auto& mn_connan =  g_connman->GetTierTwoConnMan();
     824          13 :     if (op_type == SINGLE_CONN) {
     825           2 :         for (const auto& protxhash : set_dmn_protxhash) {
     826             :             // if the connection exist or if the dmn doesn't exist,
     827             :             // it will simply not even try to connect to it.
     828           1 :             mn_connan->addPendingMasternode(protxhash);
     829             :         }
     830           1 :         return true;
     831          12 :     } else if (op_type == QUORUM_MEMBERS_CONN) {
     832           2 :         mn_connan->setQuorumNodes(llmq_type, quorum_hash, set_dmn_protxhash);
     833           2 :         return true;
     834          10 :     } else if (op_type == IQR_MEMBERS_CONN) {
     835           7 :         mn_connan->setMasternodeQuorumRelayMembers(llmq_type, quorum_hash, set_dmn_protxhash);
     836           7 :         return true;
     837           3 :     } else if (op_type == PROBE_CONN) {
     838           1 :         mn_connan->addPendingProbeConnections(set_dmn_protxhash);
     839           1 :         return true;
     840           2 :     } else if (op_type == CLEAR_CONN) {
     841           2 :         mn_connan->clear();
     842           2 :         return true;
     843             :     }
     844           0 :     return false;
     845             : }
     846             : 
     847             : // clang-format off
     848             : static const CRPCCommand commands[] =
     849             : { //  category              name                      actor (function)         okSafe argNames
     850             :   //  --------------------- ------------------------  -----------------------  ------ --------
     851             :     { "control",            "getinfo",                &getinfo,                true,  {} }, /* uses wallet if enabled */
     852             :     { "control",            "getmemoryinfo",          &getmemoryinfo,          true,  {} },
     853             :     { "control",            "mnsync",                 &mnsync,                 true,  {"mode"} },
     854             :     { "control",            "spork",                  &spork,                  true,  {"name","value"} },
     855             : 
     856             :     { "util",               "createmultisig",         &createmultisig,         true,  {"nrequired","keys"} },
     857             :     { "util",               "logging",                &logging,                true,  {"include", "exclude"} },
     858             :     { "util",               "validateaddress",        &validateaddress,        true,  {"pivxaddress"} }, /* uses wallet if enabled */
     859             :     { "util",               "verifymessage",          &verifymessage,          true,  {"pivxaddress","signature","message"} },
     860             : 
     861             :     /** Not shown in help */
     862             :     { "hidden",             "echo",                   &echo,                   true,  {"arg0","arg1","arg2","arg3","arg4","arg5","arg6","arg7","arg8","arg9"} },
     863             :     { "hidden",             "echojson",               &echo,                   true,  {"arg0","arg1","arg2","arg3","arg4","arg5","arg6","arg7","arg8","arg9"} },
     864             :     { "hidden",             "setmocktime",            &setmocktime,            true,  {"timestamp"} },
     865             :     { "hidden",             "mnconnect",              &mnconnect,              true,  {"op_type", "mn_list", "llmq_type", "quorum_hash"} },
     866             : };
     867             : // clang-format on
     868             : 
     869         494 : void RegisterMiscRPCCommands(CRPCTable &tableRPC)
     870             : {
     871        6422 :     for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++)
     872        5928 :         tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]);
     873         494 : }

Generated by: LCOV version 1.14