#include "masternode.h" #include "activemasternode.h" #include "darksend.h" #include "core.h" #include "util.h" #include "addrman.h" #include /** The list of active masternodes */ std::vector darkSendMasterNodes; /** Object for who's going to get paid on which blocks */ CMasternodePayments masternodePayments; // keep track of masternode votes I've seen map mapSeenMasternodeVotes; // keep track of the scanning errors I've seen map mapSeenMasternodeScanningErrors; // who's asked for the masternode list and the last time std::map askedForMasternodeList; // which masternodes we've asked for std::map askedForMasternodeListEntry; // manage the masternode connections void ProcessMasternodeConnections(){ LOCK(cs_vNodes); BOOST_FOREACH(CNode* pnode, vNodes) { //if it's our masternode, let it be if(darkSendPool.submittedToMasternode == pnode->addr) continue; if(pnode->fDarkSendMaster){ LogPrintf("Closing masternode connection %s \n", pnode->addr.ToString().c_str()); pnode->CloseSocketDisconnect(); } } } void ProcessMessageMasternode(CNode* pfrom, std::string& strCommand, CDataStream& vRecv) { if (strCommand == "dsee") { //DarkSend Election Entry bool fIsInitialDownload = IsInitialBlockDownload(); if(fIsInitialDownload) return; CTxIn vin; CService addr; CPubKey pubkey; CPubKey pubkey2; vector vchSig; int64_t sigTime; int count; int current; int64_t lastUpdated; int protocolVersion; std::string strMessage; // 70047 and greater vRecv >> vin >> addr >> vchSig >> sigTime >> pubkey >> pubkey2 >> count >> current >> lastUpdated >> protocolVersion; // make sure signature isn't in the future (past is OK) if (sigTime > GetAdjustedTime() + 60 * 60) { LogPrintf("dsee - Signature rejected, too far into the future %s\n", vin.ToString().c_str()); return; } bool isLocal = false; // addr.IsRFC1918(); std::string vchPubKey(pubkey.begin(), pubkey.end()); std::string vchPubKey2(pubkey2.begin(), pubkey2.end()); strMessage = addr.ToString() + boost::lexical_cast(sigTime) + vchPubKey + vchPubKey2 + boost::lexical_cast(protocolVersion); if(protocolVersion < nMasternodeMinProtocol) { LogPrintf("dsee - ignoring outdated masternode %s protocol version %d\n", vin.ToString().c_str(), protocolVersion); return; } CScript pubkeyScript; pubkeyScript.SetDestination(pubkey.GetID()); if(pubkeyScript.size() != 25) { LogPrintf("dsee - pubkey the wrong size\n"); Misbehaving(pfrom->GetId(), 100); return; } CScript pubkeyScript2; pubkeyScript2.SetDestination(pubkey2.GetID()); if(pubkeyScript2.size() != 25) { LogPrintf("dsee - pubkey the wrong size\n"); Misbehaving(pfrom->GetId(), 100); return; } std::string errorMessage = ""; if(!darkSendSigner.VerifyMessage(pubkey, vchSig, strMessage, errorMessage)){ LogPrintf("dsee - Got bad masternode address signature\n"); Misbehaving(pfrom->GetId(), 100); return; } if((Params().NetworkID() == CChainParams::TESTNET && addr.GetPort() != 19999) || (!(Params().NetworkID() == CChainParams::TESTNET) && addr.GetPort() != 9999)) return; //search existing masternode list, this is where we update existing masternodes with new dsee broadcasts BOOST_FOREACH(CMasterNode& mn, darkSendMasterNodes) { if(mn.vin.prevout == vin.prevout) { // count == -1 when it's a new entry // e.g. We don't want the entry relayed/time updated when we're syncing the list // mn.pubkey = pubkey, IsVinAssociatedWithPubkey is validated once below, // after that they just need to match if(count == -1 && mn.pubkey == pubkey && !mn.UpdatedWithin(MASTERNODE_MIN_DSEE_SECONDS)){ mn.UpdateLastSeen(); if(mn.now < sigTime){ //take the newest entry LogPrintf("dsee - Got updated entry for %s\n", addr.ToString().c_str()); mn.pubkey2 = pubkey2; mn.now = sigTime; mn.sig = vchSig; mn.protocolVersion = protocolVersion; mn.addr = addr; RelayDarkSendElectionEntry(vin, addr, vchSig, sigTime, pubkey, pubkey2, count, current, lastUpdated, protocolVersion); } } 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(vin, pubkey)) { LogPrintf("dsee - Got mismatched pubkey and vin\n"); Misbehaving(pfrom->GetId(), 100); return; } */ if(fDebug) LogPrintf("dsee - Got NEW masternode entry %s\n", addr.ToString().c_str()); // make sure it's still unspent // - this is checked later by .check() in many places and by ThreadCheckDarkSendPool() CValidationState state; CTransaction tx = CTransaction(); CTxOut vout = CTxOut(999.99*COIN, darkSendPool.collateralPubKey); tx.vin.push_back(vin); tx.vout.push_back(vout); if(AcceptableInputs(mempool, state, tx)){ if(fDebug) LogPrintf("dsee - Accepted masternode entry %i %i\n", count, current); if(GetInputAge(vin) < MASTERNODE_MIN_CONFIRMATIONS){ LogPrintf("dsee - Input must have least %d confirmations\n", MASTERNODE_MIN_CONFIRMATIONS); Misbehaving(pfrom->GetId(), 20); return; } // use this as a peer addrman.Add(CAddress(addr), pfrom->addr, 2*60*60); // add our masternode CMasterNode mn(addr, vin, pubkey, vchSig, sigTime, pubkey2, protocolVersion); mn.UpdateLastSeen(lastUpdated); darkSendMasterNodes.push_back(mn); /*// if it matches our masternodeprivkey, then we've been remotely activated if(pubkey2 == activeMasternode.pubkeyMasterNode2 && protocolVersion == PROTOCOL_VERSION){ activeMasternode.EnableHotColdMasterNode(vin, sigTime, addr); }*/ if(count == -1 && !isLocal) RelayDarkSendElectionEntry(vin, addr, vchSig, sigTime, pubkey, pubkey2, count, current, lastUpdated, protocolVersion); } else { LogPrintf("dsee - Rejected masternode entry %s\n", addr.ToString().c_str()); int nDoS = 0; if (state.IsInvalid(nDoS)) { LogPrintf("dsee - %s from %s %s was not accepted into the memory pool\n", tx.GetHash().ToString().c_str(), pfrom->addr.ToString().c_str(), pfrom->cleanSubVer.c_str()); if (nDoS > 0) Misbehaving(pfrom->GetId(), nDoS); } } } else if (strCommand == "dseep") { //DarkSend Election Entry Ping bool fIsInitialDownload = IsInitialBlockDownload(); if(fIsInitialDownload) return; CTxIn vin; vector vchSig; int64_t sigTime; bool stop; vRecv >> vin >> vchSig >> sigTime >> stop; if (sigTime > GetAdjustedTime() + 60 * 60) { LogPrintf("dseep - Signature rejected, too far into the future %s\n", vin.ToString().c_str()); return; } if (sigTime <= GetAdjustedTime() - 60 * 60) { LogPrintf("dseep - Signature rejected, too far into the past %s - %d %d \n", vin.ToString().c_str(), sigTime, GetAdjustedTime()); return; } // see if we have this masternode BOOST_FOREACH(CMasterNode& mn, darkSendMasterNodes) { if(mn.vin.prevout == vin.prevout) { // take this only if it's newer if(mn.lastDseep < sigTime){ std::string strMessage = mn.addr.ToString() + boost::lexical_cast(sigTime) + boost::lexical_cast(stop); std::string errorMessage = ""; if(!darkSendSigner.VerifyMessage(mn.pubkey2, vchSig, strMessage, errorMessage)){ LogPrintf("dseep - Got bad masternode address signature %s \n", vin.ToString().c_str()); //Misbehaving(pfrom->GetId(), 100); return; } mn.lastDseep = sigTime; if(!mn.UpdatedWithin(MASTERNODE_MIN_DSEEP_SECONDS)){ mn.UpdateLastSeen(); if(stop) { mn.Disable(); mn.Check(); } RelayDarkSendElectionEntryPing(vin, vchSig, sigTime, stop); } } return; } } if(fDebug) LogPrintf("dseep - Couldn't find masternode entry %s\n", vin.ToString().c_str()); std::map::iterator i = askedForMasternodeListEntry.find(vin.prevout); if (i != askedForMasternodeListEntry.end()){ int64_t t = (*i).second; if (GetTime() < t) { // we've asked recently return; } } // ask for the dsee info once from the node that sent dseep LogPrintf("dseep - Asking source node for missing entry %s\n", vin.ToString().c_str()); pfrom->PushMessage("dseg", vin); int64_t askAgain = GetTime()+(60*60*24); askedForMasternodeListEntry[vin.prevout] = askAgain; } else if (strCommand == "dseg") { //Get masternode list or specific entry CTxIn vin; vRecv >> vin; if(vin == CTxIn()) { //only should ask for this once //local network if(!pfrom->addr.IsRFC1918()) { std::map::iterator i = askedForMasternodeList.find(pfrom->addr); if (i != askedForMasternodeList.end()) { int64_t t = (*i).second; if (GetTime() < t) { Misbehaving(pfrom->GetId(), 100); LogPrintf("dseg - peer already asked me for the list\n"); return; } } int64_t askAgain = GetTime()+(60*60*24); askedForMasternodeList[pfrom->addr] = askAgain; } } //else, asking for a specific node which is ok int count = darkSendMasterNodes.size()-1; int i = 0; BOOST_FOREACH(CMasterNode mn, darkSendMasterNodes) { if(mn.addr.IsRFC1918()) continue; //local network if(vin == CTxIn()){ mn.Check(); if(mn.IsEnabled()) { if(fDebug) LogPrintf("dseg - Sending masternode entry - %s \n", mn.addr.ToString().c_str()); pfrom->PushMessage("dsee", mn.vin, mn.addr, mn.sig, mn.now, mn.pubkey, mn.pubkey2, count, i, mn.lastTimeSeen, mn.protocolVersion); } } else if (vin == mn.vin) { if(fDebug) LogPrintf("dseg - Sending masternode entry - %s \n", mn.addr.ToString().c_str()); pfrom->PushMessage("dsee", mn.vin, mn.addr, mn.sig, mn.now, mn.pubkey, mn.pubkey2, count, i, mn.lastTimeSeen, mn.protocolVersion); LogPrintf("dseg - Sent 1 masternode entries to %s\n", pfrom->addr.ToString().c_str()); return; } i++; } LogPrintf("dseg - Sent %d masternode entries to %s\n", count, pfrom->addr.ToString().c_str()); } else if (strCommand == "mnget") { //Masternode Payments Request Sync if(pfrom->HasFulfilledRequest("mnget")) { LogPrintf("mnget - peer already asked me for the list\n"); Misbehaving(pfrom->GetId(), 20); return; } pfrom->FulfilledRequest("mnget"); masternodePayments.Sync(pfrom); LogPrintf("mnget - Sent masternode winners to %s\n", pfrom->addr.ToString().c_str()); } else if (strCommand == "mnw") { //Masternode Payments Declare Winner CMasternodePaymentWinner winner; vRecv >> winner; if(chainActive.Tip() == NULL) return; uint256 hash = winner.GetHash(); if(mapSeenMasternodeVotes.count(hash)) { if(fDebug) LogPrintf("mnw - seen vote %s Height %d bestHeight %d\n", hash.ToString().c_str(), winner.nBlockHeight, chainActive.Tip()->nHeight); return; } if(winner.nBlockHeight < chainActive.Tip()->nHeight - 10 || winner.nBlockHeight > chainActive.Tip()->nHeight+20){ LogPrintf("mnw - winner out of range %s Height %d bestHeight %d\n", winner.vin.ToString().c_str(), winner.nBlockHeight, chainActive.Tip()->nHeight); return; } if(winner.vin.nSequence != std::numeric_limits::max()){ LogPrintf("mnw - invalid nSequence\n"); Misbehaving(pfrom->GetId(), 100); return; } LogPrintf("mnw - winning vote %s Height %d bestHeight %d\n", winner.vin.ToString().c_str(), winner.nBlockHeight, chainActive.Tip()->nHeight); if(!masternodePayments.CheckSignature(winner)){ LogPrintf("mnw - invalid signature\n"); Misbehaving(pfrom->GetId(), 100); return; } mapSeenMasternodeVotes.insert(make_pair(hash, 1)); if(masternodePayments.AddWinningMasternode(winner)){ masternodePayments.Relay(winner); } } /*else if (strCommand == "mnse") { //Masternode Scanning Error CMasternodeScanningError entry; vRecv >> entry; if(chainActive.Tip() == NULL) return; uint256 hash = entry.GetHash(); if(mapSeenMasternodeScanningErrors.count(hash)) { if(fDebug) LogPrintf("mnse - seen entry addr %d error %d\n", entry.addr.ToString().c_str(), entry.error.c_str()); return; } LogPrintf("mnse - seen entry addr %d error %d\n", entry.addr.ToString().c_str(), entry.error.c_str()); if(!masternodeScanningError.CheckSignature(entry)){ LogPrintf("mnse - invalid signature\n"); Misbehaving(pfrom->GetId(), 100); return; } mapSeenMasternodeVotes.insert(make_pair(hash, 1)); if(masternodeScanningError.AddWinningMasternode(entry)){ masternodeScanningError.Relay(entry); } }*/ } struct CompareValueOnly { bool operator()(const pair& t1, const pair& t2) const { return t1.first < t2.first; } }; struct CompareValueOnly2 { bool operator()(const pair& t1, const pair& t2) const { return t1.first < t2.first; } }; int CountMasternodesAboveProtocol(int protocolVersion) { int i = 0; BOOST_FOREACH(CMasterNode& mn, darkSendMasterNodes) { if(mn.protocolVersion < protocolVersion) continue; i++; } return i; } int GetMasternodeByVin(CTxIn& vin) { int i = 0; BOOST_FOREACH(CMasterNode& mn, darkSendMasterNodes) { if (mn.vin == vin) return i; i++; } return -1; } int GetCurrentMasterNode(int mod, int64_t nBlockHeight, int minProtocol) { int i = 0; unsigned int score = 0; int winner = -1; // scan for winner BOOST_FOREACH(CMasterNode mn, darkSendMasterNodes) { mn.Check(); if(mn.protocolVersion < minProtocol) continue; if(!mn.IsEnabled()) { i++; continue; } // calculate the score for each masternode uint256 n = mn.CalculateScore(mod, nBlockHeight); unsigned int n2 = 0; memcpy(&n2, &n, sizeof(n2)); // determine the winner if(n2 > score){ score = n2; winner = i; } i++; } return winner; } int GetMasternodeByRank(int findRank, int64_t nBlockHeight, int minProtocol) { int i = 0; std::vector > vecMasternodeScores; i = 0; BOOST_FOREACH(CMasterNode mn, darkSendMasterNodes) { mn.Check(); if(mn.protocolVersion < minProtocol) continue; if(!mn.IsEnabled()) { i++; continue; } uint256 n = mn.CalculateScore(1, nBlockHeight); unsigned int n2 = 0; memcpy(&n2, &n, sizeof(n2)); vecMasternodeScores.push_back(make_pair(n2, i)); i++; } sort(vecMasternodeScores.rbegin(), vecMasternodeScores.rend(), CompareValueOnly2()); int rank = 0; BOOST_FOREACH (PAIRTYPE(unsigned int, int)& s, vecMasternodeScores){ rank++; if(rank == findRank) return s.second; } return -1; } int GetMasternodeRank(CTxIn& vin, int64_t nBlockHeight, int minProtocol) { std::vector > vecMasternodeScores; BOOST_FOREACH(CMasterNode mn, darkSendMasterNodes) { mn.Check(); if(mn.protocolVersion < minProtocol) continue; if(!mn.IsEnabled()) { continue; } uint256 n = mn.CalculateScore(1, nBlockHeight); unsigned int n2 = 0; memcpy(&n2, &n, sizeof(n2)); vecMasternodeScores.push_back(make_pair(n2, mn.vin)); } sort(vecMasternodeScores.rbegin(), vecMasternodeScores.rend(), CompareValueOnly()); unsigned int rank = 0; BOOST_FOREACH (PAIRTYPE(unsigned int, CTxIn)& s, vecMasternodeScores){ rank++; if(s.second == vin) return rank; } return -1; } // // Deterministically calculate a given "score" for a masternode depending on how close it's hash is to // the proof of work for that block. The further away they are the better, the furthest will win the election // and get paid this block // uint256 CMasterNode::CalculateScore(int mod, int64_t nBlockHeight) { if(chainActive.Tip() == NULL) return 0; uint256 hash = 0; if(!darkSendPool.GetLastValidBlockHash(hash, mod, nBlockHeight)) return 0; uint256 hash2 = HashX11(BEGIN(hash), END(hash)); // we'll make a 4 dimensional point in space // the closest masternode to that point wins uint64_t a1 = hash2.Get64(0); uint64_t a2 = hash2.Get64(1); uint64_t a3 = hash2.Get64(2); uint64_t a4 = hash2.Get64(3); //copy part of our source hash int i1, i2, i3, i4; i1=0;i2=0;i3=0;i4=0; memcpy(&i1, &a1, 1); memcpy(&i2, &a2, 1); memcpy(&i3, &a3, 1); memcpy(&i4, &a4, 1); //split up our mn hash uint64_t b1 = vin.prevout.hash.Get64(0); uint64_t b2 = vin.prevout.hash.Get64(1); uint64_t b3 = vin.prevout.hash.Get64(2); uint64_t b4 = vin.prevout.hash.Get64(3); //move mn hash around b1 <<= (i1 % 64); b2 <<= (i2 % 64); b3 <<= (i3 % 64); b4 <<= (i4 % 64); // calculate distance between target point and mn point uint256 r = 0; r += (a1 > b1 ? a1 - b1 : b1 - a1); r += (a2 > b2 ? a2 - b2 : b2 - a2); r += (a3 > b3 ? a3 - b3 : b3 - a3); r += (a4 > b4 ? a4 - b4 : b4 - a4); /* LogPrintf(" -- MasterNode CalculateScore() n2 = %s \n", n2.ToString().c_str()); LogPrintf(" -- MasterNode CalculateScore() vin = %s \n", vin.prevout.hash.GetHex().c_str()); LogPrintf(" -- MasterNode CalculateScore() n3 = %s \n", n3.ToString().c_str());*/ return r; } void CMasterNode::Check() { //once spent, stop doing the checks if(enabled==3) return; if(!UpdatedWithin(MASTERNODE_REMOVAL_SECONDS)){ enabled = 4; return; } if(!UpdatedWithin(MASTERNODE_EXPIRATION_SECONDS)){ enabled = 2; return; } if(!unitTest){ CValidationState state; CTransaction tx = CTransaction(); CTxOut vout = CTxOut(999.99*COIN, darkSendPool.collateralPubKey); tx.vin.push_back(vin); tx.vout.push_back(vout); if(!AcceptableInputs(mempool, state, tx)){ enabled = 3; return; } } enabled = 1; // OK } bool CMasternodePayments::CheckSignature(CMasternodePaymentWinner& winner) { //note: need to investigate why this is failing /* std::string strMessage = winner.vin.ToString().c_str() + boost::lexical_cast(winner.nBlockHeight); std::string strPubKey = (Params().NetworkID() == CChainParams::TESTNET) ? strTestPubKey : strMainPubKey; CPubKey pubkey(ParseHex(strPubKey)); std::string errorMessage = ""; if(!darkSendSigner.VerifyMessage(pubkey, winner.vchSig, strMessage, errorMessage)){ return false; } */ return true; } bool CMasternodePayments::Sign(CMasternodePaymentWinner& winner) { std::string strMessage = winner.vin.ToString().c_str() + boost::lexical_cast(winner.nBlockHeight); CKey key2; CPubKey pubkey2; std::string errorMessage = ""; if(!darkSendSigner.SetKey(strMasterPrivKey, errorMessage, key2, pubkey2)) { LogPrintf("CMasternodePayments::Sign - Invalid masternodeprivkey: '%s'\n", errorMessage.c_str()); exit(0); } if(!darkSendSigner.SignMessage(strMessage, errorMessage, winner.vchSig, key2)) { LogPrintf("CMasternodePayments::Sign - Sign message failed"); return false; } if(!darkSendSigner.VerifyMessage(pubkey2, winner.vchSig, strMessage, errorMessage)) { LogPrintf("CMasternodePayments::Sign - Verify message failed"); return false; } return true; } uint64_t CMasternodePayments::CalculateScore(uint256 blockHash, CTxIn& vin) { uint256 n1 = blockHash; uint256 n2 = HashX11(BEGIN(n1), END(n1)); uint256 n3 = HashX11(BEGIN(vin.prevout.hash), END(vin.prevout.hash)); uint256 n4 = n3 > n2 ? (n3 - n2) : (n2 - n3); //printf(" -- CMasternodePayments CalculateScore() n2 = %d \n", n2.Get64()); //printf(" -- CMasternodePayments CalculateScore() n3 = %d \n", n3.Get64()); //printf(" -- CMasternodePayments CalculateScore() n4 = %d \n", n4.Get64()); return n4.Get64(); } bool CMasternodePayments::GetBlockPayee(int nBlockHeight, CScript& payee) { BOOST_FOREACH(CMasternodePaymentWinner& winner, vWinning){ if(winner.nBlockHeight == nBlockHeight) { CTransaction tx; uint256 hash; if(GetTransaction(winner.vin.prevout.hash, tx, hash, true)){ BOOST_FOREACH(CTxOut out, tx.vout){ if(out.nValue == 1000*COIN){ payee = out.scriptPubKey; return true; } } } return false; } } return false; } bool CMasternodePayments::GetWinningMasternode(int nBlockHeight, CTxIn& vinOut) { BOOST_FOREACH(CMasternodePaymentWinner& winner, vWinning){ if(winner.nBlockHeight == nBlockHeight) { vinOut = winner.vin; return true; } } return false; } bool CMasternodePayments::AddWinningMasternode(CMasternodePaymentWinner& winnerIn) { uint256 blockHash = 0; if(!darkSendPool.GetBlockHash(blockHash, winnerIn.nBlockHeight-576)) { return false; } winnerIn.score = CalculateScore(blockHash, winnerIn.vin); bool foundBlock = false; BOOST_FOREACH(CMasternodePaymentWinner& winner, vWinning){ if(winner.nBlockHeight == winnerIn.nBlockHeight) { foundBlock = true; if(winner.score < winnerIn.score){ winner.score = winnerIn.score; winner.vin = winnerIn.vin; winner.vchSig = winnerIn.vchSig; return true; } } } // if it's not in the vector if(!foundBlock){ vWinning.push_back(winnerIn); return true; } return false; } void CMasternodePayments::CleanPaymentList() { if(chainActive.Tip() == NULL) return; vector::iterator it; for(it=vWinning.begin();itnHeight - (*it).nBlockHeight > 1000){ if(fDebug) LogPrintf("CMasternodePayments::CleanPaymentList - Removing old masternode payment - block %d\n", (*it).nBlockHeight); vWinning.erase(it); break; } } } int CMasternodePayments::LastPayment(CMasterNode& mn) { if(chainActive.Tip() == NULL) return 0; int ret = mn.GetMasternodeInputAge(); BOOST_FOREACH(CMasternodePaymentWinner& winner, vWinning){ if(winner.vin == mn.vin && chainActive.Tip()->nHeight - winner.nBlockHeight < ret) ret = chainActive.Tip()->nHeight - winner.nBlockHeight; } return ret; } bool CMasternodePayments::ProcessBlock(int nBlockHeight) { if(strMasterPrivKey.empty()) return false; CMasternodePaymentWinner winner; uint256 blockHash = 0; if(!darkSendPool.GetBlockHash(blockHash, nBlockHeight-576)) return false; BOOST_FOREACH(CMasterNode& mn, darkSendMasterNodes) { mn.Check(); if(!mn.IsEnabled()) { continue; } if(LastPayment(mn) < darkSendMasterNodes.size()*.9) continue; uint64_t score = CalculateScore(blockHash, mn.vin); if(score > winner.score){ winner.score = score; winner.nBlockHeight = nBlockHeight; winner.vin = mn.vin; } } if(winner.nBlockHeight == 0) return false; //no masternodes available if(Sign(winner)){ if(AddWinningMasternode(winner)){ Relay(winner); return true; } } return false; } void CMasternodePayments::Relay(CMasternodePaymentWinner& winner) { LOCK(cs_vNodes); BOOST_FOREACH(CNode* pnode, vNodes){ if(!pnode->fRelayTxes) continue; pnode->PushMessage("mnw", winner); } } void CMasternodePayments::Sync(CNode* node) { BOOST_FOREACH(CMasternodePaymentWinner& winner, vWinning) if(winner.nBlockHeight >= chainActive.Tip()->nHeight-10 && winner.nBlockHeight <= chainActive.Tip()->nHeight + 20) node->PushMessage("mnw", winner); } bool CMasternodePayments::SetPrivKey(std::string strPrivKey) { CMasternodePaymentWinner winner; // Test signing successful, proceed strMasterPrivKey = strPrivKey; Sign(winner); if(CheckSignature(winner)){ LogPrintf("CMasternodePayments::SetPrivKey - Successfully initialized as masternode payments master\n"); return true; } else { return false; } }