LCOV - code coverage report
Current view: top level - src/rpc - masternode.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 291 559 52.1 %
Date: 2025-02-23 09:33:43 Functions: 19 30 63.3 %

          Line data    Source code
       1             : // Copyright (c) 2009-2012 The Bitcoin developers
       2             : // Copyright (c) 2015-2022 The PIVX Core developers
       3             : // Distributed under the MIT/X11 software license, see the accompanying
       4             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       5             : 
       6             : #include "activemasternode.h"
       7             : #include "db.h"
       8             : #include "evo/deterministicmns.h"
       9             : #include "key_io.h"
      10             : #include "masternode-payments.h"
      11             : #include "masternodeconfig.h"
      12             : #include "masternodeman.h"
      13             : #include "netaddress.h"
      14             : #include "netbase.h"
      15             : #include "tiertwo/tiertwo_sync_state.h"
      16             : #include "rpc/server.h"
      17             : #ifdef ENABLE_WALLET
      18             : #include "wallet/wallet.h"
      19             : #include "wallet/rpcwallet.h"
      20             : #endif
      21             : 
      22             : #include <univalue.h>
      23             : 
      24             : #include <boost/tokenizer.hpp>
      25             : 
      26             : // Duplicated from rpcevo.cpp for the compatibility phase. Remove after v6
      27        1232 : static UniValue DmnToJson(const CDeterministicMNCPtr dmn)
      28             : {
      29        1232 :     UniValue ret(UniValue::VOBJ);
      30        1232 :     dmn->ToJson(ret);
      31        1232 :     Coin coin;
      32        3696 :     if (!WITH_LOCK(cs_main, return pcoinsTip->GetUTXOCoin(dmn->collateralOutpoint, coin); )) {
      33             :         return ret;
      34             :     }
      35        2464 :     CTxDestination dest;
      36        1232 :     if (!ExtractDestination(coin.out.scriptPubKey, dest)) {
      37             :         return ret;
      38             :     }
      39        2464 :     ret.pushKV("collateralAddress", EncodeDestination(dest));
      40        1232 :     return ret;
      41             : }
      42             : 
      43         488 : UniValue mnping(const JSONRPCRequest& request)
      44             : {
      45         488 :     if (request.fHelp || !request.params.empty()) {
      46           0 :         throw std::runtime_error(
      47             :             "mnping \n"
      48             :             "\nSend masternode ping. Only for remote masternodes on Regtest\n"
      49             : 
      50             :             "\nResult:\n"
      51             :             "{\n"
      52             :             "  \"sent\":           (string YES|NO) Whether the ping was sent and, if not, the error.\n"
      53             :             "}\n"
      54             : 
      55           0 :             "\nExamples:\n" +
      56           0 :             HelpExampleCli("mnping", "") + HelpExampleRpc("mnping", ""));
      57             :     }
      58             : 
      59         488 :     if (!Params().IsRegTestNet()) {
      60           0 :         throw JSONRPCError(RPC_MISC_ERROR, "command available only for RegTest network");
      61             :     }
      62             : 
      63         488 :     if (!fMasterNode) {
      64           0 :         throw JSONRPCError(RPC_MISC_ERROR, "this is not a masternode");
      65             :     }
      66             : 
      67         488 :     UniValue ret(UniValue::VOBJ);
      68         488 :     std::string strError;
      69         976 :     ret.pushKV("sent", activeMasternode.SendMasternodePing(strError) ?
      70             :                        "YES" : strprintf("NO (%s)", strError));
      71         549 :     return ret;
      72             : }
      73             : 
      74          52 : UniValue initmasternode(const JSONRPCRequest& request)
      75             : {
      76          52 :     if (request.fHelp || (request.params.size() < 1 || request.params.size() > 2)) {
      77           0 :         throw std::runtime_error(
      78             :                 "initmasternode \"privkey\" ( \"address\" )\n"
      79             :                 "\nInitialize masternode on demand if it's not already initialized.\n"
      80             :                 "\nArguments:\n"
      81             :                 "1. privkey          (string, required) The masternode private key.\n"
      82             :                 "2. address          (string, optional) The IP:Port of the masternode. (Only needed for legacy masternodes)\n"
      83             : 
      84             :                 "\nResult:\n"
      85             :                 " success            (string) if the masternode initialization succeeded.\n"
      86             : 
      87           0 :                 "\nExamples:\n" +
      88           0 :                 HelpExampleCli("initmasternode", "\"9247iC59poZmqBYt9iDh9wDam6v9S1rW5XekjLGyPnDhrDkP4AK\" \"187.24.32.124:51472\"") +
      89           0 :                 HelpExampleRpc("initmasternode", "\"bls-sk1xye8es37kk7y2mz7mad6yz7fdygttexqwhypa0u86hzw2crqgxfqy29ajm\""));
      90             :     }
      91             : 
      92         104 :     std::string _strMasterNodePrivKey = request.params[0].get_str();
      93          52 :     if (_strMasterNodePrivKey.empty()) throw JSONRPCError(RPC_INVALID_PARAMETER, "Masternode key cannot be empty.");
      94             : 
      95          52 :     const auto& params = Params();
      96          52 :     bool isDeterministic = _strMasterNodePrivKey.find(params.Bech32HRP(CChainParams::BLS_SECRET_KEY)) != std::string::npos;
      97          52 :     if (isDeterministic) {
      98          41 :         if (!activeMasternodeManager) {
      99          41 :             activeMasternodeManager = new CActiveDeterministicMasternodeManager();
     100          41 :             RegisterValidationInterface(activeMasternodeManager);
     101             :         }
     102          82 :         auto res = activeMasternodeManager->SetOperatorKey(_strMasterNodePrivKey);
     103          41 :         if (!res) throw std::runtime_error(res.getError());
     104         123 :         const CBlockIndex* pindexTip = WITH_LOCK(cs_main, return chainActive.Tip(); );
     105          41 :         activeMasternodeManager->Init(pindexTip);
     106          41 :         if (activeMasternodeManager->GetState() == CActiveDeterministicMasternodeManager::MASTERNODE_ERROR) {
     107           0 :             throw std::runtime_error(activeMasternodeManager->GetStatus());
     108             :         }
     109          41 :         return "success";
     110             :     }
     111             :     // legacy
     112          11 :     if (request.params.size() < 2) throw JSONRPCError(RPC_INVALID_PARAMETER, "Must specify the IP address for legacy mn");
     113          63 :     std::string _strMasterNodeAddr = request.params[1].get_str();
     114          22 :     auto res = initMasternode(_strMasterNodePrivKey, _strMasterNodeAddr, false);
     115          11 :     if (!res) throw std::runtime_error(res.getError());
     116          11 :     return "success";
     117             : }
     118             : 
     119           6 : UniValue getcachedblockhashes(const JSONRPCRequest& request)
     120             : {
     121           6 :     if (request.fHelp || request.params.size() > 0)
     122           0 :         throw std::runtime_error(
     123             :             "getcachedblockhashes \n"
     124             :             "\nReturn the block hashes cached in the masternode manager\n"
     125             : 
     126             :             "\nResult:\n"
     127             :             "[\n"
     128             :             "  ...\n"
     129             :             "  \"xxxx\",   (string) hash at Index d (height modulo max cache size)\n"
     130             :             "  ...\n"
     131             :             "]\n"
     132             : 
     133           0 :             "\nExamples:\n" +
     134           0 :             HelpExampleCli("getcachedblockhashes", "") + HelpExampleRpc("getcachedblockhashes", ""));
     135             : 
     136           6 :     std::vector<uint256> vCacheCopy = mnodeman.GetCachedBlocks();
     137          12 :     UniValue ret(UniValue::VARR);
     138        1206 :     for (int i = 0; (unsigned) i < vCacheCopy.size(); i++) {
     139        2400 :         ret.push_back(vCacheCopy[i].ToString());
     140             :     }
     141          12 :     return ret;
     142             : }
     143             : 
     144        1575 : static inline bool filter(const std::string& str, const std::string& strFilter)
     145             : {
     146        3150 :     return str.find(strFilter) != std::string::npos;
     147             : }
     148             : 
     149        1232 : static inline bool filterMasternode(const UniValue& dmno, const std::string& strFilter, bool fEnabled)
     150             : {
     151        1642 :     return strFilter.empty() || (filter("ENABLED", strFilter) && fEnabled)
     152        2669 :                              || (filter("POSE_BANNED", strFilter) && !fEnabled)
     153        1642 :                              || (filter(dmno["proTxHash"].get_str(), strFilter))
     154        1616 :                              || (filter(dmno["collateralHash"].get_str(), strFilter))
     155        1616 :                              || (filter(dmno["collateralAddress"].get_str(), strFilter))
     156        1808 :                              || (filter(dmno["dmnstate"]["ownerAddress"].get_str(), strFilter))
     157        1808 :                              || (filter(dmno["dmnstate"]["operatorPubKey"].get_str(), strFilter))
     158        3053 :                              || (filter(dmno["dmnstate"]["votingAddress"].get_str(), strFilter));
     159             : }
     160             : 
     161         510 : UniValue listmasternodes(const JSONRPCRequest& request)
     162             : {
     163         510 :     if (request.fHelp || (request.params.size() > 1))
     164           0 :         throw std::runtime_error(
     165             :             "listmasternodes ( \"filter\" )\n"
     166             :             "\nGet a ranked list of masternodes\n"
     167             : 
     168             :             "\nArguments:\n"
     169             :             "1. \"filter\"    (string, optional) Filter search text. Partial match by txhash, status, or addr.\n"
     170             : 
     171             :             // !TODO: update for DMNs
     172             :             "\nResult:\n"
     173             :             "[\n"
     174             :             "  {\n"
     175             :             "    \"rank\": n,                             (numeric) Masternode Rank (or 0 if not enabled)\n"
     176             :             "    \"type\": \"legacy\"|\"deterministic\",  (string) type of masternode\n"
     177             :             "    \"txhash\": \"hash\",                    (string) Collateral transaction hash\n"
     178             :             "    \"outidx\": n,                           (numeric) Collateral transaction output index\n"
     179             :             "    \"pubkey\": \"key\",                     (string) Masternode public key used for message broadcasting\n"
     180             :             "    \"status\": s,                           (string) Status (ENABLED/EXPIRED/REMOVE/etc)\n"
     181             :             "    \"addr\": \"addr\",                      (string) Masternode PIVX address\n"
     182             :             "    \"version\": v,                          (numeric) Masternode protocol version\n"
     183             :             "    \"lastseen\": ttt,     (numeric) The time in seconds since epoch (Jan 1 1970 GMT) of the last seen\n"
     184             :             "    \"activetime\": ttt,   (numeric) The time in seconds since epoch (Jan 1 1970 GMT) masternode has been active\n"
     185             :             "    \"lastpaid\": ttt,     (numeric) The time in seconds since epoch (Jan 1 1970 GMT) masternode was last paid\n"
     186             :             "  }\n"
     187             :             "  ,...\n"
     188             :             "]\n"
     189             : 
     190           0 :             "\nExamples:\n" +
     191           0 :             HelpExampleCli("listmasternodes", "") + HelpExampleRpc("listmasternodes", ""));
     192             : 
     193             : 
     194        1355 :     const std::string& strFilter = request.params.size() > 0 ? request.params[0].get_str() : "";
     195        1020 :     UniValue ret(UniValue::VARR);
     196             : 
     197         510 :     if (deterministicMNManager->LegacyMNObsolete()) {
     198         340 :         auto mnList = deterministicMNManager->GetListAtChainTip();
     199         170 :         mnList.ForEachMN(false, [&](const CDeterministicMNCPtr& dmn) {
     200        2106 :             UniValue obj = DmnToJson(dmn);
     201        1053 :             if (filterMasternode(obj, strFilter, !dmn->IsPoSeBanned())) {
     202         993 :                 ret.push_back(obj);
     203             :             }
     204        1053 :         });
     205         170 :         return ret;
     206             :     }
     207             : 
     208             :     // Legacy masternodes (!TODO: remove when transition to dmn is complete)
     209         340 :     const CBlockIndex* chainTip = GetChainTip();
     210         340 :     if (!chainTip) return "[]";
     211         340 :     int nHeight = chainTip->nHeight;
     212         680 :     auto mnList = deterministicMNManager->GetListAtChainTip();
     213             : 
     214         340 :     int count_enabled = mnodeman.CountEnabled();
     215         680 :     std::vector<std::pair<int64_t, MasternodeRef>> vMasternodeRanks = mnodeman.GetMasternodeRanks(nHeight);
     216         992 :     for (int pos=0; pos < (int) vMasternodeRanks.size(); pos++) {
     217         652 :         const auto& s = vMasternodeRanks[pos];
     218         652 :         UniValue obj(UniValue::VOBJ);
     219         652 :         const CMasternode& mn = *(s.second);
     220             : 
     221         652 :         if (!mn.mnPayeeScript.empty()) {
     222             :             // Deterministic masternode
     223         358 :             auto dmn = mnList.GetMNByCollateral(mn.vin.prevout);
     224         179 :             if (dmn) {
     225         358 :                 UniValue obj = DmnToJson(dmn);
     226         179 :                 bool fEnabled = !dmn->IsPoSeBanned();
     227         179 :                 if (filterMasternode(obj, strFilter, fEnabled)) {
     228             :                     // Added for backward compatibility with legacy masternodes
     229          47 :                     obj.pushKV("type", "deterministic");
     230          94 :                     obj.pushKV("txhash", obj["proTxHash"].get_str());
     231          94 :                     obj.pushKV("addr", obj["dmnstate"]["payoutAddress"].get_str());
     232          47 :                     obj.pushKV("status", fEnabled ? "ENABLED" : "POSE_BANNED");
     233          94 :                     obj.pushKV("rank", fEnabled ? pos : 0);
     234          47 :                     ret.push_back(obj);
     235             :                 }
     236             :             }
     237         179 :             continue;
     238             :         }
     239             : 
     240         787 :         std::string strVin = mn.vin.prevout.ToStringShort();
     241         787 :         std::string strTxHash = mn.vin.prevout.hash.ToString();
     242         473 :         uint32_t oIdx = mn.vin.prevout.n;
     243             : 
     244         612 :         if (strFilter != "" && strTxHash.find(strFilter) == std::string::npos &&
     245        1423 :             mn.Status().find(strFilter) == std::string::npos &&
     246        1268 :             EncodeDestination(mn.pubKeyCollateralAddress.GetID()).find(strFilter) == std::string::npos) continue;
     247             : 
     248         628 :         std::string strStatus = mn.Status();
     249         628 :         std::string strHost;
     250         314 :         int port;
     251         314 :         SplitHostPort(mn.addr.ToString(), port, strHost);
     252         628 :         CNetAddr node;
     253         314 :         LookupHost(strHost.c_str(), node, false);
     254         628 :         std::string strNetwork = GetNetworkName(node.GetNetwork());
     255             : 
     256         407 :         obj.pushKV("rank", (strStatus == "ENABLED" ? pos : -1));
     257         314 :         obj.pushKV("type", "legacy");
     258         314 :         obj.pushKV("network", strNetwork);
     259         314 :         obj.pushKV("txhash", strTxHash);
     260         314 :         obj.pushKV("outidx", (uint64_t)oIdx);
     261         942 :         obj.pushKV("pubkey", EncodeDestination(mn.pubKeyMasternode.GetID()));
     262         314 :         obj.pushKV("status", strStatus);
     263         942 :         obj.pushKV("addr", EncodeDestination(mn.pubKeyCollateralAddress.GetID()));
     264         314 :         obj.pushKV("version", mn.protocolVersion);
     265         314 :         obj.pushKV("lastseen", (int64_t)mn.lastPing.sigTime);
     266         314 :         obj.pushKV("activetime", (int64_t)(mn.lastPing.sigTime - mn.sigTime));
     267         314 :         obj.pushKV("lastpaid", (int64_t)mnodeman.GetLastPaid(s.second, count_enabled, chainTip));
     268             : 
     269         314 :         ret.push_back(obj);
     270             :     }
     271             : 
     272         340 :     return ret;
     273             : }
     274             : 
     275         212 : UniValue getmasternodecount (const JSONRPCRequest& request)
     276             : {
     277         212 :     if (request.fHelp || (request.params.size() > 0))
     278           0 :         throw std::runtime_error(
     279             :             "getmasternodecount\n"
     280             :             "\nGet masternode count values\n"
     281             : 
     282             :             "\nResult:\n"
     283             :             "{\n"
     284             :             "  \"total\": n,        (numeric) Total masternodes\n"
     285             :             "  \"stable\": n,       (numeric) Stable count\n"
     286             :             "  \"enabled\": n,      (numeric) Enabled masternodes\n"
     287             :             "  \"inqueue\": n,      (numeric) Masternodes in queue\n"
     288             :             "  \"ipv4\": n,         (numeric) Number of IPv4 masternodes\n"
     289             :             "  \"ipv6\": n,         (numeric) Number of IPv6 masternodes\n"
     290             :             "  \"onion\": n         (numeric) Number of Tor masternodes\n"
     291             :             "}\n"
     292             : 
     293           0 :             "\nExamples:\n" +
     294           0 :             HelpExampleCli("getmasternodecount", "") + HelpExampleRpc("getmasternodecount", ""));
     295             : 
     296         424 :     UniValue obj(UniValue::VOBJ);
     297         212 :     int nCount = 0;
     298         212 :     const CBlockIndex* pChainTip = GetChainTip();
     299         212 :     if (!pChainTip) return "unknown";
     300             : 
     301         212 :     mnodeman.GetNextMasternodeInQueueForPayment(pChainTip->nHeight, true, nCount, pChainTip);
     302         212 :     auto infoMNs = mnodeman.getMNsInfo();
     303             : 
     304         212 :     obj.pushKV("total", infoMNs.total);
     305         212 :     obj.pushKV("stable", infoMNs.stableSize);
     306         212 :     obj.pushKV("enabled", infoMNs.enabledSize);
     307         212 :     obj.pushKV("inqueue", nCount);
     308         212 :     obj.pushKV("ipv4", infoMNs.ipv4);
     309         212 :     obj.pushKV("ipv6", infoMNs.ipv6);
     310         212 :     obj.pushKV("onion", infoMNs.onion);
     311             : 
     312         212 :     return obj;
     313             : }
     314             : 
     315           0 : UniValue masternodecurrent(const JSONRPCRequest& request)
     316             : {
     317           0 :     if (request.fHelp || (request.params.size() != 0))
     318           0 :         throw std::runtime_error(
     319             :             "masternodecurrent\n"
     320             :             "\nGet current masternode winner (scheduled to be paid next).\n"
     321             : 
     322             :             "\nResult:\n"
     323             :             "{\n"
     324             :             "  \"protocol\": xxxx,        (numeric) Protocol version\n"
     325             :             "  \"txhash\": \"xxxx\",      (string) Collateral transaction hash\n"
     326             :             "  \"pubkey\": \"xxxx\",      (string) MN Public key\n"
     327             :             "  \"lastseen\": xxx,         (numeric) Time since epoch of last seen\n"
     328             :             "  \"activeseconds\": xxx,    (numeric) Seconds MN has been active\n"
     329             :             "}\n"
     330             : 
     331           0 :             "\nExamples:\n" +
     332           0 :             HelpExampleCli("masternodecurrent", "") + HelpExampleRpc("masternodecurrent", ""));
     333             : 
     334           0 :     const CBlockIndex* pChainTip = GetChainTip();
     335           0 :     if (!pChainTip) return "unknown";
     336             : 
     337           0 :     int nCount = 0;
     338           0 :     MasternodeRef winner = mnodeman.GetNextMasternodeInQueueForPayment(pChainTip->nHeight + 1, true, nCount, pChainTip);
     339           0 :     if (winner) {
     340           0 :         UniValue obj(UniValue::VOBJ);
     341           0 :         obj.pushKV("protocol", (int64_t)winner->protocolVersion);
     342           0 :         obj.pushKV("txhash", winner->vin.prevout.hash.ToString());
     343           0 :         obj.pushKV("pubkey", EncodeDestination(winner->pubKeyCollateralAddress.GetID()));
     344           0 :         obj.pushKV("lastseen", winner->lastPing.IsNull() ? winner->sigTime : (int64_t)winner->lastPing.sigTime);
     345           0 :         obj.pushKV("activeseconds", winner->lastPing.IsNull() ? 0 : (int64_t)(winner->lastPing.sigTime - winner->sigTime));
     346           0 :         return obj;
     347             :     }
     348             : 
     349           0 :     throw std::runtime_error("unknown");
     350             : }
     351             : 
     352          14 : bool StartMasternodeEntry(UniValue& statusObjRet, CMasternodeBroadcast& mnbRet, bool& fSuccessRet, const CMasternodeConfig::CMasternodeEntry& mne, std::string& errorMessage, std::string strCommand = "")
     353             : {
     354          14 :     int nIndex;
     355          14 :     if(!mne.castOutputIndex(nIndex)) {
     356             :         return false;
     357             :     }
     358             : 
     359          42 :     CTxIn vin = CTxIn(uint256S(mne.getTxHash()), uint32_t(nIndex));
     360          14 :     CMasternode* pmn = mnodeman.Find(vin.prevout);
     361          14 :     if (pmn != nullptr) {
     362           2 :         if (strCommand == "missing") return false;
     363           2 :         if (strCommand == "disabled" && pmn->IsEnabled()) return false;
     364             :     }
     365             : 
     366          14 :     fSuccessRet = CMasternodeBroadcast::Create(mne.getIp(), mne.getPrivKey(), mne.getTxHash(), mne.getOutputIndex(), errorMessage, mnbRet, false, mnodeman.GetBestHeight());
     367             : 
     368          14 :     statusObjRet.pushKV("alias", mne.getAlias());
     369          14 :     statusObjRet.pushKV("result", fSuccessRet ? "success" : "failed");
     370          28 :     statusObjRet.pushKV("error", fSuccessRet ? "" : errorMessage);
     371             : 
     372          14 :     return true;
     373             : }
     374             : 
     375          14 : void RelayMNB(CMasternodeBroadcast& mnb, const bool fSuccess, int& successful, int& failed)
     376             : {
     377          14 :     if (fSuccess) {
     378          14 :         successful++;
     379          14 :         mnodeman.UpdateMasternodeList(mnb);
     380          14 :         mnb.Relay();
     381             :     } else {
     382           0 :         failed++;
     383             :     }
     384          14 : }
     385             : 
     386          12 : void RelayMNB(CMasternodeBroadcast& mnb, const bool fSucces)
     387             : {
     388          12 :     int successful = 0, failed = 0;
     389          12 :     return RelayMNB(mnb, fSucces, successful, failed);
     390             : }
     391             : 
     392           0 : void SerializeMNB(UniValue& statusObjRet, const CMasternodeBroadcast& mnb, const bool fSuccess, int& successful, int& failed)
     393             : {
     394           0 :     bool isBIP155 = mnb.addr.IsAddrV1Compatible();
     395           0 :     int version = isBIP155 ? PROTOCOL_VERSION | ADDRV2_FORMAT : PROTOCOL_VERSION;
     396           0 :     if(fSuccess) {
     397           0 :         successful++;
     398           0 :         CDataStream ssMnb(SER_NETWORK, version);
     399           0 :         ssMnb << mnb;
     400           0 :         statusObjRet.pushKV("hex", HexStr(ssMnb));
     401             :     } else {
     402           0 :         failed++;
     403             :     }
     404           0 : }
     405             : 
     406           0 : void SerializeMNB(UniValue& statusObjRet, const CMasternodeBroadcast& mnb, const bool fSuccess)
     407             : {
     408           0 :     int successful = 0, failed = 0;
     409           0 :     return SerializeMNB(statusObjRet, mnb, fSuccess, successful, failed);
     410             : }
     411             : 
     412          16 : UniValue startmasternode(const JSONRPCRequest& request)
     413             : {
     414             :     // Skip after legacy obsolete. !TODO: remove when transition to DMN is complete
     415          16 :     if (deterministicMNManager->LegacyMNObsolete()) {
     416           0 :         throw JSONRPCError(RPC_MISC_ERROR, "startmasternode is not supported when deterministic masternode list is active (DIP3)");
     417             :     }
     418             : 
     419          16 :     CWallet* const pwallet = GetWalletForJSONRPCRequest(request);
     420             : 
     421          16 :     if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
     422           0 :         return NullUniValue;
     423             : 
     424          29 :     std::string strCommand;
     425          16 :     if (!request.params.empty()) {
     426          16 :         strCommand = request.params[0].get_str();
     427             :     }
     428             : 
     429          16 :     if (strCommand == "local")
     430           2 :         throw JSONRPCError(RPC_INVALID_PARAMETER, "Local start is deprecated. Start your masternode from the controller wallet instead.");
     431          15 :     if (strCommand == "many")
     432           2 :         throw JSONRPCError(RPC_INVALID_PARAMETER, "Many set is deprecated. Use either 'all', 'missing', or 'disabled'.");
     433             : 
     434          14 :     if (request.fHelp || request.params.size() < 2 || request.params.size() > 4 ||
     435          14 :         (strCommand == "alias" && request.params.size() < 3))
     436           0 :         throw std::runtime_error(
     437             :             "startmasternode \"all|missing|disabled|alias\" lock_wallet ( \"alias\" reload_conf )\n"
     438           0 :             "\nAttempts to start one or more masternode(s)\n" +
     439           0 :             HelpRequiringPassphrase(pwallet) + "\n"
     440             : 
     441             :             "\nArguments:\n"
     442             :             "1. set          (string, required) Specify which set of masternode(s) to start.\n"
     443             :             "2. lock_wallet  (boolean, required) Lock wallet after completion.\n"
     444             :             "3. alias        (string, optional) Masternode alias. Required if using 'alias' as the set.\n"
     445             :             "4. reload_conf  (boolean, optional, default=False) reload the masternodes.conf data from disk"
     446             : 
     447             :             "\nResult:\n"
     448             :             "{\n"
     449             :             "  \"overall\": \"xxxx\",     (string) Overall status message\n"
     450             :             "  \"detail\": [\n"
     451             :             "    {\n"
     452             :             "      \"alias\": \"xxxx\",   (string) Node alias\n"
     453             :             "      \"result\": \"xxxx\",  (string) 'success' or 'failed'\n"
     454             :             "      \"error\": \"xxxx\"    (string) Error message, if failed\n"
     455             :             "    }\n"
     456             :             "    ,...\n"
     457             :             "  ]\n"
     458             :             "}\n"
     459             : 
     460           0 :             "\nExamples:\n" +
     461           0 :             HelpExampleCli("startmasternode", "\"alias\" false \"my_mn\"") + HelpExampleRpc("startmasternode", "\"alias\" false \"my_mn\""));
     462             : 
     463          17 :     RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VBOOL, UniValue::VSTR, UniValue::VBOOL}, true);
     464             : 
     465          14 :     EnsureWalletIsUnlocked(pwallet);
     466             : 
     467          14 :     bool fLock = request.params[1].get_bool();
     468          14 :     bool fReload = request.params.size() > 3 ? request.params[3].get_bool() : false;
     469             : 
     470             :     // Check reload param
     471          13 :     if (fReload) {
     472          13 :         masternodeConfig.clear();
     473          26 :         std::string error;
     474          13 :         if (!masternodeConfig.read(error)) {
     475           0 :             throw std::runtime_error("Error reloading masternode.conf, " + error);
     476             :         }
     477             :     }
     478             : 
     479          40 :     if (strCommand == "all" || strCommand == "missing" || strCommand == "disabled") {
     480           2 :         if ((strCommand == "missing" || strCommand == "disabled") &&
     481           0 :             (g_tiertwo_sync_state.GetSyncPhase() <= MASTERNODE_SYNC_LIST ||
     482           0 :                     g_tiertwo_sync_state.GetSyncPhase() == MASTERNODE_SYNC_FAILED)) {
     483           0 :             throw std::runtime_error("You can't use this command until masternode list is synced\n");
     484             :         }
     485             : 
     486           1 :         int successful = 0;
     487           1 :         int failed = 0;
     488             : 
     489           2 :         UniValue resultsObj(UniValue::VARR);
     490             : 
     491           3 :         for (const CMasternodeConfig::CMasternodeEntry& mne : masternodeConfig.getEntries()) {
     492           2 :             UniValue statusObj(UniValue::VOBJ);
     493           4 :             CMasternodeBroadcast mnb;
     494           4 :             std::string errorMessage;
     495           2 :             bool fSuccess = false;
     496           4 :             if (!StartMasternodeEntry(statusObj, mnb, fSuccess, mne, errorMessage, strCommand))
     497           0 :                 continue;
     498           2 :             resultsObj.push_back(statusObj);
     499           2 :             RelayMNB(mnb, fSuccess, successful, failed);
     500             :         }
     501           1 :         if (fLock)
     502           0 :             pwallet->Lock();
     503             : 
     504           2 :         UniValue returnObj(UniValue::VOBJ);
     505           2 :         returnObj.pushKV("overall", strprintf("Successfully started %d masternodes, failed to start %d, total %d", successful, failed, successful + failed));
     506           1 :         returnObj.pushKV("detail", resultsObj);
     507             : 
     508           1 :         return returnObj;
     509             :     }
     510             : 
     511          13 :     if (strCommand == "alias") {
     512          24 :         std::string alias = request.params[2].get_str();
     513             : 
     514          12 :         bool found = false;
     515             : 
     516          24 :         UniValue resultsObj(UniValue::VARR);
     517          24 :         UniValue statusObj(UniValue::VOBJ);
     518             : 
     519          26 :         for (const CMasternodeConfig::CMasternodeEntry& mne : masternodeConfig.getEntries()) {
     520          14 :             if (mne.getAlias() == alias) {
     521          12 :                 CMasternodeBroadcast mnb;
     522          12 :                 found = true;
     523          12 :                 std::string errorMessage;
     524          12 :                 bool fSuccess = false;
     525          24 :                 if (!StartMasternodeEntry(statusObj, mnb, fSuccess, mne, errorMessage, strCommand))
     526           0 :                     continue;
     527          12 :                 RelayMNB(mnb, fSuccess);
     528          12 :                 break;
     529             :             }
     530             :         }
     531             : 
     532          12 :         if (fLock)
     533           0 :             pwallet->Lock();
     534             : 
     535          12 :         if(!found) {
     536           0 :             statusObj.pushKV("alias", alias);
     537           0 :             statusObj.pushKV("result", "failed");
     538           0 :             statusObj.pushKV("error", "Could not find alias in config. Verify with listmasternodeconf.");
     539             :         }
     540             : 
     541          12 :         return statusObj;
     542             :     }
     543           2 :     throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid set name %s.", strCommand));
     544             : }
     545             : 
     546           0 : UniValue createmasternodekey(const JSONRPCRequest& request)
     547             : {
     548           0 :     if (request.fHelp || (request.params.size() != 0))
     549           0 :         throw std::runtime_error(
     550             :             "createmasternodekey\n"
     551             :             "\nCreate a new masternode private key\n"
     552             : 
     553             :             "\nResult:\n"
     554             :             "\"key\"    (string) Masternode private key\n"
     555             : 
     556           0 :             "\nExamples:\n" +
     557           0 :             HelpExampleCli("createmasternodekey", "") + HelpExampleRpc("createmasternodekey", ""));
     558             : 
     559           0 :     CKey secret;
     560           0 :     secret.MakeNewKey(false);
     561             : 
     562           0 :     return KeyIO::EncodeSecret(secret);
     563             : }
     564             : 
     565           1 : UniValue getmasternodeoutputs(const JSONRPCRequest& request)
     566             : {
     567           1 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
     568             : 
     569           1 :     if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
     570           0 :         return NullUniValue;
     571             : 
     572           1 :     if (request.fHelp || (request.params.size() != 0))
     573           0 :         throw std::runtime_error(
     574             :             "getmasternodeoutputs\n"
     575             :             "\nPrint all masternode transaction outputs\n"
     576             : 
     577             :             "\nResult:\n"
     578             :             "[\n"
     579             :             "  {\n"
     580             :             "    \"txhash\": \"xxxx\",    (string) output transaction hash\n"
     581             :             "    \"outputidx\": n       (numeric) output index number\n"
     582             :             "  }\n"
     583             :             "  ,...\n"
     584             :             "]\n"
     585             : 
     586           0 :             "\nExamples:\n" +
     587           0 :             HelpExampleCli("getmasternodeoutputs", "") + HelpExampleRpc("getmasternodeoutputs", ""));
     588             : 
     589             :     // Find possible candidates
     590           1 :     CWallet::AvailableCoinsFilter coinsFilter;
     591           1 :     coinsFilter.fIncludeDelegated = false;
     592           1 :     coinsFilter.nMaxOutValue = Params().GetConsensus().nMNCollateralAmt;
     593           1 :     coinsFilter.nMinOutValue = coinsFilter.nMaxOutValue;
     594           1 :     coinsFilter.fIncludeLocked = true;
     595           2 :     std::vector<COutput> possibleCoins;
     596           1 :     pwallet->AvailableCoins(&possibleCoins, nullptr, coinsFilter);
     597             : 
     598           2 :     UniValue ret(UniValue::VARR);
     599           2 :     for (COutput& out : possibleCoins) {
     600           2 :         UniValue obj(UniValue::VOBJ);
     601           2 :         obj.pushKV("txhash", out.tx->GetHash().ToString());
     602           1 :         obj.pushKV("outputidx", out.i);
     603           1 :         ret.push_back(obj);
     604             :     }
     605             : 
     606           1 :     return ret;
     607             : }
     608             : 
     609           0 : UniValue listmasternodeconf(const JSONRPCRequest& request)
     610             : {
     611           0 :     std::string strFilter = "";
     612             : 
     613           0 :     if (request.params.size() == 1) strFilter = request.params[0].get_str();
     614             : 
     615           0 :     if (request.fHelp || (request.params.size() > 1))
     616           0 :         throw std::runtime_error(
     617             :             "listmasternodeconf ( \"filter\" )\n"
     618             :             "\nPrint masternode.conf in JSON format\n"
     619             : 
     620             :             "\nArguments:\n"
     621             :             "1. \"filter\"    (string, optional) Filter search text. Partial match on alias, address, txHash, or status.\n"
     622             : 
     623             :             "\nResult:\n"
     624             :             "[\n"
     625             :             "  {\n"
     626             :             "    \"alias\": \"xxxx\",        (string) masternode alias\n"
     627             :             "    \"address\": \"xxxx\",      (string) masternode IP address\n"
     628             :             "    \"privateKey\": \"xxxx\",   (string) masternode private key\n"
     629             :             "    \"txHash\": \"xxxx\",       (string) transaction hash\n"
     630             :             "    \"outputIndex\": n,       (numeric) transaction output index\n"
     631             :             "    \"status\": \"xxxx\"        (string) masternode status\n"
     632             :             "  }\n"
     633             :             "  ,...\n"
     634             :             "]\n"
     635             : 
     636           0 :             "\nExamples:\n" +
     637           0 :             HelpExampleCli("listmasternodeconf", "") + HelpExampleRpc("listmasternodeconf", ""));
     638             : 
     639           0 :     std::vector<CMasternodeConfig::CMasternodeEntry> mnEntries;
     640           0 :     mnEntries = masternodeConfig.getEntries();
     641             : 
     642           0 :     UniValue ret(UniValue::VARR);
     643             : 
     644           0 :     for (CMasternodeConfig::CMasternodeEntry mne : masternodeConfig.getEntries()) {
     645           0 :         int nIndex;
     646           0 :         if(!mne.castOutputIndex(nIndex))
     647           0 :             continue;
     648           0 :         CTxIn vin = CTxIn(uint256S(mne.getTxHash()), uint32_t(nIndex));
     649           0 :         CMasternode* pmn = mnodeman.Find(vin.prevout);
     650             : 
     651           0 :         std::string strStatus = pmn ? pmn->Status() : "MISSING";
     652             : 
     653           0 :         if (strFilter != "" && mne.getAlias().find(strFilter) == std::string::npos &&
     654           0 :             mne.getIp().find(strFilter) == std::string::npos &&
     655           0 :             mne.getTxHash().find(strFilter) == std::string::npos &&
     656           0 :             strStatus.find(strFilter) == std::string::npos) continue;
     657             : 
     658           0 :         UniValue mnObj(UniValue::VOBJ);
     659           0 :         mnObj.pushKV("alias", mne.getAlias());
     660           0 :         mnObj.pushKV("address", mne.getIp());
     661           0 :         mnObj.pushKV("privateKey", mne.getPrivKey());
     662           0 :         mnObj.pushKV("txHash", mne.getTxHash());
     663           0 :         mnObj.pushKV("outputIndex", mne.getOutputIndex());
     664           0 :         mnObj.pushKV("status", strStatus);
     665           0 :         ret.push_back(mnObj);
     666             :     }
     667             : 
     668           0 :     return ret;
     669             : }
     670             : 
     671          44 : UniValue getmasternodestatus(const JSONRPCRequest& request)
     672             : {
     673          44 :     if (request.fHelp || (request.params.size() != 0))
     674           0 :         throw std::runtime_error(
     675             :             "getmasternodestatus\n"
     676             :             "\nPrint masternode status\n"
     677             : 
     678             :             "\nResult (if legacy masternode):\n"
     679             :             "{\n"
     680             :             "  \"txhash\": \"xxxx\",      (string) Collateral transaction hash\n"
     681             :             "  \"outputidx\": n,          (numeric) Collateral transaction output index number\n"
     682             :             "  \"netaddr\": \"xxxx\",     (string) Masternode network address\n"
     683             :             "  \"addr\": \"xxxx\",        (string) PIVX address for masternode payments\n"
     684             :             "  \"status\": \"xxxx\",      (string) Masternode status\n"
     685             :             "  \"message\": \"xxxx\"      (string) Masternode status message\n"
     686             :             "}\n"
     687             :             "\n"
     688             :             "\nResult (if deterministic masternode):\n"
     689             :             "{\n"
     690             :             "... !TODO ...\n"
     691             :             "}\n"
     692             : 
     693           0 :             "\nExamples:\n" +
     694           0 :             HelpExampleCli("getmasternodestatus", "") + HelpExampleRpc("getmasternodestatus", ""));
     695             : 
     696          44 :     if (!fMasterNode)
     697           0 :         throw JSONRPCError(RPC_MISC_ERROR, _("This is not a masternode."));
     698             : 
     699          44 :     bool fLegacyMN = (activeMasternode.vin != nullopt);
     700          44 :     bool fDeterministicMN = (activeMasternodeManager != nullptr);
     701             : 
     702          44 :     if (!fLegacyMN && !fDeterministicMN) {
     703           0 :         throw JSONRPCError(RPC_MISC_ERROR, _("Active Masternode not initialized."));
     704             :     }
     705             : 
     706          44 :     if (fDeterministicMN) {
     707          40 :         if (!deterministicMNManager->IsDIP3Enforced()) {
     708             :             // this should never happen as ProTx transactions are not accepted yet
     709           0 :             throw JSONRPCError(RPC_MISC_ERROR, _("Deterministic masternodes are not enforced yet"));
     710             :         }
     711          40 :         const CActiveMasternodeInfo* amninfo = activeMasternodeManager->GetInfo();
     712          40 :         UniValue mnObj(UniValue::VOBJ);
     713          80 :         auto dmn = deterministicMNManager->GetListAtChainTip().GetMNByOperatorKey(amninfo->pubKeyOperator);
     714          40 :         if (dmn) {
     715          40 :             dmn->ToJson(mnObj);
     716             :         }
     717          80 :         mnObj.pushKV("netaddr", amninfo->service.ToString());
     718          80 :         mnObj.pushKV("status", activeMasternodeManager->GetStatus());
     719          40 :         return mnObj;
     720             :     }
     721             : 
     722             :     // Legacy code !TODO: remove when transition to DMN is complete
     723           4 :     if (deterministicMNManager->LegacyMNObsolete()) {
     724           0 :         throw JSONRPCError(RPC_MISC_ERROR, _("Legacy Masternode is obsolete."));
     725             :     }
     726             : 
     727           4 :     CMasternode* pmn = mnodeman.Find(activeMasternode.vin->prevout);
     728             : 
     729           4 :     if (pmn) {
     730           8 :         UniValue mnObj(UniValue::VOBJ);
     731           8 :         mnObj.pushKV("txhash", activeMasternode.vin->prevout.hash.ToString());
     732           4 :         mnObj.pushKV("outputidx", (uint64_t)activeMasternode.vin->prevout.n);
     733           8 :         mnObj.pushKV("netaddr", activeMasternode.service.ToString());
     734          12 :         mnObj.pushKV("addr", EncodeDestination(pmn->pubKeyCollateralAddress.GetID()));
     735           4 :         mnObj.pushKV("status", activeMasternode.GetStatus());
     736           8 :         mnObj.pushKV("message", activeMasternode.GetStatusMessage());
     737           4 :         return mnObj;
     738             :     }
     739           0 :     throw std::runtime_error("Masternode not found in the list of available masternodes. Current status: "
     740           0 :                         + activeMasternode.GetStatusMessage());
     741             : }
     742             : 
     743           1 : UniValue getmasternodewinners(const JSONRPCRequest& request)
     744             : {
     745           1 :     if (request.fHelp || request.params.size() > 2)
     746           0 :         throw std::runtime_error(
     747             :             "getmasternodewinners ( blocks \"filter\" )\n"
     748             :             "\nPrint the masternode winners for the last n blocks\n"
     749             : 
     750             :             "\nArguments:\n"
     751             :             "1. blocks      (numeric, optional) Number of previous blocks to show (default: 10)\n"
     752             :             "2. filter      (string, optional) Search filter matching MN address\n"
     753             : 
     754             :             "\nResult (single winner):\n"
     755             :             "[\n"
     756             :             "  {\n"
     757             :             "    \"nHeight\": n,           (numeric) block height\n"
     758             :             "    \"winner\": {\n"
     759             :             "      \"address\": \"xxxx\",    (string) PIVX MN Address\n"
     760             :             "      \"nVotes\": n,          (numeric) Number of votes for winner\n"
     761             :             "    }\n"
     762             :             "  }\n"
     763             :             "  ,...\n"
     764             :             "]\n"
     765             : 
     766             :             "\nResult (multiple winners):\n"
     767             :             "[\n"
     768             :             "  {\n"
     769             :             "    \"nHeight\": n,           (numeric) block height\n"
     770             :             "    \"winner\": [\n"
     771             :             "      {\n"
     772             :             "        \"address\": \"xxxx\",  (string) PIVX MN Address\n"
     773             :             "        \"nVotes\": n,        (numeric) Number of votes for winner\n"
     774             :             "      }\n"
     775             :             "      ,...\n"
     776             :             "    ]\n"
     777             :             "  }\n"
     778             :             "  ,...\n"
     779             :             "]\n"
     780             : 
     781           0 :             "\nExamples:\n" +
     782           0 :             HelpExampleCli("getmasternodewinners", "") + HelpExampleRpc("getmasternodewinners", ""));
     783             : 
     784           2 :     int nHeight = WITH_LOCK(cs_main, return chainActive.Height());
     785           1 :     if (nHeight < 0) return "[]";
     786             : 
     787           1 :     int nLast = 10;
     788           2 :     std::string strFilter = "";
     789             : 
     790           1 :     if (request.params.size() >= 1)
     791           0 :         nLast = atoi(request.params[0].get_str());
     792             : 
     793           1 :     if (request.params.size() == 2)
     794           0 :         strFilter = request.params[1].get_str();
     795             : 
     796           2 :     UniValue ret(UniValue::VARR);
     797             : 
     798          31 :     for (int i = nHeight - nLast; i < nHeight + 20; i++) {
     799          30 :         UniValue obj(UniValue::VOBJ);
     800          30 :         obj.pushKV("nHeight", i);
     801             : 
     802          60 :         std::string strPayment = GetRequiredPaymentsString(i);
     803          30 :         if (strFilter != "" && strPayment.find(strFilter) == std::string::npos) continue;
     804             : 
     805          30 :         if (strPayment.find(',') != std::string::npos) {
     806           0 :             UniValue winner(UniValue::VARR);
     807           0 :             boost::char_separator<char> sep(",");
     808           0 :             boost::tokenizer< boost::char_separator<char> > tokens(strPayment, sep);
     809           0 :             for (const std::string& t : tokens) {
     810           0 :                 UniValue addr(UniValue::VOBJ);
     811           0 :                 std::size_t pos = t.find(":");
     812           0 :                 std::string strAddress = t.substr(0,pos);
     813           0 :                 uint64_t nVotes = atoi(t.substr(pos+1));
     814           0 :                 addr.pushKV("address", strAddress);
     815           0 :                 addr.pushKV("nVotes", nVotes);
     816           0 :                 winner.push_back(addr);
     817             :             }
     818           0 :             obj.pushKV("winner", winner);
     819          30 :         } else if (strPayment.find("Unknown") == std::string::npos) {
     820          15 :             UniValue winner(UniValue::VOBJ);
     821          15 :             std::size_t pos = strPayment.find(":");
     822          30 :             std::string strAddress = strPayment.substr(0,pos);
     823          15 :             uint64_t nVotes = atoi(strPayment.substr(pos+1));
     824          15 :             winner.pushKV("address", strAddress);
     825          15 :             winner.pushKV("nVotes", nVotes);
     826          30 :             obj.pushKV("winner", winner);
     827             :         } else {
     828          15 :             UniValue winner(UniValue::VOBJ);
     829          15 :             winner.pushKV("address", strPayment);
     830          15 :             winner.pushKV("nVotes", 0);
     831          30 :             obj.pushKV("winner", winner);
     832             :         }
     833             : 
     834          30 :             ret.push_back(obj);
     835             :     }
     836             : 
     837           1 :     return ret;
     838             : }
     839             : 
     840           0 : UniValue getmasternodescores(const JSONRPCRequest& request)
     841             : {
     842           0 :     if (request.fHelp || request.params.size() > 1)
     843           0 :         throw std::runtime_error(
     844             :             "getmasternodescores ( blocks )\n"
     845             :             "\nPrint list of winning masternode by score\n"
     846             : 
     847             :             "\nArguments:\n"
     848             :             "1. blocks      (numeric, optional) Show the last n blocks (default 10)\n"
     849             : 
     850             :             "\nResult:\n"
     851             :             "{\n"
     852             :             "  xxxx: \"xxxx\"   (numeric : string) Block height : Masternode hash\n"
     853             :             "  ,...\n"
     854             :             "}\n"
     855             : 
     856           0 :             "\nExamples:\n" +
     857           0 :             HelpExampleCli("getmasternodescores", "") + HelpExampleRpc("getmasternodescores", ""));
     858             : 
     859           0 :     int nLast = 10;
     860             : 
     861           0 :     if (request.params.size() == 1) {
     862           0 :         try {
     863           0 :             nLast = std::stoi(request.params[0].get_str());
     864           0 :         } catch (const std::invalid_argument&) {
     865           0 :             throw std::runtime_error("Exception on param 2");
     866             :         }
     867             :     }
     868             : 
     869           0 :     std::vector<std::pair<MasternodeRef, int>> vMnScores = mnodeman.GetMnScores(nLast);
     870           0 :     if (vMnScores.empty()) return "unknown";
     871             : 
     872           0 :     UniValue obj(UniValue::VOBJ);
     873           0 :     for (const auto& p : vMnScores) {
     874           0 :         const MasternodeRef& mn = p.first;
     875           0 :         const int nHeight = p.second;
     876           0 :         obj.pushKV(strprintf("%d", nHeight), mn->vin.prevout.hash.ToString().c_str());
     877             :     }
     878           0 :     return obj;
     879             : }
     880             : 
     881           0 : bool DecodeAddrV1(CMasternodeBroadcast& mnb, std::string strHexMnb) {
     882           0 :     std::vector<unsigned char> mnbData(ParseHex(strHexMnb));
     883           0 :     CDataStream ssData(mnbData, SER_NETWORK, PROTOCOL_VERSION);
     884           0 :     try {
     885           0 :         ssData >> mnb;
     886             :     }
     887           0 :     catch (const std::exception&) {
     888           0 :         return false;
     889             :     }
     890             : 
     891             :     return true;
     892             : }
     893             : 
     894           0 : bool DecodeHexMnb(CMasternodeBroadcast& mnb, std::string strHexMnb) {
     895             : 
     896           0 :     if (!IsHex(strHexMnb))
     897             :         return false;
     898             : 
     899           0 :     bool MNAddrV1 = DecodeAddrV1(mnb, strHexMnb);
     900           0 :     if (!MNAddrV1) {
     901           0 :         std::vector<unsigned char> mnbData(ParseHex(strHexMnb));
     902           0 :         CDataStream ssData(mnbData, SER_NETWORK, PROTOCOL_VERSION | ADDRV2_FORMAT);
     903           0 :         try {
     904           0 :             ssData >> mnb;
     905             :         }
     906           0 :         catch (const std::exception&) {
     907           0 :             return false;
     908             :         }
     909             :         return true;
     910             :     }
     911             :     return true;
     912             : }
     913             : 
     914           0 : UniValue createmasternodebroadcast(const JSONRPCRequest& request)
     915             : {
     916           0 :     CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
     917             : 
     918           0 :     if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
     919           0 :         return NullUniValue;
     920             : 
     921           0 :     std::string strCommand;
     922           0 :     if (request.params.size() >= 1)
     923           0 :         strCommand = request.params[0].get_str();
     924           0 :     if (request.fHelp || (strCommand != "alias" && strCommand != "all") || (strCommand == "alias" && request.params.size() < 2))
     925           0 :         throw std::runtime_error(
     926             :             "createmasternodebroadcast \"command\" ( \"alias\")\n"
     927           0 :             "\nCreates a masternode broadcast message for one or all masternodes configured in masternode.conf\n" +
     928           0 :             HelpRequiringPassphrase(pwallet) + "\n"
     929             : 
     930             :             "\nArguments:\n"
     931             :             "1. \"command\"      (string, required) \"alias\" for single masternode, \"all\" for all masternodes\n"
     932             :             "2. \"alias\"        (string, required if command is \"alias\") Alias of the masternode\n"
     933             : 
     934             :             "\nResult (all):\n"
     935             :             "{\n"
     936             :             "  \"overall\": \"xxx\",        (string) Overall status message indicating number of successes.\n"
     937             :             "  \"detail\": [                (array) JSON array of broadcast objects.\n"
     938             :             "    {\n"
     939             :             "      \"alias\": \"xxx\",      (string) Alias of the masternode.\n"
     940             :             "      \"success\": true|false, (boolean) Success status.\n"
     941             :             "      \"hex\": \"xxx\"         (string, if success=true) Hex encoded broadcast message.\n"
     942             :             "      \"error_message\": \"xxx\"   (string, if success=false) Error message, if any.\n"
     943             :             "    }\n"
     944             :             "    ,...\n"
     945             :             "  ]\n"
     946             :             "}\n"
     947             : 
     948             :             "\nResult (alias):\n"
     949             :             "{\n"
     950             :             "  \"alias\": \"xxx\",      (string) Alias of the masternode.\n"
     951             :             "  \"success\": true|false, (boolean) Success status.\n"
     952             :             "  \"hex\": \"xxx\"         (string, if success=true) Hex encoded broadcast message.\n"
     953             :             "  \"error_message\": \"xxx\"   (string, if success=false) Error message, if any.\n"
     954             :             "}\n"
     955             : 
     956           0 :             "\nExamples:\n" +
     957           0 :             HelpExampleCli("createmasternodebroadcast", "alias mymn1") + HelpExampleRpc("createmasternodebroadcast", "alias mymn1"));
     958             : 
     959           0 :     EnsureWalletIsUnlocked(pwallet);
     960             : 
     961           0 :     if (strCommand == "alias")
     962             :     {
     963             :         // wait for reindex and/or import to finish
     964           0 :         if (fImporting || fReindex)
     965           0 :             throw JSONRPCError(RPC_INTERNAL_ERROR, "Wait for reindex and/or import to finish");
     966             : 
     967           0 :         std::string alias = request.params[1].get_str();
     968           0 :         bool found = false;
     969             : 
     970           0 :         UniValue statusObj(UniValue::VOBJ);
     971           0 :         statusObj.pushKV("alias", alias);
     972             : 
     973           0 :         for (CMasternodeConfig::CMasternodeEntry mne : masternodeConfig.getEntries()) {
     974           0 :             if(mne.getAlias() == alias) {
     975           0 :                 CMasternodeBroadcast mnb;
     976           0 :                 found = true;
     977           0 :                 std::string errorMessage;
     978           0 :                 bool fSuccess = false;
     979           0 :                 if (!StartMasternodeEntry(statusObj, mnb, fSuccess, mne, errorMessage, strCommand))
     980           0 :                         continue;
     981           0 :                 SerializeMNB(statusObj, mnb, fSuccess);
     982           0 :                 break;
     983             :             }
     984             :         }
     985             : 
     986           0 :         if(!found) {
     987           0 :             statusObj.pushKV("success", false);
     988           0 :             statusObj.pushKV("error_message", "Could not find alias in config. Verify with listmasternodeconf.");
     989             :         }
     990             : 
     991           0 :         return statusObj;
     992             :     }
     993             : 
     994           0 :     if (strCommand == "all")
     995             :     {
     996             :         // wait for reindex and/or import to finish
     997           0 :         if (fImporting || fReindex)
     998           0 :             throw JSONRPCError(RPC_INTERNAL_ERROR, "Wait for reindex and/or import to finish");
     999             : 
    1000           0 :         int successful = 0;
    1001           0 :         int failed = 0;
    1002             : 
    1003           0 :         UniValue resultsObj(UniValue::VARR);
    1004             : 
    1005           0 :         for (CMasternodeConfig::CMasternodeEntry mne : masternodeConfig.getEntries()) {
    1006           0 :             UniValue statusObj(UniValue::VOBJ);
    1007           0 :             CMasternodeBroadcast mnb;
    1008           0 :             std::string errorMessage;
    1009           0 :             bool fSuccess = false;
    1010           0 :             if (!StartMasternodeEntry(statusObj, mnb, fSuccess, mne, errorMessage, strCommand))
    1011           0 :                     continue;
    1012           0 :             SerializeMNB(statusObj, mnb, fSuccess, successful, failed);
    1013           0 :             resultsObj.push_back(statusObj);
    1014             :         }
    1015             : 
    1016           0 :         UniValue returnObj(UniValue::VOBJ);
    1017           0 :         returnObj.pushKV("overall", strprintf("Successfully created broadcast messages for %d masternodes, failed to create %d, total %d", successful, failed, successful + failed));
    1018           0 :         returnObj.pushKV("detail", resultsObj);
    1019             : 
    1020           0 :         return returnObj;
    1021             :     }
    1022           0 :     return NullUniValue;
    1023             : }
    1024             : 
    1025           0 : UniValue decodemasternodebroadcast(const JSONRPCRequest& request)
    1026             : {
    1027           0 :     if (request.fHelp || request.params.size() != 1)
    1028           0 :         throw std::runtime_error(
    1029             :             "decodemasternodebroadcast \"hexstring\"\n"
    1030             :             "\nCommand to decode masternode broadcast messages\n"
    1031             : 
    1032             :             "\nArgument:\n"
    1033             :             "1. \"hexstring\"        (string) The hex encoded masternode broadcast message\n"
    1034             : 
    1035             :             "\nResult:\n"
    1036             :             "{\n"
    1037             :             "  \"vin\": \"xxxx\"                (string) The unspent output which is holding the masternode collateral\n"
    1038             :             "  \"addr\": \"xxxx\"               (string) IP address of the masternode\n"
    1039             :             "  \"pubkeycollateral\": \"xxxx\"   (string) Collateral address's public key\n"
    1040             :             "  \"pubkeymasternode\": \"xxxx\"   (string) Masternode's public key\n"
    1041             :             "  \"vchsig\": \"xxxx\"             (string) Base64-encoded signature of this message (verifiable via pubkeycollateral)\n"
    1042             :             "  \"sigtime\": \"nnn\"             (numeric) Signature timestamp\n"
    1043             :             "  \"sigvalid\": \"xxx\"            (string) \"true\"/\"false\" whether or not the mnb signature checks out.\n"
    1044             :             "  \"protocolversion\": \"nnn\"     (numeric) Masternode's protocol version\n"
    1045             :             "  \"nMessVersion\": \"nnn\"        (numeric) MNB Message version number\n"
    1046             :             "  \"lastping\" : {                 (object) JSON object with information about the masternode's last ping\n"
    1047             :             "      \"vin\": \"xxxx\"            (string) The unspent output of the masternode which is signing the message\n"
    1048             :             "      \"blockhash\": \"xxxx\"      (string) Current chaintip blockhash minus 12\n"
    1049             :             "      \"sigtime\": \"nnn\"         (numeric) Signature time for this ping\n"
    1050             :             "      \"sigvalid\": \"xxx\"        (string) \"true\"/\"false\" whether or not the mnp signature checks out.\n"
    1051             :             "      \"vchsig\": \"xxxx\"         (string) Base64-encoded signature of this ping (verifiable via pubkeymasternode)\n"
    1052             :             "      \"nMessVersion\": \"nnn\"    (numeric) MNP Message version number\n"
    1053             :             "  }\n"
    1054             :             "}\n"
    1055             : 
    1056           0 :             "\nExamples:\n" +
    1057           0 :             HelpExampleCli("decodemasternodebroadcast", "hexstring") + HelpExampleRpc("decodemasternodebroadcast", "hexstring"));
    1058             : 
    1059           0 :     CMasternodeBroadcast mnb;
    1060             : 
    1061           0 :     if (!DecodeHexMnb(mnb, request.params[0].get_str()))
    1062           0 :         throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Masternode broadcast message decode failed");
    1063             : 
    1064           0 :     UniValue resultObj(UniValue::VOBJ);
    1065             : 
    1066           0 :     resultObj.pushKV("vin", mnb.vin.prevout.ToString());
    1067           0 :     resultObj.pushKV("addr", mnb.addr.ToString());
    1068           0 :     resultObj.pushKV("pubkeycollateral", EncodeDestination(mnb.pubKeyCollateralAddress.GetID()));
    1069           0 :     resultObj.pushKV("pubkeymasternode", EncodeDestination(mnb.pubKeyMasternode.GetID()));
    1070           0 :     resultObj.pushKV("vchsig", mnb.GetSignatureBase64());
    1071           0 :     resultObj.pushKV("sigtime", mnb.sigTime);
    1072           0 :     resultObj.pushKV("sigvalid", mnb.CheckSignature() ? "true" : "false");
    1073           0 :     resultObj.pushKV("protocolversion", mnb.protocolVersion);
    1074           0 :     resultObj.pushKV("nMessVersion", mnb.nMessVersion);
    1075             : 
    1076           0 :     UniValue lastPingObj(UniValue::VOBJ);
    1077           0 :     lastPingObj.pushKV("vin", mnb.lastPing.vin.prevout.ToString());
    1078           0 :     lastPingObj.pushKV("blockhash", mnb.lastPing.blockHash.ToString());
    1079           0 :     lastPingObj.pushKV("sigtime", mnb.lastPing.sigTime);
    1080           0 :     lastPingObj.pushKV("sigvalid", mnb.lastPing.CheckSignature(mnb.pubKeyMasternode.GetID()) ? "true" : "false");
    1081           0 :     lastPingObj.pushKV("vchsig", mnb.lastPing.GetSignatureBase64());
    1082           0 :     lastPingObj.pushKV("nMessVersion", mnb.lastPing.nMessVersion);
    1083             : 
    1084           0 :     resultObj.pushKV("lastping", lastPingObj);
    1085             : 
    1086           0 :     return resultObj;
    1087             : }
    1088             : 
    1089           0 : UniValue relaymasternodebroadcast(const JSONRPCRequest& request)
    1090             : {
    1091           0 :     if (request.fHelp || request.params.size() != 1)
    1092           0 :         throw std::runtime_error(
    1093             :             "relaymasternodebroadcast \"hexstring\"\n"
    1094             :             "\nCommand to relay masternode broadcast messages\n"
    1095             : 
    1096             :             "\nArguments:\n"
    1097             :             "1. \"hexstring\"        (string) The hex encoded masternode broadcast message\n"
    1098             : 
    1099           0 :             "\nExamples:\n" +
    1100           0 :             HelpExampleCli("relaymasternodebroadcast", "hexstring") + HelpExampleRpc("relaymasternodebroadcast", "hexstring"));
    1101             : 
    1102             : 
    1103           0 :     CMasternodeBroadcast mnb;
    1104             : 
    1105           0 :     if (!DecodeHexMnb(mnb, request.params[0].get_str()))
    1106           0 :         throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Masternode broadcast message decode failed");
    1107             : 
    1108           0 :     if(!mnb.CheckSignature())
    1109           0 :         throw JSONRPCError(RPC_INVALID_PARAMETER, "Masternode broadcast signature verification failed");
    1110             : 
    1111           0 :     mnodeman.UpdateMasternodeList(mnb);
    1112           0 :     mnb.Relay();
    1113             : 
    1114           0 :     return strprintf("Masternode broadcast sent (service %s, vin %s)", mnb.addr.ToString(), mnb.vin.ToString());
    1115             : }
    1116             : 
    1117             : // clang-format off
    1118             : static const CRPCCommand commands[] =
    1119             : { //  category              name                         actor (function)            okSafe argNames
    1120             :   //  --------------------- ---------------------------  --------------------------  ------ --------
    1121             :     { "masternode",         "createmasternodebroadcast", &createmasternodebroadcast, true,  {"command","alias"} },
    1122             :     { "masternode",         "createmasternodekey",       &createmasternodekey,       true,  {} },
    1123             :     { "masternode",         "decodemasternodebroadcast", &decodemasternodebroadcast, true,  {"hexstring"} },
    1124             :     { "masternode",         "getmasternodecount",        &getmasternodecount,        true,  {} },
    1125             :     { "masternode",         "getmasternodeoutputs",      &getmasternodeoutputs,      true,  {} },
    1126             :     { "masternode",         "getmasternodescores",       &getmasternodescores,       true,  {"blocks"} },
    1127             :     { "masternode",         "getmasternodestatus",       &getmasternodestatus,       true,  {} },
    1128             :     { "masternode",         "getmasternodewinners",      &getmasternodewinners,      true,  {"blocks","filter"} },
    1129             :     { "masternode",         "initmasternode",            &initmasternode,            true,  {"privkey","address","deterministic"} },
    1130             :     { "masternode",         "listmasternodeconf",        &listmasternodeconf,        true,  {"filter"} },
    1131             :     { "masternode",         "listmasternodes",           &listmasternodes,           true,  {"filter"} },
    1132             :     { "masternode",         "masternodecurrent",         &masternodecurrent,         true,  {} },
    1133             :     { "masternode",         "relaymasternodebroadcast",  &relaymasternodebroadcast,  true,  {"hexstring"} },
    1134             :     { "masternode",         "startmasternode",           &startmasternode,           true,  {"set","lock_wallet","alias","reload_conf"} },
    1135             : 
    1136             :     /** Not shown in help */
    1137             :     { "hidden",             "getcachedblockhashes",      &getcachedblockhashes,      true,  {} },
    1138             :     { "hidden",             "mnping",                    &mnping,                    true,  {} },
    1139             : };
    1140             : // clang-format on
    1141             : 
    1142         494 : void RegisterMasternodeRPCCommands(CRPCTable &tableRPC)
    1143             : {
    1144        8398 :     for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++)
    1145        7904 :         tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]);
    1146         494 : }

Generated by: LCOV version 1.14