// Copyright (c) 2014-2015 The Dash 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 "key.h" #include "main.h" #include "masternode.h" #include using namespace std; extern CCriticalSection cs_vecPayments; extern CCriticalSection cs_mapMasternodeBlocks; extern CCriticalSection cs_mapMasternodePayeeVotes; class CMasternodePayments; class CMasternodePaymentWinner; class CMasternodeBlockPayees; extern CMasternodePayments masternodePayments; #define MNPAYMENTS_SIGNATURES_REQUIRED 6 #define MNPAYMENTS_SIGNATURES_TOTAL 10 void ProcessMessageMasternodePayments(CNode* pfrom, std::string& strCommand, CDataStream& vRecv); bool IsReferenceNode(CTxIn& vin); bool IsBlockPayeeValid(const CTransaction& txNew, int nBlockHeight); std::string GetRequiredPaymentsString(int nBlockHeight); bool IsBlockValueValid(const CBlock& block, int64_t nExpectedValue); void FillBlockPayee(CMutableTransaction& txNew, int64_t nFees); void DumpMasternodePayments(); /** Save Masternode Payment Data (mnpayments.dat) */ class CMasternodePaymentDB { private: boost::filesystem::path pathDB; std::string strMagicMessage; public: enum ReadResult { Ok, FileError, HashReadError, IncorrectHash, IncorrectMagicMessage, IncorrectMagicNumber, IncorrectFormat }; CMasternodePaymentDB(); bool Write(const CMasternodePayments &objToSave); ReadResult Read(CMasternodePayments& objToLoad, bool fDryRun = false); }; 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(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 << payee; ss << nBlockHeight; ss << vinMasternode.prevout; return ss.GetHash(); } bool Sign(CKey& keyMasternode, CPubKey& pubKeyMasternode); bool IsValid(CNode* pnode, 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(payee); READWRITE(vchSig); } std::string ToString() { std::string ret = ""; ret += vinMasternode.ToString(); ret += ", " + boost::lexical_cast(nBlockHeight); ret += ", " + payee.ToString(); 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: int nSyncedFromPeer; int nLastBlockHeight; public: std::map mapMasternodePayeeVotes; std::map mapMasternodeBlocks; std::map mapMasternodesLastVote; //prevout.hash + prevout.n, nBlockHeight CMasternodePayments() { nSyncedFromPeer = 0; nLastBlockHeight = 0; } 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 CleanPaymentList(); 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(outMasternode.hash + outMasternode.n)) { if(mapMasternodesLastVote[outMasternode.hash + outMasternode.n] == nBlockHeight) { return false; } } //record this masternode voted mapMasternodesLastVote[outMasternode.hash + outMasternode.n] = nBlockHeight; return true; } int GetMinMasternodePaymentsProto(); void ProcessMessageMasternodePayments(CNode* pfrom, std::string& strCommand, CDataStream& vRecv); std::string GetRequiredPaymentsString(int nBlockHeight); void FillBlockPayee(CMutableTransaction& txNew, int64_t nFees); std::string ToString() const; int GetOldestBlock(); int GetNewestBlock(); ADD_SERIALIZE_METHODS; template inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { READWRITE(mapMasternodePayeeVotes); READWRITE(mapMasternodeBlocks); } }; #endif