text: // Copyright (c) 2009-2010  Satoshi Nakamoto
  // Copyright (c) 2009-2012 The Bitcoin developers
  // Distributed under the MIT/X11 software license, see the accompanying
  // file COPYING or http://www.opensource.org/licenses/mit-license.php.
  #ifndef BITCOIN_MAIN_H
  #define BITCOIN_MAIN_H
  
  #include "core.h"
  #include "bignum.h"
  #include "sync.h"
  #include "txmempool.h"
  #include "net.h"
  #include "script.h"
  #include "scrypt.h"
  
  #include <list>
  
  class CBlock;
  class CBlockIndex;
  class CInv;
  class CKeyItem;
  class CNode;
  class CReserveKey;
  class CWallet;
  
  #define USE_OLDHASH 0
  
  /** The maximum allowed size for a serialized block, in bytes (network rule) */
  //static const unsigned int IPO_VALUES  = 100000
  static const unsigned int MAX_BLOCK_SIZE = 2000000;
  /** The maximum size for mined blocks */
  static const unsigned int MAX_BLOCK_SIZE_GEN = MAX_BLOCK_SIZE/2;
  /** The maximum size for transactions we're willing to relay/mine **/
  static const unsigned int MAX_STANDARD_TX_SIZE = MAX_BLOCK_SIZE_GEN/5;
  /** The maximum allowed number of signature check operations in a block (network rule) */
  static const unsigned int MAX_BLOCK_SIGOPS = MAX_BLOCK_SIZE/50;
  /** Maxiumum number of signature check operations in an IsStandard() P2SH script */
  static const unsigned int MAX_P2SH_SIGOPS = 15;
  /** The maximum number of sigops we're willing to relay/mine in a single tx */
  static const unsigned int MAX_TX_SIGOPS = MAX_BLOCK_SIGOPS/5;
  /** The maximum number of orphan transactions kept in memory */
  static const unsigned int MAX_ORPHAN_TRANSACTIONS = MAX_BLOCK_SIZE/100;
  /** Default for -maxorphanblocksmib, maximum number of memory to keep orphan blocks */
  static const unsigned int DEFAULT_MAX_ORPHAN_BLOCKS = 40;
  /** The maximum number of entries in an 'inv' protocol message */
  static const unsigned int MAX_INV_SZ = 50000;
  /** Fees smaller than this (in satoshi) are considered zero fee (for transaction creation) */
  static const int64_t MIN_TX_FEE = 10000;
  /** Fees smaller than this (in satoshi) are considered zero fee (for relaying) */
  static const int64_t MIN_RELAY_TX_FEE = MIN_TX_FEE;
  /** No amount larger than this (in satoshi) is valid */
  static const int64_t MAX_MONEY = 1000000000 * COIN;
  inline bool MoneyRange(int64_t nValue) { return (nValue >= 0 && nValue <= MAX_MONEY); }
  /** Threshold for nLockTime: below this value it is interpreted as block number, otherwise as UNIX timestamp. */
  static const unsigned int LOCKTIME_THRESHOLD = 500000000; // Tue Nov  5 00:53:20 1985 UTC
  static const int64_t IPO_SHARE = 630000000 * COIN;
  static const int64_t COIN_YEAR_REWARD = 1 * CENT; // 1% per year
  
  
  inline bool IsProtocolV1RetargetingFixed(int nHeight) { /*return TestNet() || nHeight > 38423;*/return true; }
  inline bool IsProtocolV2(int nHeight) { /*return TestNet() || nHeight > 319000;*/ return true; }
  inline bool IsProtocolV3(int64_t nTime) { return TestNet() || nTime > 2444028400; }
  
  inline int64_t FutureDriftV1(int64_t nTime) { return nTime + 10 * 60; }
  inline int64_t FutureDriftV2(int64_t nTime) { return nTime + 15; }
  inline int64_t FutureDrift(int64_t nTime, int nHeight) { return IsProtocolV2(nHeight) ? FutureDriftV2(nTime) : FutureDriftV1(nTime); }
  
  inline int64_t PastDriftV1(int64_t nTime) { return nTime - 10 * 60; }
  inline int64_t PastDriftV2(int64_t nTime) { return nTime - 15; }
  inline int64_t PastDrift(int64_t nTime, int nHeight)   { return  IsProtocolV2(nHeight) ? PastDriftV2(nTime) : PastDriftV1(nTime); }
  
  
  inline unsigned int GetTargetSpacing(int nHeight) { return /*IsProtocolV2(nHeight) ? 64 :*/ 60; }
  
  extern CScript COINBASE_FLAGS;
  extern CCriticalSection cs_main;
  extern CTxMemPool mempool;
  extern std::map<uint256, CBlockIndex*> mapBlockIndex;
  extern std::set<std::pair<COutPoint, unsigned int> > setStakeSeen;
  extern CBlockIndex* pindexGenesisBlock;
  extern int nStakeMinConfirmations;
  extern unsigned int nStakeMinAge;
  extern unsigned int nNodeLifespan;
  extern int nCoinbaseMaturity;
  extern int nBestHeight;
  extern uint256 nBestChainTrust;
  extern uint256 nBestInvalidTrust;
  extern uint256 hashBestChain;
  extern CBlockIndex* pindexBest;
  extern uint64_t nLastBlockTx;
  extern uint64_t nLastBlockSize;
  extern int64_t nLastCoinStakeSearchInterval;
  extern const std::string strMessageMagic;
  extern int64_t nTimeBestReceived;
  extern bool fImporting;
  extern bool fReindex;
  struct COrphanBlock;
  extern std::map<uint256, COrphanBlock*> mapOrphanBlocks;
  extern bool fHaveGUI;
  
  // Settings
  extern bool fUseFastIndex;
  extern unsigned int nDerivationMethodIndex;
  
  extern bool fMinimizeCoinAge;
  
  // Minimum disk space required - used in CheckDiskSpace()
  static const uint64_t nMinDiskSpace = 52428800;
  
  class CReserveKey;
  class CTxDB;
  class CTxIndex;
  class CWalletInterface;
  
  /** Register a wallet to receive updates from core */
  void RegisterWallet(CWalletInterface* pwalletIn);
  /** Unregister a wallet from core */
  void UnregisterWallet(CWalletInterface* pwalletIn);
  /** Unregister all wallets from core */
  void UnregisterAllWallets();
  /** Push an updated transaction to all registered wallets */
  void SyncWithWallets(const CTransaction& tx, const CBlock* pblock = NULL, bool fConnect = true);
  /** Ask wallets to resend their transactions */
  void ResendWalletTransactions(bool fForce = false);
  
  /** Register with a network node to receive its signals */
  void RegisterNodeSignals(CNodeSignals& nodeSignals);
  /** Unregister a network node */
  void UnregisterNodeSignals(CNodeSignals& nodeSignals);
  
  void PushGetBlocks(CNode* pnode, CBlockIndex* pindexBegin, uint256 hashEnd);
  
  bool ProcessBlock(CNode* pfrom, CBlock* pblock);
  bool CheckDiskSpace(uint64_t nAdditionalBytes=0);
  FILE* OpenBlockFile(unsigned int nFile, unsigned int nBlockPos, const char* pszMode="rb");
  FILE* AppendBlockFile(unsigned int& nFileRet);
  bool LoadBlockIndex(bool fAllowNew=true);
  void PrintBlockTree();
  CBlockIndex* FindBlockByHeight(int nHeight);
  bool ProcessMessages(CNode* pfrom);
  bool SendMessages(CNode* pto, bool fSendTrickle);
  void ThreadImport(std::vector<boost::filesystem::path> vImportFiles);
  
  bool CheckProofOfWork(uint256 hash, unsigned int nBits);
  unsigned int GetNextTargetRequired(const CBlockIndex* pindexLast, bool fProofOfStake);
  int64_t GetProofOfWorkReward(int nHeight,int64_t nFees);
  int64_t GetProofOfStakeReward(const CBlockIndex* pindexPrev, int64_t nCoinAge, int64_t nFees);
  bool IsInitialBlockDownload();
  bool IsConfirmedInNPrevBlocks(const CTxIndex& txindex, const CBlockIndex* pindexFrom, int nMaxDepth, int& nActualDepth);
  std::string GetWarnings(std::string strFor);
  bool GetTransaction(const uint256 &hash, CTransaction &tx, uint256 &hashBlock);
  uint256 WantedByOrphan(const COrphanBlock* pblockOrphan);
  const CBlockIndex* GetLastBlockIndex(const CBlockIndex* pindex, bool fProofOfStake);
  void ThreadStakeMiner(CWallet *pwallet);
  void ThreadBitcoinMiner(CWallet *pwallet);
  
  /** (try to) add transaction to memory pool **/
  bool AcceptToMemoryPool(CTxMemPool& pool, CTransaction &tx, bool fLimitFree,
                          bool* pfMissingInputs);
  
  
  
  
  
  
  
  /** Position on disk for a particular transaction. */
  class CDiskTxPos
  {
  public:
      unsigned int nFile;
      unsigned int nBlockPos;
      unsigned int nTxPos;
  
      CDiskTxPos()
      {
          SetNull();
      }
  
      CDiskTxPos(unsigned int nFileIn, unsigned int nBlockPosIn, unsigned int nTxPosIn)
      {
          nFile = nFileIn;
          nBlockPos = nBlockPosIn;
          nTxPos = nTxPosIn;
      }
  
      IMPLEMENT_SERIALIZE( READWRITE(FLATDATA(*this)); )
      void SetNull() { nFile = (unsigned int) -1; nBlockPos = 0; nTxPos = 0; }
      bool IsNull() const { return (nFile == (unsigned int) -1); }
  
      friend bool operator==(const CDiskTxPos& a, const CDiskTxPos& b)
      {
          return (a.nFile     == b.nFile &&
                  a.nBlockPos == b.nBlockPos &&
                  a.nTxPos    == b.nTxPos);
      }
  
      friend bool operator!=(const CDiskTxPos& a, const CDiskTxPos& b)
      {
          return !(a == b);
      }
  
  
      std::string ToString() const
      {
          if (IsNull())
              return "null";
          else
              return strprintf("(nFile=%u, nBlockPos=%u, nTxPos=%u)", nFile, nBlockPos, nTxPos);
      }
  };
  
  
  
  
  enum GetMinFee_mode
  {
      GMF_BLOCK,
      GMF_RELAY,
      GMF_SEND,
  };
  
  typedef std::map<uint256, std::pair<CTxIndex, CTransaction> > MapPrevTx;
  
  int64_t GetMinFee(const CTransaction& tx, unsigned int nBlockSize = 1, enum GetMinFee_mode mode = GMF_BLOCK, unsigned int nBytes = 0);
  
  /** The basic transaction that is broadcasted on the network and contained in
   * blocks.  A transaction can contain multiple inputs and outputs.
   */
  class CTransaction
  {
  public:
      static const int CURRENT_VERSION=1;
      int nVersion;
      unsigned int nTime;
      std::vector<CTxIn> vin;
      std::vector<CTxOut> vout;
      unsigned int nLockTime;
  
      // Denial-of-service detection:
      mutable int nDoS;
      bool DoS(int nDoSIn, bool fIn) const { nDoS += nDoSIn; return fIn; }
  
      CTransaction()
      {
          SetNull();
      }
  
      CTransaction(int nVersion, unsigned int nTime, const std::vector<CTxIn>& vin, const std::vector<CTxOut>& vout, unsigned int nLockTime)
          : nVersion(nVersion), nTime(nTime), vin(vin), vout(vout), nLockTime(nLockTime), nDoS(0)
      {
      }
  
      IMPLEMENT_SERIALIZE
      (
          READWRITE(this->nVersion);
          nVersion = this->nVersion;
          READWRITE(nTime);
          READWRITE(vin);
          READWRITE(vout);
          READWRITE(nLockTime);
      )
  
      void SetNull()
      {
          nVersion = CTransaction::CURRENT_VERSION;
          nTime = GetAdjustedTime();
          vin.clear();
          vout.clear();
          nLockTime = 0;
          nDoS = 0;  // Denial-of-service prevention
      }
  
      bool IsNull() const
      {
          return (vin.empty() && vout.empty());
      }
  
      uint256 GetHash() const
      {
          return SerializeHash(*this);
      }
  
      bool IsCoinBase() const
      {
          return (vin.size() == 1 && vin[0].prevout.IsNull() && vout.size() >= 1);
      }
  
      bool IsCoinStake() const
      {
          // Chinesepaintingcoin: the coin stake transaction is marked with the first output empty
          return (vin.size() > 0 && (!vin[0].prevout.IsNull()) && vout.size() >= 2 && vout[0].IsEmpty());
      }
  
      /** Amount of bitcoins spent by this transaction.
          @return sum of all outputs (note: does not include fees)
       */
      int64_t GetValueOut() const
      {
          int64_t nValueOut = 0;
          BOOST_FOREACH(const CTxOut& txout, vout)
          {
              nValueOut += txout.nValue;
              if (!MoneyRange(txout.nValue) || !MoneyRange(nValueOut))
                  throw std::runtime_error("CTransaction::GetValueOut() : value out of range");
          }
          return nValueOut;
      }
  
      /** Amount of bitcoins coming in to this transaction
          Note that lightweight clients may not know anything besides the hash of previous transactions,
          so may not be able to calculate this.
  
          @param[in] mapInputs	Map of previous transactions that have outputs we're spending
          @return	Sum of value of all inputs (scriptSigs)
          @see CTransaction::FetchInputs
       */
      int64_t GetValueIn(const MapPrevTx& mapInputs) const;
  
      bool ReadFromDisk(CDiskTxPos pos, FILE** pfileRet=NULL)
      {
          CAutoFile filein = CAutoFile(OpenBlockFile(pos.nFile, 0, pfileRet ? "rb+" : "rb"), SER_DISK, CLIENT_VERSION);
          if (!filein)
              return error("CTransaction::ReadFromDisk() : OpenBlockFile failed");
  
          // Read transaction
          if (fseek(filein, pos.nTxPos, SEEK_SET) != 0)
              return error("CTransaction::ReadFromDisk() : fseek failed");
  
          try {
              filein >> *this;
          }
          catch (std::exception &e) {
              return error("%s() : deserialize or I/O error", __PRETTY_FUNCTION__);
          }
  
          // Return file pointer
          if (pfileRet)
          {
              if (fseek(filein, pos.nTxPos, SEEK_SET) != 0)
                  return error("CTransaction::ReadFromDisk() : second fseek failed");
              *pfileRet = filein.release();
          }
          return true;
      }
  
      friend bool operator==(const CTransaction& a, const CTransaction& b)
      {
          return (a.nVersion  == b.nVersion &&
                  a.nTime     == b.nTime &&
                  a.vin       == b.vin &&
                  a.vout      == b.vout &&
                  a.nLockTime == b.nLockTime);
      }
  
      friend bool operator!=(const CTransaction& a, const CTransaction& b)
      {
          return !(a == b);
      }
  
      std::string ToString() const
      {
          std::string str;
          str += IsCoinBase()? "Coinbase" : (IsCoinStake()? "Coinstake" : "CTransaction");
          str += strprintf("(hash=%s, nTime=%d, ver=%d, vin.size=%u, vout.size=%u, nLockTime=%d)\n",
              GetHash().ToString(),
              nTime,
              nVersion,
              vin.size(),
              vout.size(),
              nLockTime);
          for (unsigned int i = 0; i < vin.size(); i++)
              str += "    " + vin[i].ToString() + "\n";
          for (unsigned int i = 0; i < vout.size(); i++)
              str += "    " + vout[i].ToString() + "\n";
          return str;
      }
  
  
      bool ReadFromDisk(CTxDB& txdb, COutPoint prevout, CTxIndex& txindexRet);
      bool ReadFromDisk(CTxDB& txdb, COutPoint prevout);
      bool ReadFromDisk(COutPoint prevout);
      bool DisconnectInputs(CTxDB& txdb);
  
      /** Fetch from memory and/or disk. inputsRet keys are transaction hashes.
  
       @param[in] txdb	Transaction database
       @param[in] mapTestPool	List of pending changes to the transaction index database
       @param[in] fBlock	True if being called to add a new best-block to the chain
       @param[in] fMiner	True if being called by CreateNewBlock
       @param[out] inputsRet	Pointers to this transaction's inputs
       @param[out] fInvalid	returns true if transaction is invalid
       @return	Returns true if all inputs are in txdb or mapTestPool
       */
      bool FetchInputs(CTxDB& txdb, const std::map<uint256, CTxIndex>& mapTestPool,
                       bool fBlock, bool fMiner, MapPrevTx& inputsRet, bool& fInvalid);
  
      /** Sanity check previous transactions, then, if all checks succeed,
          mark them as spent by this transaction.
  
          @param[in] inputs	Previous transactions (from FetchInputs)
          @param[out] mapTestPool	Keeps track of inputs that need to be updated on disk
          @param[in] posThisTx	Position of this transaction on disk
          @param[in] pindexBlock
          @param[in] fBlock	true if called from ConnectBlock
          @param[in] fMiner	true if called from CreateNewBlock
          @return Returns true if all checks succeed
       */
      bool ConnectInputs(CTxDB& txdb, MapPrevTx inputs,
                         std::map<uint256, CTxIndex>& mapTestPool, const CDiskTxPos& posThisTx,
                         const CBlockIndex* pindexBlock, bool fBlock, bool fMiner, unsigned int flags = STANDARD_SCRIPT_VERIFY_FLAGS);
      bool CheckTransaction() const;
      bool GetCoinAge(CTxDB& txdb, const CBlockIndex* pindexPrev, uint64_t& nCoinAge) const;
  
      const CTxOut& GetOutputFor(const CTxIn& input, const MapPrevTx& inputs) const;
  };
  
  /** wrapper for CTxOut that provides a more compact serialization */
  class CTxOutCompressor
  {
  private:
      CTxOut &txout;
  public:
      CTxOutCompressor(CTxOut &txoutIn) : txout(txoutIn) { }
  
      IMPLEMENT_SERIALIZE(
          READWRITE(VARINT(txout.nValue));
          CScriptCompressor cscript(REF(txout.scriptPubKey));
          READWRITE(cscript);
      )
  };
  
  /** Check for standard transaction types
      @param[in] mapInputs	Map of previous transactions that have outputs we're spending
      @return True if all inputs (scriptSigs) use only standard transaction forms
      @see CTransaction::FetchInputs
  */
  bool AreInputsStandard(const CTransaction& tx, const MapPrevTx& mapInputs);
  
  /** Count ECDSA signature operations the old-fashioned (pre-0.6) way
      @return number of sigops this transaction's outputs will produce when spent
      @see CTransaction::FetchInputs
  */
  unsigned int GetLegacySigOpCount(const CTransaction& tx);
  
  /** Count ECDSA signature operations in pay-to-script-hash inputs.
  
      @param[in] mapInputs	Map of previous transactions that have outputs we're spending
      @return maximum number of sigops required to validate this transaction's inputs
      @see CTransaction::FetchInputs
   */
  unsigned int GetP2SHSigOpCount(const CTransaction& tx, const MapPrevTx& mapInputs);
  
  /** Check for standard transaction types
      @return True if all outputs (scriptPubKeys) use only standard transaction forms
  */
  bool IsStandardTx(const CTransaction& tx, std::string& reason);
  
  bool IsFinalTx(const CTransaction &tx, int nBlockHeight = 0, int64_t nBlockTime = 0);
  
  
  
  /** A transaction with a merkle branch linking it to the block chain. */
  class CMerkleTx : public CTransaction
  {
  private:
      int GetDepthInMainChainINTERNAL(CBlockIndex* &pindexRet) const;
  public:
      uint256 hashBlock;
      std::vector<uint256> vMerkleBranch;
      int nIndex;
  
      // memory only
      mutable bool fMerkleVerified;
  
  
      CMerkleTx()
      {
          Init();
      }
  
      CMerkleTx(const CTransaction& txIn) : CTransaction(txIn)
      {
          Init();
      }
  
      void Init()
      {
          hashBlock = 0;
          nIndex = -1;
          fMerkleVerified = false;
      }
  
  
      IMPLEMENT_SERIALIZE
      (
          nSerSize += SerReadWrite(s, *(CTransaction*)this, nType, nVersion, ser_action);
          nVersion = this->nVersion;
          READWRITE(hashBlock);
          READWRITE(vMerkleBranch);
          READWRITE(nIndex);
      )
  
  
      int SetMerkleBranch(const CBlock* pblock=NULL);
  
      // Return depth of transaction in blockchain:
      // -1  : not in blockchain, and not in memory pool (conflicted transaction)
      //  0  : in memory pool, waiting to be included in a block
      // >=1 : this many blocks deep in the main chain
      int GetDepthInMainChain(CBlockIndex* &pindexRet) const;
      int GetDepthInMainChain() const { CBlockIndex *pindexRet; return GetDepthInMainChain(pindexRet); }
      bool IsInMainChain() const { CBlockIndex *pindexRet; return GetDepthInMainChainINTERNAL(pindexRet) > 0; }
      int GetBlocksToMaturity() const;
      bool AcceptToMemoryPool(bool fLimitFree=true);
  };
  
  
  
  
  /**  A txdb record that contains the disk location of a transaction and the
   * locations of transactions that spend its outputs.  vSpent is really only
   * used as a flag, but having the location is very helpful for debugging.
   */
  class CTxIndex
  {
  public:
      CDiskTxPos pos;
      std::vector<CDiskTxPos> vSpent;
  
      CTxIndex()
      {
          SetNull();
      }
  
      CTxIndex(const CDiskTxPos& posIn, unsigned int nOutputs)
      {
          pos = posIn;
          vSpent.resize(nOutputs);
      }
  
      IMPLEMENT_SERIALIZE
      (
          if (!(nType & SER_GETHASH))
              READWRITE(nVersion);
          READWRITE(pos);
          READWRITE(vSpent);
      )
  
      void SetNull()
      {
          pos.SetNull();
          vSpent.clear();
      }
  
      bool IsNull()
      {
          return pos.IsNull();
      }
  
      friend bool operator==(const CTxIndex& a, const CTxIndex& b)
      {
          return (a.pos    == b.pos &&
                  a.vSpent == b.vSpent);
      }
  
      friend bool operator!=(const CTxIndex& a, const CTxIndex& b)
      {
          return !(a == b);
      }
      int GetDepthInMainChain() const;
  
  };
  
  
  
  
  
  /** Nodes collect new transactions into a block, hash them into a hash tree,
   * and scan through nonce values to make the block's hash satisfy proof-of-work
   * requirements.  When they solve the proof-of-work, they broadcast the block
   * to everyone and the block is added to the block chain.  The first transaction
   * in the block is a special one that creates a new coin owned by the creator
   * of the block.
   *
   * Blocks are appended to blk0001.dat files on disk.  Their location on disk
   * is indexed by CBlockIndex objects in memory.
   */
  class CBlock
  {
  public:
      // header
      static const int CURRENT_VERSION = 1;
      int nVersion;//
      uint256 hashPrevBlock;
      uint256 hashMerkleRoot;
      unsigned int nTime;//
      unsigned int nBits;//
      unsigned int nNonce;//
  
      // network and disk
      std::vector<CTransaction> vtx;
  
      // Chinesepaintingcoin: block signature - signed by one of the coin base txout[N]'s owner
      std::vector<unsigned char> vchBlockSig;
  
      // memory only
      mutable std::vector<uint256> vMerkleTree;
  
      // Denial-of-service detection:
      mutable int nDoS;
      bool DoS(int nDoSIn, bool fIn) const { nDoS += nDoSIn; return fIn; }
  
      CBlock()
      {
          SetNull();
      }
  
      IMPLEMENT_SERIALIZE
      (
          READWRITE(this->nVersion);
          nVersion = this->nVersion;
          READWRITE(hashPrevBlock);
          READWRITE(hashMerkleRoot);
          READWRITE(nTime);
          READWRITE(nBits);
          READWRITE(nNonce);
  
          // ConnectBlock depends on vtx following header to generate CDiskTxPos
          if (!(nType & (SER_GETHASH|SER_BLOCKHEADERONLY)))
          {
              READWRITE(vtx);
              READWRITE(vchBlockSig);
          }
          else if (fRead)
          {
              const_cast<CBlock*>(this)->vtx.clear();
              const_cast<CBlock*>(this)->vchBlockSig.clear();
          }
      )
  
      void SetNull()
      {
          nVersion = CBlock::CURRENT_VERSION;
          hashPrevBlock = 0;
          hashMerkleRoot = 0;
          nTime = 0;
          nBits = 0;
          nNonce = 0;
          vtx.clear();
          vchBlockSig.clear();
          vMerkleTree.clear();
          nDoS = 0;
      }
  
      bool IsNull() const
      {
          return (nBits == 0);
      }
  
      uint256 GetHash() const;
  
      uint256 GetPoWHash() const
      {
          return Hash(BEGIN(nVersion), END(nNonce));
         // return scrypt_blockhash(CVOIDBEGIN(nVersion));
      }
  
      int64_t GetBlockTime() const
      {
          return (int64_t)nTime;
      }
  
      void UpdateTime(const CBlockIndex* pindexPrev);
  
      // entropy bit for stake modifier if chosen by modifier
      unsigned int GetStakeEntropyBit() const
      {
          // Take last bit of block hash as entropy bit
          unsigned int nEntropyBit = ((GetHash().GetLow64()) & 1llu);
          LogPrint("stakemodifier", "GetStakeEntropyBit: hashBlock=%s nEntropyBit=%u\n", GetHash().ToString(), nEntropyBit);
          return nEntropyBit;
      }
  
      // Chinesepaintingcoin: two types of block: proof-of-work or proof-of-stake
      bool IsProofOfStake() const
      {
          return (vtx.size() > 1 && vtx[1].IsCoinStake());
      }
  
      bool IsProofOfWork() const
      {
          return !IsProofOfStake();
      }
  
      std::pair<COutPoint, unsigned int> GetProofOfStake() const
      {
          return IsProofOfStake()? std::make_pair(vtx[1].vin[0].prevout, vtx[1].nTime) : std::make_pair(COutPoint(), (unsigned int)0);
      }
  
      // Chinesepaintingcoin: get max transaction timestamp
      int64_t GetMaxTransactionTime() const
      {
          int64_t maxTransactionTime = 0;
          BOOST_FOREACH(const CTransaction& tx, vtx)
              maxTransactionTime = std::max(maxTransactionTime, (int64_t)tx.nTime);
          return maxTransactionTime;
      }
  
      uint256 BuildMerkleTree() const
      {
          vMerkleTree.clear();
          BOOST_FOREACH(const CTransaction& tx, vtx)
              vMerkleTree.push_back(tx.GetHash());
          int j = 0;
          for (int nSize = vtx.size(); nSize > 1; nSize = (nSize + 1) / 2)
          {
              for (int i = 0; i < nSize; i += 2)
              {
                  int i2 = std::min(i+1, nSize-1);
                  vMerkleTree.push_back(Hash(BEGIN(vMerkleTree[j+i]),  END(vMerkleTree[j+i]),
                                             BEGIN(vMerkleTree[j+i2]), END(vMerkleTree[j+i2])));
              }
              j += nSize;
          }
          return (vMerkleTree.empty() ? 0 : vMerkleTree.back());
      }
  
      std::vector<uint256> GetMerkleBranch(int nIndex) const
      {
          if (vMerkleTree.empty())
              BuildMerkleTree();
          std::vector<uint256> vMerkleBranch;
          int j = 0;
          for (int nSize = vtx.size(); nSize > 1; nSize = (nSize + 1) / 2)
          {
              int i = std::min(nIndex^1, nSize-1);
              vMerkleBranch.push_back(vMerkleTree[j+i]);
              nIndex >>= 1;
              j += nSize;
          }
          return vMerkleBranch;
      }
  
      static uint256 CheckMerkleBranch(uint256 hash, const std::vector<uint256>& vMerkleBranch, int nIndex)
      {
          if (nIndex == -1)
              return 0;
          BOOST_FOREACH(const uint256& otherside, vMerkleBranch)
          {
              if (nIndex & 1)
                  hash = Hash(BEGIN(otherside), END(otherside), BEGIN(hash), END(hash));
              else
                  hash = Hash(BEGIN(hash), END(hash), BEGIN(otherside), END(otherside));
              nIndex >>= 1;
          }
          return hash;
      }
  
  
      bool WriteToDisk(unsigned int& nFileRet, unsigned int& nBlockPosRet)
      {
          // Open history file to append
          CAutoFile fileout = CAutoFile(AppendBlockFile(nFileRet), SER_DISK, CLIENT_VERSION);
          if (!fileout)
              return error("CBlock::WriteToDisk() : AppendBlockFile failed");
  
          // Write index header
          unsigned int nSize = fileout.GetSerializeSize(*this);
          fileout << FLATDATA(Params().MessageStart()) << nSize;
  
          // Write block
          long fileOutPos = ftell(fileout);
          if (fileOutPos < 0)
              return error("CBlock::WriteToDisk() : ftell failed");
          nBlockPosRet = fileOutPos;
          fileout << *this;
  
          // Flush stdio buffers and commit to disk before returning
          fflush(fileout);
          if (!IsInitialBlockDownload() || (nBestHeight+1) % 500 == 0)
              FileCommit(fileout);
  
          return true;
      }
  
      bool ReadFromDisk(unsigned int nFile, unsigned int nBlockPos, bool fReadTransactions=true)
      {
          SetNull();
  
          // Open history file to read
          CAutoFile filein = CAutoFile(OpenBlockFile(nFile, nBlockPos, "rb"), SER_DISK, CLIENT_VERSION);
          if (!filein)
              return error("CBlock::ReadFromDisk() : OpenBlockFile failed");
          if (!fReadTransactions)
              filein.nType |= SER_BLOCKHEADERONLY;
  
          // Read block
          try {
              filein >> *this;
          }
          catch (std::exception &e) {
              return error("%s() : deserialize or I/O error", __PRETTY_FUNCTION__);
          }
  
          // Check the header
          if (fReadTransactions && IsProofOfWork() && !CheckProofOfWork(GetPoWHash(), nBits))
              return error("CBlock::ReadFromDisk() : errors in block header");
  
          return true;
      }
  
  
  
      std::string ToString() const
      {
          std::stringstream s;
          s << strprintf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%u, nBits=%08x, nNonce=%u, vtx=%u, vchBlockSig=%s)\n",
              GetHash().ToString(),
              nVersion,
              hashPrevBlock.ToString(),
              hashMerkleRoot.ToString(),
              nTime, nBits, nNonce,
              vtx.size(),
              HexStr(vchBlockSig.begin(), vchBlockSig.end()));
          for (unsigned int i = 0; i < vtx.size(); i++)
          {
              s << "  " << vtx[i].ToString() << "\n";
          }
          s << "  vMerkleTree: ";
          for (unsigned int i = 0; i < vMerkleTree.size(); i++)
              s << " " << vMerkleTree[i].ToString();
          s << "\n";
          return s.str();
      }
  
  
      bool DisconnectBlock(CTxDB& txdb, CBlockIndex* pindex);
      bool ConnectBlock(CTxDB& txdb, CBlockIndex* pindex, bool fJustCheck=false);
      bool ReadFromDisk(const CBlockIndex* pindex, bool fReadTransactions=true);
      bool SetBestChain(CTxDB& txdb, CBlockIndex* pindexNew);
      bool AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos, const uint256& hashProof);
      bool CheckBlock(bool fCheckPOW=true, bool fCheckMerkleRoot=true, bool fCheckSig=true) const;
      bool AcceptBlock();
      bool SignBlock(CWallet& keystore, int64_t nFees);
      bool CheckBlockSignature() const;
  
  private:
      bool SetBestChainInner(CTxDB& txdb, CBlockIndex *pindexNew);
  };
  
  
  
  
  
  
  /** The block chain is a tree shaped structure starting with the
   * genesis block at the root, with each block potentially having multiple
   * candidates to be the next block.  pprev and pnext link a path through the
   * main/longest chain.  A blockindex may have multiple pprev pointing back
   * to it, but pnext will only point forward to the longest branch, or will
   * be null if the block is not part of the longest chain.
   */
  class CBlockIndex
  {
  public:
      const uint256* phashBlock;
      CBlockIndex* pprev;
      CBlockIndex* pnext;
      unsigned int nFile;
      unsigned int nBlockPos;
      uint256 nChainTrust; // Chinesepaintingcoin: trust score of block chain
      int nHeight;
  
      int64_t nMint;
      int64_t nMoneySupply;
  
      unsigned int nFlags;  // Chinesepaintingcoin: block index flags
      enum  
      {
          BLOCK_PROOF_OF_STAKE = (1 << 0), // is proof-of-stake block
          BLOCK_STAKE_ENTROPY  = (1 << 1), // entropy bit for stake modifier
          BLOCK_STAKE_MODIFIER = (1 << 2), // regenerated stake modifier
      };
  
      uint64_t nStakeModifier; // hash modifier for proof-of-stake
      uint256 bnStakeModifierV2;
  
      // proof-of-stake specific fields
      COutPoint prevoutStake;
      unsigned int nStakeTime;
  
      uint256 hashProof;
  
      // block header
      int nVersion;
      uint256 hashMerkleRoot;
      unsigned int nTime;
      unsigned int nBits;
      unsigned int nNonce;
  
      CBlockIndex()
      {
          phashBlock = NULL;
          pprev = NULL;
          pnext = NULL;
          nFile = 0;
          nBlockPos = 0;
          nHeight = 0;
          nChainTrust = 0;
          nMint = 0;
          nMoneySupply = 0;
          nFlags = 0;
          nStakeModifier = 0;
          bnStakeModifierV2 = 0;
          hashProof = 0;
          prevoutStake.SetNull();
          nStakeTime = 0;
  
          nVersion       = 0;
          hashMerkleRoot = 0;
          nTime          = 0;
          nBits          = 0;
          nNonce         = 0;
      }
  
      CBlockIndex(unsigned int nFileIn, unsigned int nBlockPosIn, CBlock& block)
      {
          phashBlock = NULL;
          pprev = NULL;
          pnext = NULL;
          nFile = nFileIn;
          nBlockPos = nBlockPosIn;
          nHeight = 0;
          nChainTrust = 0;
          nMint = 0;
          nMoneySupply = 0;
          nFlags = 0;
          nStakeModifier = 0;
          bnStakeModifierV2 = 0;
          hashProof = 0;
          if (block.IsProofOfStake())
          {
              SetProofOfStake();
              prevoutStake = block.vtx[1].vin[0].prevout;
              nStakeTime = block.vtx[1].nTime;
          }
          else
          {
              prevoutStake.SetNull();
              nStakeTime = 0;
          }
  
          nVersion       = block.nVersion;
          hashMerkleRoot = block.hashMerkleRoot;
          nTime          = block.nTime;
          nBits          = block.nBits;
          nNonce         = block.nNonce;
      }
  
      CBlock GetBlockHeader() const
      {
          CBlock block;
          block.nVersion       = nVersion;
          if (pprev)
              block.hashPrevBlock = pprev->GetBlockHash();
          block.hashMerkleRoot = hashMerkleRoot;
          block.nTime          = nTime;
          block.nBits          = nBits;
          block.nNonce         = nNonce;
          return block;
      }
  
      uint256 GetBlockHash() const
      {
          return *phashBlock;
      }
  
      int64_t GetBlockTime() const
      {
          return (int64_t)nTime;
      }
  
      uint256 GetBlockTrust() const;
  
      bool IsInMainChain() const
      {
          return (pnext || this == pindexBest);
      }
  
      bool CheckIndex() const
      {
          return true;
      }
  
      int64_t GetPastTimeLimit() const
      {
          if (IsProtocolV2(nHeight))
              return GetBlockTime();
          else
              return GetMedianTimePast();
      }
  
      enum { nMedianTimeSpan=11 };
  
      int64_t GetMedianTimePast() const
      {
          int64_t pmedian[nMedianTimeSpan];
          int64_t* pbegin = &pmedian[nMedianTimeSpan];
          int64_t* pend = &pmedian[nMedianTimeSpan];
  
          const CBlockIndex* pindex = this;
          for (int i = 0; i < nMedianTimeSpan && pindex; i++, pindex = pindex->pprev)
              *(--pbegin) = pindex->GetBlockTime();
  
          std::sort(pbegin, pend);
          return pbegin[(pend - pbegin)/2];
      }
  
      /**
       * Returns true if there are nRequired or more blocks of minVersion or above
       * in the last nToCheck blocks, starting at pstart and going backwards.
       */
      static bool IsSuperMajority(int minVersion, const CBlockIndex* pstart,
                                  unsigned int nRequired, unsigned int nToCheck);
  
  
      bool IsProofOfWork() const
      {
          return !(nFlags & BLOCK_PROOF_OF_STAKE);
      }
  
      bool IsProofOfStake() const
      {
          return (nFlags & BLOCK_PROOF_OF_STAKE);
      }
  
      void SetProofOfStake()
      {
          nFlags |= BLOCK_PROOF_OF_STAKE;
      }
  
      unsigned int GetStakeEntropyBit() const
      {
          return ((nFlags & BLOCK_STAKE_ENTROPY) >> 1);
      }
  
      bool SetStakeEntropyBit(unsigned int nEntropyBit)
      {
          if (nEntropyBit > 1)
              return false;
          nFlags |= (nEntropyBit? BLOCK_STAKE_ENTROPY : 0);
          return true;
      }
  
      bool GeneratedStakeModifier() const
      {
          return (nFlags & BLOCK_STAKE_MODIFIER);
      }
  
      void SetStakeModifier(uint64_t nModifier, bool fGeneratedStakeModifier)
      {
          nStakeModifier = nModifier;
          if (fGeneratedStakeModifier)
              nFlags |= BLOCK_STAKE_MODIFIER;
      }
  
      std::string ToString() const
      {
          return strprintf("CBlockIndex(nprev=%p, pnext=%p, nFile=%u, nBlockPos=%-6d nHeight=%d, nMint=%s, nMoneySupply=%s, nFlags=(%s)(%d)(%s), nStakeModifier=%016x, hashProof=%s, prevoutStake=(%s), nStakeTime=%d merkle=%s, hashBlock=%s)",
              pprev, pnext, nFile, nBlockPos, nHeight,
              FormatMoney(nMint), FormatMoney(nMoneySupply),
              GeneratedStakeModifier() ? "MOD" : "-", GetStakeEntropyBit(), IsProofOfStake()? "PoS" : "PoW",
              nStakeModifier,
              hashProof.ToString(),
              prevoutStake.ToString(), nStakeTime,
              hashMerkleRoot.ToString(),
              GetBlockHash().ToString());
      }
  };
  
  
  
  /** Used to marshal pointers into hashes for db storage. */
  class CDiskBlockIndex : public CBlockIndex
  {
  private:
      uint256 blockHash;
  
  public:
      uint256 hashPrev;
      uint256 hashNext;
  
      CDiskBlockIndex()
      {
          hashPrev = 0;
          hashNext = 0;
          blockHash = 0;
      }
  
      explicit CDiskBlockIndex(CBlockIndex* pindex) : CBlockIndex(*pindex)
      {
          hashPrev = (pprev ? pprev->GetBlockHash() : 0);
          hashNext = (pnext ? pnext->GetBlockHash() : 0);
      }
  
      IMPLEMENT_SERIALIZE
      (
          if (!(nType & SER_GETHASH))
              READWRITE(nVersion);
  
          READWRITE(hashNext);
          READWRITE(nFile);
          READWRITE(nBlockPos);
          READWRITE(nHeight);
          READWRITE(nMint);
          READWRITE(nMoneySupply);
          READWRITE(nFlags);
          READWRITE(nStakeModifier);
          READWRITE(bnStakeModifierV2);
          if (IsProofOfStake())
          {
              READWRITE(prevoutStake);
              READWRITE(nStakeTime);
          }
          else if (fRead)
          {
              const_cast<CDiskBlockIndex*>(this)->prevoutStake.SetNull();
              const_cast<CDiskBlockIndex*>(this)->nStakeTime = 0;
          }
          READWRITE(hashProof);
  
          // block header
          READWRITE(this->nVersion);
          READWRITE(hashPrev);
          READWRITE(hashMerkleRoot);
          READWRITE(nTime);
          READWRITE(nBits);
          READWRITE(nNonce);
          READWRITE(blockHash);
      )
  
      uint256 GetBlockHash() const
      {
          if (fUseFastIndex && (nTime < GetAdjustedTime() - 24 * 60 * 60) && blockHash != 0)
              return blockHash;
  
          CBlock block;
          block.nVersion        = nVersion;
          block.hashPrevBlock   = hashPrev;
          block.hashMerkleRoot  = hashMerkleRoot;
          block.nTime           = nTime;
          block.nBits           = nBits;
          block.nNonce          = nNonce;
  
          const_cast<CDiskBlockIndex*>(this)->blockHash = block.GetHash();
  
          return blockHash;
      }
  
      std::string ToString() const
      {
          std::string str = "CDiskBlockIndex(";
          str += CBlockIndex::ToString();
          str += strprintf("\n                hashBlock=%s, hashPrev=%s, hashNext=%s)",
              GetBlockHash().ToString(),
              hashPrev.ToString(),
              hashNext.ToString());
          return str;
      }
  };
  
  
  
  
  
  
  
  
  /** Describes a place in the block chain to another node such that if the
   * other node doesn't have the same branch, it can find a recent common trunk.
   * The further back it is, the further before the fork it may be.
   */
  class CBlockLocator
  {
  protected:
      std::vector<uint256> vHave;
  public:
  
      CBlockLocator()
      {
      }
  
      explicit CBlockLocator(const CBlockIndex* pindex)
      {
          Set(pindex);
      }
  
      explicit CBlockLocator(uint256 hashBlock)
      {
          std::map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock);
          if (mi != mapBlockIndex.end())
              Set((*mi).second);
      }
  
      CBlockLocator(const std::vector<uint256>& vHaveIn)
      {
          vHave = vHaveIn;
      }
  
      IMPLEMENT_SERIALIZE
      (
          if (!(nType & SER_GETHASH))
              READWRITE(nVersion);
          READWRITE(vHave);
      )
  
      void SetNull()
      {
          vHave.clear();
      }
  
      bool IsNull()
      {
          return vHave.empty();
      }
  
      void Set(const CBlockIndex* pindex)
      {
          vHave.clear();
          int nStep = 1;
          while (pindex)
          {
              vHave.push_back(pindex->GetBlockHash());
  
              // Exponentially larger steps back
              for (int i = 0; pindex && i < nStep; i++)
                  pindex = pindex->pprev;
              if (vHave.size() > 10)
                  nStep *= 2;
          }
          vHave.push_back(Params().HashGenesisBlock());
      }
  
      int GetDistanceBack()
      {
          // Retrace how far back it was in the sender's branch
          int nDistance = 0;
          int nStep = 1;
          BOOST_FOREACH(const uint256& hash, vHave)
          {
              std::map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hash);
              if (mi != mapBlockIndex.end())
              {
                  CBlockIndex* pindex = (*mi).second;
                  if (pindex->IsInMainChain())
                      return nDistance;
              }
              nDistance += nStep;
              if (nDistance > 10)
                  nStep *= 2;
          }
          return nDistance;
      }
  
      CBlockIndex* GetBlockIndex()
      {
          // Find the first block the caller has in the main chain
          BOOST_FOREACH(const uint256& hash, vHave)
          {
              std::map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hash);
              if (mi != mapBlockIndex.end())
              {
                  CBlockIndex* pindex = (*mi).second;
                  if (pindex->IsInMainChain())
                      return pindex;
              }
          }
          return pindexGenesisBlock;
      }
  
      uint256 GetBlockHash()
      {
          // Find the first block the caller has in the main chain
          BOOST_FOREACH(const uint256& hash, vHave)
          {
              std::map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hash);
              if (mi != mapBlockIndex.end())
              {
                  CBlockIndex* pindex = (*mi).second;
                  if (pindex->IsInMainChain())
                      return hash;
              }
          }
          return Params().HashGenesisBlock();
      }
  
      int GetHeight()
      {
          CBlockIndex* pindex = GetBlockIndex();
          if (!pindex)
              return 0;
          return pindex->nHeight;
      }
  };
  
  
  
  
  
  
  
  
  
  
  class CWalletInterface {
  protected:
      virtual void SyncTransaction(const CTransaction &tx, const CBlock *pblock, bool fConnect) =0;
      virtual void EraseFromWallet(const uint256 &hash) =0;
      virtual void SetBestChain(const CBlockLocator &locator) =0;
      virtual void UpdatedTransaction(const uint256 &hash) =0;
      virtual void Inventory(const uint256 &hash) =0;
      virtual void ResendWalletTransactions(bool fForce) =0;
      friend void ::RegisterWallet(CWalletInterface*);
      friend void ::UnregisterWallet(CWalletInterface*);
      friend void ::UnregisterAllWallets();
  };
  
  #endif
  