From 26fed436034179492f0c98e6aa61836b4e059767 Mon Sep 17 00:00:00 2001 From: UdjinM6 Date: Tue, 14 Jul 2015 08:25:07 +0300 Subject: [PATCH 1/4] Major masternode broadcast/ping changes (incompatible with prev version, proto bump required): - Do not rely on local lastTimeSeen and requested fRequested anymore. Use last know (signed) ping instead and base all logic on that. Should reduce mn list difference between nodes. - Rework CActiveMasternode accordingly along with states, errorMessages, rpc etc. - Clean some related code, move parts from public to private - drop c_str in LogPrintf that were related to this functionality (todo: drop it for LogPrintf everywhere else) --- src/activemasternode.cpp | 161 ++++++++++++++++++---------------- src/activemasternode.h | 28 +++--- src/darksend.cpp | 2 - src/darksend.h | 3 + src/main.cpp | 4 - src/masternode.cpp | 180 +++++++++++++++++++-------------------- src/masternode.h | 173 ++++++++++++++++++++----------------- src/masternodeman.cpp | 61 ++++++------- src/masternodeman.h | 7 +- src/miner.cpp | 1 - src/rpcmasternode.cpp | 36 +++----- 11 files changed, 335 insertions(+), 321 deletions(-) diff --git a/src/activemasternode.cpp b/src/activemasternode.cpp index 392c674771..6bf5d43f1d 100644 --- a/src/activemasternode.cpp +++ b/src/activemasternode.cpp @@ -17,63 +17,64 @@ void CActiveMasternode::ManageStatus() if (fDebug) LogPrintf("CActiveMasternode::ManageStatus() - Begin\n"); - //need correct adjusted time to send ping - bool fIsInitialDownload = IsInitialBlockDownload(); - if(fIsInitialDownload) { + //need correct blocks to send ping + if(IsInitialBlockDownload()) { status = MASTERNODE_SYNC_IN_PROCESS; LogPrintf("CActiveMasternode::ManageStatus() - Sync in progress. Must wait until sync is complete to start Masternode.\n"); return; } - if(status == MASTERNODE_INPUT_TOO_NEW || status == MASTERNODE_NOT_CAPABLE || status == MASTERNODE_SYNC_IN_PROCESS){ - status = MASTERNODE_NOT_PROCESSED; + if(status == MASTERNODE_INITIAL || status == MASTERNODE_SYNC_IN_PROCESS) { + CMasternode *pmn; + pmn = mnodeman.Find(pubKeyMasternode); + if(pmn != NULL) { + pmn->Check(); + if(pmn->IsEnabled()) EnableHotColdMasterNode(pmn->vin, pmn->addr); + } } - if(status == MASTERNODE_NOT_PROCESSED) { + if(status != MASTERNODE_STARTED) { + + // Set defaults + status = MASTERNODE_NOT_CAPABLE; + notCapableReason = ""; + if(strMasterNodeAddr.empty()) { if(!GetLocal(service)) { notCapableReason = "Can't detect external address. Please use the Masternodeaddr configuration option."; - status = MASTERNODE_NOT_CAPABLE; - LogPrintf("CActiveMasternode::ManageStatus() - not capable: %s\n", notCapableReason.c_str()); + LogPrintf("CActiveMasternode::ManageStatus() - not capable: %s\n", notCapableReason); return; } } else { service = CService(strMasterNodeAddr); } - LogPrintf("CActiveMasternode::ManageStatus() - Checking inbound connection to '%s'\n", service.ToString().c_str()); + LogPrintf("CActiveMasternode::ManageStatus() - Checking inbound connection to '%s'\n", service.ToString()); if(Params().NetworkID() == CBaseChainParams::MAIN) { if(service.GetPort() != 9999) { notCapableReason = "Invalid port: " + boost::lexical_cast(service.GetPort()) + " - only 9999 is supported on mainnet."; - status = MASTERNODE_NOT_CAPABLE; - LogPrintf("CActiveMasternode::ManageStatus() - not capable: %s\n", notCapableReason.c_str()); + LogPrintf("CActiveMasternode::ManageStatus() - not capable: %s\n", notCapableReason); return; } } else if(service.GetPort() == 9999) { notCapableReason = "Invalid port: " + boost::lexical_cast(service.GetPort()) + " - 9999 is only supported on mainnet."; - status = MASTERNODE_NOT_CAPABLE; - LogPrintf("CActiveMasternode::ManageStatus() - not capable: %s\n", notCapableReason.c_str()); + LogPrintf("CActiveMasternode::ManageStatus() - not capable: %s\n", notCapableReason); return; } if(!ConnectNode((CAddress)service, service.ToString().c_str())){ notCapableReason = "Could not connect to " + service.ToString(); - status = MASTERNODE_NOT_CAPABLE; - LogPrintf("CActiveMasternode::ManageStatus() - not capable: %s\n", notCapableReason.c_str()); + LogPrintf("CActiveMasternode::ManageStatus() - not capable: %s\n", notCapableReason); return; } if(pwalletMain->IsLocked()){ notCapableReason = "Wallet is locked."; - status = MASTERNODE_NOT_CAPABLE; - LogPrintf("CActiveMasternode::ManageStatus() - not capable: %s\n", notCapableReason.c_str()); + LogPrintf("CActiveMasternode::ManageStatus() - not capable: %s\n", notCapableReason); return; } - // Set defaults - status = MASTERNODE_NOT_CAPABLE; - notCapableReason = "Unknown. Check debug.log for more information."; // Choose coins to use CPubKey pubKeyCollateralAddress; @@ -84,16 +85,11 @@ void CActiveMasternode::ManageStatus() if(GetInputAge(vin) < MASTERNODE_MIN_CONFIRMATIONS){ notCapableReason = "Input must have least " + boost::lexical_cast(MASTERNODE_MIN_CONFIRMATIONS) + " confirmations - " + boost::lexical_cast(GetInputAge(vin)) + " confirmations"; - LogPrintf("CActiveMasternode::ManageStatus() - %s\n", notCapableReason.c_str()); + LogPrintf("CActiveMasternode::ManageStatus() - %s\n", notCapableReason); status = MASTERNODE_INPUT_TOO_NEW; return; } - LogPrintf("CActiveMasternode::ManageStatus() - Is capable master node!\n"); - - status = MASTERNODE_IS_CAPABLE; - notCapableReason = ""; - pwalletMain->LockCoin(vin.prevout); // send to all nodes @@ -102,31 +98,48 @@ void CActiveMasternode::ManageStatus() if(!darkSendSigner.SetKey(strMasterNodePrivKey, errorMessage, keyMasternode, pubKeyMasternode)) { - LogPrintf("Register::ManageStatus() - Error upon calling SetKey: %s\n", errorMessage.c_str()); + notCapableReason = "Error upon calling SetKey: " + errorMessage; + LogPrintf("Register::ManageStatus() - %s\n", notCapableReason); return; } if(!Register(vin, service, keyCollateralAddress, pubKeyCollateralAddress, keyMasternode, pubKeyMasternode, errorMessage)) { - LogPrintf("CActiveMasternode::ManageStatus() - Error on Register: %s\n", errorMessage.c_str()); + notCapableReason = "Error on Register: " + errorMessage; + LogPrintf("Register::ManageStatus() - %s\n", notCapableReason); + return; } + LogPrintf("CActiveMasternode::ManageStatus() - Is capable master node!\n"); + status = MASTERNODE_STARTED; + return; } else { notCapableReason = "Could not find suitable coins!"; - LogPrintf("CActiveMasternode::ManageStatus() - %s\n", notCapableReason.c_str()); + LogPrintf("CActiveMasternode::ManageStatus() - %s\n", notCapableReason); + return; } } //send to all peers - if(!Mnping(errorMessage)) { - LogPrintf("CActiveMasternode::ManageStatus() - Error on Ping: %s\n", errorMessage.c_str()); + if(!SendMasternodePing(errorMessage)) { + LogPrintf("CActiveMasternode::ManageStatus() - Error on Ping: %s\n", errorMessage); } } -bool CActiveMasternode::Mnping(std::string& errorMessage) { - if(status != MASTERNODE_IS_CAPABLE && status != MASTERNODE_REMOTELY_ENABLED) { +std::string CActiveMasternode::GetStatus() { + switch (status) { + case MASTERNODE_INITIAL: return "node just started, not yet activated"; + case MASTERNODE_SYNC_IN_PROCESS: return "sync in process. Must wait until client is synced to start"; + case MASTERNODE_INPUT_TOO_NEW: return "masternode input must have at least 15 confirmations"; + case MASTERNODE_NOT_CAPABLE: return "not capable masternode: " + notCapableReason; + case MASTERNODE_STARTED: return "masternode successfully started"; + default: return "unknown"; + } +} + +bool CActiveMasternode::SendMasternodePing(std::string& errorMessage) { + if(status != MASTERNODE_STARTED) { errorMessage = "Masternode is not in a running status"; - LogPrintf("CActiveMasternode::Mnping() - Error: %s\n", errorMessage.c_str()); return false; } @@ -135,43 +148,42 @@ bool CActiveMasternode::Mnping(std::string& errorMessage) { if(!darkSendSigner.SetKey(strMasterNodePrivKey, errorMessage, keyMasternode, pubKeyMasternode)) { - LogPrintf("CActiveMasternode::Mnping() - Error upon calling SetKey: %s\n", errorMessage.c_str()); + errorMessage = strprintf("Error upon calling SetKey: %s\n", errorMessage); return false; } - return Mnping(vin, service, keyMasternode, pubKeyMasternode, errorMessage); -} - -bool CActiveMasternode::Mnping(CTxIn vin, CService service, CKey keyMasternode, CPubKey pubKeyMasternode, std::string &retErrorMessage) { - //send to all peers - LogPrintf("CActiveMasternode::Mnping() - RelayMasternodeEntryPing vin = %s\n", vin.ToString().c_str()); + LogPrintf("CActiveMasternode::SendMasternodePing() - Relay Masternode Ping vin = %s\n", vin.ToString()); CMasternodePing mnp(vin); if(!mnp.Sign(keyMasternode, pubKeyMasternode)) { + errorMessage = "Couldn't sign Masternode Ping"; return false; } - // Update Last Seen timestamp in Masternode list + // Update lastPing for our masternode in Masternode list CMasternode* pmn = mnodeman.Find(vin); if(pmn != NULL) { - pmn->UpdateLastSeen(); + if(pmn->IsPingedWithin(MASTERNODE_PING_SECONDS, mnp.sigTime)){ + errorMessage = "Too early to send Masternode Ping"; + return false; + } + + pmn->lastPing = mnp; + mapSeenMasternodePing[mnp.GetHash()] = mnp; + mnp.Relay(); + return true; } else { // Seems like we are trying to send a ping while the Masternode is not registered in the network - retErrorMessage = "Darksend Masternode List doesn't include our Masternode, shutting down Masternode pinging service! " + vin.ToString(); - LogPrintf("CActiveMasternode::Mnping() - Error: %s\n", retErrorMessage.c_str()); + errorMessage = "Darksend Masternode List doesn't include our Masternode, shutting down Masternode pinging service! " + vin.ToString(); status = MASTERNODE_NOT_CAPABLE; - notCapableReason = retErrorMessage; + notCapableReason = errorMessage; return false; } - mapSeenMasternodePing[mnp.GetHash()] = mnp; - mnp.Relay(); - - return true; } bool CActiveMasternode::Register(std::string strService, std::string strKeyMasternode, std::string txHash, std::string strOutputIndex, std::string& errorMessage) { @@ -183,13 +195,13 @@ bool CActiveMasternode::Register(std::string strService, std::string strKeyMaste if(!darkSendSigner.SetKey(strKeyMasternode, errorMessage, keyMasternode, pubKeyMasternode)) { - LogPrintf("CActiveMasternode::Register() - Error upon calling SetKey: %s\n", errorMessage.c_str()); + LogPrintf("CActiveMasternode::Register() - Error upon calling SetKey: %s\n", errorMessage); return false; } if(!GetMasterNodeVin(vin, pubKeyCollateralAddress, keyCollateralAddress, txHash, strOutputIndex)) { errorMessage = "could not allocate vin"; - LogPrintf("CActiveMasternode::Register() - Error: %s\n", errorMessage.c_str()); + LogPrintf("CActiveMasternode::Register() - Error: %s\n", errorMessage); return false; } @@ -197,32 +209,35 @@ bool CActiveMasternode::Register(std::string strService, std::string strKeyMaste } bool CActiveMasternode::Register(CTxIn vin, CService service, CKey keyCollateralAddress, CPubKey pubKeyCollateralAddress, CKey keyMasternode, CPubKey pubKeyMasternode, std::string &retErrorMessage) { + CMasternodeBroadcast mnb; + CMasternodePing mnp(vin); + if(!mnp.Sign(keyMasternode, pubKeyMasternode)){ + LogPrintf("CActiveMasternode::Register() - Failed to sign ping, vin: %s\n", vin.ToString()); + return false; + } + mapSeenMasternodePing[mnp.GetHash()] = mnp; + + LogPrintf("CActiveMasternode::Register() - Adding to Masternode list service: %s - vin: %s\n", service.ToString(), vin.ToString()); + mnb = CMasternodeBroadcast(service, vin, pubKeyCollateralAddress, pubKeyMasternode, PROTOCOL_VERSION); + mnb.lastPing = mnp; + if(!mnb.Sign(keyCollateralAddress)){ + LogPrintf("CActiveMasternode::Register() - Failed to sign broadcast, vin: %s\n", vin.ToString()); + return false; + } + mapSeenMasternodeBroadcast[mnb.GetHash()] = mnb; + CMasternode* pmn = mnodeman.Find(vin); if(pmn == NULL) { - LogPrintf("CActiveMasternode::Register() - Adding to Masternode list service: %s - vin: %s\n", service.ToString().c_str(), vin.ToString().c_str()); - CMasternodeBroadcast mnb(service, vin, pubKeyCollateralAddress, pubKeyMasternode, PROTOCOL_VERSION); - if(!mnb.Sign(keyCollateralAddress)){ - //send to all peers - LogPrintf("CActiveMasternode::Register() - Failed to sign %s\n", vin.ToString().c_str()); - return false; - } - CMasternode mn(mnb); - mn.UpdateLastSeen(); mnodeman.Add(mn); + } else { + pmn->UpdateFromNewBroadcast(mnb); } - - if(pmn == NULL) pmn = mnodeman.Find(vin); - if(pmn != NULL) - { - CMasternodeBroadcast mnb(*pmn); - mapSeenMasternodeBroadcast[mnb.GetHash()] = mnb; - //send to all peers - LogPrintf("CActiveMasternode::Register() - RelayElectionEntry vin = %s\n", vin.ToString().c_str()); - mnb.Relay(false); - } + //send to all peers + LogPrintf("CActiveMasternode::Register() - RelayElectionEntry vin = %s\n", vin.ToString()); + mnb.Relay(); return true; } @@ -232,8 +247,6 @@ bool CActiveMasternode::GetMasterNodeVin(CTxIn& vin, CPubKey& pubkey, CKey& secr } bool CActiveMasternode::GetMasterNodeVin(CTxIn& vin, CPubKey& pubkey, CKey& secretKey, std::string strTxHash, std::string strOutputIndex) { - CScript pubScript; - // Find possible candidates vector possibleCoins = SelectCoinsMasternode(); COutput *selectedOutput; @@ -340,7 +353,7 @@ bool CActiveMasternode::EnableHotColdMasterNode(CTxIn& newVin, CService& newServ { if(!fMasterNode) return false; - status = MASTERNODE_REMOTELY_ENABLED; + status = MASTERNODE_STARTED; //The values below are needed for signing mnping messages going forward this->vin = newVin; diff --git a/src/activemasternode.h b/src/activemasternode.h index 794166edcc..e2b00afcac 100644 --- a/src/activemasternode.h +++ b/src/activemasternode.h @@ -16,6 +16,20 @@ // Responsible for activating the Masternode and pinging the network class CActiveMasternode { +private: + // critical section to protect the inner data structures + mutable CCriticalSection cs; + + /// 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 &retErrorMessage); + + /// Get 1000DRK input that can be used for the Masternode + bool GetMasterNodeVin(CTxIn& vin, CPubKey& pubkey, CKey& secretKey, std::string strTxHash, std::string strOutputIndex); + bool GetVinFromOutput(COutput out, CTxIn& vin, CPubKey& pubkey, CKey& secretKey); + public: // Initialized by init.cpp // Keys for the main Masternode @@ -30,29 +44,21 @@ public: CActiveMasternode() { - status = MASTERNODE_NOT_PROCESSED; + status = MASTERNODE_INITIAL; } /// Manage status of main Masternode void ManageStatus(); - - /// Ping for main Masternode - bool Mnping(std::string& errorMessage); - /// Ping for any Masternode - bool Mnping(CTxIn vin, CService service, CKey key, CPubKey pubKey, std::string &retErrorMessage); + std::string GetStatus(); /// Register remote Masternode bool Register(std::string strService, std::string strKey, std::string txHash, std::string strOutputIndex, std::string& errorMessage); - /// Register any Masternode - bool Register(CTxIn vin, CService service, CKey key, CPubKey pubKey, CKey keyMasternode, CPubKey pubKeyMasternode, std::string &retErrorMessage); /// Get 1000DRK input that can be used for the Masternode bool GetMasterNodeVin(CTxIn& vin, CPubKey& pubkey, CKey& secretKey); - bool GetMasterNodeVin(CTxIn& vin, CPubKey& pubkey, CKey& secretKey, std::string strTxHash, std::string strOutputIndex); vector SelectCoinsMasternode(); - bool GetVinFromOutput(COutput out, CTxIn& vin, CPubKey& pubkey, CKey& secretKey); - /// Enable hot wallet mode (run a Masternode with no funds) + /// Enable cold wallet mode (run a Masternode with no funds) bool EnableHotColdMasterNode(CTxIn& vin, CService& addr); }; diff --git a/src/darksend.cpp b/src/darksend.cpp index bf2fe8f432..a8e809cec8 100644 --- a/src/darksend.cpp +++ b/src/darksend.cpp @@ -22,8 +22,6 @@ using namespace std; using namespace boost; -CCriticalSection cs_darksend; - // The main object for accessing Darksend CDarksendPool darkSendPool; // A helper object for signing messages from Masternodes diff --git a/src/darksend.h b/src/darksend.h index 066a8c2d8c..b81f9120f0 100644 --- a/src/darksend.h +++ b/src/darksend.h @@ -267,6 +267,9 @@ public: */ class CDarksendPool { +private: + mutable CCriticalSection cs_darksend; + public: enum messages { ERR_ALREADY_HAVE, diff --git a/src/main.cpp b/src/main.cpp index fba87a558a..30f27fd712 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4180,11 +4180,9 @@ void static ProcessGetData(CNode* pfrom) if (!pushed && inv.type == MSG_MASTERNODE_ANNOUNCE) { if(mapSeenMasternodeBroadcast.count(inv.hash)){ - bool fRequested = false; // Requested full masternode list CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); ss.reserve(1000); ss << mapSeenMasternodeBroadcast[inv.hash]; - ss << fRequested; pfrom->PushMessage("mnb", ss); pushed = true; } @@ -4192,11 +4190,9 @@ void static ProcessGetData(CNode* pfrom) if (!pushed && inv.type == MSG_MASTERNODE_PING) { if(mapSeenMasternodePing.count(inv.hash)){ - bool fRequested = false; // Requested full masternode list CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); ss.reserve(1000); ss << mapSeenMasternodePing[inv.hash]; - ss << fRequested; pfrom->PushMessage("mnp", ss); pushed = true; } diff --git a/src/masternode.cpp b/src/masternode.cpp index ccfddb8fe6..9487fd3327 100644 --- a/src/masternode.cpp +++ b/src/masternode.cpp @@ -73,8 +73,7 @@ CMasternode::CMasternode() sig = std::vector(); activeState = MASTERNODE_ENABLED; sigTime = GetAdjustedTime(); - lastMnping = 0; - lastTimeSeen = 0; + lastPing = CMasternodePing(); cacheInputAge = 0; cacheInputAgeBlock = 0; unitTest = false; @@ -96,8 +95,7 @@ CMasternode::CMasternode(const CMasternode& other) sig = other.sig; activeState = other.activeState; sigTime = other.sigTime; - lastMnping = other.lastMnping; - lastTimeSeen = other.lastTimeSeen; + lastPing = other.lastPing; cacheInputAge = other.cacheInputAge; cacheInputAgeBlock = other.cacheInputAgeBlock; unitTest = other.unitTest; @@ -109,29 +107,6 @@ CMasternode::CMasternode(const CMasternode& other) nVotedTimes = other.nVotedTimes; } -CMasternode::CMasternode(CService newAddr, CTxIn newVin, CPubKey newPubkey, std::vector newSig, int64_t newSigTime, CPubKey newPubkey2, int protocolVersionIn) -{ - LOCK(cs); - vin = newVin; - addr = newAddr; - pubkey = newPubkey; - pubkey2 = newPubkey2; - sig = newSig; - activeState = MASTERNODE_ENABLED; - sigTime = newSigTime; - lastMnping = 0; - lastTimeSeen = 0; - cacheInputAge = 0; - cacheInputAgeBlock = 0; - unitTest = false; - allowFreeTx = true; - protocolVersion = protocolVersionIn; - nLastDsq = 0; - nScanningErrorCount = 0; - nLastScanningErrorBlockHeight = 0; - nVotedTimes = 0; -} - CMasternode::CMasternode(const CMasternodeBroadcast& mnb) { LOCK(cs); @@ -142,8 +117,7 @@ CMasternode::CMasternode(const CMasternodeBroadcast& mnb) sig = mnb.sig; activeState = MASTERNODE_ENABLED; sigTime = mnb.sigTime; - lastMnping = 0; - lastTimeSeen = 0; + lastPing = mnb.lastPing; cacheInputAge = 0; cacheInputAgeBlock = 0; unitTest = false; @@ -165,6 +139,11 @@ void CMasternode::UpdateFromNewBroadcast(CMasternodeBroadcast& mnb) sig = mnb.sig; protocolVersion = mnb.protocolVersion; addr = mnb.addr; + int nDoS = 0; + if(mnb.lastPing == CMasternodePing() || (mnb.lastPing != CMasternodePing() && mnb.lastPing.CheckAndUpdate(nDoS))) { + lastPing = mnb.lastPing; + mapSeenMasternodePing[lastPing.GetHash()] = lastPing; + } } // @@ -201,12 +180,12 @@ void CMasternode::Check() if(activeState == MASTERNODE_VIN_SPENT) return; - if(!UpdatedWithin(MASTERNODE_REMOVAL_SECONDS)){ + if(!IsPingedWithin(MASTERNODE_REMOVAL_SECONDS)){ activeState = MASTERNODE_REMOVE; return; } - if(!UpdatedWithin(MASTERNODE_EXPIRATION_SECONDS)){ + if(!IsPingedWithin(MASTERNODE_EXPIRATION_SECONDS)){ activeState = MASTERNODE_EXPIRED; return; } @@ -260,8 +239,7 @@ CMasternodeBroadcast::CMasternodeBroadcast() sig = std::vector(); activeState = MASTERNODE_ENABLED; sigTime = GetAdjustedTime(); - lastMnping = 0; - lastTimeSeen = 0; + lastPing = CMasternodePing(); cacheInputAge = 0; cacheInputAgeBlock = 0; unitTest = false; @@ -280,8 +258,7 @@ CMasternodeBroadcast::CMasternodeBroadcast(CService newAddr, CTxIn newVin, CPubK sig = std::vector(); activeState = MASTERNODE_ENABLED; sigTime = GetAdjustedTime(); - lastMnping = 0; - lastTimeSeen = 0; + lastPing = CMasternodePing(); cacheInputAge = 0; cacheInputAgeBlock = 0; unitTest = false; @@ -292,32 +269,32 @@ CMasternodeBroadcast::CMasternodeBroadcast(CService newAddr, CTxIn newVin, CPubK nLastScanningErrorBlockHeight = 0; } -CMasternodeBroadcast::CMasternodeBroadcast(const CMasternode& other) +CMasternodeBroadcast::CMasternodeBroadcast(const CMasternode& mn) { - vin = other.vin; - addr = other.addr; - pubkey = other.pubkey; - pubkey2 = other.pubkey2; - sig = other.sig; - activeState = other.activeState; - sigTime = other.sigTime; - lastMnping = other.lastMnping; - lastTimeSeen = other.lastTimeSeen; - cacheInputAge = other.cacheInputAge; - cacheInputAgeBlock = other.cacheInputAgeBlock; - unitTest = other.unitTest; - allowFreeTx = other.allowFreeTx; - protocolVersion = other.protocolVersion; - nLastDsq = other.nLastDsq; - nScanningErrorCount = other.nScanningErrorCount; - nLastScanningErrorBlockHeight = other.nLastScanningErrorBlockHeight; + vin = mn.vin; + addr = mn.addr; + pubkey = mn.pubkey; + pubkey2 = mn.pubkey2; + sig = mn.sig; + activeState = mn.activeState; + sigTime = mn.sigTime; + lastPing = mn.lastPing; + cacheInputAge = mn.cacheInputAge; + cacheInputAgeBlock = mn.cacheInputAgeBlock; + unitTest = mn.unitTest; + allowFreeTx = mn.allowFreeTx; + protocolVersion = mn.protocolVersion; + nLastDsq = mn.nLastDsq; + nScanningErrorCount = mn.nScanningErrorCount; + nLastScanningErrorBlockHeight = mn.nLastScanningErrorBlockHeight; } -bool CMasternodeBroadcast::CheckAndUpdate(int& nDos, bool fRequested) +bool CMasternodeBroadcast::CheckAndUpdate(int& nDos) { // make sure signature isn't in the future (past is OK) if (sigTime > GetAdjustedTime() + 60 * 60) { - LogPrintf("mnb - Signature rejected, too far into the future %s\n", vin.ToString().c_str()); + LogPrintf("mnb - Signature rejected, too far into the future %s\n", vin.ToString()); + nDos = 1; return false; } @@ -367,35 +344,39 @@ bool CMasternodeBroadcast::CheckAndUpdate(int& nDos, bool fRequested) //search existing Masternode list, this is where we update existing Masternodes with new mnb broadcasts CMasternode* pmn = mnodeman.Find(vin); - // if we are masternode but with undefined vin and this mnb is ours (matches our Masternode privkey) then just skip this part - if(pmn != NULL && !(fMasterNode && activeMasternode.vin == CTxIn() && pubkey2 == activeMasternode.pubKeyMasternode)) - { - // if Requested, we don't want to update this info - if(fRequested) { Relay(false); return true;} + // no such masternode or it's not enabled already, nothing to update + if(pmn == NULL || (pmn != NULL && !pmn->IsEnabled())) return true; - // mn.pubkey = pubkey, IsVinAssociatedWithPubkey is validated once below, - // after that they just need to match - if(pmn->pubkey == pubkey && !pmn->UpdatedWithin(MASTERNODE_MIN_MNB_SECONDS)){ - pmn->UpdateLastSeen(); - - if(pmn->sigTime < sigTime){ //take the newest entry - LogPrintf("mnb - Got updated entry for %s\n", addr.ToString().c_str()); - - pmn->UpdateFromNewBroadcast((*this)); - - pmn->Check(); - if(pmn->IsEnabled()) { - Relay(fRequested); - } - } - } + // 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)) { + //take the newest entry + LogPrintf("mnb - Got updated entry for %s\n", addr.ToString().c_str()); + pmn->UpdateFromNewBroadcast((*this)); + pmn->Check(); + if(pmn->IsEnabled()) Relay(); } return true; } -bool CMasternodeBroadcast::CheckInputsAndAdd(int& nDoS, bool fRequested) +bool CMasternodeBroadcast::CheckInputsAndAdd(int& nDoS) { + // we are a masternode with the same vin (i.e. already activated) and this mnb is ours (matches our Masternode privkey) + // so nothing to do here for us + if(fMasterNode && vin.prevout == activeMasternode.vin.prevout && pubkey2 == activeMasternode.pubKeyMasternode) + return true; + + // search existing Masternode list + CMasternode* pmn = mnodeman.Find(vin); + + if(pmn != NULL) { + // nothing to do here if we already know about this masternode and it's enabled + if(pmn->IsEnabled()) return true; + // if it's not enabled, remove old MN first and continue + else mnodeman.Remove(pmn->vin); + } + CValidationState state; CMutableTransaction tx = CMutableTransaction(); CTxOut vout = CTxOut(999.99*COIN, darkSendPool.collateralPubKey); @@ -427,9 +408,8 @@ bool CMasternodeBroadcast::CheckInputsAndAdd(int& nDoS, bool fRequested) } } - // add our Masternode - CMasternode mn((*this)); - mn.UpdateLastSeen(lastTimeSeen); + LogPrintf("mnb - Got NEW Masternode entry %s %s\n", addr.ToString(), vin.ToString()); + CMasternode mn(*this); mnodeman.Add(mn); // if it matches our Masternode privkey, then we've been remotely activated @@ -440,7 +420,7 @@ bool CMasternodeBroadcast::CheckInputsAndAdd(int& nDoS, bool fRequested) bool isLocal = addr.IsRFC1918() || addr.IsLocal(); if(Params().NetworkID() == CBaseChainParams::REGTEST) isLocal = false; - if(!fRequested && !isLocal) Relay(fRequested); + if(!isLocal) Relay(); return true; } else { @@ -451,7 +431,7 @@ bool CMasternodeBroadcast::CheckInputsAndAdd(int& nDoS, bool fRequested) return false; } -void CMasternodeBroadcast::Relay(bool fRequested) +void CMasternodeBroadcast::Relay() { CInv inv(MSG_MASTERNODE_ANNOUNCE, GetHash()); RelayInv(inv); @@ -484,13 +464,17 @@ bool CMasternodeBroadcast::Sign(CKey& keyCollateralAddress) CMasternodePing::CMasternodePing() { vin = CTxIn(); - blockHash = chainActive[chainActive.Height() - 12]->GetBlockHash(); + blockHash = uint256(0); + sigTime = 0; + vchSig = std::vector(); } CMasternodePing::CMasternodePing(CTxIn& newVin) { vin = newVin; blockHash = chainActive[chainActive.Height() - 12]->GetBlockHash(); + sigTime = GetAdjustedTime(); + vchSig = std::vector(); } @@ -518,62 +502,70 @@ bool CMasternodePing::Sign(CKey& keyMasternode, CPubKey& pubKeyMasternode) bool CMasternodePing::CheckAndUpdate(int& nDos) { if (sigTime > GetAdjustedTime() + 60 * 60) { - LogPrintf("mnping - Signature rejected, too far into the future %s\n", vin.ToString().c_str()); + LogPrintf("CMasternodePing::CheckAndUpdate - Signature rejected, too far into the future %s\n", vin.ToString().c_str()); + nDos = 1; return false; } if (sigTime <= GetAdjustedTime() - 60 * 60) { - LogPrintf("mnping - Signature rejected, too far into the past %s - %d %d \n", vin.ToString().c_str(), sigTime, GetAdjustedTime()); + LogPrintf("CMasternodePing::CheckAndUpdate - Signature rejected, too far into the past %s - %d %d \n", vin.ToString().c_str(), sigTime, GetAdjustedTime()); + nDos = 1; return false; } // see if we have this Masternode CMasternode* pmn = mnodeman.Find(vin); - if(pmn != NULL && pmn->protocolVersion >= nMasternodeMinProtocol) + if(pmn != NULL && pmn->IsEnabled() && pmn->protocolVersion >= nMasternodeMinProtocol) { // LogPrintf("mnping - Found corresponding mn for vin: %s\n", vin.ToString().c_str()); - // take this only if it's newer and last ping was more then MASTERNODE_MIN_MNP_SECONDS ago - if(sigTime - pmn->lastMnping > MASTERNODE_MIN_MNP_SECONDS-60) + // update only if there is no known ping for this masternode or + // 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("mnping - Got bad Masternode address signature %s\n", vin.ToString()); + LogPrintf("CMasternodePing::CheckAndUpdate - Got bad Masternode address signature %s\n", vin.ToString()); nDos = 33; return false; } - pmn->lastMnping = sigTime; - BlockMap::iterator mi = mapBlockIndex.find(blockHash); if (mi != mapBlockIndex.end() && (*mi).second) { if((*mi).second->nHeight < chainActive.Height() - 24) { - LogPrintf("mnping - Masternode %s block hash %s is too old\n", vin.ToString(), blockHash.ToString()); + LogPrintf("CMasternodePing::CheckAndUpdate - Masternode %s block hash %s is too old\n", vin.ToString(), blockHash.ToString()); // Do nothing here (no Masternode update, no mnping relay) // Let this node to be visible but fail to accept mnping return false; } } else { - if (fDebug) LogPrintf("mnping - Masternode %s block hash %s is unknown\n", vin.ToString(), blockHash.ToString()); + if (fDebug) LogPrintf("CMasternodePing::CheckAndUpdate - Masternode %s block hash %s is unknown\n", vin.ToString(), blockHash.ToString()); // maybe we stuck so we shouldn't ban this node, just fail to accept it // TODO: or should we also request this block? return false; } - pmn->UpdateLastSeen(); + pmn->lastPing = *this; + pmn->Check(); if(!pmn->IsEnabled()) return false; + if(fDebug) LogPrintf("CMasternodePing::CheckAndUpdate - Masternode ping accepted, vin: %s\n", vin.ToString()); + Relay(); return true; } + if(fDebug) LogPrintf("CMasternodePing::CheckAndUpdate - Masternode ping arrived too early, vin: %s\n", vin.ToString()); + nDos = 1; + return false; } + if(fDebug) LogPrintf("CMasternodePing::CheckAndUpdate - Couldn't find compatible Masternode entry, vin: %s\n", vin.ToString()); return false; } diff --git a/src/masternode.h b/src/masternode.h index 89eba8e493..86849bdd63 100644 --- a/src/masternode.h +++ b/src/masternode.h @@ -13,15 +13,11 @@ #include "main.h" #include "timedata.h" -#define MASTERNODE_NOT_PROCESSED 0 // initial state -#define MASTERNODE_IS_CAPABLE 1 -#define MASTERNODE_NOT_CAPABLE 2 -#define MASTERNODE_STOPPED 3 -#define MASTERNODE_INPUT_TOO_NEW 4 -#define MASTERNODE_PORT_NOT_OPEN 6 -#define MASTERNODE_PORT_OPEN 7 -#define MASTERNODE_SYNC_IN_PROCESS 8 -#define MASTERNODE_REMOTELY_ENABLED 9 +#define MASTERNODE_INITIAL 0 // initial state +#define MASTERNODE_SYNC_IN_PROCESS 1 +#define MASTERNODE_INPUT_TOO_NEW 2 +#define MASTERNODE_NOT_CAPABLE 3 +#define MASTERNODE_STARTED 4 #define MASTERNODE_MIN_CONFIRMATIONS 15 #define MASTERNODE_MIN_MNP_SECONDS (30*60) @@ -39,6 +35,75 @@ extern map mapCacheBlockHashes; bool GetBlockHash(uint256& hash, int nBlockHeight); + +// +// The Masternode Ping Class : Contains a different serialize method for sending pings from masternodes throughout the network +// + +class CMasternodePing +{ +public: + + CTxIn vin; + uint256 blockHash; + int64_t sigTime; //mnb message times + std::vector vchSig; + //removed stop + + CMasternodePing(); + CMasternodePing(CTxIn& newVin); + + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + READWRITE(vin); + READWRITE(blockHash); + READWRITE(sigTime); + READWRITE(vchSig); + } + + bool CheckAndUpdate(int& nDos); + bool Sign(CKey& keyMasternode, CPubKey& pubKeyMasternode); + void Relay(); + + uint256 GetHash(){ + CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION); + ss << vin; + ss << sigTime; + return ss.GetHash(); + } + + void swap(CMasternodePing& first, CMasternodePing& second) // nothrow + { + // enable ADL (not necessary in our case, but good practice) + using std::swap; + + // by swapping the members of two classes, + // the two classes are effectively swapped + swap(first.vin, second.vin); + swap(first.blockHash, second.blockHash); + swap(first.sigTime, second.sigTime); + swap(first.vchSig, second.vchSig); + } + + CMasternodePing& operator=(CMasternodePing from) + { + swap(*this, from); + return *this; + } + friend bool operator==(const CMasternodePing& a, const CMasternodePing& b) + { + return a.vin == b.vin && a.blockHash == b.blockHash; + } + friend bool operator!=(const CMasternodePing& a, const CMasternodePing& b) + { + return !(a == b); + } + +}; + + // // The Masternode Class. For managing the Darksend process. It contains the input of the 1000DRK, signature to prove // it's the one who own that ip address and code for calculating the payment election. @@ -64,9 +129,7 @@ public: CPubKey pubkey2; std::vector sig; int activeState; - int64_t sigTime; //mnb message times - int64_t lastMnping; - int64_t lastTimeSeen; + int64_t sigTime; //mnb message time int cacheInputAge; int cacheInputAgeBlock; bool unitTest; @@ -76,11 +139,12 @@ public: int nScanningErrorCount; int nLastScanningErrorBlockHeight; int nVotedTimes; - + CMasternodePing lastPing; + + CMasternode(); CMasternode(const CMasternode& other); - CMasternode(const CMasternodeBroadcast& other); - CMasternode(CService newAddr, CTxIn newVin, CPubKey newPubkey, std::vector newSig, int64_t newSigTime, CPubKey newPubkey2, int protocolVersionIn); + CMasternode(const CMasternodeBroadcast& mnb); void swap(CMasternode& first, CMasternode& second) // nothrow @@ -97,8 +161,7 @@ public: swap(first.sig, second.sig); swap(first.activeState, second.activeState); swap(first.sigTime, second.sigTime); - swap(first.lastMnping, second.lastMnping); - swap(first.lastTimeSeen, second.lastTimeSeen); + swap(first.lastPing, second.lastPing); swap(first.cacheInputAge, second.cacheInputAge); swap(first.cacheInputAgeBlock, second.cacheInputAgeBlock); swap(first.unitTest, second.unitTest); @@ -138,10 +201,9 @@ public: READWRITE(pubkey2); READWRITE(sig); READWRITE(sigTime); - READWRITE(lastTimeSeen); READWRITE(protocolVersion); READWRITE(activeState); - READWRITE(lastMnping); + READWRITE(lastPing); READWRITE(cacheInputAge); READWRITE(cacheInputAgeBlock); READWRITE(unitTest); @@ -156,15 +218,6 @@ public: void UpdateFromNewBroadcast(CMasternodeBroadcast& mnb); - void UpdateLastSeen(int64_t override=0) - { - if(override == 0){ - lastTimeSeen = GetAdjustedTime(); - } else { - lastTimeSeen = override; - } - } - inline uint64_t SliceHash(uint256& hash, int slice) { uint64_t n = 0; @@ -174,16 +227,23 @@ public: void Check(); - bool UpdatedWithin(int seconds) + bool IsBroadcastedWithin(int seconds) { - // LogPrintf("UpdatedWithin %d, %d -- %d \n", GetAdjustedTime() , lastTimeSeen, (GetAdjustedTime() - lastTimeSeen) < seconds); + return (GetAdjustedTime() - sigTime) < seconds; + } - return (GetAdjustedTime() - lastTimeSeen) < seconds; + bool IsPingedWithin(int seconds, int64_t now = -1) + { + now == -1 ? now = GetAdjustedTime() : now; + return (lastPing == CMasternodePing()) + ? false + : now - lastPing.sigTime < seconds; } void Disable() { - lastTimeSeen = 0; + sigTime = 0; + lastPing = CMasternodePing(); } bool IsEnabled() @@ -229,12 +289,12 @@ class CMasternodeBroadcast : public CMasternode public: CMasternodeBroadcast(); CMasternodeBroadcast(CService newAddr, CTxIn newVin, CPubKey newPubkey, CPubKey newPubkey2, int protocolVersionIn); - CMasternodeBroadcast(const CMasternode& other); + CMasternodeBroadcast(const CMasternode& mn); - bool CheckAndUpdate(int& nDoS, bool fRequested); - bool CheckInputsAndAdd(int& nDos, bool fRequested); + bool CheckAndUpdate(int& nDoS); + bool CheckInputsAndAdd(int& nDos); bool Sign(CKey& keyCollateralAddress); - void Relay(bool fRequested); + void Relay(); ADD_SERIALIZE_METHODS; @@ -246,8 +306,8 @@ public: READWRITE(pubkey2); READWRITE(sig); READWRITE(sigTime); - READWRITE(lastTimeSeen); READWRITE(protocolVersion); + READWRITE(lastPing); } uint256 GetHash(){ @@ -259,43 +319,4 @@ public: }; - -// -// The Masternode Ping Class : Contains a different serialize method for sending pings from masternodes throughout the network -// - -class CMasternodePing -{ -public: - - CTxIn vin; - uint256 blockHash; - std::vector vchSig; - int64_t sigTime; //mnb message times - //removed stop - - CMasternodePing(); - CMasternodePing(CTxIn& newVin); - - ADD_SERIALIZE_METHODS; - - template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { - READWRITE(vin); - READWRITE(blockHash); - READWRITE(sigTime); - READWRITE(vchSig); - } - - bool CheckAndUpdate(int& nDos); - bool Sign(CKey& keyMasternode, CPubKey& pubKeyMasternode); - void Relay(); - - uint256 GetHash(){ - CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION); - ss << vin; - ss << sigTime; - return ss.GetHash(); - } -}; #endif diff --git a/src/masternodeman.cpp b/src/masternodeman.cpp index 6d86fdd3d5..cfe14e78c0 100644 --- a/src/masternodeman.cpp +++ b/src/masternodeman.cpp @@ -12,8 +12,6 @@ #include #include -CCriticalSection cs_process_message; - /** Masternode manager */ CMasternodeMan mnodeman; @@ -84,7 +82,7 @@ bool CMasternodeDB::Write(const CMasternodeMan& mnodemanToSave) return true; } -CMasternodeDB::ReadResult CMasternodeDB::Read(CMasternodeMan& mnodemanToLoad) +CMasternodeDB::ReadResult CMasternodeDB::Read(CMasternodeMan& mnodemanToLoad, bool fDryRun) { int64_t nStart = GetTimeMillis(); // open input file, and associate with CAutoFile @@ -159,9 +157,12 @@ CMasternodeDB::ReadResult CMasternodeDB::Read(CMasternodeMan& mnodemanToLoad) return IncorrectFormat; } - mnodemanToLoad.CheckAndRemove(); // clean out expired LogPrintf("Loaded info from mncache.dat %dms\n", GetTimeMillis() - nStart); LogPrintf(" %s\n", mnodemanToLoad.ToString()); + LogPrintf("Masternode manager - cleaning....\n"); + if(!fDryRun) mnodemanToLoad.CheckAndRemove(true); + LogPrintf("Masternode manager - result:\n"); + LogPrintf(" %s\n", mnodemanToLoad.ToString()); return Ok; } @@ -174,7 +175,7 @@ void DumpMasternodes() CMasternodeMan tempMnodeman; LogPrintf("Verifying mncache.dat format...\n"); - CMasternodeDB::ReadResult readResult = mndb.Read(tempMnodeman); + CMasternodeDB::ReadResult readResult = mndb.Read(tempMnodeman, true); // there was an error and it was not an error on file openning => do not proceed if (readResult == CMasternodeDB::FileError) LogPrintf("Missing masternode cache file - mncache.dat, will try to recreate\n"); @@ -223,24 +224,22 @@ void CMasternodeMan::Check() BOOST_FOREACH(CMasternode& mn, vMasternodes) { mn.Check(); - - // // if it matches our Masternode privkey, then we've been remotely activated - // if(mn.pubkey2 == activeMasternode.pubKeyMasternode && mn.protocolVersion == PROTOCOL_VERSION){ - // activeMasternode.EnableHotColdMasterNode(mn.vin, mn.addr); - // } } } -void CMasternodeMan::CheckAndRemove() +void CMasternodeMan::CheckAndRemove(bool forceExpiredRemoval) { LOCK(cs); Check(); - //remove inactive + //remove inactive and outdated vector::iterator it = vMasternodes.begin(); while(it != vMasternodes.end()){ - if((*it).activeState == CMasternode::MASTERNODE_REMOVE || (*it).activeState == CMasternode::MASTERNODE_VIN_SPENT || (*it).protocolVersion < nMasternodeMinProtocol){ + if((*it).activeState == CMasternode::MASTERNODE_REMOVE || + (*it).activeState == CMasternode::MASTERNODE_VIN_SPENT || + (forceExpiredRemoval && (*it).activeState == CMasternode::MASTERNODE_EXPIRED) || + (*it).protocolVersion < nMasternodeMinProtocol) { if(fDebug) LogPrintf("CMasternodeMan: Removing inactive Masternode %s - %i now\n", (*it).addr.ToString().c_str(), size() - 1); it = vMasternodes.erase(it); } else { @@ -576,14 +575,13 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData if (strCommand == "mnb") { //Masternode Broadcast CMasternodeBroadcast mnb; - bool fRequested; //specifically requested? - vRecv >> mnb >> fRequested; + vRecv >> mnb; if(mapSeenMasternodeBroadcast.count(mnb.GetHash())) return; //seen mapSeenMasternodeBroadcast[mnb.GetHash()] = mnb; int nDoS = 0; - if(!mnb.CheckAndUpdate(nDoS, fRequested)){ + if(!mnb.CheckAndUpdate(nDoS)){ if(nDoS > 0) Misbehaving(pfrom->GetId(), nDoS); @@ -600,15 +598,13 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData return; } - if(fDebug) LogPrintf("mnb - Got NEW Masternode entry %s\n", mnb.addr.ToString().c_str()); - // make sure it's still unspent // - this is checked later by .check() in many places and by ThreadCheckDarkSendPool() - if(mnb.CheckInputsAndAdd(nDoS, fRequested)) { + if(mnb.CheckInputsAndAdd(nDoS)) { // use this as a peer addrman.Add(CAddress(mnb.addr), pfrom->addr, 2*60*60); } else { - LogPrintf("mnb - Rejected Masternode entry %s\n", mnb.addr.ToString().c_str()); + LogPrintf("mnb - Rejected Masternode entry %s\n", mnb.addr.ToString()); if (nDoS > 0) Misbehaving(pfrom->GetId(), nDoS); @@ -619,22 +615,22 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData CMasternodePing mnp; vRecv >> mnp; + if(fDebug) LogPrintf("mnp - Masternode ping, vin: %s\n", mnp.vin.ToString()); + if(mapSeenMasternodePing.count(mnp.GetHash())) return; //seen mapSeenMasternodePing[mnp.GetHash()] = mnp; int nDoS = 0; - if(mnp.CheckAndUpdate(nDoS)) - { - //successful, we're done + if(mnp.CheckAndUpdate(nDoS)) return; + + if(nDoS > 0) { + // if anything significant failed, mark that node and return + Misbehaving(pfrom->GetId(), nDoS); return; - } else { - //failure - if(nDoS > 0) - Misbehaving(pfrom->GetId(), nDoS); } - if(fDebug) LogPrintf("mnp - Couldn't find Masternode entry %s\n", mnp.vin.ToString().c_str()); - + // we wasn't able to accept mnp but nothing significant happened, + // we might just have to ask for a masternode entry once std::map::iterator i = mWeAskedForMasternodeListEntry.find(mnp.vin.prevout); if (i != mWeAskedForMasternodeListEntry.end()) { @@ -644,7 +640,7 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData // ask for the mnb info once from the node that sent mnp - LogPrintf("mnp - Asking source node for missing entry %s\n", mnp.vin.ToString().c_str()); + LogPrintf("mnp - Asking source node for missing entry, vin: %s\n", mnp.vin.ToString()); pfrom->PushMessage("dseg", mnp.vin); int64_t askAgain = GetTime() + MASTERNODE_MIN_MNP_SECONDS; mWeAskedForMasternodeListEntry[mnp.vin.prevout] = askAgain; @@ -677,27 +673,24 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData BOOST_FOREACH(CMasternode& mn, vMasternodes) { if(mn.addr.IsRFC1918()) continue; //local network - bool fRequested = true; if(mn.IsEnabled()) { if(fDebug) LogPrintf("dseg - Sending Masternode entry - %s \n", mn.addr.ToString().c_str()); if(vin == CTxIn()){ CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); ss.reserve(1000); ss << CMasternodeBroadcast(mn); - ss << fRequested; pfrom->PushMessage("mnb", ss); } else if (vin == mn.vin) { CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); ss.reserve(1000); ss << CMasternodeBroadcast(mn); - ss << fRequested; pfrom->PushMessage("mnb", ss); LogPrintf("dseg - Sent 1 Masternode entries to %s\n", pfrom->addr.ToString().c_str()); return; } + i++; } - i++; } LogPrintf("dseg - Sent %d Masternode entries to %s\n", i, pfrom->addr.ToString().c_str()); diff --git a/src/masternodeman.h b/src/masternodeman.h index 9a52d87d76..8c7b439353 100644 --- a/src/masternodeman.h +++ b/src/masternodeman.h @@ -49,7 +49,7 @@ public: CMasternodeDB(); bool Write(const CMasternodeMan &mnodemanToSave); - ReadResult Read(CMasternodeMan& mnodemanToLoad); + ReadResult Read(CMasternodeMan& mnodemanToLoad, bool fDryRun = false); }; class CMasternodeMan @@ -58,6 +58,9 @@ private: // critical section to protect the inner data structures mutable CCriticalSection cs; + // critical section to protect the inner data structures specifically on messaging + mutable CCriticalSection cs_process_message; + // map to hold all MNs std::vector vMasternodes; // who's asked for the Masternode list and the last time @@ -93,7 +96,7 @@ public: void Check(); /// Check all Masternodes and remove inactive - void CheckAndRemove(); + void CheckAndRemove(bool forceExpiredRemoval = false); /// Clear Masternode vector void Clear(); diff --git a/src/miner.cpp b/src/miner.cpp index dc989c3c3f..19b59ac4bd 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -19,7 +19,6 @@ #ifdef ENABLE_WALLET #include "wallet.h" #endif -#include "masternodeman.h" #include "masternode-payments.h" #include diff --git a/src/rpcmasternode.cpp b/src/rpcmasternode.cpp index b23d1bfcd5..cf96272e57 100644 --- a/src/rpcmasternode.cpp +++ b/src/rpcmasternode.cpp @@ -199,21 +199,13 @@ Value masternode(const Array& params, bool fHelp) } } - if(activeMasternode.status != MASTERNODE_REMOTELY_ENABLED && activeMasternode.status != MASTERNODE_IS_CAPABLE){ - activeMasternode.status = MASTERNODE_NOT_PROCESSED; // TODO: consider better way - std::string errorMessage; + if(activeMasternode.status != MASTERNODE_STARTED){ + activeMasternode.status = MASTERNODE_INITIAL; // TODO: consider better way activeMasternode.ManageStatus(); pwalletMain->Lock(); } - if(activeMasternode.status == MASTERNODE_REMOTELY_ENABLED) return "masternode started remotely"; - if(activeMasternode.status == MASTERNODE_INPUT_TOO_NEW) return "masternode input must have at least 15 confirmations"; - if(activeMasternode.status == MASTERNODE_STOPPED) return "masternode is stopped"; - if(activeMasternode.status == MASTERNODE_IS_CAPABLE) return "successfully started masternode"; - if(activeMasternode.status == MASTERNODE_NOT_CAPABLE) return "not capable masternode: " + activeMasternode.notCapableReason; - if(activeMasternode.status == MASTERNODE_SYNC_IN_PROCESS) return "sync in process. Must wait until client is synced to start."; - - return "unknown"; + return activeMasternode.GetStatus(); } if (strCommand == "start-alias") @@ -330,12 +322,7 @@ Value masternode(const Array& params, bool fHelp) if (strCommand == "debug") { - if(activeMasternode.status == MASTERNODE_REMOTELY_ENABLED) return "masternode started remotely"; - if(activeMasternode.status == MASTERNODE_INPUT_TOO_NEW) return "masternode input must have at least 15 confirmations"; - if(activeMasternode.status == MASTERNODE_IS_CAPABLE) return "successfully started masternode"; - if(activeMasternode.status == MASTERNODE_STOPPED) return "masternode is stopped"; - if(activeMasternode.status == MASTERNODE_NOT_CAPABLE) return "not capable masternode: " + activeMasternode.notCapableReason; - if(activeMasternode.status == MASTERNODE_SYNC_IN_PROCESS) return "sync in process. Must wait until client is synced to start."; + if(activeMasternode.status != MASTERNODE_INITIAL) return activeMasternode.GetStatus(); CTxIn vin = CTxIn(); CPubKey pubkey = CScript(); @@ -369,8 +356,10 @@ Value masternode(const Array& params, bool fHelp) obj.push_back(Pair("protocol", (int64_t)winner->protocolVersion)); obj.push_back(Pair("vin", winner->vin.prevout.hash.ToString().c_str())); obj.push_back(Pair("pubkey", address2.ToString().c_str())); - obj.push_back(Pair("lastseen", (int64_t)winner->lastTimeSeen)); - obj.push_back(Pair("activeseconds", (int64_t)(winner->lastTimeSeen - winner->sigTime))); + obj.push_back(Pair("lastseen", (winner->lastPing == CMasternodePing()) ? winner->sigTime : + (int64_t)winner->lastPing.sigTime)); + obj.push_back(Pair("activeseconds", (winner->lastPing == CMasternodePing()) ? 0 : + (int64_t)(winner->lastPing.sigTime - winner->sigTime))); return obj; } @@ -498,6 +487,7 @@ Value masternodelist(const Array& params, bool fHelp) " additional matches in some modes are also available\n" "\nAvailable modes:\n" " activeseconds - Print number of seconds masternode recognized by the network as enabled\n" + " (since latest issued \"masternode start/start-many/start-alias\")\n" " full - Print info in format 'status protocol pubkey IP lastseen activeseconds lastpaid'\n" " (can be additionally filtered, partial match)\n" " lastseen - Print timestamp of when a masternode was last seen on the network\n" @@ -526,7 +516,7 @@ Value masternodelist(const Array& params, bool fHelp) std::string strVin = mn.vin.prevout.ToStringShort(); if (strMode == "activeseconds") { if(strFilter !="" && strVin.find(strFilter) == string::npos) continue; - obj.push_back(Pair(strVin, (int64_t)(mn.lastTimeSeen - mn.sigTime))); + obj.push_back(Pair(strVin, (int64_t)(mn.lastPing.sigTime - mn.sigTime))); } else if (strMode == "full") { CScript pubkey; pubkey = GetScriptForDestination(mn.pubkey.GetID()); @@ -543,8 +533,8 @@ Value masternodelist(const Array& params, bool fHelp) mn.protocolVersion << " " << address2.ToString() << " " << mn.addr.ToString() << " " << - mn.lastTimeSeen << " " << setw(8) << - (mn.lastTimeSeen - mn.sigTime) << " " << + mn.lastPing.sigTime << " " << setw(8) << + (mn.lastPing.sigTime - mn.sigTime) << " " << mn.GetLastPaid(); std::string output = stringStream.str(); stringStream << " " << strVin; @@ -553,7 +543,7 @@ Value masternodelist(const Array& params, bool fHelp) obj.push_back(Pair(addrStream.str(), output)); } else if (strMode == "lastseen") { if(strFilter !="" && strVin.find(strFilter) == string::npos) continue; - obj.push_back(Pair(strVin, (int64_t)mn.lastTimeSeen)); + obj.push_back(Pair(strVin, (int64_t)mn.lastPing.sigTime)); } else if (strMode == "protocol") { if(strFilter !="" && strFilter != boost::lexical_cast(mn.protocolVersion) && strVin.find(strFilter) == string::npos) continue; From 3ef2cec49d5d3c78c92e0c413e5637df5cd496f6 Mon Sep 17 00:00:00 2001 From: UdjinM6 Date: Tue, 14 Jul 2015 08:59:08 +0300 Subject: [PATCH 2/4] proto bump --- src/instantx.h | 2 +- src/version.h | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/instantx.h b/src/instantx.h index 9525089033..53541dee81 100644 --- a/src/instantx.h +++ b/src/instantx.h @@ -27,7 +27,7 @@ class CConsensusVote; class CTransaction; class CTransactionLock; -static const int MIN_INSTANTX_PROTO_VERSION = 70089; +static const int MIN_INSTANTX_PROTO_VERSION = 70090; extern map mapTxLockReq; extern map mapTxLockReqRejected; diff --git a/src/version.h b/src/version.h index ce54e24fdb..0da8b8e569 100644 --- a/src/version.h +++ b/src/version.h @@ -10,7 +10,7 @@ * network protocol versioning */ -static const int PROTOCOL_VERSION = 70089; +static const int PROTOCOL_VERSION = 70090; //! initial proto version, to be increased after version/verack negotiation static const int INIT_PROTO_VERSION = 209; @@ -22,16 +22,16 @@ static const int GETHEADERS_VERSION = 70077; static const int MIN_PEER_PROTO_VERSION = 70066; //! minimum peer version accepted by DarksendPool -static const int MIN_POOL_PEER_PROTO_VERSION = 70089; +static const int MIN_POOL_PEER_PROTO_VERSION = 70090; //! minimum peer version for masternode budgets -static const int MIN_BUDGET_PEER_PROTO_VERSION = 70089; +static const int MIN_BUDGET_PEER_PROTO_VERSION = 70090; //! minimum peer version that can receive masternode payments // V1 - Last protocol version before update // V2 - Newest protocol version static const int MIN_MASTERNODE_PAYMENT_PROTO_VERSION_1 = 70066; -static const int MIN_MASTERNODE_PAYMENT_PROTO_VERSION_2 = 70089; +static const int MIN_MASTERNODE_PAYMENT_PROTO_VERSION_2 = 70090; //! nTime field added to CAddress, starting with this version; //! if possible, avoid requesting addresses nodes older than this From f2c56533792012b39b65520d84b194b6cfd0e4b1 Mon Sep 17 00:00:00 2001 From: UdjinM6 Date: Tue, 14 Jul 2015 09:10:18 +0300 Subject: [PATCH 3/4] Start all ds, mnodeman, ix related checks and activate mn only after sync is over --- src/darksend.cpp | 64 +++++++++++++++++++++++++----------------------- src/init.cpp | 1 - 2 files changed, 34 insertions(+), 31 deletions(-) diff --git a/src/darksend.cpp b/src/darksend.cpp index bf2fe8f432..4544f92f41 100644 --- a/src/darksend.cpp +++ b/src/darksend.cpp @@ -2335,27 +2335,6 @@ void ThreadCheckDarkSendPool() MilliSleep(1000); //LogPrintf("ThreadCheckDarkSendPool::check timeout\n"); - darkSendPool.CheckTimeout(); - darkSendPool.CheckForCompleteQueue(); - - if(c % 60 == 0) - { - LOCK(cs_main); - /* - cs_main is required for doing CMasternode.Check because something - is modifying the coins view without a mempool lock. It causes - segfaults from this code without the cs_main lock. - */ - mnodeman.CheckAndRemove(); - mnodeman.ProcessMasternodeConnections(); - masternodePayments.CleanPaymentList(); - CleanTransactionLocksList(); - } - - if(c % MASTERNODE_PING_SECONDS == 0) activeMasternode.ManageStatus(); - - if(c % MASTERNODES_DUMP_SECONDS == 0) DumpMasternodes(); - //try to sync the Masternode list and payment list every 5 seconds from at least 3 nodes if(c % 5 == 0 && RequestedMasternodeAssets <= 5){ bool fIsInitialDownload = IsInitialBlockDownload(); @@ -2403,18 +2382,43 @@ void ThreadCheckDarkSendPool() } } } - } else if(c % 60 == 0 && RequestedMasternodeAssets == 3){ - RequestedMasternodeAssets = MASTERNODE_LIST_SYNCED; //done syncing + } else if((c % 60 == 0 && RequestedMasternodeAssets >= 5 && RequestedMasternodeAssets < MASTERNODE_LIST_SYNCED) || //done syncing + (c % (5 * 60) == 0 && RequestedMasternodeAssets < 5)) { //couldn't find 5 peers in 5 minutes + RequestedMasternodeAssets = MASTERNODE_LIST_SYNCED; + c = 1; // reset counter } - if(c % 60 == 0){ - //if we've used 1/5 of the Masternode list, then clear the list. - if((int)vecMasternodesUsed.size() > (int)mnodeman.size() / 5) - vecMasternodesUsed.clear(); - } + if(RequestedMasternodeAssets == MASTERNODE_LIST_SYNCED) { + if(c % MASTERNODE_PING_SECONDS == 1) activeMasternode.ManageStatus(); // activate right after sync - if(darkSendPool.GetState() == POOL_STATUS_IDLE && c % 6 == 0){ - darkSendPool.DoAutomaticDenominating(); + if(c % 60 == 0) + { + LOCK(cs_main); + /* + cs_main is required for doing CMasternode.Check because something + is modifying the coins view without a mempool lock. It causes + segfaults from this code without the cs_main lock. + */ + mnodeman.CheckAndRemove(); + mnodeman.ProcessMasternodeConnections(); + masternodePayments.CleanPaymentList(); + CleanTransactionLocksList(); + } + + if(c % 60 == 0){ + //if we've used 1/5 of the Masternode list, then clear the list. + if((int)vecMasternodesUsed.size() > (int)mnodeman.size() / 5) + vecMasternodesUsed.clear(); + } + + if(c % MASTERNODES_DUMP_SECONDS == 0) DumpMasternodes(); + + darkSendPool.CheckTimeout(); + darkSendPool.CheckForCompleteQueue(); + + if(darkSendPool.GetState() == POOL_STATUS_IDLE && c % 6 == 0){ + darkSendPool.DoAutomaticDenominating(); + } } } } diff --git a/src/init.cpp b/src/init.cpp index 509bb1007f..1cba9f2561 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1490,7 +1490,6 @@ bool AppInit2(boost::thread_group& threadGroup) return InitError(_("You must specify a masternodeprivkey in the configuration. Please see documentation for help.")); } - if(Params().NetworkID() != CBaseChainParams::REGTEST) activeMasternode.ManageStatus(); } if(GetBoolArg("-mnconflock", true)) { From 59271beabd98997d3d35c9c7f57f1717ac873ec5 Mon Sep 17 00:00:00 2001 From: UdjinM6 Date: Tue, 14 Jul 2015 11:32:49 +0300 Subject: [PATCH 4/4] Fix CBudgetProposalBroadcast::IsBudgetCollateralValid log output / strError --- src/masternode-budget.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/masternode-budget.cpp b/src/masternode-budget.cpp index 38259b6704..cc22434eaf 100644 --- a/src/masternode-budget.cpp +++ b/src/masternode-budget.cpp @@ -40,8 +40,8 @@ bool IsBudgetCollateralValid(uint256 nTxCollateralHash, uint256 nExpectedHash, s CTransaction txCollateral; uint256 nBlockHash; if(!GetTransaction(nTxCollateralHash, txCollateral, nBlockHash, true)){ - strError = "Can't find collateral tx %s\n", txCollateral.ToString().c_str(); - LogPrintf ("CBudgetProposalBroadcast::FeeTXValid - Can't find collateral tx %s\n", txCollateral.ToString().c_str()); + strError = strprintf("Can't find collateral tx %s", txCollateral.ToString()); + LogPrintf ("CBudgetProposalBroadcast::IsBudgetCollateralValid - %s\n", strError); return false; } @@ -54,16 +54,16 @@ bool IsBudgetCollateralValid(uint256 nTxCollateralHash, uint256 nExpectedHash, s bool foundOpReturn = false; BOOST_FOREACH(const CTxOut o, txCollateral.vout){ if(!o.scriptPubKey.IsNormalPaymentScript() && !o.scriptPubKey.IsUnspendable()){ - strError = "Invalid Script"; - LogPrintf ("CBudgetProposalBroadcast::FeeTXValid - Invalid Script %s\n", txCollateral.ToString()); + strError = strprintf("Invalid Script %s", txCollateral.ToString()); + LogPrintf ("CBudgetProposalBroadcast::IsBudgetCollateralValid - %s\n", strError); return false; } if(o.scriptPubKey == findScript && o.nValue >= BUDGET_FEE_TX) foundOpReturn = true; } if(!foundOpReturn){ - strError = "Couldn't find opReturn"; - LogPrintf ("CBudgetProposalBroadcast::IsBudgetCollateralValid - Couldn't find opReturn %s\n", txCollateral.ToString()); + strError = strprintf("Couldn't find opReturn %s", txCollateral.ToString()); + LogPrintf ("CBudgetProposalBroadcast::IsBudgetCollateralValid - %s\n", strError); return false; } @@ -79,8 +79,8 @@ bool IsBudgetCollateralValid(uint256 nTxCollateralHash, uint256 nExpectedHash, s } if(conf < BUDGET_FEE_CONFIRMATIONS){ - strError = "Collateral requires at least 6 confirmations - " + boost::lexical_cast(conf) + " confirmations "; - LogPrintf ("CBudgetProposalBroadcast::IsBudgetCollateralValid - Collateral requires at least 6 confirmations - %s - %d confirmations\n", txCollateral.GetHash().ToString(), conf); + strError = strprintf("Collateral requires at least %d confirmations - %d confirmations", BUDGET_FEE_CONFIRMATIONS, conf); + LogPrintf ("CBudgetProposalBroadcast::IsBudgetCollateralValid - %s - %d confirmations\n", strError, conf); return false; }