text: // Copyright (c) 2014-2015 The Dash developers
  // Copyright (c) 2014-2018 The Crown 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 <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 masternodePayments;
  
  #define MNPAYMENTS_SIGNATURES_REQUIRED           6
  #define MNPAYMENTS_SIGNATURES_TOTAL              10
  #define MN_PMT_SLOT                              1
  
  void ProcessMessageMasternodePayments(CNode* pfrom, std::string& strCommand, CDataStream& vRecv);
  bool IsReferenceNode(CTxIn& vin);
  bool IsBlockPayeeValid(const CAmount& nValueCreated, const CTransaction& txNew, int nBlockHeight, const uint32_t& nTime, const uint32_t& nTimePrevBlock);
  std::string GetRequiredPaymentsString(int nBlockHeight);
  bool IsBlockValueValid(const CBlock& block, int64_t nExpectedValue);
  void FillBlockPayee(CMutableTransaction& txNew, int64_t nFees);
  
  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, const CAmount& nValueCreated);
      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, 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 += ", " + 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<COutPoint, int> mapMasternodesLastVote;
  
      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 CheckAndRemove();
      int LastPayment(CMasternode& mn);
  
      bool GetBlockPayee(int nBlockHeight, CScript& payee);
      bool IsTransactionValid(const CAmount& nValueCreated, const CTransaction& txNew, int nBlockHeight);
      bool IsScheduled(CMasternode& mn, int nNotBlockHeight);
  
      bool CanVote(COutPoint outMasternode, int nBlockHeight);
  
      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 <typename Stream, typename Operation>
      inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
          READWRITE(mapMasternodePayeeVotes);
          READWRITE(mapMasternodeBlocks);
      }
  };
  
  
  
  #endif
  