Merge branch '0.4.x' into 0.5.0.x
authorLuke Dashjr <luke-jr+git@utopios.org>
Fri, 3 Feb 2012 01:17:41 +0000 (20:17 -0500)
committerLuke Dashjr <luke-jr+git@utopios.org>
Fri, 3 Feb 2012 01:17:41 +0000 (20:17 -0500)
Conflicts:
src/main.cpp

1  2 
src/db.cpp
src/init.cpp
src/key.h
src/main.cpp
src/main.h
src/net.cpp

diff --combined src/db.cpp
@@@ -629,6 -629,24 +629,6 @@@ bool CAddrDB::LoadAddresses(
  {
      CRITICAL_BLOCK(cs_mapAddresses)
      {
 -        // Load user provided addresses
 -        CAutoFile filein = fopen((GetDataDir() + "/addr.txt").c_str(), "rt");
 -        if (filein)
 -        {
 -            try
 -            {
 -                char psz[1000];
 -                while (fgets(psz, sizeof(psz), filein))
 -                {
 -                    CAddress addr(psz, false, NODE_NETWORK);
 -                    addr.nTime = 0; // so it won't relay unless successfully connected
 -                    if (addr.IsValid())
 -                        AddAddress(addr);
 -                }
 -            }
 -            catch (...) { }
 -        }
 -
          // Get cursor
          Dbc* pcursor = GetCursor();
          if (!pcursor)
@@@ -768,7 -786,7 +768,7 @@@ int CWalletDB::LoadWallet(CWallet* pwal
      bool fIsEncrypted = false;
  
      // Modify defaults
 -#ifndef __WXMSW__
 +#ifndef WIN32
      // Tray icon sometimes disappears on 9.10 karmic koala 64-bit, leaving no way to access the program
      fMinimizeToTray = false;
      fMinimizeOnClose = false;
                      CPrivKey pkey;
                      ssValue >> pkey;
                      key.SetPrivKey(pkey);
+                     if (key.GetPubKey() != vchPubKey || !key.IsValid())
+                         return DB_CORRUPT;
                  }
                  else
                  {
                      CWalletKey wkey;
                      ssValue >> wkey;
                      key.SetPrivKey(wkey.vchPrivKey);
+                     if (key.GetPubKey() != vchPubKey || !key.IsValid())
+                         return DB_CORRUPT;
                  }
                  if (!pwallet->LoadKey(key))
                      return DB_CORRUPT;
                  ssKey >> strKey;
  
                  // Options
 -#ifndef GUI
 +#ifndef QT_GUI
                  if (strKey == "fGenerateBitcoins")  ssValue >> fGenerateBitcoins;
  #endif
                  if (strKey == "nTransactionFee")    ssValue >> nTransactionFee;
diff --combined src/init.cpp
@@@ -4,7 -4,7 +4,7 @@@
  // file license.txt or http://www.opensource.org/licenses/mit-license.php.
  #include "headers.h"
  #include "db.h"
 -#include "rpc.h"
 +#include "bitcoinrpc.h"
  #include "net.h"
  #include "init.h"
  #include "strlcpy.h"
  #include <boost/filesystem/fstream.hpp>
  #include <boost/interprocess/sync/file_lock.hpp>
  
 +#if defined(BITCOIN_NEED_QT_PLUGINS) && !defined(_BITCOIN_QT_PLUGINS_INCLUDED)
 +#define _BITCOIN_QT_PLUGINS_INCLUDED
 +#define __INSURE__
 +#include <QtPlugin>
 +Q_IMPORT_PLUGIN(qcncodecs)
 +Q_IMPORT_PLUGIN(qjpcodecs)
 +Q_IMPORT_PLUGIN(qtwcodecs)
 +Q_IMPORT_PLUGIN(qkrcodecs)
 +#endif
 +
  using namespace std;
  using namespace boost;
  
@@@ -34,7 -24,7 +34,7 @@@ CWallet* pwalletMain
  
  void ExitTimeout(void* parg)
  {
 -#ifdef __WXMSW__
 +#ifdef WIN32
      Sleep(5000);
      ExitProcess(0);
  #endif
@@@ -90,7 -80,7 +90,7 @@@ void HandleSIGTERM(int
  //
  // Start
  //
 -#ifndef GUI
 +#if !defined(QT_GUI)
  int main(int argc, char* argv[])
  {
      bool fRet = false;
@@@ -131,10 -121,10 +131,10 @@@ bool AppInit2(int argc, char* argv[]
      // Disable confusing "helpful" text message on abort, ctrl-c
      _set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
  #endif
 -#ifndef __WXMSW__
 +#ifndef WIN32
      umask(077);
  #endif
 -#ifndef __WXMSW__
 +#ifndef WIN32
      // Clean shutdown on SIGTERM
      struct sigaction sa;
      sa.sa_handler = HandleSIGTERM;
              "  -noirc           \t  "   + _("Don't find peers using internet relay chat\n") +
              "  -nolisten        \t  "   + _("Don't accept connections from outside\n") +
              "  -nodnsseed       \t  "   + _("Don't bootstrap list of peers using DNS\n") +
 +            "  -banscore=<n>    \t  "   + _("Threshold for disconnecting misbehaving peers (default: 100)\n") +
 +            "  -bantime=<n>     \t  "   + _("Number of seconds to keep misbehaving peers from reconnecting (default: 86400)\n") +
              "  -maxreceivebuffer=<n>\t  " + _("Maximum per-connection receive buffer, <n>*1000 bytes (default: 10000)\n") +
              "  -maxsendbuffer=<n>\t  "   + _("Maximum per-connection send buffer, <n>*1000 bytes (default: 10000)\n") +
  #ifdef USE_UPNP
  #ifdef GUI
              "  -server          \t\t  " + _("Accept command line and JSON-RPC commands\n") +
  #endif
 -#ifndef __WXMSW__
 +#ifndef WIN32
              "  -daemon          \t\t  " + _("Run in the background as a daemon and accept commands\n") +
  #endif
              "  -testnet         \t\t  " + _("Use the test network\n") +
          strUsage += string() +
              "  -?               \t\t  " + _("This help message\n");
  
          // Remove tabs
          strUsage.erase(std::remove(strUsage.begin(), strUsage.end(), '\t'), strUsage.end());
          fprintf(stderr, "%s", strUsage.c_str());
 -#endif
          return false;
      }
  
      fTestNet = GetBoolArg("-testnet");
      fDebug = GetBoolArg("-debug");
  
 -#ifndef __WXMSW__
 +#ifndef WIN32
      fDaemon = GetBoolArg("-daemon");
  #else
      fDaemon = false;
          fServer = GetBoolArg("-server");
  
      /* force fServer when running without GUI */
 -#ifndef GUI
 +#if !defined(QT_GUI)
      fServer = true;
  #endif
 -
      fPrintToConsole = GetBoolArg("-printtoconsole");
      fPrintToDebugger = GetBoolArg("-printtodebugger");
      fLogTimestamps = GetBoolArg("-logtimestamps");
  
 +#ifndef QT_GUI
      for (int i = 1; i < argc; i++)
          if (!IsSwitchChar(argv[i][0]))
              fCommandLine = true;
          int ret = CommandLineRPC(argc, argv);
          exit(ret);
      }
 +#endif
  
 -#ifndef __WXMSW__
 +#ifndef WIN32
      if (fDaemon)
      {
          // Daemonize
          ShrinkDebugFile();
      printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
      printf("Bitcoin version %s\n", FormatFullVersion().c_str());
 -#ifdef GUI
 -    printf("OS version %s\n", ((string)wxGetOsDescription()).c_str());
 -    printf("System default language is %d %s\n", g_locale.GetSystemLanguage(), ((string)g_locale.GetSysName()).c_str());
 -    printf("Language file %s (%s)\n", (string("locale/") + (string)g_locale.GetCanonicalName() + "/LC_MESSAGES/bitcoin.mo").c_str(), ((string)g_locale.GetLocale()).c_str());
 -#endif
      printf("Default data directory %s\n", GetDefaultDataDir().c_str());
  
      if (GetBoolArg("-loadblockindextest"))
          return false;
      }
  
 -    //
 -    // Limit to single instance per user
 -    // Required to protect the database files if we're going to keep deleting log.*
 -    //
 -#if defined(__WXMSW__) && defined(GUI)
 -    // wxSingleInstanceChecker doesn't work on Linux
 -    wxString strMutexName = wxString("bitcoin_running.") + getenv("HOMEPATH");
 -    for (int i = 0; i < strMutexName.size(); i++)
 -        if (!isalnum(strMutexName[i]))
 -            strMutexName[i] = '.';
 -    wxSingleInstanceChecker* psingleinstancechecker = new wxSingleInstanceChecker(strMutexName);
 -    if (psingleinstancechecker->IsAnotherRunning())
 -    {
 -        printf("Existing instance found\n");
 -        unsigned int nStart = GetTime();
 -        loop
 -        {
 -            // Show the previous instance and exit
 -            HWND hwndPrev = FindWindowA("wxWindowClassNR", "Bitcoin");
 -            if (hwndPrev)
 -            {
 -                if (IsIconic(hwndPrev))
 -                    ShowWindow(hwndPrev, SW_RESTORE);
 -                SetForegroundWindow(hwndPrev);
 -                return false;
 -            }
 -
 -            if (GetTime() > nStart + 60)
 -                return false;
 -
 -            // Resume this instance if the other exits
 -            delete psingleinstancechecker;
 -            Sleep(1000);
 -            psingleinstancechecker = new wxSingleInstanceChecker(strMutexName);
 -            if (!psingleinstancechecker->IsAnotherRunning())
 -                break;
 -        }
 -    }
 -#endif
 -
      // Make sure only a single bitcoin process is using the data directory.
      string strLockFile = GetDataDir() + "/.lock";
      FILE* file = fopen(strLockFile.c_str(), "a"); // empty lock file; created if it doesn't exist.
      strErrors = "";
      int64 nStart;
  
 +    InitMessage(_("Loading addresses..."));
      printf("Loading addresses...\n");
      nStart = GetTimeMillis();
      if (!LoadAddresses())
          strErrors += _("Error loading addr.dat      \n");
      printf(" addresses   %15"PRI64d"ms\n", GetTimeMillis() - nStart);
  
 +    InitMessage(_("Loading block index..."));
      printf("Loading block index...\n");
      nStart = GetTimeMillis();
      if (!LoadBlockIndex())
          strErrors += _("Error loading blkindex.dat      \n");
      printf(" block index %15"PRI64d"ms\n", GetTimeMillis() - nStart);
  
 +    InitMessage(_("Loading wallet..."));
      printf("Loading wallet...\n");
      nStart = GetTimeMillis();
      bool fFirstRun;
      }
      if (pindexBest != pindexRescan)
      {
 +        InitMessage(_("Rescanning..."));
          printf("Rescanning last %i blocks (from block %i)...\n", pindexBest->nHeight - pindexRescan->nHeight, pindexRescan->nHeight);
          nStart = GetTimeMillis();
          pwalletMain->ScanForWalletTransactions(pindexRescan, true);
          printf(" rescan      %15"PRI64d"ms\n", GetTimeMillis() - nStart);
      }
  
 +    InitMessage(_("Done loading"));
      printf("Done loading\n");
  
          //// debug print
      fAllowDNS = GetBoolArg("-dns");
      fNoListen = GetBoolArg("-nolisten");
  
-     if (fHaveUPnP)
-     {
- #if USE_UPNP
-     if (GetBoolArg("-noupnp"))
-         fUseUPnP = false;
- #else
-     if (GetBoolArg("-upnp"))
-         fUseUPnP = true;
- #endif
-     }
+     // Command-line args override in-wallet settings:
+     if (mapArgs.count("-upnp"))
+         fUseUPnP = GetBoolArg("-upnp");
+     else if (mapArgs.count("-noupnp"))
+         fUseUPnP = !GetBoolArg("-noupnp");
  
      if (!fNoListen)
      {
      }
  
      //
 -    // Create the main window and start the node
 +    // Start the node
      //
 -#ifdef GUI
 -    if (!fDaemon)
 -        CreateMainWindow();
 -#endif
 -
      if (!CheckDiskSpace())
          return false;
  
      RandAddSeedPerfmon();
  
      if (!CreateThread(StartNode, NULL))
 -        wxMessageBox("Error: CreateThread(StartNode) failed", "Bitcoin");
 +        wxMessageBox(_("Error: CreateThread(StartNode) failed"), "Bitcoin");
  
      if (fServer)
          CreateThread(ThreadRPCServer, NULL);
  
 -#if defined(__WXMSW__) && defined(GUI)
 -    if (fFirstRun)
 -        SetStartOnSystemStartup(true);
 -#endif
 -
 -#ifndef GUI
 +#if !defined(QT_GUI)
      while (1)
          Sleep(5000);
  #endif
diff --combined src/key.h
+++ b/src/key.h
@@@ -39,7 -39,6 +39,7 @@@
  // see www.keylength.com
  // script supports up to 75 for single byte push
  
 +// Generate a private key from just the secret parameter
  int static inline EC_KEY_regenerate_key(EC_KEY *eckey, BIGNUM *priv_key)
  {
      int ok = 0;
@@@ -76,79 -75,6 +76,79 @@@ err
      return(ok);
  }
  
 +// Perform ECDSA key recovery (see SEC1 4.1.6) for curves over (mod p)-fields
 +// recid selects which key is recovered
 +// if check is nonzero, additional checks are performed
 +int static inline ECDSA_SIG_recover_key_GFp(EC_KEY *eckey, ECDSA_SIG *ecsig, const unsigned char *msg, int msglen, int recid, int check)
 +{
 +    if (!eckey) return 0;
 +
 +    int ret = 0;
 +    BN_CTX *ctx = NULL;
 +
 +    BIGNUM *x = NULL;
 +    BIGNUM *e = NULL;
 +    BIGNUM *order = NULL;
 +    BIGNUM *sor = NULL;
 +    BIGNUM *eor = NULL;
 +    BIGNUM *field = NULL;
 +    EC_POINT *R = NULL;
 +    EC_POINT *O = NULL;
 +    EC_POINT *Q = NULL;
 +    BIGNUM *rr = NULL;
 +    BIGNUM *zero = NULL;
 +    int n = 0;
 +    int i = recid / 2;
 +
 +    const EC_GROUP *group = EC_KEY_get0_group(eckey);
 +    if ((ctx = BN_CTX_new()) == NULL) { ret = -1; goto err; }
 +    BN_CTX_start(ctx);
 +    order = BN_CTX_get(ctx);
 +    if (!EC_GROUP_get_order(group, order, ctx)) { ret = -2; goto err; }
 +    x = BN_CTX_get(ctx);
 +    if (!BN_copy(x, order)) { ret=-1; goto err; }
 +    if (!BN_mul_word(x, i)) { ret=-1; goto err; }
 +    if (!BN_add(x, x, ecsig->r)) { ret=-1; goto err; }
 +    field = BN_CTX_get(ctx);
 +    if (!EC_GROUP_get_curve_GFp(group, field, NULL, NULL, ctx)) { ret=-2; goto err; }
 +    if (BN_cmp(x, field) >= 0) { ret=0; goto err; }
 +    if ((R = EC_POINT_new(group)) == NULL) { ret = -2; goto err; }
 +    if (!EC_POINT_set_compressed_coordinates_GFp(group, R, x, recid % 2, ctx)) { ret=0; goto err; }
 +    if (check)
 +    {
 +        if ((O = EC_POINT_new(group)) == NULL) { ret = -2; goto err; }
 +        if (!EC_POINT_mul(group, O, NULL, R, order, ctx)) { ret=-2; goto err; }
 +        if (!EC_POINT_is_at_infinity(group, O)) { ret = 0; goto err; }
 +    }
 +    if ((Q = EC_POINT_new(group)) == NULL) { ret = -2; goto err; }
 +    n = EC_GROUP_get_degree(group);
 +    e = BN_CTX_get(ctx);
 +    if (!BN_bin2bn(msg, msglen, e)) { ret=-1; goto err; }
 +    if (8*msglen > n) BN_rshift(e, e, 8-(n & 7));
 +    zero = BN_CTX_get(ctx);
 +    if (!BN_zero(zero)) { ret=-1; goto err; }
 +    if (!BN_mod_sub(e, zero, e, order, ctx)) { ret=-1; goto err; }
 +    rr = BN_CTX_get(ctx);
 +    if (!BN_mod_inverse(rr, ecsig->r, order, ctx)) { ret=-1; goto err; }
 +    sor = BN_CTX_get(ctx);
 +    if (!BN_mod_mul(sor, ecsig->s, rr, order, ctx)) { ret=-1; goto err; }
 +    eor = BN_CTX_get(ctx);
 +    if (!BN_mod_mul(eor, e, rr, order, ctx)) { ret=-1; goto err; }
 +    if (!EC_POINT_mul(group, Q, eor, R, sor, ctx)) { ret=-2; goto err; }
 +    if (!EC_KEY_set_public_key(eckey, Q)) { ret=-2; goto err; }
 +
 +    ret = 1;
 +
 +err:
 +    if (ctx) {
 +        BN_CTX_end(ctx);
 +        BN_CTX_free(ctx);
 +    }
 +    if (R != NULL) EC_POINT_free(R);
 +    if (O != NULL) EC_POINT_free(O);
 +    if (Q != NULL) EC_POINT_free(Q);
 +    return ret;
 +}
  
  class key_error : public std::runtime_error
  {
@@@ -158,9 -84,7 +158,9 @@@ public
  
  
  // secure_allocator is defined in serialize.h
 +// CPrivKey is a serialized private key, with all parameters included (279 bytes)
  typedef std::vector<unsigned char, secure_allocator<unsigned char> > CPrivKey;
 +// CSecret is a serialization of just the secret parameter (32 bytes)
  typedef std::vector<unsigned char, secure_allocator<unsigned char> > CSecret;
  
  class CKey
@@@ -297,72 -221,6 +297,72 @@@ public
          return true;
      }
  
 +    // create a compact signature (65 bytes), which allows reconstructing the used public key
 +    // The format is one header byte, followed by two times 32 bytes for the serialized r and s values.
 +    // The header byte: 0x1B = first key with even y, 0x1C = first key with odd y,
 +    //                  0x1D = second key with even y, 0x1E = second key with odd y
 +    bool SignCompact(uint256 hash, std::vector<unsigned char>& vchSig)
 +    {
 +        bool fOk = false;
 +        ECDSA_SIG *sig = ECDSA_do_sign((unsigned char*)&hash, sizeof(hash), pkey);
 +        if (sig==NULL)
 +            return false;
 +        vchSig.clear();
 +        vchSig.resize(65,0);
 +        int nBitsR = BN_num_bits(sig->r);
 +        int nBitsS = BN_num_bits(sig->s);
 +        if (nBitsR <= 256 && nBitsS <= 256)
 +        {
 +            int nRecId = -1;
 +            for (int i=0; i<4; i++)
 +            {
 +                CKey keyRec;
 +                keyRec.fSet = true;
 +                if (ECDSA_SIG_recover_key_GFp(keyRec.pkey, sig, (unsigned char*)&hash, sizeof(hash), i, 1) == 1)
 +                    if (keyRec.GetPubKey() == this->GetPubKey())
 +                    {
 +                        nRecId = i;
 +                        break;
 +                    }
 +            }
 +
 +            if (nRecId == -1)
 +                throw key_error("CKey::SignCompact() : unable to construct recoverable key");
 +
 +            vchSig[0] = nRecId+27;
 +            BN_bn2bin(sig->r,&vchSig[33-(nBitsR+7)/8]);
 +            BN_bn2bin(sig->s,&vchSig[65-(nBitsS+7)/8]);
 +            fOk = true;
 +        }
 +        ECDSA_SIG_free(sig);
 +        return fOk;
 +    }
 +
 +    // reconstruct public key from a compact signature
 +    // This is only slightly more CPU intensive than just verifying it.
 +    // If this function succeeds, the recovered public key is guaranteed to be valid
 +    // (the signature is a valid signature of the given data for that key)
 +    bool SetCompactSignature(uint256 hash, const std::vector<unsigned char>& vchSig)
 +    {
 +        if (vchSig.size() != 65)
 +            return false;
 +        if (vchSig[0]<27 || vchSig[0]>=31)
 +            return false;
 +        ECDSA_SIG *sig = ECDSA_SIG_new();
 +        BN_bin2bn(&vchSig[1],32,sig->r);
 +        BN_bin2bn(&vchSig[33],32,sig->s);
 +
 +        EC_KEY_free(pkey);
 +        pkey = EC_KEY_new_by_curve_name(NID_secp256k1);
 +        if (ECDSA_SIG_recover_key_GFp(pkey, sig, (unsigned char*)&hash, sizeof(hash), vchSig[0] - 27, 0) == 1)
 +        {
 +            fSet = true;
 +            ECDSA_SIG_free(sig);
 +            return true;
 +        }
 +        return false;
 +    }
 +
      bool Verify(uint256 hash, const std::vector<unsigned char>& vchSig)
      {
          // -1 = error, 0 = bad sig, 1 = good
          return true;
      }
  
 +    // Verify a compact signature
 +    bool VerifyCompact(uint256 hash, const std::vector<unsigned char>& vchSig)
 +    {
 +        CKey key;
 +        if (!key.SetCompactSignature(hash, vchSig))
 +            return false;
 +        if (GetPubKey() != key.GetPubKey())
 +            return false;
 +        return true;
 +    }
 +
 +    // Get the address corresponding to this key
      CBitcoinAddress GetAddress() const
      {
          return CBitcoinAddress(GetPubKey());
      }
+     bool IsValid()
+     {
+         if (!fSet)
+             return false;
+         CSecret secret = GetSecret();
+         CKey key2;
+         key2.SetSecret(secret);
+         return GetPubKey() == key2.GetPubKey();
+     }
  };
  
  #endif
diff --combined src/main.cpp
@@@ -7,6 -7,7 +7,6 @@@
  #include "db.h"
  #include "net.h"
  #include "init.h"
 -#include "cryptopp/sha.h"
  #include <boost/filesystem.hpp>
  #include <boost/filesystem/fstream.hpp>
  
@@@ -30,6 -31,7 +30,6 @@@ map<COutPoint, CInPoint> mapNextTx
  map<uint256, CBlockIndex*> mapBlockIndex;
  uint256 hashGenesisBlock("0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f");
  static CBigNum bnProofOfWorkLimit(~uint256(0) >> 32);
 -const int nInitialBlockThreshold = 120; // Regard blocks up until N-threshold as "initial download"
  CBlockIndex* pindexGenesisBlock = NULL;
  int nBestHeight = -1;
  CBigNum bnBestChainWork = 0;
@@@ -38,8 -40,6 +38,8 @@@ uint256 hashBestChain = 0
  CBlockIndex* pindexBest = NULL;
  int64 nTimeBestReceived = 0;
  
 +CMedianFilter<int> cPeerBlockCounts(5, 0); // Amount of blocks that other nodes claim to have
 +
  map<uint256, CBlock*> mapOrphanBlocks;
  multimap<uint256, CBlock*> mapOrphanBlocksByPrev;
  
@@@ -64,14 -64,16 +64,14 @@@ int fUseUPnP = false
  #endif
  
  
 -
 -
 -
 -
 -
  //////////////////////////////////////////////////////////////////////////////
  //
  // dispatching functions
  //
  
 +// These functions dispatch to one or all registered wallets
 +
 +
  void RegisterWallet(CWallet* pwalletIn)
  {
      CRITICAL_BLOCK(cs_setpwalletRegistered)
@@@ -88,7 -90,6 +88,7 @@@ void UnregisterWallet(CWallet* pwalletI
      }
  }
  
 +// check whether the passed transaction is from us
  bool static IsFromMe(CTransaction& tx)
  {
      BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
@@@ -97,7 -98,6 +97,7 @@@
      return false;
  }
  
 +// get the wallet transaction with the given hash (if it exists)
  bool static GetTransaction(const uint256& hashTx, CWalletTx& wtx)
  {
      BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
      return false;
  }
  
 +// erases transaction with the given hash from all wallets
  void static EraseFromWallets(uint256 hash)
  {
      BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
          pwallet->EraseFromWallet(hash);
  }
  
 +// make sure all wallets know about the given transaction, in the given block
  void static SyncWithWallets(const CTransaction& tx, const CBlock* pblock = NULL, bool fUpdate = false)
  {
      BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
          pwallet->AddToWalletIfInvolvingMe(tx, pblock, fUpdate);
  }
  
 +// notify wallets about a new best chain
  void static SetBestChain(const CBlockLocator& loc)
  {
      BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
          pwallet->SetBestChain(loc);
  }
  
 +// notify wallets about an updated transaction
  void static UpdatedTransaction(const uint256& hashTx)
  {
      BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
          pwallet->UpdatedTransaction(hashTx);
  }
  
 +// dump all wallets
  void static PrintWallets(const CBlock& block)
  {
      BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
          pwallet->PrintWallet(block);
  }
  
 +// notify wallets about an incoming inventory (for request counts)
  void static Inventory(const uint256& hash)
  {
      BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
          pwallet->Inventory(hash);
  }
  
 +// ask wallets to resend their transactions
  void static ResendWalletTransactions()
  {
      BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
@@@ -303,24 -296,24 +303,24 @@@ bool CTransaction::CheckTransaction() c
  {
      // Basic checks that don't depend on any context
      if (vin.empty())
 -        return error("CTransaction::CheckTransaction() : vin empty");
 +        return DoS(10, error("CTransaction::CheckTransaction() : vin empty"));
      if (vout.empty())
 -        return error("CTransaction::CheckTransaction() : vout empty");
 +        return DoS(10, error("CTransaction::CheckTransaction() : vout empty"));
      // Size limits
      if (::GetSerializeSize(*this, SER_NETWORK) > MAX_BLOCK_SIZE)
 -        return error("CTransaction::CheckTransaction() : size limits failed");
 +        return DoS(100, error("CTransaction::CheckTransaction() : size limits failed"));
  
      // Check for negative or overflow output values
      int64 nValueOut = 0;
      BOOST_FOREACH(const CTxOut& txout, vout)
      {
          if (txout.nValue < 0)
 -            return error("CTransaction::CheckTransaction() : txout.nValue negative");
 +            return DoS(100, error("CTransaction::CheckTransaction() : txout.nValue negative"));
          if (txout.nValue > MAX_MONEY)
 -            return error("CTransaction::CheckTransaction() : txout.nValue too high");
 +            return DoS(100, error("CTransaction::CheckTransaction() : txout.nValue too high"));
          nValueOut += txout.nValue;
          if (!MoneyRange(nValueOut))
 -            return error("CTransaction::CheckTransaction() : txout total out of range");
 +            return DoS(100, error("CTransaction::CheckTransaction() : txout total out of range"));
      }
  
      // Check for duplicate inputs
      if (IsCoinBase())
      {
          if (vin[0].scriptSig.size() < 2 || vin[0].scriptSig.size() > 100)
 -            return error("CTransaction::CheckTransaction() : coinbase script size");
 +            return DoS(100, error("CTransaction::CheckTransaction() : coinbase script size"));
      }
      else
      {
          BOOST_FOREACH(const CTxIn& txin, vin)
              if (txin.prevout.IsNull())
 -                return error("CTransaction::CheckTransaction() : prevout is null");
 +                return DoS(10, error("CTransaction::CheckTransaction() : prevout is null"));
      }
  
      return true;
@@@ -357,7 -350,7 +357,7 @@@ bool CTransaction::AcceptToMemoryPool(C
  
      // Coinbase is only valid in a block, not as a loose transaction
      if (IsCoinBase())
 -        return error("AcceptToMemoryPool() : coinbase as individual tx");
 +        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)
      // 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() : nonstandard transaction");
 +        return error("AcceptToMemoryPool() : transaction with out-of-bounds SigOpCount");
  
      // Rather not work on nonstandard transactions (unless -testnet)
      if (!fTestNet && !IsStandard())
          // Check against previous transactions
          map<uint256, CTxIndex> mapUnused;
          int64 nFees = 0;
-         if (!ConnectInputs(txdb, mapUnused, CDiskTxPos(1,1,1), pindexBest, nFees, false, false))
+         bool fInvalid = false;
+         if (!ConnectInputs(txdb, mapUnused, CDiskTxPos(1,1,1), pindexBest, nFees, false, false, 0, fInvalid))
          {
-             if (pfMissingInputs)
-                 *pfMissingInputs = true;
+             if (fInvalid)
+                 return error("AcceptToMemoryPool() : FetchInputs found invalid tx %s", hash.ToString().substr(0,10).c_str());
              return error("AcceptToMemoryPool() : ConnectInputs failed %s", hash.ToString().substr(0,10).c_str());
          }
  
@@@ -668,6 -662,11 +669,11 @@@ static const int64 nInterval = nTargetT
  //
  unsigned int ComputeMinWork(unsigned int nBase, int64 nTime)
  {
+     // Testnet has min-difficulty blocks
+     // after nTargetSpacing*2 time between blocks:
+     if (fTestNet && nTime > nTargetSpacing*2)
+         return bnProofOfWorkLimit.GetCompact();
      CBigNum bnResult;
      bnResult.SetCompact(nBase);
      while (nTime > 0 && bnResult < bnProofOfWorkLimit)
      return bnResult.GetCompact();
  }
  
- unsigned int static GetNextWorkRequired(const CBlockIndex* pindexLast)
+ unsigned int static GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlock *pblock)
  {
+     unsigned int nProofOfWorkLimit = bnProofOfWorkLimit.GetCompact();
  
      // Genesis block
      if (pindexLast == NULL)
-         return bnProofOfWorkLimit.GetCompact();
+         return nProofOfWorkLimit;
  
      // Only change once per interval
      if ((pindexLast->nHeight+1) % nInterval != 0)
+     {
+         // Special rules for testnet after 15 Feb 2012:
+         if (fTestNet && pblock->nTime > 1329264000)
+         {
+             // If the new block's timestamp is more than 2* 10 minutes
+             // then allow mining of a min-difficulty block.
+             if (pblock->nTime - pindexLast->nTime > nTargetSpacing*2)
+                 return nProofOfWorkLimit;
+             else
+             {
+                 // Return the last non-special-min-difficulty-rules-block
+                 const CBlockIndex* pindex = pindexLast;
+                 while (pindex->pprev && pindex->nHeight % nInterval != 0 && pindex->nBits == nProofOfWorkLimit)
+                     pindex = pindex->pprev;
+                 return pindex->nBits;
+             }
+         }
          return pindexLast->nBits;
+     }
  
      // Go back by what we want to be 14 days worth of blocks
      const CBlockIndex* pindexFirst = pindexLast;
@@@ -741,15 -760,9 +767,15 @@@ bool CheckProofOfWork(uint256 hash, uns
      return true;
  }
  
 +// Return maximum amount of blocks that other nodes claim to have
 +int GetNumBlocksOfPeers()
 +{
 +    return std::max(cPeerBlockCounts.median(), Checkpoints::GetTotalBlocksEstimate());
 +}
 +
  bool IsInitialBlockDownload()
  {
 -    if (pindexBest == NULL || nBestHeight < (Checkpoints::GetTotalBlocksEstimate()-nInitialBlockThreshold))
 +    if (pindexBest == NULL || nBestHeight < Checkpoints::GetTotalBlocksEstimate())
          return true;
      static int64 nLastUpdate;
      static CBlockIndex* pindexLastBest;
@@@ -821,12 -834,16 +847,19 @@@ bool CTransaction::DisconnectInputs(CTx
  
  
  bool CTransaction::ConnectInputs(CTxDB& txdb, map<uint256, CTxIndex>& mapTestPool, CDiskTxPos posThisTx,
-                                  CBlockIndex* pindexBlock, int64& nFees, bool fBlock, bool fMiner, int64 nMinFee)
+                                  CBlockIndex* pindexBlock, int64& nFees, bool fBlock, bool fMiner, int64 nMinFee,
+                                  bool& fInvalid)
  {
+     // FetchInputs can return false either because we just haven't seen some inputs
+     // (in which case the transaction should be stored as an orphan)
+     // or because the transaction is malformed (in which case the transaction should
+     // be dropped).  If tx is definitely invalid, fInvalid will be set to true.
+     fInvalid = false;
      // Take over previous transactions' spent pointers
 +    // fBlock is true when this is called from AcceptBlock when a new best-block is added to the blockchain
 +    // fMiner is true when called from the internal bitcoin miner
 +    // ... both are false when called from CTransaction::AcceptToMemoryPool
      if (!IsCoinBase())
      {
          int64 nValueIn = 0;
              }
  
              if (prevout.n >= txPrev.vout.size() || prevout.n >= txindex.vSpent.size())
+             {
+                 // Revisit this if/when transaction replacement is implemented and allows
+                 // adding inputs:
+                 fInvalid = true;
 -                return error("ConnectInputs() : %s prevout.n out of range %d %d %d prev tx %s\n%s", GetHash().ToString().substr(0,10).c_str(), prevout.n, txPrev.vout.size(), txindex.vSpent.size(), prevout.hash.ToString().substr(0,10).c_str(), txPrev.ToString().c_str());
 +                return DoS(100, error("ConnectInputs() : %s prevout.n out of range %d %d %d prev tx %s\n%s", GetHash().ToString().substr(0,10).c_str(), prevout.n, txPrev.vout.size(), txindex.vSpent.size(), prevout.hash.ToString().substr(0,10).c_str(), txPrev.ToString().c_str()));
+             }
  
              // If prev is coinbase, check that it's matured
              if (txPrev.IsCoinBase())
                      if (pindex->nBlockPos == txindex.pos.nBlockPos && pindex->nFile == txindex.pos.nFile)
                          return error("ConnectInputs() : tried to spend coinbase at depth %d", pindexBlock->nHeight - pindex->nHeight);
  
 -            // Verify signature
 -            if (!VerifySignature(txPrev, *this, i))
 -                return error("ConnectInputs() : %s VerifySignature failed", GetHash().ToString().substr(0,10).c_str());
 -
 -            // Check for conflicts
 +            // Skip ECDSA signature verification when connecting blocks (fBlock=true)
 +            // before the last blockchain checkpoint. This is safe because block merkle hashes are
 +            // still computed and checked, and any change will be caught at the next checkpoint.
 +            if (!(fBlock && (nBestHeight < Checkpoints::GetTotalBlocksEstimate())))
 +                // Verify signature
 +                if (!VerifySignature(txPrev, *this, i))
 +                    return DoS(100,error("ConnectInputs() : %s VerifySignature failed", GetHash().ToString().substr(0,10).c_str()));
 +
 +            // Check for conflicts (double-spend)
 +            // This doesn't trigger the DoS code on purpose; if it did, it would make it easier
 +            // for an attacker to attempt to split the network.
              if (!txindex.vSpent[prevout.n].IsNull())
                  return fMiner ? false : error("ConnectInputs() : %s prev tx already used at %s", GetHash().ToString().substr(0,10).c_str(), txindex.vSpent[prevout.n].ToString().c_str());
  
              // Check for negative or overflow input values
              nValueIn += txPrev.vout[prevout.n].nValue;
              if (!MoneyRange(txPrev.vout[prevout.n].nValue) || !MoneyRange(nValueIn))
 -                return error("ConnectInputs() : txin values out of range");
 +                return DoS(100, error("ConnectInputs() : txin values out of range"));
  
              // Mark outpoints as spent
              txindex.vSpent[prevout.n] = posThisTx;
          }
  
          if (nValueIn < GetValueOut())
 -            return error("ConnectInputs() : %s value in < value out", GetHash().ToString().substr(0,10).c_str());
 +            return DoS(100, error("ConnectInputs() : %s value in < value out", GetHash().ToString().substr(0,10).c_str()));
  
          // Tally transaction fees
          int64 nTxFee = nValueIn - GetValueOut();
          if (nTxFee < 0)
 -            return error("ConnectInputs() : %s nTxFee < 0", GetHash().ToString().substr(0,10).c_str());
 +            return DoS(100, error("ConnectInputs() : %s nTxFee < 0", GetHash().ToString().substr(0,10).c_str()));
          if (nTxFee < nMinFee)
              return false;
          nFees += nTxFee;
          if (!MoneyRange(nFees))
 -            return error("ConnectInputs() : nFees out of range");
 +            return DoS(100, error("ConnectInputs() : nFees out of range"));
      }
  
      if (fBlock)
@@@ -1022,7 -1038,8 +1060,8 @@@ bool CBlock::ConnectBlock(CTxDB& txdb, 
          CDiskTxPos posThisTx(pindex->nFile, pindex->nBlockPos, nTxPos);
          nTxPos += ::GetSerializeSize(tx, SER_DISK);
  
-         if (!tx.ConnectInputs(txdb, mapQueuedChanges, posThisTx, pindex, nFees, true, false))
+         bool fInvalid;
+         if (!tx.ConnectInputs(txdb, mapQueuedChanges, posThisTx, pindex, nFees, true, false, 0, fInvalid))
              return false;
      }
      // Write queued txindex changes
@@@ -1263,11 -1280,11 +1302,11 @@@ bool CBlock::CheckBlock() cons
  
      // Size limits
      if (vtx.empty() || vtx.size() > MAX_BLOCK_SIZE || ::GetSerializeSize(*this, SER_NETWORK) > MAX_BLOCK_SIZE)
 -        return error("CheckBlock() : size limits failed");
 +        return DoS(100, error("CheckBlock() : size limits failed"));
  
      // Check proof of work matches claimed amount
      if (!CheckProofOfWork(GetHash(), nBits))
 -        return error("CheckBlock() : proof of work failed");
 +        return DoS(50, error("CheckBlock() : proof of work failed"));
  
      // Check timestamp
      if (GetBlockTime() > GetAdjustedTime() + 2 * 60 * 60)
  
      // First transaction must be coinbase, the rest must not be
      if (vtx.empty() || !vtx[0].IsCoinBase())
 -        return error("CheckBlock() : first tx is not coinbase");
 +        return DoS(100, error("CheckBlock() : first tx is not coinbase"));
      for (int i = 1; i < vtx.size(); i++)
          if (vtx[i].IsCoinBase())
 -            return error("CheckBlock() : more than one coinbase");
 +            return DoS(100, error("CheckBlock() : more than one coinbase"));
  
      // Check transactions
      BOOST_FOREACH(const CTransaction& tx, vtx)
          if (!tx.CheckTransaction())
 -            return error("CheckBlock() : CheckTransaction failed");
 +            return DoS(tx.nDoS, error("CheckBlock() : CheckTransaction failed"));
  
      // Check that it's not full of nonstandard transactions
      if (GetSigOpCount() > MAX_BLOCK_SIGOPS)
 -        return error("CheckBlock() : too many nonstandard transactions");
 +        return DoS(100, error("CheckBlock() : out-of-bounds SigOpCount"));
  
      // Check merkleroot
      if (hashMerkleRoot != BuildMerkleTree())
 -        return error("CheckBlock() : hashMerkleRoot mismatch");
 +        return DoS(100, error("CheckBlock() : hashMerkleRoot mismatch"));
  
      return true;
  }
@@@ -1306,13 -1323,13 +1345,13 @@@ bool CBlock::AcceptBlock(
      // Get prev block index
      map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashPrevBlock);
      if (mi == mapBlockIndex.end())
 -        return error("AcceptBlock() : prev block not found");
 +        return DoS(10, error("AcceptBlock() : prev block not found"));
      CBlockIndex* pindexPrev = (*mi).second;
      int nHeight = pindexPrev->nHeight+1;
  
      // Check proof of work
-     if (nBits != GetNextWorkRequired(pindexPrev))
+     if (nBits != GetNextWorkRequired(pindexPrev, this))
 -        return error("AcceptBlock() : incorrect proof of work");
 +        return DoS(100, error("AcceptBlock() : incorrect proof of work"));
  
      // Check timestamp against prev
      if (GetBlockTime() <= pindexPrev->GetMedianTimePast())
      // Check that all transactions are finalized
      BOOST_FOREACH(const CTransaction& tx, vtx)
          if (!tx.IsFinal(nHeight, GetBlockTime()))
 -            return error("AcceptBlock() : contains a non-final transaction");
 +            return DoS(10, error("AcceptBlock() : contains a non-final transaction"));
  
      // Check that the block chain matches the known block chain up to a checkpoint
      if (!Checkpoints::CheckBlock(nHeight, hash))
 -        return error("AcceptBlock() : rejected by checkpoint lockin at %d", nHeight);
 +        return DoS(100, error("AcceptBlock() : rejected by checkpoint lockin at %d", nHeight));
  
      // Write block to history file
      if (!CheckDiskSpace(::GetSerializeSize(*this, SER_DISK)))
      return true;
  }
  
 -bool static ProcessBlock(CNode* pfrom, CBlock* pblock)
 +bool ProcessBlock(CNode* pfrom, CBlock* pblock)
  {
      // Check for duplicate
      uint256 hash = pblock->GetHash();
          int64 deltaTime = pblock->GetBlockTime() - pcheckpoint->nTime;
          if (deltaTime < 0)
          {
 +            pfrom->Misbehaving(100);
              return error("ProcessBlock() : block with timestamp before last checkpoint");
          }
          CBigNum bnNewBlock;
          bnRequired.SetCompact(ComputeMinWork(pcheckpoint->nBits, deltaTime));
          if (bnNewBlock > bnRequired)
          {
 +            pfrom->Misbehaving(100);
              return error("ProcessBlock() : block with too little proof-of-work");
          }
      }
@@@ -1805,10 -1820,7 +1844,10 @@@ bool static ProcessMessage(CNode* pfrom
      {
          // Each connection can only send one version message
          if (pfrom->nVersion != 0)
 +        {
 +            pfrom->Misbehaving(1);
              return false;
 +        }
  
          int64 nTime;
          CAddress addrMe;
          pfrom->fSuccessfullyConnected = true;
  
          printf("version message: version %d, blocks=%d\n", pfrom->nVersion, pfrom->nStartingHeight);
 +
 +        cPeerBlockCounts.input(pfrom->nStartingHeight);
      }
  
  
      else if (pfrom->nVersion == 0)
      {
          // Must have a version message before anything else
 +        pfrom->Misbehaving(1);
          return false;
      }
  
          if (pfrom->nVersion < 31402 && mapAddresses.size() > 1000)
              return true;
          if (vAddr.size() > 1000)
 +        {
 +            pfrom->Misbehaving(20);
              return error("message addr size() = %d", vAddr.size());
 +        }
  
          // Store the new addresses
          CAddrDB addrDB;
          vector<CInv> vInv;
          vRecv >> vInv;
          if (vInv.size() > 50000)
 +        {
 +            pfrom->Misbehaving(20);
              return error("message inv size() = %d", vInv.size());
 +        }
  
          CTxDB txdb("r");
          BOOST_FOREACH(const CInv& inv, vInv)
          vector<CInv> vInv;
          vRecv >> vInv;
          if (vInv.size() > 50000)
 +        {
 +            pfrom->Misbehaving(20);
              return error("message getdata size() = %d", vInv.size());
 +        }
  
          BOOST_FOREACH(const CInv& inv, vInv)
          {
              printf("storing orphan tx %s\n", inv.hash.ToString().substr(0,10).c_str());
              AddOrphanTx(vMsg);
          }
 +        if (tx.nDoS) pfrom->Misbehaving(tx.nDoS);
      }
  
  
  
          if (ProcessBlock(pfrom, &block))
              mapAlreadyAskedFor.erase(inv);
 +        if (block.nDoS) pfrom->Misbehaving(block.nDoS);
      }
  
  
@@@ -2645,25 -2643,15 +2684,25 @@@ int static FormatHashBlocks(void* pbuff
      return blocks;
  }
  
  static const unsigned int pSHA256InitState[8] =
  {0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19};
  
 -inline void SHA256Transform(void* pstate, void* pinput, const void* pinit)
 +void SHA256Transform(void* pstate, void* pinput, const void* pinit)
  {
 -    memcpy(pstate, pinit, 32);
 -    CryptoPP::SHA256::Transform((CryptoPP::word32*)pstate, (CryptoPP::word32*)pinput);
 +    SHA256_CTX ctx;
 +    unsigned char data[64];
 +
 +    SHA256_Init(&ctx);
 +
 +    for (int i = 0; i < 16; i++)
 +        ((uint32_t*)data)[i] = ByteReverse(((uint32_t*)pinput)[i]);
 +
 +    for (int i = 0; i < 8; i++)
 +        ctx.h[i] = ((uint32_t*)pinit)[i];
 +
 +    SHA256_Update(&ctx, data, sizeof(data));
 +    for (int i = 0; i < 8; i++) 
 +        ((uint32_t*)pstate)[i] = ctx.h[i];
  }
  
  //
@@@ -2832,7 -2820,8 +2871,8 @@@ CBlock* CreateNewBlock(CReserveKey& res
              // 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);
-             if (!tx.ConnectInputs(txdb, mapTestPoolTmp, CDiskTxPos(1,1,1), pindexPrev, nFees, false, true, nMinFee))
+             bool fInvalid;
+             if (!tx.ConnectInputs(txdb, mapTestPoolTmp, CDiskTxPos(1,1,1), pindexPrev, nFees, false, true, nMinFee, fInvalid))
                  continue;
              swap(mapTestPool, mapTestPoolTmp);
  
      pblock->hashPrevBlock  = pindexPrev->GetBlockHash();
      pblock->hashMerkleRoot = pblock->BuildMerkleTree();
      pblock->nTime          = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
-     pblock->nBits          = GetNextWorkRequired(pindexPrev);
+     pblock->nBits          = GetNextWorkRequired(pindexPrev, pblock.get());
      pblock->nNonce         = 0;
  
      return pblock.release();
@@@ -2964,6 -2953,7 +3004,6 @@@ bool CheckWork(CBlock* pblock, CWallet
              return error("BitcoinMiner : ProcessBlock, block not accepted");
      }
  
 -    Sleep(2000);
      return true;
  }
  
diff --combined src/main.h
@@@ -85,7 -85,6 +85,7 @@@ class CTxIndex
  
  void RegisterWallet(CWallet* pwalletIn);
  void UnregisterWallet(CWallet* pwalletIn);
 +bool ProcessBlock(CNode* pfrom, CBlock* pblock);
  bool CheckDiskSpace(uint64 nAdditionalBytes=0);
  FILE* OpenBlockFile(unsigned int nFile, unsigned int nBlockPos, const char* pszMode="rb");
  FILE* AppendBlockFile(unsigned int& nFileRet);
@@@ -100,7 -99,6 +100,7 @@@ void FormatHashBuffers(CBlock* pblock, 
  bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey);
  bool CheckProofOfWork(uint256 hash, unsigned int nBits);
  unsigned int ComputeMinWork(unsigned int nBase, int64 nTime);
 +int GetNumBlocksOfPeers();
  bool IsInitialBlockDownload();
  std::string GetWarnings(std::string strFor);
  
@@@ -401,9 -399,6 +401,9 @@@ public
      std::vector<CTxOut> vout;
      unsigned int nLockTime;
  
 +    // Denial-of-service detection:
 +    mutable int nDoS;
 +    bool DoS(int nDoSIn, bool fIn) const { nDoS += nDoSIn; return fIn; }
  
      CTransaction()
      {
          vin.clear();
          vout.clear();
          nLockTime = 0;
 +        nDoS = 0;  // Denial-of-service prevention
      }
  
      bool IsNull() const
      bool ReadFromDisk(COutPoint prevout);
      bool DisconnectInputs(CTxDB& txdb);
      bool ConnectInputs(CTxDB& txdb, std::map<uint256, CTxIndex>& mapTestPool, CDiskTxPos posThisTx,
-                        CBlockIndex* pindexBlock, int64& nFees, bool fBlock, bool fMiner, int64 nMinFee=0);
+                        CBlockIndex* pindexBlock, int64& nFees, bool fBlock, bool fMiner, int64 nMinFee,
+                        bool& fInvalid);
      bool ClientConnectInputs();
      bool CheckTransaction() const;
      bool AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs=true, bool* pfMissingInputs=NULL);
@@@ -792,9 -787,6 +793,9 @@@ public
      // memory only
      mutable std::vector<uint256> vMerkleTree;
  
 +    // Denial-of-service detection:
 +    mutable int nDoS;
 +    bool DoS(int nDoSIn, bool fIn) const { nDoS += nDoSIn; return fIn; }
  
      CBlock()
      {
          nNonce = 0;
          vtx.clear();
          vMerkleTree.clear();
 +        nDoS = 0;
      }
  
      bool IsNull() const
          fflush(fileout);
          if (!IsInitialBlockDownload() || (nBestHeight+1) % 500 == 0)
          {
 -#ifdef __WXMSW__
 +#ifdef WIN32
              _commit(_fileno(fileout));
  #else
              fsync(fileno(fileout));
diff --combined src/net.cpp
@@@ -10,7 -10,7 +10,7 @@@
  #include "init.h"
  #include "strlcpy.h"
  
 -#ifdef __WXMSW__
 +#ifdef WIN32
  #include <string.h>
  #endif
  
@@@ -103,7 -103,7 +103,7 @@@ bool ConnectSocket(const CAddress& addr
      bool fProxy = (fUseProxy && addrConnect.IsRoutable());
      struct sockaddr_in sockaddr = (fProxy ? addrProxy.GetSockAddr() : addrConnect.GetSockAddr());
  
 -#ifdef __WXMSW__
 +#ifdef WIN32
      u_long fNonblock = 1;
      if (ioctlsocket(hSocket, FIONBIO, &fNonblock) == SOCKET_ERROR)
  #else
                  return false;
              }
              socklen_t nRetSize = sizeof(nRet);
 -#ifdef __WXMSW__
 +#ifdef WIN32
              if (getsockopt(hSocket, SOL_SOCKET, SO_ERROR, (char*)(&nRet), &nRetSize) == SOCKET_ERROR)
  #else
              if (getsockopt(hSocket, SOL_SOCKET, SO_ERROR, &nRet, &nRetSize) == SOCKET_ERROR)
                  return false;
              }
          }
 -#ifdef __WXMSW__
 +#ifdef WIN32
          else if (WSAGetLastError() != WSAEISCONN)
  #else
          else
      CNode::ConnectNode immediately turns the socket back to non-blocking
      but we'll turn it back to blocking just in case
      */
 -#ifdef __WXMSW__
 +#ifdef WIN32
      fNonblock = 0;
      if (ioctlsocket(hSocket, FIONBIO, &fNonblock) == SOCKET_ERROR)
  #else
@@@ -679,7 -679,7 +679,7 @@@ CNode* ConnectNode(CAddress addrConnect
          printf("connected %s\n", addrConnect.ToString().c_str());
  
          // Set to nonblocking
 -#ifdef __WXMSW__
 +#ifdef WIN32
          u_long nOne = 1;
          if (ioctlsocket(hSocket, FIONBIO, &nOne) == SOCKET_ERROR)
              printf("ConnectSocket() : ioctlsocket nonblocking setting failed, error %d\n", WSAGetLastError());
@@@ -731,52 -731,6 +731,52 @@@ void CNode::Cleanup(
  }
  
  
 +std::map<unsigned int, int64> CNode::setBanned;
 +CCriticalSection CNode::cs_setBanned;
 +
 +void CNode::ClearBanned()
 +{
 +    setBanned.clear();
 +}
 +
 +bool CNode::IsBanned(unsigned int ip)
 +{
 +    bool fResult = false;
 +    CRITICAL_BLOCK(cs_setBanned)
 +    {
 +        std::map<unsigned int, int64>::iterator i = setBanned.find(ip);
 +        if (i != setBanned.end())
 +        {
 +            int64 t = (*i).second;
 +            if (GetTime() < t)
 +                fResult = true;
 +        }
 +    }
 +    return fResult;
 +}
 +
 +bool CNode::Misbehaving(int howmuch)
 +{
 +    if (addr.IsLocal())
 +    {
 +        printf("Warning: local node %s misbehaving\n", addr.ToString().c_str());
 +        return false;
 +    }
 +
 +    nMisbehavior += howmuch;
 +    if (nMisbehavior >= GetArg("-banscore", 100))
 +    {
 +        int64 banTime = GetTime()+GetArg("-bantime", 60*60*24);  // Default 24-hour ban
 +        CRITICAL_BLOCK(cs_setBanned)
 +            if (setBanned[addr.ip] < banTime)
 +                setBanned[addr.ip] = banTime;
 +        CloseSocketDisconnect();
 +        printf("Disconnected %s for misbehavior (score=%d)\n", addr.ToString().c_str(), nMisbehavior);
 +        return true;
 +    }
 +    return false;
 +}
 +
  
  
  
@@@ -947,11 -901,6 +947,11 @@@ void ThreadSocketHandler2(void* parg
              {
                  closesocket(hSocket);
              }
 +            else if (CNode::IsBanned(addr.ip))
 +            {
 +                printf("connetion from %s dropped (banned)\n", addr.ToString().c_str());
 +                closesocket(hSocket);
 +            }
              else
              {
                  printf("accepted connection %s\n", addr.ToString().c_str());
@@@ -1156,11 -1105,11 +1156,11 @@@ void ThreadMapPort2(void* parg
      {
          string strDesc = "Bitcoin " + FormatFullVersion();
  #ifndef UPNPDISCOVER_SUCCESS
-     /* miniupnpc 1.5 */
+         /* miniupnpc 1.5 */
          r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype,
                              port, port, lanaddr, strDesc.c_str(), "TCP", 0);
  #else
-     /* miniupnpc 1.6 */
+         /* miniupnpc 1.6 */
          r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype,
                              port, port, lanaddr, strDesc.c_str(), "TCP", 0, "0");
  #endif
                  port, port, lanaddr, r, strupnperror(r));
          else
              printf("UPnP Port Mapping successful.\n");
+         int i = 1;
          loop {
              if (fShutdown || !fUseUPnP)
              {
                  FreeUPNPUrls(&urls);
                  return;
              }
+             if (i % 600 == 0) // Refresh every 20 minutes
+             {
+ #ifndef UPNPDISCOVER_SUCCESS
+                 /* miniupnpc 1.5 */
+                 r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype,
+                                     port, port, lanaddr, strDesc.c_str(), "TCP", 0);
+ #else
+                 /* miniupnpc 1.6 */
+                 r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype,
+                                     port, port, lanaddr, strDesc.c_str(), "TCP", 0, "0");
+ #endif
+                 if(r!=UPNPCOMMAND_SUCCESS)
+                     printf("AddPortMapping(%s, %s, %s) failed with code %d (%s)\n",
+                         port, port, lanaddr, r, strupnperror(r));
+                 else
+                     printf("UPnP Port Mapping successful.\n");;
+             }
              Sleep(2000);
+             i++;
          }
      } else {
          printf("No valid UPnP IGDs found\n");
@@@ -1499,8 -1468,6 +1519,8 @@@ void ThreadOpenConnections2(void* parg
              BOOST_FOREACH(CNode* pnode, vNodes)
                  setConnected.insert(pnode->addr.ip & 0x0000ffff);
  
 +        int64 nANow = GetAdjustedTime();
 +
          CRITICAL_BLOCK(cs_mapAddresses)
          {
              BOOST_FOREACH(const PAIRTYPE(vector<unsigned char>, CAddress)& item, mapAddresses)
                  const CAddress& addr = item.second;
                  if (!addr.IsIPv4() || !addr.IsValid() || setConnected.count(addr.ip & 0x0000ffff))
                      continue;
 -                int64 nSinceLastSeen = GetAdjustedTime() - addr.nTime;
 -                int64 nSinceLastTry = GetAdjustedTime() - addr.nLastTry;
 +                int64 nSinceLastSeen = nANow - addr.nTime;
 +                int64 nSinceLastTry = nANow - addr.nLastTry;
  
                  // Randomize the order in a deterministic way, putting the standard port first
                  int64 nRandomizer = (uint64)(nStart * 4951 + addr.nLastTry * 9567851 + addr.ip * 7789) % (2 * 60 * 60);
@@@ -1568,8 -1535,7 +1588,8 @@@ bool OpenNetworkConnection(const CAddre
      //
      if (fShutdown)
          return false;
 -    if (addrConnect.ip == addrLocalHost.ip || !addrConnect.IsIPv4() || FindNode(addrConnect.ip))
 +    if (addrConnect.ip == addrLocalHost.ip || !addrConnect.IsIPv4() ||
 +        FindNode(addrConnect.ip) || CNode::IsBanned(addrConnect.ip))
          return false;
  
      vnThreadsRunning[1]--;
@@@ -1673,7 -1639,7 +1693,7 @@@ bool BindListenPort(string& strError
      int nOne = 1;
      addrLocalHost.port = htons(GetListenPort());
  
 -#ifdef __WXMSW__
 +#ifdef WIN32
      // Initialize Windows Sockets
      WSADATA wsadata;
      int ret = WSAStartup(MAKEWORD(2,2), &wsadata);
      setsockopt(hListenSocket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&nOne, sizeof(int));
  #endif
  
 -#ifndef __WXMSW__
 +#ifndef WIN32
      // Allow binding if the port is still in TIME_WAIT state after
      // the program was closed and restarted.  Not an issue on windows.
      setsockopt(hListenSocket, SOL_SOCKET, SO_REUSEADDR, (void*)&nOne, sizeof(int));
  #endif
  
 -#ifdef __WXMSW__
 +#ifdef WIN32
      // Set to nonblocking, incoming connections will also inherit this
      if (ioctlsocket(hListenSocket, FIONBIO, (u_long*)&nOne) == SOCKET_ERROR)
  #else
@@@ -1752,7 -1718,7 +1772,7 @@@ void StartNode(void* parg
      if (pnodeLocalHost == NULL)
          pnodeLocalHost = new CNode(INVALID_SOCKET, CAddress("127.0.0.1", 0, false, nLocalServices));
  
 -#ifdef __WXMSW__
 +#ifdef WIN32
      // Get local host ip
      char pszHostName[1000] = "";
      if (gethostname(pszHostName, sizeof(pszHostName)) != SOCKET_ERROR)
@@@ -1895,7 -1861,7 +1915,7 @@@ public
              if (closesocket(hListenSocket) == SOCKET_ERROR)
                  printf("closesocket(hListenSocket) failed with error %d\n", WSAGetLastError());
  
 -#ifdef __WXMSW__
 +#ifdef WIN32
          // Shutdown Windows Sockets
          WSACleanup();
  #endif