2015-04-16 21:58:09 +02:00
|
|
|
|
|
|
|
|
2016-02-02 16:28:56 +01:00
|
|
|
// Copyright (c) 2014-2016 The Dash Core developers
|
2015-04-16 21:58:09 +02:00
|
|
|
// Distributed under the MIT/X11 software license, see the accompanying
|
|
|
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
|
|
#ifndef MASTERNODE_PAYMENTS_H
|
|
|
|
#define MASTERNODE_PAYMENTS_H
|
|
|
|
|
2016-08-17 09:08:25 +02:00
|
|
|
#include "util.h"
|
2016-02-02 16:28:56 +01:00
|
|
|
#include "core_io.h"
|
2015-04-16 21:58:09 +02:00
|
|
|
#include "key.h"
|
|
|
|
#include "main.h"
|
|
|
|
#include "masternode.h"
|
2016-02-02 16:28:56 +01:00
|
|
|
#include "utilstrencodings.h"
|
|
|
|
|
2015-05-27 21:47:01 +02:00
|
|
|
#include <boost/lexical_cast.hpp>
|
2015-04-16 21:58:09 +02:00
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
|
2016-09-08 14:04:45 +02:00
|
|
|
//! minimum peer version that can receive and send masternode payment messages,
|
|
|
|
// vote for masternode winner and be elected as a winner
|
|
|
|
// V1 - Last protocol version before update
|
|
|
|
// V2 - Newest protocol version
|
|
|
|
static const int MIN_MASTERNODE_PAYMENT_PROTO_VERSION_1 = 70103;
|
|
|
|
static const int MIN_MASTERNODE_PAYMENT_PROTO_VERSION_2 = 70201;
|
|
|
|
|
2015-07-29 17:28:49 +02:00
|
|
|
extern CCriticalSection cs_vecPayments;
|
|
|
|
extern CCriticalSection cs_mapMasternodeBlocks;
|
|
|
|
extern CCriticalSection cs_mapMasternodePayeeVotes;
|
|
|
|
|
2015-04-16 21:58:09 +02:00
|
|
|
class CMasternodePayments;
|
|
|
|
class CMasternodePaymentWinner;
|
2015-04-22 16:33:44 +02:00
|
|
|
class CMasternodeBlockPayees;
|
2015-04-16 21:58:09 +02:00
|
|
|
|
2016-02-04 20:29:09 +01:00
|
|
|
extern CMasternodePayments mnpayments;
|
2015-04-22 16:33:44 +02:00
|
|
|
|
2015-05-04 17:04:09 +02:00
|
|
|
#define MNPAYMENTS_SIGNATURES_REQUIRED 6
|
2015-06-21 19:06:25 +02:00
|
|
|
#define MNPAYMENTS_SIGNATURES_TOTAL 10
|
2015-04-16 21:58:09 +02:00
|
|
|
|
2016-05-24 23:16:42 +02:00
|
|
|
void ProcessMessage(CNode* pfrom, std::string& strCommand, CDataStream& vRecv);
|
2015-04-22 16:33:44 +02:00
|
|
|
bool IsReferenceNode(CTxIn& vin);
|
2016-08-22 03:41:40 +02:00
|
|
|
/// TODO: all 4 functions do not belong here really, they should be refactored/moved somewhere (main.cpp ?)
|
|
|
|
bool IsBlockValueValid(const CBlock& block, int nBlockHeight, CAmount blockReward);
|
|
|
|
bool IsBlockPayeeValid(const CTransaction& txNew, int nBlockHeight, CAmount blockReward);
|
2016-08-28 12:11:36 +02:00
|
|
|
void FillBlockPayments(CMutableTransaction& txNew, int nBlockHeight, CAmount blockReward, CTxOut& txoutMasternodeRet, std::vector<CTxOut>& voutSuperblockRet);
|
2015-07-17 17:07:07 +02:00
|
|
|
std::string GetRequiredPaymentsString(int nBlockHeight);
|
2015-04-22 16:33:44 +02:00
|
|
|
|
2015-06-25 20:08:50 +02:00
|
|
|
class CMasternodePayee
|
2015-04-22 16:33:44 +02:00
|
|
|
{
|
|
|
|
public:
|
2015-06-25 20:08:50 +02:00
|
|
|
CScript scriptPubKey;
|
2015-04-22 16:33:44 +02:00
|
|
|
int nVotes;
|
|
|
|
|
|
|
|
CMasternodePayee() {
|
|
|
|
scriptPubKey = CScript();
|
|
|
|
nVotes = 0;
|
2015-06-25 20:08:50 +02:00
|
|
|
}
|
2015-04-22 16:33:44 +02:00
|
|
|
|
2015-08-30 01:48:19 +02:00
|
|
|
CMasternodePayee(CScript payee, int nVotesIn) {
|
2015-04-22 16:33:44 +02:00
|
|
|
scriptPubKey = payee;
|
2015-06-22 16:20:34 +02:00
|
|
|
nVotes = nVotesIn;
|
2015-04-22 16:33:44 +02:00
|
|
|
}
|
2015-06-25 20:08:50 +02:00
|
|
|
|
|
|
|
ADD_SERIALIZE_METHODS;
|
|
|
|
|
|
|
|
template <typename Stream, typename Operation>
|
|
|
|
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
|
2016-02-02 16:28:56 +01:00
|
|
|
READWRITE(*(CScriptBase*)(&scriptPubKey));
|
2015-06-25 20:08:50 +02:00
|
|
|
READWRITE(nVotes);
|
|
|
|
}
|
2015-04-22 16:33:44 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
// Keep track of votes for payees from masternodes
|
|
|
|
class CMasternodeBlockPayees
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
int nBlockHeight;
|
|
|
|
std::vector<CMasternodePayee> vecPayments;
|
|
|
|
|
|
|
|
CMasternodeBlockPayees(){
|
|
|
|
nBlockHeight = 0;
|
|
|
|
vecPayments.clear();
|
|
|
|
}
|
|
|
|
CMasternodeBlockPayees(int nBlockHeightIn) {
|
|
|
|
nBlockHeight = nBlockHeightIn;
|
|
|
|
vecPayments.clear();
|
|
|
|
}
|
|
|
|
|
2015-08-30 01:48:19 +02:00
|
|
|
void AddPayee(CScript payeeIn, int nIncrement){
|
2015-07-29 17:28:49 +02:00
|
|
|
LOCK(cs_vecPayments);
|
|
|
|
|
2015-04-22 16:33:44 +02:00
|
|
|
BOOST_FOREACH(CMasternodePayee& payee, vecPayments){
|
2015-06-25 20:08:50 +02:00
|
|
|
if(payee.scriptPubKey == payeeIn) {
|
2015-04-22 16:33:44 +02:00
|
|
|
payee.nVotes += nIncrement;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-30 01:48:19 +02:00
|
|
|
CMasternodePayee c(payeeIn, nIncrement);
|
2015-04-22 16:33:44 +02:00
|
|
|
vecPayments.push_back(c);
|
|
|
|
}
|
2015-04-16 21:58:09 +02:00
|
|
|
|
2015-04-22 16:33:44 +02:00
|
|
|
bool GetPayee(CScript& payee)
|
|
|
|
{
|
2015-07-29 17:28:49 +02:00
|
|
|
LOCK(cs_vecPayments);
|
|
|
|
|
2015-04-22 16:33:44 +02:00
|
|
|
int nVotes = -1;
|
|
|
|
BOOST_FOREACH(CMasternodePayee& p, vecPayments){
|
|
|
|
if(p.nVotes > nVotes){
|
2015-06-25 20:08:50 +02:00
|
|
|
payee = p.scriptPubKey;
|
2015-04-22 16:33:44 +02:00
|
|
|
nVotes = p.nVotes;
|
|
|
|
}
|
2015-06-25 20:08:50 +02:00
|
|
|
}
|
2015-04-22 16:33:44 +02:00
|
|
|
|
2015-05-28 19:45:31 +02:00
|
|
|
return (nVotes > -1);
|
2015-04-22 16:33:44 +02:00
|
|
|
}
|
|
|
|
|
2015-07-21 00:09:42 +02:00
|
|
|
bool HasPayeeWithVotes(CScript payee, int nVotesReq)
|
|
|
|
{
|
2015-07-29 17:28:49 +02:00
|
|
|
LOCK(cs_vecPayments);
|
|
|
|
|
2015-07-21 00:09:42 +02:00
|
|
|
BOOST_FOREACH(CMasternodePayee& p, vecPayments){
|
2015-07-22 01:57:21 +02:00
|
|
|
if(p.nVotes >= nVotesReq && p.scriptPubKey == payee) return true;
|
2015-07-21 00:09:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-04-22 16:33:44 +02:00
|
|
|
bool IsTransactionValid(const CTransaction& txNew);
|
|
|
|
std::string GetRequiredPaymentsString();
|
|
|
|
|
|
|
|
ADD_SERIALIZE_METHODS;
|
|
|
|
|
|
|
|
template <typename Stream, typename Operation>
|
|
|
|
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
|
|
|
|
READWRITE(nBlockHeight);
|
|
|
|
READWRITE(vecPayments);
|
|
|
|
}
|
|
|
|
};
|
2015-04-16 21:58:09 +02:00
|
|
|
|
|
|
|
// for storing the winning payments
|
|
|
|
class CMasternodePaymentWinner
|
|
|
|
{
|
|
|
|
public:
|
2015-04-22 16:33:44 +02:00
|
|
|
CTxIn vinMasternode;
|
|
|
|
|
2015-04-16 21:58:09 +02:00
|
|
|
int nBlockHeight;
|
2015-06-25 20:08:50 +02:00
|
|
|
CScript payee;
|
2015-04-16 21:58:09 +02:00
|
|
|
std::vector<unsigned char> vchSig;
|
|
|
|
|
|
|
|
CMasternodePaymentWinner() {
|
|
|
|
nBlockHeight = 0;
|
2015-04-22 16:33:44 +02:00
|
|
|
vinMasternode = CTxIn();
|
2015-06-25 20:08:50 +02:00
|
|
|
payee = CScript();
|
2015-04-22 16:33:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
CMasternodePaymentWinner(CTxIn vinIn) {
|
|
|
|
nBlockHeight = 0;
|
|
|
|
vinMasternode = vinIn;
|
2015-06-25 20:08:50 +02:00
|
|
|
payee = CScript();
|
2015-04-16 21:58:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
uint256 GetHash(){
|
2015-05-28 00:07:53 +02:00
|
|
|
CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
|
2016-02-02 16:28:56 +01:00
|
|
|
ss << *(CScriptBase*)(&payee);
|
2015-05-28 19:45:31 +02:00
|
|
|
ss << nBlockHeight;
|
|
|
|
ss << vinMasternode.prevout;
|
2015-05-28 00:07:53 +02:00
|
|
|
|
2015-06-25 20:08:50 +02:00
|
|
|
return ss.GetHash();
|
2015-04-22 16:33:44 +02:00
|
|
|
}
|
2015-04-16 21:58:09 +02:00
|
|
|
|
2015-04-22 16:33:44 +02:00
|
|
|
bool Sign(CKey& keyMasternode, CPubKey& pubKeyMasternode);
|
2016-08-05 18:25:03 +02:00
|
|
|
bool IsValid(CNode* pnode, int nValidationHeight, std::string& strError);
|
2015-04-22 16:33:44 +02:00
|
|
|
bool SignatureValid();
|
|
|
|
void Relay();
|
|
|
|
|
2015-06-25 20:08:50 +02:00
|
|
|
void AddPayee(CScript payeeIn){
|
|
|
|
payee = payeeIn;
|
2015-04-16 21:58:09 +02:00
|
|
|
}
|
|
|
|
|
2015-07-24 16:12:48 +02:00
|
|
|
|
2015-04-16 21:58:09 +02:00
|
|
|
ADD_SERIALIZE_METHODS;
|
|
|
|
|
|
|
|
template <typename Stream, typename Operation>
|
|
|
|
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
|
2015-04-22 16:33:44 +02:00
|
|
|
READWRITE(vinMasternode);
|
2015-04-16 21:58:09 +02:00
|
|
|
READWRITE(nBlockHeight);
|
2016-02-02 16:28:56 +01:00
|
|
|
READWRITE(*(CScriptBase*)(&payee));
|
2015-04-16 21:58:09 +02:00
|
|
|
READWRITE(vchSig);
|
2015-05-27 21:47:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
std::string ToString()
|
|
|
|
{
|
|
|
|
std::string ret = "";
|
|
|
|
ret += vinMasternode.ToString();
|
|
|
|
ret += ", " + boost::lexical_cast<std::string>(nBlockHeight);
|
2016-02-02 16:28:56 +01:00
|
|
|
ret += ", " + ScriptToAsmStr(payee);
|
2015-05-27 21:47:01 +02:00
|
|
|
ret += ", " + boost::lexical_cast<std::string>((int)vchSig.size());
|
|
|
|
return ret;
|
|
|
|
}
|
2015-04-16 21:58:09 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
//
|
|
|
|
// Masternode Payments Class
|
|
|
|
// Keeps track of who should get paid for which blocks
|
|
|
|
//
|
|
|
|
|
|
|
|
class CMasternodePayments
|
|
|
|
{
|
|
|
|
private:
|
2016-05-30 14:11:09 +02:00
|
|
|
const int nMinBlocksToStore;
|
|
|
|
const float nStorageCoeff;
|
2016-05-29 20:35:09 +02:00
|
|
|
|
2016-03-02 22:20:04 +01:00
|
|
|
// Keep track of current block index
|
|
|
|
const CBlockIndex *pCurrentBlockIndex;
|
2015-04-16 21:58:09 +02:00
|
|
|
|
|
|
|
public:
|
2015-07-21 04:24:43 +02:00
|
|
|
std::map<uint256, CMasternodePaymentWinner> mapMasternodePayeeVotes;
|
|
|
|
std::map<int, CMasternodeBlockPayees> mapMasternodeBlocks;
|
2016-02-02 16:28:56 +01:00
|
|
|
std::map<uint256, int> mapMasternodesLastVote; //Hash(BEGIN(prevout.hash), END(prevout.n)), nBlockHeight
|
2015-04-16 21:58:09 +02:00
|
|
|
|
2016-05-30 14:11:09 +02:00
|
|
|
CMasternodePayments() : nMinBlocksToStore(4000), nStorageCoeff(1.25) {
|
2015-04-16 21:58:09 +02:00
|
|
|
}
|
|
|
|
|
2015-07-21 04:24:43 +02:00
|
|
|
void Clear() {
|
2015-07-29 17:28:49 +02:00
|
|
|
LOCK2(cs_mapMasternodeBlocks, cs_mapMasternodePayeeVotes);
|
2015-07-21 04:24:43 +02:00
|
|
|
mapMasternodeBlocks.clear();
|
|
|
|
mapMasternodePayeeVotes.clear();
|
|
|
|
}
|
|
|
|
|
2015-08-30 01:48:19 +02:00
|
|
|
bool AddWinningMasternode(CMasternodePaymentWinner& winner);
|
2015-04-16 21:58:09 +02:00
|
|
|
bool ProcessBlock(int nBlockHeight);
|
2015-06-25 20:08:50 +02:00
|
|
|
|
2015-07-21 00:09:42 +02:00
|
|
|
void Sync(CNode* node, int nCountNeeded);
|
2016-04-13 19:49:47 +02:00
|
|
|
void CheckAndRemove();
|
2015-04-16 21:58:09 +02:00
|
|
|
int LastPayment(CMasternode& mn);
|
|
|
|
|
2015-04-22 16:33:44 +02:00
|
|
|
bool GetBlockPayee(int nBlockHeight, CScript& payee);
|
|
|
|
bool IsTransactionValid(const CTransaction& txNew, int nBlockHeight);
|
2015-06-15 02:05:51 +02:00
|
|
|
bool IsScheduled(CMasternode& mn, int nNotBlockHeight);
|
2015-04-22 16:33:44 +02:00
|
|
|
|
2015-07-24 16:12:48 +02:00
|
|
|
bool CanVote(COutPoint outMasternode, int nBlockHeight) {
|
2015-07-29 17:28:49 +02:00
|
|
|
LOCK(cs_mapMasternodePayeeVotes);
|
|
|
|
|
2016-02-02 16:28:56 +01:00
|
|
|
if(mapMasternodesLastVote.count(Hash(BEGIN(outMasternode.hash), END(outMasternode.n)))) {
|
|
|
|
if(mapMasternodesLastVote[Hash(BEGIN(outMasternode.hash), END(outMasternode.n))] == nBlockHeight) {
|
2015-07-24 16:12:48 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//record this masternode voted
|
2016-02-02 16:28:56 +01:00
|
|
|
mapMasternodesLastVote[Hash(BEGIN(outMasternode.hash), END(outMasternode.n))] = nBlockHeight;
|
2015-07-24 16:12:48 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-07-08 03:57:32 +02:00
|
|
|
int GetMinMasternodePaymentsProto();
|
2016-05-24 23:16:42 +02:00
|
|
|
void ProcessMessage(CNode* pfrom, std::string& strCommand, CDataStream& vRecv);
|
2015-04-22 16:33:44 +02:00
|
|
|
std::string GetRequiredPaymentsString(int nBlockHeight);
|
2016-08-28 12:11:36 +02:00
|
|
|
void FillBlockPayee(CMutableTransaction& txNew, int nBlockHeight, CAmount blockReward, CTxOut& txoutMasternodeRet);
|
2015-07-21 04:24:43 +02:00
|
|
|
std::string ToString() const;
|
2016-02-04 20:29:09 +01:00
|
|
|
|
2015-07-22 00:14:54 +02:00
|
|
|
int GetOldestBlock();
|
2015-07-21 04:24:43 +02:00
|
|
|
int GetNewestBlock();
|
|
|
|
|
2016-02-04 20:29:09 +01:00
|
|
|
int GetBlockCount()
|
|
|
|
{
|
2016-02-04 23:48:23 +01:00
|
|
|
return mapMasternodeBlocks.size();
|
2016-02-04 20:29:09 +01:00
|
|
|
}
|
|
|
|
int GetVoteCount()
|
|
|
|
{
|
|
|
|
return mapMasternodePayeeVotes.size();
|
|
|
|
}
|
|
|
|
|
2016-05-29 20:35:09 +02:00
|
|
|
bool IsEnoughData(int nMnCount);
|
|
|
|
|
2015-07-21 04:24:43 +02:00
|
|
|
ADD_SERIALIZE_METHODS;
|
2015-04-22 16:33:44 +02:00
|
|
|
|
2015-07-21 04:24:43 +02:00
|
|
|
template <typename Stream, typename Operation>
|
|
|
|
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
|
|
|
|
READWRITE(mapMasternodePayeeVotes);
|
|
|
|
READWRITE(mapMasternodeBlocks);
|
|
|
|
}
|
2016-03-02 22:20:04 +01:00
|
|
|
|
|
|
|
void UpdatedBlockTip(const CBlockIndex *pindex);
|
2015-04-16 21:58:09 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2015-07-21 04:24:43 +02:00
|
|
|
|
2015-07-08 03:57:32 +02:00
|
|
|
#endif
|