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 : }
|