Merge branch '0.5.x' into 0.6.0.x
authorLuke Dashjr <luke-jr+git@utopios.org>
Sun, 6 May 2012 05:35:58 +0000 (05:35 +0000)
committerLuke Dashjr <luke-jr+git@utopios.org>
Sun, 6 May 2012 05:35:58 +0000 (05:35 +0000)
1  2 
src/db.cpp
src/main.cpp

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);
  }
  
@@@ -594,118 -579,19 +594,118 @@@ bool CTxDB::LoadBlockIndex(
      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 -767,21 +889,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");
  
                  //// debug print
                  //printf("LoadWallet  %s\n", wtx.GetHash().ToString().c_str());
-                 //printf(" %12I64d  %s  %s  %s\n",
+                 //printf(" %12"PRI64d"  %s  %s  %s\n",
                  //    wtx.vout[0].nValue,
                  //    DateTimeStrFormat("%x %H:%M:%S", wtx.GetBlockTime()).c_str(),
                  //    wtx.hashBlock.ToString().substr(0,20).c_str(),
                  {
                      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 -1010,7 +1114,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 -1084,14 +1188,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/main.cpp
@@@ -7,7 -7,6 +7,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>
  
@@@ -18,11 -17,6 +18,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;
  
@@@ -52,17 -46,22 +52,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
 +
  
  
  //////////////////////////////////////////////////////////////////////////////
@@@ -259,103 -258,6 +259,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)
@@@ -476,7 -378,7 +476,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
@@@ -608,11 -510,8 +608,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;
  }
@@@ -633,15 -531,10 +633,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;
  }
  
@@@ -1289,9 -1182,9 +1289,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;
  
@@@ -1459,39 -1352,6 +1459,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;
 +            }
 +            txdb.TxnBegin();
 +            // 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;
  }
  
@@@ -1669,12 -1502,8 +1669,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
@@@ -2187,7 -2016,7 +2187,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;
      }
          }
  
          CTxDB txdb("r");
 -        BOOST_FOREACH(const CInv& inv, vInv)
 +        for (unsigned int nInv = 0; nInv < vInv.size(); nInv++)
          {
 +            const CInv &inv = vInv[nInv];
 +
              if (fShutdown)
                  return true;
              pfrom->AddInventoryKnown(inv);
              if (fDebug)
                  printf("  got inventory: %s  %s\n", inv.ToString().c_str(), fAlreadyHave ? "have" : "new");
  
 -            if (!fAlreadyHave)
 +            // 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 || (inv.type == MSG_BLOCK && nInv==vInv.size()-1))
                  pfrom->AskFor(inv);
 -            else if (inv.type == MSG_BLOCK && mapOrphanBlocks.count(inv.hash))
 +            if (inv.type == MSG_BLOCK && mapOrphanBlocks.count(inv.hash))
                  pfrom->PushGetBlocks(pindexBest, GetOrphanRoot(mapOrphanBlocks[inv.hash]));
  
              // Track requests for our stuff
  
      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);
      }
  
@@@ -2777,14 -2609,17 +2777,14 @@@ bool ProcessMessages(CNode* pfrom
          }
  
          // 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)
          {
 -            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",
 -                       strCommand.c_str(), nMessageSize, nChecksum, hdr.nChecksum);
 -                continue;
 -            }
 +            printf("ProcessMessage(%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
@@@ -2849,18 -2684,18 +2849,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
          //
@@@ -3095,9 -2958,6 +3095,9 @@@ public
  };
  
  
 +uint64 nLastBlockTx = 0;
 +uint64 nLastBlockSize = 0;
 +
  CBlock* CreateNewBlock(CReserveKey& reservekey)
  {
      CBlockIndex* pindexPrev = pindexBest;
                  dPriority += (double)nValueIn * nConf;
  
                  if (fDebug && GetBoolArg("-printpriority"))
-                     printf("priority     nValueIn=%-12I64d nConf=%-5d dPriority=%-20.1f\n", nValueIn, nConf, dPriority);
+                     printf("priority     nValueIn=%-12"PRI64d" nConf=%-5d dPriority=%-20.1f\n", nValueIn, nConf, dPriority);
              }
  
              // Priority is sum(valuein * age) / txsize
          // 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);
  
@@@ -3280,9 -3133,7 +3280,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();
  }
  
@@@ -3371,10 -3222,6 +3371,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;
@@@ -3529,34 -3376,34 +3529,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++)
          {