text: // Copyright (c) 2009-2010 Satoshi Nakamoto
  // Copyright (c) 2009-2016 The Bitcoin Core developers
  // Copyright (c) 2016-2019 The MagnaChain Core developers
  // Distributed under the MIT software license, see the accompanying
  // file COPYING or http://www.opensource.org/licenses/mit-license.php.
  
  #ifndef MAGNACHAIN_MINER_H
  #define MAGNACHAIN_MINER_H
  
  #include "primitives/block.h"
  #include "transaction/txmempool.h"
  
  #include <stdint.h>
  #include <memory>
  #include "boost/multi_index_container.hpp"
  #include "boost/multi_index/ordered_index.hpp"
  
  extern uint64_t ReservePubContractBlockDataSize;
  extern uint64_t ReserveCallContractBlockDataSize;
  extern uint64_t ReserveBranchTxBlockDataSize;
  
  class MCBlockIndex;
  class MCChainParams;
  class MCScript;
  class MCKeyStore;
  
  namespace Consensus { struct Params; };
  
  static const bool DEFAULT_PRINTPRIORITY = false;
  
  struct MCBlockTemplate
  {
      MCBlock block;
      std::vector<MCAmount> vTxFees;
      std::vector<int64_t> vTxSigOpsCost;
      std::vector<unsigned char> vchCoinbaseCommitment;
  };
  
  // Container for tracking updates to ancestor feerate as we include (parent)
  // transactions in a block
  struct MCTxMemPoolModifiedEntry {
      MCTxMemPoolModifiedEntry(MCTxMemPool::txiter entry)
      {
          iter = entry;
          nSizeWithAncestors = entry->GetSizeWithAncestors();
          nModFeesWithAncestors = entry->GetModFeesWithAncestors();
          nSigOpCostWithAncestors = entry->GetSigOpCostWithAncestors();
      }
  
      MCTxMemPool::txiter iter;
      uint64_t nSizeWithAncestors;
      MCAmount nModFeesWithAncestors;
      int64_t nSigOpCostWithAncestors;
  };
  
  /** Comparator for MCTxMemPool::txiter objects.
   *  It simply compares the internal memory address of the MCTxMemPoolEntry object
   *  pointed to. This means it has no meaning, and is only useful for using them
   *  as key in other indexes.
   */
  struct CompareCTxMemPoolIter {
      bool operator()(const MCTxMemPool::txiter& a, const MCTxMemPool::txiter& b) const
      {
          return &(*a) < &(*b);
      }
  };
  
  struct modifiedentry_iter {
      typedef MCTxMemPool::txiter result_type;
      result_type operator() (const MCTxMemPoolModifiedEntry &entry) const
      {
          return entry.iter;
      }
  };
  
  // This matches the calculation in CompareTxMemPoolEntryByAncestorFee,
  // except operating on MCTxMemPoolModifiedEntry.
  // TODO: refactor to avoid duplication of this logic.
  struct CompareModifiedEntry {
      bool operator()(const MCTxMemPoolModifiedEntry &a, const MCTxMemPoolModifiedEntry &b) const
      {
          double f1 = (double)a.nModFeesWithAncestors * b.nSizeWithAncestors;
          double f2 = (double)b.nModFeesWithAncestors * a.nSizeWithAncestors;
          if (f1 == f2) {
              return MCTxMemPool::CompareIteratorByHash()(a.iter, b.iter);
          }
          return f1 > f2;
      }
  };
  
  // A comparator that sorts transactions based on number of ancestors.
  // This is sufficient to sort an ancestor package in an order that is valid
  // to appear in a block.
  struct CompareTxIterByAncestorCount {
      bool operator()(const MCTxMemPool::txiter &a, const MCTxMemPool::txiter &b)
      {
          if (a->GetCountWithAncestors() != b->GetCountWithAncestors())
              return a->GetCountWithAncestors() < b->GetCountWithAncestors();
          return MCTxMemPool::CompareIteratorByHash()(a, b);
      }
  };
  
  typedef boost::multi_index_container<
      MCTxMemPoolModifiedEntry,
      boost::multi_index::indexed_by<
          boost::multi_index::ordered_unique<
              modifiedentry_iter,
              CompareCTxMemPoolIter
          >,
          // sorted by modified ancestor fee rate
          boost::multi_index::ordered_non_unique<
              // Reuse same tag from MCTxMemPool's similar index
              boost::multi_index::tag<ancestor_score>,
              boost::multi_index::identity<MCTxMemPoolModifiedEntry>,
              CompareModifiedEntry
          >
      >
  > indexed_modified_transaction_set;
  
  typedef indexed_modified_transaction_set::nth_index<0>::type::iterator modtxiter;
  typedef indexed_modified_transaction_set::index<ancestor_score>::type::iterator modtxscoreiter;
  
  struct update_for_parent_inclusion
  {
      update_for_parent_inclusion(MCTxMemPool::txiter it) : iter(it) {}
  
      void operator() (MCTxMemPoolModifiedEntry &e) const
      {
          e.nModFeesWithAncestors -= iter->GetFee();
          e.nSizeWithAncestors -= iter->GetTxSize();
          e.nSigOpCostWithAncestors -= iter->GetSigOpCost();
      }
  
      MCTxMemPool::txiter iter;
  };
  
  class BranchUTXOCache
  {
  public:
      typedef std::map<MCOutPoint, MCTxOut> MAP_CACHE_COIN;
  
      CoinList coinlist;
      MAP_CACHE_COIN mapCacheCoin;
  };
  
  class MakeBranchTxUTXO
  {
  public:
      typedef std::map<uint160, BranchUTXOCache> MAP_BRANCH_COINS;
      typedef std::map<uint256, MCTransactionRef> MAP_MAKE_CACHE;
      
      MCAmount UseUTXO(const uint160& key, MCAmount nAmount, std::vector<MCOutPoint>& vInOutPoints);
      bool MakeTxUTXO(MCMutableTransaction& tx, const uint160& key, MCAmount nAmount, MCScript& scriptSig, MCScript& changeScriptPubKey);
  
      MAP_MAKE_CACHE mapCache;
      MAP_BRANCH_COINS mapBranchCoins;
  };
  
  /** Generate a new block, without valid proof-of-work */
  class BlockAssembler
  {
  private:
      // The constructed block template
      std::unique_ptr<MCBlockTemplate> pblocktemplate;
      // A convenience pointer that always refers to the MCBlock in pblocktemplate
      MCBlock* pblock;
  
      // Configuration parameters for the block size
      bool fIncludeWitness;
      unsigned int nBlockMaxWeight;
      MCFeeRate blockMinFeeRate;
  
      // Information on the current status of the block
      uint64_t nBlockWeight;
      uint64_t nBlockTx;
      uint64_t nBlockSigOpsCost;
      MCAmount nFees;
      MCTxMemPool::setEntries inBlock;
  
      // Chain context for the block
      int nHeight;
      int64_t nLockTimeCutoff;
      const MCChainParams& chainparams;
  	MCOutPoint outpoint;
  
  public:
      struct Options {
          Options();
          size_t nBlockMaxWeight;
          size_t nBlockMaxSize;
          MCFeeRate blockMinFeeRate;
  		MCOutPoint outpoint;
      };
  	static Options DefaultOptions(const MCChainParams& params );
  
      BlockAssembler(const MCChainParams& params);
      BlockAssembler(const MCChainParams& params, const Options& options);
  
      /** Construct a new block template with coinbase to scriptPubKeyIn */
      std::unique_ptr<MCBlockTemplate> CreateNewBlock(const MCScript& scriptPubKeyIn, bool fMineWitnessTx, 
          const MCKeyStore* keystoreIn, MCCoinsViewCache *pcoinsCache, std::string& strErr);
  
  private:
      // utility functions
      /** Clear the block's state and prepare for assembling a new block */
      void resetBlock();
      /** Add a tx to the block */
      void AddToBlock(MCTxMemPool::txiter iter, MakeBranchTxUTXO& utxoMaker);
  
      void GroupingTransaction(size_t offset, std::vector<const MCTxMemPoolEntry*>& blockTxEntries);
  
      // Methods for how to add transactions to a block.
      /** Add transactions based on feerate including unconfirmed ancestors
        * Increments nPackagesSelected / nDescendantsUpdated with corresponding
        * statistics from the package selection (for logging statistics). */
      void addPackageTxs(int &nPackagesSelected, int &nDescendantsUpdated);
  
      // helper functions for addPackageTxs()
      /** Remove confirmed (inBlock) entries from given set */
      void onlyUnconfirmed(MCTxMemPool::setEntries& testSet);
  
      uint64_t GetTxReserveBlockSize(const MCTransaction& tx);
  
      /** Test if a new package would "fit" in the block */
      bool TestPackage(MCTxMemPool::txiter iter, uint64_t packageSize, int64_t packageSigOpsCost);
      /** Perform checks on each transaction in a package:
        * locktime, premature-witness, serialized size (if necessary)
        * These checks should always succeed, and they're here
        * only as an extra check in case of suboptimal node configuration */
      bool TestPackageTransactions(const MCTxMemPool::setEntries& package);
      /** Return true if given transaction from mapTx has already been evaluated,
        * or if the transaction's cached data in mapTx is incorrect. */
      bool SkipMapTxEntry(MCTxMemPool::txiter it, indexed_modified_transaction_set &mapModifiedTx, MCTxMemPool::setEntries &failedTx);
      /** Sort the package in an order that is valid to appear in a block */
      void SortForBlock(const MCTxMemPool::setEntries& package, MCTxMemPool::txiter entry, std::vector<MCTxMemPool::txiter>& sortedEntries);
      /** Add descendants of given transactions to mapModifiedTx with ancestor
        * state updated assuming given transactions are inBlock. Returns number
        * of updated descendants. */
      int UpdatePackagesForAdded(const MCTxMemPool::setEntries& alreadyAdded, indexed_modified_transaction_set &mapModifiedTx);
  
      //
      //void addReportProofTx(const MCTransactionRef &ptxReport, const MCScript &minerpkey, const MCCoinsViewCache* pCoinsCache);
      //void addReportProofTxs(const MCScript& scriptPubKeyIn, MCCoinsViewCache *pcoinsCache);
      bool UpdateIncompleteTx(MCTxMemPool::txiter iter, MakeBranchTxUTXO& utxoMaker);
  };
  
  /** Modify the extranonce in a block */
  void IncrementExtraNonce(MCBlock* pblock, const MCBlockIndex* pindexPrev, unsigned int& nExtraNonce);
  int64_t UpdateTime(MCBlockHeader* pblock, const Consensus::Params& consensusParams, const MCBlockIndex* pindexPrev);
  
  #endif // MAGNACHAIN_MINER_H
  