neobytes/src/masternode.cpp
UdjinM6 c3b950d457 fix mn anounce: (#813)
- every node should check for "pre-enabled" status of a newly added mn to relay message further (was "enabled" which is wrong - if node is enabled, that's not the first announce, so no need to relay it because most likely we were the one who asked for that mn directly via dseg)
- we should not add ourselves to mn list if announce message has outdated protocol version (report this in log)
- we should remove ourselves from saved list if we start updated mn for the first time and just loaded old list from mncache.dat
2016-05-27 08:24:44 +02:00

750 lines
26 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 "consensus/validation.h"
#include "darksend.h"
#include "masternode.h"
#include "masternode-payments.h"
#include "masternode-sync.h"
#include "masternodeman.h"
#include "util.h"
#include "sync.h"
#include "addrman.h"
#include <boost/lexical_cast.hpp>
// keep track of the scanning errors I've seen
map<uint256, int> mapSeenMasternodeScanningErrors;
// cache block hashes as we calculate them
std::map<int64_t, uint256> mapCacheBlockHashes;
//Get the last hash that matches the modulus given. Processed in reverse order
bool GetBlockHash(uint256& hash, int nBlockHeight)
{
LOCK(cs_main);
if (chainActive.Tip() == NULL) return false;
if(nBlockHeight == 0)
nBlockHeight = chainActive.Tip()->nHeight;
if(mapCacheBlockHashes.count(nBlockHeight)){
hash = mapCacheBlockHashes[nBlockHeight];
return true;
}
const CBlockIndex *BlockLastSolved = chainActive.Tip();
const CBlockIndex *BlockReading = chainActive.Tip();
if (BlockLastSolved == NULL || BlockLastSolved->nHeight == 0 || chainActive.Tip()->nHeight+1 < nBlockHeight) return false;
int nBlocksAgo = 0;
if(nBlockHeight > 0) nBlocksAgo = (chainActive.Tip()->nHeight+1)-nBlockHeight;
assert(nBlocksAgo >= 0);
int n = 0;
for (unsigned int i = 1; BlockReading && BlockReading->nHeight > 0; i++) {
if(n >= nBlocksAgo){
hash = BlockReading->GetBlockHash();
mapCacheBlockHashes[nBlockHeight] = hash;
return true;
}
n++;
if (BlockReading->pprev == NULL) { assert(BlockReading); break; }
BlockReading = BlockReading->pprev;
}
return false;
}
CMasternode::CMasternode()
{
LOCK(cs);
vin = CTxIn();
addr = CService();
pubkey = CPubKey();
pubkey2 = CPubKey();
vchSig = std::vector<unsigned char>();
activeState = MASTERNODE_ENABLED;
sigTime = GetAdjustedTime();
lastPing = CMasternodePing();
cacheInputAge = 0;
cacheInputAgeBlock = 0;
unitTest = false;
allowFreeTx = true;
protocolVersion = PROTOCOL_VERSION;
nLastDsq = 0;
nScanningErrorCount = 0;
nLastScanningErrorBlockHeight = 0;
lastTimeChecked = 0;
}
CMasternode::CMasternode(const CMasternode& other)
{
LOCK(cs);
vin = other.vin;
addr = other.addr;
pubkey = other.pubkey;
pubkey2 = other.pubkey2;
vchSig = other.vchSig;
activeState = other.activeState;
sigTime = other.sigTime;
lastPing = other.lastPing;
cacheInputAge = other.cacheInputAge;
cacheInputAgeBlock = other.cacheInputAgeBlock;
unitTest = other.unitTest;
allowFreeTx = other.allowFreeTx;
protocolVersion = other.protocolVersion;
nLastDsq = other.nLastDsq;
nScanningErrorCount = other.nScanningErrorCount;
nLastScanningErrorBlockHeight = other.nLastScanningErrorBlockHeight;
lastTimeChecked = 0;
}
CMasternode::CMasternode(const CMasternodeBroadcast& mnb)
{
LOCK(cs);
vin = mnb.vin;
addr = mnb.addr;
pubkey = mnb.pubkey;
pubkey2 = mnb.pubkey2;
vchSig = mnb.vchSig;
activeState = MASTERNODE_ENABLED;
sigTime = mnb.sigTime;
lastPing = mnb.lastPing;
cacheInputAge = 0;
cacheInputAgeBlock = 0;
unitTest = false;
allowFreeTx = true;
protocolVersion = mnb.protocolVersion;
nLastDsq = mnb.nLastDsq;
nScanningErrorCount = 0;
nLastScanningErrorBlockHeight = 0;
lastTimeChecked = 0;
}
//
// When a new masternode broadcast is sent, update our information
//
bool CMasternode::UpdateFromNewBroadcast(CMasternodeBroadcast& mnb)
{
if(mnb.sigTime > sigTime) {
pubkey2 = mnb.pubkey2;
sigTime = mnb.sigTime;
vchSig = mnb.vchSig;
protocolVersion = mnb.protocolVersion;
addr = mnb.addr;
lastTimeChecked = 0;
int nDos = 0;
if(mnb.lastPing == CMasternodePing() || (mnb.lastPing != CMasternodePing() && mnb.lastPing.CheckAndUpdate(nDos, false))) {
lastPing = mnb.lastPing;
mnodeman.mapSeenMasternodePing.insert(make_pair(lastPing.GetHash(), lastPing));
}
return true;
}
return false;
}
//
// 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)
{
{
LOCK(cs_main);
if(chainActive.Tip() == NULL) return uint256();
}
uint256 hash = uint256();
uint256 aux = ArithToUint256(UintToArith256(vin.prevout.hash) + vin.prevout.n);
if(!GetBlockHash(hash, nBlockHeight)) {
LogPrintf("CalculateScore ERROR - nHeight %d - Returned 0\n", nBlockHeight);
return uint256();
}
CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
ss << hash;
arith_uint256 hash2 = UintToArith256(ss.GetHash());
CHashWriter ss2(SER_GETHASH, PROTOCOL_VERSION);
ss2 << hash;
ss2 << aux;
arith_uint256 hash3 = UintToArith256(ss2.GetHash());
arith_uint256 r = (hash3 > hash2 ? hash3 - hash2 : hash2 - hash3);
return ArithToUint256(r);
}
void CMasternode::Check(bool forceCheck)
{
if(ShutdownRequested()) return;
if(!forceCheck && (GetTime() - lastTimeChecked < MASTERNODE_CHECK_SECONDS)) return;
lastTimeChecked = GetTime();
//once spent, stop doing the checks
if(activeState == MASTERNODE_VIN_SPENT) return;
// If there are no pings for quite a long time ...
if(!IsPingedWithin(MASTERNODE_REMOVAL_SECONDS)
// or doesn't meet payments requirements ...
|| protocolVersion < mnpayments.GetMinMasternodePaymentsProto()
// or it's our own node and we just updated it to the new protocol but we are still waiting for activation -
|| (pubkey2 == activeMasternode.pubKeyMasternode && protocolVersion < PROTOCOL_VERSION)) {
// remove it from the list
activeState = MASTERNODE_REMOVE;
return;
}
if(!IsPingedWithin(MASTERNODE_EXPIRATION_SECONDS)){
activeState = MASTERNODE_EXPIRED;
return;
}
if(lastPing.sigTime - sigTime < MASTERNODE_MIN_MNP_SECONDS){
activeState = MASTERNODE_PRE_ENABLED;
return;
}
if(!unitTest){
CValidationState state;
CMutableTransaction tx = CMutableTransaction();
CTxOut vout = CTxOut(999.99*COIN, darkSendPool.collateralPubKey);
tx.vin.push_back(vin);
tx.vout.push_back(vout);
{
TRY_LOCK(cs_main, lockMain);
if(!lockMain) return;
if(!AcceptToMemoryPool(mempool, state, CTransaction(tx), false, NULL, false, true, true)){
activeState = MASTERNODE_VIN_SPENT;
return;
}
}
}
activeState = MASTERNODE_ENABLED; // OK
}
int64_t CMasternode::SecondsSincePayment() {
CScript pubkeyScript;
pubkeyScript = GetScriptForDestination(pubkey.GetID());
int64_t sec = (GetAdjustedTime() - GetLastPaid());
int64_t month = 60*60*24*30;
if(sec < month) return sec; //if it's less than 30 days, give seconds
CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
ss << vin;
ss << sigTime;
uint256 hash = ss.GetHash();
// return some deterministic value for unknown/unpaid but force it to be more than 30 days old
return month + UintToArith256(hash).GetCompact(false);
}
int64_t CMasternode::GetLastPaid() {
CBlockIndex *pindexPrev = NULL;
{
LOCK(cs_main);
pindexPrev = chainActive.Tip();
if(!pindexPrev) return 0;
}
CScript mnpayee;
mnpayee = GetScriptForDestination(pubkey.GetID());
CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
ss << vin;
ss << sigTime;
uint256 hash = ss.GetHash();
// use a deterministic offset to break a tie -- 2.5 minutes
int64_t nOffset = UintToArith256(hash).GetCompact(false) % 150;
const CBlockIndex *BlockReading = pindexPrev;
int nMnCount = mnodeman.CountEnabled()*1.25;
int n = 0;
for (unsigned int i = 1; BlockReading && BlockReading->nHeight > 0; i++) {
if(n >= nMnCount){
return 0;
}
n++;
if(mnpayments.mapMasternodeBlocks.count(BlockReading->nHeight)){
/*
Search for this payee, with at least 2 votes. This will aid in consensus allowing the network
to converge on the same payees quickly, then keep the same schedule.
*/
if(mnpayments.mapMasternodeBlocks[BlockReading->nHeight].HasPayeeWithVotes(mnpayee, 2)){
return BlockReading->nTime + nOffset;
}
}
if (BlockReading->pprev == NULL) { assert(BlockReading); break; }
BlockReading = BlockReading->pprev;
}
return 0;
}
CMasternodeBroadcast::CMasternodeBroadcast()
{
vin = CTxIn();
addr = CService();
pubkey = CPubKey();
pubkey2 = CPubKey();
vchSig = std::vector<unsigned char>();
activeState = MASTERNODE_ENABLED;
sigTime = GetAdjustedTime();
lastPing = CMasternodePing();
cacheInputAge = 0;
cacheInputAgeBlock = 0;
unitTest = false;
allowFreeTx = true;
protocolVersion = PROTOCOL_VERSION;
nLastDsq = 0;
nScanningErrorCount = 0;
nLastScanningErrorBlockHeight = 0;
}
CMasternodeBroadcast::CMasternodeBroadcast(CService newAddr, CTxIn newVin, CPubKey newPubkey, CPubKey newPubkey2, int protocolVersionIn)
{
vin = newVin;
addr = newAddr;
pubkey = newPubkey;
pubkey2 = newPubkey2;
vchSig = std::vector<unsigned char>();
activeState = MASTERNODE_ENABLED;
sigTime = GetAdjustedTime();
lastPing = CMasternodePing();
cacheInputAge = 0;
cacheInputAgeBlock = 0;
unitTest = false;
allowFreeTx = true;
protocolVersion = protocolVersionIn;
nLastDsq = 0;
nScanningErrorCount = 0;
nLastScanningErrorBlockHeight = 0;
}
CMasternodeBroadcast::CMasternodeBroadcast(const CMasternode& mn)
{
vin = mn.vin;
addr = mn.addr;
pubkey = mn.pubkey;
pubkey2 = mn.pubkey2;
vchSig = mn.vchSig;
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)
{
// make sure signature isn't in the future (past is OK)
if (sigTime > GetAdjustedTime() + 60 * 60) {
LogPrintf("CMasternodeBroadcast::CheckAndUpdate - Signature rejected, too far into the future %s\n", vin.ToString());
nDos = 1;
return false;
}
// incorrect ping or its sigTime
if(lastPing == CMasternodePing() || !lastPing.CheckAndUpdate(nDos, false, true))
return false;
std::string vchPubKey(pubkey.begin(), pubkey.end());
std::string vchPubKey2(pubkey2.begin(), pubkey2.end());
std::string strMessage = addr.ToString() + boost::lexical_cast<std::string>(sigTime) + vchPubKey + vchPubKey2 + boost::lexical_cast<std::string>(protocolVersion);
if(protocolVersion < mnpayments.GetMinMasternodePaymentsProto()) {
LogPrintf("CMasternodeBroadcast::CheckAndUpdate - ignoring outdated Masternode %s protocol version %d\n", vin.ToString(), protocolVersion);
return false;
}
CScript pubkeyScript;
pubkeyScript = GetScriptForDestination(pubkey.GetID());
if(pubkeyScript.size() != 25) {
LogPrintf("CMasternodeBroadcast::CheckAndUpdate - pubkey the wrong size\n");
nDos = 100;
return false;
}
CScript pubkeyScript2;
pubkeyScript2 = GetScriptForDestination(pubkey2.GetID());
if(pubkeyScript2.size() != 25) {
LogPrintf("CMasternodeBroadcast::CheckAndUpdate - pubkey2 the wrong size\n");
nDos = 100;
return false;
}
if(!vin.scriptSig.empty()) {
LogPrintf("CMasternodeBroadcast::CheckAndUpdate - Ignore Not Empty ScriptSig %s\n",vin.ToString());
return false;
}
std::string errorMessage = "";
if(!darkSendSigner.VerifyMessage(pubkey, vchSig, strMessage, errorMessage)){
LogPrintf("CMasternodeBroadcast::CheckAndUpdate - Got bad Masternode address signature\n");
nDos = 100;
return false;
}
int mainnetDefaultPort = Params(CBaseChainParams::MAIN).GetDefaultPort();
if(Params().NetworkIDString() == CBaseChainParams::MAIN) {
if(addr.GetPort() != mainnetDefaultPort) return false;
} else if(addr.GetPort() == mainnetDefaultPort) return false;
//search existing Masternode list, this is where we update existing Masternodes with new mnb broadcasts
CMasternode* pmn = mnodeman.Find(vin);
// no such masternode, nothing to update
if(pmn == NULL) return true;
// this broadcast is older or equal than the one that we already have - it's bad and should never happen
// unless someone is doing something fishy
// (mapSeenMasternodeBroadcast in CMasternodeMan::ProcessMessage should filter legit duplicates)
if(pmn->sigTime >= sigTime) {
LogPrintf("CMasternodeBroadcast::CheckAndUpdate - Bad sigTime %d for Masternode %20s %105s (existing broadcast is at %d)\n",
sigTime, addr.ToString(), vin.ToString(), pmn->sigTime);
return false;
}
// masternode is not enabled yet/already, nothing to update
if(!pmn->IsEnabled()) return true;
// mn.pubkey = pubkey, IsVinAssociatedWithPubkey is validated once below,
// after that they just need to match
if(pmn->pubkey == pubkey && !pmn->IsBroadcastedWithin(MASTERNODE_MIN_MNB_SECONDS)) {
//take the newest entry
LogPrintf("CMasternodeBroadcast::CheckAndUpdate - Got updated entry for %s\n", addr.ToString());
if(pmn->UpdateFromNewBroadcast((*this))){
pmn->Check();
// normally masternode should be in pre-enabled status after update, if not - do not relay
if(pmn->IsPreEnabled()) Relay();
}
masternodeSync.AddedMasternodeList(GetHash());
}
return true;
}
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;
// incorrect ping or its sigTime
if(lastPing == CMasternodePing() || !lastPing.CheckAndUpdate(nDos, false, true))
return false;
// 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 (pre)enabled
if(pmn->IsEnabled() || pmn->IsPreEnabled()) return true;
// if it's not (pre)enabled, remove old MN first and continue
else mnodeman.Remove(pmn->vin);
}
if(GetInputAge(vin) < Params().GetConsensus().nMasternodeMinimumConfirmations){
LogPrintf("CMasternodeBroadcast::CheckInputsAndAdd - Input must have at least %d confirmations\n", Params().GetConsensus().nMasternodeMinimumConfirmations);
// maybe we miss few blocks, let this mnb to be checked again later
mnodeman.mapSeenMasternodeBroadcast.erase(GetHash());
masternodeSync.mapSeenSyncMNB.erase(GetHash());
return false;
}
CValidationState state;
CMutableTransaction tx = CMutableTransaction();
CTxOut vout = CTxOut(999.99*COIN, darkSendPool.collateralPubKey);
tx.vin.push_back(vin);
tx.vout.push_back(vout);
{
TRY_LOCK(cs_main, lockMain);
if(!lockMain) {
// not mnb fault, let it to be checked again later
mnodeman.mapSeenMasternodeBroadcast.erase(GetHash());
masternodeSync.mapSeenSyncMNB.erase(GetHash());
return false;
}
if(!AcceptToMemoryPool(mempool, state, CTransaction(tx), false, NULL, false, true, true)) {
//set nDos
LogPrint("masternode", "CMasternodeBroadcast::CheckInputsAndAdd - Failed to accepted Masternode entry tx to mempool - %s\n", tx.ToString());
state.IsInvalid(nDos);
return false;
}
}
LogPrint("masternode", "CMasternodeBroadcast::CheckInputsAndAdd - Accepted Masternode entry to mempool (dry-run mode)\n");
// 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("CMasternodeMan::CheckInputsAndAdd - Got mismatched pubkey and vin\n");
nDos = 33;
return false;
}
// verify that sig time is legit in past
// should be at least not earlier than block when 1000 DASH tx got nMasternodeMinimumConfirmations
uint256 hashBlock = uint256();
CTransaction tx2;
GetTransaction(vin.prevout.hash, tx2, Params().GetConsensus(), hashBlock, true);
{
LOCK(cs_main);
BlockMap::iterator mi = mapBlockIndex.find(hashBlock);
if (mi != mapBlockIndex.end() && (*mi).second)
{
CBlockIndex* pMNIndex = (*mi).second; // block for 1000 DASH tx -> 1 confirmation
CBlockIndex* pConfIndex = chainActive[pMNIndex->nHeight + Params().GetConsensus().nMasternodeMinimumConfirmations - 1]; // block where tx got nMasternodeMinimumConfirmations
if(pConfIndex->GetBlockTime() > sigTime)
{
LogPrintf("CMasternodeBroadcast::CheckInputsAndAdd - Bad sigTime %d for Masternode %20s %105s (%i conf block is at %d)\n",
sigTime, addr.ToString(), vin.ToString(), Params().GetConsensus().nMasternodeMinimumConfirmations, pConfIndex->GetBlockTime());
return false;
}
}
}
// if it matches our Masternode privkey...
if(fMasterNode && pubkey2 == activeMasternode.pubKeyMasternode) {
if(protocolVersion == PROTOCOL_VERSION) {
// ... and PROTOCOL_VERSION, then we've been remotely activated ...
activeMasternode.EnableHotColdMasterNode(vin, addr);
} else {
// ... otherwise we need to reactivate our node, don not add it to the list and do not relay
// but also do not ban the node we get this message from
LogPrintf("CMasternodeBroadcast::CheckInputsAndAdd - wrong PROTOCOL_VERSION, announce message: %d MN: %d - re-activate your MN\n", protocolVersion, PROTOCOL_VERSION);
return false;
}
}
LogPrintf("CMasternodeBroadcast::CheckInputsAndAdd - Got NEW Masternode entry - %s - %s - %s - %lli \n", GetHash().ToString(), addr.ToString(), vin.ToString(), sigTime);
CMasternode mn(*this);
mnodeman.Add(mn);
bool isLocal = addr.IsRFC1918() || addr.IsLocal();
if(Params().NetworkIDString() == CBaseChainParams::REGTEST) isLocal = false;
if(!isLocal) Relay();
return true;
}
void CMasternodeBroadcast::Relay()
{
CInv inv(MSG_MASTERNODE_ANNOUNCE, GetHash());
RelayInv(inv);
}
bool CMasternodeBroadcast::Sign(CKey& keyCollateralAddress)
{
std::string errorMessage;
std::string vchPubKey(pubkey.begin(), pubkey.end());
std::string vchPubKey2(pubkey2.begin(), pubkey2.end());
sigTime = GetAdjustedTime();
std::string strMessage = addr.ToString() + boost::lexical_cast<std::string>(sigTime) + vchPubKey + vchPubKey2 + boost::lexical_cast<std::string>(protocolVersion);
if(!darkSendSigner.SignMessage(strMessage, errorMessage, vchSig, keyCollateralAddress)) {
LogPrintf("CMasternodeBroadcast::Sign() - Error: %s\n", errorMessage);
return false;
}
return true;
}
bool CMasternodeBroadcast::VerifySignature()
{
std::string errorMessage;
std::string vchPubKey(pubkey.begin(), pubkey.end());
std::string vchPubKey2(pubkey2.begin(), pubkey2.end());
std::string strMessage = addr.ToString() + boost::lexical_cast<std::string>(sigTime) + vchPubKey + vchPubKey2 + boost::lexical_cast<std::string>(protocolVersion);
if(!darkSendSigner.VerifyMessage(pubkey, vchSig, strMessage, errorMessage)) {
LogPrintf("CMasternodeBroadcast::VerifySignature() - Error: %s\n", errorMessage);
return false;
}
return true;
}
CMasternodePing::CMasternodePing()
{
vin = CTxIn();
blockHash = uint256();
sigTime = 0;
vchSig = std::vector<unsigned char>();
}
CMasternodePing::CMasternodePing(CTxIn& newVin)
{
int nHeight;
{
LOCK(cs_main);
CBlockIndex* pindexPrev = chainActive.Tip();
if(!pindexPrev) return;
nHeight = pindexPrev->nHeight;
}
vin = newVin;
blockHash = chainActive[nHeight - 12]->GetBlockHash();
sigTime = GetAdjustedTime();
vchSig = std::vector<unsigned char>();
}
bool CMasternodePing::Sign(CKey& keyMasternode, CPubKey& pubKeyMasternode)
{
std::string errorMessage;
std::string strMasterNodeSignMessage;
sigTime = GetAdjustedTime();
std::string strMessage = vin.ToString() + blockHash.ToString() + boost::lexical_cast<std::string>(sigTime);
if(!darkSendSigner.SignMessage(strMessage, errorMessage, vchSig, keyMasternode)) {
LogPrintf("CMasternodePing::Sign() - Error: %s\n", errorMessage);
return false;
}
if(!darkSendSigner.VerifyMessage(pubKeyMasternode, vchSig, strMessage, errorMessage)) {
LogPrintf("CMasternodePing::Sign() - Error: %s\n", errorMessage);
return false;
}
return true;
}
bool CMasternodePing::VerifySignature(CPubKey& pubKeyMasternode, int &nDos) {
std::string strMessage = vin.ToString() + blockHash.ToString() + boost::lexical_cast<std::string>(sigTime);
std::string errorMessage = "";
if(!darkSendSigner.VerifyMessage(pubKeyMasternode, vchSig, strMessage, errorMessage))
{
LogPrintf("CMasternodePing::VerifySignature - Got bad Masternode ping signature %s Error: %s\n", vin.ToString(), errorMessage);
nDos = 33;
return false;
}
return true;
}
bool CMasternodePing::CheckAndUpdate(int& nDos, bool fRequireEnabled, bool fCheckSigTimeOnly)
{
if (sigTime > GetAdjustedTime() + 60 * 60) {
LogPrintf("CMasternodePing::CheckAndUpdate - Signature rejected, too far into the future %s\n", vin.ToString());
nDos = 1;
return false;
}
if (sigTime <= GetAdjustedTime() - 60 * 60) {
LogPrintf("CMasternodePing::CheckAndUpdate - Signature rejected, too far into the past %s - %d %d \n", vin.ToString(), sigTime, GetAdjustedTime());
nDos = 1;
return false;
}
if(fCheckSigTimeOnly) {
CMasternode* pmn = mnodeman.Find(vin);
if(pmn) return VerifySignature(pmn->pubkey2, nDos);
return true;
}
LogPrint("masternode", "CMasternodePing::CheckAndUpdate - New Ping - %s - %s - %lli\n", GetHash().ToString(), blockHash.ToString(), sigTime);
// see if we have this Masternode
CMasternode* pmn = mnodeman.Find(vin);
if(pmn != NULL && pmn->protocolVersion >= mnpayments.GetMinMasternodePaymentsProto())
{
if (fRequireEnabled && !pmn->IsEnabled() && !pmn->IsPreEnabled()) return false;
// LogPrintf("mnping - Found corresponding mn for vin: %s\n", vin.ToString());
// 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))
{
if(!VerifySignature(pmn->pubkey2, nDos))
return false;
{
LOCK(cs_main);
BlockMap::iterator mi = mapBlockIndex.find(blockHash);
if (mi != mapBlockIndex.end() && (*mi).second)
{
if((*mi).second->nHeight < chainActive.Height() - 24)
{
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("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->lastPing = *this;
//mnodeman.mapSeenMasternodeBroadcast.lastPing is probably outdated, so we'll update it
CMasternodeBroadcast mnb(*pmn);
uint256 hash = mnb.GetHash();
if(mnodeman.mapSeenMasternodeBroadcast.count(hash)) {
mnodeman.mapSeenMasternodeBroadcast[hash].lastPing = *this;
}
pmn->Check(true);
if(!pmn->IsEnabled()) return false;
LogPrint("masternode", "CMasternodePing::CheckAndUpdate - Masternode ping accepted, vin: %s\n", vin.ToString());
Relay();
return true;
}
LogPrint("masternode", "CMasternodePing::CheckAndUpdate - Masternode ping arrived too early, vin: %s\n", vin.ToString());
//nDos = 1; //disable, this is happening frequently and causing banned peers
return false;
}
LogPrint("masternode", "CMasternodePing::CheckAndUpdate - Couldn't find compatible Masternode entry, vin: %s\n", vin.ToString());
return false;
}
void CMasternodePing::Relay()
{
CInv inv(MSG_MASTERNODE_PING, GetHash());
RelayInv(inv);
}