Merge branch '0.4.x' into 0.5.x
authorLuke Dashjr <luke-jr+git@utopios.org>
Sun, 22 Apr 2012 14:05:43 +0000 (10:05 -0400)
committerLuke Dashjr <luke-jr+git@utopios.org>
Sun, 22 Apr 2012 14:05:43 +0000 (10:05 -0400)
Conflicts:
src/main.cpp

12 files changed:
1  2 
src/base58.h
src/bitcoinrpc.cpp
src/crypter.cpp
src/key.h
src/main.cpp
src/main.h
src/net.cpp
src/net.h
src/protocol.cpp
src/util.cpp
src/wallet.cpp
src/wallet.h

diff --combined src/base58.h
@@@ -21,7 -21,7 +21,7 @@@
  
  static const char* pszBase58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
  
 -
 +// Encode a byte sequence as a base58-encoded string
  inline std::string EncodeBase58(const unsigned char* pbegin, const unsigned char* pend)
  {
      CAutoBN_CTX pctx;
      return str;
  }
  
 +// Encode a byte vector as a base58-encoded string
  inline std::string EncodeBase58(const std::vector<unsigned char>& vch)
  {
      return EncodeBase58(&vch[0], &vch[0] + vch.size());
  }
  
 +// Decode a base58-encoded string psz into byte vector vchRet
 +// returns true if decoding is succesful
  inline bool DecodeBase58(const char* psz, std::vector<unsigned char>& vchRet)
  {
      CAutoBN_CTX pctx;
      return true;
  }
  
 +// Decode a base58-encoded string str into byte vector vchRet
 +// returns true if decoding is succesful
  inline bool DecodeBase58(const std::string& str, std::vector<unsigned char>& vchRet)
  {
      return DecodeBase58(str.c_str(), vchRet);
  
  
  
 -
 +// Encode a byte vector to a base58-encoded string, including checksum
  inline std::string EncodeBase58Check(const std::vector<unsigned char>& vchIn)
  {
      // add 4-byte hash check to the end
      return EncodeBase58(vch);
  }
  
 +// Decode a base58-encoded string psz that includes a checksum, into byte vector vchRet
 +// returns true if decoding is succesful
  inline bool DecodeBase58Check(const char* psz, std::vector<unsigned char>& vchRet)
  {
      if (!DecodeBase58(psz, vchRet))
      return true;
  }
  
 +// Decode a base58-encoded string str that includes a checksum, into byte vector vchRet
 +// returns true if decoding is succesful
  inline bool DecodeBase58Check(const std::string& str, std::vector<unsigned char>& vchRet)
  {
      return DecodeBase58Check(str.c_str(), vchRet);
  
  
  
 -
 +// Base class for all base58-encoded data
  class CBase58Data
  {
  protected:
 +    // the version byte
      unsigned char nVersion;
 +
 +    // the actually encoded data
      std::vector<unsigned char> vchData;
  
      CBase58Data()
  
      ~CBase58Data()
      {
 +        // zero the memory, as it may contain sensitive data
          if (!vchData.empty())
              memset(&vchData[0], 0, vchData.size());
      }
@@@ -251,9 -238,7 +251,9 @@@ public
      bool operator> (const CBase58Data& b58) const { return CompareTo(b58) >  0; }
  };
  
 -
 +// base58-encoded bitcoin addresses
 +// Addresses have version 0 or 111 (testnet)
 +// The data vector contains RIPEMD160(SHA256(pubkey)), where pubkey is the serialized public key
  class CBitcoinAddress : public CBase58Data
  {
  public:
  
      bool IsValid() const
      {
-         int nExpectedSize = 20;
+         unsigned int nExpectedSize = 20;
          bool fExpectTestNet = false;
          switch(nVersion)
          {
diff --combined src/bitcoinrpc.cpp
@@@ -4,6 -4,7 +4,6 @@@
  // file license.txt or http://www.opensource.org/licenses/mit-license.php.
  
  #include "headers.h"
 -#include "cryptopp/sha.h"
  #include "db.h"
  #include "net.h"
  #include "init.h"
@@@ -36,8 -37,6 +36,8 @@@ void ThreadRPCServer2(void* parg)
  typedef Value(*rpcfn_type)(const Array& params, bool fHelp);
  extern map<string, rpcfn_type> mapCallTable;
  
 +static std::string strRPCUserColonPass;
 +
  static int64 nWalletUnlockTime;
  static CCriticalSection cs_nWalletUnlockTime;
  
@@@ -51,13 -50,13 +51,13 @@@ Object JSONRPCError(int code, const str
  }
  
  
 -void PrintConsole(const char* format, ...)
 +void PrintConsole(const std::string &format, ...)
  {
      char buffer[50000];
      int limit = sizeof(buffer);
      va_list arg_ptr;
      va_start(arg_ptr, format);
 -    int ret = _vsnprintf(buffer, limit, format, arg_ptr);
 +    int ret = _vsnprintf(buffer, limit, format.c_str(), arg_ptr);
      va_end(arg_ptr);
      if (ret < 0 || ret >= limit)
      {
          buffer[limit-1] = 0;
      }
      printf("%s", buffer);
 -#if defined(__WXMSW__) && defined(GUI)
 -    MyMessageBox(buffer, "Bitcoin", wxOK | wxICON_EXCLAMATION);
 -#else
      fprintf(stdout, "%s", buffer);
 -#endif
  }
  
  
@@@ -128,7 -131,6 +128,7 @@@ Value help(const Array& params, bool fH
          // We already filter duplicates, but these deprecated screw up the sort order
          if (strMethod == "getamountreceived" ||
              strMethod == "getallreceived" ||
 +            strMethod == "getblocknumber" || // deprecated
              (strMethod.find("label") != string::npos))
              continue;
          if (strCommand != "" && strMethod != strCommand)
              // Help text is returned in an exception
              string strHelp = string(e.what());
              if (strCommand == "")
-                 if (strHelp.find('\n') != -1)
+                 if (strHelp.find('\n') != string::npos)
                      strHelp = strHelp.substr(0, strHelp.find('\n'));
              strRet += strHelp + "\n";
          }
@@@ -163,13 -165,10 +163,13 @@@ Value stop(const Array& params, bool fH
          throw runtime_error(
              "stop\n"
              "Stop bitcoin server.");
 -
 +#ifndef QT_GUI
      // Shutdown will take long enough that the response should get back
      CreateThread(Shutdown, NULL);
      return "bitcoin server stopping";
 +#else
 +    throw runtime_error("NYI: cannot shut down GUI with RPC command");
 +#endif
  }
  
  
@@@ -184,13 -183,12 +184,13 @@@ Value getblockcount(const Array& params
  }
  
  
 +// deprecated
  Value getblocknumber(const Array& params, bool fHelp)
  {
      if (fHelp || params.size() != 0)
          throw runtime_error(
              "getblocknumber\n"
 -            "Returns the block number of the latest block in the longest block chain.");
 +            "Deprecated.  Use getblockcount.");
  
      return nBestHeight;
  }
@@@ -532,72 -530,6 +532,72 @@@ Value sendtoaddress(const Array& params
      return wtx.GetHash().GetHex();
  }
  
 +static const string strMessageMagic = "Bitcoin Signed Message:\n";
 +
 +Value signmessage(const Array& params, bool fHelp)
 +{
 +    if (fHelp || params.size() != 2)
 +        throw runtime_error(
 +            "signmessage <bitcoinaddress> <message>\n"
 +            "Sign a message with the private key of an address");
 +
 +    if (pwalletMain->IsLocked())
 +        throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
 +
 +    string strAddress = params[0].get_str();
 +    string strMessage = params[1].get_str();
 +
 +    CBitcoinAddress addr(strAddress);
 +    if (!addr.IsValid())
 +        throw JSONRPCError(-3, "Invalid address");
 +
 +    CKey key;
 +    if (!pwalletMain->GetKey(addr, key))
 +        throw JSONRPCError(-4, "Private key not available");
 +
 +    CDataStream ss(SER_GETHASH);
 +    ss << strMessageMagic;
 +    ss << strMessage;
 +
 +    vector<unsigned char> vchSig;
 +    if (!key.SignCompact(Hash(ss.begin(), ss.end()), vchSig))
 +        throw JSONRPCError(-5, "Sign failed");
 +
 +    return EncodeBase64(&vchSig[0], vchSig.size());
 +}
 +
 +Value verifymessage(const Array& params, bool fHelp)
 +{
 +    if (fHelp || params.size() != 3)
 +        throw runtime_error(
 +            "verifymessage <bitcoinaddress> <signature> <message>\n"
 +            "Verify a signed message");
 +
 +    string strAddress  = params[0].get_str();
 +    string strSign     = params[1].get_str();
 +    string strMessage  = params[2].get_str();
 +
 +    CBitcoinAddress addr(strAddress);
 +    if (!addr.IsValid())
 +        throw JSONRPCError(-3, "Invalid address");
 +
 +    bool fInvalid = false;
 +    vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
 +
 +    if (fInvalid)
 +        throw JSONRPCError(-5, "Malformed base64 encoding");
 +
 +    CDataStream ss(SER_GETHASH);
 +    ss << strMessageMagic;
 +    ss << strMessage;
 +
 +    CKey key;
 +    if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig))
 +        return false;
 +
 +    return (key.GetAddress() == addr);
 +}
 +
  
  Value getreceivedbyaddress(const Array& params, bool fHelp)
  {
@@@ -1011,6 -943,7 +1011,6 @@@ Value ListReceived(const Array& params
              Object obj;
              obj.push_back(Pair("address",       address.ToString()));
              obj.push_back(Pair("account",       strAccount));
 -            obj.push_back(Pair("label",         strAccount)); // deprecated
              obj.push_back(Pair("amount",        ValueFromAmount(nAmount)));
              obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
              ret.push_back(obj);
              int nConf = (*it).second.nConf;
              Object obj;
              obj.push_back(Pair("account",       (*it).first));
 -            obj.push_back(Pair("label",         (*it).first)); // deprecated
              obj.push_back(Pair("amount",        ValueFromAmount(nAmount)));
              obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
              ret.push_back(obj);
@@@ -1276,70 -1210,6 +1276,70 @@@ Value listaccounts(const Array& params
      return ret;
  }
  
 +Value listsinceblock(const Array& params, bool fHelp)
 +{
 +    if (fHelp)
 +        throw runtime_error(
 +            "listsinceblock [blockid] [target-confirmations]\n"
 +            "Get all transactions in blocks since block [blockid], or all transactions if omitted");
 +
 +    CBlockIndex *pindex = NULL;
 +    int target_confirms = 1;
 +
 +    if (params.size() > 0)
 +    {
 +        uint256 blockId = 0;
 +
 +        blockId.SetHex(params[0].get_str());
 +        pindex = CBlockLocator(blockId).GetBlockIndex();
 +    }
 +
 +    if (params.size() > 1)
 +    {
 +        target_confirms = params[1].get_int();
 +
 +        if (target_confirms < 1)
 +            throw JSONRPCError(-8, "Invalid parameter");
 +    }
 +
 +    int depth = pindex ? (1 + nBestHeight - pindex->nHeight) : -1;
 +
 +    Array transactions;
 +
 +    for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
 +    {
 +        CWalletTx tx = (*it).second;
 +
 +        if (depth == -1 || tx.GetDepthInMainChain() < depth)
 +            ListTransactions(tx, "*", 0, true, transactions);
 +    }
 +
 +    uint256 lastblock;
 +
 +    if (target_confirms == 1)
 +    {
 +        printf("oops!\n");
 +        lastblock = hashBestChain;
 +    }
 +    else
 +    {
 +        int target_height = pindexBest->nHeight + 1 - target_confirms;
 +
 +        CBlockIndex *block;
 +        for (block = pindexBest;
 +             block && block->nHeight > target_height;
 +             block = block->pprev)  { }
 +
 +        lastblock = block ? block->GetBlockHash() : 0;
 +    }
 +
 +    Object ret;
 +    ret.push_back(Pair("transactions", transactions));
 +    ret.push_back(Pair("lastblock", lastblock.GetHex()));
 +
 +    return ret;
 +}
 +
  Value gettransaction(const Array& params, bool fHelp)
  {
      if (fHelp || params.size() != 1)
@@@ -1473,16 -1343,21 +1473,16 @@@ Value walletpassphrase(const Array& par
          throw JSONRPCError(-17, "Error: Wallet is already unlocked.");
  
      // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
 -    string strWalletPass;
 +    SecureString strWalletPass;
      strWalletPass.reserve(100);
 -    mlock(&strWalletPass[0], strWalletPass.capacity());
 -    strWalletPass = params[0].get_str();
 +    // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
 +    // Alternately, find a way to make params[0] mlock()'d to begin with.
 +    strWalletPass = params[0].get_str().c_str();
  
      if (strWalletPass.length() > 0)
      {
          if (!pwalletMain->Unlock(strWalletPass))
 -        {
 -            fill(strWalletPass.begin(), strWalletPass.end(), '\0');
 -            munlock(&strWalletPass[0], strWalletPass.capacity());
              throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
 -        }
 -        fill(strWalletPass.begin(), strWalletPass.end(), '\0');
 -        munlock(&strWalletPass[0], strWalletPass.capacity());
      }
      else
          throw runtime_error(
@@@ -1508,15 -1383,15 +1508,15 @@@ Value walletpassphrasechange(const Arra
      if (!pwalletMain->IsCrypted())
          throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
  
 -    string strOldWalletPass;
 +    // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
 +    // Alternately, find a way to make params[0] mlock()'d to begin with.
 +    SecureString strOldWalletPass;
      strOldWalletPass.reserve(100);
 -    mlock(&strOldWalletPass[0], strOldWalletPass.capacity());
 -    strOldWalletPass = params[0].get_str();
 +    strOldWalletPass = params[0].get_str().c_str();
  
 -    string strNewWalletPass;
 +    SecureString strNewWalletPass;
      strNewWalletPass.reserve(100);
 -    mlock(&strNewWalletPass[0], strNewWalletPass.capacity());
 -    strNewWalletPass = params[1].get_str();
 +    strNewWalletPass = params[1].get_str().c_str();
  
      if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
          throw runtime_error(
              "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
  
      if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
 -    {
 -        fill(strOldWalletPass.begin(), strOldWalletPass.end(), '\0');
 -        fill(strNewWalletPass.begin(), strNewWalletPass.end(), '\0');
 -        munlock(&strOldWalletPass[0], strOldWalletPass.capacity());
 -        munlock(&strNewWalletPass[0], strNewWalletPass.capacity());
          throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
 -    }
 -    fill(strNewWalletPass.begin(), strNewWalletPass.end(), '\0');
 -    fill(strOldWalletPass.begin(), strOldWalletPass.end(), '\0');
 -    munlock(&strOldWalletPass[0], strOldWalletPass.capacity());
 -    munlock(&strNewWalletPass[0], strNewWalletPass.capacity());
  
      return Value::null;
  }
@@@ -1564,16 -1449,15 +1564,16 @@@ Value encryptwallet(const Array& params
      if (pwalletMain->IsCrypted())
          throw JSONRPCError(-15, "Error: running with an encrypted wallet, but encryptwallet was called.");
  
 -#ifdef GUI
 +#ifdef QT_GUI
      // shutting down via RPC while the GUI is running does not work (yet):
      throw runtime_error("Not Yet Implemented: use GUI to encrypt wallet, not RPC command");
  #endif
  
 -    string strWalletPass;
 +    // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
 +    // Alternately, find a way to make params[0] mlock()'d to begin with.
 +    SecureString strWalletPass;
      strWalletPass.reserve(100);
 -    mlock(&strWalletPass[0], strWalletPass.capacity());
 -    strWalletPass = params[0].get_str();
 +    strWalletPass = params[0].get_str().c_str();
  
      if (strWalletPass.length() < 1)
          throw runtime_error(
              "Encrypts the wallet with <passphrase>.");
  
      if (!pwalletMain->EncryptWallet(strWalletPass))
 -    {
 -        fill(strWalletPass.begin(), strWalletPass.end(), '\0');
 -        munlock(&strWalletPass[0], strWalletPass.capacity());
          throw JSONRPCError(-16, "Error: Failed to encrypt the wallet.");
 -    }
 -    fill(strWalletPass.begin(), strWalletPass.end(), '\0');
 -    munlock(&strWalletPass[0], strWalletPass.capacity());
  
      // BDB seems to have a bad habit of writing old data into
      // slack space in .dat files; that is bad if the old data is
@@@ -1623,9 -1513,9 +1623,9 @@@ Value getwork(const Array& params, boo
          throw runtime_error(
              "getwork [data]\n"
              "If [data] is not specified, returns formatted hash data to work on:\n"
 -            "  \"midstate\" : precomputed hash state after hashing the first half of the data\n"
 +            "  \"midstate\" : precomputed hash state after hashing the first half of the data (DEPRECATED)\n" // deprecated
              "  \"data\" : block data\n"
 -            "  \"hash1\" : formatted hash buffer for second hash\n"
 +            "  \"hash1\" : formatted hash buffer for second hash (DEPRECATED)\n" // deprecated
              "  \"target\" : little endian hash target\n"
              "If [data] is specified, tries to solve the block and returns true if it was successful.");
  
          uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
  
          Object result;
 -        result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate))));
 +        result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate)))); // deprecated
          result.push_back(Pair("data",     HexStr(BEGIN(pdata), END(pdata))));
 -        result.push_back(Pair("hash1",    HexStr(BEGIN(phash1), END(phash1))));
 +        result.push_back(Pair("hash1",    HexStr(BEGIN(phash1), END(phash1)))); // deprecated
          result.push_back(Pair("target",   HexStr(BEGIN(hashTarget), END(hashTarget))));
          return result;
      }
  
          // Byte reverse
          for (int i = 0; i < 128/4; i++)
 -            ((unsigned int*)pdata)[i] = CryptoPP::ByteReverse(((unsigned int*)pdata)[i]);
 +            ((unsigned int*)pdata)[i] = ByteReverse(((unsigned int*)pdata)[i]);
  
          // Get saved block
          if (!mapNewBlock.count(pdata->hashMerkleRoot))
  }
  
  
 +Value getmemorypool(const Array& params, bool fHelp)
 +{
 +    if (fHelp || params.size() > 1)
 +        throw runtime_error(
 +            "getmemorypool [data]\n"
 +            "If [data] is not specified, returns data needed to construct a block to work on:\n"
 +            "  \"version\" : block version\n"
 +            "  \"previousblockhash\" : hash of current highest block\n"
 +            "  \"transactions\" : contents of non-coinbase transactions that should be included in the next block\n"
 +            "  \"coinbasevalue\" : maximum allowable input to coinbase transaction, including the generation award and transaction fees\n"
 +            "  \"time\" : timestamp appropriate for next block\n"
 +            "  \"bits\" : compressed target of next block\n"
 +            "If [data] is specified, tries to solve the block and returns true if it was successful.");
 +
 +    if (params.size() == 0)
 +    {
 +        if (vNodes.empty())
 +            throw JSONRPCError(-9, "Bitcoin is not connected!");
 +
 +        if (IsInitialBlockDownload())
 +            throw JSONRPCError(-10, "Bitcoin is downloading blocks...");
 +
 +        static CReserveKey reservekey(pwalletMain);
 +
 +        // Update block
 +        static unsigned int nTransactionsUpdatedLast;
 +        static CBlockIndex* pindexPrev;
 +        static int64 nStart;
 +        static CBlock* pblock;
 +        if (pindexPrev != pindexBest ||
 +            (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 5))
 +        {
 +            nTransactionsUpdatedLast = nTransactionsUpdated;
 +            pindexPrev = pindexBest;
 +            nStart = GetTime();
 +
 +            // Create new block
 +            if(pblock)
 +                delete pblock;
 +            pblock = CreateNewBlock(reservekey);
 +            if (!pblock)
 +                throw JSONRPCError(-7, "Out of memory");
 +        }
 +
 +        // Update nTime
 +        pblock->UpdateTime(pindexPrev);
 +        pblock->nNonce = 0;
 +
 +        Array transactions;
 +        BOOST_FOREACH(CTransaction tx, pblock->vtx) {
 +            if(tx.IsCoinBase())
 +                continue;
 +
 +            CDataStream ssTx;
 +            ssTx << tx;
 +
 +            transactions.push_back(HexStr(ssTx.begin(), ssTx.end()));
 +        }
 +
 +        Object result;
 +        result.push_back(Pair("version", pblock->nVersion));
 +        result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
 +        result.push_back(Pair("transactions", transactions));
 +        result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue));
 +        result.push_back(Pair("time", (int64_t)pblock->nTime));
 +
 +        union {
 +            int32_t nBits;
 +            char cBits[4];
 +        } uBits;
 +        uBits.nBits = htonl((int32_t)pblock->nBits);
 +        result.push_back(Pair("bits", HexStr(BEGIN(uBits.cBits), END(uBits.cBits))));
 +
 +        return result;
 +    }
 +    else
 +    {
 +        // Parse parameters
 +        CDataStream ssBlock(ParseHex(params[0].get_str()));
 +        CBlock pblock;
 +        ssBlock >> pblock;
 +
 +        return ProcessBlock(NULL, &pblock);
 +    }
 +}
 +
 +
  
  
  
@@@ -1837,13 -1640,20 +1837,13 @@@ pair<string, rpcfn_type> pCallTable[] 
      make_pair("getnewaddress",          &getnewaddress),
      make_pair("getaccountaddress",      &getaccountaddress),
      make_pair("setaccount",             &setaccount),
 -    make_pair("setlabel",               &setaccount), // deprecated
      make_pair("getaccount",             &getaccount),
 -    make_pair("getlabel",               &getaccount), // deprecated
      make_pair("getaddressesbyaccount",  &getaddressesbyaccount),
 -    make_pair("getaddressesbylabel",    &getaddressesbyaccount), // deprecated
      make_pair("sendtoaddress",          &sendtoaddress),
 -    make_pair("getamountreceived",      &getreceivedbyaddress), // deprecated, renamed to getreceivedbyaddress
 -    make_pair("getallreceived",         &listreceivedbyaddress), // deprecated, renamed to listreceivedbyaddress
      make_pair("getreceivedbyaddress",   &getreceivedbyaddress),
      make_pair("getreceivedbyaccount",   &getreceivedbyaccount),
 -    make_pair("getreceivedbylabel",     &getreceivedbyaccount), // deprecated
      make_pair("listreceivedbyaddress",  &listreceivedbyaddress),
      make_pair("listreceivedbyaccount",  &listreceivedbyaccount),
 -    make_pair("listreceivedbylabel",    &listreceivedbyaccount), // deprecated
      make_pair("backupwallet",           &backupwallet),
      make_pair("keypoolrefill",          &keypoolrefill),
      make_pair("walletpassphrase",       &walletpassphrase),
      make_pair("sendmany",               &sendmany),
      make_pair("gettransaction",         &gettransaction),
      make_pair("listtransactions",       &listtransactions),
 +    make_pair("signmessage",           &signmessage),
 +    make_pair("verifymessage",         &verifymessage),
      make_pair("getwork",                &getwork),
      make_pair("listaccounts",           &listaccounts),
      make_pair("settxfee",               &settxfee),
 +    make_pair("getmemorypool",          &getmemorypool),
 +    make_pair("listsinceblock",        &listsinceblock),
  };
  map<string, rpcfn_type> mapCallTable(pCallTable, pCallTable + sizeof(pCallTable)/sizeof(pCallTable[0]));
  
@@@ -1872,7 -1678,7 +1872,7 @@@ string pAllowInSafeMode[] 
      "help",
      "stop",
      "getblockcount",
 -    "getblocknumber",
 +    "getblocknumber",  // deprecated
      "getconnectioncount",
      "getdifficulty",
      "getgenerate",
      "getinfo",
      "getnewaddress",
      "getaccountaddress",
 -    "setlabel", // deprecated
      "getaccount",
 -    "getlabel", // deprecated
      "getaddressesbyaccount",
 -    "getaddressesbylabel", // deprecated
      "backupwallet",
      "keypoolrefill",
      "walletpassphrase",
      "walletlock",
      "validateaddress",
      "getwork",
 +    "getmemorypool",
  };
  set<string> setAllowInSafeMode(pAllowInSafeMode, pAllowInSafeMode + sizeof(pAllowInSafeMode)/sizeof(pAllowInSafeMode[0]));
  
@@@ -1911,7 -1719,6 +1911,7 @@@ string HTTPPost(const string& strMsg, c
        << "Host: 127.0.0.1\r\n"
        << "Content-Type: application/json\r\n"
        << "Content-Length: " << strMsg.size() << "\r\n"
 +      << "Connection: close\r\n"
        << "Accept: application/json\r\n";
      BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapRequestHeaders)
          s << item.first << ": " << item.second << "\r\n";
@@@ -1952,13 -1759,12 +1952,13 @@@ static string HTTPReply(int nStatus, co
              "</HEAD>\r\n"
              "<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
              "</HTML>\r\n", rfc1123Time().c_str(), FormatFullVersion().c_str());
 -    string strStatus;
 -         if (nStatus == 200) strStatus = "OK";
 -    else if (nStatus == 400) strStatus = "Bad Request";
 -    else if (nStatus == 403) strStatus = "Forbidden";
 -    else if (nStatus == 404) strStatus = "Not Found";
 -    else if (nStatus == 500) strStatus = "Internal Server Error";
 +    const char *cStatus;
 +         if (nStatus == 200) cStatus = "OK";
 +    else if (nStatus == 400) cStatus = "Bad Request";
 +    else if (nStatus == 403) cStatus = "Forbidden";
 +    else if (nStatus == 404) cStatus = "Not Found";
 +    else if (nStatus == 500) cStatus = "Internal Server Error";
 +    else cStatus = "";
      return strprintf(
              "HTTP/1.1 %d %s\r\n"
              "Date: %s\r\n"
              "\r\n"
              "%s",
          nStatus,
 -        strStatus.c_str(),
 +        cStatus,
          rfc1123Time().c_str(),
          strMsg.size(),
          FormatFullVersion().c_str(),
@@@ -2036,6 -1842,43 +2036,6 @@@ int ReadHTTP(std::basic_istream<char>& 
      return nStatus;
  }
  
 -string EncodeBase64(string s)
 -{
 -    BIO *b64, *bmem;
 -    BUF_MEM *bptr;
 -
 -    b64 = BIO_new(BIO_f_base64());
 -    BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
 -    bmem = BIO_new(BIO_s_mem());
 -    b64 = BIO_push(b64, bmem);
 -    BIO_write(b64, s.c_str(), s.size());
 -    BIO_flush(b64);
 -    BIO_get_mem_ptr(b64, &bptr);
 -
 -    string result(bptr->data, bptr->length);
 -    BIO_free_all(b64);
 -
 -    return result;
 -}
 -
 -string DecodeBase64(string s)
 -{
 -    BIO *b64, *bmem;
 -
 -    char* buffer = static_cast<char*>(calloc(s.size(), sizeof(char)));
 -
 -    b64 = BIO_new(BIO_f_base64());
 -    BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
 -    bmem = BIO_new_mem_buf(const_cast<char*>(s.c_str()), s.size());
 -    bmem = BIO_push(b64, bmem);
 -    BIO_read(bmem, buffer, s.size());
 -    BIO_free_all(bmem);
 -
 -    string result(buffer);
 -    free(buffer);
 -    return result;
 -}
 -
  bool HTTPAuthorized(map<string, string>& mapHeaders)
  {
      string strAuth = mapHeaders["authorization"];
          return false;
      string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64);
      string strUserPass = DecodeBase64(strUserPass64);
 -    string::size_type nColon = strUserPass.find(":");
 -    if (nColon == string::npos)
 -        return false;
 -    string strUser = strUserPass.substr(0, nColon);
 -    string strPassword = strUserPass.substr(nColon+1);
 -    return (strUser == mapArgs["-rpcuser"] && strPassword == mapArgs["-rpcpassword"]);
 +    return strUserPass == strRPCUserColonPass;
  }
  
  //
@@@ -2172,16 -2020,11 +2172,16 @@@ void ThreadRPCServer(void* parg
      printf("ThreadRPCServer exiting\n");
  }
  
 +#ifdef QT_GUI
 +extern bool HACK_SHUTDOWN;
 +#endif
 +
  void ThreadRPCServer2(void* parg)
  {
      printf("ThreadRPCServer started\n");
  
 -    if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
 +    strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
 +    if (strRPCUserColonPass == ":")
      {
          unsigned char rand_pwd[32];
          RAND_bytes(rand_pwd, 32);
              strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
          else if (mapArgs.count("-daemon"))
              strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
 -        PrintConsole(
 -            _("Warning: %s, you must set a rpcpassword in the configuration file:\n %s\n"
 +        ThreadSafeMessageBox(strprintf(
 +            _("Error: %s, you must set a rpcpassword in the configuration file:\n %s\n"
                "It is recommended you use the following random password:\n"
                "rpcuser=bitcoinrpc\n"
                "rpcpassword=%s\n"
                "If the file does not exist, create it with owner-readable-only file permissions.\n"),
                  strWhatAmI.c_str(),
                  GetConfigFile().c_str(),
 -                EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32).c_str());
 +                EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32).c_str()),
 +            _("Error"), wxOK | wxMODAL);
 +#ifndef QT_GUI
          CreateThread(Shutdown, NULL);
 +#endif
          return;
      }
  
  
      asio::io_service io_service;
      ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", 8332));
 +#ifndef QT_GUI
      ip::tcp::acceptor acceptor(io_service, endpoint);
  
      acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
 +#else
 +    ip::tcp::acceptor acceptor(io_service);
 +    try
 +    {
 +        acceptor.open(endpoint.protocol());
 +        acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
 +        acceptor.bind(endpoint);
 +        acceptor.listen(socket_base::max_connections);
 +    }
 +    catch(system::system_error &e)
 +    {
 +        HACK_SHUTDOWN = true;
 +        ThreadSafeMessageBox(strprintf(_("An error occured while setting up the RPC port %i for listening: %s"), endpoint.port(), e.what()),
 +                             _("Error"), wxOK | wxMODAL);
 +        return;
 +    }
 +#endif
  
  #ifdef USE_SSL
      ssl::context context(io_service, ssl::context::sslv23);
              if (valMethod.type() != str_type)
                  throw JSONRPCError(-32600, "Method must be a string");
              string strMethod = valMethod.get_str();
 -            if (strMethod != "getwork")
 +            if (strMethod != "getwork" && strMethod != "getmemorypool")
                  printf("ThreadRPCServer method=%s\n", strMethod.c_str());
  
              // Parse params
@@@ -2503,12 -2325,18 +2503,12 @@@ int CommandLineRPC(int argc, char *argv
          if (strMethod == "setgenerate"            && n > 1) ConvertTo<boost::int64_t>(params[1]);
          if (strMethod == "sendtoaddress"          && n > 1) ConvertTo<double>(params[1]);
          if (strMethod == "settxfee"               && n > 0) ConvertTo<double>(params[0]);
 -        if (strMethod == "getamountreceived"      && n > 1) ConvertTo<boost::int64_t>(params[1]); // deprecated
          if (strMethod == "getreceivedbyaddress"   && n > 1) ConvertTo<boost::int64_t>(params[1]);
          if (strMethod == "getreceivedbyaccount"   && n > 1) ConvertTo<boost::int64_t>(params[1]);
 -        if (strMethod == "getreceivedbylabel"     && n > 1) ConvertTo<boost::int64_t>(params[1]); // deprecated
 -        if (strMethod == "getallreceived"         && n > 0) ConvertTo<boost::int64_t>(params[0]); // deprecated
 -        if (strMethod == "getallreceived"         && n > 1) ConvertTo<bool>(params[1]); // deprecated
          if (strMethod == "listreceivedbyaddress"  && n > 0) ConvertTo<boost::int64_t>(params[0]);
          if (strMethod == "listreceivedbyaddress"  && n > 1) ConvertTo<bool>(params[1]);
          if (strMethod == "listreceivedbyaccount"  && n > 0) ConvertTo<boost::int64_t>(params[0]);
          if (strMethod == "listreceivedbyaccount"  && n > 1) ConvertTo<bool>(params[1]);
 -        if (strMethod == "listreceivedbylabel"    && n > 0) ConvertTo<boost::int64_t>(params[0]); // deprecated
 -        if (strMethod == "listreceivedbylabel"    && n > 1) ConvertTo<bool>(params[1]); // deprecated
          if (strMethod == "getbalance"             && n > 1) ConvertTo<boost::int64_t>(params[1]);
          if (strMethod == "move"                   && n > 2) ConvertTo<double>(params[2]);
          if (strMethod == "move"                   && n > 3) ConvertTo<boost::int64_t>(params[3]);
          if (strMethod == "listtransactions"       && n > 2) ConvertTo<boost::int64_t>(params[2]);
          if (strMethod == "listaccounts"           && n > 0) ConvertTo<boost::int64_t>(params[0]);
          if (strMethod == "walletpassphrase"       && n > 1) ConvertTo<boost::int64_t>(params[1]);
 +        if (strMethod == "listsinceblock"         && n > 1) ConvertTo<boost::int64_t>(params[1]);
          if (strMethod == "sendmany"               && n > 1)
          {
              string s = params[1].get_str();
  
      if (strPrint != "")
      {
 -#if defined(__WXMSW__) && defined(GUI)
 -        // Windows GUI apps can't print to command line,
 -        // so settle for a message box yuck
 -        MyMessageBox(strPrint, "Bitcoin", wxOK);
 -#else
          fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
 -#endif
      }
      return nRet;
  }
diff --combined src/crypter.cpp
@@@ -7,7 -7,7 +7,7 @@@
  #include <vector>
  #include <string>
  #include "headers.h"
 -#ifdef __WXMSW__
 +#ifdef WIN32
  #include <windows.h>
  #endif
  
@@@ -15,7 -15,7 +15,7 @@@
  #include "main.h"
  #include "util.h"
  
 -bool CCrypter::SetKeyFromPassphrase(const std::string& strKeyData, const std::vector<unsigned char>& chSalt, const unsigned int nRounds, const unsigned int nDerivationMethod)
 +bool CCrypter::SetKeyFromPassphrase(const SecureString& strKeyData, const std::vector<unsigned char>& chSalt, const unsigned int nRounds, const unsigned int nDerivationMethod)
  {
      if (nRounds < 1 || chSalt.size() != WALLET_CRYPTO_SALT_SIZE)
          return false;
@@@ -31,7 -31,7 +31,7 @@@
          i = EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha512(), &chSalt[0],
                            (unsigned char *)&strKeyData[0], strKeyData.size(), nRounds, chKey, chIV);
  
-     if (i != WALLET_CRYPTO_KEY_SIZE)
+     if (i != (int)WALLET_CRYPTO_KEY_SIZE)
      {
          memset(&chKey, 0, sizeof chKey);
          memset(&chIV, 0, sizeof chIV);
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
@@@ -169,11 -93,6 +169,11 @@@ protected
      EC_KEY* pkey;
      bool fSet;
  
 +    void SetCompressedPubKey()
 +    {
 +        EC_KEY_set_conv_form(pkey, POINT_CONVERSION_COMPRESSED);
 +    }
 +
  public:
      CKey()
      {
  
      CPrivKey GetPrivKey() const
      {
-         unsigned int nSize = i2d_ECPrivateKey(pkey, NULL);
+         int nSize = i2d_ECPrivateKey(pkey, NULL);
          if (!nSize)
              throw key_error("CKey::GetPrivKey() : i2d_ECPrivateKey failed");
          CPrivKey vchPrivKey(nSize, 0);
  
      std::vector<unsigned char> GetPubKey() const
      {
-         unsigned int nSize = i2o_ECPublicKey(pkey, NULL);
+         int nSize = i2o_ECPublicKey(pkey, NULL);
          if (!nSize)
              throw key_error("CKey::GetPubKey() : i2o_ECPublicKey failed");
          std::vector<unsigned char> vchPubKey(nSize, 0);
          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;
 +        int nV = vchSig[0];
 +        if (nV<27 || nV>=35)
 +            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 (nV >= 31)
 +        {
 +            SetCompressedPubKey();
 +            nV -= 4;
 +        }
 +        if (ECDSA_SIG_recover_key_GFp(pkey, sig, (unsigned char*)&hash, sizeof(hash), nV - 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());
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)
@@@ -321,24 -314,24 +321,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;
@@@ -375,7 -368,7 +375,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)
  
      // Check for conflicts with in-memory transactions
      CTransaction* ptxOld = NULL;
-     for (int i = 0; i < vin.size(); i++)
+     for (unsigned int i = 0; i < vin.size(); i++)
      {
          COutPoint outpoint = vin[i].prevout;
          if (mapNextTx.count(outpoint))
                  return false;
              if (!IsNewerThan(*ptxOld))
                  return false;
-             for (int i = 0; i < vin.size(); i++)
+             for (unsigned int i = 0; i < vin.size(); i++)
              {
                  COutPoint outpoint = vin[i].prevout;
                  if (!mapNextTx.count(outpoint) || mapNextTx[outpoint].ptx != ptxOld)
          // 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");
  
          int64 nFees = GetValueIn(mapInputs)-GetValueOut();
  
@@@ -518,7 -511,7 +518,7 @@@ bool CTransaction::AddToMemoryPoolUnche
      {
          uint256 hash = GetHash();
          mapTransactions[hash] = *this;
-         for (int i = 0; i < vin.size(); i++)
+         for (unsigned int i = 0; i < vin.size(); i++)
              mapNextTx[vin[i].prevout] = CInPoint(&mapTransactions[hash], i);
          nTransactionsUpdated++;
      }
@@@ -795,15 -788,9 +795,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;
@@@ -897,7 -884,7 +897,7 @@@ bool CTransaction::FetchInputs(CTxDB& t
      if (IsCoinBase())
          return true; // Coinbase transactions have no inputs to fetch.
  
-     for (int i = 0; i < vin.size(); i++)
+     for (unsigned int i = 0; i < vin.size(); i++)
      {
          COutPoint prevout = vin[i].prevout;
          if (inputsRet.count(prevout.hash))
      }
  
      // Make sure all prevout.n's are valid:
-     for (int i = 0; i < vin.size(); i++)
+     for (unsigned int i = 0; i < vin.size(); i++)
      {
          const COutPoint prevout = vin[i].prevout;
          assert(inputsRet.count(prevout.hash) != 0);
              // Revisit this if/when transaction replacement is implemented and allows
              // adding inputs:
              fInvalid = true;
 -            return error("FetchInputs() : %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("FetchInputs() : %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()));
          }
      }
  
@@@ -979,7 -966,7 +979,7 @@@ int64 CTransaction::GetValueIn(const Ma
          return 0;
  
      int64 nResult = 0;
-     for (int i = 0; i < vin.size(); i++)
+     for (unsigned int i = 0; i < vin.size(); i++)
      {
          nResult += GetOutputFor(vin[i], inputs).nValue;
      }
@@@ -993,7 -980,7 +993,7 @@@ int CTransaction::GetP2SHSigOpCount(con
          return 0;
  
      int nSigOps = 0;
-     for (int i = 0; i < vin.size(); i++)
+     for (unsigned int i = 0; i < vin.size(); i++)
      {
          const CTxOut& prevout = GetOutputFor(vin[i], inputs);
          if (prevout.scriptPubKey.IsPayToScriptHash())
@@@ -1014,7 -1001,7 +1014,7 @@@ bool CTransaction::ConnectInputs(MapPre
      {
          int64 nValueIn = 0;
          int64 nFees = 0;
-         for (int i = 0; i < vin.size(); i++)
+         for (unsigned int i = 0; i < vin.size(); i++)
          {
              COutPoint prevout = vin[i].prevout;
              assert(inputs.count(prevout.hash) > 0);
              CTransaction& txPrev = inputs[prevout.hash].second;
  
              if (prevout.n >= txPrev.vout.size() || prevout.n >= txindex.vSpent.size())
 -                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())
                          return error("ConnectInputs() : tried to spend coinbase at depth %d", pindexBlock->nHeight - pindex->nHeight);
  
              // 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"));
  
 -            // Verify signature
 -            if (!VerifySignature(txPrev, *this, i, fStrictPayToScriptHash, 0))
 +            // 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())))
              {
 -                // only during transition phase for P2SH: do not invoke (external)
 -                // anti-DoS code for potentially old clients relaying bad P2SH
 -                // transactions
 -                if (fStrictPayToScriptHash && VerifySignature(txPrev, *this, i, false, 0))
 -                    return error("ConnectInputs() : %s P2SH VerifySignature failed", GetHash().ToString().substr(0,10).c_str());
 +                // Verify signature
 +                if (!VerifySignature(txPrev, *this, i, fStrictPayToScriptHash, 0))
 +                {
 +                    // only during transition phase for P2SH: do not invoke anti-DoS code for
 +                    // potentially old clients relaying bad P2SH transactions
 +                    if (fStrictPayToScriptHash && VerifySignature(txPrev, *this, i, false, 0))
 +                        return error("ConnectInputs() : %s P2SH VerifySignature failed", GetHash().ToString().substr(0,10).c_str());
  
 -                return error("ConnectInputs() : %s VerifySignature failed", GetHash().ToString().substr(0,10).c_str());
 +                    return DoS(100,error("ConnectInputs() : %s VerifySignature failed", GetHash().ToString().substr(0,10).c_str()));
 +                }
              }
  
              // Mark outpoints as spent
          }
  
          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()));
          nFees += nTxFee;
          if (!MoneyRange(nFees))
 -            return error("ConnectInputs() : nFees out of range");
 +            return DoS(100, error("ConnectInputs() : nFees out of range"));
      }
  
      return true;
@@@ -1093,7 -1073,7 +1093,7 @@@ bool CTransaction::ClientConnectInputs(
      CRITICAL_BLOCK(cs_mapTransactions)
      {
          int64 nValueIn = 0;
-         for (int i = 0; i < vin.size(); i++)
+         for (unsigned int i = 0; i < vin.size(); i++)
          {
              // Get prev tx from single transactions in memory
              COutPoint prevout = vin[i].prevout;
@@@ -1196,7 -1176,7 +1196,7 @@@ bool CBlock::ConnectBlock(CTxDB& txdb, 
      {
          nSigOps += tx.GetSigOpCount();
          if (nSigOps > MAX_BLOCK_SIGOPS)
 -            return error("ConnectBlock() : too many sigops");
 +            return DoS(100, error("ConnectBlock() : too many sigops"));
  
          CDiskTxPos posThisTx(pindex->nFile, pindex->nBlockPos, nTxPos);
          nTxPos += ::GetSerializeSize(tx, SER_DISK);
                  // an incredibly-expensive-to-validate block.
                  nSigOps += tx.GetP2SHSigOpCount(mapInputs);
                  if (nSigOps > MAX_BLOCK_SIGOPS)
 -                    return error("ConnectBlock() : too many sigops");
 +                    return DoS(100, error("ConnectBlock() : too many sigops"));
              }
  
              nFees += tx.GetValueIn(mapInputs)-tx.GetValueOut();
@@@ -1304,7 -1284,7 +1304,7 @@@ bool static Reorganize(CTxDB& txdb, CBl
  
      // Connect longer branch
      vector<CTransaction> vDelete;
-     for (int i = 0; i < vConnect.size(); i++)
+     for (unsigned int i = 0; i < vConnect.size(); i++)
      {
          CBlockIndex* pindex = vConnect[i];
          CBlock block;
@@@ -1470,11 -1450,11 +1470,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++)
+     for (unsigned 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() : out-of-bounds SigOpCount");
 +        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;
  }
@@@ -1513,13 -1493,13 +1513,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, 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)
          {
 +            if (pfrom)
 +                pfrom->Misbehaving(100);
              return error("ProcessBlock() : block with timestamp before last checkpoint");
          }
          CBigNum bnNewBlock;
          bnRequired.SetCompact(ComputeMinWork(pcheckpoint->nBits, deltaTime));
          if (bnNewBlock > bnRequired)
          {
 +            if (pfrom)
 +                pfrom->Misbehaving(100);
              return error("ProcessBlock() : block with too little proof-of-work");
          }
      }
      // Recursively process any orphan blocks that depended on this one
      vector<uint256> vWorkQueue;
      vWorkQueue.push_back(hash);
-     for (int i = 0; i < vWorkQueue.size(); i++)
+     for (unsigned int i = 0; i < vWorkQueue.size(); i++)
      {
          uint256 hashPrev = vWorkQueue[i];
          for (multimap<uint256, CBlock*>::iterator mi = mapOrphanBlocksByPrev.lower_bound(hashPrev);
@@@ -1837,7 -1813,7 +1837,7 @@@ void PrintBlockTree(
  
          // put the main timechain first
          vector<CBlockIndex*>& vNext = mapNext[pindex];
-         for (int i = 0; i < vNext.size(); i++)
+         for (unsigned int i = 0; i < vNext.size(); i++)
          {
              if (vNext[i]->pnext)
              {
          }
  
          // iterate children
-         for (int i = 0; i < vNext.size(); i++)
+         for (unsigned int i = 0; i < vNext.size(); i++)
              vStack.push_back(make_pair(nCol+i, vNext[i]));
      }
  }
@@@ -1977,7 -1953,18 +1977,18 @@@ bool static AlreadyHave(CTxDB& txdb, co
  {
      switch (inv.type)
      {
-     case MSG_TX:    return mapTransactions.count(inv.hash) || mapOrphanTransactions.count(inv.hash) || txdb.ContainsTx(inv.hash);
+     case MSG_TX:
+         {
+         bool txInMap = false;
+         CRITICAL_BLOCK(cs_mapTransactions)
+         {
+             txInMap = (mapTransactions.count(inv.hash) != 0);
+         }
+         return txInMap ||
+                mapOrphanTransactions.count(inv.hash) ||
+                txdb.ContainsTx(inv.hash);
+         }
      case MSG_BLOCK: return mapBlockIndex.count(inv.hash) || mapOrphanBlocks.count(inv.hash);
      }
      // Don't know what it is, just say we already got one
@@@ -2015,10 -2002,7 +2026,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)
          {
              vWorkQueue.push_back(inv.hash);
  
              // Recursively process any orphan transactions that depended on this one
-             for (int i = 0; i < vWorkQueue.size(); i++)
+             for (unsigned int i = 0; i < vWorkQueue.size(); i++)
              {
                  uint256 hashPrev = vWorkQueue[i];
                  for (multimap<uint256, CDataStream*>::iterator mi = mapOrphanTransactionsByPrev.lower_bound(hashPrev);
              if (nEvicted > 0)
                  printf("mapOrphan overflow, removed %d tx\n", nEvicted);
          }
 +        if (tx.nDoS) pfrom->Misbehaving(tx.nDoS);
      }
  
  
  
          if (ProcessBlock(pfrom, &block))
              mapAlreadyAskedFor.erase(inv);
 +        if (block.nDoS) pfrom->Misbehaving(block.nDoS);
      }
  
  
@@@ -2648,7 -2618,7 +2659,7 @@@ bool ProcessMessages(CNode* pfrom
  
  bool SendMessages(CNode* pto, bool fSendTrickle)
  {
-     CRITICAL_BLOCK(cs_main)
+     TRY_CRITICAL_BLOCK(cs_main)
      {
          // Don't send anything until we get their version message
          if (pto->nVersion == 0)
@@@ -2860,25 -2830,15 +2871,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];
  }
  
  //
@@@ -3152,7 -3112,7 +3163,7 @@@ void FormatHashBuffers(CBlock* pblock, 
      FormatHashBlocks(&tmp.hash1, sizeof(tmp.hash1));
  
      // Byte swap all the input buffer
-     for (int i = 0; i < sizeof(tmp)/4; i++)
+     for (unsigned int i = 0; i < sizeof(tmp)/4; i++)
          ((unsigned int*)&tmp)[i] = ByteReverse(((unsigned int*)&tmp)[i]);
  
      // Precalc the first half of the first hash, which stays constant
@@@ -3196,6 -3156,7 +3207,6 @@@ bool CheckWork(CBlock* pblock, CWallet
              return error("BitcoinMiner : ProcessBlock, block not accepted");
      }
  
 -    Sleep(2000);
      return true;
  }
  
@@@ -3273,7 -3234,7 +3284,7 @@@ void static BitcoinMiner(CWallet *pwall
              // Check if something found
              if (nNonceFound != -1)
              {
-                 for (int i = 0; i < sizeof(hash)/4; i++)
+                 for (unsigned int i = 0; i < sizeof(hash)/4; i++)
                      ((unsigned int*)&hash)[i] = ByteReverse(((unsigned int*)&hash)[i]);
  
                  if (hash <= hashTarget)
diff --combined src/main.h
@@@ -86,7 -86,6 +86,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);
@@@ -101,7 -100,6 +101,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);
  
@@@ -403,9 -401,6 +403,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
      {
          if (vin.size() != old.vin.size())
              return false;
-         for (int i = 0; i < vin.size(); i++)
+         for (unsigned int i = 0; i < vin.size(); i++)
              if (vin[i].prevout != old.vin[i].prevout)
                  return false;
  
          bool fNewer = false;
          unsigned int nLowest = UINT_MAX;
-         for (int i = 0; i < vin.size(); i++)
+         for (unsigned int i = 0; i < vin.size(); i++)
          {
              if (vin[i].nSequence != old.vin[i].nSequence)
              {
              vin.size(),
              vout.size(),
              nLockTime);
-         for (int i = 0; i < vin.size(); i++)
+         for (unsigned int i = 0; i < vin.size(); i++)
              str += "    " + vin[i].ToString() + "\n";
-         for (int i = 0; i < vout.size(); i++)
+         for (unsigned int i = 0; i < vout.size(); i++)
              str += "    " + vout[i].ToString() + "\n";
          return str;
      }
@@@ -843,9 -837,6 +843,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));
              hashMerkleRoot.ToString().substr(0,10).c_str(),
              nTime, nBits, nNonce,
              vtx.size());
-         for (int i = 0; i < vtx.size(); i++)
+         for (unsigned int i = 0; i < vtx.size(); i++)
          {
              printf("  ");
              vtx[i].print();
          }
          printf("  vMerkleTree: ");
-         for (int i = 0; i < vMerkleTree.size(); i++)
+         for (unsigned int i = 0; i < vMerkleTree.size(); i++)
              printf("%s ", vMerkleTree[i].ToString().substr(0,10).c_str());
          printf("\n");
      }
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
@@@ -316,14 -316,14 +316,14 @@@ bool GetMyExternalIP2(const CAddress& a
                  }
                  if (pszKeyword == NULL)
                      break;
-                 if (strLine.find(pszKeyword) != -1)
+                 if (strLine.find(pszKeyword) != string::npos)
                  {
                      strLine = strLine.substr(strLine.find(pszKeyword) + strlen(pszKeyword));
                      break;
                  }
              }
              closesocket(hSocket);
-             if (strLine.find("<") != -1)
+             if (strLine.find("<") != string::npos)
                  strLine = strLine.substr(0, strLine.find("<"));
              strLine = strLine.substr(strspn(strLine.c_str(), " \t\n\r"));
              while (strLine.size() > 0 && isspace(strLine[strLine.size()-1]))
@@@ -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());
@@@ -732,52 -732,6 +732,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;
 +}
 +
  
  
  
@@@ -915,7 -869,7 +915,7 @@@ void ThreadSocketHandler2(void* parg
              if (hSocketMax > -1)
              {
                  printf("socket select error %d\n", nErr);
-                 for (int i = 0; i <= hSocketMax; i++)
+                 for (unsigned int i = 0; i <= hSocketMax; i++)
                      FD_SET(i, &fdsetRecv);
              }
              FD_ZERO(&fdsetSend);
              {
                  closesocket(hSocket);
              }
 +            else if (CNode::IsBanned(addr.ip))
 +            {
 +                printf("connection from %s dropped (banned)\n", addr.ToString().c_str());
 +                closesocket(hSocket);
 +            }
              else
              {
                  printf("accepted connection %s\n", addr.ToString().c_str());
@@@ -1303,7 -1252,7 +1303,7 @@@ void ThreadDNSAddressSeed2(void* parg
      {
          printf("Loading addresses from DNS seeds (could take a while)\n");
  
-         for (int seed_idx = 0; seed_idx < ARRAYLEN(strDNSSeed); seed_idx++) {
+         for (unsigned int seed_idx = 0; seed_idx < ARRAYLEN(strDNSSeed); seed_idx++) {
              vector<CAddress> vaddr;
              if (Lookup(strDNSSeed[seed_idx], vaddr, NODE_NETWORK, -1, true))
              {
@@@ -1520,7 -1469,7 +1520,7 @@@ void ThreadOpenConnections2(void* parg
  
          if (fAddSeeds)
          {
-             for (int i = 0; i < ARRAYLEN(pnSeed); i++)
+             for (unsigned int i = 0; i < ARRAYLEN(pnSeed); i++)
              {
                  // It'll only connect to one or two seed nodes because once it connects,
                  // it'll get a pile of addresses with newer timestamps.
              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);
@@@ -1616,8 -1563,7 +1616,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]--;
@@@ -1721,7 -1667,7 +1721,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
@@@ -1800,7 -1746,7 +1800,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)
@@@ -1943,7 -1889,7 +1943,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
diff --combined src/net.h
+++ b/src/net.h
@@@ -10,7 -10,7 +10,7 @@@
  #include <boost/foreach.hpp>
  #include <openssl/rand.h>
  
 -#ifndef __WXMSW__
 +#ifndef WIN32
  #include <arpa/inet.h>
  #endif
  
@@@ -111,7 -111,7 +111,7 @@@ public
      int64 nLastRecv;
      int64 nLastSendEmpty;
      int64 nTimeConnected;
-     unsigned int nHeaderStart;
+     signed int nHeaderStart;
      unsigned int nMessageStart;
      CAddress addr;
      int nVersion;
      bool fDisconnect;
  protected:
      int nRefCount;
 +
 +    // Denial-of-service detection/prevention
 +    // Key is ip address, value is banned-until-time
 +    static std::map<unsigned int, int64> setBanned;
 +    static CCriticalSection cs_setBanned;
 +    int nMisbehavior;
 +
  public:
      int64 nReleaseTime;
      std::map<uint256, CRequestTracker> mapRequests;
      // publish and subscription
      std::vector<char> vfSubscribe;
  
 -
      CNode(SOCKET hSocketIn, CAddress addrIn, bool fInboundIn=false)
      {
          nServices = 0;
          nStartingHeight = -1;
          fGetAddr = false;
          vfSubscribe.assign(256, false);
 +        nMisbehavior = 0;
  
          // Be shy and don't send version until we hear
          if (!fInbound)
@@@ -576,25 -569,6 +576,25 @@@ public
      void CancelSubscribe(unsigned int nChannel);
      void CloseSocketDisconnect();
      void Cleanup();
 +
 +
 +    // Denial-of-service detection/prevention
 +    // The idea is to detect peers that are behaving
 +    // badly and disconnect/ban them, but do it in a
 +    // one-coding-mistake-won't-shatter-the-entire-network
 +    // way.
 +    // IMPORTANT:  There should be nothing I can give a
 +    // node that it will forward on that will make that
 +    // node's peers drop it. If there is, an attacker
 +    // can isolate a node and/or try to split the network.
 +    // Dropping a node for sending stuff that is invalid
 +    // now but might be valid in a later version is also
 +    // dangerous, because it can cause a network split
 +    // between nodes running old code and nodes running
 +    // new code.
 +    static void ClearBanned(); // needed for unit testing
 +    static bool IsBanned(unsigned int ip);
 +    bool Misbehaving(int howmuch); // 1 == a little, 100 == a lot
  };
  
  
diff --combined src/protocol.cpp
@@@ -6,7 -6,7 +6,7 @@@
  #include "protocol.h"
  #include "util.h"
  
 -#ifndef __WXMSW__
 +#ifndef WIN32
  # include <arpa/inet.h>
  #endif
  
@@@ -270,7 -270,7 +270,7 @@@ CInv::CInv(int typeIn, const uint256& h
  
  CInv::CInv(const std::string& strType, const uint256& hashIn)
  {
-     int i;
+     unsigned int i;
      for (i = 1; i < ARRAYLEN(ppszTypeName); i++)
      {
          if (strType == ppszTypeName[i])
diff --combined src/util.cpp
@@@ -75,7 -75,7 +75,7 @@@ public
              ppmutexOpenSSL[i] = new boost::interprocess::interprocess_mutex();
          CRYPTO_set_locking_callback(locking_callback);
  
 -#ifdef __WXMSW__
 +#ifdef WIN32
          // Seed random number generator with screen scrape and other hardware sources
          RAND_screen();
  #endif
@@@ -119,7 -119,7 +119,7 @@@ void RandAddSeedPerfmon(
          return;
      nLastPerfmon = GetTime();
  
 -#ifdef __WXMSW__
 +#ifdef WIN32
      // Don't need this on Linux, OpenSSL automatically uses /dev/urandom
      // Seed with the entire set of perfmon data
      unsigned char pdata[250000];
@@@ -209,7 -209,7 +209,7 @@@ inline int OutputDebugStringF(const cha
          }
      }
  
 -#ifdef __WXMSW__
 +#ifdef WIN32
      if (fPrintToDebugger)
      {
          static CCriticalSection cs_OutputDebugStringF;
@@@ -275,7 -275,8 +275,7 @@@ int my_snprintf(char* buffer, size_t li
      return ret;
  }
  
 -
 -string strprintf(const char* format, ...)
 +string strprintf(const std::string &format, ...)
  {
      char buffer[50000];
      char* p = buffer;
      {
          va_list arg_ptr;
          va_start(arg_ptr, format);
 -        ret = _vsnprintf(p, limit, format, arg_ptr);
 +        ret = _vsnprintf(p, limit, format.c_str(), arg_ptr);
          va_end(arg_ptr);
          if (ret >= 0 && ret < limit)
              break;
      return str;
  }
  
 -
 -bool error(const char* format, ...)
 +bool error(const std::string &format, ...)
  {
      char buffer[50000];
      int limit = sizeof(buffer);
      va_list arg_ptr;
      va_start(arg_ptr, format);
 -    int ret = _vsnprintf(buffer, limit, format, arg_ptr);
 +    int ret = _vsnprintf(buffer, limit, format.c_str(), arg_ptr);
      va_end(arg_ptr);
      if (ret < 0 || ret >= limit)
      {
@@@ -412,14 -414,14 +412,14 @@@ bool ParseMoney(const char* pszIn, int6
  
  vector<unsigned char> ParseHex(const char* psz)
  {
-     static char phexdigit[256] =
+     static signed char phexdigit[256] =
      { -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
        -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
        -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
        0,1,2,3,4,5,6,7,8,9,-1,-1,-1,-1,-1,-1,
        -1,0xa,0xb,0xc,0xd,0xe,0xf,-1,-1,-1,-1,-1,-1,-1,-1,-1,
        -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-       -1,0xa,0xb,0xc,0xd,0xe,0xf,-1,-1,-1,-1,-1,-1,-1,-1,-1
+       -1,0xa,0xb,0xc,0xd,0xe,0xf,-1,-1,-1,-1,-1,-1,-1,-1,-1,
        -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
        -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
        -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
      {
          while (isspace(*psz))
              psz++;
-         char c = phexdigit[(unsigned char)*psz++];
-         if (c == (char)-1)
+         signed char c = phexdigit[(unsigned char)*psz++];
+         if (c == (signed char)-1)
              break;
          unsigned char n = (c << 4);
          c = phexdigit[(unsigned char)*psz++];
-         if (c == (char)-1)
+         if (c == (signed char)-1)
              break;
          n |= c;
          vch.push_back(n);
@@@ -454,6 -456,7 +454,6 @@@ vector<unsigned char> ParseHex(const st
      return ParseHex(str.c_str());
  }
  
 -
  void ParseParameters(int argc, char* argv[])
  {
      mapArgs.clear();
              pszValue = strchr(psz, '=');
              *pszValue++ = '\0';
          }
 -        #ifdef __WXMSW__
 +        #ifdef WIN32
          _strlwr(psz);
          if (psz[0] == '/')
              psz[0] = '-';
@@@ -497,144 -500,39 +497,144 @@@ bool SoftSetArg(const std::string& strA
  }
  
  
 +string EncodeBase64(const unsigned char* pch, size_t len)
 +{
 +    static const char *pbase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
 +
 +    string strRet="";
 +    strRet.reserve((len+2)/3*4);
 +
 +    int mode=0, left=0;
 +    const unsigned char *pchEnd = pch+len;
  
 -const char* wxGetTranslation(const char* pszEnglish)
 +    while (pch<pchEnd)
 +    {
 +        int enc = *(pch++);
 +        switch (mode)
 +        {
 +            case 0: // we have no bits
 +                strRet += pbase64[enc >> 2];
 +                left = (enc & 3) << 4;
 +                mode = 1;
 +                break;
 +
 +            case 1: // we have two bits
 +                strRet += pbase64[left | (enc >> 4)];
 +                left = (enc & 15) << 2;
 +                mode = 2;
 +                break;
 +
 +            case 2: // we have four bits
 +                strRet += pbase64[left | (enc >> 6)];
 +                strRet += pbase64[enc & 63];
 +                mode = 0;
 +                break;
 +        }
 +    }
 +
 +    if (mode)
 +    {
 +        strRet += pbase64[left];
 +        strRet += '=';
 +        if (mode == 1)
 +            strRet += '=';
 +    }
 +
 +    return strRet;
 +}
 +
 +string EncodeBase64(const string& str)
  {
 -#ifdef GUI
 -    // Wrapper of wxGetTranslation returning the same const char* type as was passed in
 -    static CCriticalSection cs;
 -    CRITICAL_BLOCK(cs)
 +    return EncodeBase64((const unsigned char*)str.c_str(), str.size());
 +}
 +
 +vector<unsigned char> DecodeBase64(const char* p, bool* pfInvalid)
 +{
 +    static const int decode64_table[256] =
 +    {
 +        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 +        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 +        -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1,
 +        -1, -1, -1, -1, -1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
 +        15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28,
 +        29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
 +        49, 50, 51, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 +        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 +        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 +        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 +        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 +        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 +        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
 +    };
 +
 +    if (pfInvalid)
 +        *pfInvalid = false;
 +
 +    vector<unsigned char> vchRet;
 +    vchRet.reserve(strlen(p)*3/4);
 +
 +    int mode = 0;
 +    int left = 0;
 +
 +    while (1)
      {
 -        // Look in cache
 -        static map<string, char*> mapCache;
 -        map<string, char*>::iterator mi = mapCache.find(pszEnglish);
 -        if (mi != mapCache.end())
 -            return (*mi).second;
 -
 -        // wxWidgets translation
 -        wxString strTranslated = wxGetTranslation(wxString(pszEnglish, wxConvUTF8));
 -
 -        // We don't cache unknown strings because caller might be passing in a
 -        // dynamic string and we would keep allocating memory for each variation.
 -        if (strcmp(pszEnglish, strTranslated.utf8_str()) == 0)
 -            return pszEnglish;
 -
 -        // Add to cache, memory doesn't need to be freed.  We only cache because
 -        // we must pass back a pointer to permanently allocated memory.
 -        char* pszCached = new char[strlen(strTranslated.utf8_str())+1];
 -        strcpy(pszCached, strTranslated.utf8_str());
 -        mapCache[pszEnglish] = pszCached;
 -        return pszCached;
 +         int dec = decode64_table[(unsigned char)*p];
 +         if (dec == -1) break;
 +         p++;
 +         switch (mode)
 +         {
 +             case 0: // we have no bits and get 6
 +                 left = dec;
 +                 mode = 1;
 +                 break;
 +
 +              case 1: // we have 6 bits and keep 4
 +                  vchRet.push_back((left<<2) | (dec>>4));
 +                  left = dec & 15;
 +                  mode = 2;
 +                  break;
 +
 +             case 2: // we have 4 bits and get 6, we keep 2
 +                 vchRet.push_back((left<<4) | (dec>>2));
 +                 left = dec & 3;
 +                 mode = 3;
 +                 break;
 +
 +             case 3: // we have 2 bits and get 6
 +                 vchRet.push_back((left<<6) | dec);
 +                 mode = 0;
 +                 break;
 +         }
      }
 -    return NULL;
 -#else
 -    return pszEnglish;
 -#endif
 +
 +    if (pfInvalid)
 +        switch (mode)
 +        {
 +            case 0: // 4n base64 characters processed: ok
 +                break;
 +
 +            case 1: // 4n+1 base64 character processed: impossible
 +                *pfInvalid = true;
 +                break;
 +
 +            case 2: // 4n+2 base64 characters processed: require '=='
 +                if (left || p[0] != '=' || p[1] != '=' || decode64_table[(unsigned char)p[2]] != -1)
 +                    *pfInvalid = true;
 +                break;
 +
 +            case 3: // 4n+3 base64 characters processed: require '='
 +                if (left || p[0] != '=' || decode64_table[(unsigned char)p[1]] != -1)
 +                    *pfInvalid = true;
 +                break;
 +        }
 +
 +    return vchRet;
 +}
 +
 +string DecodeBase64(const string& str)
 +{
 +    vector<unsigned char> vchRet = DecodeBase64(str.c_str());
 +    return string((const char*)&vchRet[0], vchRet.size());
  }
  
  
@@@ -676,7 -574,7 +676,7 @@@ bool WildcardMatch(const string& str, c
  
  void FormatException(char* pszMessage, std::exception* pex, const char* pszThread)
  {
 -#ifdef __WXMSW__
 +#ifdef WIN32
      char pszModule[MAX_PATH];
      pszModule[0] = '\0';
      GetModuleFileNameA(NULL, pszModule, sizeof(pszModule));
@@@ -705,6 -603,10 +705,6 @@@ void PrintException(std::exception* pex
      printf("\n\n************************\n%s\n", pszMessage);
      fprintf(stderr, "\n\n************************\n%s\n", pszMessage);
      strMiscWarning = pszMessage;
 -#ifdef GUI
 -    if (wxTheApp && !fDaemon)
 -        MyMessageBox(pszMessage, "Bitcoin", wxOK | wxICON_ERROR);
 -#endif
      throw;
  }
  
@@@ -726,6 -628,10 +726,6 @@@ void PrintExceptionContinue(std::except
      printf("\n\n************************\n%s\n", pszMessage);
      fprintf(stderr, "\n\n************************\n%s\n", pszMessage);
      strMiscWarning = pszMessage;
 -#ifdef GUI
 -    if (wxTheApp && !fDaemon)
 -        boost::thread(boost::bind(ThreadOneMessageBox, string(pszMessage)));
 -#endif
  }
  
  
  
  
  
 -#ifdef __WXMSW__
 +#ifdef WIN32
  typedef WINSHELLAPI BOOL (WINAPI *PSHGETSPECIALFOLDERPATHA)(HWND hwndOwner, LPSTR lpszPath, int nFolder, BOOL fCreate);
  
  string MyGetSpecialFolderPath(int nFolder, bool fCreate)
@@@ -785,7 -691,7 +785,7 @@@ string GetDefaultDataDir(
      // Windows: C:\Documents and Settings\username\Application Data\Bitcoin
      // Mac: ~/Library/Application Support/Bitcoin
      // Unix: ~/.bitcoin
 -#ifdef __WXMSW__
 +#ifdef WIN32
      // Windows
      return MyGetSpecialFolderPath(CSIDL_APPDATA, true) + "\\Bitcoin";
  #else
      string strHome = pszHome;
      if (strHome[strHome.size()-1] != '/')
          strHome += '/';
 -#ifdef __WXMAC_OSX__
 +#ifdef MAC_OSX
      // Mac
      strHome += "Library/Application Support/";
      filesystem::create_directory(strHome.c_str());
@@@ -946,20 -852,11 +946,20 @@@ void ShrinkDebugFile(
  //  - Median of other nodes's clocks
  //  - The user (asking the user to fix the system clock if the first two disagree)
  //
 +static int64 nMockTime = 0;  // For unit testing
 +
  int64 GetTime()
  {
 +    if (nMockTime) return nMockTime;
 +
      return time(NULL);
  }
  
 +void SetMockTime(int64 nMockTimeIn)
 +{
 +    nMockTime = nMockTimeIn;
 +}
 +
  static int64 nTimeOffset = 0;
  
  int64 GetAdjustedTime()
diff --combined src/wallet.cpp
@@@ -5,6 -5,7 +5,6 @@@
  
  #include "headers.h"
  #include "db.h"
 -#include "cryptopp/sha.h"
  #include "crypter.h"
  
  using namespace std;
@@@ -42,7 -43,7 +42,7 @@@ bool CWallet::AddCryptedKey(const vecto
      return false;
  }
  
 -bool CWallet::Unlock(const string& strWalletPassphrase)
 +bool CWallet::Unlock(const SecureString& strWalletPassphrase)
  {
      if (!IsLocked())
          return false;
@@@ -63,7 -64,7 +63,7 @@@
      return false;
  }
  
 -bool CWallet::ChangeWalletPassphrase(const string& strOldWalletPassphrase, const string& strNewWalletPassphrase)
 +bool CWallet::ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, const SecureString& strNewWalletPassphrase)
  {
      bool fWasLocked = IsLocked();
  
@@@ -122,7 -123,7 +122,7 @@@ public
      )
  };
  
 -bool CWallet::EncryptWallet(const string& strWalletPassphrase)
 +bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
  {
      if (IsCrypted())
          return false;
@@@ -267,7 -268,7 +267,7 @@@ bool CWallet::AddToWallet(const CWallet
          if (fInsertedNew || fUpdated)
              if (!wtx.WriteToDisk())
                  return false;
 -
 +#ifndef QT_GUI
          // If default receiving address gets used, replace it with a new one
          CScript scriptDefaultKey;
          scriptDefaultKey.SetBitcoinAddress(vchDefaultKey);
                  }
              }
          }
 -
 +#endif
          // Notify UI
          vWalletUpdated.push_back(hash);
  
      return true;
  }
  
 +// Add a transaction to the wallet, or update it.
 +// pblock is optional, but should be provided if the transaction is known to be in a block.
 +// If fUpdate is true, existing transactions will be updated.
  bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate)
  {
      uint256 hash = tx.GetHash();
@@@ -514,7 -512,7 +514,7 @@@ void CWalletTx::AddSupportingTransactio
          {
              map<uint256, const CMerkleTx*> mapWalletPrev;
              set<uint256> setAlreadyDone;
-             for (int i = 0; i < vWorkQueue.size(); i++)
+             for (unsigned int i = 0; i < vWorkQueue.size(); i++)
              {
                  uint256 hash = vWorkQueue[i];
                  if (setAlreadyDone.count(hash))
@@@ -563,9 -561,6 +563,9 @@@ bool CWalletTx::WriteToDisk(
      return CWalletDB(pwallet->strWalletFile).WriteTx(GetHash(), *this);
  }
  
 +// Scan the block chain (starting in pindexStart) for transactions
 +// from or to us. If fUpdate is true, found transactions that already
 +// exist in the wallet will be updated.
  int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate)
  {
      int ret = 0;
@@@ -612,7 -607,7 +612,7 @@@ void CWallet::ReacceptWalletTransaction
                      printf("ERROR: ReacceptWalletTransactions() : txindex.vSpent.size() %d != wtx.vout.size() %d\n", txindex.vSpent.size(), wtx.vout.size());
                      continue;
                  }
-                 for (int i = 0; i < txindex.vSpent.size(); i++)
+                 for (unsigned int i = 0; i < txindex.vSpent.size(); i++)
                  {
                      if (wtx.IsSpent(i))
                          continue;
@@@ -743,21 -738,6 +743,21 @@@ int64 CWallet::GetBalance() cons
      return nTotal;
  }
  
 +int64 CWallet::GetUnconfirmedBalance() const
 +{
 +    int64 nTotal = 0;
 +    CRITICAL_BLOCK(cs_wallet)
 +    {
 +        for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
 +        {
 +            const CWalletTx* pcoin = &(*it).second;
 +            if (pcoin->IsFinal() && pcoin->IsConfirmed())
 +                continue;
 +            nTotal += pcoin->GetAvailableCredit();
 +        }
 +    }
 +    return nTotal;
 +}
  
  bool CWallet::SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfTheirs, set<pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64& nValueRet) const
  {
              if (nDepth < (pcoin->IsFromMe() ? nConfMine : nConfTheirs))
                  continue;
  
-             for (int i = 0; i < pcoin->vout.size(); i++)
+             for (unsigned int i = 0; i < pcoin->vout.size(); i++)
              {
                  if (pcoin->IsSpent(i) || !IsMine(pcoin->vout[i]))
                      continue;
  
      if (nTotalLower == nTargetValue || nTotalLower == nTargetValue + CENT)
      {
-         for (int i = 0; i < vValue.size(); ++i)
+         for (unsigned int i = 0; i < vValue.size(); ++i)
          {
              setCoinsRet.insert(vValue[i].second);
              nValueRet += vValue[i].first;
          bool fReachedTarget = false;
          for (int nPass = 0; nPass < 2 && !fReachedTarget; nPass++)
          {
-             for (int i = 0; i < vValue.size(); i++)
+             for (unsigned int i = 0; i < vValue.size(); i++)
              {
                  if (nPass == 0 ? rand() % 2 : !vfIncluded[i])
                  {
          nValueRet += coinLowestLarger.first;
      }
      else {
-         for (int i = 0; i < vValue.size(); i++)
+         for (unsigned int i = 0; i < vValue.size(); i++)
              if (vfBest[i])
              {
                  setCoinsRet.insert(vValue[i].second);
  
          //// debug print
          printf("SelectCoins() best subset: ");
-         for (int i = 0; i < vValue.size(); i++)
+         for (unsigned int i = 0; i < vValue.size(); i++)
              if (vfBest[i])
                  printf("%s ", FormatMoney(vValue[i].first).c_str());
          printf("total %s\n", FormatMoney(nBest).c_str());
diff --combined src/wallet.h
@@@ -13,9 -13,6 +13,9 @@@ class CWalletTx
  class CReserveKey;
  class CWalletDB;
  
 +// A CWallet is an extension of a keystore, which also maintains a set of
 +// transactions and balances, and provides the ability to create new
 +// transactions
  class CWallet : public CCryptoKeyStore
  {
  private:
@@@ -60,19 -57,14 +60,19 @@@ public
      std::vector<unsigned char> vchDefaultKey;
  
      // keystore implementation
 +    // Adds a key to the store, and saves it to disk.
      bool AddKey(const CKey& key);
 +    // Adds a key to the store, without saving it to disk (used by LoadWallet)
      bool LoadKey(const CKey& key) { return CCryptoKeyStore::AddKey(key); }
 +
 +    // Adds an encrypted key to the store, and saves it to disk.
      bool AddCryptedKey(const std::vector<unsigned char> &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret);
 +    // Adds an encrypted key to the store, without saving it to disk (used by LoadWallet)
      bool LoadCryptedKey(const std::vector<unsigned char> &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret) { return CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret); }
  
 -    bool Unlock(const std::string& strWalletPassphrase);
 -    bool ChangeWalletPassphrase(const std::string& strOldWalletPassphrase, const std::string& strNewWalletPassphrase);
 -    bool EncryptWallet(const std::string& strWalletPassphrase);
 +    bool Unlock(const SecureString& strWalletPassphrase);
 +    bool ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, const SecureString& strNewWalletPassphrase);
 +    bool EncryptWallet(const SecureString& strWalletPassphrase);
  
      bool AddToWallet(const CWalletTx& wtxIn);
      bool AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate = false);
@@@ -82,7 -74,6 +82,7 @@@
      void ReacceptWalletTransactions();
      void ResendWalletTransactions();
      int64 GetBalance() const;
 +    int64 GetUnconfirmedBalance() const;
      bool CreateTransaction(const std::vector<std::pair<CScript, int64> >& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet);
      bool CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet);
      bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey);
@@@ -252,7 -243,7 +252,7 @@@ public
      unsigned int nTimeReceived;  // time received by this node
      char fFromMe;
      std::string strFromAccount;
 -    std::vector<char> vfSpent;
 +    std::vector<char> vfSpent; // which outputs are already spent
  
      // memory only
      mutable char fDebitCached;
      bool UpdateSpent(const std::vector<char>& vfNewSpent)
      {
          bool fReturn = false;
-         for (int i=0; i < vfNewSpent.size(); i++)
+         for (unsigned int i = 0; i < vfNewSpent.size(); i++)
          {
              if (i == vfSpent.size())
                  break;
          return fReturn;
      }
  
 +    // make sure balances are recalculated
      void MarkDirty()
      {
          fCreditCached = false;
              return nAvailableCreditCached;
  
          int64 nCredit = 0;
-         for (int i = 0; i < vout.size(); i++)
+         for (unsigned int i = 0; i < vout.size(); i++)
          {
              if (!IsSpent(i))
              {
          std::vector<const CMerkleTx*> vWorkQueue;
          vWorkQueue.reserve(vtxPrev.size()+1);
          vWorkQueue.push_back(this);
-         for (int i = 0; i < vWorkQueue.size(); i++)
+         for (unsigned int i = 0; i < vWorkQueue.size(); i++)
          {
              const CMerkleTx* ptx = vWorkQueue[i];