mirror of
https://github.com/dashpay/dash.git
synced 2024-12-30 14:25:53 +01:00
eeb53b9682
- Syncing process is now event based, rather than timeout based. This means the system can tell when it's done with each step and moves on between phases much faster. In initial testing it seems to be about 10-15x faster and has synced everytime successfully. - Please remove print debugging when the syncing system is proven to be debugged.
656 lines
21 KiB
C++
656 lines
21 KiB
C++
// Copyright (c) 2014-2015 The Dash developers
|
|
// Distributed under the MIT/X11 software license, see the accompanying
|
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
|
|
#include "masternode.h"
|
|
#include "masternodeman.h"
|
|
#include "darksend.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)
|
|
{
|
|
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();
|
|
sig = 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;
|
|
sig = other.sig;
|
|
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;
|
|
sig = mnb.sig;
|
|
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;
|
|
sig = mnb.sig;
|
|
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)
|
|
{
|
|
if(chainActive.Tip() == NULL) return 0;
|
|
|
|
uint256 hash = 0;
|
|
uint256 aux = vin.prevout.hash + vin.prevout.n;
|
|
|
|
if(!GetBlockHash(hash, nBlockHeight)) {
|
|
LogPrintf("CalculateScore ERROR - nHeight %d - Returned 0\n", nBlockHeight);
|
|
return 0;
|
|
}
|
|
|
|
CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
|
|
ss << hash;
|
|
uint256 hash2 = ss.GetHash();
|
|
|
|
CHashWriter ss2(SER_GETHASH, PROTOCOL_VERSION);
|
|
ss2 << hash;
|
|
ss2 << aux;
|
|
uint256 hash3 = ss2.GetHash();
|
|
|
|
uint256 r = (hash3 > hash2 ? hash3 - hash2 : hash2 - hash3);
|
|
|
|
return 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(lastPing.sigTime - sigTime < MASTERNODE_MIN_MNP_SECONDS){
|
|
activeState = MASTERNODE_PRE_ENABLED;
|
|
return;
|
|
}
|
|
|
|
if(!IsPingedWithin(MASTERNODE_REMOVAL_SECONDS)){
|
|
activeState = MASTERNODE_REMOVE;
|
|
return;
|
|
}
|
|
|
|
if(!IsPingedWithin(MASTERNODE_EXPIRATION_SECONDS)){
|
|
activeState = MASTERNODE_EXPIRED;
|
|
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(!AcceptableInputs(mempool, state, CTransaction(tx), false, NULL)){
|
|
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 + hash.GetCompact(false);
|
|
}
|
|
|
|
int64_t CMasternode::GetLastPaid() {
|
|
CBlockIndex* pindexPrev = chainActive.Tip();
|
|
if(pindexPrev == NULL) return false;
|
|
|
|
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 = hash.GetCompact(false) % 150;
|
|
|
|
if (chainActive.Tip() == NULL) return false;
|
|
|
|
const CBlockIndex *BlockReading = chainActive.Tip();
|
|
|
|
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();
|
|
sig = 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;
|
|
sig = 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;
|
|
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)
|
|
{
|
|
// 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());
|
|
nDos = 1;
|
|
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("mnb - ignoring outdated Masternode %s protocol version %d\n", vin.ToString(), protocolVersion);
|
|
return false;
|
|
}
|
|
|
|
CScript pubkeyScript;
|
|
pubkeyScript = GetScriptForDestination(pubkey.GetID());
|
|
|
|
if(pubkeyScript.size() != 25) {
|
|
LogPrintf("mnb - pubkey the wrong size\n");
|
|
nDos = 100;
|
|
return false;
|
|
}
|
|
|
|
CScript pubkeyScript2;
|
|
pubkeyScript2 = GetScriptForDestination(pubkey2.GetID());
|
|
|
|
if(pubkeyScript2.size() != 25) {
|
|
LogPrintf("mnb - pubkey2 the wrong size\n");
|
|
nDos = 100;
|
|
return false;
|
|
}
|
|
|
|
if(!vin.scriptSig.empty()) {
|
|
LogPrintf("mnb - Ignore Not Empty ScriptSig %s\n",vin.ToString());
|
|
return false;
|
|
}
|
|
|
|
std::string errorMessage = "";
|
|
if(!darkSendSigner.VerifyMessage(pubkey, sig, strMessage, errorMessage)){
|
|
LogPrintf("mnb - Got bad Masternode address signature\n");
|
|
nDos = 100;
|
|
return false;
|
|
}
|
|
|
|
if(Params().NetworkID() == CBaseChainParams::MAIN) {
|
|
if(addr.GetPort() != 9999) return false;
|
|
} else if(addr.GetPort() == 9999) 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 or it's not enabled yet/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->IsBroadcastedWithin(MASTERNODE_MIN_MNB_SECONDS)) {
|
|
//take the newest entry
|
|
LogPrintf("mnb - Got updated entry for %s\n", addr.ToString());
|
|
if(pmn->UpdateFromNewBroadcast((*this))){
|
|
pmn->Check();
|
|
if(pmn->IsEnabled()) 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;
|
|
|
|
// 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 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);
|
|
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(!AcceptableInputs(mempool, state, CTransaction(tx), false, NULL)) {
|
|
//set nDos
|
|
state.IsInvalid(nDoS);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
LogPrint("masternode", "mnb - Accepted Masternode entry\n");
|
|
|
|
if(GetInputAge(vin) < MASTERNODE_MIN_CONFIRMATIONS){
|
|
LogPrintf("mnb - Input must have at least %d confirmations\n", MASTERNODE_MIN_CONFIRMATIONS);
|
|
// maybe we miss few blocks, let this mnb to be checked again later
|
|
mnodeman.mapSeenMasternodeBroadcast.erase(GetHash());
|
|
masternodeSync.mapSeenSyncMNB.erase(GetHash());
|
|
return false;
|
|
}
|
|
|
|
// verify that sig time is legit in past
|
|
// should be at least not earlier than block when 1000 DASH tx got MASTERNODE_MIN_CONFIRMATIONS
|
|
uint256 hashBlock = 0;
|
|
CTransaction tx2;
|
|
GetTransaction(vin.prevout.hash, tx2, hashBlock, true);
|
|
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 + MASTERNODE_MIN_CONFIRMATIONS - 1]; // block where tx got MASTERNODE_MIN_CONFIRMATIONS
|
|
if(pConfIndex->GetBlockTime() > sigTime)
|
|
{
|
|
LogPrintf("mnb - Bad sigTime %d for Masternode %20s %105s (%i conf block is at %d)\n",
|
|
sigTime, addr.ToString(), vin.ToString(), MASTERNODE_MIN_CONFIRMATIONS, pConfIndex->GetBlockTime());
|
|
return false;
|
|
}
|
|
}
|
|
|
|
LogPrintf("mnb - Got NEW Masternode entry - %s - %s - %s - %lli \n", GetHash().ToString(), addr.ToString(), vin.ToString(), sigTime);
|
|
CMasternode mn(*this);
|
|
mnodeman.Add(mn);
|
|
|
|
// if it matches our Masternode privkey, then we've been remotely activated
|
|
if(pubkey2 == activeMasternode.pubKeyMasternode && protocolVersion == PROTOCOL_VERSION){
|
|
activeMasternode.EnableHotColdMasterNode(vin, addr);
|
|
}
|
|
|
|
bool isLocal = addr.IsRFC1918() || addr.IsLocal();
|
|
if(Params().NetworkID() == 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, sig, keyCollateralAddress)) {
|
|
LogPrintf("CMasternodeBroadcast::Sign() - Error: %s\n", errorMessage);
|
|
return false;
|
|
}
|
|
|
|
if(!darkSendSigner.VerifyMessage(pubkey, sig, strMessage, errorMessage)) {
|
|
LogPrintf("CMasternodeBroadcast::Sign() - Error: %s\n", errorMessage);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
CMasternodePing::CMasternodePing()
|
|
{
|
|
vin = CTxIn();
|
|
blockHash = uint256(0);
|
|
sigTime = 0;
|
|
vchSig = std::vector<unsigned char>();
|
|
}
|
|
|
|
CMasternodePing::CMasternodePing(CTxIn& newVin)
|
|
{
|
|
vin = newVin;
|
|
blockHash = chainActive[chainActive.Height() - 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::CheckAndUpdate(int& nDos, bool fRequireEnabled)
|
|
{
|
|
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;
|
|
}
|
|
|
|
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))
|
|
{
|
|
std::string strMessage = vin.ToString() + blockHash.ToString() + boost::lexical_cast<std::string>(sigTime);
|
|
|
|
std::string errorMessage = "";
|
|
if(!darkSendSigner.VerifyMessage(pmn->pubkey2, vchSig, strMessage, errorMessage))
|
|
{
|
|
LogPrintf("CMasternodePing::CheckAndUpdate - Got bad Masternode address signature %s\n", vin.ToString());
|
|
nDos = 33;
|
|
return false;
|
|
}
|
|
|
|
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);
|
|
}
|