b4cb1e2610
- mn hash compatibility with 70103 - ignore some requests while syncing - fix locking/initializing in sync - do not ban for old mnw - split budget/governance messages/invs
743 lines
24 KiB
C++
743 lines
24 KiB
C++
// Copyright (c) 2014-2016 The Dash Core developers
|
|
// Distributed under the MIT/X11 software license, see the accompanying
|
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
|
|
#include "masternodeman.h"
|
|
#include "activemasternode.h"
|
|
#include "darksend.h"
|
|
#include "masternode.h"
|
|
#include "masternode-payments.h"
|
|
#include "masternode-sync.h"
|
|
#include "util.h"
|
|
#include "addrman.h"
|
|
#include "spork.h"
|
|
#include <boost/lexical_cast.hpp>
|
|
#include <boost/filesystem.hpp>
|
|
|
|
/** Masternode manager */
|
|
CMasternodeMan mnodeman;
|
|
|
|
struct CompareLastPaid
|
|
{
|
|
bool operator()(const pair<int64_t, CTxIn>& t1,
|
|
const pair<int64_t, CTxIn>& t2) const
|
|
{
|
|
return t1.first < t2.first;
|
|
}
|
|
};
|
|
|
|
struct CompareScoreTxIn
|
|
{
|
|
bool operator()(const pair<int64_t, CTxIn>& t1,
|
|
const pair<int64_t, CTxIn>& t2) const
|
|
{
|
|
return t1.first < t2.first;
|
|
}
|
|
};
|
|
|
|
struct CompareScoreMN
|
|
{
|
|
bool operator()(const pair<int64_t, CMasternode>& t1,
|
|
const pair<int64_t, CMasternode>& t2) const
|
|
{
|
|
return t1.first < t2.first;
|
|
}
|
|
};
|
|
|
|
CMasternodeMan::CMasternodeMan() {
|
|
nDsqCount = 0;
|
|
}
|
|
|
|
bool CMasternodeMan::Add(CMasternode &mn)
|
|
{
|
|
LOCK(cs);
|
|
|
|
if (!mn.IsEnabled() && !mn.IsPreEnabled())
|
|
return false;
|
|
|
|
CMasternode *pmn = Find(mn.vin);
|
|
if (pmn == NULL)
|
|
{
|
|
LogPrint("masternode", "CMasternodeMan: Adding new Masternode %s - %i now\n", mn.addr.ToString(), size() + 1);
|
|
vMasternodes.push_back(mn);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void CMasternodeMan::AskForMN(CNode* pnode, CTxIn &vin)
|
|
{
|
|
std::map<COutPoint, int64_t>::iterator i = mWeAskedForMasternodeListEntry.find(vin.prevout);
|
|
if (i != mWeAskedForMasternodeListEntry.end())
|
|
{
|
|
int64_t t = (*i).second;
|
|
if (GetTime() < t) return; // we've asked recently
|
|
}
|
|
|
|
// ask for the mnb info once from the node that sent mnp
|
|
|
|
LogPrintf("CMasternodeMan::AskForMN - Asking node for missing entry, vin: %s\n", vin.ToString());
|
|
pnode->PushMessage(NetMsgType::DSEG, vin);
|
|
int64_t askAgain = GetTime() + MASTERNODE_MIN_MNP_SECONDS;
|
|
mWeAskedForMasternodeListEntry[vin.prevout] = askAgain;
|
|
}
|
|
|
|
void CMasternodeMan::Check()
|
|
{
|
|
LOCK(cs);
|
|
|
|
BOOST_FOREACH(CMasternode& mn, vMasternodes) {
|
|
mn.Check();
|
|
}
|
|
}
|
|
|
|
void CMasternodeMan::CheckAndRemove(bool forceExpiredRemoval)
|
|
{
|
|
LogPrintf("CMasternodeMan::CheckAndRemove\n");
|
|
|
|
Check();
|
|
|
|
LOCK(cs);
|
|
|
|
//remove inactive and outdated
|
|
vector<CMasternode>::iterator it = vMasternodes.begin();
|
|
while(it != vMasternodes.end()){
|
|
if((*it).activeState == CMasternode::MASTERNODE_REMOVE ||
|
|
(*it).activeState == CMasternode::MASTERNODE_VIN_SPENT ||
|
|
(forceExpiredRemoval && (*it).activeState == CMasternode::MASTERNODE_EXPIRED)) {
|
|
LogPrint("masternode", "CMasternodeMan::CheckAndRemove - Removing %s Masternode %s - %i now\n", (*it).Status(), (*it).addr.ToString(), size() - 1);
|
|
|
|
//erase all of the broadcasts we've seen from this vin
|
|
// -- if we missed a few pings and the node was removed, this will allow is to get it back without them
|
|
// sending a brand new mnb
|
|
map<uint256, CMasternodeBroadcast>::iterator it3 = mapSeenMasternodeBroadcast.begin();
|
|
while(it3 != mapSeenMasternodeBroadcast.end()){
|
|
if((*it3).second.vin == (*it).vin){
|
|
masternodeSync.mapSeenSyncMNB.erase((*it3).first);
|
|
mapSeenMasternodeBroadcast.erase(it3++);
|
|
} else {
|
|
++it3;
|
|
}
|
|
}
|
|
|
|
// allow us to ask for this masternode again if we see another ping
|
|
map<COutPoint, int64_t>::iterator it2 = mWeAskedForMasternodeListEntry.begin();
|
|
while(it2 != mWeAskedForMasternodeListEntry.end()){
|
|
if((*it2).first == (*it).vin.prevout){
|
|
mWeAskedForMasternodeListEntry.erase(it2++);
|
|
} else {
|
|
++it2;
|
|
}
|
|
}
|
|
|
|
it = vMasternodes.erase(it);
|
|
} else {
|
|
++it;
|
|
}
|
|
}
|
|
|
|
// check who's asked for the Masternode list
|
|
map<CNetAddr, int64_t>::iterator it1 = mAskedUsForMasternodeList.begin();
|
|
while(it1 != mAskedUsForMasternodeList.end()){
|
|
if((*it1).second < GetTime()) {
|
|
mAskedUsForMasternodeList.erase(it1++);
|
|
} else {
|
|
++it1;
|
|
}
|
|
}
|
|
|
|
// check who we asked for the Masternode list
|
|
it1 = mWeAskedForMasternodeList.begin();
|
|
while(it1 != mWeAskedForMasternodeList.end()){
|
|
if((*it1).second < GetTime()){
|
|
mWeAskedForMasternodeList.erase(it1++);
|
|
} else {
|
|
++it1;
|
|
}
|
|
}
|
|
|
|
// check which Masternodes we've asked for
|
|
map<COutPoint, int64_t>::iterator it2 = mWeAskedForMasternodeListEntry.begin();
|
|
while(it2 != mWeAskedForMasternodeListEntry.end()){
|
|
if((*it2).second < GetTime()){
|
|
mWeAskedForMasternodeListEntry.erase(it2++);
|
|
} else {
|
|
++it2;
|
|
}
|
|
}
|
|
|
|
// remove expired mapSeenMasternodeBroadcast
|
|
map<uint256, CMasternodeBroadcast>::iterator it3 = mapSeenMasternodeBroadcast.begin();
|
|
while(it3 != mapSeenMasternodeBroadcast.end()){
|
|
if((*it3).second.lastPing.sigTime < GetTime() - MASTERNODE_REMOVAL_SECONDS*2){
|
|
LogPrint("masternode", "CMasternodeMan::CheckAndRemove - Removing expired Masternode broadcast %s\n", (*it3).second.GetHash().ToString());
|
|
masternodeSync.mapSeenSyncMNB.erase((*it3).second.GetHash());
|
|
mapSeenMasternodeBroadcast.erase(it3++);
|
|
} else {
|
|
++it3;
|
|
}
|
|
}
|
|
|
|
// remove expired mapSeenMasternodePing
|
|
map<uint256, CMasternodePing>::iterator it4 = mapSeenMasternodePing.begin();
|
|
while(it4 != mapSeenMasternodePing.end()){
|
|
if((*it4).second.sigTime < GetTime() - MASTERNODE_REMOVAL_SECONDS*2){
|
|
LogPrint("masternode", "CMasternodeMan::CheckAndRemove - Removing expired Masternode ping %s\n", (*it4).second.GetHash().ToString());
|
|
mapSeenMasternodePing.erase(it4++);
|
|
} else {
|
|
++it4;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
void CMasternodeMan::Clear()
|
|
{
|
|
LOCK(cs);
|
|
vMasternodes.clear();
|
|
mAskedUsForMasternodeList.clear();
|
|
mWeAskedForMasternodeList.clear();
|
|
mWeAskedForMasternodeListEntry.clear();
|
|
mapSeenMasternodeBroadcast.clear();
|
|
mapSeenMasternodePing.clear();
|
|
nDsqCount = 0;
|
|
}
|
|
|
|
int CMasternodeMan::CountEnabled(int protocolVersion)
|
|
{
|
|
int i = 0;
|
|
protocolVersion = protocolVersion == -1 ? mnpayments.GetMinMasternodePaymentsProto() : protocolVersion;
|
|
|
|
BOOST_FOREACH(CMasternode& mn, vMasternodes) {
|
|
mn.Check();
|
|
if(mn.protocolVersion < protocolVersion || !mn.IsEnabled()) continue;
|
|
i++;
|
|
}
|
|
|
|
return i;
|
|
}
|
|
|
|
void CMasternodeMan::DsegUpdate(CNode* pnode)
|
|
{
|
|
LOCK(cs);
|
|
|
|
if(Params().NetworkIDString() == CBaseChainParams::MAIN) {
|
|
if(!(pnode->addr.IsRFC1918() || pnode->addr.IsLocal())){
|
|
std::map<CNetAddr, int64_t>::iterator it = mWeAskedForMasternodeList.find(pnode->addr);
|
|
if (it != mWeAskedForMasternodeList.end())
|
|
{
|
|
if (GetTime() < (*it).second) {
|
|
LogPrintf("dseg - we already asked %s for the list; skipping...\n", pnode->addr.ToString());
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
pnode->PushMessage(NetMsgType::DSEG, CTxIn());
|
|
int64_t askAgain = GetTime() + MASTERNODES_DSEG_SECONDS;
|
|
mWeAskedForMasternodeList[pnode->addr] = askAgain;
|
|
}
|
|
|
|
CMasternode *CMasternodeMan::Find(const CScript &payee)
|
|
{
|
|
LOCK(cs);
|
|
CScript payee2;
|
|
|
|
BOOST_FOREACH(CMasternode& mn, vMasternodes)
|
|
{
|
|
payee2 = GetScriptForDestination(mn.pubkey.GetID());
|
|
if(payee2 == payee)
|
|
return &mn;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
CMasternode *CMasternodeMan::Find(const CTxIn &vin)
|
|
{
|
|
LOCK(cs);
|
|
|
|
BOOST_FOREACH(CMasternode& mn, vMasternodes)
|
|
{
|
|
if(mn.vin.prevout == vin.prevout)
|
|
return &mn;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
CMasternode *CMasternodeMan::Find(const CPubKey &pubKeyMasternode)
|
|
{
|
|
LOCK(cs);
|
|
|
|
BOOST_FOREACH(CMasternode& mn, vMasternodes)
|
|
{
|
|
if(mn.pubkey2 == pubKeyMasternode)
|
|
return &mn;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// Deterministically select the oldest/best masternode to pay on the network
|
|
//
|
|
CMasternode* CMasternodeMan::GetNextMasternodeInQueueForPayment(int nBlockHeight, bool fFilterSigTime, int& nCount)
|
|
{
|
|
LOCK(cs);
|
|
|
|
CMasternode *pBestMasternode = NULL;
|
|
std::vector<pair<int64_t, CTxIn> > vecMasternodeLastPaid;
|
|
|
|
/*
|
|
Make a vector with all of the last paid times
|
|
*/
|
|
|
|
int nMnCount = CountEnabled();
|
|
BOOST_FOREACH(CMasternode &mn, vMasternodes)
|
|
{
|
|
mn.Check();
|
|
if(!mn.IsEnabled()) continue;
|
|
|
|
// //check protocol version
|
|
if(mn.protocolVersion < mnpayments.GetMinMasternodePaymentsProto()) continue;
|
|
|
|
//it's in the list (up to 8 entries ahead of current block to allow propagation) -- so let's skip it
|
|
if(mnpayments.IsScheduled(mn, nBlockHeight)) continue;
|
|
|
|
//it's too new, wait for a cycle
|
|
if(fFilterSigTime && mn.sigTime + (nMnCount*2.6*60) > GetAdjustedTime()) continue;
|
|
|
|
//make sure it has as many confirmations as there are masternodes
|
|
if(mn.GetMasternodeInputAge() < nMnCount) continue;
|
|
|
|
vecMasternodeLastPaid.push_back(make_pair(mn.SecondsSincePayment(), mn.vin));
|
|
}
|
|
|
|
nCount = (int)vecMasternodeLastPaid.size();
|
|
|
|
//when the network is in the process of upgrading, don't penalize nodes that recently restarted
|
|
if(fFilterSigTime && nCount < nMnCount/3) return GetNextMasternodeInQueueForPayment(nBlockHeight, false, nCount);
|
|
|
|
// Sort them high to low
|
|
sort(vecMasternodeLastPaid.rbegin(), vecMasternodeLastPaid.rend(), CompareLastPaid());
|
|
|
|
// Look at 1/10 of the oldest nodes (by last payment), calculate their scores and pay the best one
|
|
// -- This doesn't look at who is being paid in the +8-10 blocks, allowing for double payments very rarely
|
|
// -- 1/100 payments should be a double payment on mainnet - (1/(3000/10))*2
|
|
// -- (chance per block * chances before IsScheduled will fire)
|
|
int nTenthNetwork = CountEnabled()/10;
|
|
int nCountTenth = 0;
|
|
arith_uint256 nHigh = 0;
|
|
BOOST_FOREACH (PAIRTYPE(int64_t, CTxIn)& s, vecMasternodeLastPaid){
|
|
CMasternode* pmn = Find(s.second);
|
|
if(!pmn) break;
|
|
|
|
arith_uint256 n = UintToArith256(pmn->CalculateScore(1, nBlockHeight-100));
|
|
if(n > nHigh){
|
|
nHigh = n;
|
|
pBestMasternode = pmn;
|
|
}
|
|
nCountTenth++;
|
|
if(nCountTenth >= nTenthNetwork) break;
|
|
}
|
|
return pBestMasternode;
|
|
}
|
|
|
|
CMasternode *CMasternodeMan::FindRandomNotInVec(std::vector<CTxIn> &vecToExclude, int nProtocolVersion)
|
|
{
|
|
LOCK(cs);
|
|
|
|
nProtocolVersion = nProtocolVersion == -1 ? mnpayments.GetMinMasternodePaymentsProto() : nProtocolVersion;
|
|
|
|
int nCountEnabled = CountEnabled(nProtocolVersion);
|
|
int nCountNotExcluded = nCountEnabled - vecToExclude.size();
|
|
|
|
LogPrintf("CMasternodeMan::FindRandomNotInVec -- %d enabled masternodes, %d masternodes aren't yet exluded\n", nCountEnabled, nCountNotExcluded);
|
|
if(nCountNotExcluded < 1) return NULL;
|
|
|
|
std::vector<CMasternode> vMasternodesShuffled = vMasternodes;
|
|
std::random_shuffle(vMasternodesShuffled.begin(), vMasternodesShuffled.end(), GetRandInt);
|
|
bool fExclude;
|
|
|
|
BOOST_FOREACH(CMasternode &mn, vMasternodesShuffled) {
|
|
if(mn.protocolVersion < nProtocolVersion || !mn.IsEnabled()) continue;
|
|
fExclude = false;
|
|
BOOST_FOREACH(CTxIn &txinToExclude, vecToExclude) {
|
|
if(mn.vin.prevout == txinToExclude.prevout) {
|
|
fExclude = true;
|
|
break;
|
|
}
|
|
}
|
|
if(fExclude) continue;
|
|
// found the one not in vecToExclude
|
|
return Find(mn.vin);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
CMasternode* CMasternodeMan::GetCurrentMasterNode(int mod, int64_t nBlockHeight, int minProtocol)
|
|
{
|
|
int64_t score = 0;
|
|
CMasternode* winner = NULL;
|
|
|
|
// scan for winner
|
|
BOOST_FOREACH(CMasternode& mn, vMasternodes) {
|
|
mn.Check();
|
|
if(mn.protocolVersion < minProtocol || !mn.IsEnabled()) continue;
|
|
|
|
// calculate the score for each Masternode
|
|
uint256 n = mn.CalculateScore(mod, nBlockHeight);
|
|
int64_t n2 = UintToArith256(n).GetCompact(false);
|
|
|
|
// determine the winner
|
|
if(n2 > score){
|
|
score = n2;
|
|
winner = &mn;
|
|
}
|
|
}
|
|
|
|
return winner;
|
|
}
|
|
|
|
int CMasternodeMan::GetMasternodeRank(const CTxIn& vin, int64_t nBlockHeight, int minProtocol, bool fOnlyActive)
|
|
{
|
|
std::vector<pair<int64_t, CTxIn> > vecMasternodeScores;
|
|
|
|
//make sure we know about this block
|
|
uint256 hash = uint256();
|
|
if(!GetBlockHash(hash, nBlockHeight)) return -1;
|
|
|
|
// scan for winner
|
|
BOOST_FOREACH(CMasternode& mn, vMasternodes) {
|
|
if(mn.protocolVersion < minProtocol) continue;
|
|
if(fOnlyActive) {
|
|
mn.Check();
|
|
if(!mn.IsEnabled()) continue;
|
|
}
|
|
uint256 n = mn.CalculateScore(1, nBlockHeight);
|
|
int64_t n2 = UintToArith256(n).GetCompact(false);
|
|
|
|
vecMasternodeScores.push_back(make_pair(n2, mn.vin));
|
|
}
|
|
|
|
sort(vecMasternodeScores.rbegin(), vecMasternodeScores.rend(), CompareScoreTxIn());
|
|
|
|
int rank = 0;
|
|
BOOST_FOREACH (PAIRTYPE(int64_t, CTxIn)& s, vecMasternodeScores){
|
|
rank++;
|
|
if(s.second.prevout == vin.prevout) {
|
|
return rank;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
std::vector<pair<int, CMasternode> > CMasternodeMan::GetMasternodeRanks(int64_t nBlockHeight, int minProtocol)
|
|
{
|
|
std::vector<pair<int64_t, CMasternode> > vecMasternodeScores;
|
|
std::vector<pair<int, CMasternode> > vecMasternodeRanks;
|
|
|
|
//make sure we know about this block
|
|
uint256 hash = uint256();
|
|
if(!GetBlockHash(hash, nBlockHeight)) return vecMasternodeRanks;
|
|
|
|
// scan for winner
|
|
BOOST_FOREACH(CMasternode& mn, vMasternodes) {
|
|
|
|
mn.Check();
|
|
|
|
if(mn.protocolVersion < minProtocol) continue;
|
|
if(!mn.IsEnabled()) {
|
|
continue;
|
|
}
|
|
|
|
uint256 n = mn.CalculateScore(1, nBlockHeight);
|
|
int64_t n2 = UintToArith256(n).GetCompact(false);
|
|
|
|
vecMasternodeScores.push_back(make_pair(n2, mn));
|
|
}
|
|
|
|
sort(vecMasternodeScores.rbegin(), vecMasternodeScores.rend(), CompareScoreMN());
|
|
|
|
int rank = 0;
|
|
BOOST_FOREACH (PAIRTYPE(int64_t, CMasternode)& s, vecMasternodeScores){
|
|
rank++;
|
|
vecMasternodeRanks.push_back(make_pair(rank, s.second));
|
|
}
|
|
|
|
return vecMasternodeRanks;
|
|
}
|
|
|
|
CMasternode* CMasternodeMan::GetMasternodeByRank(int nRank, int64_t nBlockHeight, int minProtocol, bool fOnlyActive)
|
|
{
|
|
std::vector<pair<int64_t, CTxIn> > vecMasternodeScores;
|
|
|
|
// scan for winner
|
|
BOOST_FOREACH(CMasternode& mn, vMasternodes) {
|
|
|
|
if(mn.protocolVersion < minProtocol) continue;
|
|
if(fOnlyActive) {
|
|
mn.Check();
|
|
if(!mn.IsEnabled()) continue;
|
|
}
|
|
|
|
uint256 n = mn.CalculateScore(1, nBlockHeight);
|
|
int64_t n2 = UintToArith256(n).GetCompact(false);
|
|
|
|
vecMasternodeScores.push_back(make_pair(n2, mn.vin));
|
|
}
|
|
|
|
sort(vecMasternodeScores.rbegin(), vecMasternodeScores.rend(), CompareScoreTxIn());
|
|
|
|
int rank = 0;
|
|
BOOST_FOREACH (PAIRTYPE(int64_t, CTxIn)& s, vecMasternodeScores){
|
|
rank++;
|
|
if(rank == nRank) {
|
|
return Find(s.second);
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void CMasternodeMan::InitDummyScriptPubkey() {
|
|
CKey secret;
|
|
secret.MakeNewKey(true);
|
|
|
|
CPubKey pubkey = secret.GetPubKey();
|
|
assert(secret.VerifyPubKey(pubkey));
|
|
|
|
if (pubkey.IsValid()) {
|
|
CKeyID keyID = pubkey.GetID();
|
|
LogPrintf("Generated dummyScriptPubkey: address %s privkey %s\n", CBitcoinAddress(keyID).ToString(), CBitcoinSecret(secret).ToString());
|
|
dummyScriptPubkey = GetScriptForDestination(keyID);
|
|
} else {
|
|
LogPrintf("CMasternodeMan::InitDummyScriptPubkey - ERROR: can't assign dummyScriptPubkey\n");
|
|
}
|
|
}
|
|
|
|
void CMasternodeMan::ProcessMasternodeConnections()
|
|
{
|
|
//we don't care about this for regtest
|
|
if(Params().NetworkIDString() == CBaseChainParams::REGTEST) return;
|
|
|
|
LOCK(cs_vNodes);
|
|
BOOST_FOREACH(CNode* pnode, vNodes) {
|
|
if(pnode->fMasternode) {
|
|
if(darkSendPool.pSubmittedToMasternode != NULL && pnode->addr == darkSendPool.pSubmittedToMasternode->addr) continue;
|
|
LogPrintf("Closing Masternode connection %s \n", pnode->addr.ToString());
|
|
pnode->fDisconnect = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CDataStream& vRecv)
|
|
{
|
|
|
|
if(fLiteMode) return; //disable all Darksend/Masternode related functionality
|
|
if(!masternodeSync.IsBlockchainSynced()) return;
|
|
|
|
LOCK(cs_process_message);
|
|
|
|
if (strCommand == NetMsgType::MNANNOUNCE) { //Masternode Broadcast
|
|
CMasternodeBroadcast mnb;
|
|
vRecv >> mnb;
|
|
|
|
int nDos = 0;
|
|
|
|
if (CheckMnbAndUpdateMasternodeList(mnb, nDos)) {
|
|
// use announced Masternode as a peer
|
|
addrman.Add(CAddress(mnb.addr), pfrom->addr, 2*60*60);
|
|
} else {
|
|
if(nDos > 0) Misbehaving(pfrom->GetId(), nDos);
|
|
}
|
|
}
|
|
|
|
else if (strCommand == NetMsgType::MNPING) { //Masternode Ping
|
|
CMasternodePing mnp;
|
|
vRecv >> mnp;
|
|
|
|
LogPrint("masternode", "mnp - Masternode ping, vin: %s\n", mnp.vin.ToString());
|
|
|
|
if(mapSeenMasternodePing.count(mnp.GetHash())) return; //seen
|
|
mapSeenMasternodePing.insert(make_pair(mnp.GetHash(), mnp));
|
|
|
|
LogPrint("masternode", "mnp - Masternode ping, vin: %s new\n", mnp.vin.ToString());
|
|
|
|
int nDos = 0;
|
|
if(mnp.CheckAndUpdate(nDos)) return;
|
|
|
|
if(nDos > 0) {
|
|
// if anything significant failed, mark that node
|
|
Misbehaving(pfrom->GetId(), nDos);
|
|
} else {
|
|
// if nothing significant failed, search existing Masternode list
|
|
CMasternode* pmn = Find(mnp.vin);
|
|
// if it's known, don't ask for the mnb, just return
|
|
if(pmn != NULL) return;
|
|
}
|
|
|
|
// something significant is broken or mn is unknown,
|
|
// we might have to ask for a masternode entry once
|
|
AskForMN(pfrom, mnp.vin);
|
|
|
|
} else if (strCommand == NetMsgType::DSEG) { //Get Masternode list or specific entry
|
|
|
|
// ignore such request until we are fully synced
|
|
if (!masternodeSync.IsSynced()) return;
|
|
|
|
CTxIn vin;
|
|
vRecv >> vin;
|
|
|
|
LogPrint("masternode", "dseg - Masternode list, vin: %s\n", vin.ToString());
|
|
|
|
if(vin == CTxIn()) { //only should ask for this once
|
|
//local network
|
|
bool isLocal = (pfrom->addr.IsRFC1918() || pfrom->addr.IsLocal());
|
|
|
|
if(!isLocal && Params().NetworkIDString() == CBaseChainParams::MAIN) {
|
|
std::map<CNetAddr, int64_t>::iterator i = mAskedUsForMasternodeList.find(pfrom->addr);
|
|
if (i != mAskedUsForMasternodeList.end()){
|
|
int64_t t = (*i).second;
|
|
if (GetTime() < t) {
|
|
Misbehaving(pfrom->GetId(), 34);
|
|
LogPrintf("dseg - peer already asked me for the list\n");
|
|
return;
|
|
}
|
|
}
|
|
int64_t askAgain = GetTime() + MASTERNODES_DSEG_SECONDS;
|
|
mAskedUsForMasternodeList[pfrom->addr] = askAgain;
|
|
}
|
|
} //else, asking for a specific node which is ok
|
|
|
|
|
|
int nInvCount = 0;
|
|
|
|
BOOST_FOREACH(CMasternode& mn, vMasternodes) {
|
|
if(mn.addr.IsRFC1918() || mn.addr.IsLocal()) continue; //local network
|
|
|
|
if(mn.IsEnabled()) {
|
|
if(vin == CTxIn() || vin == mn.vin){
|
|
LogPrint("masternode", "dseg - Sending Masternode entry - %s \n", mn.addr.ToString());
|
|
CMasternodeBroadcast mnb = CMasternodeBroadcast(mn);
|
|
uint256 hash = mnb.GetHash();
|
|
pfrom->PushInventory(CInv(MSG_MASTERNODE_ANNOUNCE, hash));
|
|
nInvCount++;
|
|
|
|
if(!mapSeenMasternodeBroadcast.count(hash)) mapSeenMasternodeBroadcast.insert(make_pair(hash, mnb));
|
|
|
|
if(vin == mn.vin) {
|
|
LogPrintf("dseg - Sent 1 Masternode entries to %s\n", pfrom->addr.ToString());
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if(vin == CTxIn()) {
|
|
pfrom->PushMessage(NetMsgType::SYNCSTATUSCOUNT, MASTERNODE_SYNC_LIST, nInvCount);
|
|
LogPrintf("dseg - Sent %d Masternode entries to %s\n", nInvCount, pfrom->addr.ToString());
|
|
}
|
|
}
|
|
}
|
|
|
|
void CMasternodeMan::Remove(CTxIn vin)
|
|
{
|
|
LOCK(cs);
|
|
|
|
vector<CMasternode>::iterator it = vMasternodes.begin();
|
|
while(it != vMasternodes.end()){
|
|
if((*it).vin == vin){
|
|
LogPrint("masternode", "CMasternodeMan: Removing Masternode %s - %i now\n", (*it).addr.ToString(), size() - 1);
|
|
vMasternodes.erase(it);
|
|
break;
|
|
}
|
|
++it;
|
|
}
|
|
}
|
|
|
|
std::string CMasternodeMan::ToString() const
|
|
{
|
|
std::ostringstream info;
|
|
|
|
info << "Masternodes: " << (int)vMasternodes.size() <<
|
|
", peers who asked us for Masternode list: " << (int)mAskedUsForMasternodeList.size() <<
|
|
", peers we asked for Masternode list: " << (int)mWeAskedForMasternodeList.size() <<
|
|
", entries in Masternode list we asked for: " << (int)mWeAskedForMasternodeListEntry.size() <<
|
|
", nDsqCount: " << (int)nDsqCount;
|
|
|
|
return info.str();
|
|
}
|
|
|
|
int CMasternodeMan::GetEstimatedMasternodes(int nBlock)
|
|
{
|
|
/*
|
|
Masternodes = (Coins/1000)*X on average
|
|
|
|
*X = nPercentage, starting at 0.52
|
|
nPercentage goes up 0.01 each period
|
|
Period starts at 35040, which has exponential slowing growth
|
|
|
|
*/
|
|
|
|
int nPercentage = 52; //0.52
|
|
int nPeriod = 35040;
|
|
int nCollateral = 1000;
|
|
|
|
for(int i = nPeriod; i <= nBlock; i += nPeriod)
|
|
{
|
|
nPercentage++;
|
|
nPeriod*=2;
|
|
}
|
|
return (GetTotalCoinEstimate(nBlock)/100*nPercentage/nCollateral);
|
|
}
|
|
|
|
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 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;
|
|
}
|