text: // Copyright (c) 2009-2010 Satoshi Nakamoto
  // Copyright (c) 2009-2012 The Bitcoin developers
  // Copyright (c) 2011-2015 The Peercoin developers
  // Copyright (c) 2014-2015 The Paycoin developers
  // Distributed under the MIT 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 "bignum.h"
  #include "net.h"
  #include "script.h"
  
  #ifdef WIN32
  #include <io.h> /* for _commit */
  #endif
  
  #include <list>
  
  class CWallet;
  class CBlock;
  class CBlockIndex;
  class CKeyItem;
  class CReserveKey;
  class COutPoint;
  
  class CAddress;
  class CInv;
  class CRequestTracker;
  class CNode;
  
  static const unsigned int MAX_BLOCK_SIZE = 1000000;
  //static const unsigned int MAX_BLOCK_SIZE = 100000000;
  static const unsigned int MAX_BLOCK_SIZE_GEN = MAX_BLOCK_SIZE/2;
  static const unsigned int MAX_BLOCK_SIGOPS = MAX_BLOCK_SIZE/50;
  static const unsigned int MAX_ORPHAN_TRANSACTIONS = MAX_BLOCK_SIZE/100;
  static const int64 MIN_TX_FEE = 0.1 * CENT;
  static const int64 MIN_RELAY_TX_FEE = 0.1 * CENT;
  static const int64 MAX_MONEY = 2000000000 * COIN;
  static const int64 MAX_MINT_PROOF_OF_WORK = 9999 * COIN;
  static const int64 MIN_TXOUT_AMOUNT = MIN_TX_FEE;
  inline bool MoneyRange(int64 nValue) { return (nValue >= 0 && nValue <= MAX_MONEY); }
  static const int COINBASE_MATURITY_PPC = 100;
  // Threshold for nLockTime: below this value it is interpreted as block number, otherwise as UNIX timestamp.
  static const int LOCKTIME_THRESHOLD = 500000000; // Tue Nov  5 00:53:20 1985 UTC
  static const int STAKE_TARGET_SPACING = 1 * 60; // 1-minute block
  //static const int STAKE_TARGET_SPACING = 1; // 1 second block spacing
  static const int STAKE_MIN_AGE = 60 * 60; // minimum age for coin age
  //static const int STAKE_MIN_AGE = 60; // minimum age for coin age
  static const int STAKE_MAX_AGE = 60 * 60 * 24 * 5; // stake age of full weight
  //static const int STAKE_MAX_AGE = 60 * 2; // stake age of full weight
  static const int STAKE_START_TIME = 1418470264; // Sat 13 Dec 2014 06:31:04 AM EST
  //static const int STAKE_START_TIME = 1418345400; // Thu 11 Dec 2014 05:30:00 PM EST
  static const unsigned int POW_START_TIME = 1418403600; // Fri 12 Dec 2014 12:00:00 PM EST
  //static const unsigned int POW_START_TIME = 1418345100; // Thu 11 Dec 2014 05:00:00 PM EST
  static const unsigned int POW_END_TIME = 1419181200; // Sun 21 Dec 2014 12:00:00 PM EST
  //static const unsigned int POW_END_TIME = 1418345700; // Thu 11 Dec 2014 05:40:00 PM EST
  // MODIFIER_INTERVAL: time to elapse before new modifier is computed
  //static const unsigned int MODIFIER_INTERVAL = 6 * 60 * 60;
  static const unsigned int MODIFIER_INTERVAL = 10 * 60;
  //static const unsigned int MODIFIER_INTERVAL = 10;
  static const int64 NUMBER_OF_PRIMENODE = 50;
  static const int64 MINIMUM_FOR_ORION = 50 * COIN;
  static const int64 MINIMUM_FOR_PRIMENODE = 125000 * COIN;
  static const int MAX_TIME_SINCE_BEST_BLOCK = 10; // how many seconds to wait before sending next PushGetBlocks()
  // Reset all primenode stakerates to 100% after the given date
  static const unsigned int RESET_PRIMERATES = 1429531200; // Mon, 20 Apr 2015 12:00:00 GMT
  
  #ifdef USE_UPNP
  static const int fHaveUPnP = true;
  #else
  static const int fHaveUPnP = false;
  #endif
  
  static const uint256 hashGenesisBlockOfficial("0x00000e5695fbec8e36c10064491946ee3b723a9fa640fc0e25d3b8e4737e53e3");
  static const uint256 hashGenesisBlockTestNet("0x0000000f6bb18c77c5b39a25fa03e4c90bffa5cc10d6d9758a1bed5adcee9404");
  
  
  static const int64 nMaxClockDrift = 2 * 60 * 60;        // two hours
  
  extern CScript COINBASE_FLAGS;
  
  
  
  
  
  
  extern CCriticalSection cs_main;
  extern std::map<uint256, CBlockIndex*> mapBlockIndex;
  extern std::set<std::pair<COutPoint, unsigned int> > setStakeSeen;
  extern uint256 hashGenesisBlock;
  extern unsigned int nStakeMinAge;
  extern int nCoinbaseMaturity;
  extern CBlockIndex* pindexGenesisBlock;
  extern int nBestHeight;
  extern CBigNum bnBestChainTrust;
  extern CBigNum bnBestInvalidTrust;
  extern uint256 hashBestChain;
  extern CBlockIndex* pindexBest;
  extern unsigned int nTransactionsUpdated;
  extern uint64 nLastBlockTx;
  extern uint64 nLastBlockSize;
  extern int64 nLastCoinStakeSearchInterval;
  extern const std::string strMessageMagic;
  extern double dHashesPerSec;
  extern int64 nHPSTimerStart;
  extern int64 nTimeBestReceived;
  extern CCriticalSection cs_setpwalletRegistered;
  extern std::set<CWallet*> setpwalletRegistered;
  extern std::map<uint256, CBlock*> mapOrphanBlocks;
  
  // Settings
  extern int64 nTransactionFee;
  
  
  
  
  
  class CReserveKey;
  class CTxDB;
  class CTxIndex;
  
  void RegisterWallet(CWallet* pwalletIn);
  void UnregisterWallet(CWallet* pwalletIn);
  void SyncWithWallets(const CTransaction& tx, const CBlock* pblock = NULL, bool fUpdate = false, bool fConnect = true);
  bool ProcessBlock(CNode* pfrom, CBlock* pblock);
  bool CheckDiskSpace(uint64 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();
  bool ProcessMessages(CNode* pfrom);
  bool SendMessages(CNode* pto, bool fSendTrickle);
  void GenerateBitcoins(bool fGenerate, CWallet* pwallet);
  CBlock* CreateNewBlock(CReserveKey& reservekey, CWallet* pwallet, bool fProofOfStake=false);
  void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& nExtraNonce);
  void FormatHashBuffers(CBlock* pblock, char* pmidstate, char* pdata, char* phash1);
  bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey);
  bool CheckProofOfWork(uint256 hash, unsigned int nBits);
  int64 GetProofOfWorkReward(unsigned int nBits);
  int64 GetProofOfStakeReward(int64 nCoinAge, int primeNodeRate=-1);
  unsigned int ComputeMinWork(unsigned int nBase, int64 nTime, bool fProofOfStake);
  int GetNumBlocksOfPeers();
  bool IsInitialBlockDownload();
  std::string GetWarnings(std::string strFor);
  uint256 WantedByOrphan(const CBlock* pblockOrphan);
  const CBlockIndex* GetLastBlockIndex(const CBlockIndex* pindex, bool fProofOfStake);
  void BitcoinMiner(CWallet *pwallet, bool fProofOfStake);
  bool GetTransaction(const uint256 &hash, CTransaction &tx, uint256 &hashBlock);
  double GetBlockDifficulty(const CBlockIndex* blockindex = NULL);
  
  
  
  
  
  
  
  
  bool GetWalletFile(CWallet* pwallet, std::string &strWalletFileOut);
  
  /** 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 = -1; nBlockPos = 0; nTxPos = 0; }
      bool IsNull() const { return (nFile == -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=%d, nBlockPos=%d, nTxPos=%d)", nFile, nBlockPos, nTxPos);
      }
  
      void print() const
      {
          printf("%s", ToString().c_str());
      }
  };
  
  
  
  /** An inpoint - a combination of a transaction and an index n into its vin */
  class CInPoint
  {
  public:
      CTransaction* ptx;
      unsigned int n;
  
      CInPoint() { SetNull(); }
      CInPoint(CTransaction* ptxIn, unsigned int nIn) { ptx = ptxIn; n = nIn; }
      void SetNull() { ptx = NULL; n = -1; }
      bool IsNull() const { return (ptx == NULL && n == -1); }
  };
  
  
  
  /** An outpoint - a combination of a transaction hash and an index n into its vout */
  class COutPoint
  {
  public:
      uint256 hash;
      unsigned int n;
  
      COutPoint() { SetNull(); }
      COutPoint(uint256 hashIn, unsigned int nIn) { hash = hashIn; n = nIn; }
      IMPLEMENT_SERIALIZE( READWRITE(FLATDATA(*this)); )
      void SetNull() { hash = 0; n = -1; }
      bool IsNull() const { return (hash == 0 && n == -1); }
  
      friend bool operator<(const COutPoint& a, const COutPoint& b)
      {
          return (a.hash < b.hash || (a.hash == b.hash && a.n < b.n));
      }
  
      friend bool operator==(const COutPoint& a, const COutPoint& b)
      {
          return (a.hash == b.hash && a.n == b.n);
      }
  
      friend bool operator!=(const COutPoint& a, const COutPoint& b)
      {
          return !(a == b);
      }
  
      std::string ToString() const
      {
          return strprintf("COutPoint(%s, %d)", hash.ToString().substr(0,10).c_str(), n);
      }
  
      void print() const
      {
          printf("%s\n", ToString().c_str());
      }
  };
  
  
  
  
  /** An input of a transaction.  It contains the location of the previous
   * transaction's output that it claims and a signature that matches the
   * output's public key.
   */
  class CTxIn
  {
  public:
      COutPoint prevout;
      CScript scriptSig;
      unsigned int nSequence;
  
      CTxIn()
      {
          nSequence = std::numeric_limits<unsigned int>::max();
      }
  
      explicit CTxIn(COutPoint prevoutIn, CScript scriptSigIn=CScript(), unsigned int nSequenceIn=std::numeric_limits<unsigned int>::max())
      {
          prevout = prevoutIn;
          scriptSig = scriptSigIn;
          nSequence = nSequenceIn;
      }
  
      CTxIn(uint256 hashPrevTx, unsigned int nOut, CScript scriptSigIn=CScript(), unsigned int nSequenceIn=std::numeric_limits<unsigned int>::max())
      {
          prevout = COutPoint(hashPrevTx, nOut);
          scriptSig = scriptSigIn;
          nSequence = nSequenceIn;
      }
  
      IMPLEMENT_SERIALIZE
      (
          READWRITE(prevout);
          READWRITE(scriptSig);
          READWRITE(nSequence);
      )
  
      bool IsFinal() const
      {
          return (nSequence == std::numeric_limits<unsigned int>::max());
      }
  
      friend bool operator==(const CTxIn& a, const CTxIn& b)
      {
          return (a.prevout   == b.prevout &&
                  a.scriptSig == b.scriptSig &&
                  a.nSequence == b.nSequence);
      }
  
      friend bool operator!=(const CTxIn& a, const CTxIn& b)
      {
          return !(a == b);
      }
  
      std::string ToStringShort() const
      {
          return strprintf(" %s %d", prevout.hash.ToString().c_str(), prevout.n);
      }
  
      std::string ToString() const
      {
          std::string str;
          str += "CTxIn(";
          str += prevout.ToString();
          if (prevout.IsNull())
              str += strprintf(", coinbase %s", HexStr(scriptSig).c_str());
          else
              str += strprintf(", scriptSig=%s", scriptSig.ToString().substr(0,24).c_str());
          if (nSequence != std::numeric_limits<unsigned int>::max())
              str += strprintf(", nSequence=%u", nSequence);
          str += ")";
          return str;
      }
  
      void print() const
      {
          printf("%s\n", ToString().c_str());
      }
  };
  
  
  
  
  /** An output of a transaction.  It contains the public key that the next input
   * must be able to sign with to claim it.
   */
  class CTxOut
  {
  public:
      int64 nValue;
      CScript scriptPubKey;
  
      CTxOut()
      {
          SetNull();
      }
  
      CTxOut(int64 nValueIn, CScript scriptPubKeyIn)
      {
          nValue = nValueIn;
          scriptPubKey = scriptPubKeyIn;
      }
  
      IMPLEMENT_SERIALIZE
      (
          READWRITE(nValue);
          READWRITE(scriptPubKey);
      )
  
      void SetNull()
      {
          nValue = -1;
          scriptPubKey.clear();
      }
  
      bool IsNull()
      {
          return (nValue == -1);
      }
  
      void SetEmpty()
      {
          nValue = 0;
          scriptPubKey.clear();
      }
  
      bool IsEmpty() const
      {
          return (nValue == 0 && scriptPubKey.empty());
      }
  
      uint256 GetHash() const
      {
          return SerializeHash(*this);
      }
  
      friend bool operator==(const CTxOut& a, const CTxOut& b)
      {
          return (a.nValue       == b.nValue &&
                  a.scriptPubKey == b.scriptPubKey);
      }
  
      friend bool operator!=(const CTxOut& a, const CTxOut& b)
      {
          return !(a == b);
      }
  
      std::string ToStringShort() const
      {
          return strprintf(" out %s %s", FormatMoney(nValue).c_str(), scriptPubKey.ToString(true).c_str());
      }
  
      std::string ToString() const
      {
          if (IsEmpty()) return "CTxOut(empty)";
          if (scriptPubKey.size() < 6)
              return "CTxOut(error)";
          return strprintf("CTxOut(nValue=%s, scriptPubKey=%s)", FormatMoney(nValue).c_str(), scriptPubKey.ToString().c_str());
      }
  
      void print() const
      {
          printf("%s\n", ToString().c_str());
      }
  };
  
  
  
  
  enum GetMinFee_mode
  {
      GMF_BLOCK,
      GMF_RELAY,
      GMF_SEND,
  };
  
  typedef std::map<uint256, std::pair<CTxIndex, CTransaction> > MapPrevTx;
  
  /** The basic transaction that is broadcasted on the network and contained in
   * blocks.  A transaction can contain multiple inputs and outputs.
   */
  class CTransaction
  {
  public:
      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();
      }
  
      IMPLEMENT_SERIALIZE
      (
          READWRITE(this->nVersion);
          nVersion = this->nVersion;
          READWRITE(nTime);
          READWRITE(vin);
          READWRITE(vout);
          READWRITE(nLockTime);
      )
  
      void SetNull()
      {
          nVersion = 1;
          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 IsFinal(int nBlockHeight=0, int64 nBlockTime=0) const
      {
          // Time based nLockTime implemented in 0.1.6
          if (nLockTime == 0)
              return true;
          if (nBlockHeight == 0)
              nBlockHeight = nBestHeight;
          if (nBlockTime == 0)
              nBlockTime = GetAdjustedTime();
          if ((int64)nLockTime < ((int64)nLockTime < LOCKTIME_THRESHOLD ? (int64)nBlockHeight : nBlockTime))
              return true;
          BOOST_FOREACH(const CTxIn& txin, vin)
              if (!txin.IsFinal())
                  return false;
          return true;
      }
  
      bool IsNewerThan(const CTransaction& old) const
      {
          if (vin.size() != old.vin.size())
              return false;
          for (unsigned int i = 0; i < vin.size(); i++)
              if (vin[i].prevout != old.vin[i].prevout)
                  return false;
  
          bool fNewer = false;
          unsigned int nLowest = std::numeric_limits<unsigned int>::max();
          for (unsigned int i = 0; i < vin.size(); i++)
          {
              if (vin[i].nSequence != old.vin[i].nSequence)
              {
                  if (vin[i].nSequence <= nLowest)
                  {
                      fNewer = false;
                      nLowest = vin[i].nSequence;
                  }
                  if (old.vin[i].nSequence < nLowest)
                  {
                      fNewer = true;
                      nLowest = old.vin[i].nSequence;
                  }
              }
          }
          return fNewer;
      }
  
      bool IsCoinBase() const
      {
          return (vin.size() == 1 && vin[0].prevout.IsNull() && vout.size() >= 1);
      }
  
      bool IsCoinStake() const
      {
          if(!vout[0].IsEmpty() && vout[0].scriptPubKey[0] == OP_PRIMENODE350){
              return (vin.size() > 0 && (!vin[0].prevout.IsNull()) && vout.size() >= 2 && vout[0].scriptPubKey[0] == OP_PRIMENODE350);
          }else if(!vout[0].IsEmpty() && vout[0].scriptPubKey[0] == OP_PRIMENODE100){
              return (vin.size() > 0 && (!vin[0].prevout.IsNull()) && vout.size() >= 2 && vout[0].scriptPubKey[0] == OP_PRIMENODE100);
          }else if(!vout[0].IsEmpty() && vout[0].scriptPubKey[0] == OP_PRIMENODE20){
              return (vin.size() > 0 && (!vin[0].prevout.IsNull()) && vout.size() >= 2 && vout[0].scriptPubKey[0] == OP_PRIMENODE20);
          }else if(!vout[0].IsEmpty() && vout[0].scriptPubKey[0] == OP_PRIMENODE10){
              return (vin.size() > 0 && (!vin[0].prevout.IsNull()) && vout.size() >= 2 && vout[0].scriptPubKey[0] == OP_PRIMENODE10);
          }else{
              return (vin.size() > 0 && (!vin[0].prevout.IsNull()) && vout.size() >= 2 && vout[0].IsEmpty());
          }
  
      }
  
      /** Check for standard transaction types
          @return True if all outputs (scriptPubKeys) use only standard transaction forms
      */
      bool IsStandard() const;
  
      /** 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 MapPrevTx& mapInputs) const;
  
      /** 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;
  
      /** 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 MapPrevTx& mapInputs) const;
  
      /** Amount of bitcoins spent by this transaction.
          @return sum of all outputs (note: does not include fees)
       */
      int64 GetValueOut() const
      {
          int64 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 GetValueIn(const MapPrevTx& mapInputs) const;
  
      static bool AllowFree(double dPriority)
      {
          // Large (in bytes) low-priority (new, small-coin) transactions
          // need a fee.
          return dPriority > COIN * 144 / 250;
      }
  
      int64 GetMinFee(unsigned int nBlockSize=1, bool fAllowFree=false, enum GetMinFee_mode mode=GMF_BLOCK, unsigned int nBytes=0) 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 ToStringShort() const
      {
          std::string str;
          str += strprintf("%s %s", GetHash().ToString().c_str(), IsCoinBase()? "base" : (IsCoinStake()? "stake" : "user"));
          return str;
      }
  
      std::string ToString() const
      {
          std::string str;
          str += IsCoinBase()? "Coinbase" : (IsCoinStake()? "Coinstake" : "CTransaction");
          str += strprintf("(hash=%s, nTime=%d, ver=%d, vin.size=%d, vout.size=%d, nLockTime=%d)\n",
              GetHash().ToString().substr(0,10).c_str(),
              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;
      }
  
      void print() const
      {
          printf("%s", ToString().c_str());
      }
  
  
      bool ReadFromDisk(CTxDB& txdb, const uint256& hash, CTxIndex& txindexRet);
      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
          @param[in] fStrictPayToScriptHash	true if fully validating p2sh transactions
          @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, bool fStrictPayToScriptHash=true);
      bool ClientConnectInputs();
      bool CheckTransaction() const;
      bool AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs=true, bool* pfMissingInputs=NULL);
      bool GetCoinAge(CTxDB& txdb, uint64& nCoinAge) const;  // paycoin: get transaction coin age
  
  protected:
      const CTxOut& GetOutputFor(const CTxIn& input, const MapPrevTx& inputs) const;
  };
  
  
  
  
  
  /** A transaction with a merkle branch linking it to the block chain. */
  class CMerkleTx : public CTransaction
  {
  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);
      int GetDepthInMainChain(CBlockIndex* &pindexRet) const;
      int GetDepthInMainChain() const { CBlockIndex *pindexRet; return GetDepthInMainChain(pindexRet); }
      bool IsInMainChain() const { return GetDepthInMainChain() > 0; }
      int GetBlocksToMaturity() const;
      bool AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs=true);
      bool AcceptToMemoryPool();
  };
  
  
  
  
  /**  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
      int nVersion;
      uint256 hashPrevBlock;
      uint256 hashMerkleRoot;
      unsigned int nTime;
      unsigned int nBits;
      unsigned int nNonce;
  
      // network and disk
      std::vector<CTransaction> vtx;
  
      // paycoin: block signature - signed by coin base txout[0]'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 = 1;
          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
      {
          return Hash(BEGIN(nVersion), END(nNonce));
      }
  
      int64 GetBlockTime() const
      {
          return (int64)nTime;
      }
  
      void UpdateTime(const CBlockIndex* pindexPrev);
  
      // paycoin: 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);
      }
  
      // paycoin: get max transaction timestamp
      int64 GetMaxTransactionTime() const
      {
          int64 maxTransactionTime = 0;
          BOOST_FOREACH(const CTransaction& tx, vtx)
              maxTransactionTime = std::max(maxTransactionTime, (int64)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 char pchMessageStart[4];
          GetMessageStart(pchMessageStart, true);
          unsigned int nSize = fileout.GetSerializeSize(*this);
          fileout << FLATDATA(pchMessageStart) << 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)
          {
  #ifdef WIN32
              _commit(_fileno(fileout));
  #else
              fsync(fileno(fileout));
  #endif
          }
  
          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(GetHash(), nBits))
              return error("CBlock::ReadFromDisk() : errors in block header");
  
          return true;
      }
  
  
  
      void print() const
      {
          printf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%u, nBits=%08x, nNonce=%u, vtx=%d, vchBlockSig=%s)\n",
              GetHash().ToString().substr(0,20).c_str(),
              nVersion,
              hashPrevBlock.ToString().substr(0,20).c_str(),
              hashMerkleRoot.ToString().substr(0,10).c_str(),
              nTime, nBits, nNonce,
              vtx.size(),
              HexStr(vchBlockSig.begin(), vchBlockSig.end()).c_str());
          for (unsigned int i = 0; i < vtx.size(); i++)
          {
              printf("  ");
              vtx[i].print();
          }
          printf("  vMerkleTree: ");
          for (unsigned int i = 0; i < vMerkleTree.size(); i++)
              printf("%s ", vMerkleTree[i].ToString().substr(0,10).c_str());
          printf("\n");
      }
  
  
      bool DisconnectBlock(CTxDB& txdb, CBlockIndex* pindex);
      bool ConnectBlock(CTxDB& txdb, CBlockIndex* pindex);
      bool ReadFromDisk(const CBlockIndex* pindex, bool fReadTransactions=true);
      bool SetBestChain(CTxDB& txdb, CBlockIndex* pindexNew);
      bool AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos);
      bool CheckBlock(int64 nHeight=-1) const;
      bool AcceptBlock();
      bool GetCoinAge(uint64& nCoinAge) const; // paycoin: calculate total coin age spent in block
      bool SignBlock(const CKeyStore& keystore);
      bool CheckBlockSignature() const;
      unsigned int GetStakeEntropyBit() const; // paycoin: entropy bit for stake modifier if chosen by modifier
  
  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;
      CBigNum bnChainTrust; // paycoin: trust score of block chain
      int nHeight;
      int64 nMint;
      int64 nMoneySupply;
  
      unsigned int nFlags;  // paycoin: 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 nStakeModifier; // hash modifier for proof-of-stake
      unsigned int nStakeModifierChecksum; // checksum of index; in-memeory only
  
      // proof-of-stake specific fields
      COutPoint prevoutStake;
      unsigned int nStakeTime;
      uint256 hashProofOfStake;
  
      // 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;
          bnChainTrust = 0;
          nMint = 0;
          nMoneySupply = 0;
          nFlags = 0;
          nStakeModifier = 0;
          nStakeModifierChecksum = 0;
          hashProofOfStake = 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;
          bnChainTrust = 0;
          nMint = 0;
          nMoneySupply = 0;
          nFlags = 0;
          nStakeModifier = 0;
          nStakeModifierChecksum = 0;
          hashProofOfStake = 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 GetBlockTime() const
      {
          return (int64)nTime;
      }
  
      /**
       * Duplicate from bitcoinrpc that originaly define this method.
       * May require some cleanup since this method should be available both for rpc
       * and qt clients.
       */
      double GetBlockDifficulty() const
      {
          int nShift = (nBits >> 24) & 0xff;
  
          double dDiff =
              (double)0x0000ffff / (double)(nBits & 0x00ffffff);
  
          while (nShift < 29)
          {
              dDiff *= 256.0;
              nShift++;
          }
          while (nShift > 29)
          {
              dDiff /= 256.0;
              nShift--;
          }
  
          return dDiff;
      }
  
      CBigNum GetBlockTrust() const
      {
          CBigNum bnTarget;
          bnTarget.SetCompact(nBits);
          if (bnTarget <= 0)
              return 0;
          return (IsProofOfStake()? (CBigNum(1)<<256) / (bnTarget+1) : 1);
      }
  
      bool IsInMainChain() const
      {
          return (pnext || this == pindexBest);
      }
  
      bool CheckIndex() const
      {
          return IsProofOfWork() ? CheckProofOfWork(GetBlockHash(), nBits) : true;
      }
  
      bool EraseBlockFromDisk()
      {
          // Open history file
          CAutoFile fileout = CAutoFile(OpenBlockFile(nFile, nBlockPos, "rb+"), SER_DISK, CLIENT_VERSION);
          if (!fileout)
              return false;
  
          // Overwrite with empty null block
          CBlock block;
          block.SetNull();
          fileout << block;
  
          return true;
      }
  
      enum { nMedianTimeSpan=11 };
  
      int64 GetMedianTimePast() const
      {
          int64 pmedian[nMedianTimeSpan];
          int64* pbegin = &pmedian[nMedianTimeSpan];
          int64* 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];
      }
  
      int64 GetMedianTime() const
      {
          const CBlockIndex* pindex = this;
          for (int i = 0; i < nMedianTimeSpan/2; i++)
          {
              if (!pindex->pnext)
                  return GetBlockTime();
              pindex = pindex->pnext;
          }
          return pindex->GetMedianTimePast();
      }
  
      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 nModifier, bool fGeneratedStakeModifier)
      {
          nStakeModifier = nModifier;
          if (fGeneratedStakeModifier)
              nFlags |= BLOCK_STAKE_MODIFIER;
      }
  
      std::string ToString() const
      {
          return strprintf("CBlockIndex(nprev=%08x, pnext=%08x, nFile=%d, nBlockPos=%-6d nHeight=%d, nMint=%s, nMoneySupply=%s, nFlags=(%s)(%d)(%s), nStakeModifier=%016"PRI64x", nStakeModifierChecksum=%08x, hashProofOfStake=%s, prevoutStake=(%s), nStakeTime=%d merkle=%s, hashBlock=%s)",
              pprev, pnext, nFile, nBlockPos, nHeight,
              FormatMoney(nMint).c_str(), FormatMoney(nMoneySupply).c_str(),
              GeneratedStakeModifier() ? "MOD" : "-", GetStakeEntropyBit(), IsProofOfStake()? "PoS" : "PoW",
              nStakeModifier, nStakeModifierChecksum, 
              hashProofOfStake.ToString().c_str(),
              prevoutStake.ToString().c_str(), nStakeTime,
              hashMerkleRoot.ToString().substr(0,10).c_str(),
              GetBlockHash().ToString().substr(0,20).c_str());
      }
  
      void print() const
      {
          printf("%s\n", ToString().c_str());
      }
  };
  
  
  
  /** Used to marshal pointers into hashes for db storage. */
  class CDiskBlockIndex : public CBlockIndex
  {
  public:
      uint256 hashPrev;
      uint256 hashNext;
  
      CDiskBlockIndex()
      {
          hashPrev = 0;
          hashNext = 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);
          if (IsProofOfStake())
          {
              READWRITE(prevoutStake);
              READWRITE(nStakeTime);
              READWRITE(hashProofOfStake);
          }
          else if (fRead)
          {
              const_cast<CDiskBlockIndex*>(this)->prevoutStake.SetNull();
              const_cast<CDiskBlockIndex*>(this)->nStakeTime = 0;
              const_cast<CDiskBlockIndex*>(this)->hashProofOfStake = 0;
          }
  
          // block header
          READWRITE(this->nVersion);
          READWRITE(hashPrev);
          READWRITE(hashMerkleRoot);
          READWRITE(nTime);
          READWRITE(nBits);
          READWRITE(nNonce);
      )
  
      uint256 GetBlockHash() const
      {
          CBlock block;
          block.nVersion        = nVersion;
          block.hashPrevBlock   = hashPrev;
          block.hashMerkleRoot  = hashMerkleRoot;
          block.nTime           = nTime;
          block.nBits           = nBits;
          block.nNonce          = nNonce;
          return block.GetHash();
      }
  
  
      std::string ToString() const
      {
          std::string str = "CDiskBlockIndex(";
          str += CBlockIndex::ToString();
          str += strprintf("\n                hashBlock=%s, hashPrev=%s, hashNext=%s)",
              GetBlockHash().ToString().c_str(),
              hashPrev.ToString().substr(0,20).c_str(),
              hashNext.ToString().substr(0,20).c_str());
          return str;
      }
  
      void print() const
      {
          printf("%s\n", ToString().c_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(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 hashGenesisBlock;
      }
  
      int GetHeight()
      {
          CBlockIndex* pindex = GetBlockIndex();
          if (!pindex)
              return 0;
          return pindex->nHeight;
      }
  };
  
  
  
  
  
  
  
  
  
  /** Alerts are for notifying old versions if they become too obsolete and
   * need to upgrade.  The message is displayed in the status bar.
   * Alert messages are broadcast as a vector of signed data.  Unserializing may
   * not read the entire buffer if the alert is for a newer version, but older
   * versions can still relay the original data.
   */
  class CUnsignedAlert
  {
  public:
      int nVersion;
      int64 nRelayUntil;      // when newer nodes stop relaying to newer nodes
      int64 nExpiration;
      int nID;
      int nCancel;
      std::set<int> setCancel;
      int nMinVer;            // lowest version inclusive
      int nMaxVer;            // highest version inclusive
      std::set<std::string> setSubVer;  // empty matches all
      int nPriority;
  
      // Actions
      std::string strComment;
      std::string strStatusBar;
      std::string strReserved;
  
      IMPLEMENT_SERIALIZE
      (
          READWRITE(this->nVersion);
          nVersion = this->nVersion;
          READWRITE(nRelayUntil);
          READWRITE(nExpiration);
          READWRITE(nID);
          READWRITE(nCancel);
          READWRITE(setCancel);
          READWRITE(nMinVer);
          READWRITE(nMaxVer);
          READWRITE(setSubVer);
          READWRITE(nPriority);
  
          READWRITE(strComment);
          READWRITE(strStatusBar);
          READWRITE(strReserved);
      )
  
      void SetNull()
      {
          nVersion = 1;
          nRelayUntil = 0;
          nExpiration = 0;
          nID = 0;
          nCancel = 0;
          setCancel.clear();
          nMinVer = 0;
          nMaxVer = 0;
          setSubVer.clear();
          nPriority = 0;
  
          strComment.clear();
          strStatusBar.clear();
          strReserved.clear();
      }
  
      std::string ToString() const
      {
          std::string strSetCancel;
          BOOST_FOREACH(int n, setCancel)
              strSetCancel += strprintf("%d ", n);
          std::string strSetSubVer;
          BOOST_FOREACH(std::string str, setSubVer)
              strSetSubVer += "\"" + str + "\" ";
          return strprintf(
                  "CAlert(\n"
                  "    nVersion     = %d\n"
                  "    nRelayUntil  = %"PRI64d"\n"
                  "    nExpiration  = %"PRI64d"\n"
                  "    nID          = %d\n"
                  "    nCancel      = %d\n"
                  "    setCancel    = %s\n"
                  "    nMinVer      = %d\n"
                  "    nMaxVer      = %d\n"
                  "    setSubVer    = %s\n"
                  "    nPriority    = %d\n"
                  "    strComment   = \"%s\"\n"
                  "    strStatusBar = \"%s\"\n"
                  ")\n",
              nVersion,
              nRelayUntil,
              nExpiration,
              nID,
              nCancel,
              strSetCancel.c_str(),
              nMinVer,
              nMaxVer,
              strSetSubVer.c_str(),
              nPriority,
              strComment.c_str(),
              strStatusBar.c_str());
      }
  
      void print() const
      {
          printf("%s", ToString().c_str());
      }
  };
  
  /** An alert is a combination of a serialized CUnsignedAlert and a signature. */
  class CAlert : public CUnsignedAlert
  {
  public:
      std::vector<unsigned char> vchMsg;
      std::vector<unsigned char> vchSig;
  
      CAlert()
      {
          SetNull();
      }
  
      IMPLEMENT_SERIALIZE
      (
          READWRITE(vchMsg);
          READWRITE(vchSig);
      )
  
      void SetNull()
      {
          CUnsignedAlert::SetNull();
          vchMsg.clear();
          vchSig.clear();
      }
  
      bool IsNull() const
      {
          return (nExpiration == 0);
      }
  
      uint256 GetHash() const
      {
          return SerializeHash(*this);
      }
  
      bool IsInEffect() const
      {
          return (GetAdjustedTime() < nExpiration);
      }
  
      bool Cancels(const CAlert& alert) const
      {
          if (!IsInEffect())
              return false; // this was a no-op before 31403
          return (alert.nID <= nCancel || setCancel.count(alert.nID));
      }
  
      bool AppliesTo(int nVersion, std::string strSubVerIn) const
      {
          // TODO: rework for client-version-embedded-in-strSubVer ?
          return (IsInEffect() &&
                  nMinVer <= nVersion && nVersion <= nMaxVer &&
                  (setSubVer.empty() || setSubVer.count(strSubVerIn)));
      }
  
      bool AppliesToMe() const
      {
          return AppliesTo(PROTOCOL_VERSION, FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, std::vector<std::string>()));
      }
  
      bool RelayTo(CNode* pnode) const
      {
          if (!IsInEffect())
              return false;
          // returns true if wasn't already contained in the set
          if (pnode->setKnown.insert(GetHash()).second)
          {
              if (AppliesTo(pnode->nVersion, pnode->strSubVer) ||
                  AppliesToMe() ||
                  GetAdjustedTime() < nRelayUntil)
              {
                  pnode->PushMessage("alert", *this);
                  return true;
              }
          }
          return false;
      }
  
      bool CheckSignature()
      {
          CKey key;
          if (!key.SetPubKey(ParseHex("045dc635516bcd6c75152473bef99e700f364f4aac8fd1951c35e4696c9be8487e750e5efcc67e6e3f71a17696a6d9bd12e97c239bd00cd3fdea8296905c9b7dcf")))
              return error("CAlert::CheckSignature() : SetPubKey failed");
          if (!key.Verify(Hash(vchMsg.begin(), vchMsg.end()), vchSig))
              return error("CAlert::CheckSignature() : verify signature failed");
  
          // Now unserialize the data
          CDataStream sMsg(vchMsg, SER_NETWORK, PROTOCOL_VERSION);
          sMsg >> *(CUnsignedAlert*)this;
          return true;
      }
  
      bool ProcessAlert();
  };
  
  class CTxMemPool
  {
  public:
      mutable CCriticalSection cs;
      std::map<uint256, CTransaction> mapTx;
      std::map<COutPoint, CInPoint> mapNextTx;
  
      bool accept(CTxDB& txdb, CTransaction &tx,
                  bool fCheckInputs, bool* pfMissingInputs);
      bool addUnchecked(CTransaction &tx);
      bool remove(CTransaction &tx);
      void queryHashes(std::vector<uint256>& vtxid);
  
      unsigned long size()
      {
          LOCK(cs);
          return mapTx.size();
      }
  
      bool exists(uint256 hash)
      {
          return (mapTx.count(hash) != 0);
      }
  
      CTransaction& lookup(uint256 hash)
      {
          return mapTx[hash];
      }
  };
  
  extern CTxMemPool mempool;
  
  #endif
  