2014-12-09 02:17:57 +01:00
|
|
|
|
2015-03-13 10:28:20 +01:00
|
|
|
// Copyright (c) 2014-2015 The Dash developers
|
2014-12-09 02:17:57 +01:00
|
|
|
// 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 "bignum.h"
|
|
|
|
#include "sync.h"
|
|
|
|
#include "net.h"
|
|
|
|
#include "key.h"
|
|
|
|
#include "core.h"
|
|
|
|
#include "util.h"
|
|
|
|
#include "script.h"
|
|
|
|
#include "base58.h"
|
|
|
|
#include "main.h"
|
2015-03-13 10:28:20 +01:00
|
|
|
#include "masternode-pos.h"
|
2014-12-09 02:17:57 +01:00
|
|
|
|
|
|
|
#define MASTERNODE_NOT_PROCESSED 0 // initial state
|
|
|
|
#define MASTERNODE_IS_CAPABLE 1
|
|
|
|
#define MASTERNODE_NOT_CAPABLE 2
|
|
|
|
#define MASTERNODE_STOPPED 3
|
|
|
|
#define MASTERNODE_INPUT_TOO_NEW 4
|
2014-12-31 03:54:00 +01:00
|
|
|
#define MASTERNODE_PORT_NOT_OPEN 6
|
2014-12-09 02:17:57 +01:00
|
|
|
#define MASTERNODE_PORT_OPEN 7
|
|
|
|
#define MASTERNODE_SYNC_IN_PROCESS 8
|
|
|
|
#define MASTERNODE_REMOTELY_ENABLED 9
|
|
|
|
|
|
|
|
#define MASTERNODE_MIN_CONFIRMATIONS 15
|
|
|
|
#define MASTERNODE_MIN_DSEEP_SECONDS (30*60)
|
|
|
|
#define MASTERNODE_MIN_DSEE_SECONDS (5*60)
|
|
|
|
#define MASTERNODE_PING_SECONDS (1*60)
|
|
|
|
#define MASTERNODE_EXPIRATION_SECONDS (65*60)
|
|
|
|
#define MASTERNODE_REMOVAL_SECONDS (70*60)
|
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
|
2015-02-23 21:01:21 +01:00
|
|
|
class CMasternode;
|
|
|
|
class CMasternodePayments;
|
2015-02-09 21:22:31 +01:00
|
|
|
class CMasternodePaymentWinner;
|
|
|
|
|
2014-12-09 02:17:57 +01:00
|
|
|
extern CMasternodePayments masternodePayments;
|
2015-02-09 21:22:31 +01:00
|
|
|
extern map<uint256, CMasternodePaymentWinner> mapSeenMasternodeVotes;
|
2015-02-05 23:56:59 +01:00
|
|
|
extern map<int64_t, uint256> mapCacheBlockHashes;
|
2014-12-09 02:17:57 +01:00
|
|
|
|
2015-02-23 21:01:21 +01:00
|
|
|
enum masternodeState {
|
|
|
|
MASTERNODE_ENABLED = 1,
|
|
|
|
MASTERNODE_EXPIRED = 2,
|
|
|
|
MASTERNODE_VIN_SPENT = 3,
|
2015-03-13 10:28:20 +01:00
|
|
|
MASTERNODE_REMOVE = 4,
|
|
|
|
MASTERNODE_POS_ERROR = 5
|
2015-02-23 21:01:21 +01:00
|
|
|
};
|
2014-12-09 02:17:57 +01:00
|
|
|
|
2015-02-23 21:12:33 +01:00
|
|
|
void ProcessMessageMasternodePayments(CNode* pfrom, std::string& strCommand, CDataStream& vRecv);
|
2014-12-09 02:17:57 +01:00
|
|
|
|
2014-12-31 03:54:00 +01:00
|
|
|
//
|
2015-03-05 09:10:15 +01:00
|
|
|
// The Masternode Class. For managing the Darksend process. It contains the input of the 1000DRK, signature to prove
|
2014-12-09 02:17:57 +01:00
|
|
|
// it's the one who own that ip address and code for calculating the payment election.
|
2014-12-31 03:54:00 +01:00
|
|
|
//
|
2015-02-23 21:01:21 +01:00
|
|
|
class CMasternode
|
2014-12-09 02:17:57 +01:00
|
|
|
{
|
2015-02-23 21:01:21 +01:00
|
|
|
private:
|
|
|
|
// critical section to protect the inner data structures
|
|
|
|
mutable CCriticalSection cs;
|
|
|
|
|
2014-12-09 02:17:57 +01:00
|
|
|
public:
|
|
|
|
CTxIn vin;
|
2015-02-23 21:01:21 +01:00
|
|
|
CService addr;
|
2014-12-09 02:17:57 +01:00
|
|
|
CPubKey pubkey;
|
|
|
|
CPubKey pubkey2;
|
|
|
|
std::vector<unsigned char> sig;
|
2015-02-23 21:01:21 +01:00
|
|
|
int activeState;
|
2015-03-01 16:38:53 +01:00
|
|
|
int64_t sigTime; //dsee message times
|
2014-12-09 02:17:57 +01:00
|
|
|
int64_t lastDseep;
|
2015-02-23 21:01:21 +01:00
|
|
|
int64_t lastTimeSeen;
|
2014-12-09 02:17:57 +01:00
|
|
|
int cacheInputAge;
|
|
|
|
int cacheInputAgeBlock;
|
|
|
|
bool unitTest;
|
|
|
|
bool allowFreeTx;
|
|
|
|
int protocolVersion;
|
2015-02-23 21:01:21 +01:00
|
|
|
int64_t nLastDsq; //the dsq count from the last dsq broadcast of this node
|
2015-03-13 10:28:20 +01:00
|
|
|
int nScanningErrorCount;
|
|
|
|
int nLastScanningErrorBlockHeight;
|
2014-12-09 02:17:57 +01:00
|
|
|
|
2015-02-23 21:01:21 +01:00
|
|
|
CMasternode();
|
|
|
|
CMasternode(const CMasternode& other);
|
2015-03-01 16:38:53 +01:00
|
|
|
CMasternode(CService newAddr, CTxIn newVin, CPubKey newPubkey, std::vector<unsigned char> newSig, int64_t newSigTime, CPubKey newPubkey2, int protocolVersionIn);
|
2014-12-09 02:17:57 +01:00
|
|
|
|
2015-02-23 21:01:21 +01:00
|
|
|
void swap(CMasternode& first, CMasternode& second) // nothrow
|
2014-12-09 02:17:57 +01:00
|
|
|
{
|
2015-02-23 21:01:21 +01:00
|
|
|
// 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.pubkey, second.pubkey);
|
|
|
|
swap(first.pubkey2, second.pubkey2);
|
|
|
|
swap(first.sig, second.sig);
|
|
|
|
swap(first.activeState, second.activeState);
|
2015-03-01 16:38:53 +01:00
|
|
|
swap(first.sigTime, second.sigTime);
|
2015-02-23 21:01:21 +01:00
|
|
|
swap(first.lastDseep, second.lastDseep);
|
|
|
|
swap(first.lastTimeSeen, second.lastTimeSeen);
|
|
|
|
swap(first.cacheInputAge, second.cacheInputAge);
|
|
|
|
swap(first.cacheInputAgeBlock, second.cacheInputAgeBlock);
|
|
|
|
swap(first.allowFreeTx, second.allowFreeTx);
|
|
|
|
swap(first.protocolVersion, second.protocolVersion);
|
|
|
|
swap(first.unitTest, second.unitTest);
|
|
|
|
swap(first.nLastDsq, second.nLastDsq);
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
2014-12-09 02:17:57 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
uint256 CalculateScore(int mod=1, int64_t nBlockHeight=0);
|
|
|
|
|
2015-02-23 21:01:21 +01:00
|
|
|
IMPLEMENT_SERIALIZE
|
|
|
|
(
|
|
|
|
// serialized format:
|
|
|
|
// * version byte (currently 0)
|
|
|
|
// * all fields (?)
|
|
|
|
{
|
|
|
|
LOCK(cs);
|
|
|
|
unsigned char nVersion = 0;
|
|
|
|
READWRITE(nVersion);
|
|
|
|
READWRITE(vin);
|
|
|
|
READWRITE(addr);
|
|
|
|
READWRITE(pubkey);
|
|
|
|
READWRITE(pubkey2);
|
|
|
|
READWRITE(sig);
|
|
|
|
READWRITE(activeState);
|
2015-03-01 16:38:53 +01:00
|
|
|
READWRITE(sigTime);
|
2015-02-23 21:01:21 +01:00
|
|
|
READWRITE(lastDseep);
|
|
|
|
READWRITE(lastTimeSeen);
|
|
|
|
READWRITE(cacheInputAge);
|
|
|
|
READWRITE(cacheInputAgeBlock);
|
|
|
|
READWRITE(unitTest);
|
|
|
|
READWRITE(allowFreeTx);
|
|
|
|
READWRITE(protocolVersion);
|
|
|
|
READWRITE(nLastDsq);
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
2014-12-09 02:17:57 +01:00
|
|
|
void UpdateLastSeen(int64_t override=0)
|
|
|
|
{
|
|
|
|
if(override == 0){
|
|
|
|
lastTimeSeen = GetAdjustedTime();
|
|
|
|
} else {
|
|
|
|
lastTimeSeen = override;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
inline uint64_t SliceHash(uint256& hash, int slice)
|
|
|
|
{
|
|
|
|
uint64_t n = 0;
|
|
|
|
memcpy(&n, &hash+slice*64, 64);
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Check();
|
|
|
|
|
|
|
|
bool UpdatedWithin(int seconds)
|
|
|
|
{
|
|
|
|
// LogPrintf("UpdatedWithin %d, %d -- %d \n", GetAdjustedTime() , lastTimeSeen, (GetAdjustedTime() - lastTimeSeen) < seconds);
|
2014-12-31 03:54:00 +01:00
|
|
|
|
2014-12-09 02:17:57 +01:00
|
|
|
return (GetAdjustedTime() - lastTimeSeen) < seconds;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Disable()
|
|
|
|
{
|
|
|
|
lastTimeSeen = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool IsEnabled()
|
|
|
|
{
|
2015-02-23 21:01:21 +01:00
|
|
|
return activeState == MASTERNODE_ENABLED;
|
2014-12-09 02:17:57 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
int GetMasternodeInputAge()
|
|
|
|
{
|
|
|
|
if(chainActive.Tip() == NULL) return 0;
|
|
|
|
|
|
|
|
if(cacheInputAge == 0){
|
|
|
|
cacheInputAge = GetInputAge(vin);
|
|
|
|
cacheInputAgeBlock = chainActive.Tip()->nHeight;
|
|
|
|
}
|
|
|
|
|
|
|
|
return cacheInputAge+(chainActive.Tip()->nHeight-cacheInputAgeBlock);
|
|
|
|
}
|
2015-03-13 10:28:20 +01:00
|
|
|
|
|
|
|
void ApplyScanningError(CMasternodeScanningError& mnse)
|
|
|
|
{
|
|
|
|
if(!mnse.IsValid()) return;
|
|
|
|
|
|
|
|
if(mnse.nBlockHeight == nLastScanningErrorBlockHeight) return;
|
|
|
|
nLastScanningErrorBlockHeight = mnse.nBlockHeight;
|
|
|
|
|
|
|
|
if(mnse.nErrorType == SCANNING_SUCCESS){
|
|
|
|
nScanningErrorCount--;
|
|
|
|
if(nScanningErrorCount < 0) nScanningErrorCount = 0;
|
|
|
|
} else { //all other codes are equally as bad
|
|
|
|
nScanningErrorCount++;
|
|
|
|
if(nScanningErrorCount > MASTERNODE_SCANNING_ERROR_THESHOLD*2) nScanningErrorCount = MASTERNODE_SCANNING_ERROR_THESHOLD*2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-09 02:17:57 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
// for storing the winning payments
|
|
|
|
class CMasternodePaymentWinner
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
int nBlockHeight;
|
|
|
|
CTxIn vin;
|
2015-02-03 18:17:30 +01:00
|
|
|
CScript payee;
|
2014-12-09 02:17:57 +01:00
|
|
|
std::vector<unsigned char> vchSig;
|
|
|
|
uint64_t score;
|
|
|
|
|
|
|
|
CMasternodePaymentWinner() {
|
|
|
|
nBlockHeight = 0;
|
|
|
|
score = 0;
|
|
|
|
vin = CTxIn();
|
2015-02-03 18:17:30 +01:00
|
|
|
payee = CScript();
|
2014-12-09 02:17:57 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
uint256 GetHash(){
|
|
|
|
uint256 n2 = HashX11(BEGIN(nBlockHeight), END(nBlockHeight));
|
|
|
|
uint256 n3 = vin.prevout.hash > n2 ? (vin.prevout.hash - n2) : (n2 - vin.prevout.hash);
|
|
|
|
|
|
|
|
return n3;
|
|
|
|
}
|
|
|
|
|
|
|
|
IMPLEMENT_SERIALIZE(
|
|
|
|
READWRITE(nBlockHeight);
|
2015-02-03 18:17:30 +01:00
|
|
|
READWRITE(payee);
|
2014-12-09 02:17:57 +01:00
|
|
|
READWRITE(vin);
|
2015-02-03 18:17:30 +01:00
|
|
|
READWRITE(score);
|
2014-12-09 02:17:57 +01:00
|
|
|
READWRITE(vchSig);
|
|
|
|
)
|
|
|
|
};
|
|
|
|
|
|
|
|
//
|
2014-12-31 03:54:00 +01:00
|
|
|
// Masternode Payments Class
|
2014-12-09 02:17:57 +01:00
|
|
|
// Keeps track of who should get paid for which blocks
|
|
|
|
//
|
|
|
|
|
|
|
|
class CMasternodePayments
|
|
|
|
{
|
|
|
|
private:
|
|
|
|
std::vector<CMasternodePaymentWinner> vWinning;
|
|
|
|
int nSyncedFromPeer;
|
|
|
|
std::string strMasterPrivKey;
|
|
|
|
std::string strTestPubKey;
|
|
|
|
std::string strMainPubKey;
|
2015-01-20 11:02:11 +01:00
|
|
|
bool enabled;
|
2014-12-09 02:17:57 +01:00
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
CMasternodePayments() {
|
|
|
|
strMainPubKey = "04549ac134f694c0243f503e8c8a9a986f5de6610049c40b07816809b0d1d06a21b07be27b9bb555931773f62ba6cf35a25fd52f694d4e1106ccd237a7bb899fdd";
|
|
|
|
strTestPubKey = "046f78dcf911fbd61910136f7f0f8d90578f68d0b3ac973b5040fb7afb501b5939f39b108b0569dca71488f5bbf498d92e4d1194f6f941307ffd95f75e76869f0e";
|
2015-01-20 11:02:11 +01:00
|
|
|
enabled = false;
|
2014-12-09 02:17:57 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool SetPrivKey(std::string strPrivKey);
|
|
|
|
bool CheckSignature(CMasternodePaymentWinner& winner);
|
|
|
|
bool Sign(CMasternodePaymentWinner& winner);
|
2014-12-31 03:54:00 +01:00
|
|
|
|
|
|
|
// Deterministically calculate a given "score" for a masternode depending on how close it's hash is
|
|
|
|
// to the blockHeight. The further away they are the better, the furthest will win the election
|
2014-12-09 02:17:57 +01:00
|
|
|
// and get paid this block
|
2014-12-31 03:54:00 +01:00
|
|
|
//
|
2014-12-09 02:17:57 +01:00
|
|
|
|
|
|
|
uint64_t CalculateScore(uint256 blockHash, CTxIn& vin);
|
|
|
|
bool GetWinningMasternode(int nBlockHeight, CTxIn& vinOut);
|
|
|
|
bool AddWinningMasternode(CMasternodePaymentWinner& winner);
|
|
|
|
bool ProcessBlock(int nBlockHeight);
|
|
|
|
void Relay(CMasternodePaymentWinner& winner);
|
|
|
|
void Sync(CNode* node);
|
|
|
|
void CleanPaymentList();
|
2015-02-23 21:01:21 +01:00
|
|
|
int LastPayment(CMasternode& mn);
|
2014-12-09 02:17:57 +01:00
|
|
|
|
|
|
|
//slow
|
|
|
|
bool GetBlockPayee(int nBlockHeight, CScript& payee);
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
#endif
|