Merge branch '0.5.x' into 0.6.0.x
authorLuke Dashjr <luke-jr+git@utopios.org>
Tue, 22 May 2012 22:57:10 +0000 (22:57 +0000)
committerLuke Dashjr <luke-jr+git@utopios.org>
Tue, 22 May 2012 22:57:10 +0000 (22:57 +0000)
Conflicts:
src/main.cpp

1  2 
src/db.cpp
src/db.h
src/main.cpp
src/main.h

diff --combined src/db.cpp
@@@ -6,7 -6,6 +6,7 @@@
  #include "headers.h"
  #include "db.h"
  #include "net.h"
 +#include <boost/version.hpp>
  #include <boost/filesystem.hpp>
  #include <boost/filesystem/fstream.hpp>
  
@@@ -28,7 -27,6 +28,7 @@@ static bool fDbEnvInit = false
  DbEnv dbenv(0);
  static map<string, int> mapFileUseCount;
  static map<string, Db*> mapDb;
 +static int64 nTxn = 0;
  
  static void EnvShutdown()
  {
@@@ -85,16 -83,12 +85,16 @@@ CDB::CDB(const char* pszFile, const cha
              string strErrorFile = strDataDir + "/db.log";
              printf("dbenv.open strLogDir=%s strErrorFile=%s\n", strLogDir.c_str(), strErrorFile.c_str());
  
 +            int nDbCache = GetArg("-dbcache", 25);
              dbenv.set_lg_dir(strLogDir.c_str());
 -            dbenv.set_lg_max(10000000);
 +            dbenv.set_cachesize(nDbCache / 1024, (nDbCache % 1024)*1048576, 1);
 +            dbenv.set_lg_bsize(1048576);
 +            dbenv.set_lg_max(10485760);
              dbenv.set_lk_max_locks(10000);
              dbenv.set_lk_max_objects(10000);
              dbenv.set_errfile(fopen(strErrorFile.c_str(), "a")); /// debug
              dbenv.set_flags(DB_AUTO_COMMIT, 1);
 +            dbenv.log_set_config(DB_LOG_AUTO_REMOVE, 1);
              ret = dbenv.open(strDataDir.c_str(),
                               DB_CREATE     |
                               DB_INIT_LOCK  |
              {
                  bool fTmp = fReadOnly;
                  fReadOnly = false;
 -                WriteVersion(VERSION);
 +                WriteVersion(CLIENT_VERSION);
                  fReadOnly = fTmp;
              }
  
@@@ -161,15 -155,8 +161,15 @@@ void CDB::Close(
          nMinutes = 1;
      if (strFile == "addr.dat")
          nMinutes = 2;
 -    if (strFile == "blkindex.dat" && IsInitialBlockDownload() && nBestHeight % 500 != 0)
 -        nMinutes = 1;
 +    if (strFile == "blkindex.dat" && IsInitialBlockDownload())
 +        nMinutes = 5;
 +
 +    if (nMinutes == 0 || nTxn > 200000)
 +    {
 +        nTxn = 0;
 +        nMinutes = 0;
 +    }
 +
      dbenv.txn_checkpoint(0, nMinutes, 0);
  
      CRITICAL_BLOCK(cs_db)
@@@ -249,7 -236,7 +249,7 @@@ bool CDB::Rewrite(const string& strFile
                              {
                                  // Update version:
                                  ssValue.clear();
 -                                ssValue << VERSION;
 +                                ssValue << CLIENT_VERSION;
                              }
                              Dbt datKey(&ssKey[0], ssKey.size());
                              Dbt datValue(&ssValue[0], ssValue.size());
@@@ -344,7 -331,6 +344,7 @@@ bool CTxDB::ReadTxIndex(uint256 hash, C
  bool CTxDB::UpdateTxIndex(uint256 hash, const CTxIndex& txindex)
  {
      assert(!fClient);
 +    nTxn++;
      return Write(make_pair(string("tx"), hash), txindex);
  }
  
@@@ -355,7 -341,6 +355,7 @@@ bool CTxDB::AddTxIndex(const CTransacti
      // Add to tx index
      uint256 hash = tx.GetHash();
      CTxIndex txindex(pos, tx.vout.size());
 +    nTxn++;
      return Write(make_pair(string("tx"), hash), txindex);
  }
  
@@@ -405,9 -390,15 +405,15 @@@ bool CTxDB::ReadOwnerTxes(uint160 hash1
          string strType;
          uint160 hashItem;
          CDiskTxPos pos;
-         ssKey >> strType >> hashItem >> pos;
          int nItemHeight;
-         ssValue >> nItemHeight;
+         try {
+             ssKey >> strType >> hashItem >> pos;
+             ssValue >> nItemHeight;
+         }
+         catch (std::exception &e) {
+             return error("%s() : deserialize error", __PRETTY_FUNCTION__);
+         }
  
          // Read transaction
          if (strType != "owner" || hashItem != hash160)
@@@ -527,6 -518,8 +533,8 @@@ bool CTxDB::LoadBlockIndex(
              return false;
  
          // Unserialize
+         try {
          string strType;
          ssKey >> strType;
          if (strType == "blockindex")
          {
              break;
          }
+         }    // try
+         catch (std::exception &e) {
+             return error("%s() : deserialize error", __PRETTY_FUNCTION__);
+         }
      }
      pcursor->close();
  
      ReadBestInvalidWork(bnBestInvalidWork);
  
      // Verify blocks in the best chain
 +    int nCheckLevel = GetArg("-checklevel", 1);
 +    int nCheckDepth = GetArg( "-checkblocks", 2500);
 +    if (nCheckDepth == 0)
 +        nCheckDepth = 1000000000; // suffices until the year 19000
 +    if (nCheckDepth > nBestHeight)
 +        nCheckDepth = nBestHeight;
 +    printf("Verifying last %i blocks at level %i\n", nCheckDepth, nCheckLevel);
      CBlockIndex* pindexFork = NULL;
 +    map<pair<unsigned int, unsigned int>, CBlockIndex*> mapBlockPos;
      for (CBlockIndex* pindex = pindexBest; pindex && pindex->pprev; pindex = pindex->pprev)
      {
 -        if (pindex->nHeight < nBestHeight-2500 && !mapArgs.count("-checkblocks"))
 +        if (pindex->nHeight < nBestHeight-nCheckDepth)
              break;
          CBlock block;
          if (!block.ReadFromDisk(pindex))
              return error("LoadBlockIndex() : block.ReadFromDisk failed");
 -        if (!block.CheckBlock())
 +        // check level 1: verify block validity
 +        if (nCheckLevel>0 && !block.CheckBlock())
          {
              printf("LoadBlockIndex() : *** found bad block at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString().c_str());
              pindexFork = pindex->pprev;
          }
 +        // check level 2: verify transaction index validity
 +        if (nCheckLevel>1)
 +        {
 +            pair<unsigned int, unsigned int> pos = make_pair(pindex->nFile, pindex->nBlockPos);
 +            mapBlockPos[pos] = pindex;
 +            BOOST_FOREACH(const CTransaction &tx, block.vtx)
 +            {
 +                uint256 hashTx = tx.GetHash();
 +                CTxIndex txindex;
 +                if (ReadTxIndex(hashTx, txindex))
 +                {
 +                    // check level 3: checker transaction hashes
 +                    if (nCheckLevel>2 || pindex->nFile != txindex.pos.nFile || pindex->nBlockPos != txindex.pos.nBlockPos)
 +                    {
 +                        // either an error or a duplicate transaction
 +                        CTransaction txFound;
 +                        if (!txFound.ReadFromDisk(txindex.pos))
 +                        {
 +                            printf("LoadBlockIndex() : *** cannot read mislocated transaction %s\n", hashTx.ToString().c_str());
 +                            pindexFork = pindex->pprev;
 +                        }
 +                        else
 +                            if (txFound.GetHash() != hashTx) // not a duplicate tx
 +                            {
 +                                printf("LoadBlockIndex(): *** invalid tx position for %s\n", hashTx.ToString().c_str());
 +                                pindexFork = pindex->pprev;
 +                            }
 +                    }
 +                    // check level 4: check whether spent txouts were spent within the main chain
 +                    int nOutput = 0;
 +                    if (nCheckLevel>3)
 +                    {
 +                        BOOST_FOREACH(const CDiskTxPos &txpos, txindex.vSpent)
 +                        {
 +                            if (!txpos.IsNull())
 +                            {
 +                                pair<unsigned int, unsigned int> posFind = make_pair(txpos.nFile, txpos.nBlockPos);
 +                                if (!mapBlockPos.count(posFind))
 +                                {
 +                                    printf("LoadBlockIndex(): *** found bad spend at %d, hashBlock=%s, hashTx=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString().c_str(), hashTx.ToString().c_str());
 +                                    pindexFork = pindex->pprev;
 +                                }
 +                                // check level 6: check whether spent txouts were spent by a valid transaction that consume them
 +                                if (nCheckLevel>5)
 +                                {
 +                                    CTransaction txSpend;
 +                                    if (!txSpend.ReadFromDisk(txpos))
 +                                    {
 +                                        printf("LoadBlockIndex(): *** cannot read spending transaction of %s:%i from disk\n", hashTx.ToString().c_str(), nOutput);
 +                                        pindexFork = pindex->pprev;
 +                                    }
 +                                    else if (!txSpend.CheckTransaction())
 +                                    {
 +                                        printf("LoadBlockIndex(): *** spending transaction of %s:%i is invalid\n", hashTx.ToString().c_str(), nOutput);
 +                                        pindexFork = pindex->pprev;
 +                                    }
 +                                    else
 +                                    {
 +                                        bool fFound = false;
 +                                        BOOST_FOREACH(const CTxIn &txin, txSpend.vin)
 +                                            if (txin.prevout.hash == hashTx && txin.prevout.n == nOutput)
 +                                                fFound = true;
 +                                        if (!fFound)
 +                                        {
 +                                            printf("LoadBlockIndex(): *** spending transaction of %s:%i does not spend it\n", hashTx.ToString().c_str(), nOutput);
 +                                            pindexFork = pindex->pprev;
 +                                        }
 +                                    }
 +                                }
 +                            }
 +                            nOutput++;
 +                        }
 +                    }
 +                }
 +                // check level 5: check whether all prevouts are marked spent
 +                if (nCheckLevel>4)
 +                {
 +                     BOOST_FOREACH(const CTxIn &txin, tx.vin)
 +                     {
 +                          CTxIndex txindex;
 +                          if (ReadTxIndex(txin.prevout.hash, txindex))
 +                              if (txindex.vSpent.size()-1 < txin.prevout.n || txindex.vSpent[txin.prevout.n].IsNull())
 +                              {
 +                                  printf("LoadBlockIndex(): *** found unspent prevout %s:%i in %s\n", txin.prevout.hash.ToString().c_str(), txin.prevout.n, hashTx.ToString().c_str());
 +                                  pindexFork = pindex->pprev;
 +                              }
 +                     }
 +                }
 +            }
 +        }
      }
      if (pindexFork)
      {
  // CAddrDB
  //
  
 -bool CAddrDB::WriteAddress(const CAddress& addr)
 -{
 -    return Write(make_pair(string("addr"), addr.GetKey()), addr);
 -}
 -
 -bool CAddrDB::EraseAddress(const CAddress& addr)
 +bool CAddrDB::WriteAddrman(const CAddrMan& addrman)
  {
 -    return Erase(make_pair(string("addr"), addr.GetKey()));
 +    return Write(string("addrman"), addrman);
  }
  
  bool CAddrDB::LoadAddresses()
  {
 -    CRITICAL_BLOCK(cs_mapAddresses)
 +    if (Read(string("addrman"), addrman))
      {
 -        // Get cursor
 -        Dbc* pcursor = GetCursor();
 -        if (!pcursor)
 +        printf("Loaded %i addresses\n", addrman.size());
 +        return true;
 +    }
 +    
 +    // Read pre-0.6 addr records
 +
 +    vector<CAddress> vAddr;
 +    vector<vector<unsigned char> > vDelete;
 +
 +    // Get cursor
 +    Dbc* pcursor = GetCursor();
 +    if (!pcursor)
 +        return false;
 +
 +    loop
 +    {
 +        // Read next record
 +        CDataStream ssKey;
 +        CDataStream ssValue;
 +        int ret = ReadAtCursor(pcursor, ssKey, ssValue);
 +        if (ret == DB_NOTFOUND)
 +            break;
 +        else if (ret != 0)
              return false;
  
 -        loop
 +        // Unserialize
 +        string strType;
 +        ssKey >> strType;
 +        if (strType == "addr")
          {
 -            // Read next record
 -            CDataStream ssKey;
 -            CDataStream ssValue;
 -            int ret = ReadAtCursor(pcursor, ssKey, ssValue);
 -            if (ret == DB_NOTFOUND)
 -                break;
 -            else if (ret != 0)
 -                return false;
 -
 -            // Unserialize
 -            string strType;
 -            ssKey >> strType;
 -            if (strType == "addr")
 -            {
 -                CAddress addr;
 -                ssValue >> addr;
 -                mapAddresses.insert(make_pair(addr.GetKey(), addr));
 -            }
 +            CAddress addr;
 +            ssValue >> addr;
 +            vAddr.push_back(addr);
          }
 -        pcursor->close();
 -
 -        printf("Loaded %d addresses\n", mapAddresses.size());
      }
 +    pcursor->close();
 +
 +    addrman.Add(vAddr, CNetAddr("0.0.0.0"));
 +    printf("Loaded %i addresses\n", addrman.size());
 +
 +    // Note: old records left; we ran into hangs-on-startup
 +    // bugs for some users who (we think) were running after
 +    // an unclean shutdown.
  
      return true;
  }
@@@ -889,15 -779,21 +901,15 @@@ int CWalletDB::LoadWallet(CWallet* pwal
      vector<uint256> vWalletUpgrade;
      bool fIsEncrypted = false;
  
 -    // Modify defaults
 -#ifndef WIN32
 -    // Tray icon sometimes disappears on 9.10 karmic koala 64-bit, leaving no way to access the program
 -    fMinimizeToTray = false;
 -    fMinimizeOnClose = false;
 -#endif
 -
      //// todo: shouldn't we catch exceptions and try to recover and continue?
      CRITICAL_BLOCK(pwallet->cs_wallet)
      {
          int nMinVersion = 0;
          if (Read((string)"minversion", nMinVersion))
          {
 -            if (nMinVersion > VERSION)
 +            if (nMinVersion > CLIENT_VERSION)
                  return DB_TOO_NEW;
 +            pwallet->LoadMinVersion(nMinVersion);
          }
  
          // Get cursor
                  ssKey >> hash;
                  CWalletTx& wtx = pwallet->mapWallet[hash];
                  ssValue >> wtx;
 -                wtx.pwallet = pwallet;
 +                wtx.BindWallet(pwallet);
  
                  if (wtx.GetHash() != hash)
                      printf("Error in wallet.dat, hash mismatch\n");
                  {
                      CPrivKey pkey;
                      ssValue >> pkey;
 +                    key.SetPubKey(vchPubKey);
                      key.SetPrivKey(pkey);
                      if (key.GetPubKey() != vchPubKey)
                      {
                  {
                      CWalletKey wkey;
                      ssValue >> wkey;
 +                    key.SetPubKey(vchPubKey);
                      key.SetPrivKey(wkey.vchPrivKey);
                      if (key.GetPubKey() != vchPubKey)
                      {
                  if (nFileVersion == 10300)
                      nFileVersion = 300;
              }
 -            else if (strType == "setting")
 +            else if (strType == "cscript")
              {
 -                string strKey;
 -                ssKey >> strKey;
 -
 -                // Options
 -#ifndef QT_GUI
 -                if (strKey == "fGenerateBitcoins")  ssValue >> fGenerateBitcoins;
 -#endif
 -                if (strKey == "nTransactionFee")    ssValue >> nTransactionFee;
 -                if (strKey == "fLimitProcessors")   ssValue >> fLimitProcessors;
 -                if (strKey == "nLimitProcessors")   ssValue >> nLimitProcessors;
 -                if (strKey == "fMinimizeToTray")    ssValue >> fMinimizeToTray;
 -                if (strKey == "fMinimizeOnClose")   ssValue >> fMinimizeOnClose;
 -                if (strKey == "fUseProxy")          ssValue >> fUseProxy;
 -                if (strKey == "addrProxy")          ssValue >> addrProxy;
 -                if (fHaveUPnP && strKey == "fUseUPnP")           ssValue >> fUseUPnP;
 +                uint160 hash;
 +                ssKey >> hash;
 +                CScript script;
 +                ssValue >> script;
 +                if (!pwallet->LoadCScript(script))
 +                {
 +                    printf("Error reading wallet database: LoadCScript failed\n");
 +                    return DB_CORRUPT;
 +                }
              }
          }
          pcursor->close();
          WriteTx(hash, pwallet->mapWallet[hash]);
  
      printf("nFileVersion = %d\n", nFileVersion);
 -    printf("fGenerateBitcoins = %d\n", fGenerateBitcoins);
 -    printf("nTransactionFee = %"PRI64d"\n", nTransactionFee);
 -    printf("fMinimizeToTray = %d\n", fMinimizeToTray);
 -    printf("fMinimizeOnClose = %d\n", fMinimizeOnClose);
 -    printf("fUseProxy = %d\n", fUseProxy);
 -    printf("addrProxy = %s\n", addrProxy.ToString().c_str());
 -    if (fHaveUPnP)
 -        printf("fUseUPnP = %d\n", fUseUPnP);
  
  
      // Rewrite encrypted wallets of versions 0.4.0 and 0.5.0rc:
      if (fIsEncrypted && (nFileVersion == 40000 || nFileVersion == 50000))
          return DB_NEED_REWRITE;
  
 -    if (nFileVersion < VERSION) // Update
 +    if (nFileVersion < CLIENT_VERSION) // Update
      {
          // Get rid of old debug.log file in current directory
          if (nFileVersion <= 105 && !pszSetDataDir[0])
              unlink("debug.log");
  
 -        WriteVersion(VERSION);
 +        WriteVersion(CLIENT_VERSION);
      }
  
      return DB_LOAD_OK;
@@@ -1114,7 -1022,7 +1126,7 @@@ void ThreadFlushWalletDB(void* parg
      if (fOneThread)
          return;
      fOneThread = true;
 -    if (mapArgs.count("-noflushwallet"))
 +    if (!GetBoolArg("-flushwallet", true))
          return;
  
      unsigned int nLastSeen = nWalletDBUpdated;
@@@ -1188,19 -1096,14 +1200,19 @@@ bool BackupWallet(const CWallet& wallet
                  filesystem::path pathDest(strDest);
                  if (filesystem::is_directory(pathDest))
                      pathDest = pathDest / wallet.strWalletFile;
 +
 +                try {
  #if BOOST_VERSION >= 104000
 -                filesystem::copy_file(pathSrc, pathDest, filesystem::copy_option::overwrite_if_exists);
 +                    filesystem::copy_file(pathSrc, pathDest, filesystem::copy_option::overwrite_if_exists);
  #else
 -                filesystem::copy_file(pathSrc, pathDest);
 +                    filesystem::copy_file(pathSrc, pathDest);
  #endif
 -                printf("copied wallet.dat to %s\n", pathDest.string().c_str());
 -
 -                return true;
 +                    printf("copied wallet.dat to %s\n", pathDest.string().c_str());
 +                    return true;
 +                } catch(const filesystem::filesystem_error &e) {
 +                    printf("error copying wallet.dat to %s - %s\n", pathDest.string().c_str(), e.what());
 +                    return false;
 +                }
              }
          }
          Sleep(100);
diff --combined src/db.h
+++ b/src/db.h
@@@ -1,5 -1,5 +1,5 @@@
  // Copyright (c) 2009-2010 Satoshi Nakamoto
 -// Copyright (c) 2011 The Bitcoin developers
 +// 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_DB_H
  
  #include <db_cxx.h>
  
 -class CTxIndex;
 +class CAccount;
 +class CAccountingEntry;
 +class CAddress;
 +class CAddrMan;
 +class CBlockLocator;
  class CDiskBlockIndex;
  class CDiskTxPos;
 +class CMasterKey;
  class COutPoint;
 -class CAddress;
 -class CWalletTx;
 +class CTxIndex;
  class CWallet;
 -class CAccount;
 -class CAccountingEntry;
 -class CBlockLocator;
 -
 +class CWalletTx;
  
  extern unsigned int nWalletDBUpdated;
  extern DbEnv dbenv;
@@@ -34,7 -33,7 +34,7 @@@ void ThreadFlushWalletDB(void* parg)
  bool BackupWallet(const CWallet& wallet, const std::string& strDest);
  
  
 -
 +/** RAII class that provides access to a Berkeley database */
  class CDB
  {
  protected:
@@@ -73,8 -72,13 +73,13 @@@ protected
              return false;
  
          // Unserialize value
-         CDataStream ssValue((char*)datValue.get_data(), (char*)datValue.get_data() + datValue.get_size(), SER_DISK);
-         ssValue >> value;
+         try {
+             CDataStream ssValue((char*)datValue.get_data(), (char*)datValue.get_data() + datValue.get_size(), SER_DISK);
+             ssValue >> value;
+         }
+         catch (std::exception &e) {
+             return false;
+         }
  
          // Clear and free memory
          memset(datValue.get_data(), 0, datValue.get_size());
@@@ -266,7 -270,7 +271,7 @@@ public
  
  
  
 -
 +/** Access to the transaction database (blkindex.dat) */
  class CTxDB : public CDB
  {
  public:
@@@ -297,7 -301,7 +302,7 @@@ public
  
  
  
 -
 +/** Access to the (IP) address database (addr.dat) */
  class CAddrDB : public CDB
  {
  public:
@@@ -306,14 -310,15 +311,14 @@@ private
      CAddrDB(const CAddrDB&);
      void operator=(const CAddrDB&);
  public:
 -    bool WriteAddress(const CAddress& addr);
 -    bool EraseAddress(const CAddress& addr);
 +    bool WriteAddrman(const CAddrMan& addr);
      bool LoadAddresses();
  };
  
  bool LoadAddresses();
  
  
 -
 +/** A key pool entry */
  class CKeyPool
  {
  public:
  
  
  
 -
 +/** Error statuses for the wallet database */
  enum DBErrors
  {
      DB_LOAD_OK,
      DB_NEED_REWRITE
  };
  
 +/** Access to the wallet database (wallet.dat) */
  class CWalletDB : public CDB
  {
  public:
@@@ -421,19 -425,6 +426,19 @@@ public
          return Write(std::make_pair(std::string("mkey"), nID), kMasterKey, true);
      }
  
 +    // Support for BIP 0013 : see https://en.bitcoin.it/wiki/BIP_0013
 +    bool ReadCScript(const uint160 &hash, CScript& redeemScript)
 +    {
 +        redeemScript.clear();
 +        return Read(std::make_pair(std::string("cscript"), hash), redeemScript);
 +    }
 +
 +    bool WriteCScript(const uint160& hash, const CScript& redeemScript)
 +    {
 +        nWalletDBUpdated++;
 +        return Write(std::make_pair(std::string("cscript"), hash), redeemScript, false);
 +    }
 +
      bool WriteBestBlock(const CBlockLocator& locator)
      {
          nWalletDBUpdated++;
          return Erase(std::make_pair(std::string("pool"), nPool));
      }
  
 +    // Settings are no longer stored in wallet.dat; these are
 +    // used only for backwards compatibility:
      template<typename T>
      bool ReadSetting(const std::string& strKey, T& value)
      {
          return Read(std::make_pair(std::string("setting"), strKey), value);
      }
 -
      template<typename T>
      bool WriteSetting(const std::string& strKey, const T& value)
      {
          nWalletDBUpdated++;
          return Write(std::make_pair(std::string("setting"), strKey), value);
      }
 +    bool EraseSetting(const std::string& strKey)
 +    {
 +        nWalletDBUpdated++;
 +        return Erase(std::make_pair(std::string("setting"), strKey));
 +    }
 +
 +    bool WriteMinVersion(int nVersion)
 +    {
 +        return Write(std::string("minversion"), nVersion);
 +    }
  
      bool ReadAccount(const std::string& strAccount, CAccount& account);
      bool WriteAccount(const std::string& strAccount, const CAccount& account);
diff --combined src/main.cpp
@@@ -8,7 -8,6 +8,7 @@@
  #include "db.h"
  #include "net.h"
  #include "init.h"
 +#include <boost/algorithm/string/replace.hpp>
  #include <boost/filesystem.hpp>
  #include <boost/filesystem/fstream.hpp>
  
@@@ -19,11 -18,6 +19,11 @@@ using namespace boost
  // Global state
  //
  
 +// Name of client reported in the 'version' message. Report the same name
 +// for both bitcoind and bitcoin-qt, to make it harder for attackers to
 +// target servers or GUI users specifically.
 +const std::string CLIENT_NAME("Satoshi");
 +
  CCriticalSection cs_setpwalletRegistered;
  set<CWallet*> setpwalletRegistered;
  
@@@ -53,17 -47,22 +53,17 @@@ multimap<uint256, CBlock*> mapOrphanBlo
  map<uint256, CDataStream*> mapOrphanTransactions;
  multimap<uint256, CDataStream*> mapOrphanTransactionsByPrev;
  
 +// Constant stuff for coinbase transactions we create:
 +CScript COINBASE_FLAGS;
 +
 +const string strMessageMagic = "Bitcoin Signed Message:\n";
  
  double dHashesPerSec;
  int64 nHPSTimerStart;
  
  // Settings
 -int fGenerateBitcoins = false;
  int64 nTransactionFee = 0;
 -int fLimitProcessors = false;
 -int nLimitProcessors = 1;
 -int fMinimizeToTray = true;
 -int fMinimizeOnClose = true;
 -#if USE_UPNP
 -int fUseUPnP = true;
 -#else
 -int fUseUPnP = false;
 -#endif
 +
  
  
  //////////////////////////////////////////////////////////////////////////////
@@@ -260,103 -259,6 +260,103 @@@ bool CTransaction::ReadFromDisk(COutPoi
      return ReadFromDisk(txdb, prevout, txindex);
  }
  
 +bool CTransaction::IsStandard() const
 +{
 +    BOOST_FOREACH(const CTxIn& txin, vin)
 +    {
 +        // Biggest 'standard' txin is a 3-signature 3-of-3 CHECKMULTISIG
 +        // pay-to-script-hash, which is 3 ~80-byte signatures, 3
 +        // ~65-byte public keys, plus a few script ops.
 +        if (txin.scriptSig.size() > 500)
 +            return false;
 +        if (!txin.scriptSig.IsPushOnly())
 +            return false;
 +    }
 +    BOOST_FOREACH(const CTxOut& txout, vout)
 +        if (!::IsStandard(txout.scriptPubKey))
 +            return false;
 +    return true;
 +}
 +
 +//
 +// Check transaction inputs, and make sure any
 +// pay-to-script-hash transactions are evaluating IsStandard scripts
 +//
 +// Why bother? To avoid denial-of-service attacks; an attacker
 +// can submit a standard HASH... OP_EQUAL transaction,
 +// which will get accepted into blocks. The redemption
 +// script can be anything; an attacker could use a very
 +// expensive-to-check-upon-redemption script like:
 +//   DUP CHECKSIG DROP ... repeated 100 times... OP_1
 +//
 +bool CTransaction::AreInputsStandard(const MapPrevTx& mapInputs) const
 +{
 +    if (IsCoinBase())
 +        return true; // Coinbases don't use vin normally
 +
 +    for (unsigned int i = 0; i < vin.size(); i++)
 +    {
 +        const CTxOut& prev = GetOutputFor(vin[i], mapInputs);
 +
 +        vector<vector<unsigned char> > vSolutions;
 +        txnouttype whichType;
 +        // get the scriptPubKey corresponding to this input:
 +        const CScript& prevScript = prev.scriptPubKey;
 +        if (!Solver(prevScript, whichType, vSolutions))
 +            return false;
 +        int nArgsExpected = ScriptSigArgsExpected(whichType, vSolutions);
 +        if (nArgsExpected < 0)
 +            return false;
 +
 +        // Transactions with extra stuff in their scriptSigs are
 +        // non-standard. Note that this EvalScript() call will
 +        // be quick, because if there are any operations
 +        // beside "push data" in the scriptSig the
 +        // IsStandard() call returns false
 +        vector<vector<unsigned char> > stack;
 +        if (!EvalScript(stack, vin[i].scriptSig, *this, i, 0))
 +            return false;
 +
 +        if (whichType == TX_SCRIPTHASH)
 +        {
 +            if (stack.empty())
 +                return false;
 +            CScript subscript(stack.back().begin(), stack.back().end());
 +            vector<vector<unsigned char> > vSolutions2;
 +            txnouttype whichType2;
 +            if (!Solver(subscript, whichType2, vSolutions2))
 +                return false;
 +            if (whichType2 == TX_SCRIPTHASH)
 +                return false;
 +
 +            int tmpExpected;
 +            tmpExpected = ScriptSigArgsExpected(whichType2, vSolutions2);
 +            if (tmpExpected < 0)
 +                return false;
 +            nArgsExpected += tmpExpected;
 +        }
 +
 +        if (stack.size() != (unsigned int)nArgsExpected)
 +            return false;
 +    }
 +
 +    return true;
 +}
 +
 +int
 +CTransaction::GetLegacySigOpCount() const
 +{
 +    int nSigOps = 0;
 +    BOOST_FOREACH(const CTxIn& txin, vin)
 +    {
 +        nSigOps += txin.scriptSig.GetSigOpCount(false);
 +    }
 +    BOOST_FOREACH(const CTxOut& txout, vout)
 +    {
 +        nSigOps += txout.scriptPubKey.GetSigOpCount(false);
 +    }
 +    return nSigOps;
 +}
  
  
  int CMerkleTx::SetMerkleBranch(const CBlock* pblock)
@@@ -477,7 -379,7 +477,7 @@@ bool CTransaction::AcceptToMemoryPool(C
          return DoS(100, error("AcceptToMemoryPool() : coinbase as individual tx"));
  
      // To help v0.1.5 clients who would see it as a negative number
 -    if ((int64)nLockTime > INT_MAX)
 +    if ((int64)nLockTime > std::numeric_limits<int>::max())
          return error("AcceptToMemoryPool() : not accepting nLockTime beyond 2038 yet");
  
      // Rather not work on nonstandard transactions (unless -testnet)
              return error("AcceptToMemoryPool() : FetchInputs failed %s", hash.ToString().substr(0,10).c_str());
          }
  
 -        // Safety limits
 -        unsigned int nSize = ::GetSerializeSize(*this, SER_NETWORK);
 -        // Checking ECDSA signatures is a CPU bottleneck, so to avoid denial-of-service
 -        // attacks disallow transactions with more than one SigOp per 34 bytes.
 -        // 34 bytes because a TxOut is:
 -        //   20-byte address + 8 byte bitcoin amount + 5 bytes of ops + 1 byte script length
 -        if (GetSigOpCount() > nSize / 34 || nSize < 100)
 -            return error("AcceptToMemoryPool() : transaction with out-of-bounds SigOpCount");
 +        // Check for non-standard pay-to-script-hash in inputs
 +        if (!AreInputsStandard(mapInputs) && !fTestNet)
 +            return error("AcceptToMemoryPool() : nonstandard transaction input");
 +
 +        // Note: if you modify this code to accept non-standard transactions, then
 +        // you should add code here to check that the transaction does a
 +        // reasonable number of ECDSA signature verifications.
  
          int64 nFees = GetValueIn(mapInputs)-GetValueOut();
 +        unsigned int nSize = ::GetSerializeSize(*this, SER_NETWORK);
  
          // Don't accept it if it can't get into a block
 -        if (nFees < GetMinFee(1000, true, true))
 +        if (nFees < GetMinFee(1000, true, GMF_RELAY))
              return error("AcceptToMemoryPool() : not enough fees");
  
          // Continuously rate-limit free transactions
@@@ -609,11 -511,8 +609,11 @@@ bool CTransaction::AcceptToMemoryPool(b
      return AcceptToMemoryPool(txdb, fCheckInputs, pfMissingInputs);
  }
  
 +uint64 nPooledTx = 0;
 +
  bool CTransaction::AddToMemoryPoolUnchecked()
  {
 +    printf("AcceptToMemoryPoolUnchecked(): size %lu\n",  mapTransactions.size());
      // Add to memory pool without checking anything.  Don't call this directly,
      // call AcceptToMemoryPool to properly check the transaction first.
      CRITICAL_BLOCK(cs_mapTransactions)
          for (unsigned int i = 0; i < vin.size(); i++)
              mapNextTx[vin[i].prevout] = CInPoint(&mapTransactions[hash], i);
          nTransactionsUpdated++;
 +        ++nPooledTx;
      }
      return true;
  }
@@@ -634,15 -532,10 +634,15 @@@ bool CTransaction::RemoveFromMemoryPool
      // Remove transaction from memory pool
      CRITICAL_BLOCK(cs_mapTransactions)
      {
 -        BOOST_FOREACH(const CTxIn& txin, vin)
 -            mapNextTx.erase(txin.prevout);
 -        mapTransactions.erase(GetHash());
 -        nTransactionsUpdated++;
 +        uint256 hash = GetHash();
 +        if (mapTransactions.count(hash))
 +        {
 +            BOOST_FOREACH(const CTxIn& txin, vin)
 +                mapNextTx.erase(txin.prevout);
 +            mapTransactions.erase(hash);
 +            nTransactionsUpdated++;
 +            --nPooledTx;
 +        }
      }
      return true;
  }
  
  
  
 -int CMerkleTx::GetDepthInMainChain(int& nHeightRet) const
 +int CMerkleTx::GetDepthInMainChain(CBlockIndex* &pindexRet) const
  {
      if (hashBlock == 0 || nIndex == -1)
          return 0;
          fMerkleVerified = true;
      }
  
 -    nHeightRet = pindex->nHeight;
 +    pindexRet = pindex;
      return pindexBest->nHeight - pindex->nHeight + 1;
  }
  
@@@ -1290,9 -1183,9 +1290,9 @@@ bool CBlock::ConnectBlock(CTxDB& txdb, 
          }
      }
  
 -    // P2SH didn't become active until Apr 1 2012 (Feb 15 on testnet)
 -    int64 nEvalSwitchTime = fTestNet ? 1329264000 : 1333238400;
 -    bool fStrictPayToScriptHash = (pindex->nTime >= nEvalSwitchTime);
 +    // BIP16 didn't become active until Apr 1 2012 (Feb 15 on testnet)
 +    int64 nBIP16SwitchTime = fTestNet ? 1329264000 : 1333238400;
 +    bool fStrictPayToScriptHash = (pindex->nTime >= nBIP16SwitchTime);
  
      //// issue here: it doesn't know the version
      unsigned int nTxPos = pindex->nBlockPos + ::GetSerializeSize(CBlock(), SER_DISK) - 1 + GetSizeOfCompactSize(vtx.size());
      int nSigOps = 0;
      BOOST_FOREACH(CTransaction& tx, vtx)
      {
 -        nSigOps += tx.GetSigOpCount();
 +        nSigOps += tx.GetLegacySigOpCount();
          if (nSigOps > MAX_BLOCK_SIGOPS)
              return DoS(100, error("ConnectBlock() : too many sigops"));
  
          CDiskTxPos posThisTx(pindex->nFile, pindex->nBlockPos, nTxPos);
          nTxPos += ::GetSerializeSize(tx, SER_DISK);
  
          MapPrevTx mapInputs;
          if (!tx.IsCoinBase())
          {
 +            bool fInvalid;
              if (!tx.FetchInputs(txdb, mapQueuedChanges, true, false, mapInputs, fInvalid))
                  return false;
  
@@@ -1460,39 -1353,6 +1460,39 @@@ bool static Reorganize(CTxDB& txdb, CBl
  }
  
  
 +static void
 +runCommand(std::string strCommand)
 +{
 +    int nErr = ::system(strCommand.c_str());
 +    if (nErr)
 +        printf("runCommand error: system(%s) returned %d\n", strCommand.c_str(), nErr);
 +}
 +
 +// Called from inside SetBestChain: attaches a block to the new best chain being built
 +bool CBlock::SetBestChainInner(CTxDB& txdb, CBlockIndex *pindexNew)
 +{
 +    uint256 hash = GetHash();
 +
 +    // Adding to current best branch
 +    if (!ConnectBlock(txdb, pindexNew) || !txdb.WriteHashBestChain(hash))
 +    {
 +        txdb.TxnAbort();
 +        InvalidChainFound(pindexNew);
 +        return false;
 +    }
 +    if (!txdb.TxnCommit())
 +        return error("SetBestChain() : TxnCommit failed");
 +
 +    // Add to current best branch
 +    pindexNew->pprev->pnext = pindexNew;
 +
 +    // Delete redundant memory transactions
 +    BOOST_FOREACH(CTransaction& tx, vtx)
 +        tx.RemoveFromMemoryPool();
 +
 +    return true;
 +}
 +
  bool CBlock::SetBestChain(CTxDB& txdb, CBlockIndex* pindexNew)
  {
      uint256 hash = GetHash();
      }
      else if (hashPrevBlock == hashBestChain)
      {
 -        // Adding to current best branch
 -        if (!ConnectBlock(txdb, pindexNew) || !txdb.WriteHashBestChain(hash))
 +        if (!SetBestChainInner(txdb, pindexNew))
 +            return error("SetBestChain() : SetBestChainInner failed");
 +    }
 +    else
 +    {
 +        // the first block in the new chain that will cause it to become the new best chain
 +        CBlockIndex *pindexIntermediate = pindexNew;
 +
 +        // list of blocks that need to be connected afterwards
 +        std::vector<CBlockIndex*> vpindexSecondary;
 +
 +        // Reorganize is costly in terms of db load, as it works in a single db transaction.
 +        // Try to limit how much needs to be done inside
 +        while (pindexIntermediate->pprev && pindexIntermediate->pprev->bnChainWork > pindexBest->bnChainWork)
          {
 -            txdb.TxnAbort();
 -            InvalidChainFound(pindexNew);
 -            return error("SetBestChain() : ConnectBlock failed");
 +            vpindexSecondary.push_back(pindexIntermediate);
 +            pindexIntermediate = pindexIntermediate->pprev;
          }
 -        if (!txdb.TxnCommit())
 -            return error("SetBestChain() : TxnCommit failed");
  
 -        // Add to current best branch
 -        pindexNew->pprev->pnext = pindexNew;
 +        if (!vpindexSecondary.empty())
 +            printf("Postponing %i reconnects\n", vpindexSecondary.size());
  
 -        // Delete redundant memory transactions
 -        BOOST_FOREACH(CTransaction& tx, vtx)
 -            tx.RemoveFromMemoryPool();
 -    }
 -    else
 -    {
 -        // New best branch
 -        if (!Reorganize(txdb, pindexNew))
 +        // Switch to new best branch
 +        if (!Reorganize(txdb, pindexIntermediate))
          {
              txdb.TxnAbort();
              InvalidChainFound(pindexNew);
              return error("SetBestChain() : Reorganize failed");
          }
 +
 +        // Connect futher blocks
 +        BOOST_REVERSE_FOREACH(CBlockIndex *pindex, vpindexSecondary)
 +        {
 +            CBlock block;
 +            if (!block.ReadFromDisk(pindex))
 +            {
 +                printf("SetBestChain() : ReadFromDisk failed\n");
 +                break;
 +            }
 +            if (!txdb.TxnBegin()) {
 +                printf("SetBestChain() : TxnBegin 2 failed\n");
 +                break;
 +            }
 +            // errors now are not fatal, we still did a reorganisation to a new chain in a valid way
 +            if (!block.SetBestChainInner(txdb, pindex))
 +                break;
 +        }
      }
  
      // Update best block in wallet (so we can detect restored wallets)
 -    if (!IsInitialBlockDownload())
 +    bool fIsInitialDownload = IsInitialBlockDownload();
 +    if (!fIsInitialDownload)
      {
          const CBlockLocator locator(pindexNew);
          ::SetBestChain(locator);
      nTransactionsUpdated++;
      printf("SetBestChain: new best=%s  height=%d  work=%s\n", hashBestChain.ToString().substr(0,20).c_str(), nBestHeight, bnBestChainWork.ToString().c_str());
  
 +    std::string strCmd = GetArg("-blocknotify", "");
 +
 +    if (!fIsInitialDownload && !strCmd.empty())
 +    {
 +        boost::replace_all(strCmd, "%s", hashBestChain.GetHex());
 +        boost::thread t(runCommand, strCmd); // thread runs free
 +    }
 +
      return true;
  }
  
@@@ -1676,12 -1506,8 +1676,12 @@@ bool CBlock::CheckBlock() cons
      if (uniqueTx.size() != vtx.size())
          return DoS(100, error("CheckBlock() : duplicate transaction"));
  
 -    // Check that it's not full of nonstandard transactions
 -    if (GetSigOpCount() > MAX_BLOCK_SIGOPS)
 +    int nSigOps = 0;
 +    BOOST_FOREACH(const CTransaction& tx, vtx)
 +    {
 +        nSigOps += tx.GetLegacySigOpCount();
 +    }
 +    if (nSigOps > MAX_BLOCK_SIGOPS)
          return DoS(100, error("CheckBlock() : out-of-bounds SigOpCount"));
  
      // Check merkleroot
@@@ -1836,7 -1662,7 +1836,7 @@@ bool CheckDiskSpace(uint64 nAdditionalB
      if (nFreeBytesAvailable < (uint64)15000000 + nAdditionalBytes)
      {
          fShutdown = true;
-         string strMessage = _("Warning: Disk space is low  ");
+         string strMessage = _("Warning: Disk space is low");
          strMiscWarning = strMessage;
          printf("*** %s\n", strMessage.c_str());
          ThreadSafeMessageBox(strMessage, "Bitcoin", wxOK | wxICON_EXCLAMATION);
@@@ -2194,7 -2020,7 +2194,7 @@@ unsigned char pchMessageStart[4] = { 0x
  
  bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
  {
 -    static map<unsigned int, vector<unsigned char> > mapReuseKey;
 +    static map<CService, vector<unsigned char> > mapReuseKey;
      RandAddSeedPerfmon();
      if (fDebug) {
          printf("%s ", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str());
          CAddress addrFrom;
          uint64 nNonce = 1;
          vRecv >> pfrom->nVersion >> pfrom->nServices >> nTime >> addrMe;
 +        if (pfrom->nVersion < 209)
 +        {
 +            // Since February 20, 2012, the protocol is initiated at version 209,
 +            // and earlier versions are no longer supported
 +            printf("partner %s using obsolete version %i; disconnecting\n", pfrom->addr.ToString().c_str(), pfrom->nVersion);
 +            pfrom->fDisconnect = true;
 +            return false;
 +        }
 +
          if (pfrom->nVersion == 10300)
              pfrom->nVersion = 300;
 -        if (pfrom->nVersion >= 106 && !vRecv.empty())
 +        if (!vRecv.empty())
              vRecv >> addrFrom >> nNonce;
 -        if (pfrom->nVersion >= 106 && !vRecv.empty())
 +        if (!vRecv.empty())
              vRecv >> pfrom->strSubVer;
 -        if (pfrom->nVersion >= 209 && !vRecv.empty())
 +        if (!vRecv.empty())
              vRecv >> pfrom->nStartingHeight;
  
 -        if (pfrom->nVersion == 0)
 -            return false;
 -
          // Disconnect if we connected to ourself
          if (nNonce == nLocalHostNonce && nNonce > 1)
          {
  
          pfrom->fClient = !(pfrom->nServices & NODE_NETWORK);
  
 -        AddTimeData(pfrom->addr.ip, nTime);
 +        AddTimeData(pfrom->addr, nTime);
  
          // Change version
 -        if (pfrom->nVersion >= 209)
 -            pfrom->PushMessage("verack");
 -        pfrom->vSend.SetVersion(min(pfrom->nVersion, VERSION));
 -        if (pfrom->nVersion < 209)
 -            pfrom->vRecv.SetVersion(min(pfrom->nVersion, VERSION));
 +        pfrom->PushMessage("verack");
 +        pfrom->vSend.SetVersion(min(pfrom->nVersion, PROTOCOL_VERSION));
  
          if (!pfrom->fInbound)
          {
              // Advertise our address
 -            if (addrLocalHost.IsRoutable() && !fUseProxy)
 +            if (!fNoListen && !fUseProxy && addrLocalHost.IsRoutable() &&
 +                !IsInitialBlockDownload())
              {
                  CAddress addr(addrLocalHost);
                  addr.nTime = GetAdjustedTime();
              }
  
              // Get recent addresses
 -            if (pfrom->nVersion >= 31402 || mapAddresses.size() < 1000)
 +            if (pfrom->nVersion >= 31402 || addrman.size() < 1000)
              {
                  pfrom->PushMessage("getaddr");
                  pfrom->fGetAddr = true;
              }
 +            addrman.Good(pfrom->addr);
 +        } else {
 +            if (((CNetAddr)pfrom->addr) == (CNetAddr)addrFrom)
 +            {
 +                addrman.Add(addrFrom, addrFrom);
 +                addrman.Good(addrFrom);
 +            }
          }
  
          // Ask the first connected node for block updates
  
      else if (strCommand == "verack")
      {
 -        pfrom->vRecv.SetVersion(min(pfrom->nVersion, VERSION));
 +        pfrom->vRecv.SetVersion(min(pfrom->nVersion, PROTOCOL_VERSION));
      }
  
  
          vRecv >> vAddr;
  
          // Don't want addr from older versions unless seeding
 -        if (pfrom->nVersion < 209)
 -            return true;
 -        if (pfrom->nVersion < 31402 && mapAddresses.size() > 1000)
 +        if (pfrom->nVersion < 31402 && addrman.size() > 1000)
              return true;
          if (vAddr.size() > 1000)
          {
          }
  
          // Store the new addresses
 -        CAddrDB addrDB;
 -        addrDB.TxnBegin();
          int64 nNow = GetAdjustedTime();
          int64 nSince = nNow - 10 * 60;
          BOOST_FOREACH(CAddress& addr, vAddr)
                  continue;
              if (addr.nTime <= 100000000 || addr.nTime > nNow + 10 * 60)
                  addr.nTime = nNow - 5 * 24 * 60 * 60;
 -            AddAddress(addr, 2 * 60 * 60, &addrDB);
              pfrom->AddAddressKnown(addr);
              if (addr.nTime > nSince && !pfrom->fGetAddr && vAddr.size() <= 10 && addr.IsRoutable())
              {
                      static uint256 hashSalt;
                      if (hashSalt == 0)
                          RAND_bytes((unsigned char*)&hashSalt, sizeof(hashSalt));
 -                    uint256 hashRand = hashSalt ^ (((int64)addr.ip)<<32) ^ ((GetTime()+addr.ip)/(24*60*60));
 +                    int64 hashAddr = addr.GetHash();
 +                    uint256 hashRand = hashSalt ^ (hashAddr<<32) ^ ((GetTime()+hashAddr)/(24*60*60));
                      hashRand = Hash(BEGIN(hashRand), END(hashRand));
                      multimap<uint256, CNode*> mapMix;
                      BOOST_FOREACH(CNode* pnode, vNodes)
                  }
              }
          }
 -        addrDB.TxnCommit();  // Save addresses (it's ok if this fails)
 +        addrman.Add(vAddr, pfrom->addr, 2 * 60 * 60);
          if (vAddr.size() < 1000)
              pfrom->fGetAddr = false;
      }
          // find last block in inv vector
          unsigned int nLastBlock = (unsigned int)(-1);
          for (unsigned int nInv = 0; nInv < vInv.size(); nInv++) {
-             if (vInv[vInv.size() - 1 - nInv].type == MSG_BLOCK)
+             if (vInv[vInv.size() - 1 - nInv].type == MSG_BLOCK) {
                  nLastBlock = vInv.size() - 1 - nInv;
+                 break;
+             }
          }
          CTxDB txdb("r");
 -        for (int nInv = 0; nInv < vInv.size(); nInv++)
 +        for (unsigned int nInv = 0; nInv < vInv.size(); nInv++)
          {
              const CInv &inv = vInv[nInv];
  
              if (fDebug)
                  printf("  got inventory: %s  %s\n", inv.ToString().c_str(), fAlreadyHave ? "have" : "new");
  
-             // Always request the last block in an inv bundle (even if we already have it), as it is the
-             // trigger for the other side to send further invs. If we are stuck on a (very long) side chain,
-             // this is necessary to connect earlier received orphan blocks to the chain again.
-             if (fAlreadyHave && nInv == nLastBlock) {
-                 // bypass mapAskFor, and send request directly; it must go through.
-                 std::vector<CInv> vGetData(1,inv);
-                 pfrom->PushMessage("getdata", vGetData);
-             }
              if (!fAlreadyHave)
                  pfrom->AskFor(inv);
-             else if (inv.type == MSG_BLOCK && mapOrphanBlocks.count(inv.hash))
+             else if (inv.type == MSG_BLOCK && mapOrphanBlocks.count(inv.hash)) {
                  pfrom->PushGetBlocks(pindexBest, GetOrphanRoot(mapOrphanBlocks[inv.hash]));
+             } else if (nInv == nLastBlock) {
+                 // In case we are on a very long side-chain, it is possible that we already have
+                 // the last block in an inv bundle sent in response to getblocks. Try to detect
+                 // this situation and push another getblocks to continue.
+                 std::vector<CInv> vGetData(1,inv);
+                 pfrom->PushGetBlocks(mapBlockIndex[inv.hash], uint256(0));
+                 if (fDebug)
+                     printf("force request: %s\n", inv.ToString().c_str());
+             }
  
              // Track requests for our stuff
              Inventory(inv.hash);
  
      else if (strCommand == "getaddr")
      {
 -        // Nodes rebroadcast an addr every 24 hours
          pfrom->vAddrToSend.clear();
 -        int64 nSince = GetAdjustedTime() - 3 * 60 * 60; // in the last 3 hours
 -        CRITICAL_BLOCK(cs_mapAddresses)
 -        {
 -            unsigned int nCount = 0;
 -            BOOST_FOREACH(const PAIRTYPE(vector<unsigned char>, CAddress)& item, mapAddresses)
 -            {
 -                const CAddress& addr = item.second;
 -                if (addr.nTime > nSince)
 -                    nCount++;
 -            }
 -            BOOST_FOREACH(const PAIRTYPE(vector<unsigned char>, CAddress)& item, mapAddresses)
 -            {
 -                const CAddress& addr = item.second;
 -                if (addr.nTime > nSince && GetRand(nCount) < 2500)
 -                    pfrom->PushAddress(addr);
 -            }
 -        }
 +        vector<CAddress> vAddr = addrman.GetAddr();
 +        BOOST_FOREACH(const CAddress &addr, vAddr)
 +            pfrom->PushAddress(addr);
      }
  
  
          /// we have a chance to check the order here
  
          // Keep giving the same key to the same ip until they use it
 -        if (!mapReuseKey.count(pfrom->addr.ip))
 -            pwalletMain->GetKeyFromPool(mapReuseKey[pfrom->addr.ip], true);
 +        if (!mapReuseKey.count(pfrom->addr))
 +            pwalletMain->GetKeyFromPool(mapReuseKey[pfrom->addr], true);
  
          // Send back approval of order and pubkey to use
          CScript scriptPubKey;
 -        scriptPubKey << mapReuseKey[pfrom->addr.ip] << OP_CHECKSIG;
 +        scriptPubKey << mapReuseKey[pfrom->addr] << OP_CHECKSIG;
          pfrom->PushMessage("reply", hashReply, (int)0, scriptPubKey);
      }
  
@@@ -2785,7 -2621,7 +2787,7 @@@ bool ProcessMessages(CNode* pfrom
          unsigned int nMessageSize = hdr.nMessageSize;
          if (nMessageSize > MAX_SIZE)
          {
-             printf("ProcessMessage(%s, %u bytes) : nMessageSize > MAX_SIZE\n", strCommand.c_str(), nMessageSize);
+             printf("ProcessMessages(%s, %u bytes) : nMessageSize > MAX_SIZE\n", strCommand.c_str(), nMessageSize);
              continue;
          }
          if (nMessageSize > vRecv.size())
          }
  
          // Checksum
 -        if (vRecv.GetVersion() >= 209)
 +        uint256 hash = Hash(vRecv.begin(), vRecv.begin() + nMessageSize);
 +        unsigned int nChecksum = 0;
 +        memcpy(&nChecksum, &hash, sizeof(nChecksum));
 +        if (nChecksum != hdr.nChecksum)
          {
-             printf("ProcessMessage(%s, %u bytes) : CHECKSUM ERROR nChecksum=%08x hdr.nChecksum=%08x\n",
 -            uint256 hash = Hash(vRecv.begin(), vRecv.begin() + nMessageSize);
 -            unsigned int nChecksum = 0;
 -            memcpy(&nChecksum, &hash, sizeof(nChecksum));
 -            if (nChecksum != hdr.nChecksum)
 -            {
 -                printf("ProcessMessages(%s, %u bytes) : CHECKSUM ERROR nChecksum=%08x hdr.nChecksum=%08x\n",
 -                       strCommand.c_str(), nMessageSize, nChecksum, hdr.nChecksum);
 -                continue;
 -            }
++            printf("ProcessMessages(%s, %u bytes) : CHECKSUM ERROR nChecksum=%08x hdr.nChecksum=%08x\n",
 +               strCommand.c_str(), nMessageSize, nChecksum, hdr.nChecksum);
 +            continue;
          }
  
          // Copy message to its own buffer
              if (strstr(e.what(), "end of data"))
              {
                  // Allow exceptions from underlength message on vRecv
-                 printf("ProcessMessage(%s, %u bytes) : Exception '%s' caught, normally caused by a message being shorter than its stated length\n", strCommand.c_str(), nMessageSize, e.what());
+                 printf("ProcessMessages(%s, %u bytes) : Exception '%s' caught, normally caused by a message being shorter than its stated length\n", strCommand.c_str(), nMessageSize, e.what());
              }
              else if (strstr(e.what(), "size too large"))
              {
                  // Allow exceptions from overlong size
-                 printf("ProcessMessage(%s, %u bytes) : Exception '%s' caught\n", strCommand.c_str(), nMessageSize, e.what());
+                 printf("ProcessMessages(%s, %u bytes) : Exception '%s' caught\n", strCommand.c_str(), nMessageSize, e.what());
              }
              else
              {
-                 PrintExceptionContinue(&e, "ProcessMessage()");
+                 PrintExceptionContinue(&e, "ProcessMessages()");
              }
          }
          catch (std::exception& e) {
-             PrintExceptionContinue(&e, "ProcessMessage()");
+             PrintExceptionContinue(&e, "ProcessMessages()");
          } catch (...) {
-             PrintExceptionContinue(NULL, "ProcessMessage()");
+             PrintExceptionContinue(NULL, "ProcessMessages()");
          }
  
          if (!fRet)
@@@ -2868,18 -2707,18 +2870,18 @@@ bool SendMessages(CNode* pto, bool fSen
  
          // Address refresh broadcast
          static int64 nLastRebroadcast;
 -        if (GetTime() - nLastRebroadcast > 24 * 60 * 60)
 +        if (!IsInitialBlockDownload() && (GetTime() - nLastRebroadcast > 24 * 60 * 60))
          {
 -            nLastRebroadcast = GetTime();
              CRITICAL_BLOCK(cs_vNodes)
              {
                  BOOST_FOREACH(CNode* pnode, vNodes)
                  {
                      // Periodically clear setAddrKnown to allow refresh broadcasts
 -                    pnode->setAddrKnown.clear();
 +                    if (nLastRebroadcast)
 +                        pnode->setAddrKnown.clear();
  
                      // Rebroadcast our address
 -                    if (addrLocalHost.IsRoutable() && !fUseProxy)
 +                    if (!fNoListen && !fUseProxy && addrLocalHost.IsRoutable())
                      {
                          CAddress addr(addrLocalHost);
                          addr.nTime = GetAdjustedTime();
                      }
                  }
              }
 +            nLastRebroadcast = GetTime();
          }
  
 -        // Clear out old addresses periodically so it's not too much work at once
 -        static int64 nLastClear;
 -        if (nLastClear == 0)
 -            nLastClear = GetTime();
 -        if (GetTime() - nLastClear > 10 * 60 && vNodes.size() >= 3)
 -        {
 -            nLastClear = GetTime();
 -            CRITICAL_BLOCK(cs_mapAddresses)
 -            {
 -                CAddrDB addrdb;
 -                int64 nSince = GetAdjustedTime() - 14 * 24 * 60 * 60;
 -                for (map<vector<unsigned char>, CAddress>::iterator mi = mapAddresses.begin();
 -                     mi != mapAddresses.end();)
 -                {
 -                    const CAddress& addr = (*mi).second;
 -                    if (addr.nTime < nSince)
 -                    {
 -                        if (mapAddresses.size() < 1000 || GetTime() > nLastClear + 20)
 -                            break;
 -                        addrdb.EraseAddress(addr);
 -                        mapAddresses.erase(mi++);
 -                    }
 -                    else
 -                        mi++;
 -                }
 -            }
 -        }
 -
 -
          //
          // Message: addr
          //
@@@ -3114,9 -2981,6 +3116,9 @@@ public
  };
  
  
 +uint64 nLastBlockTx = 0;
 +uint64 nLastBlockSize = 0;
 +
  CBlock* CreateNewBlock(CReserveKey& reservekey)
  {
      CBlockIndex* pindexPrev = pindexBest;
          // Collect transactions into block
          map<uint256, CTxIndex> mapTestPool;
          uint64 nBlockSize = 1000;
 +        uint64 nBlockTx = 0;
          int nBlockSigOps = 100;
          while (!mapPriority.empty())
          {
                  continue;
  
              // Legacy limits on sigOps:
 -            int nTxSigOps = tx.GetSigOpCount();
 +            int nTxSigOps = tx.GetLegacySigOpCount();
              if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS)
                  continue;
  
              // Transaction fee required depends on block size
              bool fAllowFree = (nBlockSize + nTxSize < 4000 || CTransaction::AllowFree(dPriority));
 -            int64 nMinFee = tx.GetMinFee(nBlockSize, fAllowFree);
 +            int64 nMinFee = tx.GetMinFee(nBlockSize, fAllowFree, GMF_BLOCK);
  
              // Connecting shouldn't fail due to dependency on other memory pool transactions
              // because we're already processing them in order of dependency
              map<uint256, CTxIndex> mapTestPoolTmp(mapTestPool);
 -            bool fInvalid;
              MapPrevTx mapInputs;
 +            bool fInvalid;
              if (!tx.FetchInputs(txdb, mapTestPoolTmp, false, true, mapInputs, fInvalid))
                  continue;
  
              // Added
              pblock->vtx.push_back(tx);
              nBlockSize += nTxSize;
 +            ++nBlockTx;
              nBlockSigOps += nTxSigOps;
              nFees += nTxFees;
  
                  }
              }
          }
 +
 +        nLastBlockTx = nBlockTx;
 +        nLastBlockSize = nBlockSize;
 +        printf("CreateNewBlock(): total size %lu\n", nBlockSize);
 +
      }
      pblock->vtx[0].vout[0].nValue = GetBlockValue(pindexPrev->nHeight+1, nFees);
  
@@@ -3299,9 -3156,7 +3301,9 @@@ void IncrementExtraNonce(CBlock* pblock
          hashPrevBlock = pblock->hashPrevBlock;
      }
      ++nExtraNonce;
 -    pblock->vtx[0].vin[0].scriptSig = CScript() << pblock->nTime << CBigNum(nExtraNonce);
 +    pblock->vtx[0].vin[0].scriptSig = (CScript() << pblock->nTime << CBigNum(nExtraNonce)) + COINBASE_FLAGS;
 +    assert(pblock->vtx[0].vin[0].scriptSig.size() <= 100);
 +
      pblock->hashMerkleRoot = pblock->BuildMerkleTree();
  }
  
@@@ -3390,10 -3245,6 +3392,10 @@@ bool CheckWork(CBlock* pblock, CWallet
  
  void static ThreadBitcoinMiner(void* parg);
  
 +static bool fGenerateBitcoins = false;
 +static bool fLimitProcessors = false;
 +static int nLimitProcessors = -1;
 +
  void static BitcoinMiner(CWallet *pwallet)
  {
      printf("BitcoinMiner started\n");
                          {
                              nLogTime = GetTime();
                              printf("%s ", DateTimeStrFormat("%x %H:%M", GetTime()).c_str());
 -                            printf("hashmeter %3d CPUs %6.0f khash/s\n", vnThreadsRunning[3], dHashesPerSec/1000.0);
 +                            printf("hashmeter %3d CPUs %6.0f khash/s\n", vnThreadsRunning[THREAD_MINER], dHashesPerSec/1000.0);
                          }
                      }
                  }
                  return;
              if (!fGenerateBitcoins)
                  return;
 -            if (fLimitProcessors && vnThreadsRunning[3] > nLimitProcessors)
 +            if (fLimitProcessors && vnThreadsRunning[THREAD_MINER] > nLimitProcessors)
                  return;
              if (vNodes.empty())
                  break;
@@@ -3548,34 -3399,34 +3550,34 @@@ void static ThreadBitcoinMiner(void* pa
      CWallet* pwallet = (CWallet*)parg;
      try
      {
 -        vnThreadsRunning[3]++;
 +        vnThreadsRunning[THREAD_MINER]++;
          BitcoinMiner(pwallet);
 -        vnThreadsRunning[3]--;
 +        vnThreadsRunning[THREAD_MINER]--;
      }
      catch (std::exception& e) {
 -        vnThreadsRunning[3]--;
 +        vnThreadsRunning[THREAD_MINER]--;
          PrintException(&e, "ThreadBitcoinMiner()");
      } catch (...) {
 -        vnThreadsRunning[3]--;
 +        vnThreadsRunning[THREAD_MINER]--;
          PrintException(NULL, "ThreadBitcoinMiner()");
      }
      UIThreadCall(boost::bind(CalledSetStatusBar, "", 0));
      nHPSTimerStart = 0;
 -    if (vnThreadsRunning[3] == 0)
 +    if (vnThreadsRunning[THREAD_MINER] == 0)
          dHashesPerSec = 0;
 -    printf("ThreadBitcoinMiner exiting, %d threads remaining\n", vnThreadsRunning[3]);
 +    printf("ThreadBitcoinMiner exiting, %d threads remaining\n", vnThreadsRunning[THREAD_MINER]);
  }
  
  
  void GenerateBitcoins(bool fGenerate, CWallet* pwallet)
  {
 -    if (fGenerateBitcoins != fGenerate)
 -    {
 -        fGenerateBitcoins = fGenerate;
 -        WriteSetting("fGenerateBitcoins", fGenerateBitcoins);
 -        MainFrameRepaint();
 -    }
 -    if (fGenerateBitcoins)
 +    fGenerateBitcoins = fGenerate;
 +    nLimitProcessors = GetArg("-genproclimit", -1);
 +    if (nLimitProcessors == 0)
 +        fGenerateBitcoins = false;
 +    fLimitProcessors = (nLimitProcessors != -1);
 +
 +    if (fGenerate)
      {
          int nProcessors = boost::thread::hardware_concurrency();
          printf("%d processors\n", nProcessors);
              nProcessors = 1;
          if (fLimitProcessors && nProcessors > nLimitProcessors)
              nProcessors = nLimitProcessors;
 -        int nAddThreads = nProcessors - vnThreadsRunning[3];
 +        int nAddThreads = nProcessors - vnThreadsRunning[THREAD_MINER];
          printf("Starting %d BitcoinMiner threads\n", nAddThreads);
          for (int i = 0; i < nAddThreads; i++)
          {
diff --combined src/main.h
@@@ -25,10 -25,7 +25,10 @@@ class CAddress
  class CInv;
  class CRequestTracker;
  class CNode;
 -class CBlockIndex;
 +
 +static const int CLIENT_VERSION = 60008;
 +static const bool VERSION_IS_BETA = true;
 +extern const std::string CLIENT_NAME;
  
  static const unsigned int MAX_BLOCK_SIZE = 1000000;
  static const unsigned int MAX_BLOCK_SIZE_GEN = MAX_BLOCK_SIZE/2;
@@@ -50,9 -47,6 +50,9 @@@ static const int fHaveUPnP = false
  #endif
  
  
 +extern CScript COINBASE_FLAGS;
 +
 +
  
  
  
@@@ -66,11 -60,7 +66,11 @@@ extern CBigNum bnBestChainWork
  extern CBigNum bnBestInvalidWork;
  extern uint256 hashBestChain;
  extern CBlockIndex* pindexBest;
 +extern uint64 nPooledTx;
  extern unsigned int nTransactionsUpdated;
 +extern uint64 nLastBlockTx;
 +extern uint64 nLastBlockSize;
 +extern const std::string strMessageMagic;
  extern double dHashesPerSec;
  extern int64 nHPSTimerStart;
  extern int64 nTimeBestReceived;
@@@ -78,7 -68,13 +78,7 @@@ extern CCriticalSection cs_setpwalletRe
  extern std::set<CWallet*> setpwalletRegistered;
  
  // Settings
 -extern int fGenerateBitcoins;
  extern int64 nTransactionFee;
 -extern int fLimitProcessors;
 -extern int nLimitProcessors;
 -extern int fMinimizeToTray;
 -extern int fMinimizeOnClose;
 -extern int fUseUPnP;
  
  
  
@@@ -122,7 -118,21 +122,7 @@@ std::string GetWarnings(std::string str
  
  bool GetWalletFile(CWallet* pwallet, std::string &strWalletFileOut);
  
 -template<typename T>
 -bool WriteSetting(const std::string& strKey, const T& value)
 -{
 -    bool fOk = false;
 -    BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
 -    {
 -        std::string strWalletFile;
 -        if (!GetWalletFile(pwallet, strWalletFile))
 -            continue;
 -        fOk |= CWalletDB(strWalletFile).WriteSetting(strKey, value);
 -    }
 -    return fOk;
 -}
 -
 -
 +/** Position on disk for a particular transaction. */
  class CDiskTxPos
  {
  public:
  
  
  
 -
 +/** An inpoint - a combination of a transaction and an index n into its vin */
  class CInPoint
  {
  public:
  
  
  
 -
 +/** An outpoint - a combination of a transaction hash and an index n into its vout */
  class COutPoint
  {
  public:
  
  
  
 -//
 -// 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.
 -//
 +/** 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:
  
      CTxIn()
      {
 -        nSequence = UINT_MAX;
 +        nSequence = std::numeric_limits<unsigned int>::max();
      }
  
 -    explicit CTxIn(COutPoint prevoutIn, CScript scriptSigIn=CScript(), unsigned int nSequenceIn=UINT_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=UINT_MAX)
 +    CTxIn(uint256 hashPrevTx, unsigned int nOut, CScript scriptSigIn=CScript(), unsigned int nSequenceIn=std::numeric_limits<unsigned int>::max())
      {
          prevout = COutPoint(hashPrevTx, nOut);
          scriptSig = scriptSigIn;
  
      bool IsFinal() const
      {
 -        return (nSequence == UINT_MAX);
 +        return (nSequence == std::numeric_limits<unsigned int>::max());
      }
  
      friend bool operator==(const CTxIn& a, const CTxIn& b)
              str += strprintf(", coinbase %s", HexStr(scriptSig).c_str());
          else
              str += strprintf(", scriptSig=%s", scriptSig.ToString().substr(0,24).c_str());
 -        if (nSequence != UINT_MAX)
 +        if (nSequence != std::numeric_limits<unsigned int>::max())
              str += strprintf(", nSequence=%u", nSequence);
          str += ")";
          return str;
  
  
  
 -//
 -// An output of a transaction.  It contains the public key that the next input
 -// must be able to sign with to claim it.
 -//
 +/** 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:
  };
  
  
 -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.
 -//
 +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:
                  return false;
  
          bool fNewer = false;
 -        unsigned int nLowest = UINT_MAX;
 +        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)
          return (vin.size() == 1 && vin[0].prevout.IsNull());
      }
  
 -    int GetSigOpCount() const
 -    {
 -        int n = 0;
 -        BOOST_FOREACH(const CTxIn& txin, vin)
 -            n += txin.scriptSig.GetSigOpCount();
 -        BOOST_FOREACH(const CTxOut& txout, vout)
 -            n += txout.scriptPubKey.GetSigOpCount();
 -        return n;
 -    }
 +    /** 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
 +    */
 +    int GetLegacySigOpCount() const;
  
      /** Count ECDSA signature operations in pay-to-script-hash inputs.
 -        This is a better measure of how expensive it is to process this transaction.
  
 -        @param[in] mapInputsMap of previous transactions that have outputs we're spending
 +        @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
 -    */
 +     */
      int GetP2SHSigOpCount(const MapPrevTx& mapInputs) const;
  
 -    bool IsStandard() const
 -    {
 -        BOOST_FOREACH(const CTxIn& txin, vin)
 -            if (!txin.scriptSig.IsPushOnly())
 -                return error("nonstandard txin: %s", txin.scriptSig.ToString().c_str());
 -        BOOST_FOREACH(const CTxOut& txout, vout)
 -            if (!::IsStandard(txout.scriptPubKey))
 -                return error("nonstandard txout: %s", txout.scriptPubKey.ToString().c_str());
 -        return true;
 -    }
 -
 +    /** Amount of bitcoins spent by this transaction.
 +        @return sum of all outputs (note: does not include fees)
 +     */
      int64 GetValueOut() const
      {
          int64 nValueOut = 0;
          Note that lightweight clients may not know anything besides the hash of previous transactions,
          so may not be able to calculate this.
  
 -        @param[in] mapInputsMap of previous transactions that have outputs we're spending
 -        @returnSum of value of all inputs (scriptSigs)
 +        @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)
          return dPriority > COIN * 144 / 250;
      }
  
 -    int64 GetMinFee(unsigned int nBlockSize=1, bool fAllowFree=true, bool fForRelay=false) const
 +    int64 GetMinFee(unsigned int nBlockSize=1, bool fAllowFree=true, enum GetMinFee_mode mode=GMF_BLOCK) const
      {
          // Base fee is either MIN_TX_FEE or MIN_RELAY_TX_FEE
 -        int64 nBaseFee = fForRelay ? MIN_RELAY_TX_FEE : MIN_TX_FEE;
 +        int64 nBaseFee = (mode == GMF_RELAY) ? MIN_RELAY_TX_FEE : MIN_TX_FEE;
  
          unsigned int nBytes = ::GetSerializeSize(*this, SER_NETWORK);
          unsigned int nNewBlockSize = nBlockSize + nBytes;
          // Read transaction
          if (fseek(filein, pos.nTxPos, SEEK_SET) != 0)
              return error("CTransaction::ReadFromDisk() : fseek failed");
-         filein >> *this;
+         try {
+             filein >> *this;
+         }
+         catch (std::exception &e) {
+             return error("%s() : deserialize or I/O error", __PRETTY_FUNCTION__);
+         }
  
          // Return file pointer
          if (pfileRet)
      /** Sanity check previous transactions, then, if all checks succeed,
          mark them as spent by this transaction.
  
 -        @param[in] inputsPrevious transactions (from FetchInputs)
 -        @param[out] mapTestPoolKeeps track of inputs that need to be updated on disk
 -        @param[in] posThisTxPosition of this transaction on disk
 +        @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
 +        @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(MapPrevTx inputs,
                         std::map<uint256, CTxIndex>& mapTestPool, const CDiskTxPos& posThisTx,
                         const CBlockIndex* pindexBlock, bool fBlock, bool fMiner, bool fStrictPayToScriptHash=true);
      bool CheckTransaction() const;
      bool AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs=true, bool* pfMissingInputs=NULL);
      bool AcceptToMemoryPool(bool fCheckInputs=true, bool* pfMissingInputs=NULL);
 +
  protected:
      const CTxOut& GetOutputFor(const CTxIn& input, const MapPrevTx& inputs) const;
      bool AddToMemoryPoolUnchecked();
@@@ -698,7 -709,9 +704,7 @@@ public
  
  
  
 -//
 -// A transaction with a merkle branch linking it to the block chain
 -//
 +/** A transaction with a merkle branch linking it to the block chain. */
  class CMerkleTx : public CTransaction
  {
  public:
  
  
      int SetMerkleBranch(const CBlock* pblock=NULL);
 -    int GetDepthInMainChain(int& nHeightRet) const;
 -    int GetDepthInMainChain() const { int nHeight; return GetDepthInMainChain(nHeight); }
 +    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);
  
  
  
 -//
 -// 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.
 -//
 +/**  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:
          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.
 -//
 +/** 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:
          return (int64)nTime;
      }
  
 -    int GetSigOpCount() const
 -    {
 -        int n = 0;
 -        BOOST_FOREACH(const CTransaction& tx, vtx)
 -            n += tx.GetSigOpCount();
 -        return n;
 -    }
 -
      void UpdateTime(const CBlockIndex* pindexPrev);
  
  
              filein.nType |= SER_BLOCKHEADERONLY;
  
          // Read block
-         filein >> *this;
+         try {
+             filein >> *this;
+         }
+         catch (std::exception &e) {
+             return error("%s() : deserialize or I/O error", __PRETTY_FUNCTION__);
+         }
  
          // Check the header
          if (!CheckProofOfWork(GetHash(), nBits))
      bool AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos);
      bool CheckBlock() const;
      bool AcceptBlock();
 +
 +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.
 -//
 +/** 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:
  
  
  
 -//
 -// Used to marshal pointers into hashes for db storage.
 -//
 +/** Used to marshal pointers into hashes for db storage. */
  class CDiskBlockIndex : public CBlockIndex
  {
  public:
  
  
  
 -//
 -// 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.
 -//
 +/** 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:
@@@ -1300,11 -1328,6 +1311,11 @@@ public
              Set((*mi).second);
      }
  
 +    CBlockLocator(const std::vector<uint256>& vHaveIn)
 +    {
 +        vHave = vHaveIn;
 +    }
 +
      IMPLEMENT_SERIALIZE
      (
          if (!(nType & SER_GETHASH))
  
  
  
 -//
 -// 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.
 -//
 +/** 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:
      }
  };
  
 +/** An alert is a combination of a serialized CUnsignedAlert and a signature. */
  class CAlert : public CUnsignedAlert
  {
  public:
  
      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(VERSION, ::pszSubVer);
 +        return AppliesTo(PROTOCOL_VERSION, FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, std::vector<std::string>()));
      }
  
      bool RelayTo(CNode* pnode) const