3b606b0c63
b6b6d6c Added nSuperblockStartBlock, adjusted testnet/regtest params 15a3c64 More for governance block checks, p1 (non-compilable): - add GetPaymentsLimit() and GetPaymentsTotalAmount() - IsValidBlockHeight() should check nSuperblockStartBlock - CSuperblock::IsValid should check payment limit and miner payout - no cs_main - slightly refactored related things e8f9e5d More for governance checks, p2 (compilable): - IsBlockValueValid(), IsBlockPayeeValid() and FillBlockPayee() rewritten, no cs_main for them - CreateNewBlock adjusted, need more work on CBlockTemplate (see TODO) - moved (and simplified) IsBlockPayeeValid() call from CheckBlock() to ConnectBlock() 51434cf Add ability to calculate only superblock part of subsidy in GetBlockSubsidy() aa74200 Fix GetPaymentsLimit() f7b6234 braces and comment ade8f64 more checks for IsValidBlockHeight()
283 lines
7.6 KiB
C++
283 lines
7.6 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_PAYMENTS_H
|
|
#define MASTERNODE_PAYMENTS_H
|
|
|
|
#include "util.h"
|
|
#include "core_io.h"
|
|
#include "key.h"
|
|
#include "main.h"
|
|
#include "masternode.h"
|
|
#include "utilstrencodings.h"
|
|
|
|
#include <boost/lexical_cast.hpp>
|
|
|
|
using namespace std;
|
|
|
|
extern CCriticalSection cs_vecPayments;
|
|
extern CCriticalSection cs_mapMasternodeBlocks;
|
|
extern CCriticalSection cs_mapMasternodePayeeVotes;
|
|
|
|
class CMasternodePayments;
|
|
class CMasternodePaymentWinner;
|
|
class CMasternodeBlockPayees;
|
|
|
|
extern CMasternodePayments mnpayments;
|
|
|
|
#define MNPAYMENTS_SIGNATURES_REQUIRED 6
|
|
#define MNPAYMENTS_SIGNATURES_TOTAL 10
|
|
|
|
void ProcessMessage(CNode* pfrom, std::string& strCommand, CDataStream& vRecv);
|
|
bool IsReferenceNode(CTxIn& vin);
|
|
/// 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);
|
|
void FillBlockPayee(CMutableTransaction& txNew, CAmount blockReward, int nBlockHeight);
|
|
std::string GetRequiredPaymentsString(int nBlockHeight);
|
|
|
|
class CMasternodePayee
|
|
{
|
|
public:
|
|
CScript scriptPubKey;
|
|
int nVotes;
|
|
|
|
CMasternodePayee() {
|
|
scriptPubKey = CScript();
|
|
nVotes = 0;
|
|
}
|
|
|
|
CMasternodePayee(CScript payee, int nVotesIn) {
|
|
scriptPubKey = payee;
|
|
nVotes = nVotesIn;
|
|
}
|
|
|
|
ADD_SERIALIZE_METHODS;
|
|
|
|
template <typename Stream, typename Operation>
|
|
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
|
|
READWRITE(*(CScriptBase*)(&scriptPubKey));
|
|
READWRITE(nVotes);
|
|
}
|
|
};
|
|
|
|
// 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();
|
|
}
|
|
|
|
void AddPayee(CScript payeeIn, int nIncrement){
|
|
LOCK(cs_vecPayments);
|
|
|
|
BOOST_FOREACH(CMasternodePayee& payee, vecPayments){
|
|
if(payee.scriptPubKey == payeeIn) {
|
|
payee.nVotes += nIncrement;
|
|
return;
|
|
}
|
|
}
|
|
|
|
CMasternodePayee c(payeeIn, nIncrement);
|
|
vecPayments.push_back(c);
|
|
}
|
|
|
|
bool GetPayee(CScript& payee)
|
|
{
|
|
LOCK(cs_vecPayments);
|
|
|
|
int nVotes = -1;
|
|
BOOST_FOREACH(CMasternodePayee& p, vecPayments){
|
|
if(p.nVotes > nVotes){
|
|
payee = p.scriptPubKey;
|
|
nVotes = p.nVotes;
|
|
}
|
|
}
|
|
|
|
return (nVotes > -1);
|
|
}
|
|
|
|
bool HasPayeeWithVotes(CScript payee, int nVotesReq)
|
|
{
|
|
LOCK(cs_vecPayments);
|
|
|
|
BOOST_FOREACH(CMasternodePayee& p, vecPayments){
|
|
if(p.nVotes >= nVotesReq && p.scriptPubKey == payee) return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
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);
|
|
}
|
|
};
|
|
|
|
// for storing the winning payments
|
|
class CMasternodePaymentWinner
|
|
{
|
|
public:
|
|
CTxIn vinMasternode;
|
|
|
|
int nBlockHeight;
|
|
CScript payee;
|
|
std::vector<unsigned char> vchSig;
|
|
|
|
CMasternodePaymentWinner() {
|
|
nBlockHeight = 0;
|
|
vinMasternode = CTxIn();
|
|
payee = CScript();
|
|
}
|
|
|
|
CMasternodePaymentWinner(CTxIn vinIn) {
|
|
nBlockHeight = 0;
|
|
vinMasternode = vinIn;
|
|
payee = CScript();
|
|
}
|
|
|
|
uint256 GetHash(){
|
|
CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
|
|
ss << *(CScriptBase*)(&payee);
|
|
ss << nBlockHeight;
|
|
ss << vinMasternode.prevout;
|
|
|
|
return ss.GetHash();
|
|
}
|
|
|
|
bool Sign(CKey& keyMasternode, CPubKey& pubKeyMasternode);
|
|
bool IsValid(CNode* pnode, int nValidationHeight, std::string& strError);
|
|
bool SignatureValid();
|
|
void Relay();
|
|
|
|
void AddPayee(CScript payeeIn){
|
|
payee = payeeIn;
|
|
}
|
|
|
|
|
|
ADD_SERIALIZE_METHODS;
|
|
|
|
template <typename Stream, typename Operation>
|
|
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
|
|
READWRITE(vinMasternode);
|
|
READWRITE(nBlockHeight);
|
|
READWRITE(*(CScriptBase*)(&payee));
|
|
READWRITE(vchSig);
|
|
}
|
|
|
|
std::string ToString()
|
|
{
|
|
std::string ret = "";
|
|
ret += vinMasternode.ToString();
|
|
ret += ", " + boost::lexical_cast<std::string>(nBlockHeight);
|
|
ret += ", " + ScriptToAsmStr(payee);
|
|
ret += ", " + boost::lexical_cast<std::string>((int)vchSig.size());
|
|
return ret;
|
|
}
|
|
};
|
|
|
|
//
|
|
// Masternode Payments Class
|
|
// Keeps track of who should get paid for which blocks
|
|
//
|
|
|
|
class CMasternodePayments
|
|
{
|
|
private:
|
|
const int nMinBlocksToStore;
|
|
const float nStorageCoeff;
|
|
|
|
// Keep track of current block index
|
|
const CBlockIndex *pCurrentBlockIndex;
|
|
|
|
public:
|
|
std::map<uint256, CMasternodePaymentWinner> mapMasternodePayeeVotes;
|
|
std::map<int, CMasternodeBlockPayees> mapMasternodeBlocks;
|
|
std::map<uint256, int> mapMasternodesLastVote; //Hash(BEGIN(prevout.hash), END(prevout.n)), nBlockHeight
|
|
|
|
CMasternodePayments() : nMinBlocksToStore(4000), nStorageCoeff(1.25) {
|
|
}
|
|
|
|
void Clear() {
|
|
LOCK2(cs_mapMasternodeBlocks, cs_mapMasternodePayeeVotes);
|
|
mapMasternodeBlocks.clear();
|
|
mapMasternodePayeeVotes.clear();
|
|
}
|
|
|
|
bool AddWinningMasternode(CMasternodePaymentWinner& winner);
|
|
bool ProcessBlock(int nBlockHeight);
|
|
|
|
void Sync(CNode* node, int nCountNeeded);
|
|
void CheckAndRemove();
|
|
int LastPayment(CMasternode& mn);
|
|
|
|
bool GetBlockPayee(int nBlockHeight, CScript& payee);
|
|
bool IsTransactionValid(const CTransaction& txNew, int nBlockHeight);
|
|
bool IsScheduled(CMasternode& mn, int nNotBlockHeight);
|
|
|
|
bool CanVote(COutPoint outMasternode, int nBlockHeight) {
|
|
LOCK(cs_mapMasternodePayeeVotes);
|
|
|
|
if(mapMasternodesLastVote.count(Hash(BEGIN(outMasternode.hash), END(outMasternode.n)))) {
|
|
if(mapMasternodesLastVote[Hash(BEGIN(outMasternode.hash), END(outMasternode.n))] == nBlockHeight) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
//record this masternode voted
|
|
mapMasternodesLastVote[Hash(BEGIN(outMasternode.hash), END(outMasternode.n))] = nBlockHeight;
|
|
return true;
|
|
}
|
|
|
|
int GetMinMasternodePaymentsProto();
|
|
void ProcessMessage(CNode* pfrom, std::string& strCommand, CDataStream& vRecv);
|
|
std::string GetRequiredPaymentsString(int nBlockHeight);
|
|
void FillBlockPayee(CMutableTransaction& txNew, CAmount blockReward, int nBlockHeight);
|
|
std::string ToString() const;
|
|
|
|
int GetOldestBlock();
|
|
int GetNewestBlock();
|
|
|
|
int GetBlockCount()
|
|
{
|
|
return mapMasternodeBlocks.size();
|
|
}
|
|
int GetVoteCount()
|
|
{
|
|
return mapMasternodePayeeVotes.size();
|
|
}
|
|
|
|
bool IsEnoughData(int nMnCount);
|
|
|
|
ADD_SERIALIZE_METHODS;
|
|
|
|
template <typename Stream, typename Operation>
|
|
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
|
|
READWRITE(mapMasternodePayeeVotes);
|
|
READWRITE(mapMasternodeBlocks);
|
|
}
|
|
|
|
void UpdatedBlockTip(const CBlockIndex *pindex);
|
|
};
|
|
|
|
|
|
|
|
#endif
|