Merge branch '0.4.x' into 0.5.x
authorLuke Dashjr <luke-jr+git@utopios.org>
Tue, 22 May 2012 22:55:49 +0000 (22:55 +0000)
committerLuke Dashjr <luke-jr+git@utopios.org>
Tue, 22 May 2012 22:55:49 +0000 (22:55 +0000)
Conflicts:
src/ui.cpp
src/ui.h
src/uibase.cpp
src/xpm/about.xpm

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

diff --combined src/bitcoinrpc.cpp
@@@ -4,6 -4,7 +4,6 @@@
  // file COPYING 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)
@@@ -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)
  {
@@@ -791,7 -723,8 +791,8 @@@ Value movecmd(const Array& params, boo
          strComment = params[4].get_str();
  
      CWalletDB walletdb(pwalletMain->strWalletFile);
-     walletdb.TxnBegin();
+     if (!walletdb.TxnBegin())
+         throw JSONRPCError(-20, "database error");
  
      int64 nNow = GetAdjustedTime();
  
      credit.strComment = strComment;
      walletdb.WriteAccountingEntry(credit);
  
-     walletdb.TxnCommit();
+     if (!walletdb.TxnCommit())
+         throw JSONRPCError(-20, "database error");
  
      return true;
  }
@@@ -1011,6 -945,7 +1013,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,69 -1212,6 +1278,69 @@@ Value listaccounts(const Array& params
      return ret;
  }
  
 +Value listsinceblock(const Array& params, bool fHelp)
 +{
 +    if (fHelp)
 +        throw runtime_error(
 +            "listsinceblock [blockhash] [target-confirmations]\n"
 +            "Get all transactions in blocks since block [blockhash], 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)
 +    {
 +        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)
@@@ -1472,16 -1345,21 +1474,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(
@@@ -1507,15 -1385,15 +1509,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;
  }
@@@ -1563,16 -1451,15 +1565,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
@@@ -1622,9 -1515,9 +1624,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);
 +    }
 +}
 +
 +
  
  
  
@@@ -1836,13 -1642,20 +1838,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]));
  
@@@ -1871,7 -1680,7 +1873,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]));
  
@@@ -1910,7 -1721,6 +1912,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";
@@@ -1951,13 -1761,12 +1953,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(),
@@@ -2035,6 -1844,43 +2037,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;
  }
  
  //
@@@ -2171,16 -2022,11 +2173,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(boost::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
@@@ -2502,12 -2327,18 +2504,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/db.cpp
@@@ -390,9 -390,15 +390,15 @@@ bool CTxDB::ReadOwnerTxes(uint160 hash1
          string strType;
          uint160 hashItem;
          CDiskTxPos pos;
-         ssKey >> strType >> hashItem >> pos;
          int nItemHeight;
-         ssValue >> nItemHeight;
+         try {
+             ssKey >> strType >> hashItem >> pos;
+             ssValue >> nItemHeight;
+         }
+         catch (std::exception &e) {
+             return error("%s() : deserialize error", __PRETTY_FUNCTION__);
+         }
  
          // Read transaction
          if (strType != "owner" || hashItem != hash160)
@@@ -512,6 -518,8 +518,8 @@@ bool CTxDB::LoadBlockIndex(
              return false;
  
          // Unserialize
+         try {
          string strType;
          ssKey >> strType;
          if (strType == "blockindex")
          {
              break;
          }
+         }    // try
+         catch (std::exception &e) {
+             return error("%s() : deserialize error", __PRETTY_FUNCTION__);
+         }
      }
      pcursor->close();
  
@@@ -629,6 -641,24 +641,6 @@@ bool CAddrDB::LoadAddresses(
  {
      CRITICAL_BLOCK(cs_mapAddresses)
      {
 -        // Load user provided addresses
 -        CAutoFile filein = fopen((GetDataDir() + "/addr.txt").c_str(), "rt");
 -        if (filein)
 -        {
 -            try
 -            {
 -                char psz[1000];
 -                while (fgets(psz, sizeof(psz), filein))
 -                {
 -                    CAddress addr(psz, false, NODE_NETWORK);
 -                    addr.nTime = 0; // so it won't relay unless successfully connected
 -                    if (addr.IsValid())
 -                        AddAddress(addr);
 -                }
 -            }
 -            catch (...) { }
 -        }
 -
          // Get cursor
          Dbc* pcursor = GetCursor();
          if (!pcursor)
@@@ -768,7 -798,7 +780,7 @@@ int CWalletDB::LoadWallet(CWallet* pwal
      bool fIsEncrypted = false;
  
      // Modify defaults
 -#ifndef __WXMSW__
 +#ifndef WIN32
      // Tray icon sometimes disappears on 9.10 karmic koala 64-bit, leaving no way to access the program
      fMinimizeToTray = false;
      fMinimizeOnClose = false;
                  ssKey >> strKey;
  
                  // Options
 -#ifndef GUI
 +#ifndef QT_GUI
                  if (strKey == "fGenerateBitcoins")  ssValue >> fGenerateBitcoins;
  #endif
                  if (strKey == "nTransactionFee")    ssValue >> nTransactionFee;
diff --combined src/main.cpp
@@@ -8,6 -8,7 +8,6 @@@
  #include "db.h"
  #include "net.h"
  #include "init.h"
 -#include "cryptopp/sha.h"
  #include <boost/filesystem.hpp>
  #include <boost/filesystem/fstream.hpp>
  
@@@ -31,6 -32,7 +31,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;
@@@ -39,8 -41,6 +39,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;
  
@@@ -65,14 -65,16 +65,14 @@@ int fUseUPnP = false
  #endif
  
  
 -
 -
 -
 -
 -
  //////////////////////////////////////////////////////////////////////////////
  //
  // dispatching functions
  //
  
 +// These functions dispatch to one or all registered wallets
 +
 +
  void RegisterWallet(CWallet* pwalletIn)
  {
      CRITICAL_BLOCK(cs_setpwalletRegistered)
@@@ -89,7 -91,6 +89,7 @@@ void UnregisterWallet(CWallet* pwalletI
      }
  }
  
 +// check whether the passed transaction is from us
  bool static IsFromMe(CTransaction& tx)
  {
      BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
@@@ -98,7 -99,6 +98,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)
@@@ -322,24 -315,24 +322,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;
@@@ -376,7 -369,7 +376,7 @@@ bool CTransaction::AcceptToMemoryPool(C
  
      // Coinbase is only valid in a block, not as a loose transaction
      if (IsCoinBase())
 -        return error("AcceptToMemoryPool() : coinbase as individual tx");
 +        return DoS(100, error("AcceptToMemoryPool() : coinbase as individual tx"));
  
      // To help v0.1.5 clients who would see it as a negative number
      if ((int64)nLockTime > INT_MAX)
          // 34 bytes because a TxOut is:
          //   20-byte address + 8 byte bitcoin amount + 5 bytes of ops + 1 byte script length
          if (GetSigOpCount() > nSize / 34 || nSize < 100)
 -            return error("AcceptToMemoryPool() : nonstandard transaction");
 +            return error("AcceptToMemoryPool() : transaction with out-of-bounds SigOpCount");
  
          int64 nFees = GetValueIn(mapInputs)-GetValueOut();
  
@@@ -796,15 -789,9 +796,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;
@@@ -954,7 -941,7 +954,7 @@@ bool CTransaction::FetchInputs(CTxDB& t
              // 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()));
          }
      }
  
@@@ -1023,7 -1010,7 +1023,7 @@@ bool CTransaction::ConnectInputs(MapPre
              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;
@@@ -1197,7 -1177,7 +1197,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();
@@@ -1357,7 -1337,9 +1357,9 @@@ bool CBlock::SetBestChain(CTxDB& txdb, 
  {
      uint256 hash = GetHash();
  
-     txdb.TxnBegin();
+     if (!txdb.TxnBegin())
+         return error("SetBestChain() : TxnBegin failed");
      if (pindexGenesisBlock == NULL && hash == hashGenesisBlock)
      {
          txdb.WriteHashBestChain(hash);
@@@ -1437,7 -1419,8 +1439,8 @@@ bool CBlock::AddToBlockIndex(unsigned i
      pindexNew->bnChainWork = (pindexNew->pprev ? pindexNew->pprev->bnChainWork : 0) + pindexNew->GetBlockWork();
  
      CTxDB txdb;
-     txdb.TxnBegin();
+     if (!txdb.TxnBegin())
+         return false;
      txdb.WriteBlockIndex(CDiskBlockIndex(pindexNew));
      if (!txdb.TxnCommit())
          return false;
@@@ -1471,11 -1454,11 +1474,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 (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 for duplicate txids. This is caught by ConnectInputs(),
      // but catching it earlier avoids a potential DoS attack:
          uniqueTx.insert(tx.GetHash());
      }
      if (uniqueTx.size() != vtx.size())
 -        return error("CheckBlock() : duplicate transaction");
 +        return DoS(100, error("CheckBlock() : duplicate transaction"));
  
      // 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;
  }
@@@ -1524,13 -1507,13 +1527,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");
          }
      }
@@@ -1659,7 -1638,7 +1662,7 @@@ bool CheckDiskSpace(uint64 nAdditionalB
      if (nFreeBytesAvailable < (uint64)15000000 + nAdditionalBytes)
      {
          fShutdown = true;
-         string strMessage = _("Warning: Disk space is low  ");
+         string strMessage = _("Warning: Disk space is low");
          strMiscWarning = strMessage;
          printf("*** %s\n", strMessage.c_str());
          ThreadSafeMessageBox(strMessage, "Bitcoin", wxOK | wxICON_EXCLAMATION);
@@@ -2037,10 -2016,7 +2040,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());
 +        }
  
          // find last block in inv vector
          unsigned int nLastBlock = (unsigned int)(-1);
          for (unsigned int nInv = 0; nInv < vInv.size(); nInv++) {
-             if (vInv[vInv.size() - 1 - nInv].type == MSG_BLOCK)
+             if (vInv[vInv.size() - 1 - nInv].type == MSG_BLOCK) {
                  nLastBlock = vInv.size() - 1 - nInv;
+                 break;
+             }
          }
          CTxDB txdb("r");
          for (int nInv = 0; nInv < vInv.size(); nInv++)
              if (fDebug)
                  printf("  got inventory: %s  %s\n", inv.ToString().c_str(), fAlreadyHave ? "have" : "new");
  
-             // Always request the last block in an inv bundle (even if we already have it), as it is the
-             // trigger for the other side to send further invs. If we are stuck on a (very long) side chain,
-             // this is necessary to connect earlier received orphan blocks to the chain again.
-             if (fAlreadyHave && nInv == nLastBlock) {
-                 // bypass mapAskFor, and send request directly; it must go through.
-                 std::vector<CInv> vGetData(1,inv);
-                 pfrom->PushMessage("getdata", vGetData);
-             }
              if (!fAlreadyHave)
                  pfrom->AskFor(inv);
-             else if (inv.type == MSG_BLOCK && mapOrphanBlocks.count(inv.hash))
+             else if (inv.type == MSG_BLOCK && mapOrphanBlocks.count(inv.hash)) {
                  pfrom->PushGetBlocks(pindexBest, GetOrphanRoot(mapOrphanBlocks[inv.hash]));
+             } else if (nInv == nLastBlock) {
+                 // In case we are on a very long side-chain, it is possible that we already have
+                 // the last block in an inv bundle sent in response to getblocks. Try to detect
+                 // this situation and push another getblocks to continue.
+                 std::vector<CInv> vGetData(1,inv);
+                 pfrom->PushGetBlocks(mapBlockIndex[inv.hash], uint256(0));
+                 if (fDebug)
+                     printf("force request: %s\n", inv.ToString().c_str());
+             }
  
              // Track requests for our stuff
              Inventory(inv.hash);
          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)
          {
              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);
      }
  
  
@@@ -2616,7 -2580,7 +2621,7 @@@ bool ProcessMessages(CNode* pfrom
          unsigned int nMessageSize = hdr.nMessageSize;
          if (nMessageSize > MAX_SIZE)
          {
-             printf("ProcessMessage(%s, %u bytes) : nMessageSize > MAX_SIZE\n", strCommand.c_str(), nMessageSize);
+             printf("ProcessMessages(%s, %u bytes) : nMessageSize > MAX_SIZE\n", strCommand.c_str(), nMessageSize);
              continue;
          }
          if (nMessageSize > vRecv.size())
              memcpy(&nChecksum, &hash, sizeof(nChecksum));
              if (nChecksum != hdr.nChecksum)
              {
-                 printf("ProcessMessage(%s, %u bytes) : CHECKSUM ERROR nChecksum=%08x hdr.nChecksum=%08x\n",
+                 printf("ProcessMessages(%s, %u bytes) : CHECKSUM ERROR nChecksum=%08x hdr.nChecksum=%08x\n",
                         strCommand.c_str(), nMessageSize, nChecksum, hdr.nChecksum);
                  continue;
              }
              if (strstr(e.what(), "end of data"))
              {
                  // Allow exceptions from underlength message on vRecv
-                 printf("ProcessMessage(%s, %u bytes) : Exception '%s' caught, normally caused by a message being shorter than its stated length\n", strCommand.c_str(), nMessageSize, e.what());
+                 printf("ProcessMessages(%s, %u bytes) : Exception '%s' caught, normally caused by a message being shorter than its stated length\n", strCommand.c_str(), nMessageSize, e.what());
              }
              else if (strstr(e.what(), "size too large"))
              {
                  // Allow exceptions from overlong size
-                 printf("ProcessMessage(%s, %u bytes) : Exception '%s' caught\n", strCommand.c_str(), nMessageSize, e.what());
+                 printf("ProcessMessages(%s, %u bytes) : Exception '%s' caught\n", strCommand.c_str(), nMessageSize, e.what());
              }
              else
              {
-                 PrintExceptionContinue(&e, "ProcessMessage()");
+                 PrintExceptionContinue(&e, "ProcessMessages()");
              }
          }
          catch (std::exception& e) {
-             PrintExceptionContinue(&e, "ProcessMessage()");
+             PrintExceptionContinue(&e, "ProcessMessages()");
          } catch (...) {
-             PrintExceptionContinue(NULL, "ProcessMessage()");
+             PrintExceptionContinue(NULL, "ProcessMessages()");
          }
  
          if (!fRet)
@@@ -2899,25 -2863,15 +2904,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];
  }
  
  //
@@@ -3235,6 -3189,7 +3240,6 @@@ bool CheckWork(CBlock* pblock, CWallet
              return error("BitcoinMiner : ProcessBlock, block not accepted");
      }
  
 -    Sleep(2000);
      return true;
  }
  
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
          // Read transaction
          if (fseek(filein, pos.nTxPos, SEEK_SET) != 0)
              return error("CTransaction::ReadFromDisk() : fseek failed");
-         filein >> *this;
+         try {
+             filein >> *this;
+         }
+         catch (std::exception &e) {
+             return error("%s() : deserialize or I/O error", __PRETTY_FUNCTION__);
+         }
  
          // Return file pointer
          if (pfileRet)
@@@ -843,9 -843,6 +849,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));
              filein.nType |= SER_BLOCKHEADERONLY;
  
          // Read block
-         filein >> *this;
+         try {
+             filein >> *this;
+         }
+         catch (std::exception &e) {
+             return error("%s() : deserialize or I/O error", __PRETTY_FUNCTION__);
+         }
  
          // Check the header
          if (!CheckProofOfWork(GetHash(), nBits))
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;
          if (fFileBacked)
          {
              pwalletdbEncryption = new CWalletDB(strWalletFile);
-             pwalletdbEncryption->TxnBegin();
+             if (!pwalletdbEncryption->TxnBegin())
+                 return false;
              pwalletdbEncryption->WriteMasterKey(nMasterKeyMaxID, kMasterKey);
          }
  
@@@ -267,7 -269,7 +268,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();
@@@ -563,9 -562,6 +564,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;
@@@ -743,21 -739,6 +744,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
  {