Merge bitcoin v0.5.1 into ppcoin
authorSunny King <p2pcoin@gmail.com>
Tue, 20 Dec 2011 19:07:42 +0000 (19:07 +0000)
committerSunny King <p2pcoin@gmail.com>
Tue, 20 Dec 2011 19:12:52 +0000 (19:12 +0000)
1  2 
src/bitcoinrpc.cpp
src/checkpoints.cpp
src/init.cpp
src/main.cpp
src/main.h
src/makefile.unix
src/net.cpp
src/util.cpp
src/wallet.cpp

diff --combined src/bitcoinrpc.cpp
@@@ -4,7 -4,6 +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"
@@@ -37,6 -36,8 +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;
  
@@@ -50,13 -51,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
  }
  
  
  int64 AmountFromValue(const Value& value)
  {
      double dAmount = value.get_real();
 -    if (dAmount <= 0.0 || dAmount > 21000000.0)
 +    if (dAmount <= 0.0 || dAmount > MAX_MONEY)
          throw JSONRPCError(-3, "Invalid amount");
      int64 nAmount = roundint64(dAmount * COIN);
      if (!MoneyRange(nAmount))
@@@ -131,6 -128,7 +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)
@@@ -165,10 -163,13 +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
  }
  
  
@@@ -183,12 -184,13 +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;
  }
@@@ -483,13 -485,12 +485,13 @@@ Value settxfee(const Array& params, boo
      if (fHelp || params.size() < 1 || params.size() > 1)
          throw runtime_error(
              "settxfee <amount>\n"
 -            "<amount> is a real and is rounded to the nearest 0.00000001");
 +            "<amount> is a real and is rounded to the nearest 0.0001\n"
 +            "Minimum and default transaction fee is 1 coin");
  
      // Amount
 -    int64 nAmount = 0;
 -    if (params[0].get_real() != 0.0)
 -        nAmount = AmountFromValue(params[0]);        // rejects 0.0 amounts
 +    int64 nAmount = MIN_TX_FEE;
 +    if (params[0].get_real() != 0.0)                    // rejects 0.0 amounts
 +        nAmount = max(nAmount, AmountFromValue(params[0]));
  
      nTransactionFee = nAmount;
      return true;
@@@ -531,6 -532,72 +533,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)
  {
@@@ -942,7 -1009,6 +1010,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);
@@@ -1199,6 -1264,70 +1265,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)
@@@ -1326,21 -1455,16 +1456,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(
@@@ -1366,15 -1490,15 +1491,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;
  }
@@@ -1432,10 -1546,16 +1547,16 @@@ Value encryptwallet(const Array& params
      if (pwalletMain->IsCrypted())
          throw JSONRPCError(-15, "Error: running with an encrypted wallet, but encryptwallet was called.");
  
-     string strWalletPass;
+ #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
+     // 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());
  
-     return Value::null;
+     // 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
+     // unencrypted private keys.  So:
+     CreateThread(Shutdown, NULL);
+     return "wallet encrypted; bitcoin server stopping, restart to run with encrypted wallet";
  }
  
  
@@@ -1487,9 -1605,9 +1606,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);
+     }
+ }
  
  
  
@@@ -1614,20 -1819,13 +1820,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]));
  
@@@ -1652,7 -1854,7 +1855,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]));
  
@@@ -1693,6 -1893,7 +1894,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";
@@@ -1733,12 -1934,13 +1935,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(),
@@@ -1816,43 -2018,6 +2019,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;
  }
  
  //
@@@ -1998,7 -2158,8 +2159,8 @@@ void ThreadRPCServer2(void* parg
  {
      printf("ThreadRPCServer started\n");
  
-     if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
+     strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
+     if (strRPCUserColonPass == ":")
      {
          string strWhatAmI = "To use bitcoind";
          if (mapArgs.count("-server"))
          else if (mapArgs.count("-daemon"))
              strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
          PrintConsole(
-             _("Warning: %s, you must set rpcpassword=<password>\nin the configuration file: %s\n"
+             _("Error: %s, you must set rpcpassword=<password>\nin the configuration file: %s\n"
                "If the file does not exist, create it with owner-readable-only file permissions.\n"),
                  strWhatAmI.c_str(),
                  GetConfigFile().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
@@@ -2290,18 -2453,12 +2454,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/checkpoints.cpp
index 0000000,c7e054d..d20fe24
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,65 +1,57 @@@
+ // Copyright (c) 2011 The Bitcoin developers
+ // Distributed under the MIT/X11 software license, see the accompanying
+ // file license.txt or http://www.opensource.org/licenses/mit-license.php.
+ #include <boost/assign/list_of.hpp> // for 'map_list_of()'
+ #include <boost/foreach.hpp>
+ #include "headers.h"
+ #include "checkpoints.h"
+ namespace Checkpoints
+ {
+     typedef std::map<int, uint256> MapCheckpoints;
+     //
+     // What makes a good checkpoint block?
+     // + Is surrounded by blocks with reasonable timestamps
+     //   (no blocks before with a timestamp after, none after with
+     //    timestamp before)
+     // + Contains no strange transactions
+     //
+     static MapCheckpoints mapCheckpoints =
+         boost::assign::map_list_of
 -        ( 11111, uint256("0x0000000069e244f73d78e8fd29ba2fd2ed618bd6fa2ee92559f542fdb26e7c1d"))
 -        ( 33333, uint256("0x000000002dd5588a74784eaa7ab0507a18ad16a236e7b1ce69f00d7ddfb5d0a6"))
 -        ( 68555, uint256("0x00000000001e1b4903550a0b96e9a9405c8a95f387162e4944e8d9fbe501cd6a"))
 -        ( 70567, uint256("0x00000000006a49b14bcf27462068f1264c961f11fa2e0eddd2be0791e1d4124a"))
 -        ( 74000, uint256("0x0000000000573993a3c9e41ce34471c079dcf5f52a0e824a81e7f953b8661a20"))
 -        (105000, uint256("0x00000000000291ce28027faea320c8d2b054b2e0fe44a773f3eefb151d6bdc97"))
 -        (118000, uint256("0x000000000000774a7f8a7a12dc906ddb9e17e75d684f15e00f8767f9e8f36553"))
 -        (134444, uint256("0x00000000000005b12ffd4cd315cd34ffd4a594f430ac814c91184a0d42d2b0fe"))
 -        (140700, uint256("0x000000000000033b512028abb90e1626d8b346fd0ed598ac0a3c371138dce2bd"))
 -        ;
++        ( 0, hashGenesisBlock )
++        ; // ppcoin: no checkpoint yet; to be created in future releases
+     bool CheckBlock(int nHeight, const uint256& hash)
+     {
+         if (fTestNet) return true; // Testnet has no checkpoints
+         MapCheckpoints::const_iterator i = mapCheckpoints.find(nHeight);
+         if (i == mapCheckpoints.end()) return true;
+         return hash == i->second;
+     }
+     int GetTotalBlocksEstimate()
+     {
+         if (fTestNet) return 0;
+         return mapCheckpoints.rbegin()->first;
+     }
+     CBlockIndex* GetLastCheckpoint(const std::map<uint256, CBlockIndex*>& mapBlockIndex)
+     {
+         if (fTestNet) return NULL;
+         int64 nResult;
+         BOOST_REVERSE_FOREACH(const MapCheckpoints::value_type& i, mapCheckpoints)
+         {
+             const uint256& hash = i.second;
+             std::map<uint256, CBlockIndex*>::const_iterator t = mapBlockIndex.find(hash);
+             if (t != mapBlockIndex.end())
+                 return t->second;
+         }
+         return NULL;
+     }
+ }
diff --combined src/init.cpp
@@@ -1,11 -1,10 +1,11 @@@
  // Copyright (c) 2009-2010 Satoshi Nakamoto
  // Copyright (c) 2011 The Bitcoin developers
 +// Copyright (c) 2011 The PPCoin developers
  // Distributed under the MIT/X11 software license, see the accompanying
  // file license.txt or http://www.opensource.org/licenses/mit-license.php.
  #include "headers.h"
  #include "db.h"
- #include "rpc.h"
+ #include "bitcoinrpc.h"
  #include "net.h"
  #include "init.h"
  #include "strlcpy.h"
  #include <boost/filesystem/fstream.hpp>
  #include <boost/interprocess/sync/file_lock.hpp>
  
+ #if defined(BITCOIN_NEED_QT_PLUGINS) && !defined(_BITCOIN_QT_PLUGINS_INCLUDED)
+ #define _BITCOIN_QT_PLUGINS_INCLUDED
+ #define __INSURE__
+ #include <QtPlugin>
+ Q_IMPORT_PLUGIN(qcncodecs)
+ Q_IMPORT_PLUGIN(qjpcodecs)
+ Q_IMPORT_PLUGIN(qtwcodecs)
+ Q_IMPORT_PLUGIN(qkrcodecs)
+ #endif
  using namespace std;
  using namespace boost;
  
@@@ -25,7 -34,7 +35,7 @@@ CWallet* pwalletMain
  
  void ExitTimeout(void* parg)
  {
- #ifdef __WXMSW__
+ #ifdef WIN32
      Sleep(5000);
      ExitProcess(0);
  #endif
@@@ -35,8 -44,8 +45,8 @@@ void Shutdown(void* parg
  {
      static CCriticalSection cs_Shutdown;
      static bool fTaken;
-     bool fFirstThread;
-     CRITICAL_BLOCK(cs_Shutdown)
+     bool fFirstThread = false;
+     TRY_CRITICAL_BLOCK(cs_Shutdown)
      {
          fFirstThread = !fTaken;
          fTaken = true;
@@@ -81,8 -90,7 +91,8 @@@ void HandleSIGTERM(int
  //
  // Start
  //
- #ifndef GUI
+ #if !defined(QT_GUI)
 +#if !defined(PPCOIN_GENESIS)
  int main(int argc, char* argv[])
  {
      bool fRet = false;
      return 1;
  }
  #endif
 +#endif
  
  bool AppInit(int argc, char* argv[])
  {
@@@ -124,10 -131,10 +134,10 @@@ bool AppInit2(int argc, char* argv[]
      // Disable confusing "helpful" text message on abort, ctrl-c
      _set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
  #endif
- #ifndef __WXMSW__
+ #ifndef WIN32
      umask(077);
  #endif
- #ifndef __WXMSW__
+ #ifndef WIN32
      // Clean shutdown on SIGTERM
      struct sigaction sa;
      sa.sa_handler = HandleSIGTERM;
          string strUsage = string() +
            _("Bitcoin version") + " " + FormatFullVersion() + "\n\n" +
            _("Usage:") + "\t\t\t\t\t\t\t\t\t\t\n" +
-             "  bitcoin [options]                   \t  " + "\n" +
-             "  bitcoin [options] <command> [params]\t  " + _("Send command to -server or bitcoind\n") +
-             "  bitcoin [options] help              \t\t  " + _("List commands\n") +
-             "  bitcoin [options] help <command>    \t\t  " + _("Get help for a command\n") +
+             "  bitcoind [options]                   \t  " + "\n" +
+             "  bitcoind [options] <command> [params]\t  " + _("Send command to -server or bitcoind\n") +
+             "  bitcoind [options] help              \t\t  " + _("List commands\n") +
+             "  bitcoind [options] help <command>    \t\t  " + _("Get help for a command\n") +
            _("Options:\n") +
 -            "  -conf=<file>     \t\t  " + _("Specify configuration file (default: bitcoin.conf)\n") +
 -            "  -pid=<file>      \t\t  " + _("Specify pid file (default: bitcoind.pid)\n") +
 +            "  -conf=<file>     \t\t  " + _("Specify configuration file (default: ppcoin.conf)\n") +
 +            "  -pid=<file>      \t\t  " + _("Specify pid file (default: ppcoind.pid)\n") +
              "  -gen             \t\t  " + _("Generate coins\n") +
              "  -gen=0           \t\t  " + _("Don't generate coins\n") +
              "  -min             \t\t  " + _("Start minimized\n") +
              "  -timeout=<n>     \t  "   + _("Specify connection timeout (in milliseconds)\n") +
              "  -proxy=<ip:port> \t  "   + _("Connect through socks4 proxy\n") +
              "  -dns             \t  "   + _("Allow DNS lookups for addnode and connect\n") +
+             "  -port=<port>     \t\t  " + _("Listen for connections on <port> (default: 8333 or testnet: 18333)\n") +
+             "  -maxconnections=<n>\t  " + _("Maintain at most <n> connections to peers (default: 125)\n") +
              "  -addnode=<ip>    \t  "   + _("Add a node to connect to\n") +
              "  -connect=<ip>    \t\t  " + _("Connect only to the specified node\n") +
              "  -nolisten        \t  "   + _("Don't accept connections from outside\n") +
+             "  -nodnsseed       \t  "   + _("Don't bootstrap list of peers using DNS\n") +
+             "  -banscore=<n>    \t  "   + _("Threshold for disconnecting misbehaving peers (default: 100)\n") +
+             "  -bantime=<n>     \t  "   + _("Number of seconds to keep misbehaving peers from reconnecting (default: 86400)\n") +
+             "  -maxreceivebuffer=<n>\t  " + _("Maximum per-connection receive buffer, <n>*1000 bytes (default: 10000)\n") +
+             "  -maxsendbuffer=<n>\t  "   + _("Maximum per-connection send buffer, <n>*1000 bytes (default: 10000)\n") +
  #ifdef USE_UPNP
  #if USE_UPNP
              "  -noupnp          \t  "   + _("Don't attempt to use UPnP to map the listening port\n") +
  #ifdef GUI
              "  -server          \t\t  " + _("Accept command line and JSON-RPC commands\n") +
  #endif
- #ifndef __WXMSW__
+ #ifndef WIN32
              "  -daemon          \t\t  " + _("Run in the background as a daemon and accept commands\n") +
  #endif
              "  -testnet         \t\t  " + _("Use the test network\n") +
+             "  -debug           \t\t  " + _("Output extra debugging information\n") +
+             "  -logtimestamps   \t  "   + _("Prepend debug output with timestamp\n") +
+             "  -printtoconsole  \t  "   + _("Send trace/debug info to console instead of debug.log file\n") +
+ #ifdef WIN32
+             "  -printtodebugger \t  "   + _("Send trace/debug info to debugger\n") +
+ #endif
              "  -rpcuser=<user>  \t  "   + _("Username for JSON-RPC connections\n") +
              "  -rpcpassword=<pw>\t  "   + _("Password for JSON-RPC connections\n") +
              "  -rpcport=<port>  \t\t  " + _("Listen for JSON-RPC connections on <port> (default: 8332)\n") +
          strUsage += string() +
              "  -?               \t\t  " + _("This help message\n");
  
          // Remove tabs
          strUsage.erase(std::remove(strUsage.begin(), strUsage.end(), '\t'), strUsage.end());
          fprintf(stderr, "%s", strUsage.c_str());
- #endif
          return false;
      }
  
      fDebug = GetBoolArg("-debug");
      fAllowDNS = GetBoolArg("-dns");
  
- #ifndef __WXMSW__
+ #ifndef WIN32
      fDaemon = GetBoolArg("-daemon");
  #else
      fDaemon = false;
          fServer = GetBoolArg("-server");
  
      /* force fServer when running without GUI */
- #ifndef GUI
+ #if !defined(QT_GUI)
      fServer = true;
  #endif
      fPrintToConsole = GetBoolArg("-printtoconsole");
      fPrintToDebugger = GetBoolArg("-printtodebugger");
  
      fNoListen = GetBoolArg("-nolisten") || fTOR;
      fLogTimestamps = GetBoolArg("-logtimestamps");
  
+ #ifndef QT_GUI
      for (int i = 1; i < argc; i++)
          if (!IsSwitchChar(argv[i][0]))
              fCommandLine = true;
          int ret = CommandLineRPC(argc, argv);
          exit(ret);
      }
+ #endif
  
- #ifndef __WXMSW__
+ #ifndef WIN32
      if (fDaemon)
      {
          // Daemonize
          ShrinkDebugFile();
      printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
      printf("Bitcoin version %s\n", FormatFullVersion().c_str());
- #ifdef GUI
-     printf("OS version %s\n", ((string)wxGetOsDescription()).c_str());
-     printf("System default language is %d %s\n", g_locale.GetSystemLanguage(), ((string)g_locale.GetSysName()).c_str());
-     printf("Language file %s (%s)\n", (string("locale/") + (string)g_locale.GetCanonicalName() + "/LC_MESSAGES/bitcoin.mo").c_str(), ((string)g_locale.GetLocale()).c_str());
- #endif
      printf("Default data directory %s\n", GetDefaultDataDir().c_str());
  
      if (GetBoolArg("-loadblockindextest"))
          return false;
      }
  
-     //
-     // Limit to single instance per user
-     // Required to protect the database files if we're going to keep deleting log.*
-     //
- #if defined(__WXMSW__) && defined(GUI)
-     // wxSingleInstanceChecker doesn't work on Linux
-     wxString strMutexName = wxString("bitcoin_running.") + getenv("HOMEPATH");
-     for (int i = 0; i < strMutexName.size(); i++)
-         if (!isalnum(strMutexName[i]))
-             strMutexName[i] = '.';
-     wxSingleInstanceChecker* psingleinstancechecker = new wxSingleInstanceChecker(strMutexName);
-     if (psingleinstancechecker->IsAnotherRunning())
-     {
-         printf("Existing instance found\n");
-         unsigned int nStart = GetTime();
-         loop
-         {
-             // Show the previous instance and exit
-             HWND hwndPrev = FindWindowA("wxWindowClassNR", "Bitcoin");
-             if (hwndPrev)
-             {
-                 if (IsIconic(hwndPrev))
-                     ShowWindow(hwndPrev, SW_RESTORE);
-                 SetForegroundWindow(hwndPrev);
-                 return false;
-             }
-             if (GetTime() > nStart + 60)
-                 return false;
-             // Resume this instance if the other exits
-             delete psingleinstancechecker;
-             Sleep(1000);
-             psingleinstancechecker = new wxSingleInstanceChecker(strMutexName);
-             if (!psingleinstancechecker->IsAnotherRunning())
-                 break;
-         }
-     }
- #endif
      // Make sure only a single bitcoin process is using the data directory.
      string strLockFile = GetDataDir() + "/.lock";
      FILE* file = fopen(strLockFile.c_str(), "a"); // empty lock file; created if it doesn't exist.
      strErrors = "";
      int64 nStart;
  
+     InitMessage(_("Loading addresses..."));
      printf("Loading addresses...\n");
      nStart = GetTimeMillis();
      if (!LoadAddresses())
          strErrors += _("Error loading addr.dat      \n");
      printf(" addresses   %15"PRI64d"ms\n", GetTimeMillis() - nStart);
  
+     InitMessage(_("Loading block index..."));
      printf("Loading block index...\n");
      nStart = GetTimeMillis();
      if (!LoadBlockIndex())
          strErrors += _("Error loading blkindex.dat      \n");
      printf(" block index %15"PRI64d"ms\n", GetTimeMillis() - nStart);
  
+     InitMessage(_("Loading wallet..."));
      printf("Loading wallet...\n");
      nStart = GetTimeMillis();
      bool fFirstRun;
              strErrors += _("Error loading wallet.dat: Wallet corrupted      \n");
          else if (nLoadWalletRet == DB_TOO_NEW)
              strErrors += _("Error loading wallet.dat: Wallet requires newer version of Bitcoin      \n");
+         else if (nLoadWalletRet == DB_NEED_REWRITE)
+         {
+             strErrors += _("Wallet needed to be rewritten: restart Bitcoin to complete    \n");
+             wxMessageBox(strErrors, "Bitcoin", wxOK | wxICON_ERROR);
+             return false;
+         }
          else
              strErrors += _("Error loading wallet.dat      \n");
      }
      }
      if (pindexBest != pindexRescan)
      {
+         InitMessage(_("Rescanning..."));
          printf("Rescanning last %i blocks (from block %i)...\n", pindexBest->nHeight - pindexRescan->nHeight, pindexRescan->nHeight);
          nStart = GetTimeMillis();
          pwalletMain->ScanForWalletTransactions(pindexRescan, true);
          printf(" rescan      %15"PRI64d"ms\n", GetTimeMillis() - nStart);
      }
  
+     InitMessage(_("Done loading"));
      printf("Done loading\n");
  
          //// debug print
          }
      }
  
-     if (GetBoolArg("-nodnsseed"))
-         printf("DNS seeding disabled\n");
-     else
-         DNSAddressSeed();
      if (mapArgs.count("-paytxfee"))
      {
          if (!ParseMoney(mapArgs["-paytxfee"], nTransactionFee))
              wxMessageBox(_("Invalid amount for -paytxfee=<amount>"), "Bitcoin");
              return false;
          }
 -        if (nTransactionFee > 0.25 * COIN)
 +        if (nTransactionFee >= 10 * COIN)
              wxMessageBox(_("Warning: -paytxfee is set very high.  This is the transaction fee you will pay if you send a transaction."), "Bitcoin", wxOK | wxICON_EXCLAMATION);
      }
  
      }
  
      //
-     // Create the main window and start the node
+     // Start the node
      //
- #ifdef GUI
-     if (!fDaemon)
-         CreateMainWindow();
- #endif
      if (!CheckDiskSpace())
          return false;
  
      RandAddSeedPerfmon();
  
      if (!CreateThread(StartNode, NULL))
-         wxMessageBox("Error: CreateThread(StartNode) failed", "Bitcoin");
+         wxMessageBox(_("Error: CreateThread(StartNode) failed"), "Bitcoin");
  
      if (fServer)
          CreateThread(ThreadRPCServer, NULL);
  
- #if defined(__WXMSW__) && defined(GUI)
-     if (fFirstRun)
-         SetStartOnSystemStartup(true);
- #endif
- #ifndef GUI
+ #if !defined(QT_GUI)
      while (1)
          Sleep(5000);
  #endif
diff --combined src/main.cpp
@@@ -1,13 -1,12 +1,13 @@@
  // Copyright (c) 2009-2010 Satoshi Nakamoto
  // Copyright (c) 2011 The Bitcoin developers
 +// Copyright (c) 2011 The PPCoin developers
  // Distributed under the MIT/X11 software license, see the accompanying
  // file license.txt or http://www.opensource.org/licenses/mit-license.php.
  #include "headers.h"
+ #include "checkpoints.h"
  #include "db.h"
  #include "net.h"
  #include "init.h"
- #include "cryptopp/sha.h"
  #include <boost/filesystem.hpp>
  #include <boost/filesystem/fstream.hpp>
  
@@@ -29,9 -28,8 +29,8 @@@ unsigned int nTransactionsUpdated = 0
  map<COutPoint, CInPoint> mapNextTx;
  
  map<uint256, CBlockIndex*> mapBlockIndex;
 -uint256 hashGenesisBlock("0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f");
 +uint256 hashGenesisBlock("0x00000000e74ef41733382f8a94d41bf29f20c6c48a7ab489e1fab0ab719bf676");
  static CBigNum bnProofOfWorkLimit(~uint256(0) >> 32);
- const int nTotalBlocksEstimate = 0; // Conservative estimate of total nr of blocks on main chain
  const int nInitialBlockThreshold = 120; // Regard blocks up until N-threshold as "initial download"
  CBlockIndex* pindexGenesisBlock = NULL;
  int nBestHeight = -1;
@@@ -41,6 -39,8 +40,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;
  
@@@ -53,7 -53,7 +54,7 @@@ int64 nHPSTimerStart
  
  // Settings
  int fGenerateBitcoins = false;
 -int64 nTransactionFee = 0;
 +int64 nTransactionFee = MIN_TX_FEE;
  int fLimitProcessors = false;
  int nLimitProcessors = 1;
  int fMinimizeToTray = true;
@@@ -65,16 -65,14 +66,14 @@@ int fUseUPnP = false
  #endif
  
  
  //////////////////////////////////////////////////////////////////////////////
  //
  // dispatching functions
  //
  
+ // These functions dispatch to one or all registered wallets
  void RegisterWallet(CWallet* pwalletIn)
  {
      CRITICAL_BLOCK(cs_setpwalletRegistered)
@@@ -91,6 -89,7 +90,7 @@@ void UnregisterWallet(CWallet* pwalletI
      }
  }
  
+ // check whether the passed transaction is from us
  bool static IsFromMe(CTransaction& tx)
  {
      BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
@@@ -99,6 -98,7 +99,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)
@@@ -297,24 -304,24 +305,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;
@@@ -351,7 -358,7 +359,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())
          }
  
          // Don't accept it if it can't get into a block
 -        if (nFees < GetMinFee(1000, true, true))
 +        if (nFees < GetMinFee(1000, false, true))
              return error("AcceptToMemoryPool() : not enough fees");
  
          // Continuously rate-limit free transactions
@@@ -652,28 -659,70 +660,48 @@@ int64 static GetBlockValue(int nHeight
      return nSubsidy + nFees;
  }
  
- unsigned int static GetNextWorkRequired(const CBlockIndex* pindexLast)
 -static const int64 nTargetTimespan = 14 * 24 * 60 * 60; // two weeks
++static const int64 nTargetTimespan = 7 * 24 * 60 * 60; // one week
+ static const int64 nTargetSpacing = 10 * 60;
+ static const int64 nInterval = nTargetTimespan / nTargetSpacing;
+ //
+ // minimum amount of work that could possibly be required nTime after
+ // minimum work required was nBase
+ //
+ unsigned int ComputeMinWork(unsigned int nBase, int64 nTime)
  {
-     const int64 nTargetTimespan = 7 * 24 * 60 * 60; // one week
-     const int64 nTargetSpacing = 10 * 60;
-     const int64 nInterval = nTargetTimespan / nTargetSpacing;
+     CBigNum bnResult;
+     bnResult.SetCompact(nBase);
+     while (nTime > 0 && bnResult < bnProofOfWorkLimit)
+     {
+         // Maximum 400% adjustment...
+         bnResult *= 4;
+         // ... in best-case exactly 4-times-normal target time
+         nTime -= nTargetTimespan*4;
+     }
+     if (bnResult > bnProofOfWorkLimit)
+         bnResult = bnProofOfWorkLimit;
+     return bnResult.GetCompact();
+ }
  
+ unsigned int static GetNextWorkRequired(const CBlockIndex* pindexLast)
+ {
 -
 -    // Genesis block
 -    if (pindexLast == NULL)
 +    // Genesis block and first block
 +    if (pindexLast == NULL || pindexLast->pprev == NULL)
          return bnProofOfWorkLimit.GetCompact();
  
 -    // Only change once per interval
 -    if ((pindexLast->nHeight+1) % nInterval != 0)
 -        return pindexLast->nBits;
 -
 -    // Go back by what we want to be 14 days worth of blocks
 -    const CBlockIndex* pindexFirst = pindexLast;
 -    for (int i = 0; pindexFirst && i < nInterval-1; i++)
 -        pindexFirst = pindexFirst->pprev;
 -    assert(pindexFirst);
 -
 -    // Limit adjustment step
 -    int64 nActualTimespan = pindexLast->GetBlockTime() - pindexFirst->GetBlockTime();
 -    printf("  nActualTimespan = %"PRI64d"  before bounds\n", nActualTimespan);
 -    if (nActualTimespan < nTargetTimespan/4)
 -        nActualTimespan = nTargetTimespan/4;
 -    if (nActualTimespan > nTargetTimespan*4)
 -        nActualTimespan = nTargetTimespan*4;
 -
 -    // Retarget
 +    int64 nActualSpacing = pindexLast->GetBlockTime() - pindexLast->pprev->GetBlockTime();
 +
 +    // ppcoin: target change every block
 +    // ppcoin: retarget with exponential moving toward target spacing
      CBigNum bnNew;
      bnNew.SetCompact(pindexLast->nBits);
 -    bnNew *= nActualTimespan;
 -    bnNew /= nTargetTimespan;
 +    bnNew *= ((nInterval - 1) * nTargetSpacing + nActualSpacing + nActualSpacing);
 +    bnNew /= ((nInterval + 1) * nTargetSpacing);
  
      if (bnNew > bnProofOfWorkLimit)
          bnNew = bnProofOfWorkLimit;
  
 -    /// debug print
 -    printf("GetNextWorkRequired RETARGET\n");
 -    printf("nTargetTimespan = %"PRI64d"    nActualTimespan = %"PRI64d"\n", nTargetTimespan, nActualTimespan);
 -    printf("Before: %08x  %s\n", pindexLast->nBits, CBigNum().SetCompact(pindexLast->nBits).getuint256().ToString().c_str());
 -    printf("After:  %08x  %s\n", bnNew.GetCompact(), bnNew.getuint256().ToString().c_str());
 -
      return bnNew.GetCompact();
  }
  
@@@ -693,22 -742,15 +721,15 @@@ bool CheckProofOfWork(uint256 hash, uns
      return true;
  }
  
- // Return conservative estimate of total number of blocks, 0 if unknown
- int GetTotalBlocksEstimate()
+ // Return maximum amount of blocks that other nodes claim to have
+ int GetNumBlocksOfPeers()
  {
-     if(fTestNet)
-     {
-         return 0;
-     }
-     else
-     {
-         return nTotalBlocksEstimate;
-     }
+     return std::max(cPeerBlockCounts.median(), Checkpoints::GetTotalBlocksEstimate());
  }
  
  bool IsInitialBlockDownload()
  {
-     if (pindexBest == NULL || nBestHeight < (GetTotalBlocksEstimate()-nInitialBlockThreshold))
+     if (pindexBest == NULL || nBestHeight < (Checkpoints::GetTotalBlocksEstimate()-nInitialBlockThreshold))
          return true;
      static int64 nLastUpdate;
      static CBlockIndex* pindexLastBest;
@@@ -783,6 -825,9 +804,9 @@@ bool CTransaction::ConnectInputs(CTxDB
                                   CBlockIndex* pindexBlock, int64& nFees, bool fBlock, bool fMiner, int64 nMinFee)
  {
      // Take over previous transactions' spent pointers
+     // fBlock is true when this is called from AcceptBlock when a new best-block is added to the blockchain
+     // fMiner is true when called from the internal bitcoin miner
+     // ... both are false when called from CTransaction::AcceptToMemoryPool
      if (!IsCoinBase())
      {
          int64 nValueIn = 0;
              }
  
              if (prevout.n >= txPrev.vout.size() || prevout.n >= txindex.vSpent.size())
-                 return error("ConnectInputs() : %s prevout.n out of range %d %d %d prev tx %s\n%s", GetHash().ToString().substr(0,10).c_str(), prevout.n, txPrev.vout.size(), txindex.vSpent.size(), prevout.hash.ToString().substr(0,10).c_str(), txPrev.ToString().c_str());
+                 return DoS(100, error("ConnectInputs() : %s prevout.n out of range %d %d %d prev tx %s\n%s", GetHash().ToString().substr(0,10).c_str(), prevout.n, txPrev.vout.size(), txindex.vSpent.size(), prevout.hash.ToString().substr(0,10).c_str(), txPrev.ToString().c_str()));
  
              // If prev is coinbase, check that it's matured
              if (txPrev.IsCoinBase())
                      if (pindex->nBlockPos == txindex.pos.nBlockPos && pindex->nFile == txindex.pos.nFile)
                          return error("ConnectInputs() : tried to spend coinbase at depth %d", pindexBlock->nHeight - pindex->nHeight);
  
-             // Verify signature
-             if (!VerifySignature(txPrev, *this, i))
-                 return error("ConnectInputs() : %s VerifySignature failed", GetHash().ToString().substr(0,10).c_str());
-             // Check for conflicts
+             // Skip ECDSA signature verification when connecting blocks (fBlock=true) during initial download
+             // (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 && IsInitialBlockDownload()))
+                 // 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)
@@@ -1213,11 -1264,11 +1243,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;
  }
@@@ -1256,13 -1307,13 +1286,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))
-         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 (!fTestNet)
-         // ppcoin: no checkpoint yet; to be created after beta
-         if ((nHeight == -1 && hash != uint256("0x83f760b87b13d7002eaccc4a5a154aaea0f861e52b6eb481d30a344f55605c01")))
-             return error("AcceptBlock() : rejected by checkpoint lockin at %d", nHeight);
+     if (!Checkpoints::CheckBlock(nHeight, hash))
+         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();
      if (!pblock->CheckBlock())
          return error("ProcessBlock() : CheckBlock FAILED");
  
+     CBlockIndex* pcheckpoint = Checkpoints::GetLastCheckpoint(mapBlockIndex);
+     if (pcheckpoint && pblock->hashPrevBlock != hashBestChain)
+     {
+         // Extra checks to prevent "fill up memory by spamming with bogus blocks"
+         int64 deltaTime = pblock->GetBlockTime() - pcheckpoint->nTime;
+         if (deltaTime < 0)
+         {
+             pfrom->Misbehaving(100);
+             return error("ProcessBlock() : block with timestamp before last checkpoint");
+         }
+         CBigNum bnNewBlock;
+         bnNewBlock.SetCompact(pblock->nBits);
+         CBigNum bnRequired;
+         bnRequired.SetCompact(ComputeMinWork(pcheckpoint->nBits, deltaTime));
+         if (bnNewBlock > bnRequired)
+         {
+             pfrom->Misbehaving(100);
+             return error("ProcessBlock() : block with too little proof-of-work");
+         }
+     }
      // If don't already have its previous block, shunt it off to holding area until we get it
      if (!mapBlockIndex.count(pblock->hashPrevBlock))
      {
@@@ -1455,7 -1526,7 +1505,7 @@@ bool LoadBlockIndex(bool fAllowNew
          //   vMerkleTree: 4a5e1e
  
          // Genesis block
 -        const char* pszTimestamp = "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks";
 +        const char* pszTimestamp = "MarketWatch 07/Nov/2011 Gold tops $1,790 to end at over six-week high";
          CTransaction txNew;
          txNew.vin.resize(1);
          txNew.vout.resize(1);
          block.hashPrevBlock = 0;
          block.hashMerkleRoot = block.BuildMerkleTree();
          block.nVersion = 1;
 -        block.nTime    = 1231006505;
 +        block.nTime    = 1320941849;
          block.nBits    = 0x1d00ffff;
 -        block.nNonce   = 2083236893;
 +        block.nNonce   = 725069208;
  
          if (fTestNet)
          {
          printf("%s\n", block.GetHash().ToString().c_str());
          printf("%s\n", hashGenesisBlock.ToString().c_str());
          printf("%s\n", block.hashMerkleRoot.ToString().c_str());
 -        assert(block.hashMerkleRoot == uint256("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"));
 +        assert(block.hashMerkleRoot == uint256("0x09cc647316c90e7e14f225113eec3539e80284695c91e7262a65c72c5d75a868"));
          block.print();
          assert(block.GetHash() == hashGenesisBlock);
  
@@@ -1735,7 -1806,10 +1785,10 @@@ bool static ProcessMessage(CNode* pfrom
      {
          // Each connection can only send one version message
          if (pfrom->nVersion != 0)
+         {
+             pfrom->Misbehaving(1);
              return false;
+         }
  
          int64 nTime;
          CAddress addrMe;
          pfrom->fSuccessfullyConnected = true;
  
          printf("version message: version %d, blocks=%d\n", pfrom->nVersion, pfrom->nStartingHeight);
+         cPeerBlockCounts.input(pfrom->nStartingHeight);
      }
  
  
      else if (pfrom->nVersion == 0)
      {
          // Must have a version message before anything else
+         pfrom->Misbehaving(1);
          return false;
      }
  
          if (pfrom->nVersion < 31402 && mapAddresses.size() > 1000)
              return true;
          if (vAddr.size() > 1000)
+         {
+             pfrom->Misbehaving(20);
              return error("message addr size() = %d", vAddr.size());
+         }
  
          // Store the new addresses
          CAddrDB addrDB;
          vector<CInv> vInv;
          vRecv >> vInv;
          if (vInv.size() > 50000)
+         {
+             pfrom->Misbehaving(20);
              return error("message inv size() = %d", vInv.size());
+         }
  
          CTxDB txdb("r");
          BOOST_FOREACH(const CInv& inv, vInv)
          vector<CInv> vInv;
          vRecv >> vInv;
          if (vInv.size() > 50000)
+         {
+             pfrom->Misbehaving(20);
              return error("message getdata size() = %d", vInv.size());
+         }
  
          BOOST_FOREACH(const CInv& inv, vInv)
          {
              printf("storing orphan tx %s\n", inv.hash.ToString().substr(0,10).c_str());
              AddOrphanTx(vMsg);
          }
+         if (tx.nDoS) pfrom->Misbehaving(tx.nDoS);
      }
  
  
  
          if (ProcessBlock(pfrom, &block))
              mapAlreadyAskedFor.erase(inv);
+         if (block.nDoS) pfrom->Misbehaving(block.nDoS);
      }
  
  
@@@ -2558,15 -2646,25 +2625,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];
  }
  
  //
@@@ -2728,8 -2826,9 +2805,8 @@@ CBlock* CreateNewBlock(CReserveKey& res
              if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS)
                  continue;
  
 -            // Transaction fee required depends on block size
 -            bool fAllowFree = (nBlockSize + nTxSize < 4000 || CTransaction::AllowFree(dPriority));
 -            int64 nMinFee = tx.GetMinFee(nBlockSize, fAllowFree, true);
 +            // ppcoin: simplify transaction fee - allow free = false
 +            int64 nMinFee = tx.GetMinFee(nBlockSize, false, true);
  
              // Connecting shouldn't fail due to dependency on other memory pool transactions
              // because we're already processing them in order of dependency
@@@ -2866,7 -2965,6 +2943,6 @@@ bool CheckWork(CBlock* pblock, CWallet
              return error("BitcoinMiner : ProcessBlock, block not accepted");
      }
  
-     Sleep(2000);
      return true;
  }
  
diff --combined src/main.h
@@@ -1,6 -1,5 +1,6 @@@
  // Copyright (c) 2009-2010 Satoshi Nakamoto
  // Copyright (c) 2011 The Bitcoin developers
 +// Copyright (c) 2011 The PPCoin developers
  // Distributed under the MIT/X11 software license, see the accompanying
  // file license.txt or http://www.opensource.org/licenses/mit-license.php.
  #ifndef BITCOIN_MAIN_H
@@@ -31,11 -30,11 +31,11 @@@ 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 int64 COIN = 100000000;
 -static const int64 CENT = 1000000;
 -static const int64 MIN_TX_FEE = 50000;
 +static const int64 COIN = 10000;
 +static const int64 CENT = 100;
 +static const int64 MIN_TX_FEE = 10000;
  static const int64 MIN_RELAY_TX_FEE = 10000;
 -static const int64 MAX_MONEY = 21000000 * COIN;
 +static const int64 MAX_MONEY = 800000000000000 * COIN;
  inline bool MoneyRange(int64 nValue) { return (nValue >= 0 && nValue <= MAX_MONEY); }
  static const int COINBASE_MATURITY = 100;
  // Threshold for nLockTime: below this value it is interpreted as block number, otherwise as UNIX timestamp.
@@@ -86,6 -85,7 +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);
@@@ -99,7 -99,8 +100,8 @@@ void IncrementExtraNonce(CBlock* pblock
  void FormatHashBuffers(CBlock* pblock, char* pmidstate, char* pdata, char* phash1);
  bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey);
  bool CheckProofOfWork(uint256 hash, unsigned int nBits);
- int GetTotalBlocksEstimate();
+ unsigned int ComputeMinWork(unsigned int nBase, int64 nTime);
+ int GetNumBlocksOfPeers();
  bool IsInitialBlockDownload();
  std::string GetWarnings(std::string strFor);
  
@@@ -376,7 -377,7 +378,7 @@@ public
      {
          if (scriptPubKey.size() < 6)
              return "CTxOut(error)";
 -        return strprintf("CTxOut(nValue=%"PRI64d".%08"PRI64d", scriptPubKey=%s)", nValue / COIN, nValue % COIN, scriptPubKey.ToString().substr(0,30).c_str());
 +        return strprintf("CTxOut(nValue=%s, scriptPubKey=%s)", FormatMoney(nValue).c_str(), scriptPubKey.ToString().substr(0,30).c_str());
      }
  
      void print() const
@@@ -400,6 -401,9 +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
  
          unsigned int nBytes = ::GetSerializeSize(*this, SER_NETWORK);
          unsigned int nNewBlockSize = nBlockSize + nBytes;
 -        int64 nMinFee = (1 + (int64)nBytes / 1000) * nBaseFee;
 +        int64 nMinFee = nBaseFee;          // ppcoin: simplify transaction fee
  
          if (fAllowFree)
          {
@@@ -787,6 -792,9 +793,9 @@@ public
      // memory only
      mutable std::vector<uint256> vMerkleTree;
  
+     // Denial-of-service detection:
+     mutable int nDoS;
+     bool DoS(int nDoSIn, bool fIn) const { nDoS += nDoSIn; return fIn; }
  
      CBlock()
      {
          nNonce = 0;
          vtx.clear();
          vMerkleTree.clear();
+         nDoS = 0;
      }
  
      bool IsNull() const
          fflush(fileout);
          if (!IsInitialBlockDownload() || (nBestHeight+1) % 500 == 0)
          {
- #ifdef __WXMSW__
+ #ifdef WIN32
              _commit(_fileno(fileout));
  #else
              fsync(fileno(fileout));
diff --combined src/makefile.unix
@@@ -1,47 -1,93 +1,94 @@@
  # Copyright (c) 2009-2010 Satoshi Nakamoto
 +# Copyright (c) 2011 The PPCoin developers
  # Distributed under the MIT/X11 software license, see the accompanying
  # file license.txt or http://www.opensource.org/licenses/mit-license.php.
  
- CXX=g++
- WXINCLUDEPATHS=$(shell wx-config --cxxflags)
+ USE_UPNP:=0
  
- WXLIBS=$(shell wx-config --libs)
+ DEFS=-DNOPCH
  
- USE_UPNP:=0
+ DEFS += $(addprefix -I,$(BOOST_INCLUDE_PATH) $(BDB_INCLUDE_PATH) $(OPENSSL_INCLUDE_PATH))
+ LIBS += $(addprefix -l,$(BOOST_LIB_PATH) $(BDB_LIB_PATH) $(OPENSSL_LIB_PATH))
  
- DEFS=-DNOPCH -DUSE_SSL
+ LMODE = dynamic
+ LMODE2 = dynamic
+ ifdef STATIC
+       LMODE = static
+       ifeq (${STATIC}, all)
+               LMODE2 = static
+       endif
+ endif
  
  # for boost 1.37, add -mt to the boost libraries
  LIBS= \
-  -Wl,-Bstatic \
-    -l boost_system \
-    -l boost_filesystem \
-    -l boost_program_options \
-    -l boost_thread \
-    -l db_cxx \
+  -Wl,-B$(LMODE) \
+    -l boost_system$(BOOST_LIB_SUFFIX) \
+    -l boost_filesystem$(BOOST_LIB_SUFFIX) \
+    -l boost_program_options$(BOOST_LIB_SUFFIX) \
+    -l boost_thread$(BOOST_LIB_SUFFIX) \
+    -l db_cxx$(BDB_LIB_SUFFIX) \
     -l ssl \
     -l crypto
  
- ifdef USE_UPNP
+ ifndef USE_UPNP
+       override USE_UPNP = -
+ endif
+ ifneq (${USE_UPNP}, -)
        LIBS += -l miniupnpc
        DEFS += -DUSE_UPNP=$(USE_UPNP)
  endif
  
+ ifneq (${USE_SSL}, 0)
+       DEFS += -DUSE_SSL
+ endif
  LIBS+= \
-  -Wl,-Bdynamic \
-    -l gthread-2.0 \
+  -Wl,-B$(LMODE2) \
     -l z \
     -l dl \
     -l pthread
  
  
- DEBUGFLAGS=-g -D__WXDEBUG__
- CXXFLAGS=-O2 -Wno-invalid-offsetof -Wformat $(DEBUGFLAGS) $(DEFS)
+ # Hardening
+ # Make some classes of vulnerabilities unexploitable in case one is discovered.
+ #
+     # This is a workaround for Ubuntu bug #691722, the default -fstack-protector causes
+     # -fstack-protector-all to be ignored unless -fno-stack-protector is used first.
+     # see: https://bugs.launchpad.net/ubuntu/+source/gcc-4.5/+bug/691722
+     HARDENING=-fno-stack-protector
+     # Stack Canaries
+     # Put numbers at the beginning of each stack frame and check that they are the same.
+     # If a stack buffer if overflowed, it writes over the canary number and then on return
+     # when that number is checked, it won't be the same and the program will exit with
+     # a "Stack smashing detected" error instead of being exploited.
+     HARDENING+=-fstack-protector-all -Wstack-protector
+     # Make some important things such as the global offset table read only as soon as
+     # the dynamic linker is finished building it. This will prevent overwriting of addresses
+     # which would later be jumped to.
+     HARDENING+=-Wl,-z,relro -Wl,-z,now
+     # Build position independent code to take advantage of Address Space Layout Randomization
+     # offered by some kernels.
+     # see doc/build-unix.txt for more information.
+     ifdef PIE
+         HARDENING+=-fPIE -pie
+     endif
+     # -D_FORTIFY_SOURCE=2 does some checking for potentially exploitable code patterns in
+     # the source such overflowing a statically defined buffer.
+     HARDENING+=-D_FORTIFY_SOURCE=2
+ #
+ DEBUGFLAGS=-g
+ CXXFLAGS=-O2
+ xCXXFLAGS=-pthread -Wno-invalid-offsetof -Wformat $(DEBUGFLAGS) $(DEFS) $(HARDENING) $(CXXFLAGS)
  HEADERS = \
      base58.h \
      bignum.h \
+     checkpoints.h \
      crypter.h \
      db.h \
      headers.h \
      net.h \
      noui.h \
      protocol.h \
-     rpc.h \
+     bitcoinrpc.h \
      script.h \
      serialize.h \
      strlcpy.h \
-     ui.h \
-     uibase.h \
      uint256.h \
      util.h \
      wallet.h
  
  OBJS= \
+     obj/checkpoints.o \
      obj/crypter.o \
      obj/db.o \
      obj/init.o \
      obj/main.o \
      obj/net.o \
      obj/protocol.o \
-     obj/rpc.o \
+     obj/bitcoinrpc.o \
      obj/script.o \
      obj/util.o \
-     obj/wallet.o \
-     cryptopp/obj/sha.o \
-     cryptopp/obj/cpu.o
+     obj/wallet.o
  
  
- all: bitcoin
+ all: bitcoind
  
+ # auto-generated dependencies:
+ -include obj/nogui/*.P
+ -include obj/test/*.P
  
- obj/%.o: %.cpp $(HEADERS)
-       $(CXX) -c $(CXXFLAGS) $(WXINCLUDEPATHS) -DGUI -o $@ $<
- cryptopp/obj/%.o: cryptopp/%.cpp
-       $(CXX) -c $(CXXFLAGS) -O3 -o $@ $<
- bitcoin: $(OBJS) obj/ui.o obj/uibase.o
-       $(CXX) $(CXXFLAGS) -o $@ $^ $(WXLIBS) $(LIBS)
- obj/nogui/%.o: %.cpp $(HEADERS)
-       $(CXX) -c $(CXXFLAGS) -o $@ $<
+ obj/nogui/%.o: %.cpp
+       $(CXX) -c $(xCXXFLAGS) -MMD -o $@ $<
+       @cp $(@:%.o=%.d) $(@:%.o=%.P); \
+         sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
+             -e '/^$$/ d' -e 's/$$/ :/' < $(@:%.o=%.d) >> $(@:%.o=%.P); \
+         rm -f $(@:%.o=%.d)
  
  bitcoind: $(OBJS:obj/%=obj/nogui/%)
-       $(CXX) $(CXXFLAGS) -o $@ $^ $(LIBS)
+       $(CXX) $(xCXXFLAGS) -o $@ $^ $(LDFLAGS) $(LIBS)
  
- obj/test/test_bitcoin.o: $(wildcard test/*.cpp) $(HEADERS)
-       $(CXX) -c $(CFLAGS) -o $@ test/test_bitcoin.cpp
+ obj/test/%.o: test/%.cpp
+       $(CXX) -c $(xCXXFLAGS) -MMD -o $@ $<
+       @cp $(@:%.o=%.d) $(@:%.o=%.P); \
+         sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
+             -e '/^$$/ d' -e 's/$$/ :/' < $(@:%.o=%.d) >> $(@:%.o=%.P); \
+         rm -f $(@:%.o=%.d)
  
  test_bitcoin: obj/test/test_bitcoin.o $(filter-out obj/nogui/init.o,$(OBJS:obj/%=obj/nogui/%))
-       $(CXX) $(CXXFLAGS) -o $@ $(LIBPATHS) $^ -Wl,-Bstatic -lboost_unit_test_framework $(LIBS)
+       $(CXX) $(xCXXFLAGS) -o $@ $(LIBPATHS) $^ -Wl,-Bstatic -lboost_unit_test_framework $(LDFLAGS) $(LIBS)
  
  clean:
-       -rm -f bitcoin bitcoind test_bitcoin genesis
 -      -rm -f bitcoind test_bitcoin
++      -rm -f bitcoind test_bitcoin genesis
        -rm -f obj/*.o
        -rm -f obj/nogui/*.o
        -rm -f obj/test/*.o
-       -rm -f cryptopp/obj/*.o
-       -rm -f headers.h.gch
+       -rm -f obj/*.P
+       -rm -f obj/nogui/*.P
+       -rm -f obj/test/*.P
 +      -rm -f ppcoin/obj/*.o
 +
 +ppcoin/obj/genesis.o: ppcoin/genesis.cpp
 +      $(CXX) -c $(CXXFLAGS) -o $@ $<
 +      $(CXX) -c $(CXXFLAGS) -DPPCOIN_GENESIS -o obj/nogui/init.o init.cpp
 +
 +genesis: ppcoin/obj/genesis.o $(OBJS:obj/%=obj/nogui/%)
 +      $(CXX) $(CXXFLAGS) -o $@ $^ $(LIBS)
 +      -rm -f obj/nogui/init.o
diff --combined src/net.cpp
@@@ -1,6 -1,5 +1,6 @@@
  // Copyright (c) 2009-2010 Satoshi Nakamoto
  // Copyright (c) 2011 The Bitcoin developers
 +// Copyright (c) 2011 The PPCoin developers
  // Distributed under the MIT/X11 software license, see the accompanying
  // file license.txt or http://www.opensource.org/licenses/mit-license.php.
  
@@@ -11,7 -10,7 +11,7 @@@
  #include "init.h"
  #include "strlcpy.h"
  
- #ifdef __WXMSW__
+ #ifdef WIN32
  #include <string.h>
  #endif
  
@@@ -33,6 -32,7 +33,7 @@@ void ThreadOpenConnections2(void* parg)
  #ifdef USE_UPNP
  void ThreadMapPort2(void* parg);
  #endif
+ void ThreadDNSAddressSeed2(void* parg);
  bool OpenNetworkConnection(const CAddress& addrConnect);
  
  
@@@ -103,7 -103,7 +104,7 @@@ bool ConnectSocket(const CAddress& addr
      bool fProxy = (fUseProxy && addrConnect.IsRoutable());
      struct sockaddr_in sockaddr = (fProxy ? addrProxy.GetSockAddr() : addrConnect.GetSockAddr());
  
- #ifdef __WXMSW__
+ #ifdef WIN32
      u_long fNonblock = 1;
      if (ioctlsocket(hSocket, FIONBIO, &fNonblock) == SOCKET_ERROR)
  #else
                  return false;
              }
              socklen_t nRetSize = sizeof(nRet);
- #ifdef __WXMSW__
+ #ifdef WIN32
              if (getsockopt(hSocket, SOL_SOCKET, SO_ERROR, (char*)(&nRet), &nRetSize) == SOCKET_ERROR)
  #else
              if (getsockopt(hSocket, SOL_SOCKET, SO_ERROR, &nRet, &nRetSize) == SOCKET_ERROR)
                  return false;
              }
          }
- #ifdef __WXMSW__
+ #ifdef WIN32
          else if (WSAGetLastError() != WSAEISCONN)
  #else
          else
      CNode::ConnectNode immediately turns the socket back to non-blocking
      but we'll turn it back to blocking just in case
      */
- #ifdef __WXMSW__
+ #ifdef WIN32
      fNonblock = 0;
      if (ioctlsocket(hSocket, FIONBIO, &fNonblock) == SOCKET_ERROR)
  #else
@@@ -675,7 -675,7 +676,7 @@@ CNode* ConnectNode(CAddress addrConnect
          printf("connected %s\n", addrConnect.ToString().c_str());
  
          // Set to nonblocking
- #ifdef __WXMSW__
+ #ifdef WIN32
          u_long nOne = 1;
          if (ioctlsocket(hSocket, FIONBIO, &nOne) == SOCKET_ERROR)
              printf("ConnectSocket() : ioctlsocket nonblocking setting failed, error %d\n", WSAGetLastError());
@@@ -727,6 -727,52 +728,52 @@@ void CNode::Cleanup(
  }
  
  
+ std::map<unsigned int, int64> CNode::setBanned;
+ CCriticalSection CNode::cs_setBanned;
+ void CNode::ClearBanned()
+ {
+     setBanned.clear();
+ }
+ bool CNode::IsBanned(unsigned int ip)
+ {
+     bool fResult = false;
+     CRITICAL_BLOCK(cs_setBanned)
+     {
+         std::map<unsigned int, int64>::iterator i = setBanned.find(ip);
+         if (i != setBanned.end())
+         {
+             int64 t = (*i).second;
+             if (GetTime() < t)
+                 fResult = true;
+         }
+     }
+     return fResult;
+ }
+ bool CNode::Misbehaving(int howmuch)
+ {
+     if (addr.IsLocal())
+     {
+         printf("Warning: local node %s misbehaving\n", addr.ToString().c_str());
+         return false;
+     }
+     nMisbehavior += howmuch;
+     if (nMisbehavior >= GetArg("-banscore", 100))
+     {
+         int64 banTime = GetTime()+GetArg("-bantime", 60*60*24);  // Default 24-hour ban
+         CRITICAL_BLOCK(cs_setBanned)
+             if (setBanned[addr.ip] < banTime)
+                 setBanned[addr.ip] = banTime;
+         CloseSocketDisconnect();
+         printf("Disconnected %s for misbehavior (score=%d)\n", addr.ToString().c_str(), nMisbehavior);
+         return true;
+     }
+     return false;
+ }
  
  
  
@@@ -897,6 -943,11 +944,11 @@@ void ThreadSocketHandler2(void* parg
              {
                  closesocket(hSocket);
              }
+             else if (CNode::IsBanned(addr.ip))
+             {
+                 printf("connetion from %s dropped (banned)\n", addr.ToString().c_str());
+                 closesocket(hSocket);
+             }
              else
              {
                  printf("accepted connection %s\n", addr.ToString().c_str());
@@@ -1081,11 -1132,17 +1133,17 @@@ void ThreadMapPort2(void* parg
      const char * rootdescurl = 0;
      const char * multicastif = 0;
      const char * minissdpdpath = 0;
      struct UPNPDev * devlist = 0;
      char lanaddr[64];
  
+ #ifndef UPNPDISCOVER_SUCCESS
+     /* miniupnpc 1.5 */
+     devlist = upnpDiscover(2000, multicastif, minissdpdpath, 0);
+ #else
+     /* miniupnpc 1.6 */
+     int error = 0;
      devlist = upnpDiscover(2000, multicastif, minissdpdpath, 0, 0, &error);
+ #endif
  
      struct UPNPUrls urls;
      struct IGDdatas data;
          char intClient[16];
          char intPort[6];
          string strDesc = "Bitcoin " + FormatFullVersion();
+ #ifndef UPNPDISCOVER_SUCCESS
+     /* miniupnpc 1.5 */
+         r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype,
+                               port, port, lanaddr, strDesc.c_str(), "TCP", 0);
+ #else
+     /* miniupnpc 1.6 */
          r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype,
                                port, port, lanaddr, strDesc.c_str(), "TCP", 0, "0");
+ #endif
  
          if(r!=UPNPCOMMAND_SUCCESS)
              printf("AddPortMapping(%s, %s, %s) failed with code %d (%s)\n",
@@@ -1159,11 -1223,32 +1224,31 @@@ void MapPort(bool /* unused fMapPort */
  
  
  static const char *strDNSSeed[] = {
 -    "bitseed.xf2.org",
 -    "dnsseed.bluematt.me",
 +    // "seeds.ppcoin.org"
  };
  
- void DNSAddressSeed()
+ void ThreadDNSAddressSeed(void* parg)
  {
+     IMPLEMENT_RANDOMIZE_STACK(ThreadDNSAddressSeed(parg));
+     try
+     {
+         vnThreadsRunning[6]++;
+         ThreadDNSAddressSeed2(parg);
+         vnThreadsRunning[6]--;
+     }
+     catch (std::exception& e) {
+         vnThreadsRunning[6]--;
+         PrintException(&e, "ThreadDNSAddressSeed()");
+     } catch (...) {
+         vnThreadsRunning[6]--;
+         throw; // support pthread_cancel()
+     }
+     printf("ThreadDNSAddressSeed exiting\n");
+ }
+ void ThreadDNSAddressSeed2(void* parg)
+ {
+     printf("ThreadDNSAddressSeed started\n");
      int found = 0;
  
      if (!fTestNet)
  
  
  
  unsigned int pnSeed[] =
  {
 -    0x6884ac63, 0x3ffecead, 0x2919b953, 0x0942fe50, 0x7a1d922e, 0xcdd6734a, 0x953a5bb6, 0x2c46922e,
 -    0xe2a5f143, 0xaa39103a, 0xa06afa5c, 0x135ffd59, 0xe8e82863, 0xf61ef029, 0xf75f042e, 0x2b363532,
 -    0x29b2df42, 0x16b1f64e, 0xd46e281b, 0x5280bf58, 0x60372229, 0x1be58e4f, 0xa8496f45, 0x1fb1a057,
 -    0x756b3844, 0x3bb79445, 0x0b375518, 0xcccb0102, 0xb682bf2e, 0x46431c02, 0x3a81073a, 0xa3771f1f,
 -    0x213a121f, 0x85dc2c1b, 0x56b4323b, 0xb34e8945, 0x3c40b33d, 0xfa276418, 0x1f818d29, 0xebe1e344,
 -    0xf6160a18, 0xf4fa384a, 0x34b09558, 0xb882b543, 0xe3ce2253, 0x6abf56d8, 0xe91b1155, 0x688ee6ad,
 -    0x2efc6058, 0x4792cd47, 0x0c32f757, 0x4c813a46, 0x8c93644a, 0x37507444, 0x813ad218, 0xdac06d4a,
 -    0xe4c63e4b, 0x21a1ea3c, 0x8d88556f, 0x30e9173a, 0x041f681b, 0xdc77ba50, 0xc0072753, 0xceddd44f,
 -    0x052d1743, 0xe3c77a4a, 0x13981c3a, 0x5685d918, 0x3c0e4e70, 0x3e56fb54, 0xb676ae0c, 0xac93c859,
 -    0x22279f43, 0x975a4542, 0xe527f071, 0xea162f2e, 0x3c65a32e, 0x5be5713b, 0x961ec418, 0xb202922e,
 -    0x5ef7be50, 0xce49f53e, 0x05803b47, 0x8463b055, 0x78576153, 0x3ec2ae3a, 0x4bbd7118, 0xafcee043,
 -    0x56a3e8ba, 0x6174de4d, 0x8d01ba4b, 0xc9af564e, 0xdbc9c547, 0xa627474d, 0xdada9244, 0xd3b3083a,
 -    0x523e071f, 0xd6b96f18, 0xbd527c46, 0xdf2bbb4d, 0xd37b4a4b, 0x3a6a2158, 0xc064b055, 0x18a8e055,
 -    0xec4dae3b, 0x0540416c, 0x475b4fbe, 0x064803b2, 0x48e9f062, 0x2898524b, 0xd315ff43, 0xf786d247,
 -    0xc7ea2f3e, 0xc087f043, 0xc163354b, 0x8250284d, 0xed300029, 0xbf36e05c, 0x8eb3ae4c, 0xe7aa623e,
 -    0x7ced0274, 0xdd362c1b, 0x362b995a, 0xca26b629, 0x3fc41618, 0xb97b364e, 0xa05b8729, 0x0f5e3c43,
 -    0xdf942618, 0x6aeb9b5b, 0xbf04762e, 0xfaaeb118, 0x87579958, 0x76520044, 0xc2660c5b, 0x628b201b,
 -    0xf193932e, 0x1c0ad045, 0xff908346, 0x8da9d4da, 0xed201c1f, 0xa47a2b1b, 0x330007d4, 0x8ba1ed47,
 -    0xb2f02d44, 0x7db62c1b, 0x781c454b, 0xc0300029, 0xb7062a45, 0x88b52e3a, 0x78dd6b63, 0x1cb9b718,
 -    0x5d358e47, 0x59912c3b, 0x79607544, 0x5197f759, 0xc023be48, 0xd1013743, 0x0f354057, 0x8e3aac3b,
 -    0x4114693e, 0x22316318, 0xe27dda50, 0x878eac3b, 0x4948a21f, 0x5db7f24c, 0x8ccb6157, 0x26a5de18,
 -    0x0a11bd43, 0x27bb1e41, 0x60a7a951, 0x3e16b35e, 0x07888b53, 0x5648a853, 0x0149fe50, 0xd070a34f,
 -    0x6454c96d, 0xd6e54758, 0xa96dc152, 0x65447861, 0xf6bdf95e, 0x10400202, 0x2c29d483, 0x18174732,
 -    0x1d840618, 0x12e61818, 0x089d3f3c, 0x917e931f, 0xd1b0c90e, 0x25bd3c42, 0xeb05775b, 0x7d550c59,
 -    0x6cfacb01, 0xe4224444, 0xa41dd943, 0x0f5aa643, 0x5e33731b, 0x81036d50, 0x6f46a0d1, 0x7731be43,
 -    0x14840e18, 0xf1e8d059, 0x661d2b1f, 0x40a3201b, 0x9407b843, 0xedf0254d, 0x7bd1a5bc, 0x073dbe51,
 -    0xe864a97b, 0x2efd947b, 0xb9ca0e45, 0x4e2113ad, 0xcc305731, 0xd39ca63c, 0x733df918, 0xda172b1f,
 -    0xaa03b34d, 0x7230fd4d, 0xf1ce6e3a, 0x2e9fab43, 0xa4010750, 0xa928bd18, 0x6809be42, 0xb19de348,
 -    0xff956270, 0x0d795f51, 0xd2dec247, 0x6df5774b, 0xbac11f79, 0xdfb05c75, 0x887683d8, 0xa1e83632,
 -    0x2c0f7671, 0x28bcb65d, 0xac2a7545, 0x3eebfc60, 0x304ad7c4, 0xa215a462, 0xc86f0f58, 0xcfb92ebe,
 -    0x5e23ed82, 0xf506184b, 0xec0f19b7, 0x060c59ad, 0x86ee3174, 0x85380774, 0xa199a562, 0x02b507ae,
 -    0x33eb2163, 0xf2112b1f, 0xb702ba50, 0x131b9618, 0x90ccd04a, 0x08f3273b, 0xecb61718, 0x64b8b44d,
 -    0x182bf4dc, 0xc7b68286, 0x6e318d5f, 0xfdb03654, 0xb3272e54, 0xe014ad4b, 0x274e4a31, 0x7806375c,
 -    0xbc34a748, 0x1b5ad94a, 0x6b54d10e, 0x73e2ae6e, 0x5529d483, 0x8455a76d, 0x99c13f47, 0x1d811741,
 -    0xa9782a78, 0x0b00464d, 0x7266ea50, 0x532dab46, 0x33e1413e, 0x780d0c18, 0x0fb0854e, 0x03370155,
 -    0x2693042e, 0xfa3d824a, 0x2bb1681b, 0x37ea2a18, 0x7fb8414b, 0x32e0713b, 0xacf38d3f, 0xa282716f,
 -    0xb1a09d7b, 0xa04b764b, 0x83c94d18, 0x05ee4c6d, 0x0e795f51, 0x46984352, 0xf80fc247, 0x3fccb946,
 -    0xd7ae244b, 0x0a8e0a4c, 0x57b141bc, 0x3647bed1, 0x1431b052, 0x803a8bbb, 0xfc69056b, 0xf5991862,
 -    0x14963b2e, 0xd35d5dda, 0xc6c73574, 0xc8f1405b, 0x0ca4224d, 0xecd36071, 0xa9461754, 0xe7a0ed72,
 -    0x559e8346, 0x1c9beec1, 0xc786ea4a, 0x9561b44d, 0x9788074d, 0x1a69934f, 0x23c5614c, 0x07c79d4b,
 -    0xc7ee52db, 0xc72df351, 0xcb135e44, 0xa0988346, 0xc211fc4c, 0x87dec34b, 0x1381074d, 0x04a65cb7,
 -    0x4409083a, 0x4a407a4c, 0x92b8d37d, 0xacf50b4d, 0xa58aa5bc, 0x448f801f, 0x9c83762e, 0x6fd5734a,
 -    0xfe2d454b, 0x84144c55, 0x05190e4c, 0xb2151448, 0x63867a3e, 0x16099018, 0x9c010d3c, 0x962d8f3d,
 -    0xd51ee453, 0x9d86801f, 0x68e87b47, 0x6bf7bb73, 0x5fc7910e, 0x10d90118, 0x3db04442, 0x729d3e4b,
 -    0xc397d842, 0x57bb15ad, 0x72f31f4e, 0xc9380043, 0x2bb24e18, 0xd9b8ab50, 0xb786801f, 0xf4dc4847,
 -    0x85f4bb51, 0x4435995b, 0x5ba07e40, 0x2c57392e, 0x3628124b, 0x9839b64b, 0x6fe8b24d, 0xaddce847,
 -    0x75260e45, 0x0c572a43, 0xfea21902, 0xb9f9742e, 0x5a70d443, 0x8fc5910e, 0x868d4744, 0x56245e02,
 -    0xd7eb5f02, 0x35c12c1b, 0x4373034b, 0x8786554c, 0xa6facf18, 0x4b11a31f, 0x3570664e, 0x5a64bc42,
 -    0x0b03983f, 0x8f457e4c, 0x0fd874c3, 0xb6cf31b2, 0x2bbc2d4e, 0x146ca5b2, 0x9d00b150, 0x048a4153,
 -    0xca4dcd43, 0xc1607cca, 0x8234cf57, 0x9c7daead, 0x3dc07658, 0xea5c6e4c, 0xf1a0084e, 0x16d2ee53,
 -    0x1b849418, 0xfe913a47, 0x1e988f62, 0x208b644c, 0xc55ee980, 0xbdbce747, 0xf59a384e, 0x0f56091b,
 -    0x7417b745, 0x0c37344e, 0x2c62ab47, 0xf8533a4d, 0x8030084d, 0x76b93c4b, 0xda6ea0ad, 0x3c54f618,
 -    0x63b0de1f, 0x7370d858, 0x1a70bb4c, 0xdda63b2e, 0x60b2ba50, 0x1ba7d048, 0xbe1b2c1b, 0xabea5747,
 -    0x29ad2e4d, 0xe8cd7642, 0x66c80e18, 0x138bf34a, 0xc6145e44, 0x2586794c, 0x07bc5478, 0x0da0b14d,
 -    0x8f95354e, 0x9eb11c62, 0xa1545e46, 0x2e7a2602, 0x408c9c3d, 0x59065d55, 0xf51d1a4c, 0x3bbc6a4e,
 -    0xc71b2a2e, 0xcdaaa545, 0x17d659d0, 0x5202e7ad, 0xf1b68445, 0x93375961, 0xbd88a043, 0x066ad655,
 -    0x890f6318, 0x7b7dca47, 0x99bdd662, 0x3bb4fc53, 0x1231efdc, 0xc0a99444, 0x96bbea47, 0x61ed8748,
 -    0x27dfa73b, 0x8d4d1754, 0x3460042e, 0x551f0c4c, 0x8d0e0718, 0x162ddc53, 0x53231718, 0x1ecd65d0,
 -    0x944d28bc, 0x3b79d058, 0xaff97fbc, 0x4860006c, 0xc101c90e, 0xace41743, 0xa5975d4c, 0x5cc2703e,
 -    0xb55a4450, 0x02d18840, 0xee2765ae, 0xd6012fd5, 0x24c94d7d, 0x8c6eec47, 0x7520ba5d, 0x9e15e460,
 -    0x8510b04c, 0x75ec3847, 0x1dfa6661, 0xe172b3ad, 0x5744c90e, 0x52a0a152, 0x8d6fad18, 0x67b74b6d,
 -    0x93a089b2, 0x0f3ac5d5, 0xe5de1855, 0x43d25747, 0x4bad804a, 0x55b408d8, 0x60a36441, 0xf553e860,
 -    0xdb2fa2c8, 0x03152b32, 0xdd27a7d5, 0x3116a8b8, 0x0a1d708c, 0xeee2f13c, 0x6acf436f, 0xce6eb4ca,
 -    0x101cd3d9, 0x1c48a6b8, 0xe57d6f44, 0x93dcf562,
 +    0xfc01a8c0
  };
  
  
@@@ -1323,6 -1480,8 +1417,8 @@@ void ThreadOpenConnections2(void* parg
              BOOST_FOREACH(CNode* pnode, vNodes)
                  setConnected.insert(pnode->addr.ip & 0x0000ffff);
  
+         int64 nANow = GetAdjustedTime();
          CRITICAL_BLOCK(cs_mapAddresses)
          {
              BOOST_FOREACH(const PAIRTYPE(vector<unsigned char>, CAddress)& item, mapAddresses)
                  const CAddress& addr = item.second;
                  if (!addr.IsIPv4() || !addr.IsValid() || setConnected.count(addr.ip & 0x0000ffff))
                      continue;
-                 int64 nSinceLastSeen = GetAdjustedTime() - addr.nTime;
-                 int64 nSinceLastTry = GetAdjustedTime() - addr.nLastTry;
+                 int64 nSinceLastSeen = nANow - addr.nTime;
+                 int64 nSinceLastTry = nANow - addr.nLastTry;
  
                  // Randomize the order in a deterministic way, putting the standard port first
                  int64 nRandomizer = (uint64)(nStart * 4951 + addr.nLastTry * 9567851 + addr.ip * 7789) % (2 * 60 * 60);
@@@ -1390,7 -1549,8 +1486,8 @@@ bool OpenNetworkConnection(const CAddre
      //
      if (fShutdown)
          return false;
-     if (addrConnect.ip == addrLocalHost.ip || !addrConnect.IsIPv4() || FindNode(addrConnect.ip))
+     if (addrConnect.ip == addrLocalHost.ip || !addrConnect.IsIPv4() ||
+         FindNode(addrConnect.ip) || CNode::IsBanned(addrConnect.ip))
          return false;
  
      vnThreadsRunning[1]--;
@@@ -1494,7 -1654,7 +1591,7 @@@ bool BindListenPort(string& strError
      int nOne = 1;
      addrLocalHost.port = htons(GetListenPort());
  
- #ifdef __WXMSW__
+ #ifdef WIN32
      // Initialize Windows Sockets
      WSADATA wsadata;
      int ret = WSAStartup(MAKEWORD(2,2), &wsadata);
      setsockopt(hListenSocket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&nOne, sizeof(int));
  #endif
  
- #ifndef __WXMSW__
+ #ifndef WIN32
      // Allow binding if the port is still in TIME_WAIT state after
      // the program was closed and restarted.  Not an issue on windows.
      setsockopt(hListenSocket, SOL_SOCKET, SO_REUSEADDR, (void*)&nOne, sizeof(int));
  #endif
  
- #ifdef __WXMSW__
+ #ifdef WIN32
      // Set to nonblocking, incoming connections will also inherit this
      if (ioctlsocket(hListenSocket, FIONBIO, (u_long*)&nOne) == SOCKET_ERROR)
  #else
@@@ -1573,7 -1733,7 +1670,7 @@@ void StartNode(void* parg
      if (pnodeLocalHost == NULL)
          pnodeLocalHost = new CNode(INVALID_SOCKET, CAddress("127.0.0.1", 0, false, nLocalServices));
  
- #ifdef __WXMSW__
+ #ifdef WIN32
      // Get local host ip
      char pszHostName[1000] = "";
      if (gethostname(pszHostName, sizeof(pszHostName)) != SOCKET_ERROR)
      // Start threads
      //
  
+     if (GetBoolArg("-nodnsseed"))
+         printf("DNS seeding disabled\n");
+     else
+         if (!CreateThread(ThreadDNSAddressSeed, NULL))
+             printf("Error: CreateThread(ThreadDNSAddressSeed) failed\n");
      // Map ports with UPnP
      if (fHaveUPnP)
          MapPort(fUseUPnP);
          printf("Error: CreateThread(ThreadIRCSeed) failed\n");
  
      // Send and receive from sockets, accept connections
-     CreateThread(ThreadSocketHandler, NULL);
+     if (!CreateThread(ThreadSocketHandler, NULL))
+         printf("Error: CreateThread(ThreadSocketHandler) failed\n");
  
      // Initiate outbound connections
      if (!CreateThread(ThreadOpenConnections, NULL))
@@@ -1685,6 -1852,7 +1789,7 @@@ bool StopNode(
      if (vnThreadsRunning[3] > 0) printf("ThreadBitcoinMiner still running\n");
      if (vnThreadsRunning[4] > 0) printf("ThreadRPCServer still running\n");
      if (fHaveUPnP && vnThreadsRunning[5] > 0) printf("ThreadMapPort still running\n");
+     if (vnThreadsRunning[6] > 0) printf("ThreadDNSAddressSeed still running\n");
      while (vnThreadsRunning[2] > 0 || vnThreadsRunning[4] > 0)
          Sleep(20);
      Sleep(50);
@@@ -1708,7 -1876,7 +1813,7 @@@ public
              if (closesocket(hListenSocket) == SOCKET_ERROR)
                  printf("closesocket(hListenSocket) failed with error %d\n", WSAGetLastError());
  
- #ifdef __WXMSW__
+ #ifdef WIN32
          // Shutdown Windows Sockets
          WSACleanup();
  #endif
diff --combined src/util.cpp
@@@ -1,6 -1,5 +1,6 @@@
  // Copyright (c) 2009-2010 Satoshi Nakamoto
  // Copyright (c) 2011 The Bitcoin developers
 +// Copyright (c) 2011 The PPCoin developers
  // Distributed under the MIT/X11 software license, see the accompanying
  // file license.txt or http://www.opensource.org/licenses/mit-license.php.
  #include "headers.h"
@@@ -65,7 -64,7 +65,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
@@@ -109,7 -108,7 +109,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];
@@@ -199,7 -198,7 +199,7 @@@ inline int OutputDebugStringF(const cha
          }
      }
  
- #ifdef __WXMSW__
+ #ifdef WIN32
      if (fPrintToDebugger)
      {
          static CCriticalSection cs_OutputDebugStringF;
@@@ -265,8 -264,7 +265,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)
      {
@@@ -339,7 -336,7 +337,7 @@@ string FormatMoney(int64 n, bool fPlus
      int64 n_abs = (n > 0 ? n : -n);
      int64 quotient = n_abs/COIN;
      int64 remainder = n_abs%COIN;
 -    string str = strprintf("%"PRI64d".%08"PRI64d, quotient, remainder);
 +    string str = strprintf("%"PRI64d".%04"PRI64d, quotient, remainder);
  
      // Right-trim excess 0's before the decimal point:
      int nTrim = 0;
@@@ -390,7 -387,7 +388,7 @@@ bool ParseMoney(const char* pszIn, int6
      for (; *p; p++)
          if (!isspace(*p))
              return false;
-     if (strWhole.size() > 14)
+     if (strWhole.size() > 10) // guard against 63 bit overflow
          return false;
      if (nUnits < 0 || nUnits > COIN)
          return false;
@@@ -446,7 -443,6 +444,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] = '-';
      }
  }
  
+ 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());
  }
  
  
@@@ -547,7 -648,7 +649,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));
@@@ -576,10 -677,6 +678,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;
  }
  
@@@ -601,10 -698,6 +699,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)
  
  string GetDefaultDataDir()
  {
 -    // Windows: C:\Documents and Settings\username\Application Data\Bitcoin
 -    // Mac: ~/Library/Application Support/Bitcoin
 -    // Unix: ~/.bitcoin
 +    // Windows: C:\Documents and Settings\username\Application Data\PPCoin
 +    // Mac: ~/Library/Application Support/PPCoin
 +    // Unix: ~/.ppcoin
- #ifdef __WXMSW__
+ #ifdef WIN32
      // Windows
 -    return MyGetSpecialFolderPath(CSIDL_APPDATA, true) + "\\Bitcoin";
 +    return MyGetSpecialFolderPath(CSIDL_APPDATA, true) + "\\PPCoin";
  #else
      char* pszHome = getenv("HOME");
      if (pszHome == NULL || strlen(pszHome) == 0)
      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());
 -    return strHome + "Bitcoin";
 +    return strHome + "PPCoin";
  #else
      // Unix
 -    return strHome + ".bitcoin";
 +    return strHome + ".ppcoin";
  #endif
  #endif
  }
@@@ -722,7 -815,7 +816,7 @@@ string GetDataDir(
  string GetConfigFile()
  {
      namespace fs = boost::filesystem;
 -    fs::path pathConfig(GetArg("-conf", "bitcoin.conf"));
 +    fs::path pathConfig(GetArg("-conf", "ppcoin.conf"));
      if (!pathConfig.is_complete())
          pathConfig = fs::path(GetDataDir()) / pathConfig;
      return pathConfig.string();
@@@ -754,7 -847,7 +848,7 @@@ void ReadConfigFile(map<string, string>
  string GetPidFile()
  {
      namespace fs = boost::filesystem;
 -    fs::path pathConfig(GetArg("-pid", "bitcoind.pid"));
 +    fs::path pathConfig(GetArg("-pid", "ppcoind.pid"));
      if (!pathConfig.is_complete())
          pathConfig = fs::path(GetDataDir()) / pathConfig;
      return pathConfig.string();
@@@ -816,11 -909,20 +910,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
@@@ -1,12 -1,10 +1,11 @@@
 -// Copyright (c) 2009-2010 Satoshi Nakamoto
 +// Copyright (c) 2009-2011 Satoshi Nakamoto
  // Copyright (c) 2011 The Bitcoin developers
 +// Copyright (c) 2011 The PPCoin developers
  // Distributed under the MIT/X11 software license, see the accompanying
  // file license.txt or http://www.opensource.org/licenses/mit-license.php.
  
  #include "headers.h"
  #include "db.h"
- #include "cryptopp/sha.h"
  #include "crypter.h"
  
  using namespace std;
@@@ -41,9 -39,10 +40,10 @@@ bool CWallet::AddCryptedKey(const vecto
          else
              return CWalletDB(strWalletFile).WriteCryptedKey(vchPubKey, vchCryptedSecret);
      }
+     return false;
  }
  
- bool CWallet::Unlock(const string& strWalletPassphrase)
+ bool CWallet::Unlock(const SecureString& strWalletPassphrase)
  {
      if (!IsLocked())
          return false;
@@@ -64,7 -63,7 +64,7 @@@
      return false;
  }
  
- bool CWallet::ChangeWalletPassphrase(const string& strOldWalletPassphrase, const string& strNewWalletPassphrase)
+ bool CWallet::ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, const SecureString& strNewWalletPassphrase)
  {
      bool fWasLocked = IsLocked();
  
@@@ -123,7 -122,7 +123,7 @@@ public
      )
  };
  
- bool CWallet::EncryptWallet(const string& strWalletPassphrase)
+ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
  {
      if (IsCrypted())
          return false;
          }
  
          Lock();
+         Unlock(strWalletPassphrase);
+         NewKeyPool();
+         Lock();
+         // Need to completely rewrite the wallet file; if we don't, bdb might keep
+         // bits of the unencrypted private key in slack space in the database file.
+         CDB::Rewrite(strWalletFile);
      }
  
      return true;
@@@ -261,7 -267,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();
@@@ -552,6 -561,9 +562,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;
@@@ -729,6 -741,21 +742,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
  {
@@@ -983,8 -1010,9 +1011,8 @@@ bool CWallet::CreateTransaction(const v
                  dPriority /= nBytes;
  
                  // Check that enough fee is included
 -                int64 nPayFee = nTransactionFee * (1 + (int64)nBytes / 1000);
 -                bool fAllowFree = CTransaction::AllowFree(dPriority);
 -                int64 nMinFee = wtxNew.GetMinFee(1, fAllowFree);
 +                int64 nPayFee = nTransactionFee;   // ppcoin: simplify tx fee
 +                int64 nMinFee = wtxNew.GetMinFee(1, false);
                  if (nFeeRet < max(nPayFee, nMinFee))
                  {
                      nFeeRet = max(nPayFee, nMinFee);
@@@ -1121,6 -1149,18 +1149,18 @@@ int CWallet::LoadWallet(bool& fFirstRun
          return false;
      fFirstRunRet = false;
      int nLoadWalletRet = CWalletDB(strWalletFile,"cr+").LoadWallet(this);
+     if (nLoadWalletRet == DB_NEED_REWRITE)
+     {
+         if (CDB::Rewrite(strWalletFile, "\x04pool"))
+         {
+             setKeyPool.clear();
+             // Note: can't top-up keypool here, because wallet is locked.
+             // User will be prompted to unlock wallet the next operation
+             // the requires a new key.
+         }
+         nLoadWalletRet = DB_NEED_REWRITE;
+     }
      if (nLoadWalletRet != DB_LOAD_OK)
          return nLoadWalletRet;
      fFirstRunRet = vchDefaultKey.empty();
@@@ -1206,6 -1246,34 +1246,34 @@@ bool GetWalletFile(CWallet* pwallet, st
      return true;
  }
  
+ //
+ // Mark old keypool keys as used,
+ // and generate all new keys
+ //
+ bool CWallet::NewKeyPool()
+ {
+     CRITICAL_BLOCK(cs_wallet)
+     {
+         CWalletDB walletdb(strWalletFile);
+         BOOST_FOREACH(int64 nIndex, setKeyPool)
+             walletdb.ErasePool(nIndex);
+         setKeyPool.clear();
+         if (IsLocked())
+             return false;
+         int64 nKeys = max(GetArg("-keypool", 100), (int64)0);
+         for (int i = 0; i < nKeys; i++)
+         {
+             int64 nIndex = i+1;
+             walletdb.WritePool(nIndex, CKeyPool(GenerateNewKey()));
+             setKeyPool.insert(nIndex);
+         }
+         printf("CWallet::NewKeyPool wrote %"PRI64d" new keys\n", nKeys);
+     }
+     return true;
+ }
  bool CWallet::TopUpKeyPool()
  {
      CRITICAL_BLOCK(cs_wallet)