Merge branch '0.4.x' into 0.5.0.x
authorLuke Dashjr <luke-jr+git@utopios.org>
Sun, 12 Feb 2012 02:26:11 +0000 (21:26 -0500)
committerLuke Dashjr <luke-jr+git@utopios.org>
Sun, 12 Feb 2012 02:26:11 +0000 (21:26 -0500)
1  2 
src/bitcoinrpc.cpp
src/net.cpp
src/net.h

diff --combined src/bitcoinrpc.cpp
@@@ -4,6 -4,7 +4,6 @@@
  // file license.txt or http://www.opensource.org/licenses/mit-license.php.
  
  #include "headers.h"
 -#include "cryptopp/sha.h"
  #include "db.h"
  #include "net.h"
  #include "init.h"
@@@ -49,13 -50,13 +49,13 @@@ Object JSONRPCError(int code, const str
  }
  
  
 -void PrintConsole(const char* format, ...)
 +void PrintConsole(const std::string &format, ...)
  {
      char buffer[50000];
      int limit = sizeof(buffer);
      va_list arg_ptr;
      va_start(arg_ptr, format);
 -    int ret = _vsnprintf(buffer, limit, format, arg_ptr);
 +    int ret = _vsnprintf(buffer, limit, format.c_str(), arg_ptr);
      va_end(arg_ptr);
      if (ret < 0 || ret >= limit)
      {
          buffer[limit-1] = 0;
      }
      printf("%s", buffer);
 -#if defined(__WXMSW__) && defined(GUI)
 -    MyMessageBox(buffer, "Bitcoin", wxOK | wxICON_EXCLAMATION);
 -#else
      fprintf(stdout, "%s", buffer);
 -#endif
  }
  
  
@@@ -160,13 -165,10 +160,13 @@@ Value stop(const Array& params, bool fH
          throw runtime_error(
              "stop\n"
              "Stop bitcoin server.");
 -
 +#ifndef QT_GUI
      // Shutdown will take long enough that the response should get back
      CreateThread(Shutdown, NULL);
      return "bitcoin server stopping";
 +#else
 +    throw runtime_error("NYI: cannot shut down GUI with RPC command");
 +#endif
  }
  
  
@@@ -528,72 -530,6 +528,72 @@@ Value sendtoaddress(const Array& params
      return wtx.GetHash().GetHex();
  }
  
 +static const string strMessageMagic = "Bitcoin Signed Message:\n";
 +
 +Value signmessage(const Array& params, bool fHelp)
 +{
 +    if (fHelp || params.size() != 2)
 +        throw runtime_error(
 +            "signmessage <bitcoinaddress> <message>\n"
 +            "Sign a message with the private key of an address");
 +
 +    if (pwalletMain->IsLocked())
 +        throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
 +
 +    string strAddress = params[0].get_str();
 +    string strMessage = params[1].get_str();
 +
 +    CBitcoinAddress addr(strAddress);
 +    if (!addr.IsValid())
 +        throw JSONRPCError(-3, "Invalid address");
 +
 +    CKey key;
 +    if (!pwalletMain->GetKey(addr, key))
 +        throw JSONRPCError(-4, "Private key not available");
 +
 +    CDataStream ss(SER_GETHASH);
 +    ss << strMessageMagic;
 +    ss << strMessage;
 +
 +    vector<unsigned char> vchSig;
 +    if (!key.SignCompact(Hash(ss.begin(), ss.end()), vchSig))
 +        throw JSONRPCError(-5, "Sign failed");
 +
 +    return EncodeBase64(&vchSig[0], vchSig.size());
 +}
 +
 +Value verifymessage(const Array& params, bool fHelp)
 +{
 +    if (fHelp || params.size() != 3)
 +        throw runtime_error(
 +            "verifymessage <bitcoinaddress> <signature> <message>\n"
 +            "Verify a signed message");
 +
 +    string strAddress  = params[0].get_str();
 +    string strSign     = params[1].get_str();
 +    string strMessage  = params[2].get_str();
 +
 +    CBitcoinAddress addr(strAddress);
 +    if (!addr.IsValid())
 +        throw JSONRPCError(-3, "Invalid address");
 +
 +    bool fInvalid = false;
 +    vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
 +
 +    if (fInvalid)
 +        throw JSONRPCError(-5, "Malformed base64 encoding");
 +
 +    CDataStream ss(SER_GETHASH);
 +    ss << strMessageMagic;
 +    ss << strMessage;
 +
 +    CKey key;
 +    if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig))
 +        return false;
 +
 +    return (key.GetAddress() == addr);
 +}
 +
  
  Value getreceivedbyaddress(const Array& params, bool fHelp)
  {
@@@ -1005,6 -941,7 +1005,6 @@@ Value ListReceived(const Array& params
              Object obj;
              obj.push_back(Pair("address",       address.ToString()));
              obj.push_back(Pair("account",       strAccount));
 -            obj.push_back(Pair("label",         strAccount)); // deprecated
              obj.push_back(Pair("amount",        ValueFromAmount(nAmount)));
              obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
              ret.push_back(obj);
              int nConf = (*it).second.nConf;
              Object obj;
              obj.push_back(Pair("account",       (*it).first));
 -            obj.push_back(Pair("label",         (*it).first)); // deprecated
              obj.push_back(Pair("amount",        ValueFromAmount(nAmount)));
              obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
              ret.push_back(obj);
@@@ -1260,70 -1198,6 +1260,70 @@@ Value listaccounts(const Array& params
      return ret;
  }
  
 +Value listsinceblock(const Array& params, bool fHelp)
 +{
 +    if (fHelp)
 +        throw runtime_error(
 +            "listsinceblock [blockid] [target-confirmations]\n"
 +            "Get all transactions in blocks since block [blockid], or all transactions if omitted");
 +
 +    CBlockIndex *pindex = NULL;
 +    int target_confirms = 1;
 +
 +    if (params.size() > 0)
 +    {
 +        uint256 blockId = 0;
 +
 +        blockId.SetHex(params[0].get_str());
 +        pindex = CBlockLocator(blockId).GetBlockIndex();
 +    }
 +
 +    if (params.size() > 1)
 +    {
 +        target_confirms = params[1].get_int();
 +
 +        if (target_confirms < 1)
 +            throw JSONRPCError(-8, "Invalid parameter");
 +    }
 +
 +    int depth = pindex ? (1 + nBestHeight - pindex->nHeight) : -1;
 +
 +    Array transactions;
 +
 +    for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
 +    {
 +        CWalletTx tx = (*it).second;
 +
 +        if (depth == -1 || tx.GetDepthInMainChain() < depth)
 +            ListTransactions(tx, "*", 0, true, transactions);
 +    }
 +
 +    uint256 lastblock;
 +
 +    if (target_confirms == 1)
 +    {
 +        printf("oops!\n");
 +        lastblock = hashBestChain;
 +    }
 +    else
 +    {
 +        int target_height = pindexBest->nHeight + 1 - target_confirms;
 +
 +        CBlockIndex *block;
 +        for (block = pindexBest;
 +             block && block->nHeight > target_height;
 +             block = block->pprev)  { }
 +
 +        lastblock = block ? block->GetBlockHash() : 0;
 +    }
 +
 +    Object ret;
 +    ret.push_back(Pair("transactions", transactions));
 +    ret.push_back(Pair("lastblock", lastblock.GetHex()));
 +
 +    return ret;
 +}
 +
  Value gettransaction(const Array& params, bool fHelp)
  {
      if (fHelp || params.size() != 1)
@@@ -1427,7 -1301,7 +1427,7 @@@ void ThreadCleanWalletPassphrase(void* 
              if (nWalletUnlockTime < nMyWakeTime)
                  nWalletUnlockTime = nMyWakeTime;
          }
-         free(parg);
+         delete (int*)parg;
          return;
      }
  
@@@ -1451,16 -1325,21 +1451,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(
@@@ -1486,15 -1365,15 +1486,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;
  }
@@@ -1542,16 -1431,15 +1542,16 @@@ Value encryptwallet(const Array& params
      if (pwalletMain->IsCrypted())
          throw JSONRPCError(-15, "Error: running with an encrypted wallet, but encryptwallet was called.");
  
 -#ifdef GUI
 +#ifdef QT_GUI
      // shutting down via RPC while the GUI is running does not work (yet):
      throw runtime_error("Not Yet Implemented: use GUI to encrypt wallet, not RPC command");
  #endif
  
 -    string strWalletPass;
 +    // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
 +    // Alternately, find a way to make params[0] mlock()'d to begin with.
 +    SecureString strWalletPass;
      strWalletPass.reserve(100);
 -    mlock(&strWalletPass[0], strWalletPass.capacity());
 -    strWalletPass = params[0].get_str();
 +    strWalletPass = params[0].get_str().c_str();
  
      if (strWalletPass.length() < 1)
          throw runtime_error(
              "Encrypts the wallet with <passphrase>.");
  
      if (!pwalletMain->EncryptWallet(strWalletPass))
 -    {
 -        fill(strWalletPass.begin(), strWalletPass.end(), '\0');
 -        munlock(&strWalletPass[0], strWalletPass.capacity());
          throw JSONRPCError(-16, "Error: Failed to encrypt the wallet.");
 -    }
 -    fill(strWalletPass.begin(), strWalletPass.end(), '\0');
 -    munlock(&strWalletPass[0], strWalletPass.capacity());
  
      // BDB seems to have a bad habit of writing old data into
      // slack space in .dat files; that is bad if the old data is
@@@ -1601,9 -1495,9 +1601,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);
 +    }
 +}
 +
 +
  
  
  
@@@ -1815,13 -1622,20 +1815,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]));
  
@@@ -1859,15 -1669,17 +1859,15 @@@ string pAllowInSafeMode[] 
      "getinfo",
      "getnewaddress",
      "getaccountaddress",
 -    "setlabel", // deprecated
      "getaccount",
 -    "getlabel", // deprecated
      "getaddressesbyaccount",
 -    "getaddressesbylabel", // deprecated
      "backupwallet",
      "keypoolrefill",
      "walletpassphrase",
      "walletlock",
      "validateaddress",
      "getwork",
 +    "getmemorypool",
  };
  set<string> setAllowInSafeMode(pAllowInSafeMode, pAllowInSafeMode + sizeof(pAllowInSafeMode)/sizeof(pAllowInSafeMode[0]));
  
@@@ -1889,7 -1701,6 +1889,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";
@@@ -1930,13 -1741,12 +1930,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(),
@@@ -2014,6 -1824,43 +2014,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"];
@@@ -2169,7 -2016,7 +2169,7 @@@ void ThreadRPCServer2(void* parg
          else if (mapArgs.count("-daemon"))
              strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
          PrintConsole(
 -            _("Warning: %s, you must set a rpcpassword in the configuration file:\n %s\n"
 +            _("Error: %s, you must set a rpcpassword in the configuration file:\n %s\n"
                "It is recommended you use the following random password:\n"
                "rpcuser=bitcoinrpc\n"
                "rpcpassword=%s\n"
                  strWhatAmI.c_str(),
                  GetConfigFile().c_str(),
                  EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32).c_str());
 +#ifndef QT_GUI
          CreateThread(Shutdown, NULL);
 +#endif
          return;
      }
  
              if (valMethod.type() != str_type)
                  throw JSONRPCError(-32600, "Method must be a string");
              string strMethod = valMethod.get_str();
 -            if (strMethod != "getwork")
 +            if (strMethod != "getwork" && strMethod != "getmemorypool")
                  printf("ThreadRPCServer method=%s\n", strMethod.c_str());
  
              // Parse params
@@@ -2462,12 -2307,18 +2462,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/net.cpp
@@@ -10,7 -10,7 +10,7 @@@
  #include "init.h"
  #include "strlcpy.h"
  
 -#ifdef __WXMSW__
 +#ifdef WIN32
  #include <string.h>
  #endif
  
@@@ -103,7 -103,7 +103,7 @@@ bool ConnectSocket(const CAddress& addr
      bool fProxy = (fUseProxy && addrConnect.IsRoutable());
      struct sockaddr_in sockaddr = (fProxy ? addrProxy.GetSockAddr() : addrConnect.GetSockAddr());
  
 -#ifdef __WXMSW__
 +#ifdef WIN32
      u_long fNonblock = 1;
      if (ioctlsocket(hSocket, FIONBIO, &fNonblock) == SOCKET_ERROR)
  #else
                  return false;
              }
              socklen_t nRetSize = sizeof(nRet);
 -#ifdef __WXMSW__
 +#ifdef WIN32
              if (getsockopt(hSocket, SOL_SOCKET, SO_ERROR, (char*)(&nRet), &nRetSize) == SOCKET_ERROR)
  #else
              if (getsockopt(hSocket, SOL_SOCKET, SO_ERROR, &nRet, &nRetSize) == SOCKET_ERROR)
                  return false;
              }
          }
 -#ifdef __WXMSW__
 +#ifdef WIN32
          else if (WSAGetLastError() != WSAEISCONN)
  #else
          else
      CNode::ConnectNode immediately turns the socket back to non-blocking
      but we'll turn it back to blocking just in case
      */
 -#ifdef __WXMSW__
 +#ifdef WIN32
      fNonblock = 0;
      if (ioctlsocket(hSocket, FIONBIO, &fNonblock) == SOCKET_ERROR)
  #else
@@@ -679,7 -679,7 +679,7 @@@ CNode* ConnectNode(CAddress addrConnect
          printf("connected %s\n", addrConnect.ToString().c_str());
  
          // Set to nonblocking
 -#ifdef __WXMSW__
 +#ifdef WIN32
          u_long nOne = 1;
          if (ioctlsocket(hSocket, FIONBIO, &nOne) == SOCKET_ERROR)
              printf("ConnectSocket() : ioctlsocket nonblocking setting failed, error %d\n", WSAGetLastError());
@@@ -731,52 -731,6 +731,52 @@@ void CNode::Cleanup(
  }
  
  
 +std::map<unsigned int, int64> CNode::setBanned;
 +CCriticalSection CNode::cs_setBanned;
 +
 +void CNode::ClearBanned()
 +{
 +    setBanned.clear();
 +}
 +
 +bool CNode::IsBanned(unsigned int ip)
 +{
 +    bool fResult = false;
 +    CRITICAL_BLOCK(cs_setBanned)
 +    {
 +        std::map<unsigned int, int64>::iterator i = setBanned.find(ip);
 +        if (i != setBanned.end())
 +        {
 +            int64 t = (*i).second;
 +            if (GetTime() < t)
 +                fResult = true;
 +        }
 +    }
 +    return fResult;
 +}
 +
 +bool CNode::Misbehaving(int howmuch)
 +{
 +    if (addr.IsLocal())
 +    {
 +        printf("Warning: local node %s misbehaving\n", addr.ToString().c_str());
 +        return false;
 +    }
 +
 +    nMisbehavior += howmuch;
 +    if (nMisbehavior >= GetArg("-banscore", 100))
 +    {
 +        int64 banTime = GetTime()+GetArg("-bantime", 60*60*24);  // Default 24-hour ban
 +        CRITICAL_BLOCK(cs_setBanned)
 +            if (setBanned[addr.ip] < banTime)
 +                setBanned[addr.ip] = banTime;
 +        CloseSocketDisconnect();
 +        printf("Disconnected %s for misbehavior (score=%d)\n", addr.ToString().c_str(), nMisbehavior);
 +        return true;
 +    }
 +    return false;
 +}
 +
  
  
  
@@@ -947,11 -901,6 +947,11 @@@ void ThreadSocketHandler2(void* parg
              {
                  closesocket(hSocket);
              }
 +            else if (CNode::IsBanned(addr.ip))
 +            {
 +                printf("connetion from %s dropped (banned)\n", addr.ToString().c_str());
 +                closesocket(hSocket);
 +            }
              else
              {
                  printf("accepted connection %s\n", addr.ToString().c_str());
@@@ -1154,6 -1103,26 +1154,26 @@@ void ThreadMapPort2(void* parg
      r = UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr));
      if (r == 1)
      {
+         if (!addrLocalHost.IsRoutable())
+         {
+             char externalIPAddress[40];
+             r = UPNP_GetExternalIPAddress(urls.controlURL, data.first.servicetype, externalIPAddress);
+             if(r != UPNPCOMMAND_SUCCESS)
+                 printf("UPnP: GetExternalIPAddress() returned %d\n", r);
+             else
+             {
+                 if(externalIPAddress[0])
+                 {
+                     printf("UPnP: ExternalIPAddress = %s\n", externalIPAddress);
+                     CAddress addrExternalFromUPnP(externalIPAddress, 0, false, nLocalServices);
+                     if (addrExternalFromUPnP.IsRoutable())
+                         addrLocalHost = addrExternalFromUPnP;
+                 }
+                 else
+                     printf("UPnP: GetExternalIPAddress failed.\n");
+             }
+         }
          string strDesc = "Bitcoin " + FormatFullVersion();
  #ifndef UPNPDISCOVER_SUCCESS
          /* miniupnpc 1.5 */
@@@ -1519,8 -1488,6 +1539,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);
@@@ -1588,8 -1555,7 +1608,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]--;
@@@ -1693,7 -1659,7 +1713,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
@@@ -1772,7 -1738,7 +1792,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)
@@@ -1915,7 -1881,7 +1935,7 @@@ public
              if (closesocket(hListenSocket) == SOCKET_ERROR)
                  printf("closesocket(hListenSocket) failed with error %d\n", WSAGetLastError());
  
 -#ifdef __WXMSW__
 +#ifdef WIN32
          // Shutdown Windows Sockets
          WSACleanup();
  #endif
diff --combined src/net.h
+++ b/src/net.h
@@@ -10,7 -10,7 +10,7 @@@
  #include <boost/foreach.hpp>
  #include <openssl/rand.h>
  
 -#ifndef __WXMSW__
 +#ifndef WIN32
  #include <arpa/inet.h>
  #endif
  
@@@ -123,13 -123,6 +123,13 @@@ public
      bool fDisconnect;
  protected:
      int nRefCount;
 +
 +    // Denial-of-service detection/prevention
 +    // Key is ip address, value is banned-until-time
 +    static std::map<unsigned int, int64> setBanned;
 +    static CCriticalSection cs_setBanned;
 +    int nMisbehavior;
 +
  public:
      int64 nReleaseTime;
      std::map<uint256, CRequestTracker> mapRequests;
      // publish and subscription
      std::vector<char> vfSubscribe;
  
 -
      CNode(SOCKET hSocketIn, CAddress addrIn, bool fInboundIn=false)
      {
          nServices = 0;
          nStartingHeight = -1;
          fGetAddr = false;
          vfSubscribe.assign(256, false);
 +        nMisbehavior = 0;
  
          // Be shy and don't send version until we hear
          if (!fInbound)
@@@ -362,7 -355,7 +362,7 @@@ public
          /// when NTP implemented, change to just nTime = GetAdjustedTime()
          int64 nTime = (fInbound ? GetAdjustedTime() : GetTime());
          CAddress addrYou = (fUseProxy ? CAddress("0.0.0.0") : addr);
-         CAddress addrMe = (fUseProxy ? CAddress("0.0.0.0") : addrLocalHost);
+         CAddress addrMe = (fUseProxy || !addrLocalHost.IsRoutable() ? CAddress("0.0.0.0") : addrLocalHost);
          RAND_bytes((unsigned char*)&nLocalHostNonce, sizeof(nLocalHostNonce));
          PushMessage("version", VERSION, nLocalServices, nTime, addrYou, addrMe,
                      nLocalHostNonce, std::string(pszSubVer), nBestHeight);
      void CancelSubscribe(unsigned int nChannel);
      void CloseSocketDisconnect();
      void Cleanup();
 +
 +
 +    // Denial-of-service detection/prevention
 +    // The idea is to detect peers that are behaving
 +    // badly and disconnect/ban them, but do it in a
 +    // one-coding-mistake-won't-shatter-the-entire-network
 +    // way.
 +    // IMPORTANT:  There should be nothing I can give a
 +    // node that it will forward on that will make that
 +    // node's peers drop it. If there is, an attacker
 +    // can isolate a node and/or try to split the network.
 +    // Dropping a node for sending stuff that is invalid
 +    // now but might be valid in a later version is also
 +    // dangerous, because it can cause a network split
 +    // between nodes running old code and nodes running
 +    // new code.
 +    static void ClearBanned(); // needed for unit testing
 +    static bool IsBanned(unsigned int ip);
 +    bool Misbehaving(int howmuch); // 1 == a little, 100 == a lot
  };