Merge branch '0.4.x' into 0.5.0.x
authorLuke Dashjr <luke-jr+git@utopios.org>
Sat, 3 Mar 2012 18:59:19 +0000 (13:59 -0500)
committerLuke Dashjr <luke-jr+git@utopios.org>
Sat, 3 Mar 2012 18:59:19 +0000 (13:59 -0500)
1  2 
src/bitcoinrpc.cpp
src/key.h
src/main.cpp
src/main.h
src/util.cpp
src/wallet.cpp

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"
@@@ -49,13 -50,13 +49,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
  }
  
  
@@@ -160,13 -165,10 +160,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
  }
  
  
@@@ -314,7 -316,7 +314,7 @@@ Value getinfo(const Array& params, boo
      obj.push_back(Pair("keypoolsize",   pwalletMain->GetKeyPoolSize()));
      obj.push_back(Pair("paytxfee",      ValueFromAmount(nTransactionFee)));
      if (pwalletMain->IsCrypted())
-         obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime));
+         obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime / 1000));
      obj.push_back(Pair("errors",        GetWarnings("statusbar")));
      return obj;
  }
@@@ -528,72 -530,6 +528,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)
  {
@@@ -1005,6 -941,7 +1005,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);
@@@ -1260,70 -1198,6 +1260,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)
@@@ -1403,7 -1277,7 +1403,7 @@@ void ThreadTopUpKeyPool(void* parg
  
  void ThreadCleanWalletPassphrase(void* parg)
  {
-     int64 nMyWakeTime = GetTime() + *((int*)parg);
+     int64 nMyWakeTime = GetTimeMillis() + *((int*)parg) * 1000;
  
      ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
  
      {
          nWalletUnlockTime = nMyWakeTime;
  
-         while (GetTime() < nWalletUnlockTime)
+         do
          {
-             int64 nToSleep = GetTime() - nWalletUnlockTime;
+             if (nWalletUnlockTime==0)
+                 break;
+             int64 nToSleep = nWalletUnlockTime - GetTimeMillis();
+             if (nToSleep <= 0)
+                 break;
  
              LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime);
              Sleep(nToSleep);
              ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime);
-         }
  
-         nWalletUnlockTime = 0;
-         pwalletMain->Lock();
+         } while(1);
+         if (nWalletUnlockTime)
+         {
+             nWalletUnlockTime = 0;
+             pwalletMain->Lock();
+         }
      }
      else
      {
@@@ -1449,16 -1331,21 +1457,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(
@@@ -1484,15 -1371,15 +1492,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;
  }
@@@ -1519,9 -1416,9 +1527,9 @@@ Value walletlock(const Array& params, b
      if (!pwalletMain->IsCrypted())
          throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletlock was called.");
  
-     pwalletMain->Lock();
      CRITICAL_BLOCK(cs_nWalletUnlockTime)
      {
+         pwalletMain->Lock();
          nWalletUnlockTime = 0;
      }
  
@@@ -1540,16 -1437,15 +1548,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
@@@ -1599,9 -1501,9 +1607,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->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
 +        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);
 +    }
 +}
 +
 +
  
  
  
@@@ -1813,13 -1628,20 +1821,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]));
  
@@@ -1857,15 -1675,17 +1865,15 @@@ string pAllowInSafeMode[] 
      "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]));
  
@@@ -1887,7 -1707,6 +1895,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";
@@@ -1928,13 -1747,12 +1936,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(),
@@@ -2012,6 -1830,43 +2020,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"];
@@@ -2167,7 -2022,7 +2175,7 @@@ void ThreadRPCServer2(void* parg
          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"
 +            _("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"
                  strWhatAmI.c_str(),
                  GetConfigFile().c_str(),
                  EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32).c_str());
 +#ifndef QT_GUI
          CreateThread(Shutdown, NULL);
 +#endif
          return;
      }
  
              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
@@@ -2460,12 -2313,18 +2468,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/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
@@@ -229,10 -153,13 +229,13 @@@ public
          if (vchSecret.size() != 32)
              throw key_error("CKey::SetSecret() : secret must be 32 bytes");
          BIGNUM *bn = BN_bin2bn(&vchSecret[0],32,BN_new());
-         if (bn == NULL) 
+         if (bn == NULL)
              throw key_error("CKey::SetSecret() : BN_bin2bn failed");
          if (!EC_KEY_regenerate_key(pkey,bn))
+         {
+             BN_clear_free(bn);
              throw key_error("CKey::SetSecret() : EC_KEY_regenerate_key failed");
+         }
          BN_clear_free(bn);
          fSet = true;
          return true;
          return true;
      }
  
 +    // create a compact signature (65 bytes), which allows reconstructing the used public key
 +    // The format is one header byte, followed by two times 32 bytes for the serialized r and s values.
 +    // The header byte: 0x1B = first key with even y, 0x1C = first key with odd y,
 +    //                  0x1D = second key with even y, 0x1E = second key with odd y
 +    bool SignCompact(uint256 hash, std::vector<unsigned char>& vchSig)
 +    {
 +        bool fOk = false;
 +        ECDSA_SIG *sig = ECDSA_do_sign((unsigned char*)&hash, sizeof(hash), pkey);
 +        if (sig==NULL)
 +            return false;
 +        vchSig.clear();
 +        vchSig.resize(65,0);
 +        int nBitsR = BN_num_bits(sig->r);
 +        int nBitsS = BN_num_bits(sig->s);
 +        if (nBitsR <= 256 && nBitsS <= 256)
 +        {
 +            int nRecId = -1;
 +            for (int i=0; i<4; i++)
 +            {
 +                CKey keyRec;
 +                keyRec.fSet = true;
 +                if (ECDSA_SIG_recover_key_GFp(keyRec.pkey, sig, (unsigned char*)&hash, sizeof(hash), i, 1) == 1)
 +                    if (keyRec.GetPubKey() == this->GetPubKey())
 +                    {
 +                        nRecId = i;
 +                        break;
 +                    }
 +            }
 +
 +            if (nRecId == -1)
 +                throw key_error("CKey::SignCompact() : unable to construct recoverable key");
 +
 +            vchSig[0] = nRecId+27;
 +            BN_bn2bin(sig->r,&vchSig[33-(nBitsR+7)/8]);
 +            BN_bn2bin(sig->s,&vchSig[65-(nBitsS+7)/8]);
 +            fOk = true;
 +        }
 +        ECDSA_SIG_free(sig);
 +        return fOk;
 +    }
 +
 +    // reconstruct public key from a compact signature
 +    // This is only slightly more CPU intensive than just verifying it.
 +    // If this function succeeds, the recovered public key is guaranteed to be valid
 +    // (the signature is a valid signature of the given data for that key)
 +    bool SetCompactSignature(uint256 hash, const std::vector<unsigned char>& vchSig)
 +    {
 +        if (vchSig.size() != 65)
 +            return false;
 +        if (vchSig[0]<27 || vchSig[0]>=31)
 +            return false;
 +        ECDSA_SIG *sig = ECDSA_SIG_new();
 +        BN_bin2bn(&vchSig[1],32,sig->r);
 +        BN_bin2bn(&vchSig[33],32,sig->s);
 +
 +        EC_KEY_free(pkey);
 +        pkey = EC_KEY_new_by_curve_name(NID_secp256k1);
 +        if (ECDSA_SIG_recover_key_GFp(pkey, sig, (unsigned char*)&hash, sizeof(hash), vchSig[0] - 27, 0) == 1)
 +        {
 +            fSet = true;
 +            ECDSA_SIG_free(sig);
 +            return true;
 +        }
 +        return false;
 +    }
 +
      bool Verify(uint256 hash, const std::vector<unsigned char>& vchSig)
      {
          // -1 = error, 0 = bad sig, 1 = good
          return true;
      }
  
 +    // Verify a compact signature
 +    bool VerifyCompact(uint256 hash, const std::vector<unsigned char>& vchSig)
 +    {
 +        CKey key;
 +        if (!key.SetCompactSignature(hash, vchSig))
 +            return false;
 +        if (GetPubKey() != key.GetPubKey())
 +            return false;
 +        return true;
 +    }
 +
 +    // Get the address corresponding to this key
      CBitcoinAddress GetAddress() const
      {
          return CBitcoinAddress(GetPubKey());
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)
  // mapOrphanTransactions
  //
  
- void static AddOrphanTx(const CDataStream& vMsg)
+ void AddOrphanTx(const CDataStream& vMsg)
  {
      CTransaction tx;
      CDataStream(vMsg) >> tx;
      uint256 hash = tx.GetHash();
      if (mapOrphanTransactions.count(hash))
          return;
      CDataStream* pvMsg = mapOrphanTransactions[hash] = new CDataStream(vMsg);
      BOOST_FOREACH(const CTxIn& txin, tx.vin)
          mapOrphanTransactionsByPrev.insert(make_pair(txin.prevout.hash, pvMsg));
@@@ -200,6 -194,23 +201,23 @@@ void static EraseOrphanTx(uint256 hash
      mapOrphanTransactions.erase(hash);
  }
  
+ int LimitOrphanTxSize(int nMaxOrphans)
+ {
+     int nEvicted = 0;
+     while (mapOrphanTransactions.size() > nMaxOrphans)
+     {
+         // Evict a random orphan:
+         std::vector<unsigned char> randbytes(32);
+         RAND_bytes(&randbytes[0], 32);
+         uint256 randomhash(randbytes);
+         map<uint256, CDataStream*>::iterator it = mapOrphanTransactions.lower_bound(randomhash);
+         if (it == mapOrphanTransactions.end())
+             it = mapOrphanTransactions.begin();
+         EraseOrphanTx(it->first);
+         ++nEvicted;
+     }
+     return nEvicted;
+ }
  
  
  
@@@ -303,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;
@@@ -357,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)
      // 34 bytes because a TxOut is:
      //   20-byte address + 8 byte bitcoin amount + 5 bytes of ops + 1 byte script length
      if (GetSigOpCount() > nSize / 34 || nSize < 100)
 -        return error("AcceptToMemoryPool() : nonstandard transaction");
 +        return error("AcceptToMemoryPool() : transaction with out-of-bounds SigOpCount");
  
      // Rather not work on nonstandard transactions (unless -testnet)
      if (!fTestNet && !IsStandard())
@@@ -767,15 -778,9 +785,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;
@@@ -839,8 -844,10 +857,10 @@@ bool CTransaction::DisconnectInputs(CTx
      }
  
      // Remove transaction from index
-     if (!txdb.EraseTxIndex(*this))
-         return error("DisconnectInputs() : EraseTxPos failed");
+     // This can fail if a duplicate of this transaction was in a chain that got
+     // reorganized away. This is only possible if this transaction was completely
+     // spent, so erasing it would be a no-op anway.
+     txdb.EraseTxIndex(*this);
  
      return true;
  }
@@@ -857,9 -864,6 +877,9 @@@ bool CTransaction::ConnectInputs(CTxDB
      fInvalid = false;
  
      // Take over previous transactions' spent pointers
 +    // fBlock is true when this is called from AcceptBlock when a new best-block is added to the blockchain
 +    // fMiner is true when called from the internal bitcoin miner
 +    // ... both are false when called from CTransaction::AcceptToMemoryPool
      if (!IsCoinBase())
      {
          int64 nValueIn = 0;
                  // Revisit this if/when transaction replacement is implemented and allows
                  // adding inputs:
                  fInvalid = true;
 -                return error("ConnectInputs() : %s prevout.n out of range %d %d %d prev tx %s\n%s", GetHash().ToString().substr(0,10).c_str(), prevout.n, txPrev.vout.size(), txindex.vSpent.size(), prevout.hash.ToString().substr(0,10).c_str(), txPrev.ToString().c_str());
 +                return DoS(100, error("ConnectInputs() : %s prevout.n out of range %d %d %d prev tx %s\n%s", GetHash().ToString().substr(0,10).c_str(), prevout.n, txPrev.vout.size(), txindex.vSpent.size(), prevout.hash.ToString().substr(0,10).c_str(), txPrev.ToString().c_str()));
              }
  
              // If prev is coinbase, check that it's matured
                      if (pindex->nBlockPos == txindex.pos.nBlockPos && pindex->nFile == txindex.pos.nFile)
                          return error("ConnectInputs() : tried to spend coinbase at depth %d", pindexBlock->nHeight - pindex->nHeight);
  
 -            // Verify signature
 -            if (!VerifySignature(txPrev, *this, i))
 -                return error("ConnectInputs() : %s VerifySignature failed", GetHash().ToString().substr(0,10).c_str());
 -
 -            // Check for conflicts
 +            // Skip ECDSA signature verification when connecting blocks (fBlock=true)
 +            // before the last blockchain checkpoint. This is safe because block merkle hashes are
 +            // still computed and checked, and any change will be caught at the next checkpoint.
 +            if (!(fBlock && (nBestHeight < Checkpoints::GetTotalBlocksEstimate())))
 +                // Verify signature
 +                if (!VerifySignature(txPrev, *this, i))
 +                    return DoS(100,error("ConnectInputs() : %s VerifySignature failed", GetHash().ToString().substr(0,10).c_str()));
 +
 +            // Check for conflicts (double-spend)
 +            // This doesn't trigger the DoS code on purpose; if it did, it would make it easier
 +            // for an attacker to attempt to split the network.
              if (!txindex.vSpent[prevout.n].IsNull())
                  return fMiner ? false : error("ConnectInputs() : %s prev tx already used at %s", GetHash().ToString().substr(0,10).c_str(), txindex.vSpent[prevout.n].ToString().c_str());
  
              // Check for negative or overflow input values
              nValueIn += txPrev.vout[prevout.n].nValue;
              if (!MoneyRange(txPrev.vout[prevout.n].nValue) || !MoneyRange(nValueIn))
 -                return error("ConnectInputs() : txin values out of range");
 +                return DoS(100, error("ConnectInputs() : txin values out of range"));
  
              // Mark outpoints as spent
              txindex.vSpent[prevout.n] = posThisTx;
          }
  
          if (nValueIn < GetValueOut())
 -            return error("ConnectInputs() : %s value in < value out", GetHash().ToString().substr(0,10).c_str());
 +            return DoS(100, error("ConnectInputs() : %s value in < value out", GetHash().ToString().substr(0,10).c_str()));
  
          // Tally transaction fees
          int64 nTxFee = nValueIn - GetValueOut();
          if (nTxFee < 0)
 -            return error("ConnectInputs() : %s nTxFee < 0", GetHash().ToString().substr(0,10).c_str());
 +            return DoS(100, error("ConnectInputs() : %s nTxFee < 0", GetHash().ToString().substr(0,10).c_str()));
          if (nTxFee < nMinFee)
              return false;
          nFees += nTxFee;
          if (!MoneyRange(nFees))
 -            return error("ConnectInputs() : nFees out of range");
 +            return DoS(100, error("ConnectInputs() : nFees out of range"));
      }
  
      if (fBlock)
@@@ -1050,6 -1048,26 +1070,26 @@@ bool CBlock::ConnectBlock(CTxDB& txdb, 
      if (!CheckBlock())
          return false;
  
+     // Do not allow blocks that contain transactions which 'overwrite' older transactions,
+     // unless those are already completely spent.
+     // If such overwrites are allowed, coinbases and transactions depending upon those
+     // can be duplicated to remove the ability to spend the first instance -- even after
+     // being sent to another address.
+     // See BIP30 and http://r6.ca/blog/20120206T005236Z.html for more information.
+     // This logic is not necessary for memory pool transactions, as AcceptToMemoryPool
+     // already refuses previously-known transaction id's entirely.
+     // This rule applies to all blocks whose timestamp is after March 15, 2012, 0:00 UTC.
+     // On testnet it is enabled as of februari 20, 2012, 0:00 UTC.
+     if (pindex->nTime > 1331769600 || (fTestNet && pindex->nTime > 1329696000))
+         BOOST_FOREACH(CTransaction& tx, vtx)
+         {
+             CTxIndex txindexOld;
+             if (txdb.ReadTxIndex(tx.GetHash(), txindexOld))
+                 BOOST_FOREACH(CDiskTxPos &pos, txindexOld.vSpent)
+                     if (pos.IsNull())
+                         return false;
+         }
      //// issue here: it doesn't know the version
      unsigned int nTxPos = pindex->nBlockPos + ::GetSerializeSize(CBlock(), SER_DISK) - 1 + GetSizeOfCompactSize(vtx.size());
  
@@@ -1302,11 -1320,11 +1342,11 @@@ bool CBlock::CheckBlock() cons
  
      // Size limits
      if (vtx.empty() || vtx.size() > MAX_BLOCK_SIZE || ::GetSerializeSize(*this, SER_NETWORK) > MAX_BLOCK_SIZE)
 -        return error("CheckBlock() : size limits failed");
 +        return DoS(100, error("CheckBlock() : size limits failed"));
  
      // Check proof of work matches claimed amount
      if (!CheckProofOfWork(GetHash(), nBits))
 -        return error("CheckBlock() : proof of work failed");
 +        return DoS(50, error("CheckBlock() : proof of work failed"));
  
      // Check timestamp
      if (GetBlockTime() > GetAdjustedTime() + 2 * 60 * 60)
  
      // First transaction must be coinbase, the rest must not be
      if (vtx.empty() || !vtx[0].IsCoinBase())
 -        return error("CheckBlock() : first tx is not coinbase");
 +        return DoS(100, error("CheckBlock() : first tx is not coinbase"));
      for (int i = 1; i < vtx.size(); i++)
          if (vtx[i].IsCoinBase())
 -            return error("CheckBlock() : more than one coinbase");
 +            return DoS(100, error("CheckBlock() : more than one coinbase"));
  
      // Check transactions
      BOOST_FOREACH(const CTransaction& tx, vtx)
          if (!tx.CheckTransaction())
 -            return error("CheckBlock() : CheckTransaction failed");
 +            return DoS(tx.nDoS, error("CheckBlock() : CheckTransaction failed"));
  
      // Check that it's not full of nonstandard transactions
      if (GetSigOpCount() > MAX_BLOCK_SIGOPS)
 -        return error("CheckBlock() : too many nonstandard transactions");
 +        return DoS(100, error("CheckBlock() : out-of-bounds SigOpCount"));
  
      // Check merkleroot
      if (hashMerkleRoot != BuildMerkleTree())
 -        return error("CheckBlock() : hashMerkleRoot mismatch");
 +        return DoS(100, error("CheckBlock() : hashMerkleRoot mismatch"));
  
      return true;
  }
@@@ -1345,13 -1363,13 +1385,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");
          }
      }
@@@ -1846,10 -1860,7 +1886,10 @@@ bool static ProcessMessage(CNode* pfrom
      {
          // Each connection can only send one version message
          if (pfrom->nVersion != 0)
 +        {
 +            pfrom->Misbehaving(1);
              return false;
 +        }
  
          int64 nTime;
          CAddress addrMe;
          pfrom->fSuccessfullyConnected = true;
  
          printf("version message: version %d, blocks=%d\n", pfrom->nVersion, pfrom->nStartingHeight);
 +
 +        cPeerBlockCounts.input(pfrom->nStartingHeight);
      }
  
  
      else if (pfrom->nVersion == 0)
      {
          // Must have a version message before anything else
 +        pfrom->Misbehaving(1);
          return false;
      }
  
          if (pfrom->nVersion < 31402 && mapAddresses.size() > 1000)
              return true;
          if (vAddr.size() > 1000)
 +        {
 +            pfrom->Misbehaving(20);
              return error("message addr size() = %d", vAddr.size());
 +        }
  
          // Store the new addresses
          CAddrDB addrDB;
          vector<CInv> vInv;
          vRecv >> vInv;
          if (vInv.size() > 50000)
 +        {
 +            pfrom->Misbehaving(20);
              return error("message inv size() = %d", vInv.size());
 +        }
  
          CTxDB txdb("r");
          BOOST_FOREACH(const CInv& inv, vInv)
          vector<CInv> vInv;
          vRecv >> vInv;
          if (vInv.size() > 50000)
 +        {
 +            pfrom->Misbehaving(20);
              return error("message getdata size() = %d", vInv.size());
 +        }
  
          BOOST_FOREACH(const CInv& inv, vInv)
          {
          {
              printf("storing orphan tx %s\n", inv.hash.ToString().substr(0,10).c_str());
              AddOrphanTx(vMsg);
+             // DoS prevention: do not allow mapOrphanTransactions to grow unbounded
+             int nEvicted = LimitOrphanTxSize(MAX_ORPHAN_TRANSACTIONS);
+             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);
      }
  
  
@@@ -2686,25 -2688,15 +2731,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];
  }
  
  //
@@@ -3006,6 -2998,7 +3051,6 @@@ bool CheckWork(CBlock* pblock, CWallet
              return error("BitcoinMiner : ProcessBlock, block not accepted");
      }
  
 -    Sleep(2000);
      return true;
  }
  
diff --combined src/main.h
@@@ -30,6 -30,7 +30,7 @@@ class CBlockIndex
  static const unsigned int MAX_BLOCK_SIZE = 1000000;
  static const unsigned int MAX_BLOCK_SIZE_GEN = MAX_BLOCK_SIZE/2;
  static const int MAX_BLOCK_SIGOPS = MAX_BLOCK_SIZE/50;
+ static const int MAX_ORPHAN_TRANSACTIONS = MAX_BLOCK_SIZE/100;
  static const int64 COIN = 100000000;
  static const int64 CENT = 1000000;
  static const int64 MIN_TX_FEE = 50000;
@@@ -85,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);
@@@ -100,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);
  
@@@ -401,9 -400,6 +402,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
@@@ -793,9 -788,6 +794,9 @@@ public
      // memory only
      mutable std::vector<uint256> vMerkleTree;
  
 +    // Denial-of-service detection:
 +    mutable int nDoS;
 +    bool DoS(int nDoSIn, bool fIn) const { nDoS += nDoSIn; return fIn; }
  
      CBlock()
      {
          nNonce = 0;
          vtx.clear();
          vMerkleTree.clear();
 +        nDoS = 0;
      }
  
      bool IsNull() const
          fflush(fileout);
          if (!IsInitialBlockDownload() || (nBestHeight+1) % 500 == 0)
          {
 -#ifdef __WXMSW__
 +#ifdef WIN32
              _commit(_fileno(fileout));
  #else
              fsync(fileno(fileout));
diff --combined src/util.cpp
@@@ -64,7 -64,7 +64,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
@@@ -108,7 -108,7 +108,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];
@@@ -198,7 -198,7 +198,7 @@@ inline int OutputDebugStringF(const cha
          }
      }
  
 -#ifdef __WXMSW__
 +#ifdef WIN32
      if (fPrintToDebugger)
      {
          static CCriticalSection cs_OutputDebugStringF;
@@@ -264,7 -264,8 +264,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)
      {
@@@ -443,6 -445,7 +443,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] = '-';
@@@ -486,144 -489,39 +486,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[*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[p[2]] != -1)
 +                    *pfInvalid = true;
 +                break;
 +
 +            case 3: // 4n+3 base64 characters processed: require '='
 +                if (left || p[0] != '=' || decode64_table[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());
  }
  
  
@@@ -665,7 -563,7 +665,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));
@@@ -694,6 -592,10 +694,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;
  }
  
@@@ -715,6 -617,10 +715,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)
      {
          PSHGETSPECIALFOLDERPATHA pSHGetSpecialFolderPath =
              (PSHGETSPECIALFOLDERPATHA)GetProcAddress(hShell32, "SHGetSpecialFolderPathA");
+         bool fSuccess = false;
          if (pSHGetSpecialFolderPath)
+             fSuccess =
              (*pSHGetSpecialFolderPath)(NULL, pszPath, nFolder, fCreate);
          FreeModule(hShell32);
+         if (fSuccess)
+             return pszPath;
      }
  
      // Backup option
-     if (pszPath[0] == '\0')
+     std::string strPath;
      {
+         const char *pszEnv;
          if (nFolder == CSIDL_STARTUP)
          {
-             strcpy(pszPath, getenv("USERPROFILE"));
-             strcat(pszPath, "\\Start Menu\\Programs\\Startup");
+             pszEnv = getenv("USERPROFILE");
+             if (pszEnv)
+                 strPath = pszEnv;
+             strPath += "\\Start Menu\\Programs\\Startup";
          }
          else if (nFolder == CSIDL_APPDATA)
          {
-             strcpy(pszPath, getenv("APPDATA"));
+             pszEnv = getenv("APPDATA");
+             if (pszEnv)
+                 strPath = pszEnv;
          }
      }
  
-     return pszPath;
+     return strPath;
  }
  #endif
  
@@@ -765,7 -680,7 +774,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());
@@@ -926,20 -841,11 +935,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;
              if (!pwalletdbEncryption->TxnCommit())
                  exit(1); //We now have keys encrypted in memory, but no on disk...die to avoid confusion and let the user reload their unencrypted wallet.
  
-             pwalletdbEncryption->Close();
+             delete pwalletdbEncryption;
              pwalletdbEncryption = NULL;
          }
  
@@@ -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();
@@@ -561,9 -559,6 +561,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;
@@@ -741,21 -736,6 +741,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
  {