dash/src/masternode.h
UdjinM6 fa301ecb49 local nLastDsq (#1211)
* Revert behaviour introduced in 5e1a6afe7f, make nLastDsq local variable instead of being network-wide one. Should fix mixing for new clients and for those who was offline for too long.

* fix docs
2016-12-20 03:09:38 +04:00

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();
static bool IsValidNetAddr(CService addrIn);
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);
}
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