text: // Copyright (c) 2014-2017 The Expcoin 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"
  
  class CMasternodePayments;
  class CMasternodePaymentVote;
  class CMasternodeBlockPayees;
  
  static const int MNPAYMENTS_SIGNATURES_REQUIRED         = 6;
  static const int MNPAYMENTS_SIGNATURES_TOTAL            = 10;
  
  //! minimum peer version that can receive and send masternode payment messages,
  //  vote for masternode and be elected as a payment winner
  // V1 - Last protocol version before update
  // V2 - Newest protocol version
  static const int MIN_MASTERNODE_PAYMENT_PROTO_VERSION_1 = 70206;
  static const int MIN_MASTERNODE_PAYMENT_PROTO_VERSION_2 = 70206;
  
  extern CCriticalSection cs_vecPayees;
  extern CCriticalSection cs_mapMasternodeBlocks;
  extern CCriticalSection cs_mapMasternodePayeeVotes;
  
  extern CMasternodePayments mnpayments;
  
  /// 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, std::string &strErrorRet);
  bool IsBlockPayeeValid(const CTransaction& txNew, int nBlockHeight, CAmount blockReward);
  void FillBlockPayments(CMutableTransaction& txNew, int nBlockHeight, CAmount blockReward, CTxOut& txoutMasternodeRet, std::vector<CTxOut>& voutSuperblockRet);
  std::string GetRequiredPaymentsString(int nBlockHeight);
  
  class CMasternodePayee
  {
  private:
      CScript scriptPubKey;
      std::vector<uint256> vecVoteHashes;
  
  public:
      CMasternodePayee() :
          scriptPubKey(),
          vecVoteHashes()
          {}
  
      CMasternodePayee(CScript payee, uint256 hashIn) :
          scriptPubKey(payee),
          vecVoteHashes()
      {
          vecVoteHashes.push_back(hashIn);
      }
  
      ADD_SERIALIZE_METHODS;
  
      template <typename Stream, typename Operation>
      inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
          READWRITE(*(CScriptBase*)(&scriptPubKey));
          READWRITE(vecVoteHashes);
      }
  
      CScript GetPayee() { return scriptPubKey; }
  
      void AddVoteHash(uint256 hashIn) { vecVoteHashes.push_back(hashIn); }
      std::vector<uint256> GetVoteHashes() { return vecVoteHashes; }
      int GetVoteCount() { return vecVoteHashes.size(); }
  };
  
  // Keep track of votes for payees from masternodes
  class CMasternodeBlockPayees
  {
  public:
      int nBlockHeight;
      std::vector<CMasternodePayee> vecPayees;
  
      CMasternodeBlockPayees() :
          nBlockHeight(0),
          vecPayees()
          {}
      CMasternodeBlockPayees(int nBlockHeightIn) :
          nBlockHeight(nBlockHeightIn),
          vecPayees()
          {}
  
      ADD_SERIALIZE_METHODS;
  
      template <typename Stream, typename Operation>
      inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
          READWRITE(nBlockHeight);
          READWRITE(vecPayees);
      }
  
      void AddPayee(const CMasternodePaymentVote& vote);
      bool GetBestPayee(CScript& payeeRet);
      bool HasPayeeWithVotes(CScript payeeIn, int nVotesReq);
  
      bool IsTransactionValid(const CTransaction& txNew);
  
      std::string GetRequiredPaymentsString();
  };
  
  // vote for the winning payment
  class CMasternodePaymentVote
  {
  public:
      CTxIn vinMasternode;
  
      int nBlockHeight;
      CScript payee;
      std::vector<unsigned char> vchSig;
  
      CMasternodePaymentVote() :
          vinMasternode(),
          nBlockHeight(0),
          payee(),
          vchSig()
          {}
  
      CMasternodePaymentVote(CTxIn vinMasternode, int nBlockHeight, CScript payee) :
          vinMasternode(vinMasternode),
          nBlockHeight(nBlockHeight),
          payee(payee),
          vchSig()
          {}
  
      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);
      }
  
      uint256 GetHash() const {
          CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
          ss << *(CScriptBase*)(&payee);
          ss << nBlockHeight;
          ss << vinMasternode.prevout;
          return ss.GetHash();
      }
  
      bool Sign();
      bool CheckSignature(const CPubKey& pubKeyMasternode, int nValidationHeight, int &nDos);
  
      bool IsValid(CNode* pnode, int nValidationHeight, std::string& strError);
      void Relay();
  
      bool IsVerified() { return !vchSig.empty(); }
      void MarkAsNotVerified() { vchSig.clear(); }
  
      std::string ToString() const;
  };
  
  //
  // Masternode Payments Class
  // Keeps track of who should get paid for which blocks
  //
  
  class CMasternodePayments
  {
  private:
      // masternode count times nStorageCoeff payments blocks should be stored ...
      const float nStorageCoeff;
      // ... but at least nMinBlocksToStore (payments blocks)
      const int nMinBlocksToStore;
  
      // Keep track of current block index
      const CBlockIndex *pCurrentBlockIndex;
  
  public:
      std::map<uint256, CMasternodePaymentVote> mapMasternodePaymentVotes;
      std::map<int, CMasternodeBlockPayees> mapMasternodeBlocks;
      std::map<COutPoint, int> mapMasternodesLastVote;
  
      CMasternodePayments() : nStorageCoeff(1.25), nMinBlocksToStore(5000) {}
  
      ADD_SERIALIZE_METHODS;
  
      template <typename Stream, typename Operation>
      inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
          READWRITE(mapMasternodePaymentVotes);
          READWRITE(mapMasternodeBlocks);
      }
  
      void Clear();
  
      bool AddPaymentVote(const CMasternodePaymentVote& vote);
      bool HasVerifiedPaymentVote(uint256 hashIn);
      bool ProcessBlock(int nBlockHeight);
  
      void Sync(CNode* node);
      void RequestLowDataPaymentBlocks(CNode* pnode);
      void CheckAndRemove();
  
      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);
  
      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 GetBlockCount() { return mapMasternodeBlocks.size(); }
      int GetVoteCount() { return mapMasternodePaymentVotes.size(); }
  
      bool IsEnoughData();
      int GetStorageLimit();
  
      void UpdatedBlockTip(const CBlockIndex *pindex);
  };
  
  #endif
  