// 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 using namespace std; //! 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; 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 FillBlockPayments(CMutableTransaction& txNew, int nBlockHeight, CAmount blockReward, CTxOut& txoutMasternodeRet, std::vector& voutSuperblockRet); 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 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 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 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 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 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(nBlockHeight); ret += ", " + ScriptToAsmStr(payee); ret += ", " + boost::lexical_cast((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 mapMasternodePayeeVotes; std::map mapMasternodeBlocks; std::map 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, int nBlockHeight, CAmount blockReward, CTxOut& txoutMasternodeRet); 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 inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { READWRITE(mapMasternodePayeeVotes); READWRITE(mapMasternodeBlocks); } void UpdatedBlockTip(const CBlockIndex *pindex); }; #endif