From 256e02f760accccd0895bc1ef58eb53f69230fdd Mon Sep 17 00:00:00 2001 From: UdjinM6 Date: Thu, 7 Jul 2016 15:11:17 +0300 Subject: [PATCH] Backport `masternodebroadcast` to v0.12.0.x see 40f0d1f1dc6782d640beb925b14a7eccc6fbd69a and c96284a7879b02fdc365a9bb2e28fd8199c01e91 for more info --- src/activemasternode.cpp | 61 ++++----- src/activemasternode.h | 8 +- src/masternode.cpp | 74 +++++++--- src/masternode.h | 4 +- src/masternodeman.cpp | 91 ++++++++----- src/masternodeman.h | 5 + src/rpcmasternode.cpp | 285 ++++++++++++++++++++++++++++++++++++++- src/rpcserver.cpp | 1 + src/rpcserver.h | 1 + 9 files changed, 437 insertions(+), 93 deletions(-) diff --git a/src/activemasternode.cpp b/src/activemasternode.cpp index e8cc1acb95305..42214cae060c1 100644 --- a/src/activemasternode.cpp +++ b/src/activemasternode.cpp @@ -113,12 +113,17 @@ void CActiveMasternode::ManageStatus() return; } - if(!Register(vin, service, keyCollateralAddress, pubKeyCollateralAddress, keyMasternode, pubKeyMasternode, errorMessage)) { - notCapableReason = "Error on Register: " + errorMessage; + CMasternodeBroadcast mnb; + if(!CreateBroadcast(vin, service, keyCollateralAddress, pubKeyCollateralAddress, keyMasternode, pubKeyMasternode, errorMessage, mnb)) { + notCapableReason = "Error on CreateBroadcast: " + errorMessage; LogPrintf("Register::ManageStatus() - %s\n", notCapableReason); return; } + //send to all peers + LogPrintf("CActiveMasternode::ManageStatus() - Relay broadcast vin = %s\n", vin.ToString()); + mnb.Relay(); + LogPrintf("CActiveMasternode::ManageStatus() - Is capable master node!\n"); status = ACTIVE_MASTERNODE_STARTED; @@ -203,7 +208,7 @@ bool CActiveMasternode::SendMasternodePing(std::string& errorMessage) { } -bool CActiveMasternode::Register(std::string strService, std::string strKeyMasternode, std::string strTxHash, std::string strOutputIndex, std::string& errorMessage) { +bool CActiveMasternode::CreateBroadcast(std::string strService, std::string strKeyMasternode, std::string strTxHash, std::string strOutputIndex, std::string& errorMessage, CMasternodeBroadcast &mnb, bool fOffline) { CTxIn vin; CPubKey pubKeyCollateralAddress; CKey keyCollateralAddress; @@ -211,22 +216,22 @@ bool CActiveMasternode::Register(std::string strService, std::string strKeyMaste CKey keyMasternode; //need correct blocks to send ping - if(!masternodeSync.IsBlockchainSynced()) { - errorMessage = GetStatus(); - LogPrintf("CActiveMasternode::Register() - %s\n", errorMessage); + if(!fOffline && !masternodeSync.IsBlockchainSynced()) { + errorMessage = "Sync in progress. Must wait until sync is complete to start Masternode"; + LogPrintf("CActiveMasternode::CreateBroadcast() - %s\n", errorMessage); return false; } if(!darkSendSigner.SetKey(strKeyMasternode, errorMessage, keyMasternode, pubKeyMasternode)) { errorMessage = strprintf("Can't find keys for masternode %s - %s", strService, errorMessage); - LogPrintf("CActiveMasternode::Register() - %s\n", errorMessage); + LogPrintf("CActiveMasternode::CreateBroadcast() - %s\n", errorMessage); return false; } if(!GetMasterNodeVin(vin, pubKeyCollateralAddress, keyCollateralAddress, strTxHash, strOutputIndex)) { errorMessage = strprintf("Could not allocate vin %s:%s for masternode %s", strTxHash, strOutputIndex, strService); - LogPrintf("CActiveMasternode::Register() - %s\n", errorMessage); + LogPrintf("CActiveMasternode::CreateBroadcast() - %s\n", errorMessage); return false; } @@ -234,53 +239,40 @@ bool CActiveMasternode::Register(std::string strService, std::string strKeyMaste if(Params().NetworkID() == CBaseChainParams::MAIN) { if(service.GetPort() != 9999) { errorMessage = strprintf("Invalid port %u for masternode %s - only 9999 is supported on mainnet.", service.GetPort(), strService); - LogPrintf("CActiveMasternode::Register() - %s\n", errorMessage); + LogPrintf("CActiveMasternode::CreateBroadcast() - %s\n", errorMessage); return false; } } else if(service.GetPort() == 9999) { errorMessage = strprintf("Invalid port %u for masternode %s - 9999 is only supported on mainnet.", service.GetPort(), strService); - LogPrintf("CActiveMasternode::Register() - %s\n", errorMessage); + LogPrintf("CActiveMasternode::CreateBroadcast() - %s\n", errorMessage); return false; } addrman.Add(CAddress(service), CNetAddr("127.0.0.1"), 2*60*60); - return Register(vin, CService(strService), keyCollateralAddress, pubKeyCollateralAddress, keyMasternode, pubKeyMasternode, errorMessage); + return CreateBroadcast(vin, CService(strService), keyCollateralAddress, pubKeyCollateralAddress, keyMasternode, pubKeyMasternode, errorMessage, mnb); } -bool CActiveMasternode::Register(CTxIn vin, CService service, CKey keyCollateralAddress, CPubKey pubKeyCollateralAddress, CKey keyMasternode, CPubKey pubKeyMasternode, std::string &errorMessage) { - CMasternodeBroadcast mnb; +bool CActiveMasternode::CreateBroadcast(CTxIn vin, CService service, CKey keyCollateralAddress, CPubKey pubKeyCollateralAddress, CKey keyMasternode, CPubKey pubKeyMasternode, std::string &errorMessage, CMasternodeBroadcast &mnb) { + // wait for reindex and/or import to finish + if (fImporting || fReindex) return false; + CMasternodePing mnp(vin); if(!mnp.Sign(keyMasternode, pubKeyMasternode)){ errorMessage = strprintf("Failed to sign ping, vin: %s", vin.ToString()); - LogPrintf("CActiveMasternode::Register() - %s\n", errorMessage); + LogPrintf("CActiveMasternode::CreateBroadcast() - %s\n", errorMessage); + mnb = CMasternodeBroadcast(); return false; } - mnodeman.mapSeenMasternodePing.insert(make_pair(mnp.GetHash(), mnp)); - LogPrintf("CActiveMasternode::Register() - Adding to Masternode list\n service: %s\n vin: %s\n", service.ToString(), vin.ToString()); mnb = CMasternodeBroadcast(service, vin, pubKeyCollateralAddress, pubKeyMasternode, PROTOCOL_VERSION); mnb.lastPing = mnp; if(!mnb.Sign(keyCollateralAddress)){ errorMessage = strprintf("Failed to sign broadcast, vin: %s", vin.ToString()); - LogPrintf("CActiveMasternode::Register() - %s\n", errorMessage); + LogPrintf("CActiveMasternode::CreateBroadcast() - %s\n", errorMessage); + mnb = CMasternodeBroadcast(); return false; } - mnodeman.mapSeenMasternodeBroadcast.insert(make_pair(mnb.GetHash(), mnb)); - masternodeSync.AddedMasternodeList(mnb.GetHash()); - - CMasternode* pmn = mnodeman.Find(vin); - if(pmn == NULL) - { - CMasternode mn(mnb); - mnodeman.Add(mn); - } else { - pmn->UpdateFromNewBroadcast(mnb); - } - - //send to all peers - LogPrintf("CActiveMasternode::Register() - RelayElectionEntry vin = %s\n", vin.ToString()); - mnb.Relay(); return true; } @@ -290,6 +282,9 @@ bool CActiveMasternode::GetMasterNodeVin(CTxIn& vin, CPubKey& pubkey, CKey& secr } bool CActiveMasternode::GetMasterNodeVin(CTxIn& vin, CPubKey& pubkey, CKey& secretKey, std::string strTxHash, std::string strOutputIndex) { + // wait for reindex and/or import to finish + if (fImporting || fReindex) return false; + // Find possible candidates TRY_LOCK(pwalletMain->cs_wallet, fWallet); if(!fWallet) return false; @@ -332,6 +327,8 @@ bool CActiveMasternode::GetMasterNodeVin(CTxIn& vin, CPubKey& pubkey, CKey& secr // Extract Masternode vin information from output bool CActiveMasternode::GetVinFromOutput(COutput out, CTxIn& vin, CPubKey& pubkey, CKey& secretKey) { + // wait for reindex and/or import to finish + if (fImporting || fReindex) return false; CScript pubScript; diff --git a/src/activemasternode.h b/src/activemasternode.h index 93a64eeab253a..fa6a7c45f887e 100644 --- a/src/activemasternode.h +++ b/src/activemasternode.h @@ -29,8 +29,8 @@ class CActiveMasternode /// Ping Masternode bool SendMasternodePing(std::string& errorMessage); - /// Register any Masternode - bool Register(CTxIn vin, CService service, CKey key, CPubKey pubKey, CKey keyMasternode, CPubKey pubKeyMasternode, std::string &errorMessage); + /// Create Masternode broadcast, needs to be relayed manually after that + bool CreateBroadcast(CTxIn vin, CService service, CKey key, CPubKey pubKey, CKey keyMasternode, CPubKey pubKeyMasternode, std::string &errorMessage, CMasternodeBroadcast &mnb); /// Get 1000DRK input that can be used for the Masternode bool GetMasterNodeVin(CTxIn& vin, CPubKey& pubkey, CKey& secretKey, std::string strTxHash, std::string strOutputIndex); @@ -57,8 +57,8 @@ class CActiveMasternode void ManageStatus(); std::string GetStatus(); - /// Register remote Masternode - bool Register(std::string strService, std::string strKey, std::string strTxHash, std::string strOutputIndex, std::string& errorMessage); + /// Create Masternode broadcast, needs to be relayed manually after that + bool CreateBroadcast(std::string strService, std::string strKey, std::string strTxHash, std::string strOutputIndex, std::string& errorMessage, CMasternodeBroadcast &mnb, bool fOffline = false); /// Get 1000DRK input that can be used for the Masternode bool GetMasterNodeVin(CTxIn& vin, CPubKey& pubkey, CKey& secretKey); diff --git a/src/masternode.cpp b/src/masternode.cpp index 4b449075208de..07afa7c2fca01 100644 --- a/src/masternode.cpp +++ b/src/masternode.cpp @@ -376,6 +376,10 @@ bool CMasternodeBroadcast::CheckAndUpdate(int& nDos) return false; } + // incorrect ping or its sigTime + if(lastPing == CMasternodePing() || !lastPing.CheckAndUpdate(nDos, false, true)) + return false; + std::string strMessage; std::string errorMessage = ""; @@ -436,18 +440,20 @@ bool CMasternodeBroadcast::CheckAndUpdate(int& nDos) CMasternode* pmn = mnodeman.Find(vin); // no such masternode, nothing to update - if(pmn == NULL) return true ; - else { - // this broadcast older than we have, it's bad. - if(pmn->sigTime > sigTime) { - LogPrintf("mnb - Bad sigTime %d for Masternode %20s %105s (existing broadcast is at %d)\n", - sigTime, addr.ToString(), vin.ToString(), pmn->sigTime); - return false; - } - // masternode is not enabled yet/already, nothing to update - if(!pmn->IsEnabled()) return true; + if(pmn == NULL) return true; + + // this broadcast is older or equal than the one that we already have - it's bad and should never happen + // unless someone is doing something fishy + // (mapSeenMasternodeBroadcast in CMasternodeMan::ProcessMessage should filter legit duplicates) + if(pmn->sigTime >= sigTime) { + LogPrintf("CMasternodeBroadcast::CheckAndUpdate - Bad sigTime %d for Masternode %20s %105s (existing broadcast is at %d)\n", + sigTime, addr.ToString(), vin.ToString(), pmn->sigTime); + return false; } + // masternode is not enabled yet/already, nothing to update + if(!pmn->IsEnabled()) return true; + // mn.pubkey = pubkey, IsVinAssociatedWithPubkey is validated once below, // after that they just need to match if(pmn->pubkey == pubkey && !pmn->IsBroadcastedWithin(MASTERNODE_MIN_MNB_SECONDS)) { @@ -470,6 +476,10 @@ bool CMasternodeBroadcast::CheckInputsAndAdd(int& nDoS) if(fMasterNode && vin.prevout == activeMasternode.vin.prevout && pubkey2 == activeMasternode.pubKeyMasternode) return true; + // incorrect ping or its sigTime + if(lastPing == CMasternodePing() || !lastPing.CheckAndUpdate(nDoS, false, true)) + return false; + // search existing Masternode list CMasternode* pmn = mnodeman.Find(vin); @@ -569,8 +579,20 @@ bool CMasternodeBroadcast::Sign(CKey& keyCollateralAddress) return false; } + return true; +} + +bool CMasternodeBroadcast::VerifySignature() +{ + std::string errorMessage; + + std::string vchPubKey(pubkey.begin(), pubkey.end()); + std::string vchPubKey2(pubkey2.begin(), pubkey2.end()); + + std::string strMessage = addr.ToString() + boost::lexical_cast(sigTime) + vchPubKey + vchPubKey2 + boost::lexical_cast(protocolVersion); + if(!darkSendSigner.VerifyMessage(pubkey, sig, strMessage, errorMessage)) { - LogPrintf("CMasternodeBroadcast::Sign() - Error: %s\n", errorMessage); + LogPrintf("CMasternodeBroadcast::VerifySignature() - Error: %s\n", errorMessage); return false; } @@ -615,7 +637,20 @@ bool CMasternodePing::Sign(CKey& keyMasternode, CPubKey& pubKeyMasternode) return true; } -bool CMasternodePing::CheckAndUpdate(int& nDos, bool fRequireEnabled) +bool CMasternodePing::VerifySignature(CPubKey& pubKeyMasternode, int &nDos) { + std::string strMessage = vin.ToString() + blockHash.ToString() + boost::lexical_cast(sigTime); + std::string errorMessage = ""; + + if(!darkSendSigner.VerifyMessage(pubKeyMasternode, vchSig, strMessage, errorMessage)) + { + LogPrintf("CMasternodePing::VerifySignature - Got bad Masternode ping signature %s Error: %s\n", vin.ToString(), errorMessage); + nDos = 33; + return false; + } + return true; +} + +bool CMasternodePing::CheckAndUpdate(int& nDos, bool fRequireEnabled, bool fCheckSigTimeOnly) { if (sigTime > GetAdjustedTime() + 60 * 60) { LogPrintf("CMasternodePing::CheckAndUpdate - Signature rejected, too far into the future %s\n", vin.ToString()); @@ -629,6 +664,12 @@ bool CMasternodePing::CheckAndUpdate(int& nDos, bool fRequireEnabled) return false; } + if(fCheckSigTimeOnly) { + CMasternode* pmn = mnodeman.Find(vin); + if(pmn) return VerifySignature(pmn->pubkey2, nDos); + return true; + } + LogPrint("masternode", "CMasternodePing::CheckAndUpdate - New Ping - %s - %s - %lli\n", GetHash().ToString(), blockHash.ToString(), sigTime); // see if we have this Masternode @@ -642,15 +683,8 @@ bool CMasternodePing::CheckAndUpdate(int& nDos, bool fRequireEnabled) // last ping was more then MASTERNODE_MIN_MNP_SECONDS-60 ago comparing to this one if(!pmn->IsPingedWithin(MASTERNODE_MIN_MNP_SECONDS - 60, sigTime)) { - std::string strMessage = vin.ToString() + blockHash.ToString() + boost::lexical_cast(sigTime); - - std::string errorMessage = ""; - if(!darkSendSigner.VerifyMessage(pmn->pubkey2, vchSig, strMessage, errorMessage)) - { - LogPrintf("CMasternodePing::CheckAndUpdate - Got bad Masternode address signature %s\n", vin.ToString()); - nDos = 33; + if(!VerifySignature(pmn->pubkey2, nDos)) return false; - } BlockMap::iterator mi = mapBlockIndex.find(blockHash); if (mi != mapBlockIndex.end() && (*mi).second) diff --git a/src/masternode.h b/src/masternode.h index da97d0e7e560e..7219ea0a5014c 100644 --- a/src/masternode.h +++ b/src/masternode.h @@ -58,8 +58,9 @@ class CMasternodePing READWRITE(vchSig); } - bool CheckAndUpdate(int& nDos, bool fRequireEnabled = true); + bool CheckAndUpdate(int& nDos, bool fRequireEnabled = true, bool fCheckSigTimeOnly = false); bool Sign(CKey& keyMasternode, CPubKey& pubKeyMasternode); + bool VerifySignature(CPubKey& pubKeyMasternode, int &nDos); void Relay(); uint256 GetHash(){ @@ -286,6 +287,7 @@ class CMasternodeBroadcast : public CMasternode bool CheckAndUpdate(int& nDoS); bool CheckInputsAndAdd(int& nDos); bool Sign(CKey& keyCollateralAddress); + bool VerifySignature(); void Relay(); ADD_SERIALIZE_METHODS; diff --git a/src/masternodeman.cpp b/src/masternodeman.cpp index aeab17e28d2d9..580cac75a9a24 100644 --- a/src/masternodeman.cpp +++ b/src/masternodeman.cpp @@ -686,41 +686,12 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData CMasternodeBroadcast mnb; vRecv >> mnb; - if(mapSeenMasternodeBroadcast.count(mnb.GetHash())) { //seen - masternodeSync.AddedMasternodeList(mnb.GetHash()); - return; - } - mapSeenMasternodeBroadcast.insert(make_pair(mnb.GetHash(), mnb)); - int nDoS = 0; - if(!mnb.CheckAndUpdate(nDoS)){ - - if(nDoS > 0) - Misbehaving(pfrom->GetId(), nDoS); - - //failed - return; - } - - // make sure the vout that was signed is related to the transaction that spawned the Masternode - // - this is expensive, so it's only done once per Masternode - if(!darkSendSigner.IsVinAssociatedWithPubkey(mnb.vin, mnb.pubkey)) { - LogPrintf("mnb - Got mismatched pubkey and vin\n"); - Misbehaving(pfrom->GetId(), 33); - return; - } - - // make sure it's still unspent - // - this is checked later by .check() in many places and by ThreadCheckDarkSendPool() - if(mnb.CheckInputsAndAdd(nDoS)) { - // use this as a peer - addrman.Add(CAddress(mnb.addr), pfrom->addr, 2*60*60); - masternodeSync.AddedMasternodeList(mnb.GetHash()); + if (CheckMnbAndUpdateMasternodeList(mnb, nDoS)) { + // use announced Masternode as a peer + addrman.Add(CAddress(mnb.addr), pfrom->addr, 2*60*60); } else { - LogPrintf("mnb - Rejected Masternode entry %s\n", mnb.addr.ToString()); - - if (nDoS > 0) - Misbehaving(pfrom->GetId(), nDoS); + if(nDoS > 0) Misbehaving(pfrom->GetId(), nDoS); } } @@ -833,3 +804,57 @@ std::string CMasternodeMan::ToString() const return info.str(); } + +void CMasternodeMan::UpdateMasternodeList(CMasternodeBroadcast mnb) { + mapSeenMasternodePing.insert(make_pair(mnb.lastPing.GetHash(), mnb.lastPing)); + mapSeenMasternodeBroadcast.insert(make_pair(mnb.GetHash(), mnb)); + masternodeSync.AddedMasternodeList(mnb.GetHash()); + + LogPrintf("CMasternodeMan::UpdateMasternodeList() - addr: %s\n vin: %s\n", mnb.addr.ToString(), mnb.vin.ToString()); + + CMasternode* pmn = Find(mnb.vin); + if(pmn == NULL) + { + CMasternode mn(mnb); + Add(mn); + } else { + pmn->UpdateFromNewBroadcast(mnb); + } +} + +bool CMasternodeMan::CheckMnbAndUpdateMasternodeList(CMasternodeBroadcast mnb, int& nDos) { + nDos = 0; + LogPrint("masternode", "CMasternodeMan::CheckMnbAndUpdateMasternodeList - Masternode broadcast, vin: %s\n", mnb.vin.ToString()); + + if(mapSeenMasternodeBroadcast.count(mnb.GetHash())) { //seen + masternodeSync.AddedMasternodeList(mnb.GetHash()); + return true; + } + mapSeenMasternodeBroadcast.insert(make_pair(mnb.GetHash(), mnb)); + + LogPrint("masternode", "CMasternodeMan::CheckMnbAndUpdateMasternodeList - Masternode broadcast, vin: %s new\n", mnb.vin.ToString()); + + if(!mnb.CheckAndUpdate(nDos)){ + LogPrint("masternode", "CMasternodeMan::CheckMnbAndUpdateMasternodeList - Masternode broadcast, vin: %s CheckAndUpdate failed\n", mnb.vin.ToString()); + return false; + } + + // make sure the vout that was signed is related to the transaction that spawned the Masternode + // - this is expensive, so it's only done once per Masternode + if(!darkSendSigner.IsVinAssociatedWithPubkey(mnb.vin, mnb.pubkey)) { + LogPrintf("CMasternodeMan::CheckMnbAndUpdateMasternodeList - Got mismatched pubkey and vin\n"); + nDos = 33; + return false; + } + + // make sure it's still unspent + // - this is checked later by .check() in many places and by ThreadCheckDarkSendPool() + if(mnb.CheckInputsAndAdd(nDos)) { + masternodeSync.AddedMasternodeList(mnb.GetHash()); + } else { + LogPrintf("CMasternodeMan::CheckMnbAndUpdateMasternodeList - Rejected Masternode entry %s\n", mnb.addr.ToString()); + return false; + } + + return true; +} \ No newline at end of file diff --git a/src/masternodeman.h b/src/masternodeman.h index 033f197c92003..b743af1c1f1d9 100644 --- a/src/masternodeman.h +++ b/src/masternodeman.h @@ -141,6 +141,11 @@ class CMasternodeMan void Remove(CTxIn vin); + /// Update masternode list and maps using provided CMasternodeBroadcast + void UpdateMasternodeList(CMasternodeBroadcast mnb); + /// Perform complete check and only then update list and maps + bool CheckMnbAndUpdateMasternodeList(CMasternodeBroadcast mnb, int& nDos); + }; #endif diff --git a/src/rpcmasternode.cpp b/src/rpcmasternode.cpp index ce066a4cd736f..348e4105f77e1 100644 --- a/src/rpcmasternode.cpp +++ b/src/rpcmasternode.cpp @@ -306,11 +306,15 @@ Value masternode(const Array& params, bool fHelp) if(mne.getAlias() == alias) { found = true; std::string errorMessage; + CMasternodeBroadcast mnb; - bool result = activeMasternode.Register(mne.getIp(), mne.getPrivKey(), mne.getTxHash(), mne.getOutputIndex(), errorMessage); + bool result = activeMasternode.CreateBroadcast(mne.getIp(), mne.getPrivKey(), mne.getTxHash(), mne.getOutputIndex(), errorMessage, mnb); statusObj.push_back(Pair("result", result ? "successful" : "failed")); - if(!result) { + if(result) { + mnodeman.UpdateMasternodeList(mnb); + mnb.Relay(); + } else { statusObj.push_back(Pair("errorMessage", errorMessage)); } break; @@ -363,11 +367,12 @@ Value masternode(const Array& params, bool fHelp) CTxIn vin = CTxIn(uint256(mne.getTxHash()), uint32_t(atoi(mne.getOutputIndex().c_str()))); CMasternode *pmn = mnodeman.Find(vin); + CMasternodeBroadcast mnb; if(strCommand == "start-missing" && pmn) continue; if(strCommand == "start-disabled" && pmn && pmn->IsEnabled()) continue; - bool result = activeMasternode.Register(mne.getIp(), mne.getPrivKey(), mne.getTxHash(), mne.getOutputIndex(), errorMessage); + bool result = activeMasternode.CreateBroadcast(mne.getIp(), mne.getPrivKey(), mne.getTxHash(), mne.getOutputIndex(), errorMessage, mnb); Object statusObj; statusObj.push_back(Pair("alias", mne.getAlias())); @@ -375,6 +380,8 @@ Value masternode(const Array& params, bool fHelp) if(result) { successful++; + mnodeman.UpdateMasternodeList(mnb); + mnb.Relay(); } else { failed++; statusObj.push_back(Pair("errorMessage", errorMessage)); @@ -610,3 +617,275 @@ Value masternodelist(const Array& params, bool fHelp) return obj; } + +bool DecodeHexVecMnb(std::vector& vecMnb, std::string strHexMnb) { + + if (!IsHex(strHexMnb)) + return false; + + vector mnbData(ParseHex(strHexMnb)); + CDataStream ssData(mnbData, SER_NETWORK, PROTOCOL_VERSION); + try { + ssData >> vecMnb; + } + catch (const std::exception&) { + return false; + } + + return true; +} + +Value masternodebroadcast(const Array& params, bool fHelp) +{ + string strCommand; + if (params.size() >= 1) + strCommand = params[0].get_str(); + + if (fHelp || + (strCommand != "create-alias" && strCommand != "create-all" && strCommand != "decode" && strCommand != "relay")) + throw runtime_error( + "masternodebroadcast \"command\"... ( \"passphrase\" )\n" + "Set of commands to create and relay masternode broadcast messages\n" + "\nArguments:\n" + "1. \"command\" (string or set of strings, required) The command to execute\n" + "2. \"passphrase\" (string, optional) The wallet passphrase\n" + "\nAvailable commands:\n" + " create-alias - Create single remote masternode broadcast message by assigned alias configured in masternode.conf\n" + " create-all - Create remote masternode broadcast messages for all masternodes configured in masternode.conf\n" + " decode - Decode masternode broadcast message\n" + " relay - Relay masternode broadcast message to the network\n" + + HelpRequiringPassphrase()); + + if (strCommand == "create-alias") + { + // wait for reindex and/or import to finish + if (fImporting || fReindex) + throw JSONRPCError(RPC_INTERNAL_ERROR, "Wait for reindex and/or import to finish"); + + if (params.size() < 2) + throw JSONRPCError(RPC_INVALID_PARAMETER, "Command needs at least 2 parameters"); + + std::string alias = params[1].get_str(); + + if(pwalletMain->IsLocked()) { + SecureString strWalletPass; + strWalletPass.reserve(100); + + if (params.size() == 3){ + strWalletPass = params[2].get_str().c_str(); + } else { + throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Your wallet is locked, passphrase is required"); + } + + if(!pwalletMain->Unlock(strWalletPass)){ + throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "The wallet passphrase entered was incorrect"); + } + } + + bool found = false; + + Object statusObj; + std::vector vecMnb; + + statusObj.push_back(Pair("alias", alias)); + + BOOST_FOREACH(CMasternodeConfig::CMasternodeEntry mne, masternodeConfig.getEntries()) { + if(mne.getAlias() == alias) { + found = true; + std::string errorMessage; + CMasternodeBroadcast mnb; + + bool result = activeMasternode.CreateBroadcast(mne.getIp(), mne.getPrivKey(), mne.getTxHash(), mne.getOutputIndex(), errorMessage, mnb, true); + + statusObj.push_back(Pair("result", result ? "successful" : "failed")); + if(result) { + vecMnb.push_back(mnb); + CDataStream ssVecMnb(SER_NETWORK, PROTOCOL_VERSION); + ssVecMnb << vecMnb; + statusObj.push_back(Pair("hex", HexStr(ssVecMnb.begin(), ssVecMnb.end()))); + } else { + statusObj.push_back(Pair("errorMessage", errorMessage)); + } + break; + } + } + + if(!found) { + statusObj.push_back(Pair("result", "not found")); + statusObj.push_back(Pair("errorMessage", "Could not find alias in config. Verify with list-conf.")); + } + + pwalletMain->Lock(); + return statusObj; + + } + + if (strCommand == "create-all") + { + // wait for reindex and/or import to finish + if (fImporting || fReindex) + throw JSONRPCError(RPC_INTERNAL_ERROR, "Wait for reindex and/or import to finish"); + + if(pwalletMain->IsLocked()) { + SecureString strWalletPass; + strWalletPass.reserve(100); + + if (params.size() == 2){ + strWalletPass = params[1].get_str().c_str(); + } else { + throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Your wallet is locked, passphrase is required"); + } + + if(!pwalletMain->Unlock(strWalletPass)){ + throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "The wallet passphrase entered was incorrect"); + } + } + + std::vector mnEntries; + mnEntries = masternodeConfig.getEntries(); + + int successful = 0; + int failed = 0; + + Object resultsObj; + std::vector vecMnb; + + BOOST_FOREACH(CMasternodeConfig::CMasternodeEntry mne, masternodeConfig.getEntries()) { + std::string errorMessage; + + CTxIn vin = CTxIn(uint256(mne.getTxHash()), uint32_t(atoi(mne.getOutputIndex().c_str()))); + CMasternodeBroadcast mnb; + + bool result = activeMasternode.CreateBroadcast(mne.getIp(), mne.getPrivKey(), mne.getTxHash(), mne.getOutputIndex(), errorMessage, mnb, true); + + Object statusObj; + statusObj.push_back(Pair("alias", mne.getAlias())); + statusObj.push_back(Pair("result", result ? "successful" : "failed")); + + if(result) { + successful++; + vecMnb.push_back(mnb); + } else { + failed++; + statusObj.push_back(Pair("errorMessage", errorMessage)); + } + + resultsObj.push_back(Pair("status", statusObj)); + } + pwalletMain->Lock(); + + CDataStream ssVecMnb(SER_NETWORK, PROTOCOL_VERSION); + ssVecMnb << vecMnb; + Object returnObj; + returnObj.push_back(Pair("overall", strprintf("Successfully created broadcast messages for %d masternodes, failed to create %d, total %d", successful, failed, successful + failed))); + returnObj.push_back(Pair("detail", resultsObj)); + returnObj.push_back(Pair("hex", HexStr(ssVecMnb.begin(), ssVecMnb.end()))); + + return returnObj; + } + + if (strCommand == "decode") + { + if (params.size() != 2) + throw JSONRPCError(RPC_INVALID_PARAMETER, "Correct usage is 'masternodebroadcast decode \"hexstring\"'"); + + int successful = 0; + int failed = 0; + + std::vector vecMnb; + Object returnObj; + + if (!DecodeHexVecMnb(vecMnb, params[1].get_str())) + throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Masternode broadcast message decode failed"); + + BOOST_FOREACH(CMasternodeBroadcast& mnb, vecMnb) { + Object resultObj; + + if(mnb.VerifySignature()) { + successful++; + resultObj.push_back(Pair("vin", mnb.vin.ToString())); + resultObj.push_back(Pair("addr", mnb.addr.ToString())); + resultObj.push_back(Pair("pubkey", CBitcoinAddress(mnb.pubkey.GetID()).ToString())); + resultObj.push_back(Pair("pubkey2", CBitcoinAddress(mnb.pubkey2.GetID()).ToString())); + resultObj.push_back(Pair("vchSig", EncodeBase64(&mnb.sig[0], mnb.sig.size()))); + resultObj.push_back(Pair("sigTime", mnb.sigTime)); + resultObj.push_back(Pair("protocolVersion", mnb.protocolVersion)); + resultObj.push_back(Pair("nLastDsq", mnb.nLastDsq)); + + Object lastPingObj; + lastPingObj.push_back(Pair("vin", mnb.lastPing.vin.ToString())); + lastPingObj.push_back(Pair("blockHash", mnb.lastPing.blockHash.ToString())); + lastPingObj.push_back(Pair("sigTime", mnb.lastPing.sigTime)); + lastPingObj.push_back(Pair("vchSig", EncodeBase64(&mnb.lastPing.vchSig[0], mnb.lastPing.vchSig.size()))); + + resultObj.push_back(Pair("lastPing", lastPingObj)); + } else { + failed++; + resultObj.push_back(Pair("errorMessage", "Masternode broadcast signature verification failed")); + } + + returnObj.push_back(Pair(mnb.GetHash().ToString(), resultObj)); + } + + returnObj.push_back(Pair("overall", strprintf("Successfully decoded broadcast messages for %d masternodes, failed to decode %d, total %d", successful, failed, successful + failed))); + + return returnObj; + } + + if (strCommand == "relay") + { + if (params.size() < 2 || params.size() > 3) + throw JSONRPCError(RPC_INVALID_PARAMETER, "masternodebroadcast relay \"hexstring\" ( fast )\n" + "\nArguments:\n" + "1. \"hex\" (string, required) Broadcast messages hex string\n" + "2. fast (string, optional) If none, using safe method\n"); + + int successful = 0; + int failed = 0; + bool fSafe = params.size() == 2; + + std::vector vecMnb; + Object returnObj; + + if (!DecodeHexVecMnb(vecMnb, params[1].get_str())) + throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Masternode broadcast message decode failed"); + + // verify all signatures first, bailout if any of them broken + BOOST_FOREACH(CMasternodeBroadcast& mnb, vecMnb) { + Object resultObj; + + resultObj.push_back(Pair("vin", mnb.vin.ToString())); + resultObj.push_back(Pair("addr", mnb.addr.ToString())); + + int nDos = 0; + bool fResult; + if (mnb.VerifySignature()) { + if (fSafe) { + fResult = mnodeman.CheckMnbAndUpdateMasternodeList(mnb, nDos); + } else { + mnodeman.UpdateMasternodeList(mnb); + mnb.Relay(); + fResult = true; + } + } else fResult = false; + + if(fResult) { + successful++; + mnodeman.UpdateMasternodeList(mnb); + mnb.Relay(); + resultObj.push_back(Pair(mnb.GetHash().ToString(), "successful")); + } else { + failed++; + resultObj.push_back(Pair("errorMessage", "Masternode broadcast signature verification failed")); + } + + returnObj.push_back(Pair(mnb.GetHash().ToString(), resultObj)); + } + + returnObj.push_back(Pair("overall", strprintf("Successfully relayed broadcast messages for %d masternodes, failed to relay %d, total %d", successful, failed, successful + failed))); + + return returnObj; + } + + return Value::null; +} diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index d5eb1efd33460..9df0f1fad3383 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -311,6 +311,7 @@ static const CRPCCommand vRPCCommands[] = /* Dash features */ { "dash", "masternode", &masternode, true, true, false }, { "dash", "masternodelist", &masternodelist, true, true, false }, + { "dash", "masternodebroadcast", &masternodebroadcast, true, true, false }, { "dash", "mnbudget", &mnbudget, true, true, false }, { "dash", "mnbudgetvoteraw", &mnbudgetvoteraw, true, true, false }, { "dash", "mnfinalbudget", &mnfinalbudget, true, true, false }, diff --git a/src/rpcserver.h b/src/rpcserver.h index ff8d556173f6d..228fd1875ed78 100644 --- a/src/rpcserver.h +++ b/src/rpcserver.h @@ -231,6 +231,7 @@ extern json_spirit::Value darksend(const json_spirit::Array& params, bool fHelp) extern json_spirit::Value spork(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value masternode(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value masternodelist(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value masternodebroadcast(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value mnbudget(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value mnbudgetvoteraw(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value mnfinalbudget(const json_spirit::Array& params, bool fHelp);