6d9e414c6a
- SimpleCheck - to verify only future time and unknown blockhash - CheckAndUpdate - to verify everything
443 lines
13 KiB
C++
443 lines
13 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.
|
|
|
|
#ifndef MASTERNODE_H
|
|
#define MASTERNODE_H
|
|
|
|
#include "key.h"
|
|
#include "main.h"
|
|
#include "net.h"
|
|
#include "spork.h"
|
|
#include "timedata.h"
|
|
|
|
class CMasternode;
|
|
class CMasternodeBroadcast;
|
|
class CMasternodePing;
|
|
|
|
static const int MASTERNODE_MIN_MNP_SECONDS = 10 * 60;
|
|
static const int MASTERNODE_MIN_MNB_SECONDS = 5 * 60;
|
|
static const int MASTERNODE_EXPIRATION_SECONDS = 65 * 60;
|
|
static const int MASTERNODE_REMOVAL_SECONDS = 75 * 60;
|
|
static const int MASTERNODE_CHECK_SECONDS = 5;
|
|
static const int MASTERNODE_WATCHDOG_MAX_SECONDS = 2 * 60 * 60;
|
|
|
|
static const int MASTERNODE_POSE_BAN_MAX_SCORE = 5;
|
|
//
|
|
// 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<unsigned char> vchSig;
|
|
//removed stop
|
|
|
|
CMasternodePing() :
|
|
vin(),
|
|
blockHash(),
|
|
sigTime(0),
|
|
vchSig()
|
|
{}
|
|
|
|
CMasternodePing(CTxIn& vinNew);
|
|
|
|
ADD_SERIALIZE_METHODS;
|
|
|
|
template <typename Stream, typename Operation>
|
|
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
|
|
READWRITE(vin);
|
|
READWRITE(blockHash);
|
|
READWRITE(sigTime);
|
|
READWRITE(vchSig);
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
uint256 GetHash() const
|
|
{
|
|
CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
|
|
ss << vin;
|
|
ss << sigTime;
|
|
return ss.GetHash();
|
|
}
|
|
|
|
bool Sign(CKey& keyMasternode, CPubKey& pubKeyMasternode);
|
|
bool CheckSignature(CPubKey& pubKeyMasternode, int &nDos);
|
|
bool SimpleCheck(int& nDos);
|
|
bool CheckAndUpdate(int& nDos);
|
|
void Relay();
|
|
|
|
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);
|
|
}
|
|
|
|
};
|
|
|
|
struct masternode_info_t {
|
|
|
|
masternode_info_t()
|
|
: vin(),
|
|
addr(),
|
|
pubKeyCollateralAddress(),
|
|
pubKeyMasternode(),
|
|
sigTime(0),
|
|
nLastDsq(0),
|
|
nTimeLastChecked(0),
|
|
nTimeLastPaid(0),
|
|
nTimeLastWatchdogVote(0),
|
|
nActiveState(0),
|
|
nProtocolVersion(0),
|
|
fInfoValid(false)
|
|
{}
|
|
|
|
CTxIn vin;
|
|
CService addr;
|
|
CPubKey pubKeyCollateralAddress;
|
|
CPubKey pubKeyMasternode;
|
|
int64_t sigTime; //mnb message time
|
|
int64_t nLastDsq; //the dsq count from the last dsq broadcast of this node
|
|
int64_t nTimeLastChecked;
|
|
int64_t nTimeLastPaid;
|
|
int64_t nTimeLastWatchdogVote;
|
|
int nActiveState;
|
|
int nProtocolVersion;
|
|
bool fInfoValid;
|
|
};
|
|
|
|
//
|
|
// 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.
|
|
//
|
|
class CMasternode
|
|
{
|
|
private:
|
|
// critical section to protect the inner data structures
|
|
mutable CCriticalSection cs;
|
|
|
|
public:
|
|
enum state {
|
|
MASTERNODE_PRE_ENABLED,
|
|
MASTERNODE_ENABLED,
|
|
MASTERNODE_EXPIRED,
|
|
MASTERNODE_OUTPOINT_SPENT,
|
|
MASTERNODE_REMOVE,
|
|
MASTERNODE_WATCHDOG_EXPIRED,
|
|
MASTERNODE_POSE_BAN
|
|
};
|
|
|
|
CTxIn vin;
|
|
CService addr;
|
|
CPubKey pubKeyCollateralAddress;
|
|
CPubKey pubKeyMasternode;
|
|
CMasternodePing lastPing;
|
|
std::vector<unsigned char> vchSig;
|
|
int64_t sigTime; //mnb message time
|
|
int64_t nLastDsq; //the dsq count from the last dsq broadcast of this node
|
|
int64_t nTimeLastChecked;
|
|
int64_t nTimeLastPaid;
|
|
int64_t nTimeLastWatchdogVote;
|
|
int nActiveState;
|
|
int nCacheCollateralBlock;
|
|
int nBlockLastPaid;
|
|
int nProtocolVersion;
|
|
int nPoSeBanScore;
|
|
int nPoSeBanHeight;
|
|
bool fAllowMixingTx;
|
|
bool fUnitTest;
|
|
|
|
// KEEP TRACK OF GOVERNANCE ITEMS EACH MASTERNODE HAS VOTE UPON FOR RECALCULATION
|
|
std::map<uint256, int> mapGovernanceObjectsVotedOn;
|
|
|
|
CMasternode();
|
|
CMasternode(const CMasternode& other);
|
|
CMasternode(const CMasternodeBroadcast& mnb);
|
|
CMasternode(CService addrNew, CTxIn vinNew, CPubKey pubKeyCollateralAddressNew, CPubKey pubKeyMasternodeNew, int nProtocolVersionIn);
|
|
|
|
ADD_SERIALIZE_METHODS;
|
|
|
|
template <typename Stream, typename Operation>
|
|
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
|
|
LOCK(cs);
|
|
READWRITE(vin);
|
|
READWRITE(addr);
|
|
READWRITE(pubKeyCollateralAddress);
|
|
READWRITE(pubKeyMasternode);
|
|
READWRITE(lastPing);
|
|
READWRITE(vchSig);
|
|
READWRITE(sigTime);
|
|
READWRITE(nLastDsq);
|
|
READWRITE(nTimeLastChecked);
|
|
READWRITE(nTimeLastPaid);
|
|
READWRITE(nTimeLastWatchdogVote);
|
|
READWRITE(nActiveState);
|
|
READWRITE(nCacheCollateralBlock);
|
|
READWRITE(nBlockLastPaid);
|
|
READWRITE(nProtocolVersion);
|
|
READWRITE(nPoSeBanScore);
|
|
READWRITE(nPoSeBanHeight);
|
|
READWRITE(fAllowMixingTx);
|
|
READWRITE(fUnitTest);
|
|
READWRITE(mapGovernanceObjectsVotedOn);
|
|
}
|
|
|
|
void swap(CMasternode& first, CMasternode& 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.addr, second.addr);
|
|
swap(first.pubKeyCollateralAddress, second.pubKeyCollateralAddress);
|
|
swap(first.pubKeyMasternode, second.pubKeyMasternode);
|
|
swap(first.lastPing, second.lastPing);
|
|
swap(first.vchSig, second.vchSig);
|
|
swap(first.sigTime, second.sigTime);
|
|
swap(first.nLastDsq, second.nLastDsq);
|
|
swap(first.nTimeLastChecked, second.nTimeLastChecked);
|
|
swap(first.nTimeLastPaid, second.nTimeLastPaid);
|
|
swap(first.nTimeLastWatchdogVote, second.nTimeLastWatchdogVote);
|
|
swap(first.nActiveState, second.nActiveState);
|
|
swap(first.nCacheCollateralBlock, second.nCacheCollateralBlock);
|
|
swap(first.nBlockLastPaid, second.nBlockLastPaid);
|
|
swap(first.nProtocolVersion, second.nProtocolVersion);
|
|
swap(first.nPoSeBanScore, second.nPoSeBanScore);
|
|
swap(first.nPoSeBanHeight, second.nPoSeBanHeight);
|
|
swap(first.fAllowMixingTx, second.fAllowMixingTx);
|
|
swap(first.fUnitTest, second.fUnitTest);
|
|
swap(first.mapGovernanceObjectsVotedOn, second.mapGovernanceObjectsVotedOn);
|
|
}
|
|
|
|
// CALCULATE A RANK AGAINST OF GIVEN BLOCK
|
|
arith_uint256 CalculateScore(const uint256& blockHash);
|
|
|
|
bool UpdateFromNewBroadcast(CMasternodeBroadcast& mnb);
|
|
|
|
void Check(bool fForce = false);
|
|
|
|
bool IsBroadcastedWithin(int nSeconds) { return GetAdjustedTime() - sigTime < nSeconds; }
|
|
|
|
bool IsPingedWithin(int nSeconds, int64_t nTimeToCheckAt = -1)
|
|
{
|
|
if(lastPing == CMasternodePing()) return false;
|
|
|
|
if(nTimeToCheckAt == -1) {
|
|
nTimeToCheckAt = GetAdjustedTime();
|
|
}
|
|
return nTimeToCheckAt - lastPing.sigTime < nSeconds;
|
|
}
|
|
|
|
bool IsEnabled() { return nActiveState == MASTERNODE_ENABLED; }
|
|
bool IsPreEnabled() { return nActiveState == MASTERNODE_PRE_ENABLED; }
|
|
bool IsPoSeBanned() { return nActiveState == MASTERNODE_POSE_BAN; }
|
|
bool IsPoSeVerified() { return nPoSeBanScore <= -MASTERNODE_POSE_BAN_MAX_SCORE; }
|
|
|
|
bool IsWatchdogExpired() { return nActiveState == MASTERNODE_WATCHDOG_EXPIRED; }
|
|
|
|
bool IsValidForPayment()
|
|
{
|
|
if(nActiveState == MASTERNODE_ENABLED) {
|
|
return true;
|
|
}
|
|
if(!sporkManager.IsSporkActive(SPORK_14_REQUIRE_SENTINEL_FLAG) &&
|
|
(nActiveState == MASTERNODE_WATCHDOG_EXPIRED)) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool IsValidNetAddr();
|
|
|
|
void IncreasePoSeBanScore() { if(nPoSeBanScore < MASTERNODE_POSE_BAN_MAX_SCORE) nPoSeBanScore++; }
|
|
void DecreasePoSeBanScore() { if(nPoSeBanScore > -MASTERNODE_POSE_BAN_MAX_SCORE) nPoSeBanScore--; }
|
|
|
|
masternode_info_t GetInfo();
|
|
|
|
static std::string StateToString(int nStateIn);
|
|
std::string GetStateString() const;
|
|
std::string GetStatus() const;
|
|
|
|
int GetCollateralAge();
|
|
|
|
int GetLastPaidTime() { return nTimeLastPaid; }
|
|
int GetLastPaidBlock() { return nBlockLastPaid; }
|
|
void UpdateLastPaid(const CBlockIndex *pindex, int nMaxBlocksToScanBack);
|
|
|
|
// KEEP TRACK OF EACH GOVERNANCE ITEM INCASE THIS NODE GOES OFFLINE, SO WE CAN RECALC THEIR STATUS
|
|
void AddGovernanceVote(uint256 nGovernanceObjectHash);
|
|
// RECALCULATE CACHED STATUS FLAGS FOR ALL AFFECTED OBJECTS
|
|
void FlagGovernanceItemsAsDirty();
|
|
|
|
void RemoveGovernanceObject(uint256 nGovernanceObjectHash);
|
|
|
|
void UpdateWatchdogVoteTime();
|
|
|
|
CMasternode& operator=(CMasternode from)
|
|
{
|
|
swap(*this, from);
|
|
return *this;
|
|
}
|
|
friend bool operator==(const CMasternode& a, const CMasternode& b)
|
|
{
|
|
return a.vin == b.vin;
|
|
}
|
|
friend bool operator!=(const CMasternode& a, const CMasternode& b)
|
|
{
|
|
return !(a.vin == b.vin);
|
|
}
|
|
|
|
};
|
|
|
|
|
|
//
|
|
// The Masternode Broadcast Class : Contains a different serialize method for sending masternodes through the network
|
|
//
|
|
|
|
class CMasternodeBroadcast : public CMasternode
|
|
{
|
|
public:
|
|
|
|
CMasternodeBroadcast() : CMasternode() {}
|
|
CMasternodeBroadcast(const CMasternode& mn) : CMasternode(mn) {}
|
|
CMasternodeBroadcast(CService addrNew, CTxIn vinNew, CPubKey pubKeyCollateralAddressNew, CPubKey pubKeyMasternodeNew, int nProtocolVersionIn) :
|
|
CMasternode(addrNew, vinNew, pubKeyCollateralAddressNew, pubKeyMasternodeNew, nProtocolVersionIn) {}
|
|
|
|
ADD_SERIALIZE_METHODS;
|
|
|
|
template <typename Stream, typename Operation>
|
|
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
|
|
READWRITE(vin);
|
|
READWRITE(addr);
|
|
READWRITE(pubKeyCollateralAddress);
|
|
READWRITE(pubKeyMasternode);
|
|
READWRITE(vchSig);
|
|
READWRITE(sigTime);
|
|
READWRITE(nProtocolVersion);
|
|
READWRITE(lastPing);
|
|
READWRITE(nLastDsq);
|
|
}
|
|
|
|
uint256 GetHash() const
|
|
{
|
|
CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
|
|
//
|
|
// REMOVE AFTER MIGRATION TO 12.1
|
|
//
|
|
if(nProtocolVersion < 70201) {
|
|
ss << sigTime;
|
|
ss << pubKeyCollateralAddress;
|
|
} else {
|
|
//
|
|
// END REMOVE
|
|
//
|
|
ss << vin;
|
|
ss << pubKeyCollateralAddress;
|
|
ss << sigTime;
|
|
}
|
|
return ss.GetHash();
|
|
}
|
|
|
|
/// Create Masternode broadcast, needs to be relayed manually after that
|
|
static bool Create(CTxIn vin, CService service, CKey keyCollateralAddressNew, CPubKey pubKeyCollateralAddressNew, CKey keyMasternodeNew, CPubKey pubKeyMasternodeNew, std::string &strErrorRet, CMasternodeBroadcast &mnbRet);
|
|
static bool Create(std::string strService, std::string strKey, std::string strTxHash, std::string strOutputIndex, std::string& strErrorRet, CMasternodeBroadcast &mnbRet, bool fOffline = false);
|
|
|
|
bool SimpleCheck(int& nDos);
|
|
bool Update(CMasternode* pmn, int& nDos);
|
|
bool CheckOutpoint(int& nDos);
|
|
|
|
bool Sign(CKey& keyCollateralAddress);
|
|
bool CheckSignature(int& nDos);
|
|
void Relay();
|
|
};
|
|
|
|
class CMasternodeVerification
|
|
{
|
|
public:
|
|
CTxIn vin1;
|
|
CTxIn vin2;
|
|
CService addr;
|
|
int nonce;
|
|
int nBlockHeight;
|
|
std::vector<unsigned char> vchSig1;
|
|
std::vector<unsigned char> vchSig2;
|
|
|
|
CMasternodeVerification() :
|
|
vin1(),
|
|
vin2(),
|
|
addr(),
|
|
nonce(0),
|
|
nBlockHeight(0),
|
|
vchSig1(),
|
|
vchSig2()
|
|
{}
|
|
|
|
CMasternodeVerification(CService addr, int nonce, int nBlockHeight) :
|
|
vin1(),
|
|
vin2(),
|
|
addr(addr),
|
|
nonce(nonce),
|
|
nBlockHeight(nBlockHeight),
|
|
vchSig1(),
|
|
vchSig2()
|
|
{}
|
|
|
|
ADD_SERIALIZE_METHODS;
|
|
|
|
template <typename Stream, typename Operation>
|
|
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
|
|
READWRITE(vin1);
|
|
READWRITE(vin2);
|
|
READWRITE(addr);
|
|
READWRITE(nonce);
|
|
READWRITE(nBlockHeight);
|
|
READWRITE(vchSig1);
|
|
READWRITE(vchSig2);
|
|
}
|
|
|
|
uint256 GetHash() const
|
|
{
|
|
CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
|
|
ss << vin1;
|
|
ss << vin2;
|
|
ss << addr;
|
|
ss << nonce;
|
|
ss << nBlockHeight;
|
|
return ss.GetHash();
|
|
}
|
|
|
|
void Relay() const
|
|
{
|
|
CInv inv(MSG_MASTERNODE_VERIFY, GetHash());
|
|
RelayInv(inv);
|
|
}
|
|
};
|
|
|
|
#endif
|