text: 
  
  // 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 "sync.h"
  #include "net.h"
  #include "key.h"
  #include "util.h"
  #include "base58.h"
  #include "main.h"
  #include "masternode.h"
  
  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 IsBlockPayeeValid(const CBlock& block, int nBlockHeight);
  std::string GetRequiredPaymentsString(int nBlockHeight);
  bool IsBlockValueValid(const CBlock& block, int64_t nExpectedValue, CAmount nMinted);
  void FillBlockPayee(CTransaction& txNew, int64_t nFees, bool fProofOfStake);
  
  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 <typename Stream, typename Operation>
      inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion)
      {
          unsigned int nSerSize = 0;
          READWRITE(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);
  
          for (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;
          for (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);
  
          for (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)
      {
          unsigned int nSerSize = 0;
          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 << 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 <typename Stream, typename Operation>
      inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion)
      {
          unsigned int nSerSize = 0;
          READWRITE(vinMasternode);
          READWRITE(nBlockHeight);
          READWRITE(payee);
          READWRITE(vchSig);
      }
  
      std::string ToString()
      {
          std::string ret = "";
          ret += vinMasternode.ToString();
          ret += ", " + boost::lexical_cast<std::string>(nBlockHeight);
          ret += ", " + payee.ToString();
          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:
      int nSyncedFromPeer;
      int nLastBlockHeight;
  
  public:
      std::map<uint256, CMasternodePaymentWinner> mapMasternodePayeeVotes;
      std::map<int, CMasternodeBlockPayees> mapMasternodeBlocks;
      std::map<uint256, int> 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(CTransaction& txNew, int64_t nFees, bool fProofOfStake);
      std::string ToString() const;
      int GetOldestBlock();
      int GetNewestBlock();
  
      ADD_SERIALIZE_METHODS;
  
      template <typename Stream, typename Operation>
      inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion)
      {
          unsigned int nSerSize = 0;
          READWRITE(mapMasternodePayeeVotes);
          READWRITE(mapMasternodeBlocks);
      }
  };
  
  #endif
  