Merge branch '0.5.x' into 0.6.0.x
authorLuke Dashjr <luke-jr+git@utopios.org>
Thu, 14 Jun 2012 18:13:46 +0000 (18:13 +0000)
committerLuke Dashjr <luke-jr+git@utopios.org>
Thu, 14 Jun 2012 18:13:46 +0000 (18:13 +0000)
Conflicts:
src/main.h
src/net.cpp
src/serialize.h

14 files changed:
1  2 
contrib/debian/control
doc/build-unix.txt
doc/release-process.txt
src/bitcoinrpc.cpp
src/init.cpp
src/init.h
src/main.cpp
src/net.cpp
src/qt/addressbookpage.cpp
src/qt/bitcoin.cpp
src/qt/bitcoingui.cpp
src/qtui.h
src/test/test_bitcoin.cpp
src/util.cpp

diff --combined contrib/debian/control
@@@ -15,8 -15,7 +15,8 @@@ Build-Depends: debhelper
   libboost-thread-dev (>> 1.35) | libboost-thread1.35-dev,
   libboost-test-dev (>> 1.35) | libboost-test1.35-dev,
   qt4-qmake,
 - libqt4-dev
 + libqt4-dev,
 + libqrencode-dev
  Standards-Version: 3.9.2
  Homepage: http://www.bitcoin.org/
  Vcs-Git: git://github.com/bitcoin/bitcoin.git
@@@ -35,7 -34,7 +35,7 @@@ Description: peer-to-peer network base
   By default connects to an IRC network to discover other peers.
   .
   Full transaction history is stored locally at each client.  This
-  requires 150+ MB of space, slowly growing.
+  requires 2+ GB of space, slowly growing.
   .
   This package provides bitcoind, a combined daemon and CLI tool to
   interact with the daemon.
@@@ -53,6 -52,6 +53,6 @@@ Description: peer-to-peer network base
   By default connects to an IRC network to discover other peers.
   .
   Full transaction history is stored locally at each client.  This
-  requires 150+ MB of space, slowly growing.
+  requires 2+ GB of space, slowly growing.
   .
   This package provides bitcoin-qt, a GUI for Bitcoin based on QT.
diff --combined doc/build-unix.txt
@@@ -1,4 -1,5 +1,4 @@@
 -Copyright (c) 2009-2010 Satoshi Nakamoto
 -Copyright (c) 2011 Bitcoin Developers
 +Copyright (c) 2009-2012 Bitcoin Developers
  Distributed under the MIT/X11 software license, see the accompanying
  file license.txt or http://www.opensource.org/licenses/mit-license.php.
  This product includes software developed by the OpenSSL Project for use in
@@@ -22,27 -23,20 +22,27 @@@ the graphical bitcoin
  Dependencies
  ------------
  
 - Library    Purpose       Description
 - -------    -------       -----------
 - libssl     SSL Support   Secure communications
 - libdb4.8   Berkeley DB   Blockchain & wallet storage
 - libboost   Boost         C++ Library
 - miniupnpc  UPnP Support  Optional firewall-jumping support
 + Library     Purpose           Description
 + -------     -------           -----------
 + libssl      SSL Support       Secure communications
 + libdb4.8    Berkeley DB       Blockchain & wallet storage
 + libboost    Boost             C++ Library
 + miniupnpc   UPnP Support      Optional firewall-jumping support
 + libqrencode QRCode generation Optional QRCode generation
  
  miniupnpc may be used for UPnP port mapping.  It can be downloaded from
  http://miniupnp.tuxfamily.org/files/.  UPnP support is compiled in and
  turned off by default.  Set USE_UPNP to a different value to control this:
-  USE_UPNP=     No UPnP support - miniupnp not required
+  USE_UPNP=-    No UPnP support - miniupnp not required
   USE_UPNP=0    (the default) UPnP support turned off by default at runtime
   USE_UPNP=1    UPnP support turned on by default at runtime
  
 +libqrencode may be used for QRCode image generation. It can be downloaded
 +from http://fukuchi.org/works/qrencode/index.html.en, or installed via
 +your package manager. Set USE_QRCODE to control this:
 + USE_QRCODE=0   (the default) No QRCode support - libqrcode not required
 + USE_QRCODE=1   QRCode support enabled
 +
  Licenses of statically linked libraries:
   Berkeley DB   New BSD license with additional requirement that linked
                 software must be free open source
@@@ -56,6 -50,7 +56,6 @@@ Versions used in this release
   Boost         1.37
   miniupnpc     1.6
  
 -
  Dependency Build Instructions: Ubuntu & Debian
  ----------------------------------------------
  sudo apt-get install build-essential
@@@ -64,7 -59,6 +64,7 @@@ sudo apt-get install libdb4.8-de
  sudo apt-get install libdb4.8++-dev
   Boost 1.40+: sudo apt-get install libboost-all-dev
   or Boost 1.37: sudo apt-get install libboost1.37-dev
 +sudo apt-get install libqrencode-dev
  
  If using Boost 1.37, append -mt to the boost libraries in the makefile.
  
diff --combined doc/release-process.txt
@@@ -2,7 -2,7 +2,7 @@@
  
  * update (commit) version in sources
    bitcoin-qt.pro
 -  src/serialize.h
 +  src/main.h      (CLIENT_VERSION : PROTOCOL_VERSION in serialize.h is updated only on protocol changes)
    share/setup.nsi
    doc/README*
  
@@@ -26,9 -26,6 +26,9 @@@
     wget 'http://miniupnp.free.fr/files/download.php?file=miniupnpc-1.6.tar.gz' -O miniupnpc-1.6.tar.gz
     wget 'http://www.openssl.org/source/openssl-1.0.1b.tar.gz'
     wget 'http://download.oracle.com/berkeley-db/db-4.8.30.NC.tar.gz'
 +   wget 'http://zlib.net/zlib-1.2.6.tar.gz'
 +   wget 'ftp://ftp.simplesystems.org/pub/libpng/png/src/libpng-1.5.9.tar.gz'
 +   wget 'http://fukuchi.org/works/qrencode/qrencode-3.2.0.tar.bz2'
     wget 'http://downloads.sourceforge.net/project/boost/boost/1.47.0/boost_1_47_0.tar.bz2'
     wget 'http://download.qt.nokia.com/qt/source/qt-everywhere-opensource-src-4.7.4.tar.gz'
     cd ..
@@@ -36,8 -33,6 +36,8 @@@
     cp build/out/boost-win32-1.47.0-gitian.zip inputs/
     ./bin/gbuild ../bitcoin/contrib/gitian-descriptors/qt-win32.yml
     cp build/out/qt-win32-4.7.4-gitian.zip inputs/
 +   ./bin/gbuild ../bitcoin/contrib/gitian-descriptors/deps-win32.yml
 +   cp build/out/bitcoin-deps-0.0.3.zip inputs/
  
    * Build bitcoind and bitcoin-qt on Linux32, Linux64, and Win32:
     ./bin/gbuild --commit bitcoin=v${VERSION} ../bitcoin/contrib/gitian-descriptors/gitian.yml
     rm -rf bitcoin-${VERSION}-win32
  
  * perform Mac build
 -  See this blog post for how Gavin set up his build environment and
 -  patched macdeployqt to build the OSX release:
 +  See this blog post for how Gavin set up his build environment to build the OSX
 +  release; note that a patched version of macdeployqt is not needed anymore, as
 +  the required functionality and fixes are implemented directly in macdeployqtplus:
      http://gavintech.blogspot.com/2011/11/deploying-bitcoin-qt-on-osx.html
 -  qmake USE_SSL=1 USE_UPNP=1 bitcoin-qt.pro
 +  Gavin also had trouble with the macports py27-appscript package; he
 +  ended up installing a version that worked with: /usr/bin/easy_install-2.7 appscript
 +
 +  qmake RELEASE=1 USE_SSL=1 USE_UPNP=1 USE_QRCODE=1 bitcoin-qt.pro
    make
    export QTDIR=/opt/local/share/qt4  # needed to find translations/qt_*.qm files
    T=$(contrib/qt_translations.py $QTDIR/translations src/qt/locale)
 -  contrib/macdeploy/macdeployqtplus Bitcoin-Qt.app -add-qt-tr $T -dmg -fancy contrib/macdeploy/fancy.plist  
 +  python2.7 contrib/macdeploy/macdeployqtplus Bitcoin-Qt.app -add-qt-tr $T -dmg -fancy contrib/macdeploy/fancy.plist
  
   Build output expected:
    Bitcoin-Qt.dmg
@@@ -98,6 -89,8 +98,8 @@@
  
  * update wiki download links
  
+ * update wiki changelog: https://en.bitcoin.it/wiki/Changelog
  * Commit your signature to gitian.sigs:
    pushd gitian.sigs
    git add ${VERSION}/${SIGNER}
diff --combined src/bitcoinrpc.cpp
@@@ -9,11 -9,9 +9,11 @@@
  #include "init.h"
  #undef printf
  #include <boost/asio.hpp>
 +#include <boost/filesystem.hpp>
  #include <boost/iostreams/concepts.hpp>
  #include <boost/iostreams/stream.hpp>
  #include <boost/algorithm/string.hpp>
 +#include <boost/lexical_cast.hpp>
  #ifdef USE_SSL
  #include <boost/asio/ssl.hpp> 
  #include <boost/filesystem.hpp>
@@@ -43,8 -41,6 +43,8 @@@ static std::string strRPCUserColonPass
  static int64 nWalletUnlockTime;
  static CCriticalSection cs_nWalletUnlockTime;
  
 +extern Value dumpprivkey(const Array& params, bool fHelp);
 +extern Value importprivkey(const Array& params, bool fHelp);
  
  Object JSONRPCError(int code, const string& message)
  {
      return error;
  }
  
 -
 -void PrintConsole(const std::string &format, ...)
 +double GetDifficulty(const CBlockIndex* blockindex = NULL)
  {
 -    char buffer[50000];
 -    int limit = sizeof(buffer);
 -    va_list arg_ptr;
 -    va_start(arg_ptr, format);
 -    int ret = _vsnprintf(buffer, limit, format.c_str(), arg_ptr);
 -    va_end(arg_ptr);
 -    if (ret < 0 || ret >= limit)
 +    // Floating point number that is a multiple of the minimum difficulty,
 +    // minimum difficulty = 1.0.
 +    if (blockindex == NULL)
 +    {
 +        if (pindexBest == NULL)
 +            return 1.0;
 +        else
 +            blockindex = pindexBest;
 +    }
 +
 +    int nShift = (blockindex->nBits >> 24) & 0xff;
 +
 +    double dDiff =
 +        (double)0x0000ffff / (double)(blockindex->nBits & 0x00ffffff);
 +
 +    while (nShift < 29)
      {
 -        ret = limit - 1;
 -        buffer[limit-1] = 0;
 +        dDiff *= 256.0;
 +        nShift++;
      }
 -    printf("%s", buffer);
 -    fprintf(stdout, "%s", buffer);
 +    while (nShift > 29)
 +    {
 +        dDiff /= 256.0;
 +        nShift--;
 +    }
 +
 +    return dDiff;
  }
  
  
@@@ -102,26 -85,9 +102,26 @@@ Value ValueFromAmount(int64 amount
      return (double)amount / (double)COIN;
  }
  
 +std::string
 +HexBits(unsigned int nBits)
 +{
 +    union {
 +        int32_t nBits;
 +        char cBits[4];
 +    } uBits;
 +    uBits.nBits = htonl((int32_t)nBits);
 +    return HexStr(BEGIN(uBits.cBits), END(uBits.cBits));
 +}
 +
  void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
  {
 -    entry.push_back(Pair("confirmations", wtx.GetDepthInMainChain()));
 +    int confirms = wtx.GetDepthInMainChain();
 +    entry.push_back(Pair("confirmations", confirms));
 +    if (confirms)
 +    {
 +        entry.push_back(Pair("blockhash", wtx.hashBlock.GetHex()));
 +        entry.push_back(Pair("blockindex", wtx.nIndex));
 +    }
      entry.push_back(Pair("txid", wtx.GetHash().GetHex()));
      entry.push_back(Pair("time", (boost::int64_t)wtx.GetTxTime()));
      BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
@@@ -136,30 -102,6 +136,30 @@@ string AccountFromValue(const Value& va
      return strAccount;
  }
  
 +Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex)
 +{
 +    Object result;
 +    result.push_back(Pair("hash", block.GetHash().GetHex()));
 +    result.push_back(Pair("size", (int)::GetSerializeSize(block, SER_NETWORK)));
 +    result.push_back(Pair("height", blockindex->nHeight));
 +    result.push_back(Pair("version", block.nVersion));
 +    result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex()));
 +    result.push_back(Pair("time", (boost::int64_t)block.GetBlockTime()));
 +    result.push_back(Pair("nonce", (boost::uint64_t)block.nNonce));
 +    result.push_back(Pair("bits", HexBits(block.nBits)));
 +    result.push_back(Pair("difficulty", GetDifficulty(blockindex)));
 +    Array txhashes;
 +    BOOST_FOREACH (const CTransaction&tx, block.vtx)
 +        txhashes.push_back(tx.GetHash().GetHex());
 +    result.push_back(Pair("tx", txhashes));
 +
 +    if (blockindex->pprev)
 +        result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex()));
 +    if (blockindex->pnext)
 +        result.push_back(Pair("nextblockhash", blockindex->pnext->GetBlockHash().GetHex()));
 +    return result;
 +}
 +
  
  
  ///
@@@ -223,7 -165,8 +223,8 @@@ Value stop(const Array& params, bool fH
              "Stop bitcoin server.");
  #ifndef QT_GUI
      // Shutdown will take long enough that the response should get back
-     CreateThread(Shutdown, NULL);
 -    // NOTE: This should actually work with Bitcoin-Qt too now, but 0.5.0 didn't allow it
++    // NOTE: This should actually work with Bitcoin-Qt too now, but 0.6.0 didn't allow it
+     StartShutdown();
      return "bitcoin server stopping";
  #else
      throw runtime_error("NYI: cannot shut down GUI with RPC command");
@@@ -265,6 -208,32 +266,6 @@@ Value getconnectioncount(const Array& p
  }
  
  
 -double GetDifficulty()
 -{
 -    // Floating point number that is a multiple of the minimum difficulty,
 -    // minimum difficulty = 1.0.
 -
 -    if (pindexBest == NULL)
 -        return 1.0;
 -    int nShift = (pindexBest->nBits >> 24) & 0xff;
 -
 -    double dDiff =
 -        (double)0x0000ffff / (double)(pindexBest->nBits & 0x00ffffff);
 -
 -    while (nShift < 29)
 -    {
 -        dDiff *= 256.0;
 -        nShift++;
 -    }
 -    while (nShift > 29)
 -    {
 -        dDiff /= 256.0;
 -        nShift--;
 -    }
 -
 -    return dDiff;
 -}
 -
  Value getdifficulty(const Array& params, bool fHelp)
  {
      if (fHelp || params.size() != 0)
@@@ -283,7 -252,7 +284,7 @@@ Value getgenerate(const Array& params, 
              "getgenerate\n"
              "Returns true or false.");
  
 -    return (bool)fGenerateBitcoins;
 +    return GetBoolArg("-gen");
  }
  
  
@@@ -302,11 -271,13 +303,11 @@@ Value setgenerate(const Array& params, 
      if (params.size() > 1)
      {
          int nGenProcLimit = params[1].get_int();
 -        fLimitProcessors = (nGenProcLimit != -1);
 -        WriteSetting("fLimitProcessors", fLimitProcessors);
 -        if (nGenProcLimit != -1)
 -            WriteSetting("nLimitProcessors", nLimitProcessors = nGenProcLimit);
 +        mapArgs["-genproclimit"] = itostr(nGenProcLimit);
          if (nGenProcLimit == 0)
              fGenerate = false;
      }
 +    mapArgs["-gen"] = (fGenerate ? "1" : "0");
  
      GenerateBitcoins(fGenerate, pwalletMain);
      return Value::null;
@@@ -334,14 -305,15 +335,14 @@@ Value getinfo(const Array& params, boo
              "Returns an object containing various state info.");
  
      Object obj;
 -    obj.push_back(Pair("version",       (int)VERSION));
 +    obj.push_back(Pair("version",       (int)CLIENT_VERSION));
 +    obj.push_back(Pair("protocolversion",(int)PROTOCOL_VERSION));
 +    obj.push_back(Pair("walletversion", pwalletMain->GetVersion()));
      obj.push_back(Pair("balance",       ValueFromAmount(pwalletMain->GetBalance())));
      obj.push_back(Pair("blocks",        (int)nBestHeight));
      obj.push_back(Pair("connections",   (int)vNodes.size()));
      obj.push_back(Pair("proxy",         (fUseProxy ? addrProxy.ToStringIPPort() : string())));
 -    obj.push_back(Pair("generate",      (bool)fGenerateBitcoins));
 -    obj.push_back(Pair("genproclimit",  (int)(fLimitProcessors ? nLimitProcessors : -1)));
      obj.push_back(Pair("difficulty",    (double)GetDifficulty()));
 -    obj.push_back(Pair("hashespersec",  gethashespersec(params, false)));
      obj.push_back(Pair("testnet",       fTestNet));
      obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime()));
      obj.push_back(Pair("keypoolsize",   pwalletMain->GetKeyPoolSize()));
  }
  
  
 +Value getmininginfo(const Array& params, bool fHelp)
 +{
 +    if (fHelp || params.size() != 0)
 +        throw runtime_error(
 +            "getmininginfo\n"
 +            "Returns an object containing mining-related information.");
 +
 +    Object obj;
 +    obj.push_back(Pair("blocks",        (int)nBestHeight));
 +    obj.push_back(Pair("currentblocksize",(uint64_t)nLastBlockSize));
 +    obj.push_back(Pair("currentblocktx",(uint64_t)nLastBlockTx));
 +    obj.push_back(Pair("difficulty",    (double)GetDifficulty()));
 +    obj.push_back(Pair("errors",        GetWarnings("statusbar")));
 +    obj.push_back(Pair("generate",      GetBoolArg("-gen")));
 +    obj.push_back(Pair("genproclimit",  (int)GetArg("-genproclimit", -1)));
 +    obj.push_back(Pair("hashespersec",  gethashespersec(params, false)));
 +    obj.push_back(Pair("pooledtx",      (uint64_t)nPooledTx));
 +    obj.push_back(Pair("testnet",       fTestNet));
 +    return obj;
 +}
 +
 +
  Value getnewaddress(const Array& params, bool fHelp)
  {
      if (fHelp || params.size() > 1)
@@@ -583,6 -533,8 +584,6 @@@ 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)
@@@ -644,7 -596,7 +645,7 @@@ Value verifymessage(const Array& params
      if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig))
          return false;
  
 -    return (key.GetAddress() == addr);
 +    return (CBitcoinAddress(key.GetPubKey()) == addr);
  }
  
  
@@@ -711,7 -663,7 +712,7 @@@ Value getreceivedbyaccount(const Array
      if (params.size() > 1)
          nMinDepth = params[1].get_int();
  
 -    // Get the set of pub keys that have the label
 +    // Get the set of pub keys assigned to account
      string strAccount = AccountFromValue(params[0]);
      set<CBitcoinAddress> setAddress;
      GetAccountAddresses(strAccount, setAddress);
          BOOST_FOREACH(const CTxOut& txout, wtx.vout)
          {
              CBitcoinAddress address;
 -            if (ExtractAddress(txout.scriptPubKey, pwalletMain, address) && setAddress.count(address))
 +            if (ExtractAddress(txout.scriptPubKey, address) && pwalletMain->HaveKey(address) && setAddress.count(address))
                  if (wtx.GetDepthInMainChain() >= nMinDepth)
                      nAmount += txout.nValue;
          }
@@@ -984,81 -936,6 +985,81 @@@ Value sendmany(const Array& params, boo
      return wtx.GetHash().GetHex();
  }
  
 +Value addmultisigaddress(const Array& params, bool fHelp)
 +{
 +    if (fHelp || params.size() < 2 || params.size() > 3)
 +    {
 +        string msg = "addmultisigaddress <nrequired> <'[\"key\",\"key\"]'> [account]\n"
 +            "Add a nrequired-to-sign multisignature address to the wallet\"\n"
 +            "each key is a bitcoin address or hex-encoded public key\n"
 +            "If [account] is specified, assign address to [account].";
 +        throw runtime_error(msg);
 +    }
 +    if (!fTestNet)
 +        throw runtime_error("addmultisigaddress available only when running -testnet\n");
 +
 +    int nRequired = params[0].get_int();
 +    const Array& keys = params[1].get_array();
 +    string strAccount;
 +    if (params.size() > 2)
 +        strAccount = AccountFromValue(params[2]);
 +
 +    // Gather public keys
 +    if (nRequired < 1)
 +        throw runtime_error("a multisignature address must require at least one key to redeem");
 +    if (keys.size() < nRequired)
 +        throw runtime_error(
 +            strprintf("not enough keys supplied "
 +                      "(got %d keys, but need at least %d to redeem)", keys.size(), nRequired));
 +    std::vector<CKey> pubkeys;
 +    pubkeys.resize(keys.size());
 +    for (unsigned int i = 0; i < keys.size(); i++)
 +    {
 +        const std::string& ks = keys[i].get_str();
 +
 +        // Case 1: bitcoin address and we have full public key:
 +        CBitcoinAddress address(ks);
 +        if (address.IsValid())
 +        {
 +            if (address.IsScript())
 +                throw runtime_error(
 +                    strprintf("%s is a pay-to-script address",ks.c_str()));
 +            std::vector<unsigned char> vchPubKey;
 +            if (!pwalletMain->GetPubKey(address, vchPubKey))
 +                throw runtime_error(
 +                    strprintf("no full public key for address %s",ks.c_str()));
 +            if (vchPubKey.empty() || !pubkeys[i].SetPubKey(vchPubKey))
 +                throw runtime_error(" Invalid public key: "+ks);
 +        }
 +
 +        // Case 2: hex public key
 +        else if (IsHex(ks))
 +        {
 +            vector<unsigned char> vchPubKey = ParseHex(ks);
 +            if (vchPubKey.empty() || !pubkeys[i].SetPubKey(vchPubKey))
 +                throw runtime_error(" Invalid public key: "+ks);
 +        }
 +        else
 +        {
 +            throw runtime_error(" Invalid public key: "+ks);
 +        }
 +    }
 +
 +    // Construct using pay-to-script-hash:
 +    CScript inner;
 +    inner.SetMultisig(nRequired, pubkeys);
 +
 +    uint160 scriptHash = Hash160(inner);
 +    CScript scriptPubKey;
 +    scriptPubKey.SetPayToScriptHash(inner);
 +    pwalletMain->AddCScript(inner);
 +    CBitcoinAddress address;
 +    address.SetScriptHash160(scriptHash);
 +
 +    pwalletMain->SetAddressBookName(address, strAccount);
 +    return address.ToString();
 +}
 +
  
  struct tallyitem
  {
      tallyitem()
      {
          nAmount = 0;
 -        nConf = INT_MAX;
 +        nConf = std::numeric_limits<int>::max();
      }
  };
  
@@@ -1088,7 -965,6 +1089,7 @@@ Value ListReceived(const Array& params
      for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
      {
          const CWalletTx& wtx = (*it).second;
 +
          if (wtx.IsCoinBase() || !wtx.IsFinal())
              continue;
  
          BOOST_FOREACH(const CTxOut& txout, wtx.vout)
          {
              CBitcoinAddress address;
 -            if (!ExtractAddress(txout.scriptPubKey, pwalletMain, address) || !address.IsValid())
 +            if (!ExtractAddress(txout.scriptPubKey, address) || !pwalletMain->HaveKey(address) || !address.IsValid())
                  continue;
  
              tallyitem& item = mapTally[address];
              continue;
  
          int64 nAmount = 0;
 -        int nConf = INT_MAX;
 +        int nConf = std::numeric_limits<int>::max();
          if (it != mapTally.end())
          {
              nAmount = (*it).second.nAmount;
              obj.push_back(Pair("address",       address.ToString()));
              obj.push_back(Pair("account",       strAccount));
              obj.push_back(Pair("amount",        ValueFromAmount(nAmount)));
 -            obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
 +            obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
              ret.push_back(obj);
          }
      }
              Object obj;
              obj.push_back(Pair("account",       (*it).first));
              obj.push_back(Pair("amount",        ValueFromAmount(nAmount)));
 -            obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
 +            obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
              ret.push_back(obj);
          }
      }
@@@ -1198,7 -1074,6 +1199,7 @@@ void ListTransactions(const CWalletTx& 
      string strSentAccount;
      list<pair<CBitcoinAddress, int64> > listReceived;
      list<pair<CBitcoinAddress, int64> > listSent;
 +
      wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
  
      bool fAllAccounts = (strAccount == string("*"));
@@@ -1713,7 -1588,7 +1714,7 @@@ Value encryptwallet(const Array& params
      // 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);
+     StartShutdown();
      return "wallet encrypted; bitcoin server stopping, restart to run with encrypted wallet";
  }
  
@@@ -1736,42 -1611,14 +1737,42 @@@ Value validateaddress(const Array& para
          // version of the address:
          string currentAddress = address.ToString();
          ret.push_back(Pair("address", currentAddress));
 -        ret.push_back(Pair("ismine", (pwalletMain->HaveKey(address) > 0)));
 +        if (pwalletMain->HaveKey(address))
 +        {
 +            ret.push_back(Pair("ismine", true));
 +            std::vector<unsigned char> vchPubKey;
 +            pwalletMain->GetPubKey(address, vchPubKey);
 +            ret.push_back(Pair("pubkey", HexStr(vchPubKey)));
 +            CKey key;
 +            key.SetPubKey(vchPubKey);
 +            ret.push_back(Pair("iscompressed", key.IsCompressed()));
 +        }
 +        else if (pwalletMain->HaveCScript(address.GetHash160()))
 +        {
 +            ret.push_back(Pair("isscript", true));
 +            CScript subscript;
 +            pwalletMain->GetCScript(address.GetHash160(), subscript);
 +            ret.push_back(Pair("ismine", ::IsMine(*pwalletMain, subscript)));
 +            std::vector<CBitcoinAddress> addresses;
 +            txnouttype whichType;
 +            int nRequired;
 +            ExtractAddresses(subscript, whichType, addresses, nRequired);
 +            ret.push_back(Pair("script", GetTxnOutputType(whichType)));
 +            Array a;
 +            BOOST_FOREACH(const CBitcoinAddress& addr, addresses)
 +                a.push_back(addr.ToString());
 +            ret.push_back(Pair("addresses", a));
 +            if (whichType == TX_MULTISIG)
 +                ret.push_back(Pair("sigsrequired", nRequired));
 +        }
 +        else
 +            ret.push_back(Pair("ismine", false));
          if (pwalletMain->mapAddressBook.count(address))
              ret.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
      }
      return ret;
  }
  
 -
  Value getwork(const Array& params, bool fHelp)
  {
      if (fHelp || params.size() > 1)
@@@ -1887,10 -1734,7 +1888,10 @@@ Value getmemorypool(const Array& params
              "  \"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"
 +            "  \"coinbaseflags\" : data that should be included in coinbase so support for new features can be judged\n"
              "  \"time\" : timestamp appropriate for next block\n"
 +            "  \"mintime\" : minimum timestamp appropriate for next block\n"
 +            "  \"curtime\" : current timestamp\n"
              "  \"bits\" : compressed target of next block\n"
              "If [data] is specified, tries to solve the block and returns true if it was successful.");
  
          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("coinbaseflags", HexStr(COINBASE_FLAGS.begin(), COINBASE_FLAGS.end())));
          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))));
 +        result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1));
 +        result.push_back(Pair("curtime", (int64_t)GetAdjustedTime()));
 +        result.push_back(Pair("bits", HexBits(pblock->nBits)));
  
          return result;
      }
      }
  }
  
 +Value getblockhash(const Array& params, bool fHelp)
 +{
 +    if (fHelp || params.size() != 1)
 +        throw runtime_error(
 +            "getblockhash <index>\n"
 +            "Returns hash of block in best-block-chain at <index>.");
 +
 +    int nHeight = params[0].get_int();
 +    if (nHeight < 0 || nHeight > nBestHeight)
 +        throw runtime_error("Block number out of range.");
 +
 +    CBlock block;
 +    CBlockIndex* pblockindex = mapBlockIndex[hashBestChain];
 +    while (pblockindex->nHeight > nHeight)
 +        pblockindex = pblockindex->pprev;
 +    return pblockindex->phashBlock->GetHex();
 +}
 +
 +Value getblock(const Array& params, bool fHelp)
 +{
 +    if (fHelp || params.size() != 1)
 +        throw runtime_error(
 +            "getblock <hash>\n"
 +            "Returns details of a block with given block-hash.");
 +
 +    std::string strHash = params[0].get_str();
 +    uint256 hash(strHash);
 +
 +    if (mapBlockIndex.count(hash) == 0)
 +        throw JSONRPCError(-5, "Block not found");
 +
 +    CBlock block;
 +    CBlockIndex* pblockindex = mapBlockIndex[hash];
 +    block.ReadFromDisk(pblockindex, true);
 +
 +    return blockToJSON(block, pblockindex);
 +}
 +
  
  
  
@@@ -2027,7 -1836,6 +2028,7 @@@ pair<string, rpcfn_type> pCallTable[] 
      make_pair("setgenerate",            &setgenerate),
      make_pair("gethashespersec",        &gethashespersec),
      make_pair("getinfo",                &getinfo),
 +    make_pair("getmininginfo",          &getmininginfo),
      make_pair("getnewaddress",          &getnewaddress),
      make_pair("getaccountaddress",      &getaccountaddress),
      make_pair("setaccount",             &setaccount),
      make_pair("move",                   &movecmd),
      make_pair("sendfrom",               &sendfrom),
      make_pair("sendmany",               &sendmany),
 +    make_pair("addmultisigaddress",     &addmultisigaddress),
 +    make_pair("getblock",               &getblock),
 +    make_pair("getblockhash",           &getblockhash),
      make_pair("gettransaction",         &gettransaction),
      make_pair("listtransactions",       &listtransactions),
 -    make_pair("signmessage",           &signmessage),
 -    make_pair("verifymessage",         &verifymessage),
 +    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),
 +    make_pair("listsinceblock",         &listsinceblock),
 +    make_pair("dumpprivkey",            &dumpprivkey),
 +    make_pair("importprivkey",          &importprivkey)
  };
  map<string, rpcfn_type> mapCallTable(pCallTable, pCallTable + sizeof(pCallTable)/sizeof(pCallTable[0]));
  
@@@ -2078,7 -1881,6 +2079,7 @@@ string pAllowInSafeMode[] 
      "setgenerate",
      "gethashespersec",
      "getinfo",
 +    "getmininginfo",
      "getnewaddress",
      "getaccountaddress",
      "getaccount",
@@@ -2358,30 -2160,26 +2359,26 @@@ void ThreadRPCServer(void* parg
      IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer(parg));
      try
      {
 -        vnThreadsRunning[4]++;
 +        vnThreadsRunning[THREAD_RPCSERVER]++;
          ThreadRPCServer2(parg);
 -        vnThreadsRunning[4]--;
 +        vnThreadsRunning[THREAD_RPCSERVER]--;
      }
      catch (std::exception& e) {
 -        vnThreadsRunning[4]--;
 +        vnThreadsRunning[THREAD_RPCSERVER]--;
          PrintException(&e, "ThreadRPCServer()");
      } catch (...) {
 -        vnThreadsRunning[4]--;
 +        vnThreadsRunning[THREAD_RPCSERVER]--;
          PrintException(NULL, "ThreadRPCServer()");
      }
      printf("ThreadRPCServer exiting\n");
  }
  
- #ifdef QT_GUI
- extern bool HACK_SHUTDOWN;
- #endif
  void ThreadRPCServer2(void* parg)
  {
      printf("ThreadRPCServer started\n");
  
      strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
 -    if (strRPCUserColonPass == ":")
 +    if (mapArgs["-rpcpassword"] == "")
      {
          unsigned char rand_pwd[32];
          RAND_bytes(rand_pwd, 32);
          else if (mapArgs.count("-daemon"))
              strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
          ThreadSafeMessageBox(strprintf(
 -            _("Error: %s, you must set a rpcpassword in the configuration file:\n %s\n"
 +            _("%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"
                  EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32).c_str()),
              _("Error"), wxOK | wxMODAL);
  #ifndef QT_GUI
-         CreateThread(Shutdown, NULL);
+         StartShutdown();
  #endif
          return;
      }
      }
      catch(boost::system::system_error &e)
      {
-         HACK_SHUTDOWN = true;
          ThreadSafeMessageBox(strprintf(_("An error occured while setting up the RPC port %i for listening: %s"), endpoint.port(), e.what()),
                               _("Error"), wxOK | wxMODAL);
+         StartShutdown();
          return;
      }
  #endif
  #endif
  
          ip::tcp::endpoint peer;
 -        vnThreadsRunning[4]--;
 +        vnThreadsRunning[THREAD_RPCSERVER]--;
  #ifdef USE_SSL
          acceptor.accept(sslStream.lowest_layer(), peer);
  #else
@@@ -2710,7 -2508,6 +2707,7 @@@ int CommandLineRPC(int argc, char *argv
          if (strMethod == "listreceivedbyaccount"  && n > 0) ConvertTo<boost::int64_t>(params[0]);
          if (strMethod == "listreceivedbyaccount"  && n > 1) ConvertTo<bool>(params[1]);
          if (strMethod == "getbalance"             && n > 1) ConvertTo<boost::int64_t>(params[1]);
 +        if (strMethod == "getblockhash"           && n > 0) ConvertTo<boost::int64_t>(params[0]);
          if (strMethod == "move"                   && n > 2) ConvertTo<double>(params[2]);
          if (strMethod == "move"                   && n > 3) ConvertTo<boost::int64_t>(params[3]);
          if (strMethod == "sendfrom"               && n > 2) ConvertTo<double>(params[2]);
              params[1] = v.get_obj();
          }
          if (strMethod == "sendmany"                && n > 2) ConvertTo<boost::int64_t>(params[2]);
 +        if (strMethod == "addmultisigaddress"      && n > 0) ConvertTo<boost::int64_t>(params[0]);
 +        if (strMethod == "addmultisigaddress"      && n > 1)
 +        {
 +            string s = params[1].get_str();
 +            Value v;
 +            if (!read_string(s, v) || v.type() != array_type)
 +                throw runtime_error("type mismatch "+s);
 +            params[1] = v.get_array();
 +        }
  
          // Execute
          Object reply = CallRPC(strMethod, params);
diff --combined src/init.cpp
@@@ -10,7 -10,6 +10,7 @@@
  #include "strlcpy.h"
  #include <boost/filesystem.hpp>
  #include <boost/filesystem/fstream.hpp>
 +#include <boost/filesystem/convenience.hpp>
  #include <boost/interprocess/sync/file_lock.hpp>
  
  #if defined(BITCOIN_NEED_QT_PLUGINS) && !defined(_BITCOIN_QT_PLUGINS_INCLUDED)
@@@ -42,6 -41,17 +42,17 @@@ void ExitTimeout(void* parg
  #endif
  }
  
+ void StartShutdown()
+ {
+ #ifdef QT_GUI
+     // ensure we leave the Qt main loop for a clean GUI exit (Shutdown() is called in bitcoin.cpp afterwards)
+     QueueShutdown();
+ #else
+     // Without UI, Shutdown() can simply be started in a new thread
+     CreateThread(Shutdown, NULL);
+ #endif
+ }
  void Shutdown(void* parg)
  {
      static CCriticalSection cs_Shutdown;
          Sleep(50);
          printf("Bitcoin exiting\n\n");
          fExit = true;
+ #ifndef QT_GUI
+         // ensure non UI client get's exited here, but let Bitcoin-Qt reach return 0; in bitcoin.cpp
          exit(0);
+ #endif
      }
      else
      {
@@@ -150,15 -163,24 +164,15 @@@ bool AppInit2(int argc, char* argv[]
      //
      // Parameters
      //
 +    // If Qt is used, parameters/bitcoin.conf are parsed in qt/bitcoin.cpp's main()
 +#if !defined(QT_GUI)
      ParseParameters(argc, argv);
 -
 -    if (mapArgs.count("-datadir"))
 +    if (!ReadConfigFile(mapArgs, mapMultiArgs))
      {
 -        if (filesystem::is_directory(filesystem::system_complete(mapArgs["-datadir"])))
 -        {
 -            filesystem::path pathDataDir = filesystem::system_complete(mapArgs["-datadir"]);
 -            strlcpy(pszSetDataDir, pathDataDir.string().c_str(), sizeof(pszSetDataDir));
 -        }
 -        else
 -        {
 -            fprintf(stderr, "Error: Specified directory does not exist\n");
 -            Shutdown(NULL);
 -        }
 +        fprintf(stderr, "Error: Specified directory does not exist\n");
 +        Shutdown(NULL);
      }
 -
 -
 -    ReadConfigFile(mapArgs, mapMultiArgs); // Must be done after processing datadir
 +#endif
  
      if (mapArgs.count("-?") || mapArgs.count("--help"))
      {
            _("Bitcoin version") + " " + FormatFullVersion() + "\n\n" +
            _("Usage:") + "\t\t\t\t\t\t\t\t\t\t\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") +
 -            "  -gen             \t\t  " + _("Generate coins\n") +
 -            "  -gen=0           \t\t  " + _("Don't generate coins\n") +
 -            "  -min             \t\t  " + _("Start minimized\n") +
 -            "  -datadir=<dir>   \t\t  " + _("Specify data directory\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") +
 -            "  -noirc           \t  "   + _("Don't find peers using internet relay chat\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") +
 +            "  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" +
 +            "  -gen             \t\t  " + _("Generate coins") + "\n" +
 +            "  -gen=0           \t\t  " + _("Don't generate coins") + "\n" +
 +            "  -min             \t\t  " + _("Start minimized") + "\n" +
 +            "  -splash          \t\t  " + _("Show splash screen on startup (default: 1)") + "\n" +
 +            "  -datadir=<dir>   \t\t  " + _("Specify data directory") + "\n" +
 +            "  -dbcache=<n>     \t\t  " + _("Set database cache size in megabytes (default: 25)") + "\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 and attempt to keep the connection open") + "\n" +
 +            "  -connect=<ip>    \t\t  " + _("Connect only to the specified node") + "\n" +
 +            "  -irc             \t  "   + _("Find peers using internet relay chat (default: 0)") + "\n" +
 +            "  -listen          \t  "   + _("Accept connections from outside (default: 1)") + "\n" +
 +#ifdef QT_GUI
 +            "  -lang=<lang>     \t\t  " + _("Set language, for example \"de_DE\" (default: system locale)") + "\n" +
 +#endif
 +            "  -dnsseed         \t  "   + _("Find peers using DNS lookup (default: 1)") + "\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") +
 +            "  -upnp            \t  "   + _("Use Universal Plug and Play to map the listening port (default: 1)") + "\n" +
  #else
 -            "  -upnp            \t  "   + _("Attempt to use UPnP to map the listening port\n") +
 +            "  -upnp            \t  "   + _("Use Universal Plug and Play to map the listening port (default: 0)") + "\n" +
  #endif
  #endif
 -            "  -paytxfee=<amt>  \t  "   + _("Fee per kB to add to transactions you send\n") +
 +            "  -paytxfee=<amt>  \t  "   + _("Fee per KB to add to transactions you send") + "\n" +
  #ifdef QT_GUI
 -            "  -server          \t\t  " + _("Accept command line and JSON-RPC commands\n") +
 +            "  -server          \t\t  " + _("Accept command line and JSON-RPC commands") + "\n" +
  #endif
  #if !defined(WIN32) && !defined(QT_GUI)
 -            "  -daemon          \t\t  " + _("Run in the background as a daemon and accept commands\n") +
 +            "  -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") +
 +            "  -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") +
 +            "  -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") +
 -            "  -rpcallowip=<ip> \t\t  " + _("Allow JSON-RPC connections from specified IP address\n") +
 -            "  -rpcconnect=<ip> \t  "   + _("Send commands to node running on <ip> (default: 127.0.0.1)\n") +
 -            "  -keypool=<n>     \t  "   + _("Set key pool size to <n> (default: 100)\n") +
 -            "  -rescan          \t  "   + _("Rescan the block chain for missing wallet transactions\n");
 +            "  -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" +
 +            "  -rpcallowip=<ip> \t\t  " + _("Allow JSON-RPC connections from specified IP address") + "\n" +
 +            "  -rpcconnect=<ip> \t  "   + _("Send commands to node running on <ip> (default: 127.0.0.1)") + "\n" +
 +            "  -blocknotify=<cmd> "     + _("Execute command when the best block changes (%s in cmd is replaced by block hash)") + "\n" +
 +            "  -upgradewallet   \t  "   + _("Upgrade wallet to latest format") + "\n" +
 +            "  -keypool=<n>     \t  "   + _("Set key pool size to <n> (default: 100)") + "\n" +
 +            "  -rescan          \t  "   + _("Rescan the block chain for missing wallet transactions") + "\n" +
 +            "  -checkblocks=<n> \t\t  " + _("How many blocks to check at startup (default: 2500, 0 = all)") + "\n" +
 +            "  -checklevel=<n>  \t\t  " + _("How thorough the block verification is (0-6, default: 1)") + "\n";
  
  #ifdef USE_SSL
          strUsage += string() +
 -            _("\nSSL options: (see the Bitcoin Wiki for SSL setup instructions)\n") +
 -            "  -rpcssl                                \t  " + _("Use OpenSSL (https) for JSON-RPC connections\n") +
 -            "  -rpcsslcertificatechainfile=<file.cert>\t  " + _("Server certificate file (default: server.cert)\n") +
 -            "  -rpcsslprivatekeyfile=<file.pem>       \t  " + _("Server private key (default: server.pem)\n") +
 -            "  -rpcsslciphers=<ciphers>               \t  " + _("Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH)\n");
 +            _("\nSSL options: (see the Bitcoin Wiki for SSL setup instructions)") + "\n" +
 +            "  -rpcssl                                \t  " + _("Use OpenSSL (https) for JSON-RPC connections") + "\n" +
 +            "  -rpcsslcertificatechainfile=<file.cert>\t  " + _("Server certificate file (default: server.cert)") + "\n" +
 +            "  -rpcsslprivatekeyfile=<file.pem>       \t  " + _("Server private key (default: server.pem)") + "\n" +
 +            "  -rpcsslciphers=<ciphers>               \t  " + _("Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH)") + "\n";
  #endif
  
          strUsage += string() +
 -            "  -?               \t\t  " + _("This help message\n");
 +            "  -?               \t\t  " + _("This help message") + "\n";
  
          // Remove tabs
          strUsage.erase(std::remove(strUsage.begin(), strUsage.end(), '\t'), strUsage.end());
      }
  
      fTestNet = GetBoolArg("-testnet");
 +    if (fTestNet)
 +    {
 +        SoftSetBoolArg("-irc", true);
 +    }
 +
      fDebug = GetBoolArg("-debug");
  
  #if !defined(WIN32) && !defined(QT_GUI)
  
  #ifndef QT_GUI
      for (int i = 1; i < argc; i++)
 -        if (!IsSwitchChar(argv[i][0]))
 +        if (!IsSwitchChar(argv[i][0]) && !(strlen(argv[i]) > 7 && strncasecmp(argv[i], "bitcoin:", 8) == 0))
              fCommandLine = true;
  
      if (fCommandLine)
          return false;
      }
  
 -    string strErrors;
 -
 +    std::ostringstream strErrors;
      //
      // Load data files
      //
      if (fDaemon)
          fprintf(stdout, "bitcoin server starting\n");
 -    strErrors = "";
      int64 nStart;
  
      InitMessage(_("Loading addresses..."));
      printf("Loading addresses...\n");
      nStart = GetTimeMillis();
      if (!LoadAddresses())
 -        strErrors += _("Error loading addr.dat      \n");
 +        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");
 +        strErrors << _("Error loading blkindex.dat") << "\n";
      printf(" block index %15"PRI64d"ms\n", GetTimeMillis() - nStart);
  
      InitMessage(_("Loading wallet..."));
      if (nLoadWalletRet != DB_LOAD_OK)
      {
          if (nLoadWalletRet == DB_CORRUPT)
 -            strErrors += _("Error loading wallet.dat: Wallet corrupted      \n");
 +            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");
 +            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");
 -            printf("%s", strErrors.c_str());
 -            wxMessageBox(strErrors, "Bitcoin", wxOK | wxICON_ERROR);
 +            strErrors << _("Wallet needed to be rewritten: restart Bitcoin to complete") << "\n";
 +            printf("%s", strErrors.str().c_str());
 +            wxMessageBox(strErrors.str(), "Bitcoin", wxOK | wxICON_ERROR);
              return false;
          }
          else
 -            strErrors += _("Error loading wallet.dat      \n");
 +            strErrors << _("Error loading wallet.dat") << "\n";
 +    }
 +
 +    if (GetBoolArg("-upgradewallet", fFirstRun))
 +    {
 +        int nMaxVersion = GetArg("-upgradewallet", 0);
 +        if (nMaxVersion == 0) // the -walletupgrade without argument case
 +        {
 +            printf("Performing wallet upgrade to %i\n", FEATURE_LATEST);
 +            nMaxVersion = CLIENT_VERSION;
 +            pwalletMain->SetMinVersion(FEATURE_LATEST); // permanently upgrade the wallet immediately
 +        }
 +        else
 +            printf("Allowing wallet upgrade up to %i\n", nMaxVersion);
 +        if (nMaxVersion < pwalletMain->GetVersion())
 +            strErrors << _("Cannot downgrade wallet") << "\n";
 +        pwalletMain->SetMaxVersion(nMaxVersion);
      }
 -    printf("%s", strErrors.c_str());
 +
 +    if (fFirstRun)
 +    {
 +        // Create new keyUser and set as default key
 +        RandAddSeedPerfmon();
 +
 +        std::vector<unsigned char> newDefaultKey;
 +        if (!pwalletMain->GetKeyFromPool(newDefaultKey, false))
 +            strErrors << _("Cannot initialize keypool") << "\n";
 +        pwalletMain->SetDefaultKey(newDefaultKey);
 +        if (!pwalletMain->SetAddressBookName(CBitcoinAddress(pwalletMain->vchDefaultKey), ""))
 +            strErrors << _("Cannot write default address") << "\n";
 +    }
 +
 +    printf("%s", strErrors.str().c_str());
      printf(" wallet      %15"PRI64d"ms\n", GetTimeMillis() - nStart);
  
      RegisterWallet(pwalletMain);
      InitMessage(_("Done loading"));
      printf("Done loading\n");
  
 -        //// debug print
 -        printf("mapBlockIndex.size() = %d\n",   mapBlockIndex.size());
 -        printf("nBestHeight = %d\n",            nBestHeight);
 -        printf("setKeyPool.size() = %d\n",      pwalletMain->setKeyPool.size());
 -        printf("mapWallet.size() = %d\n",       pwalletMain->mapWallet.size());
 -        printf("mapAddressBook.size() = %d\n",  pwalletMain->mapAddressBook.size());
 +    //// debug print
 +    printf("mapBlockIndex.size() = %d\n",   mapBlockIndex.size());
 +    printf("nBestHeight = %d\n",            nBestHeight);
 +    printf("setKeyPool.size() = %d\n",      pwalletMain->setKeyPool.size());
 +    printf("mapWallet.size() = %d\n",       pwalletMain->mapWallet.size());
 +    printf("mapAddressBook.size() = %d\n",  pwalletMain->mapAddressBook.size());
  
 -    if (!strErrors.empty())
 +    if (!strErrors.str().empty())
      {
 -        wxMessageBox(strErrors, "Bitcoin", wxOK | wxICON_ERROR);
 +        wxMessageBox(strErrors.str(), "Bitcoin", wxOK | wxICON_ERROR);
          return false;
      }
  
          return false;
      }
  
      if (mapArgs.count("-proxy"))
      {
          fUseProxy = true;
 -        addrProxy = CAddress(mapArgs["-proxy"]);
 +        addrProxy = CService(mapArgs["-proxy"], 9050);
          if (!addrProxy.IsValid())
          {
              wxMessageBox(_("Invalid -proxy address"), "Bitcoin");
          }
      }
  
 -    bool fTor = (fUseProxy && addrProxy.port == htons(9050));
 +    bool fTor = (fUseProxy && addrProxy.GetPort() == 9050);
      if (fTor)
      {
 -        // Use SoftSetArg here so user can override any of these if they wish.
 +        // Use SoftSetBoolArg here so user can override any of these if they wish.
          // Note: the GetBoolArg() calls for all of these must happen later.
 -        SoftSetArg("-nolisten", true);
 -        SoftSetArg("-noirc", true);
 -        SoftSetArg("-nodnsseed", true);
 -        SoftSetArg("-noupnp", true);
 -        SoftSetArg("-upnp", false);
 -        SoftSetArg("-dns", false);
 +        SoftSetBoolArg("-listen", false);
 +        SoftSetBoolArg("-irc", false);
 +        SoftSetBoolArg("-dnsseed", false);
 +        SoftSetBoolArg("-upnp", false);
 +        SoftSetBoolArg("-dns", false);
      }
  
      fAllowDNS = GetBoolArg("-dns");
 -    fNoListen = GetBoolArg("-nolisten");
 +    fNoListen = !GetBoolArg("-listen", true);
  
 -    // Command-line args override in-wallet settings:
 -    if (mapArgs.count("-upnp"))
 -        fUseUPnP = GetBoolArg("-upnp");
 -    else if (mapArgs.count("-noupnp"))
 -        fUseUPnP = !GetBoolArg("-noupnp");
 +    // Continue to put "/P2SH/" in the coinbase to monitor
 +    // BIP16 support.
 +    // This can be removed eventually...
 +    const char* pszP2SH = "/P2SH/";
 +    COINBASE_FLAGS << std::vector<unsigned char>(pszP2SH, pszP2SH+strlen(pszP2SH));
  
      if (!fNoListen)
      {
 -        if (!BindListenPort(strErrors))
 +        std::string strError;
 +        if (!BindListenPort(strError))
          {
 -            wxMessageBox(strErrors, "Bitcoin");
 +            wxMessageBox(strError, "Bitcoin");
              return false;
          }
      }
      {
          BOOST_FOREACH(string strAddr, mapMultiArgs["-addnode"])
          {
 -            CAddress addr(strAddr, fAllowDNS);
 +            CAddress addr(CService(strAddr, GetDefaultPort(), fAllowDNS));
              addr.nTime = 0; // so it won't relay unless successfully connected
              if (addr.IsValid())
 -                AddAddress(addr);
 +                addrman.Add(addr, CNetAddr("127.0.0.1"));
          }
      }
  
      if (fServer)
          CreateThread(ThreadRPCServer, NULL);
  
 +#ifdef QT_GUI
 +    if(GetStartOnSystemStartup())
 +        SetStartOnSystemStartup(true); // Remove startup links to bitcoin-wx
 +#endif
 +
  #if !defined(QT_GUI)
      while (1)
          Sleep(5000);
  
      return true;
  }
 +
 +#ifdef WIN32
 +string StartupShortcutPath()
 +{
 +    return MyGetSpecialFolderPath(CSIDL_STARTUP, true) + "\\Bitcoin.lnk";
 +}
 +
 +bool GetStartOnSystemStartup()
 +{
 +    return filesystem::exists(StartupShortcutPath().c_str());
 +}
 +
 +bool SetStartOnSystemStartup(bool fAutoStart)
 +{
 +    // If the shortcut exists already, remove it for updating
 +    remove(StartupShortcutPath().c_str());
 +
 +    if (fAutoStart)
 +    {
 +        CoInitialize(NULL);
 +
 +        // Get a pointer to the IShellLink interface.
 +        IShellLink* psl = NULL;
 +        HRESULT hres = CoCreateInstance(CLSID_ShellLink, NULL,
 +                                CLSCTX_INPROC_SERVER, IID_IShellLink,
 +                                reinterpret_cast<void**>(&psl));
 +
 +        if (SUCCEEDED(hres))
 +        {
 +            // Get the current executable path
 +            TCHAR pszExePath[MAX_PATH];
 +            GetModuleFileName(NULL, pszExePath, sizeof(pszExePath));
 +
 +            TCHAR pszArgs[5] = TEXT("-min");
 +
 +            // Set the path to the shortcut target
 +            psl->SetPath(pszExePath);
 +            PathRemoveFileSpec(pszExePath);
 +            psl->SetWorkingDirectory(pszExePath);
 +            psl->SetShowCmd(SW_SHOWMINNOACTIVE);
 +            psl->SetArguments(pszArgs);
 +
 +            // Query IShellLink for the IPersistFile interface for
 +            // saving the shortcut in persistent storage.
 +            IPersistFile* ppf = NULL;
 +            hres = psl->QueryInterface(IID_IPersistFile,
 +                                       reinterpret_cast<void**>(&ppf));
 +            if (SUCCEEDED(hres))
 +            {
 +                WCHAR pwsz[MAX_PATH];
 +                // Ensure that the string is ANSI.
 +                MultiByteToWideChar(CP_ACP, 0, StartupShortcutPath().c_str(), -1, pwsz, MAX_PATH);
 +                // Save the link by calling IPersistFile::Save.
 +                hres = ppf->Save(pwsz, TRUE);
 +                ppf->Release();
 +                psl->Release();
 +                CoUninitialize();
 +                return true;
 +            }
 +            psl->Release();
 +        }
 +        CoUninitialize();
 +        return false;
 +    }
 +    return true;
 +}
 +
 +#elif defined(LINUX)
 +
 +// Follow the Desktop Application Autostart Spec:
 +//  http://standards.freedesktop.org/autostart-spec/autostart-spec-latest.html
 +
 +boost::filesystem::path GetAutostartDir()
 +{
 +    namespace fs = boost::filesystem;
 +
 +    char* pszConfigHome = getenv("XDG_CONFIG_HOME");
 +    if (pszConfigHome) return fs::path(pszConfigHome) / fs::path("autostart");
 +    char* pszHome = getenv("HOME");
 +    if (pszHome) return fs::path(pszHome) / fs::path(".config/autostart");
 +    return fs::path();
 +}
 +
 +boost::filesystem::path GetAutostartFilePath()
 +{
 +    return GetAutostartDir() / boost::filesystem::path("bitcoin.desktop");
 +}
 +
 +bool GetStartOnSystemStartup()
 +{
 +    boost::filesystem::ifstream optionFile(GetAutostartFilePath());
 +    if (!optionFile.good())
 +        return false;
 +    // Scan through file for "Hidden=true":
 +    string line;
 +    while (!optionFile.eof())
 +    {
 +        getline(optionFile, line);
 +        if (line.find("Hidden") != string::npos &&
 +            line.find("true") != string::npos)
 +            return false;
 +    }
 +    optionFile.close();
 +
 +    return true;
 +}
 +
 +bool SetStartOnSystemStartup(bool fAutoStart)
 +{
 +    if (!fAutoStart)
 +    {
 +#if defined(BOOST_FILESYSTEM_VERSION) && BOOST_FILESYSTEM_VERSION >= 3
 +        unlink(GetAutostartFilePath().string().c_str());
 +#else
 +        unlink(GetAutostartFilePath().native_file_string().c_str());
 +#endif
 +    }
 +    else
 +    {
 +        char pszExePath[MAX_PATH+1];
 +        memset(pszExePath, 0, sizeof(pszExePath));
 +        if (readlink("/proc/self/exe", pszExePath, sizeof(pszExePath)-1) == -1)
 +            return false;
 +
 +        boost::filesystem::create_directories(GetAutostartDir());
 +
 +        boost::filesystem::ofstream optionFile(GetAutostartFilePath(), ios_base::out|ios_base::trunc);
 +        if (!optionFile.good())
 +            return false;
 +        // Write a bitcoin.desktop file to the autostart directory:
 +        optionFile << "[Desktop Entry]\n";
 +        optionFile << "Type=Application\n";
 +        optionFile << "Name=Bitcoin\n";
 +        optionFile << "Exec=" << pszExePath << " -min\n";
 +        optionFile << "Terminal=false\n";
 +        optionFile << "Hidden=false\n";
 +        optionFile.close();
 +    }
 +    return true;
 +}
 +#else
 +
 +// TODO: OSX startup stuff; see:
 +// http://developer.apple.com/mac/library/documentation/MacOSX/Conceptual/BPSystemStartup/Articles/CustomLogin.html
 +
 +bool GetStartOnSystemStartup() { return false; }
 +bool SetStartOnSystemStartup(bool fAutoStart) { return false; }
 +
 +#endif
diff --combined src/init.h
@@@ -1,5 -1,5 +1,5 @@@
  // Copyright (c) 2009-2010 Satoshi Nakamoto
 -// Copyright (c) 2011 The Bitcoin developers
 +// Copyright (c) 2009-2012 The Bitcoin developers
  // Distributed under the MIT/X11 software license, see the accompanying
  // file COPYING or http://www.opensource.org/licenses/mit-license.php.
  #ifndef BITCOIN_INIT_H
@@@ -7,11 -7,9 +7,12 @@@
  
  extern CWallet* pwalletMain;
  
+ void StartShutdown();
  void Shutdown(void* parg);
  bool AppInit(int argc, char* argv[]);
  bool AppInit2(int argc, char* argv[]);
  
 +bool GetStartOnSystemStartup();
 +bool SetStartOnSystemStartup(bool fAutoStart);
 +
  #endif
diff --combined src/main.cpp
@@@ -8,7 -8,6 +8,7 @@@
  #include "db.h"
  #include "net.h"
  #include "init.h"
 +#include <boost/algorithm/string/replace.hpp>
  #include <boost/filesystem.hpp>
  #include <boost/filesystem/fstream.hpp>
  
@@@ -19,11 -18,6 +19,11 @@@ using namespace boost
  // Global state
  //
  
 +// Name of client reported in the 'version' message. Report the same name
 +// for both bitcoind and bitcoin-qt, to make it harder for attackers to
 +// target servers or GUI users specifically.
 +const std::string CLIENT_NAME("Satoshi");
 +
  CCriticalSection cs_setpwalletRegistered;
  set<CWallet*> setpwalletRegistered;
  
@@@ -53,17 -47,22 +53,17 @@@ multimap<uint256, CBlock*> mapOrphanBlo
  map<uint256, CDataStream*> mapOrphanTransactions;
  multimap<uint256, CDataStream*> mapOrphanTransactionsByPrev;
  
 +// Constant stuff for coinbase transactions we create:
 +CScript COINBASE_FLAGS;
 +
 +const string strMessageMagic = "Bitcoin Signed Message:\n";
  
  double dHashesPerSec;
  int64 nHPSTimerStart;
  
  // Settings
 -int fGenerateBitcoins = false;
  int64 nTransactionFee = 0;
 -int fLimitProcessors = false;
 -int nLimitProcessors = 1;
 -int fMinimizeToTray = true;
 -int fMinimizeOnClose = true;
 -#if USE_UPNP
 -int fUseUPnP = true;
 -#else
 -int fUseUPnP = false;
 -#endif
 +
  
  
  //////////////////////////////////////////////////////////////////////////////
@@@ -260,103 -259,6 +260,103 @@@ bool CTransaction::ReadFromDisk(COutPoi
      return ReadFromDisk(txdb, prevout, txindex);
  }
  
 +bool CTransaction::IsStandard() const
 +{
 +    BOOST_FOREACH(const CTxIn& txin, vin)
 +    {
 +        // Biggest 'standard' txin is a 3-signature 3-of-3 CHECKMULTISIG
 +        // pay-to-script-hash, which is 3 ~80-byte signatures, 3
 +        // ~65-byte public keys, plus a few script ops.
 +        if (txin.scriptSig.size() > 500)
 +            return false;
 +        if (!txin.scriptSig.IsPushOnly())
 +            return false;
 +    }
 +    BOOST_FOREACH(const CTxOut& txout, vout)
 +        if (!::IsStandard(txout.scriptPubKey))
 +            return false;
 +    return true;
 +}
 +
 +//
 +// Check transaction inputs, and make sure any
 +// pay-to-script-hash transactions are evaluating IsStandard scripts
 +//
 +// Why bother? To avoid denial-of-service attacks; an attacker
 +// can submit a standard HASH... OP_EQUAL transaction,
 +// which will get accepted into blocks. The redemption
 +// script can be anything; an attacker could use a very
 +// expensive-to-check-upon-redemption script like:
 +//   DUP CHECKSIG DROP ... repeated 100 times... OP_1
 +//
 +bool CTransaction::AreInputsStandard(const MapPrevTx& mapInputs) const
 +{
 +    if (IsCoinBase())
 +        return true; // Coinbases don't use vin normally
 +
 +    for (unsigned int i = 0; i < vin.size(); i++)
 +    {
 +        const CTxOut& prev = GetOutputFor(vin[i], mapInputs);
 +
 +        vector<vector<unsigned char> > vSolutions;
 +        txnouttype whichType;
 +        // get the scriptPubKey corresponding to this input:
 +        const CScript& prevScript = prev.scriptPubKey;
 +        if (!Solver(prevScript, whichType, vSolutions))
 +            return false;
 +        int nArgsExpected = ScriptSigArgsExpected(whichType, vSolutions);
 +        if (nArgsExpected < 0)
 +            return false;
 +
 +        // Transactions with extra stuff in their scriptSigs are
 +        // non-standard. Note that this EvalScript() call will
 +        // be quick, because if there are any operations
 +        // beside "push data" in the scriptSig the
 +        // IsStandard() call returns false
 +        vector<vector<unsigned char> > stack;
 +        if (!EvalScript(stack, vin[i].scriptSig, *this, i, 0))
 +            return false;
 +
 +        if (whichType == TX_SCRIPTHASH)
 +        {
 +            if (stack.empty())
 +                return false;
 +            CScript subscript(stack.back().begin(), stack.back().end());
 +            vector<vector<unsigned char> > vSolutions2;
 +            txnouttype whichType2;
 +            if (!Solver(subscript, whichType2, vSolutions2))
 +                return false;
 +            if (whichType2 == TX_SCRIPTHASH)
 +                return false;
 +
 +            int tmpExpected;
 +            tmpExpected = ScriptSigArgsExpected(whichType2, vSolutions2);
 +            if (tmpExpected < 0)
 +                return false;
 +            nArgsExpected += tmpExpected;
 +        }
 +
 +        if (stack.size() != (unsigned int)nArgsExpected)
 +            return false;
 +    }
 +
 +    return true;
 +}
 +
 +int
 +CTransaction::GetLegacySigOpCount() const
 +{
 +    int nSigOps = 0;
 +    BOOST_FOREACH(const CTxIn& txin, vin)
 +    {
 +        nSigOps += txin.scriptSig.GetSigOpCount(false);
 +    }
 +    BOOST_FOREACH(const CTxOut& txout, vout)
 +    {
 +        nSigOps += txout.scriptPubKey.GetSigOpCount(false);
 +    }
 +    return nSigOps;
 +}
  
  
  int CMerkleTx::SetMerkleBranch(const CBlock* pblock)
@@@ -477,7 -379,7 +477,7 @@@ bool CTransaction::AcceptToMemoryPool(C
          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)
 +    if ((int64)nLockTime > std::numeric_limits<int>::max())
          return error("AcceptToMemoryPool() : not accepting nLockTime beyond 2038 yet");
  
      // Rather not work on nonstandard transactions (unless -testnet)
              return error("AcceptToMemoryPool() : FetchInputs failed %s", hash.ToString().substr(0,10).c_str());
          }
  
 -        // Safety limits
 -        unsigned int nSize = ::GetSerializeSize(*this, SER_NETWORK);
 -        // Checking ECDSA signatures is a CPU bottleneck, so to avoid denial-of-service
 -        // attacks disallow transactions with more than one SigOp per 34 bytes.
 -        // 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() : transaction with out-of-bounds SigOpCount");
 +        // Check for non-standard pay-to-script-hash in inputs
 +        if (!AreInputsStandard(mapInputs) && !fTestNet)
 +            return error("AcceptToMemoryPool() : nonstandard transaction input");
 +
 +        // Note: if you modify this code to accept non-standard transactions, then
 +        // you should add code here to check that the transaction does a
 +        // reasonable number of ECDSA signature verifications.
  
          int64 nFees = GetValueIn(mapInputs)-GetValueOut();
 +        unsigned int nSize = ::GetSerializeSize(*this, SER_NETWORK);
  
          // Don't accept it if it can't get into a block
 -        if (nFees < GetMinFee(1000, true, true))
 +        if (nFees < GetMinFee(1000, true, GMF_RELAY))
              return error("AcceptToMemoryPool() : not enough fees");
  
          // Continuously rate-limit free transactions
@@@ -609,11 -511,8 +609,11 @@@ bool CTransaction::AcceptToMemoryPool(b
      return AcceptToMemoryPool(txdb, fCheckInputs, pfMissingInputs);
  }
  
 +uint64 nPooledTx = 0;
 +
  bool CTransaction::AddToMemoryPoolUnchecked()
  {
 +    printf("AcceptToMemoryPoolUnchecked(): size %lu\n",  mapTransactions.size());
      // Add to memory pool without checking anything.  Don't call this directly,
      // call AcceptToMemoryPool to properly check the transaction first.
      CRITICAL_BLOCK(cs_mapTransactions)
          for (unsigned int i = 0; i < vin.size(); i++)
              mapNextTx[vin[i].prevout] = CInPoint(&mapTransactions[hash], i);
          nTransactionsUpdated++;
 +        ++nPooledTx;
      }
      return true;
  }
@@@ -634,15 -532,10 +634,15 @@@ bool CTransaction::RemoveFromMemoryPool
      // Remove transaction from memory pool
      CRITICAL_BLOCK(cs_mapTransactions)
      {
 -        BOOST_FOREACH(const CTxIn& txin, vin)
 -            mapNextTx.erase(txin.prevout);
 -        mapTransactions.erase(GetHash());
 -        nTransactionsUpdated++;
 +        uint256 hash = GetHash();
 +        if (mapTransactions.count(hash))
 +        {
 +            BOOST_FOREACH(const CTxIn& txin, vin)
 +                mapNextTx.erase(txin.prevout);
 +            mapTransactions.erase(hash);
 +            nTransactionsUpdated++;
 +            --nPooledTx;
 +        }
      }
      return true;
  }
  
  
  
 -int CMerkleTx::GetDepthInMainChain(int& nHeightRet) const
 +int CMerkleTx::GetDepthInMainChain(CBlockIndex* &pindexRet) const
  {
      if (hashBlock == 0 || nIndex == -1)
          return 0;
          fMerkleVerified = true;
      }
  
 -    nHeightRet = pindex->nHeight;
 +    pindexRet = pindex;
      return pindexBest->nHeight - pindex->nHeight + 1;
  }
  
@@@ -1290,9 -1183,9 +1290,9 @@@ bool CBlock::ConnectBlock(CTxDB& txdb, 
          }
      }
  
 -    // P2SH didn't become active until Apr 1 2012 (Feb 15 on testnet)
 -    int64 nEvalSwitchTime = fTestNet ? 1329264000 : 1333238400;
 -    bool fStrictPayToScriptHash = (pindex->nTime >= nEvalSwitchTime);
 +    // BIP16 didn't become active until Apr 1 2012 (Feb 15 on testnet)
 +    int64 nBIP16SwitchTime = fTestNet ? 1329264000 : 1333238400;
 +    bool fStrictPayToScriptHash = (pindex->nTime >= nBIP16SwitchTime);
  
      //// issue here: it doesn't know the version
      unsigned int nTxPos = pindex->nBlockPos + ::GetSerializeSize(CBlock(), SER_DISK) - 1 + GetSizeOfCompactSize(vtx.size());
      int nSigOps = 0;
      BOOST_FOREACH(CTransaction& tx, vtx)
      {
 -        nSigOps += tx.GetSigOpCount();
 +        nSigOps += tx.GetLegacySigOpCount();
          if (nSigOps > MAX_BLOCK_SIGOPS)
              return DoS(100, error("ConnectBlock() : too many sigops"));
  
          CDiskTxPos posThisTx(pindex->nFile, pindex->nBlockPos, nTxPos);
          nTxPos += ::GetSerializeSize(tx, SER_DISK);
  
          MapPrevTx mapInputs;
          if (!tx.IsCoinBase())
          {
 +            bool fInvalid;
              if (!tx.FetchInputs(txdb, mapQueuedChanges, true, false, mapInputs, fInvalid))
                  return false;
  
@@@ -1460,39 -1353,6 +1460,39 @@@ bool static Reorganize(CTxDB& txdb, CBl
  }
  
  
 +static void
 +runCommand(std::string strCommand)
 +{
 +    int nErr = ::system(strCommand.c_str());
 +    if (nErr)
 +        printf("runCommand error: system(%s) returned %d\n", strCommand.c_str(), nErr);
 +}
 +
 +// Called from inside SetBestChain: attaches a block to the new best chain being built
 +bool CBlock::SetBestChainInner(CTxDB& txdb, CBlockIndex *pindexNew)
 +{
 +    uint256 hash = GetHash();
 +
 +    // Adding to current best branch
 +    if (!ConnectBlock(txdb, pindexNew) || !txdb.WriteHashBestChain(hash))
 +    {
 +        txdb.TxnAbort();
 +        InvalidChainFound(pindexNew);
 +        return false;
 +    }
 +    if (!txdb.TxnCommit())
 +        return error("SetBestChain() : TxnCommit failed");
 +
 +    // Add to current best branch
 +    pindexNew->pprev->pnext = pindexNew;
 +
 +    // Delete redundant memory transactions
 +    BOOST_FOREACH(CTransaction& tx, vtx)
 +        tx.RemoveFromMemoryPool();
 +
 +    return true;
 +}
 +
  bool CBlock::SetBestChain(CTxDB& txdb, CBlockIndex* pindexNew)
  {
      uint256 hash = GetHash();
      }
      else if (hashPrevBlock == hashBestChain)
      {
 -        // Adding to current best branch
 -        if (!ConnectBlock(txdb, pindexNew) || !txdb.WriteHashBestChain(hash))
 +        if (!SetBestChainInner(txdb, pindexNew))
 +            return error("SetBestChain() : SetBestChainInner failed");
 +    }
 +    else
 +    {
 +        // the first block in the new chain that will cause it to become the new best chain
 +        CBlockIndex *pindexIntermediate = pindexNew;
 +
 +        // list of blocks that need to be connected afterwards
 +        std::vector<CBlockIndex*> vpindexSecondary;
 +
 +        // Reorganize is costly in terms of db load, as it works in a single db transaction.
 +        // Try to limit how much needs to be done inside
 +        while (pindexIntermediate->pprev && pindexIntermediate->pprev->bnChainWork > pindexBest->bnChainWork)
          {
 -            txdb.TxnAbort();
 -            InvalidChainFound(pindexNew);
 -            return error("SetBestChain() : ConnectBlock failed");
 +            vpindexSecondary.push_back(pindexIntermediate);
 +            pindexIntermediate = pindexIntermediate->pprev;
          }
 -        if (!txdb.TxnCommit())
 -            return error("SetBestChain() : TxnCommit failed");
  
 -        // Add to current best branch
 -        pindexNew->pprev->pnext = pindexNew;
 +        if (!vpindexSecondary.empty())
 +            printf("Postponing %i reconnects\n", vpindexSecondary.size());
  
 -        // Delete redundant memory transactions
 -        BOOST_FOREACH(CTransaction& tx, vtx)
 -            tx.RemoveFromMemoryPool();
 -    }
 -    else
 -    {
 -        // New best branch
 -        if (!Reorganize(txdb, pindexNew))
 +        // Switch to new best branch
 +        if (!Reorganize(txdb, pindexIntermediate))
          {
              txdb.TxnAbort();
              InvalidChainFound(pindexNew);
              return error("SetBestChain() : Reorganize failed");
          }
 +
 +        // Connect futher blocks
 +        BOOST_REVERSE_FOREACH(CBlockIndex *pindex, vpindexSecondary)
 +        {
 +            CBlock block;
 +            if (!block.ReadFromDisk(pindex))
 +            {
 +                printf("SetBestChain() : ReadFromDisk failed\n");
 +                break;
 +            }
 +            if (!txdb.TxnBegin()) {
 +                printf("SetBestChain() : TxnBegin 2 failed\n");
 +                break;
 +            }
 +            // errors now are not fatal, we still did a reorganisation to a new chain in a valid way
 +            if (!block.SetBestChainInner(txdb, pindex))
 +                break;
 +        }
      }
  
      // Update best block in wallet (so we can detect restored wallets)
 -    if (!IsInitialBlockDownload())
 +    bool fIsInitialDownload = IsInitialBlockDownload();
 +    if (!fIsInitialDownload)
      {
          const CBlockLocator locator(pindexNew);
          ::SetBestChain(locator);
      nTransactionsUpdated++;
      printf("SetBestChain: new best=%s  height=%d  work=%s\n", hashBestChain.ToString().substr(0,20).c_str(), nBestHeight, bnBestChainWork.ToString().c_str());
  
 +    std::string strCmd = GetArg("-blocknotify", "");
 +
 +    if (!fIsInitialDownload && !strCmd.empty())
 +    {
 +        boost::replace_all(strCmd, "%s", hashBestChain.GetHex());
 +        boost::thread t(runCommand, strCmd); // thread runs free
 +    }
 +
      return true;
  }
  
@@@ -1676,12 -1506,8 +1676,12 @@@ bool CBlock::CheckBlock() cons
      if (uniqueTx.size() != vtx.size())
          return DoS(100, error("CheckBlock() : duplicate transaction"));
  
 -    // Check that it's not full of nonstandard transactions
 -    if (GetSigOpCount() > MAX_BLOCK_SIGOPS)
 +    int nSigOps = 0;
 +    BOOST_FOREACH(const CTransaction& tx, vtx)
 +    {
 +        nSigOps += tx.GetLegacySigOpCount();
 +    }
 +    if (nSigOps > MAX_BLOCK_SIGOPS)
          return DoS(100, error("CheckBlock() : out-of-bounds SigOpCount"));
  
      // Check merkleroot
@@@ -1840,7 -1666,7 +1840,7 @@@ bool CheckDiskSpace(uint64 nAdditionalB
          strMiscWarning = strMessage;
          printf("*** %s\n", strMessage.c_str());
          ThreadSafeMessageBox(strMessage, "Bitcoin", wxOK | wxICON_EXCLAMATION);
-         CreateThread(Shutdown, NULL);
+         StartShutdown();
          return false;
      }
      return true;
@@@ -2194,7 -2020,7 +2194,7 @@@ unsigned char pchMessageStart[4] = { 0x
  
  bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
  {
 -    static map<unsigned int, vector<unsigned char> > mapReuseKey;
 +    static map<CService, vector<unsigned char> > mapReuseKey;
      RandAddSeedPerfmon();
      if (fDebug) {
          printf("%s ", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str());
          CAddress addrFrom;
          uint64 nNonce = 1;
          vRecv >> pfrom->nVersion >> pfrom->nServices >> nTime >> addrMe;
 +        if (pfrom->nVersion < 209)
 +        {
 +            // Since February 20, 2012, the protocol is initiated at version 209,
 +            // and earlier versions are no longer supported
 +            printf("partner %s using obsolete version %i; disconnecting\n", pfrom->addr.ToString().c_str(), pfrom->nVersion);
 +            pfrom->fDisconnect = true;
 +            return false;
 +        }
 +
          if (pfrom->nVersion == 10300)
              pfrom->nVersion = 300;
 -        if (pfrom->nVersion >= 106 && !vRecv.empty())
 +        if (!vRecv.empty())
              vRecv >> addrFrom >> nNonce;
 -        if (pfrom->nVersion >= 106 && !vRecv.empty())
 +        if (!vRecv.empty())
              vRecv >> pfrom->strSubVer;
 -        if (pfrom->nVersion >= 209 && !vRecv.empty())
 +        if (!vRecv.empty())
              vRecv >> pfrom->nStartingHeight;
  
 -        if (pfrom->nVersion == 0)
 -            return false;
 -
          // Disconnect if we connected to ourself
          if (nNonce == nLocalHostNonce && nNonce > 1)
          {
  
          pfrom->fClient = !(pfrom->nServices & NODE_NETWORK);
  
 -        AddTimeData(pfrom->addr.ip, nTime);
 +        AddTimeData(pfrom->addr, nTime);
  
          // Change version
 -        if (pfrom->nVersion >= 209)
 -            pfrom->PushMessage("verack");
 -        pfrom->vSend.SetVersion(min(pfrom->nVersion, VERSION));
 -        if (pfrom->nVersion < 209)
 -            pfrom->vRecv.SetVersion(min(pfrom->nVersion, VERSION));
 +        pfrom->PushMessage("verack");
 +        pfrom->vSend.SetVersion(min(pfrom->nVersion, PROTOCOL_VERSION));
  
          if (!pfrom->fInbound)
          {
              // Advertise our address
 -            if (addrLocalHost.IsRoutable() && !fUseProxy)
 +            if (!fNoListen && !fUseProxy && addrLocalHost.IsRoutable() &&
 +                !IsInitialBlockDownload())
              {
                  CAddress addr(addrLocalHost);
                  addr.nTime = GetAdjustedTime();
              }
  
              // Get recent addresses
 -            if (pfrom->nVersion >= 31402 || mapAddresses.size() < 1000)
 +            if (pfrom->nVersion >= 31402 || addrman.size() < 1000)
              {
                  pfrom->PushMessage("getaddr");
                  pfrom->fGetAddr = true;
              }
 +            addrman.Good(pfrom->addr);
 +        } else {
 +            if (((CNetAddr)pfrom->addr) == (CNetAddr)addrFrom)
 +            {
 +                addrman.Add(addrFrom, addrFrom);
 +                addrman.Good(addrFrom);
 +            }
          }
  
          // Ask the first connected node for block updates
  
      else if (strCommand == "verack")
      {
 -        pfrom->vRecv.SetVersion(min(pfrom->nVersion, VERSION));
 +        pfrom->vRecv.SetVersion(min(pfrom->nVersion, PROTOCOL_VERSION));
      }
  
  
          vRecv >> vAddr;
  
          // Don't want addr from older versions unless seeding
 -        if (pfrom->nVersion < 209)
 -            return true;
 -        if (pfrom->nVersion < 31402 && mapAddresses.size() > 1000)
 +        if (pfrom->nVersion < 31402 && addrman.size() > 1000)
              return true;
          if (vAddr.size() > 1000)
          {
          }
  
          // Store the new addresses
 -        CAddrDB addrDB;
 -        addrDB.TxnBegin();
          int64 nNow = GetAdjustedTime();
          int64 nSince = nNow - 10 * 60;
          BOOST_FOREACH(CAddress& addr, vAddr)
                  continue;
              if (addr.nTime <= 100000000 || addr.nTime > nNow + 10 * 60)
                  addr.nTime = nNow - 5 * 24 * 60 * 60;
 -            AddAddress(addr, 2 * 60 * 60, &addrDB);
              pfrom->AddAddressKnown(addr);
              if (addr.nTime > nSince && !pfrom->fGetAddr && vAddr.size() <= 10 && addr.IsRoutable())
              {
                      static uint256 hashSalt;
                      if (hashSalt == 0)
                          RAND_bytes((unsigned char*)&hashSalt, sizeof(hashSalt));
 -                    uint256 hashRand = hashSalt ^ (((int64)addr.ip)<<32) ^ ((GetTime()+addr.ip)/(24*60*60));
 +                    int64 hashAddr = addr.GetHash();
 +                    uint256 hashRand = hashSalt ^ (hashAddr<<32) ^ ((GetTime()+hashAddr)/(24*60*60));
                      hashRand = Hash(BEGIN(hashRand), END(hashRand));
                      multimap<uint256, CNode*> mapMix;
                      BOOST_FOREACH(CNode* pnode, vNodes)
                  }
              }
          }
 -        addrDB.TxnCommit();  // Save addresses (it's ok if this fails)
 +        addrman.Add(vAddr, pfrom->addr, 2 * 60 * 60);
          if (vAddr.size() < 1000)
              pfrom->fGetAddr = false;
      }
              }
          }
          CTxDB txdb("r");
 -        for (int nInv = 0; nInv < vInv.size(); nInv++)
 +        for (unsigned int nInv = 0; nInv < vInv.size(); nInv++)
          {
              const CInv &inv = vInv[nInv];
  
  
      else if (strCommand == "getaddr")
      {
 -        // Nodes rebroadcast an addr every 24 hours
          pfrom->vAddrToSend.clear();
 -        int64 nSince = GetAdjustedTime() - 3 * 60 * 60; // in the last 3 hours
 -        CRITICAL_BLOCK(cs_mapAddresses)
 -        {
 -            unsigned int nCount = 0;
 -            BOOST_FOREACH(const PAIRTYPE(vector<unsigned char>, CAddress)& item, mapAddresses)
 -            {
 -                const CAddress& addr = item.second;
 -                if (addr.nTime > nSince)
 -                    nCount++;
 -            }
 -            BOOST_FOREACH(const PAIRTYPE(vector<unsigned char>, CAddress)& item, mapAddresses)
 -            {
 -                const CAddress& addr = item.second;
 -                if (addr.nTime > nSince && GetRand(nCount) < 2500)
 -                    pfrom->PushAddress(addr);
 -            }
 -        }
 +        vector<CAddress> vAddr = addrman.GetAddr();
 +        BOOST_FOREACH(const CAddress &addr, vAddr)
 +            pfrom->PushAddress(addr);
      }
  
  
          /// we have a chance to check the order here
  
          // Keep giving the same key to the same ip until they use it
 -        if (!mapReuseKey.count(pfrom->addr.ip))
 -            pwalletMain->GetKeyFromPool(mapReuseKey[pfrom->addr.ip], true);
 +        if (!mapReuseKey.count(pfrom->addr))
 +            pwalletMain->GetKeyFromPool(mapReuseKey[pfrom->addr], true);
  
          // Send back approval of order and pubkey to use
          CScript scriptPubKey;
 -        scriptPubKey << mapReuseKey[pfrom->addr.ip] << OP_CHECKSIG;
 +        scriptPubKey << mapReuseKey[pfrom->addr] << OP_CHECKSIG;
          pfrom->PushMessage("reply", hashReply, (int)0, scriptPubKey);
      }
  
@@@ -2798,14 -2632,17 +2798,14 @@@ bool ProcessMessages(CNode* pfrom
          }
  
          // Checksum
 -        if (vRecv.GetVersion() >= 209)
 +        uint256 hash = Hash(vRecv.begin(), vRecv.begin() + nMessageSize);
 +        unsigned int nChecksum = 0;
 +        memcpy(&nChecksum, &hash, sizeof(nChecksum));
 +        if (nChecksum != hdr.nChecksum)
          {
 -            uint256 hash = Hash(vRecv.begin(), vRecv.begin() + nMessageSize);
 -            unsigned int nChecksum = 0;
 -            memcpy(&nChecksum, &hash, sizeof(nChecksum));
 -            if (nChecksum != hdr.nChecksum)
 -            {
 -                printf("ProcessMessages(%s, %u bytes) : CHECKSUM ERROR nChecksum=%08x hdr.nChecksum=%08x\n",
 -                       strCommand.c_str(), nMessageSize, nChecksum, hdr.nChecksum);
 -                continue;
 -            }
 +            printf("ProcessMessages(%s, %u bytes) : CHECKSUM ERROR nChecksum=%08x hdr.nChecksum=%08x\n",
 +               strCommand.c_str(), nMessageSize, nChecksum, hdr.nChecksum);
 +            continue;
          }
  
          // Copy message to its own buffer
@@@ -2870,18 -2707,18 +2870,18 @@@ bool SendMessages(CNode* pto, bool fSen
  
          // Address refresh broadcast
          static int64 nLastRebroadcast;
 -        if (GetTime() - nLastRebroadcast > 24 * 60 * 60)
 +        if (!IsInitialBlockDownload() && (GetTime() - nLastRebroadcast > 24 * 60 * 60))
          {
 -            nLastRebroadcast = GetTime();
              CRITICAL_BLOCK(cs_vNodes)
              {
                  BOOST_FOREACH(CNode* pnode, vNodes)
                  {
                      // Periodically clear setAddrKnown to allow refresh broadcasts
 -                    pnode->setAddrKnown.clear();
 +                    if (nLastRebroadcast)
 +                        pnode->setAddrKnown.clear();
  
                      // Rebroadcast our address
 -                    if (addrLocalHost.IsRoutable() && !fUseProxy)
 +                    if (!fNoListen && !fUseProxy && addrLocalHost.IsRoutable())
                      {
                          CAddress addr(addrLocalHost);
                          addr.nTime = GetAdjustedTime();
                      }
                  }
              }
 +            nLastRebroadcast = GetTime();
          }
  
 -        // Clear out old addresses periodically so it's not too much work at once
 -        static int64 nLastClear;
 -        if (nLastClear == 0)
 -            nLastClear = GetTime();
 -        if (GetTime() - nLastClear > 10 * 60 && vNodes.size() >= 3)
 -        {
 -            nLastClear = GetTime();
 -            CRITICAL_BLOCK(cs_mapAddresses)
 -            {
 -                CAddrDB addrdb;
 -                int64 nSince = GetAdjustedTime() - 14 * 24 * 60 * 60;
 -                for (map<vector<unsigned char>, CAddress>::iterator mi = mapAddresses.begin();
 -                     mi != mapAddresses.end();)
 -                {
 -                    const CAddress& addr = (*mi).second;
 -                    if (addr.nTime < nSince)
 -                    {
 -                        if (mapAddresses.size() < 1000 || GetTime() > nLastClear + 20)
 -                            break;
 -                        addrdb.EraseAddress(addr);
 -                        mapAddresses.erase(mi++);
 -                    }
 -                    else
 -                        mi++;
 -                }
 -            }
 -        }
 -
 -
          //
          // Message: addr
          //
@@@ -3116,9 -2981,6 +3116,9 @@@ public
  };
  
  
 +uint64 nLastBlockTx = 0;
 +uint64 nLastBlockSize = 0;
 +
  CBlock* CreateNewBlock(CReserveKey& reservekey)
  {
      CBlockIndex* pindexPrev = pindexBest;
          // Collect transactions into block
          map<uint256, CTxIndex> mapTestPool;
          uint64 nBlockSize = 1000;
 +        uint64 nBlockTx = 0;
          int nBlockSigOps = 100;
          while (!mapPriority.empty())
          {
                  continue;
  
              // Legacy limits on sigOps:
 -            int nTxSigOps = tx.GetSigOpCount();
 +            int nTxSigOps = tx.GetLegacySigOpCount();
              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);
 +            int64 nMinFee = tx.GetMinFee(nBlockSize, fAllowFree, GMF_BLOCK);
  
              // Connecting shouldn't fail due to dependency on other memory pool transactions
              // because we're already processing them in order of dependency
              map<uint256, CTxIndex> mapTestPoolTmp(mapTestPool);
 -            bool fInvalid;
              MapPrevTx mapInputs;
 +            bool fInvalid;
              if (!tx.FetchInputs(txdb, mapTestPoolTmp, false, true, mapInputs, fInvalid))
                  continue;
  
              // Added
              pblock->vtx.push_back(tx);
              nBlockSize += nTxSize;
 +            ++nBlockTx;
              nBlockSigOps += nTxSigOps;
              nFees += nTxFees;
  
                  }
              }
          }
 +
 +        nLastBlockTx = nBlockTx;
 +        nLastBlockSize = nBlockSize;
 +        printf("CreateNewBlock(): total size %lu\n", nBlockSize);
 +
      }
      pblock->vtx[0].vout[0].nValue = GetBlockValue(pindexPrev->nHeight+1, nFees);
  
@@@ -3301,9 -3156,7 +3301,9 @@@ void IncrementExtraNonce(CBlock* pblock
          hashPrevBlock = pblock->hashPrevBlock;
      }
      ++nExtraNonce;
 -    pblock->vtx[0].vin[0].scriptSig = CScript() << pblock->nTime << CBigNum(nExtraNonce);
 +    pblock->vtx[0].vin[0].scriptSig = (CScript() << pblock->nTime << CBigNum(nExtraNonce)) + COINBASE_FLAGS;
 +    assert(pblock->vtx[0].vin[0].scriptSig.size() <= 100);
 +
      pblock->hashMerkleRoot = pblock->BuildMerkleTree();
  }
  
@@@ -3392,10 -3245,6 +3392,10 @@@ bool CheckWork(CBlock* pblock, CWallet
  
  void static ThreadBitcoinMiner(void* parg);
  
 +static bool fGenerateBitcoins = false;
 +static bool fLimitProcessors = false;
 +static int nLimitProcessors = -1;
 +
  void static BitcoinMiner(CWallet *pwallet)
  {
      printf("BitcoinMiner started\n");
                          {
                              nLogTime = GetTime();
                              printf("%s ", DateTimeStrFormat("%x %H:%M", GetTime()).c_str());
 -                            printf("hashmeter %3d CPUs %6.0f khash/s\n", vnThreadsRunning[3], dHashesPerSec/1000.0);
 +                            printf("hashmeter %3d CPUs %6.0f khash/s\n", vnThreadsRunning[THREAD_MINER], dHashesPerSec/1000.0);
                          }
                      }
                  }
                  return;
              if (!fGenerateBitcoins)
                  return;
 -            if (fLimitProcessors && vnThreadsRunning[3] > nLimitProcessors)
 +            if (fLimitProcessors && vnThreadsRunning[THREAD_MINER] > nLimitProcessors)
                  return;
              if (vNodes.empty())
                  break;
@@@ -3550,34 -3399,34 +3550,34 @@@ void static ThreadBitcoinMiner(void* pa
      CWallet* pwallet = (CWallet*)parg;
      try
      {
 -        vnThreadsRunning[3]++;
 +        vnThreadsRunning[THREAD_MINER]++;
          BitcoinMiner(pwallet);
 -        vnThreadsRunning[3]--;
 +        vnThreadsRunning[THREAD_MINER]--;
      }
      catch (std::exception& e) {
 -        vnThreadsRunning[3]--;
 +        vnThreadsRunning[THREAD_MINER]--;
          PrintException(&e, "ThreadBitcoinMiner()");
      } catch (...) {
 -        vnThreadsRunning[3]--;
 +        vnThreadsRunning[THREAD_MINER]--;
          PrintException(NULL, "ThreadBitcoinMiner()");
      }
      UIThreadCall(boost::bind(CalledSetStatusBar, "", 0));
      nHPSTimerStart = 0;
 -    if (vnThreadsRunning[3] == 0)
 +    if (vnThreadsRunning[THREAD_MINER] == 0)
          dHashesPerSec = 0;
 -    printf("ThreadBitcoinMiner exiting, %d threads remaining\n", vnThreadsRunning[3]);
 +    printf("ThreadBitcoinMiner exiting, %d threads remaining\n", vnThreadsRunning[THREAD_MINER]);
  }
  
  
  void GenerateBitcoins(bool fGenerate, CWallet* pwallet)
  {
 -    if (fGenerateBitcoins != fGenerate)
 -    {
 -        fGenerateBitcoins = fGenerate;
 -        WriteSetting("fGenerateBitcoins", fGenerateBitcoins);
 -        MainFrameRepaint();
 -    }
 -    if (fGenerateBitcoins)
 +    fGenerateBitcoins = fGenerate;
 +    nLimitProcessors = GetArg("-genproclimit", -1);
 +    if (nLimitProcessors == 0)
 +        fGenerateBitcoins = false;
 +    fLimitProcessors = (nLimitProcessors != -1);
 +
 +    if (fGenerate)
      {
          int nProcessors = boost::thread::hardware_concurrency();
          printf("%d processors\n", nProcessors);
              nProcessors = 1;
          if (fLimitProcessors && nProcessors > nLimitProcessors)
              nProcessors = nLimitProcessors;
 -        int nAddThreads = nProcessors - vnThreadsRunning[3];
 +        int nAddThreads = nProcessors - vnThreadsRunning[THREAD_MINER];
          printf("Starting %d BitcoinMiner threads\n", nAddThreads);
          for (int i = 0; i < nAddThreads; i++)
          {
diff --combined src/net.cpp
@@@ -9,7 -9,6 +9,7 @@@
  #include "net.h"
  #include "init.h"
  #include "strlcpy.h"
 +#include "addrman.h"
  
  #ifdef WIN32
  #include <string.h>
@@@ -32,7 -31,6 +32,7 @@@ static const int MAX_OUTBOUND_CONNECTIO
  void ThreadMessageHandler2(void* parg);
  void ThreadSocketHandler2(void* parg);
  void ThreadOpenConnections2(void* parg);
 +void ThreadOpenAddedConnections2(void* parg);
  #ifdef USE_UPNP
  void ThreadMapPort2(void* parg);
  #endif
@@@ -41,30 -39,34 +41,30 @@@ bool OpenNetworkConnection(const CAddre
  
  
  
 -
 -
  //
  // Global state variables
  //
  bool fClient = false;
  bool fAllowDNS = false;
 +static bool fUseUPnP = false;
  uint64 nLocalServices = (fClient ? 0 : NODE_NETWORK);
 -CAddress addrLocalHost("0.0.0.0", 0, false, nLocalServices);
 +CAddress addrLocalHost(CService("0.0.0.0", 0), nLocalServices);
  static CNode* pnodeLocalHost = NULL;
  uint64 nLocalHostNonce = 0;
 -array<int, 10> vnThreadsRunning;
 +array<int, THREAD_MAX> vnThreadsRunning;
  static SOCKET hListenSocket = INVALID_SOCKET;
 +CAddrMan addrman;
  
  vector<CNode*> vNodes;
  CCriticalSection cs_vNodes;
 -map<vector<unsigned char>, CAddress> mapAddresses;
 -CCriticalSection cs_mapAddresses;
  map<CInv, CDataStream> mapRelay;
  deque<pair<int64, CInv> > vRelayExpiration;
  CCriticalSection cs_mapRelay;
  map<CInv, int64> mapAlreadyAskedFor;
  
 -// Settings
 -int fUseProxy = false;
 -int nConnectTimeout = 5000;
 -CAddress addrProxy("127.0.0.1",9050);
  
 +set<CNetAddr> setservAddNodeAddresses;
 +CCriticalSection cs_setservAddNodeAddresses;
  
  
  
@@@ -86,60 -88,215 +86,60 @@@ void CNode::PushGetBlocks(CBlockIndex* 
  
  
  
 -
 -
 -bool ConnectSocket(const CAddress& addrConnect, SOCKET& hSocketRet, int nTimeout)
 +bool RecvLine(SOCKET hSocket, string& strLine)
  {
 -    hSocketRet = INVALID_SOCKET;
 -
 -    SOCKET hSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
 -    if (hSocket == INVALID_SOCKET)
 -        return false;
 -#ifdef SO_NOSIGPIPE
 -    int set = 1;
 -    setsockopt(hSocket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&set, sizeof(int));
 -#endif
 -
 -    bool fProxy = (fUseProxy && addrConnect.IsRoutable());
 -    struct sockaddr_in sockaddr = (fProxy ? addrProxy.GetSockAddr() : addrConnect.GetSockAddr());
 -
 -#ifdef WIN32
 -    u_long fNonblock = 1;
 -    if (ioctlsocket(hSocket, FIONBIO, &fNonblock) == SOCKET_ERROR)
 -#else
 -    int fFlags = fcntl(hSocket, F_GETFL, 0);
 -    if (fcntl(hSocket, F_SETFL, fFlags | O_NONBLOCK) == -1)
 -#endif
 -    {
 -        closesocket(hSocket);
 -        return false;
 -    }
 -
 -
 -    if (connect(hSocket, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) == SOCKET_ERROR)
 +    strLine = "";
 +    loop
      {
 -        // WSAEINVAL is here because some legacy version of winsock uses it
 -        if (WSAGetLastError() == WSAEINPROGRESS || WSAGetLastError() == WSAEWOULDBLOCK || WSAGetLastError() == WSAEINVAL)
 +        char c;
 +        int nBytes = recv(hSocket, &c, 1, 0);
 +        if (nBytes > 0)
          {
 -            struct timeval timeout;
 -            timeout.tv_sec  = nTimeout / 1000;
 -            timeout.tv_usec = (nTimeout % 1000) * 1000;
 -
 -            fd_set fdset;
 -            FD_ZERO(&fdset);
 -            FD_SET(hSocket, &fdset);
 -            int nRet = select(hSocket + 1, NULL, &fdset, NULL, &timeout);
 -            if (nRet == 0)
 -            {
 -                printf("connection timeout\n");
 -                closesocket(hSocket);
 +            if (c == '\n')
 +                continue;
 +            if (c == '\r')
 +                return true;
 +            strLine += c;
 +            if (strLine.size() >= 9000)
 +                return true;
 +        }
 +        else if (nBytes <= 0)
 +        {
 +            if (fShutdown)
                  return false;
 -            }
 -            if (nRet == SOCKET_ERROR)
 +            if (nBytes < 0)
              {
 -                printf("select() for connection failed: %i\n",WSAGetLastError());
 -                closesocket(hSocket);
 -                return false;
 +                int nErr = WSAGetLastError();
 +                if (nErr == WSAEMSGSIZE)
 +                    continue;
 +                if (nErr == WSAEWOULDBLOCK || nErr == WSAEINTR || nErr == WSAEINPROGRESS)
 +                {
 +                    Sleep(10);
 +                    continue;
 +                }
              }
 -            socklen_t nRetSize = sizeof(nRet);
 -#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)
 -#endif
 +            if (!strLine.empty())
 +                return true;
 +            if (nBytes == 0)
              {
 -                printf("getsockopt() for connection failed: %i\n",WSAGetLastError());
 -                closesocket(hSocket);
 +                // socket closed
 +                printf("socket closed\n");
                  return false;
              }
 -            if (nRet != 0)
 +            else
              {
 -                printf("connect() failed after select(): %s\n",strerror(nRet));
 -                closesocket(hSocket);
 +                // socket error
 +                int nErr = WSAGetLastError();
 +                printf("recv failed: %d\n", nErr);
                  return false;
              }
          }
 -#ifdef WIN32
 -        else if (WSAGetLastError() != WSAEISCONN)
 -#else
 -        else
 -#endif
 -        {
 -            printf("connect() failed: %i\n",WSAGetLastError());
 -            closesocket(hSocket);
 -            return false;
 -        }
 -    }
 -
 -    /*
 -    this isn't even strictly necessary
 -    CNode::ConnectNode immediately turns the socket back to non-blocking
 -    but we'll turn it back to blocking just in case
 -    */
 -#ifdef WIN32
 -    fNonblock = 0;
 -    if (ioctlsocket(hSocket, FIONBIO, &fNonblock) == SOCKET_ERROR)
 -#else
 -    fFlags = fcntl(hSocket, F_GETFL, 0);
 -    if (fcntl(hSocket, F_SETFL, fFlags & !O_NONBLOCK) == SOCKET_ERROR)
 -#endif
 -    {
 -        closesocket(hSocket);
 -        return false;
      }
 -
 -    if (fProxy)
 -    {
 -        printf("proxy connecting %s\n", addrConnect.ToString().c_str());
 -        char pszSocks4IP[] = "\4\1\0\0\0\0\0\0user";
 -        memcpy(pszSocks4IP + 2, &addrConnect.port, 2);
 -        memcpy(pszSocks4IP + 4, &addrConnect.ip, 4);
 -        char* pszSocks4 = pszSocks4IP;
 -        int nSize = sizeof(pszSocks4IP);
 -
 -        int ret = send(hSocket, pszSocks4, nSize, MSG_NOSIGNAL);
 -        if (ret != nSize)
 -        {
 -            closesocket(hSocket);
 -            return error("Error sending to proxy");
 -        }
 -        char pchRet[8];
 -        if (recv(hSocket, pchRet, 8, 0) != 8)
 -        {
 -            closesocket(hSocket);
 -            return error("Error reading proxy response");
 -        }
 -        if (pchRet[1] != 0x5a)
 -        {
 -            closesocket(hSocket);
 -            if (pchRet[1] != 0x5b)
 -                printf("ERROR: Proxy returned error %d\n", pchRet[1]);
 -            return false;
 -        }
 -        printf("proxy connected %s\n", addrConnect.ToString().c_str());
 -    }
 -
 -    hSocketRet = hSocket;
 -    return true;
  }
  
 -// portDefault is in host order
 -bool Lookup(const char *pszName, vector<CAddress>& vaddr, int nServices, int nMaxSolutions, bool fAllowLookup, int portDefault, bool fAllowPort)
 -{
 -    vaddr.clear();
 -    if (pszName[0] == 0)
 -        return false;
 -    int port = portDefault;
 -    char psz[256];
 -    char *pszHost = psz;
 -    strlcpy(psz, pszName, sizeof(psz));
 -    if (fAllowPort)
 -    {
 -        char* pszColon = strrchr(psz+1,':');
 -        char *pszPortEnd = NULL;
 -        int portParsed = pszColon ? strtoul(pszColon+1, &pszPortEnd, 10) : 0;
 -        if (pszColon && pszPortEnd && pszPortEnd[0] == 0)
 -        {
 -            if (psz[0] == '[' && pszColon[-1] == ']')
 -            {
 -                // Future: enable IPv6 colon-notation inside []
 -                pszHost = psz+1;
 -                pszColon[-1] = 0;
 -            }
 -            else
 -                pszColon[0] = 0;
 -            port = portParsed;
 -            if (port < 0 || port > USHRT_MAX)
 -                port = USHRT_MAX;
 -        }
 -    }
 -
 -    unsigned int addrIP = inet_addr(pszHost);
 -    if (addrIP != INADDR_NONE)
 -    {
 -        // valid IP address passed
 -        vaddr.push_back(CAddress(addrIP, port, nServices));
 -        return true;
 -    }
 -
 -    if (!fAllowLookup)
 -        return false;
 -
 -    struct hostent* phostent = gethostbyname(pszHost);
 -    if (!phostent)
 -        return false;
 -
 -    if (phostent->h_addrtype != AF_INET)
 -        return false;
 -
 -    char** ppAddr = phostent->h_addr_list;
 -    while (*ppAddr != NULL && vaddr.size() != nMaxSolutions)
 -    {
 -        CAddress addr(((struct in_addr*)ppAddr[0])->s_addr, port, nServices);
 -        if (addr.IsValid())
 -            vaddr.push_back(addr);
 -        ppAddr++;
 -    }
  
 -    return (vaddr.size() > 0);
 -}
  
 -// portDefault is in host order
 -bool Lookup(const char *pszName, CAddress& addr, int nServices, bool fAllowLookup, int portDefault, bool fAllowPort)
 -{
 -    vector<CAddress> vaddr;
 -    bool fRet = Lookup(pszName, vaddr, nServices, 1, fAllowLookup, portDefault, fAllowPort);
 -    if (fRet)
 -        addr = vaddr[0];
 -    return fRet;
 -}
 -
 -bool GetMyExternalIP2(const CAddress& addrConnect, const char* pszGet, const char* pszKeyword, unsigned int& ipRet)
 +bool GetMyExternalIP2(const CService& addrConnect, const char* pszGet, const char* pszKeyword, CNetAddr& ipRet)
  {
      SOCKET hSocket;
      if (!ConnectSocket(addrConnect, hSocket))
              strLine = strLine.substr(strspn(strLine.c_str(), " \t\n\r"));
              while (strLine.size() > 0 && isspace(strLine[strLine.size()-1]))
                  strLine.resize(strLine.size()-1);
 -            CAddress addr(strLine,0,true);
 +            CService addr(strLine,0,true);
              printf("GetMyExternalIP() received [%s] %s\n", strLine.c_str(), addr.ToString().c_str());
 -            if (addr.ip == 0 || addr.ip == INADDR_NONE || !addr.IsRoutable())
 +            if (!addr.IsValid() || !addr.IsRoutable())
                  return false;
 -            ipRet = addr.ip;
 +            ipRet.SetIP(addr);
              return true;
          }
      }
  }
  
  // We now get our external IP from the IRC server first and only use this as a backup
 -bool GetMyExternalIP(unsigned int& ipRet)
 +bool GetMyExternalIP(CNetAddr& ipRet)
  {
 -    CAddress addrConnect;
 +    CService addrConnect;
      const char* pszGet;
      const char* pszKeyword;
  
 -    if (fUseProxy)
 +    if (fNoListen||fUseProxy)
          return false;
  
      for (int nLookup = 0; nLookup <= 1; nLookup++)
          //  <?php echo $_SERVER["REMOTE_ADDR"]; ?>
          if (nHost == 1)
          {
 -            addrConnect = CAddress("91.198.22.70",80); // checkip.dyndns.org
 +            addrConnect = CService("91.198.22.70",80); // checkip.dyndns.org
  
              if (nLookup == 1)
              {
 -                CAddress addrIP("checkip.dyndns.org", 80, true);
 +                CService addrIP("checkip.dyndns.org", 80, true);
                  if (addrIP.IsValid())
                      addrConnect = addrIP;
              }
          }
          else if (nHost == 2)
          {
 -            addrConnect = CAddress("74.208.43.192", 80); // www.showmyip.com
 +            addrConnect = CService("74.208.43.192", 80); // www.showmyip.com
  
              if (nLookup == 1)
              {
 -                CAddress addrIP("www.showmyip.com", 80, true);
 +                CService addrIP("www.showmyip.com", 80, true);
                  if (addrIP.IsValid())
                      addrConnect = addrIP;
              }
  void ThreadGetMyExternalIP(void* parg)
  {
      // Wait for IRC to get it first
 -    if (!GetBoolArg("-noirc"))
 +    if (GetBoolArg("-irc", false))
      {
          for (int i = 0; i < 2 * 60; i++)
          {
      }
  
      // Fallback in case IRC fails to get it
 -    if (GetMyExternalIP(addrLocalHost.ip))
 +    if (GetMyExternalIP(addrLocalHost))
      {
          printf("GetMyExternalIP() returned %s\n", addrLocalHost.ToStringIP().c_str());
          if (addrLocalHost.IsRoutable())
  
  
  
 -bool AddAddress(CAddress addr, int64 nTimePenalty, CAddrDB *pAddrDB)
 +void AddressCurrentlyConnected(const CService& addr)
  {
 -    if (!addr.IsRoutable())
 -        return false;
 -    if (addr.ip == addrLocalHost.ip)
 -        return false;
 -    addr.nTime = max((int64)0, (int64)addr.nTime - nTimePenalty);
 -    bool fUpdated = false;
 -    bool fNew = false;
 -    CAddress addrFound = addr;
 -
 -    CRITICAL_BLOCK(cs_mapAddresses)
 -    {
 -        map<vector<unsigned char>, CAddress>::iterator it = mapAddresses.find(addr.GetKey());
 -        if (it == mapAddresses.end())
 -        {
 -            // New address
 -            printf("AddAddress(%s)\n", addr.ToString().c_str());
 -            mapAddresses.insert(make_pair(addr.GetKey(), addr));
 -            fUpdated = true;
 -            fNew = true;
 -        }
 -        else
 -        {
 -            addrFound = (*it).second;
 -            if ((addrFound.nServices | addr.nServices) != addrFound.nServices)
 -            {
 -                // Services have been added
 -                addrFound.nServices |= addr.nServices;
 -                fUpdated = true;
 -            }
 -            bool fCurrentlyOnline = (GetAdjustedTime() - addr.nTime < 24 * 60 * 60);
 -            int64 nUpdateInterval = (fCurrentlyOnline ? 60 * 60 : 24 * 60 * 60);
 -            if (addrFound.nTime < addr.nTime - nUpdateInterval)
 -            {
 -                // Periodically update most recently seen time
 -                addrFound.nTime = addr.nTime;
 -                fUpdated = true;
 -            }
 -        }
 -    }
 -    // There is a nasty deadlock bug if this is done inside the cs_mapAddresses
 -    // CRITICAL_BLOCK:
 -    // Thread 1:  begin db transaction (locks inside-db-mutex)
 -    //            then AddAddress (locks cs_mapAddresses)
 -    // Thread 2:  AddAddress (locks cs_mapAddresses)
 -    //             ... then db operation hangs waiting for inside-db-mutex
 -    if (fUpdated)
 -    {
 -        if (pAddrDB)
 -            pAddrDB->WriteAddress(addrFound);
 -        else
 -            CAddrDB().WriteAddress(addrFound);
 -    }
 -    return fNew;
 -}
 -
 -void AddressCurrentlyConnected(const CAddress& addr)
 -{
 -    CAddress *paddrFound = NULL;
 -
 -    CRITICAL_BLOCK(cs_mapAddresses)
 -    {
 -        // Only if it's been published already
 -        map<vector<unsigned char>, CAddress>::iterator it = mapAddresses.find(addr.GetKey());
 -        if (it != mapAddresses.end())
 -            paddrFound = &(*it).second;
 -    }
 -
 -    if (paddrFound)
 -    {
 -        int64 nUpdateInterval = 20 * 60;
 -        if (paddrFound->nTime < GetAdjustedTime() - nUpdateInterval)
 -        {
 -            // Periodically update most recently seen time
 -            paddrFound->nTime = GetAdjustedTime();
 -            CAddrDB addrdb;
 -            addrdb.WriteAddress(*paddrFound);
 -        }
 -    }
 +    addrman.Connected(addr);
  }
  
  
@@@ -392,23 -626,23 +392,23 @@@ void CNode::CancelSubscribe(unsigned in
  
  
  
 -CNode* FindNode(unsigned int ip)
 +CNode* FindNode(const CNetAddr& ip)
  {
      CRITICAL_BLOCK(cs_vNodes)
      {
          BOOST_FOREACH(CNode* pnode, vNodes)
 -            if (pnode->addr.ip == ip)
 +            if ((CNetAddr)pnode->addr == ip)
                  return (pnode);
      }
      return NULL;
  }
  
 -CNode* FindNode(CAddress addr)
 +CNode* FindNode(const CService& addr)
  {
      CRITICAL_BLOCK(cs_vNodes)
      {
          BOOST_FOREACH(CNode* pnode, vNodes)
 -            if (pnode->addr == addr)
 +            if ((CService)pnode->addr == addr)
                  return (pnode);
      }
      return NULL;
  
  CNode* ConnectNode(CAddress addrConnect, int64 nTimeout)
  {
 -    if (addrConnect.ip == addrLocalHost.ip)
 +    if ((CNetAddr)addrConnect == (CNetAddr)addrLocalHost)
          return NULL;
  
      // Look for an existing connection
 -    CNode* pnode = FindNode(addrConnect.ip);
 +    CNode* pnode = FindNode((CService)addrConnect);
      if (pnode)
      {
          if (nTimeout != 0)
      }
  
      /// debug print
 -    printf("trying connection %s lastseen=%.1fhrs lasttry=%.1fhrs\n",
 +    printf("trying connection %s lastseen=%.1fhrs\n",
          addrConnect.ToString().c_str(),
 -        (double)(addrConnect.nTime - GetAdjustedTime())/3600.0,
 -        (double)(addrConnect.nLastTry - GetAdjustedTime())/3600.0);
 +        (double)(addrConnect.nTime - GetAdjustedTime())/3600.0);
  
 -    CRITICAL_BLOCK(cs_mapAddresses)
 -        mapAddresses[addrConnect.GetKey()].nLastTry = GetAdjustedTime();
 +    addrman.Attempt(addrConnect);
  
      // Connect
      SOCKET hSocket;
@@@ -498,22 -734,7 +498,22 @@@ void CNode::Cleanup(
  }
  
  
 -std::map<unsigned int, int64> CNode::setBanned;
 +void CNode::PushVersion()
 +{
 +    /// when NTP implemented, change to just nTime = GetAdjustedTime()
 +    int64 nTime = (fInbound ? GetAdjustedTime() : GetTime());
 +    CAddress addrYou = (fUseProxy ? CAddress(CService("0.0.0.0",0)) : addr);
 +    CAddress addrMe = (fUseProxy || !addrLocalHost.IsRoutable() ? CAddress(CService("0.0.0.0",0)) : addrLocalHost);
 +    RAND_bytes((unsigned char*)&nLocalHostNonce, sizeof(nLocalHostNonce));
 +    PushMessage("version", PROTOCOL_VERSION, nLocalServices, nTime, addrYou, addrMe,
 +                nLocalHostNonce, FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, std::vector<string>()), nBestHeight);
 +}
 +
 +
 +
 +
 +
 +std::map<CNetAddr, int64> CNode::setBanned;
  CCriticalSection CNode::cs_setBanned;
  
  void CNode::ClearBanned()
      setBanned.clear();
  }
  
 -bool CNode::IsBanned(unsigned int ip)
 +bool CNode::IsBanned(CNetAddr ip)
  {
      bool fResult = false;
      CRITICAL_BLOCK(cs_setBanned)
      {
 -        std::map<unsigned int, int64>::iterator i = setBanned.find(ip);
 +        std::map<CNetAddr, int64>::iterator i = setBanned.find(ip);
          if (i != setBanned.end())
          {
              int64 t = (*i).second;
@@@ -550,8 -771,8 +550,8 @@@ bool CNode::Misbehaving(int howmuch
      {
          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;
 +            if (setBanned[addr] < banTime)
 +                setBanned[addr] = banTime;
          CloseSocketDisconnect();
          printf("Disconnected %s for misbehavior (score=%d)\n", addr.ToString().c_str(), nMisbehavior);
          return true;
@@@ -575,15 -796,15 +575,15 @@@ void ThreadSocketHandler(void* parg
      IMPLEMENT_RANDOMIZE_STACK(ThreadSocketHandler(parg));
      try
      {
 -        vnThreadsRunning[0]++;
 +        vnThreadsRunning[THREAD_SOCKETHANDLER]++;
          ThreadSocketHandler2(parg);
 -        vnThreadsRunning[0]--;
 +        vnThreadsRunning[THREAD_SOCKETHANDLER]--;
      }
      catch (std::exception& e) {
 -        vnThreadsRunning[0]--;
 +        vnThreadsRunning[THREAD_SOCKETHANDLER]--;
          PrintException(&e, "ThreadSocketHandler()");
      } catch (...) {
 -        vnThreadsRunning[0]--;
 +        vnThreadsRunning[THREAD_SOCKETHANDLER]--;
          throw; // support pthread_cancel()
      }
      printf("ThreadSocketHandler exiting\n");
@@@ -685,15 -906,15 +685,15 @@@ void ThreadSocketHandler2(void* parg
              }
          }
  
 -        vnThreadsRunning[0]--;
 +        vnThreadsRunning[THREAD_SOCKETHANDLER]--;
          int nSelect = select(hSocketMax + 1, &fdsetRecv, &fdsetSend, &fdsetError, &timeout);
 -        vnThreadsRunning[0]++;
 +        vnThreadsRunning[THREAD_SOCKETHANDLER]++;
          if (fShutdown)
              return;
          if (nSelect == SOCKET_ERROR)
          {
              int nErr = WSAGetLastError();
-             if (hSocketMax > -1)
+             if (hSocketMax != INVALID_SOCKET)
              {
                  printf("socket select error %d\n", nErr);
                  for (unsigned int i = 0; i <= hSocketMax; i++)
              }
              else if (nInbound >= GetArg("-maxconnections", 125) - MAX_OUTBOUND_CONNECTIONS)
              {
 -                closesocket(hSocket);
 +                CRITICAL_BLOCK(cs_setservAddNodeAddresses)
 +                    if (!setservAddNodeAddresses.count(addr))
 +                        closesocket(hSocket);
              }
 -            else if (CNode::IsBanned(addr.ip))
 +            else if (CNode::IsBanned(addr))
              {
                  printf("connection from %s dropped (banned)\n", addr.ToString().c_str());
                  closesocket(hSocket);
@@@ -900,15 -1119,15 +900,15 @@@ void ThreadMapPort(void* parg
      IMPLEMENT_RANDOMIZE_STACK(ThreadMapPort(parg));
      try
      {
 -        vnThreadsRunning[5]++;
 +        vnThreadsRunning[THREAD_UPNP]++;
          ThreadMapPort2(parg);
 -        vnThreadsRunning[5]--;
 +        vnThreadsRunning[THREAD_UPNP]--;
      }
      catch (std::exception& e) {
 -        vnThreadsRunning[5]--;
 +        vnThreadsRunning[THREAD_UPNP]--;
          PrintException(&e, "ThreadMapPort()");
      } catch (...) {
 -        vnThreadsRunning[5]--;
 +        vnThreadsRunning[THREAD_UPNP]--;
          PrintException(NULL, "ThreadMapPort()");
      }
      printf("ThreadMapPort exiting\n");
@@@ -953,7 -1172,7 +953,7 @@@ void ThreadMapPort2(void* parg
                  if(externalIPAddress[0])
                  {
                      printf("UPnP: ExternalIPAddress = %s\n", externalIPAddress);
 -                    CAddress addrExternalFromUPnP(externalIPAddress, 0, false, nLocalServices);
 +                    CAddress addrExternalFromUPnP(CService(externalIPAddress, 0), nLocalServices);
                      if (addrExternalFromUPnP.IsRoutable())
                          addrLocalHost = addrExternalFromUPnP;
                  }
@@@ -1027,8 -1246,9 +1027,8 @@@ void MapPort(bool fMapPort
      if (fUseUPnP != fMapPort)
      {
          fUseUPnP = fMapPort;
 -        WriteSetting("fUseUPnP", fUseUPnP);
      }
 -    if (fUseUPnP && vnThreadsRunning[5] < 1)
 +    if (fUseUPnP && vnThreadsRunning[THREAD_UPNP] < 1)
      {
          if (!CreateThread(ThreadMapPort, NULL))
              printf("Error: ThreadMapPort(ThreadMapPort) failed\n");
@@@ -1049,15 -1269,12 +1049,15 @@@ void MapPort(bool /* unused fMapPort */
  
  
  
 -
 -static const char *strDNSSeed[] = {
 -    "bitseed.xf2.org",
 -    "dnsseed.bluematt.me",
 -    "seed.bitcoin.sipa.be",
 -    "dnsseed.bitcoin.dashjr.org",
 +// DNS seeds
 +// Each pair gives a source name and a seed name.
 +// The first name is used as information source for addrman.
 +// The second name should resolve to a list of seed addresses.
 +static const char *strDNSSeed[][2] = {
 +    {"xf2.org", "bitseed.xf2.org"},
 +    {"bluematt.me", "dnsseed.bluematt.me"},
 +    {"bitcoin.sipa.be", "seed.bitcoin.sipa.be"},
 +    {"dashjr.org", "dnsseed.bitcoin.dashjr.org"},
  };
  
  void ThreadDNSAddressSeed(void* parg)
      IMPLEMENT_RANDOMIZE_STACK(ThreadDNSAddressSeed(parg));
      try
      {
 -        vnThreadsRunning[6]++;
 +        vnThreadsRunning[THREAD_DNSSEED]++;
          ThreadDNSAddressSeed2(parg);
 -        vnThreadsRunning[6]--;
 +        vnThreadsRunning[THREAD_DNSSEED]--;
      }
      catch (std::exception& e) {
 -        vnThreadsRunning[6]--;
 +        vnThreadsRunning[THREAD_DNSSEED]--;
          PrintException(&e, "ThreadDNSAddressSeed()");
      } catch (...) {
 -        vnThreadsRunning[6]--;
 +        vnThreadsRunning[THREAD_DNSSEED]--;
          throw; // support pthread_cancel()
      }
      printf("ThreadDNSAddressSeed exiting\n");
@@@ -1089,20 -1306,22 +1089,20 @@@ void ThreadDNSAddressSeed2(void* parg
          printf("Loading addresses from DNS seeds (could take a while)\n");
  
          for (unsigned int seed_idx = 0; seed_idx < ARRAYLEN(strDNSSeed); seed_idx++) {
 -            vector<CAddress> vaddr;
 -            if (Lookup(strDNSSeed[seed_idx], vaddr, NODE_NETWORK, -1, true))
 +            vector<CNetAddr> vaddr;
 +            vector<CAddress> vAdd;
 +            if (LookupHost(strDNSSeed[seed_idx][1], vaddr))
              {
 -                CAddrDB addrDB;
 -                addrDB.TxnBegin();
 -                BOOST_FOREACH (CAddress& addr, vaddr)
 +                BOOST_FOREACH(CNetAddr& ip, vaddr)
                  {
 -                    if (addr.GetByte(3) != 127)
 -                    {
 -                        addr.nTime = 0;
 -                        AddAddress(addr, 0, &addrDB);
 -                        found++;
 -                    }
 +                    int nOneDay = 24*3600;
 +                    CAddress addr = CAddress(CService(ip, GetDefaultPort()));
 +                    addr.nTime = GetTime() - 3*nOneDay - GetRand(4*nOneDay); // use a random age between 3 and 7 days old
 +                    vAdd.push_back(addr);
 +                    found++;
                  }
 -                addrDB.TxnCommit();  // Save addresses (it's ok if this fails)
              }
 +            addrman.Add(vAdd, CNetAddr(strDNSSeed[seed_idx][0], true));
          }
      }
  
@@@ -1201,52 -1420,22 +1201,52 @@@ unsigned int pnSeed[] 
      0xc461d84a, 0xb2dbe247,
  };
  
 +void DumpAddresses()
 +{
 +    CAddrDB adb;
 +    adb.WriteAddrman(addrman);
 +}
 +
 +void ThreadDumpAddress2(void* parg)
 +{
 +    vnThreadsRunning[THREAD_DUMPADDRESS]++;
 +    while (!fShutdown)
 +    {
 +        DumpAddresses();
 +        vnThreadsRunning[THREAD_DUMPADDRESS]--;
 +        Sleep(100000);
 +        vnThreadsRunning[THREAD_DUMPADDRESS]++;
 +    }
 +    vnThreadsRunning[THREAD_DUMPADDRESS]--;
 +}
  
 +void ThreadDumpAddress(void* parg)
 +{
 +    IMPLEMENT_RANDOMIZE_STACK(ThreadDumpAddress(parg));
 +    try
 +    {
 +        ThreadDumpAddress2(parg);
 +    }
 +    catch (std::exception& e) {
 +        PrintException(&e, "ThreadDumpAddress()");
 +    }
 +    printf("ThreadDumpAddress exiting\n");
 +}
  
  void ThreadOpenConnections(void* parg)
  {
      IMPLEMENT_RANDOMIZE_STACK(ThreadOpenConnections(parg));
      try
      {
 -        vnThreadsRunning[1]++;
 +        vnThreadsRunning[THREAD_OPENCONNECTIONS]++;
          ThreadOpenConnections2(parg);
 -        vnThreadsRunning[1]--;
 +        vnThreadsRunning[THREAD_OPENCONNECTIONS]--;
      }
      catch (std::exception& e) {
 -        vnThreadsRunning[1]--;
 +        vnThreadsRunning[THREAD_OPENCONNECTIONS]--;
          PrintException(&e, "ThreadOpenConnections()");
      } catch (...) {
 -        vnThreadsRunning[1]--;
 +        vnThreadsRunning[THREAD_OPENCONNECTIONS]--;
          PrintException(NULL, "ThreadOpenConnections()");
      }
      printf("ThreadOpenConnections exiting\n");
@@@ -1263,7 -1452,7 +1263,7 @@@ void ThreadOpenConnections2(void* parg
          {
              BOOST_FOREACH(string strAddr, mapMultiArgs["-connect"])
              {
 -                CAddress addr(strAddr, fAllowDNS);
 +                CAddress addr(CService(strAddr, GetDefaultPort(), fAllowDNS));
                  if (addr.IsValid())
                      OpenNetworkConnection(addr);
                  for (int i = 0; i < 10 && i < nLoop; i++)
          }
      }
  
 -    // Connect to manually added nodes first
 -    if (mapArgs.count("-addnode"))
 -    {
 -        BOOST_FOREACH(string strAddr, mapMultiArgs["-addnode"])
 -        {
 -            CAddress addr(strAddr, fAllowDNS);
 -            if (addr.IsValid())
 -            {
 -                OpenNetworkConnection(addr);
 -                Sleep(500);
 -                if (fShutdown)
 -                    return;
 -            }
 -        }
 -    }
 -
      // Initiate network connections
      int64 nStart = GetTime();
      loop
      {
 -        vnThreadsRunning[1]--;
 +        int nOutbound = 0;
 +
 +        vnThreadsRunning[THREAD_OPENCONNECTIONS]--;
          Sleep(500);
 -        vnThreadsRunning[1]++;
 +        vnThreadsRunning[THREAD_OPENCONNECTIONS]++;
          if (fShutdown)
              return;
  
          // Limit outbound connections
          loop
          {
 -            int nOutbound = 0;
 +            nOutbound = 0;
              CRITICAL_BLOCK(cs_vNodes)
                  BOOST_FOREACH(CNode* pnode, vNodes)
                      if (!pnode->fInbound)
              nMaxOutboundConnections = min(nMaxOutboundConnections, (int)GetArg("-maxconnections", 125));
              if (nOutbound < nMaxOutboundConnections)
                  break;
 -            vnThreadsRunning[1]--;
 +            vnThreadsRunning[THREAD_OPENCONNECTIONS]--;
              Sleep(2000);
 -            vnThreadsRunning[1]++;
 +            vnThreadsRunning[THREAD_OPENCONNECTIONS]++;
              if (fShutdown)
                  return;
          }
  
 -        bool fAddSeeds = false;
 -
 -        CRITICAL_BLOCK(cs_mapAddresses)
 -        {
 -            // Add seed nodes if IRC isn't working
 -            bool fTOR = (fUseProxy && addrProxy.port == htons(9050));
 -            if (mapAddresses.empty() && (GetTime() - nStart > 60 || fUseProxy) && !fTestNet)
 -                fAddSeeds = true;
 -        }
 -
 -        if (fAddSeeds)
 +        // Add seed nodes if IRC isn't working
 +        bool fTOR = (fUseProxy && addrProxy.GetPort() == 9050);
 +        if (addrman.size()==0 && (GetTime() - nStart > 60 || fTOR) && !fTestNet)
          {
 +            std::vector<CAddress> vAdd;
              for (unsigned int i = 0; i < ARRAYLEN(pnSeed); i++)
              {
                  // It'll only connect to one or two seed nodes because once it connects,
                  // Seed nodes are given a random 'last seen time' of between one and two
                  // weeks ago.
                  const int64 nOneWeek = 7*24*60*60;
 -                CAddress addr;
 -                addr.ip = pnSeed[i];
 +                struct in_addr ip;
 +                memcpy(&ip, &pnSeed[i], sizeof(ip));
 +                CAddress addr(CService(ip, GetDefaultPort()));
                  addr.nTime = GetTime()-GetRand(nOneWeek)-nOneWeek;
 -                AddAddress(addr);
 +                vAdd.push_back(addr);
              }
 +            addrman.Add(vAdd, CNetAddr("127.0.0.1"));
          }
  
          //
          // Choose an address to connect to based on most recently seen
          //
          CAddress addrConnect;
  
          // Only connect to one address per a.b.?.? range.
          // Do this here so we don't have to critsect vNodes inside mapAddresses critsect.
 -        set<unsigned int> setConnected;
 +        set<vector<unsigned char> > setConnected;
          CRITICAL_BLOCK(cs_vNodes)
              BOOST_FOREACH(CNode* pnode, vNodes)
 -                setConnected.insert(pnode->addr.ip & 0x0000ffff);
 +                setConnected.insert(pnode->addr.GetGroup());
  
          int64 nANow = GetAdjustedTime();
  
 -        CRITICAL_BLOCK(cs_mapAddresses)
 +        int nTries = 0;
 +        loop
          {
 -            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 = 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);
 -                if (addr.port != htons(GetDefaultPort()))
 -                    nRandomizer += 2 * 60 * 60;
 -
 -                // Last seen  Base retry frequency
 -                //   <1 hour   10 min
 -                //    1 hour    1 hour
 -                //    4 hours   2 hours
 -                //   24 hours   5 hours
 -                //   48 hours   7 hours
 -                //    7 days   13 hours
 -                //   30 days   27 hours
 -                //   90 days   46 hours
 -                //  365 days   93 hours
 -                int64 nDelay = (int64)(3600.0 * sqrt(fabs((double)nSinceLastSeen) / 3600.0) + nRandomizer);
 -
 -                // Fast reconnect for one hour after last seen
 -                if (nSinceLastSeen < 60 * 60)
 -                    nDelay = 10 * 60;
 -
 -                // Limit retry frequency
 -                if (nSinceLastTry < nDelay)
 -                    continue;
 +            // use an nUnkBias between 10 (no outgoing connections) and 90 (8 outgoing connections)
 +            CAddress addr = addrman.Select(10 + min(nOutbound,8)*10);
  
 -                // If we have IRC, we'll be notified when they first come online,
 -                // and again every 24 hours by the refresh broadcast.
 -                if (nGotIRCAddresses > 0 && vNodes.size() >= 2 && nSinceLastSeen > 24 * 60 * 60)
 -                    continue;
 +            // if we selected an invalid address, restart
 +            if (!addr.IsIPv4() || !addr.IsValid() || setConnected.count(addr.GetGroup()) || addr == addrLocalHost)
 +                break;
  
 -                // Only try the old stuff if we don't have enough connections
 -                if (vNodes.size() >= 8 && nSinceLastSeen > 24 * 60 * 60)
 -                    continue;
 +            nTries++;
  
 -                // If multiple addresses are ready, prioritize by time since
 -                // last seen and time since last tried.
 -                int64 nScore = min(nSinceLastTry, (int64)24 * 60 * 60) - nSinceLastSeen - nRandomizer;
 -                if (nScore > nBest)
 -                {
 -                    nBest = nScore;
 -                    addrConnect = addr;
 -                }
 -            }
 +            // only consider very recently tried nodes after 30 failed attempts
 +            if (nANow - addr.nLastTry < 600 && nTries < 30)
 +                continue;
 +
 +            // do not allow non-default ports, unless after 50 invalid addresses selected already
 +            if (addr.GetPort() != GetDefaultPort() && nTries < 50)
 +                continue;
 +
 +            addrConnect = addr;
 +            break;
          }
  
          if (addrConnect.IsValid())
      }
  }
  
 +void ThreadOpenAddedConnections(void* parg)
 +{
 +    IMPLEMENT_RANDOMIZE_STACK(ThreadOpenAddedConnections(parg));
 +    try
 +    {
 +        vnThreadsRunning[THREAD_ADDEDCONNECTIONS]++;
 +        ThreadOpenAddedConnections2(parg);
 +        vnThreadsRunning[THREAD_ADDEDCONNECTIONS]--;
 +    }
 +    catch (std::exception& e) {
 +        vnThreadsRunning[THREAD_ADDEDCONNECTIONS]--;
 +        PrintException(&e, "ThreadOpenAddedConnections()");
 +    } catch (...) {
 +        vnThreadsRunning[THREAD_ADDEDCONNECTIONS]--;
 +        PrintException(NULL, "ThreadOpenAddedConnections()");
 +    }
 +    printf("ThreadOpenAddedConnections exiting\n");
 +}
 +
 +void ThreadOpenAddedConnections2(void* parg)
 +{
 +    printf("ThreadOpenAddedConnections started\n");
 +
 +    if (mapArgs.count("-addnode") == 0)
 +        return;
 +
 +    vector<vector<CService> > vservAddressesToAdd(0);
 +    BOOST_FOREACH(string& strAddNode, mapMultiArgs["-addnode"])
 +    {
 +        vector<CService> vservNode(0);
 +        if(Lookup(strAddNode.c_str(), vservNode, GetDefaultPort(), fAllowDNS, 0))
 +        {
 +            vservAddressesToAdd.push_back(vservNode);
 +            CRITICAL_BLOCK(cs_setservAddNodeAddresses)
 +                BOOST_FOREACH(CService& serv, vservNode)
 +                    setservAddNodeAddresses.insert(serv);
 +        }
 +    }
 +    loop
 +    {
 +        vector<vector<CService> > vservConnectAddresses = vservAddressesToAdd;
 +        // Attempt to connect to each IP for each addnode entry until at least one is successful per addnode entry
 +        // (keeping in mind that addnode entries can have many IPs if fAllowDNS)
 +        CRITICAL_BLOCK(cs_vNodes)
 +            BOOST_FOREACH(CNode* pnode, vNodes)
 +                for (vector<vector<CService> >::iterator it = vservConnectAddresses.begin(); it != vservConnectAddresses.end(); it++)
 +                    BOOST_FOREACH(CService& addrNode, *(it))
 +                        if (pnode->addr == addrNode)
 +                        {
 +                            it = vservConnectAddresses.erase(it);
 +                            it--;
 +                            break;
 +                        }
 +        BOOST_FOREACH(vector<CService>& vserv, vservConnectAddresses)
 +        {
 +            OpenNetworkConnection(CAddress(*(vserv.begin())));
 +            Sleep(500);
 +            if (fShutdown)
 +                return;
 +        }
 +        if (fShutdown)
 +            return;
 +        vnThreadsRunning[THREAD_ADDEDCONNECTIONS]--;
 +        Sleep(120000); // Retry every 2 minutes
 +        vnThreadsRunning[THREAD_ADDEDCONNECTIONS]++;
 +        if (fShutdown)
 +            return;
 +    }
 +}
 +
  bool OpenNetworkConnection(const CAddress& addrConnect)
  {
      //
      //
      if (fShutdown)
          return false;
 -    if (addrConnect.ip == addrLocalHost.ip || !addrConnect.IsIPv4() ||
 -        FindNode(addrConnect.ip) || CNode::IsBanned(addrConnect.ip))
 +    if ((CNetAddr)addrConnect == (CNetAddr)addrLocalHost || !addrConnect.IsIPv4() ||
 +        FindNode((CNetAddr)addrConnect) || CNode::IsBanned(addrConnect))
          return false;
  
 -    vnThreadsRunning[1]--;
 +    vnThreadsRunning[THREAD_OPENCONNECTIONS]--;
      CNode* pnode = ConnectNode(addrConnect);
 -    vnThreadsRunning[1]++;
 +    vnThreadsRunning[THREAD_OPENCONNECTIONS]++;
      if (fShutdown)
          return false;
      if (!pnode)
@@@ -1476,15 -1646,15 +1476,15 @@@ void ThreadMessageHandler(void* parg
      IMPLEMENT_RANDOMIZE_STACK(ThreadMessageHandler(parg));
      try
      {
 -        vnThreadsRunning[2]++;
 +        vnThreadsRunning[THREAD_MESSAGEHANDLER]++;
          ThreadMessageHandler2(parg);
 -        vnThreadsRunning[2]--;
 +        vnThreadsRunning[THREAD_MESSAGEHANDLER]--;
      }
      catch (std::exception& e) {
 -        vnThreadsRunning[2]--;
 +        vnThreadsRunning[THREAD_MESSAGEHANDLER]--;
          PrintException(&e, "ThreadMessageHandler()");
      } catch (...) {
 -        vnThreadsRunning[2]--;
 +        vnThreadsRunning[THREAD_MESSAGEHANDLER]--;
          PrintException(NULL, "ThreadMessageHandler()");
      }
      printf("ThreadMessageHandler exiting\n");
@@@ -1532,11 -1702,11 +1532,11 @@@ void ThreadMessageHandler2(void* parg
          // Wait and allow messages to bunch up.
          // Reduce vnThreadsRunning so StopNode has permission to exit while
          // we're sleeping, but we must always check fShutdown after doing this.
 -        vnThreadsRunning[2]--;
 +        vnThreadsRunning[THREAD_MESSAGEHANDLER]--;
          Sleep(100);
          if (fRequestShutdown)
-             Shutdown(NULL);
+             StartShutdown();
 -        vnThreadsRunning[2]++;
 +        vnThreadsRunning[THREAD_MESSAGEHANDLER]++;
          if (fShutdown)
              return;
      }
@@@ -1551,7 -1721,7 +1551,7 @@@ bool BindListenPort(string& strError
  {
      strError = "";
      int nOne = 1;
 -    addrLocalHost.port = htons(GetListenPort());
 +    addrLocalHost.SetPort(GetListenPort());
  
  #ifdef WIN32
      // Initialize Windows Sockets
  
  void StartNode(void* parg)
  {
 +#ifdef USE_UPNP
 +#if USE_UPNP
 +    fUseUPnP = GetBoolArg("-upnp", true);
 +#else
 +    fUseUPnP = GetBoolArg("-upnp", false);
 +#endif
 +#endif
 +
      if (pnodeLocalHost == NULL)
 -        pnodeLocalHost = new CNode(INVALID_SOCKET, CAddress("127.0.0.1", 0, false, nLocalServices));
 +        pnodeLocalHost = new CNode(INVALID_SOCKET, CAddress(CService("127.0.0.1", 0), nLocalServices));
  
  #ifdef WIN32
      // Get local host ip
      char pszHostName[1000] = "";
      if (gethostname(pszHostName, sizeof(pszHostName)) != SOCKET_ERROR)
      {
 -        vector<CAddress> vaddr;
 -        if (Lookup(pszHostName, vaddr, nLocalServices, -1, true))
 -            BOOST_FOREACH (const CAddress &addr, vaddr)
 -                if (addr.GetByte(3) != 127)
 +        vector<CNetAddr> vaddr;
 +        if (LookupHost(pszHostName, vaddr))
 +            BOOST_FOREACH (const CNetAddr &addr, vaddr)
 +                if (!addr.IsLocal())
                  {
 -                    addrLocalHost = addr;
 +                    addrLocalHost.SetIP(addr);
                      break;
                  }
      }
                      printf("ipv4 %s: %s\n", ifa->ifa_name, pszIP);
  
                  // Take the first IP that isn't loopback 127.x.x.x
 -                CAddress addr(*(unsigned int*)&s4->sin_addr, GetListenPort(), nLocalServices);
 -                if (addr.IsValid() && addr.GetByte(3) != 127)
 +                CAddress addr(CService(s4->sin_addr, GetListenPort()), nLocalServices);
 +                if (addr.IsValid() && !addr.IsLocal())
                  {
                      addrLocalHost = addr;
                      break;
      if (fUseProxy || mapArgs.count("-connect") || fNoListen)
      {
          // Proxies can't take incoming connections
 -        addrLocalHost.ip = CAddress("0.0.0.0").ip;
 +        addrLocalHost.SetIP(CNetAddr("0.0.0.0"));
          printf("addrLocalHost = %s\n", addrLocalHost.ToString().c_str());
      }
      else
      // Start threads
      //
  
 -    if (GetBoolArg("-nodnsseed"))
 +    if (!GetBoolArg("-dnsseed", true))
          printf("DNS seeding disabled\n");
      else
          if (!CreateThread(ThreadDNSAddressSeed, NULL))
      if (!CreateThread(ThreadSocketHandler, NULL))
          printf("Error: CreateThread(ThreadSocketHandler) failed\n");
  
 +    // Initiate outbound connections from -addnode
 +    if (!CreateThread(ThreadOpenAddedConnections, NULL))
 +        printf("Error: CreateThread(ThreadOpenAddedConnections) failed\n");
 +
      // Initiate outbound connections
      if (!CreateThread(ThreadOpenConnections, NULL))
          printf("Error: CreateThread(ThreadOpenConnections) failed\n");
      if (!CreateThread(ThreadMessageHandler, NULL))
          printf("Error: CreateThread(ThreadMessageHandler) failed\n");
  
 +    // Dump network addresses
 +    if (!CreateThread(ThreadDumpAddress, NULL))
 +        printf("Error; CreateThread(ThreadDumpAddress) failed\n");
 +
      // Generate coins in the background
 -    GenerateBitcoins(fGenerateBitcoins, pwalletMain);
 +    GenerateBitcoins(GetBoolArg("-gen", false), pwalletMain);
  }
  
  bool StopNode()
      fShutdown = true;
      nTransactionsUpdated++;
      int64 nStart = GetTime();
 -    while (vnThreadsRunning[0] > 0 || vnThreadsRunning[1] > 0 || vnThreadsRunning[2] > 0 || vnThreadsRunning[3] > 0 || vnThreadsRunning[4] > 0
 -#ifdef USE_UPNP
 -        || vnThreadsRunning[5] > 0
 -#endif
 -    )
 +    do
      {
 +        int nThreadsRunning = 0;
 +        for (int n = 0; n < THREAD_MAX; n++)
 +            nThreadsRunning += vnThreadsRunning[n];
 +        if (nThreadsRunning == 0)
 +            break;
          if (GetTime() - nStart > 20)
              break;
          Sleep(20);
 -    }
 -    if (vnThreadsRunning[0] > 0) printf("ThreadSocketHandler still running\n");
 -    if (vnThreadsRunning[1] > 0) printf("ThreadOpenConnections still running\n");
 -    if (vnThreadsRunning[2] > 0) printf("ThreadMessageHandler still running\n");
 -    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)
 +    } while(true);
 +    if (vnThreadsRunning[THREAD_SOCKETHANDLER] > 0) printf("ThreadSocketHandler still running\n");
 +    if (vnThreadsRunning[THREAD_OPENCONNECTIONS] > 0) printf("ThreadOpenConnections still running\n");
 +    if (vnThreadsRunning[THREAD_MESSAGEHANDLER] > 0) printf("ThreadMessageHandler still running\n");
 +    if (vnThreadsRunning[THREAD_MINER] > 0) printf("ThreadBitcoinMiner still running\n");
 +    if (vnThreadsRunning[THREAD_RPCSERVER] > 0) printf("ThreadRPCServer still running\n");
 +    if (fHaveUPnP && vnThreadsRunning[THREAD_UPNP] > 0) printf("ThreadMapPort still running\n");
 +    if (vnThreadsRunning[THREAD_DNSSEED] > 0) printf("ThreadDNSAddressSeed still running\n");
 +    if (vnThreadsRunning[THREAD_ADDEDCONNECTIONS] > 0) printf("ThreadOpenAddedConnections still running\n");
 +    if (vnThreadsRunning[THREAD_DUMPADDRESS] > 0) printf("ThreadDumpAddresses still running\n");
 +    while (vnThreadsRunning[THREAD_MESSAGEHANDLER] > 0 || vnThreadsRunning[THREAD_RPCSERVER] > 0)
          Sleep(20);
      Sleep(50);
 -
 +    DumpAddresses();
      return true;
  }
  
@@@ -2,7 -2,6 +2,7 @@@
  #include "ui_addressbookpage.h"
  
  #include "addresstablemodel.h"
 +#include "bitcoingui.h"
  #include "editaddressdialog.h"
  #include "csvmodelwriter.h"
  #include "guiutil.h"
  #include <QSortFilterProxyModel>
  #include <QClipboard>
  #include <QMessageBox>
 +#include <QMenu>
 +
 +#ifdef USE_QRCODE
 +#include "qrcodedialog.h"
 +#endif
  
  AddressBookPage::AddressBookPage(Mode mode, Tabs tab, QWidget *parent) :
      QDialog(parent),
      ui->deleteButton->setIcon(QIcon());
  #endif
  
 +#ifndef USE_QRCODE
 +    ui->showQRCode->setVisible(false);
 +#endif
 +
      switch(mode)
      {
      case ForSending:
          break;
      }
      ui->tableView->setTabKeyNavigation(false);
 +    ui->tableView->setContextMenuPolicy(Qt::CustomContextMenu);
 +
 +    // Context menu actions
 +    QAction *copyAddressAction = new QAction(tr("Copy address"), this);
 +    QAction *copyLabelAction = new QAction(tr("Copy label"), this);
 +    QAction *editAction = new QAction(tr("Edit"), this);
 +    deleteAction = new QAction(tr("Delete"), this);
 +
 +    contextMenu = new QMenu();
 +    contextMenu->addAction(copyAddressAction);
 +    contextMenu->addAction(copyLabelAction);
 +    contextMenu->addAction(editAction);
 +    contextMenu->addAction(deleteAction);
  
 +    connect(copyAddressAction, SIGNAL(triggered()), this, SLOT(on_copyToClipboard_clicked()));
 +    connect(copyLabelAction, SIGNAL(triggered()), this, SLOT(onCopyLabelAction()));
 +    connect(editAction, SIGNAL(triggered()), this, SLOT(onEditAction()));
 +    connect(deleteAction, SIGNAL(triggered()), this, SLOT(on_deleteButton_clicked()));
 +
 +    connect(ui->tableView, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(contextualMenu(QPoint)));
 +
 +    // Pass through accept action from button box
      connect(ui->buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
  }
  
@@@ -121,57 -90,23 +121,52 @@@ void AddressBookPage::setModel(AddressT
      connect(ui->tableView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
              this, SLOT(selectionChanged()));
  
-     if(mode == ForSending)
-     {
-         // Auto-select first row when in sending mode
-         ui->tableView->selectRow(0);
-     }
      selectionChanged();
  }
  
  void AddressBookPage::on_copyToClipboard_clicked()
  {
 -    // Copy currently selected address to clipboard
 -    //   (or nothing, if nothing selected)
 -    QTableView *table = ui->tableView;
 -    if(!table->selectionModel())
 +    GUIUtil::copyEntryData(ui->tableView, AddressTableModel::Address);
 +}
 +void AddressBookPage::onCopyLabelAction()
 +{
 +    GUIUtil::copyEntryData(ui->tableView, AddressTableModel::Label);
 +}
 +
 +void AddressBookPage::onEditAction()
 +{
 +    if(!ui->tableView->selectionModel())
 +        return;
 +    QModelIndexList indexes = ui->tableView->selectionModel()->selectedRows();
 +    if(indexes.isEmpty())
          return;
 +
 +    EditAddressDialog dlg(
 +            tab == SendingTab ?
 +            EditAddressDialog::EditSendingAddress :
 +            EditAddressDialog::EditReceivingAddress);
 +    dlg.setModel(model);
 +    QModelIndex origIndex = proxyModel->mapToSource(indexes.at(0));
 +    dlg.loadRow(origIndex.row());
 +    dlg.exec();
 +}
 +
 +void AddressBookPage::on_signMessage_clicked()
 +{
 +    QTableView *table = ui->tableView;
      QModelIndexList indexes = table->selectionModel()->selectedRows(AddressTableModel::Address);
 +    QString addr;
  
      foreach (QModelIndex index, indexes)
      {
          QVariant address = index.data();
 -        QApplication::clipboard()->setText(address.toString());
 +        addr = address.toString();
      }
 +
 +    QObject *qoGUI = parent()->parent();
 +    BitcoinGUI *gui = qobject_cast<BitcoinGUI *>(qoGUI);
 +    if (gui)
 +        gui->gotoMessagePage(addr);
  }
  
  void AddressBookPage::on_newAddressButton_clicked()
@@@ -222,27 -157,18 +217,27 @@@ void AddressBookPage::selectionChanged(
          switch(tab)
          {
          case SendingTab:
 +            // In sending tab, allow deletion of selection
              ui->deleteButton->setEnabled(true);
 +            deleteAction->setEnabled(true);
 +            ui->signMessage->setEnabled(false);
              break;
          case ReceivingTab:
 +            // Deleting receiving addresses, however, is not allowed
              ui->deleteButton->setEnabled(false);
 +            deleteAction->setEnabled(false);
 +            ui->signMessage->setEnabled(true);
              break;
          }
          ui->copyToClipboard->setEnabled(true);
 +        ui->showQRCode->setEnabled(true);
      }
      else
      {
          ui->deleteButton->setEnabled(false);
 +        ui->showQRCode->setEnabled(false);
          ui->copyToClipboard->setEnabled(false);
 +        ui->signMessage->setEnabled(false);
      }
  }
  
@@@ -266,7 -192,6 +261,7 @@@ void AddressBookPage::done(int retval
  
      if(returnValue.isEmpty())
      {
 +        // If no address entry selected, return rejected
          retval = Rejected;
      }
  
@@@ -296,32 -221,3 +291,32 @@@ void AddressBookPage::exportClicked(
                                QMessageBox::Abort, QMessageBox::Abort);
      }
  }
 +
 +void AddressBookPage::on_showQRCode_clicked()
 +{
 +#ifdef USE_QRCODE
 +    QTableView *table = ui->tableView;
 +    QModelIndexList indexes = table->selectionModel()->selectedRows(AddressTableModel::Address);
 +
 +
 +    QRCodeDialog *d;
 +    foreach (QModelIndex index, indexes)
 +    {
 +        QString address = index.data().toString(),
 +            label = index.sibling(index.row(), 0).data(Qt::EditRole).toString(),
 +            title = QString("%1%2<< %3 >>").arg(label).arg(label.isEmpty() ? "" : " ").arg(address);
 +
 +        QRCodeDialog *d = new QRCodeDialog(title, address, label, tab == ReceivingTab, this);
 +        d->show();
 +    }
 +#endif
 +}
 +
 +void AddressBookPage::contextualMenu(const QPoint &point)
 +{
 +    QModelIndex index = ui->tableView->indexAt(point);
 +    if(index.isValid())
 +    {
 +        contextMenu->exec(QCursor::pos());
 +    }
 +}
diff --combined src/qt/bitcoin.cpp
@@@ -1,5 -1,5 +1,5 @@@
  /*
 - * W.J. van der Laan 2011
 + * W.J. van der Laan 2011-2012
   */
  #include "bitcoingui.h"
  #include "clientmodel.h"
@@@ -8,7 -8,6 +8,7 @@@
  
  #include "headers.h"
  #include "init.h"
 +#include "qtipcserver.h"
  #include "util.h"
  
  #include <QApplication>
  #include <QSplashScreen>
  #include <QLibraryInfo>
  
 +#include <boost/interprocess/ipc/message_queue.hpp>
 +
  // Need a global reference for the notifications to find the GUI
  BitcoinGUI *guiref;
  QSplashScreen *splashref;
  
  int MyMessageBox(const std::string& message, const std::string& caption, int style, wxWindow* parent, int x, int y)
  {
 -    // Message from main thread
 -    if(guiref)
 -    {
 -        guiref->error(QString::fromStdString(caption),
 -                      QString::fromStdString(message));
 -    }
 -    else
 -    {
 -        QMessageBox::critical(0, QString::fromStdString(caption),
 -            QString::fromStdString(message),
 -            QMessageBox::Ok, QMessageBox::Ok);
 -    }
 +    // Message from AppInit2(), always in main thread before main window is constructed
 +    QMessageBox::critical(0, QString::fromStdString(caption),
 +        QString::fromStdString(message),
 +        QMessageBox::Ok, QMessageBox::Ok);
      return 4;
  }
  
@@@ -82,22 -87,6 +82,22 @@@ bool ThreadSafeAskFee(int64 nFeeRequire
      return payFee;
  }
  
 +void ThreadSafeHandleURI(const std::string& strURI)
 +{
 +    if(!guiref)
 +        return;
 +
 +    // Call slot on GUI thread.
 +    // If called from another thread, use a blocking QueuedConnection.
 +    Qt::ConnectionType connectionType = Qt::DirectConnection;
 +    if(QThread::currentThread() != QCoreApplication::instance()->thread())
 +    {
 +        connectionType = Qt::BlockingQueuedConnection;
 +    }
 +    QMetaObject::invokeMethod(guiref, "handleURI", connectionType,
 +                               Q_ARG(QString, QString::fromStdString(strURI)));
 +}
 +
  void CalledSetStatusBar(const std::string& strText, int nField)
  {
      // Only used for built-in mining, which is disabled, simple ignore
@@@ -123,6 -112,11 +123,11 @@@ void InitMessage(const std::string &mes
      }
  }
  
+ void QueueShutdown()
+ {
+     QMetaObject::invokeMethod(QCoreApplication::instance(), "quit", Qt::QueuedConnection);
+ }
  /*
     Translate string to current locale using Qt.
   */
@@@ -140,68 -134,19 +145,68 @@@ static void handleRunawayException(std:
      exit(1);
  }
  
 +#ifndef BITCOIN_QT_TEST
  int main(int argc, char *argv[])
  {
 +#if !defined(MAC_OSX) && !defined(WIN32)
 +// TODO: implement qtipcserver.cpp for Mac and Windows
 +
 +    // Do this early as we don't want to bother initializing if we are just calling IPC
 +    for (int i = 1; i < argc; i++)
 +    {
 +        if (strlen(argv[i]) > 7 && strncasecmp(argv[i], "bitcoin:", 8) == 0)
 +        {
 +            const char *strURI = argv[i];
 +            try {
 +                boost::interprocess::message_queue mq(boost::interprocess::open_only, BITCOINURI_QUEUE_NAME);
 +                if(mq.try_send(strURI, strlen(strURI), 0))
 +                    exit(0);
 +                else
 +                    break;
 +            }
 +            catch (boost::interprocess::interprocess_exception &ex) {
 +                break;
 +            }
 +        }
 +    }
 +#endif
 +
 +    // Internal string conversion is all UTF-8
      QTextCodec::setCodecForTr(QTextCodec::codecForName("UTF-8"));
      QTextCodec::setCodecForCStrings(QTextCodec::codecForTr());
  
      Q_INIT_RESOURCE(bitcoin);
      QApplication app(argc, argv);
  
 -    // Load language files for system locale:
 +    // Command-line options take precedence:
 +    ParseParameters(argc, argv);
 +
 +    // ... then bitcoin.conf:
 +    if (!ReadConfigFile(mapArgs, mapMultiArgs))
 +    {
 +        fprintf(stderr, "Error: Specified directory does not exist\n");
 +        return 1;
 +    }
 +
 +    // Application identification (must be set before OptionsModel is initialized,
 +    // as it is used to locate QSettings)
 +    app.setOrganizationName("Bitcoin");
 +    app.setOrganizationDomain("bitcoin.org");
 +    if(GetBoolArg("-testnet")) // Separate UI settings for testnet
 +        app.setApplicationName("Bitcoin-Qt-testnet");
 +    else
 +        app.setApplicationName("Bitcoin-Qt");
 +
 +    // ... then GUI settings:
 +    OptionsModel optionsModel;
 +
 +    // Get desired locale ("en_US") from command line or system locale
 +    QString lang_territory = QString::fromStdString(GetArg("-lang", QLocale::system().name().toStdString()));
 +    // Load language files for configured locale:
      // - First load the translator for the base language, without territory
      // - Then load the more specific locale translator
 -    QString lang_territory = QLocale::system().name(); // "en_US"
      QString lang = lang_territory;
 +
      lang.truncate(lang_territory.lastIndexOf('_')); // "en"
      QTranslator qtTranslatorBase, qtTranslator, translatorBase, translator;
  
      if (!translator.isEmpty())
          app.installTranslator(&translator);
  
 -    app.setApplicationName(QApplication::translate("main", "Bitcoin-Qt"));
 -
      QSplashScreen splash(QPixmap(":/images/splash"), 0);
 -    if (!GetBoolArg("-min"))
 +    if (GetBoolArg("-splash", true) && !GetBoolArg("-min"))
      {
          splash.show();
          splash.setAutoFillBackground(true);
              {
                  // Put this in a block, so that BitcoinGUI is cleaned up properly before
                  // calling Shutdown() in case of exceptions.
 +
 +                optionsModel.Upgrade(); // Must be done after AppInit2
 +
                  BitcoinGUI window;
                  if (splashref)
                      splash.finish(&window);
 -                OptionsModel optionsModel(pwalletMain);
 +
                  ClientModel clientModel(&optionsModel);
                  WalletModel walletModel(pwalletMain, &optionsModel);
  
                      window.show();
                  }
  
 +                // Place this here as guiref has to be defined if we dont want to lose URIs
 +                ipcInit();
 +
 +#if !defined(MAC_OSX) && !defined(WIN32)
 +// TODO: implement qtipcserver.cpp for Mac and Windows
 +
 +                // Check for URI in argv
 +                for (int i = 1; i < argc; i++)
 +                {
 +                    if (strlen(argv[i]) > 7 && strncasecmp(argv[i], "bitcoin:", 8) == 0)
 +                    {
 +                        const char *strURI = argv[i];
 +                        try {
 +                            boost::interprocess::message_queue mq(boost::interprocess::open_only, BITCOINURI_QUEUE_NAME);
 +                            mq.try_send(strURI, strlen(strURI), 0);
 +                        }
 +                        catch (boost::interprocess::interprocess_exception &ex) {
 +                        }
 +                    }
 +                }
 +#endif
                  app.exec();
  
                  window.hide();
                  guiref = 0;
              }
+             // Shutdown the core and it's threads, but don't exit Bitcoin-Qt here
              Shutdown(NULL);
          }
          else
      }
      return 0;
  }
 +#endif // BITCOIN_QT_TEST
diff --combined src/qt/bitcoingui.cpp
@@@ -1,8 -1,8 +1,8 @@@
  /*
   * Qt4 bitcoin GUI.
   *
 - * W.J. van der Laan 2011
 - * The Bitcoin Developers 2011
 + * W.J. van der Laan 2011-2012
 + * The Bitcoin Developers 2011-2012
   */
  
  #include "checkpoints.h"
@@@ -11,7 -11,6 +11,7 @@@
  #include "transactiontablemodel.h"
  #include "addressbookpage.h"
  #include "sendcoinsdialog.h"
 +#include "messagepage.h"
  #include "optionsdialog.h"
  #include "aboutdialog.h"
  #include "clientmodel.h"
@@@ -49,8 -48,6 +49,8 @@@
  #include <QStackedWidget>
  #include <QDateTime>
  #include <QMovie>
 +#include <QFileDialog>
 +#include <QDesktopServices>
  #include <QTimer>
  
  #include <QDragEnterEvent>
@@@ -106,17 -103,12 +106,17 @@@ BitcoinGUI::BitcoinGUI(QWidget *parent)
  
      sendCoinsPage = new SendCoinsDialog(this);
  
 +    messagePage = new MessagePage(this);
 +
      centralWidget = new QStackedWidget(this);
      centralWidget->addWidget(overviewPage);
      centralWidget->addWidget(transactionsPage);
      centralWidget->addWidget(addressBookPage);
      centralWidget->addWidget(receiveCoinsPage);
      centralWidget->addWidget(sendCoinsPage);
 +#ifdef FIRST_CLASS_MESSAGING
 +    centralWidget->addWidget(messagePage);
 +#endif
      setCentralWidget(centralWidget);
  
      // Create status bar
  
      // Status bar notification icons
      QFrame *frameBlocks = new QFrame();
 -    //frameBlocks->setFrameStyle(QFrame::Panel | QFrame::Sunken);
      frameBlocks->setContentsMargins(0,0,0,0);
      frameBlocks->setMinimumWidth(56);
      frameBlocks->setMaximumWidth(56);
@@@ -204,25 -197,16 +204,25 @@@ void BitcoinGUI::createActions(
      sendCoinsAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_2));
      tabGroup->addAction(sendCoinsAction);
  
 -    connect(overviewAction, SIGNAL(triggered()), this, SLOT(showNormal()));
 +    messageAction = new QAction(QIcon(":/icons/edit"), tr("Sign &message"), this);
 +    messageAction->setToolTip(tr("Prove you control an address"));
 +#ifdef FIRST_CLASS_MESSAGING
 +    messageAction->setCheckable(true);
 +#endif
 +    tabGroup->addAction(messageAction);
 +
 +    connect(overviewAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized()));
      connect(overviewAction, SIGNAL(triggered()), this, SLOT(gotoOverviewPage()));
 -    connect(historyAction, SIGNAL(triggered()), this, SLOT(showNormal()));
 +    connect(historyAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized()));
      connect(historyAction, SIGNAL(triggered()), this, SLOT(gotoHistoryPage()));
 -    connect(addressBookAction, SIGNAL(triggered()), this, SLOT(showNormal()));
 +    connect(addressBookAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized()));
      connect(addressBookAction, SIGNAL(triggered()), this, SLOT(gotoAddressBookPage()));
 -    connect(receiveCoinsAction, SIGNAL(triggered()), this, SLOT(showNormal()));
 +    connect(receiveCoinsAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized()));
      connect(receiveCoinsAction, SIGNAL(triggered()), this, SLOT(gotoReceiveCoinsPage()));
 -    connect(sendCoinsAction, SIGNAL(triggered()), this, SLOT(showNormal()));
 +    connect(sendCoinsAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized()));
      connect(sendCoinsAction, SIGNAL(triggered()), this, SLOT(gotoSendCoinsPage()));
 +    connect(messageAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized()));
 +    connect(messageAction, SIGNAL(triggered()), this, SLOT(gotoMessagePage()));
  
      quitAction = new QAction(QIcon(":/icons/quit"), tr("E&xit"), this);
      quitAction->setToolTip(tr("Quit application"));
      openBitcoinAction = new QAction(QIcon(":/icons/bitcoin"), tr("Open &Bitcoin"), this);
      openBitcoinAction->setToolTip(tr("Show the Bitcoin window"));
      exportAction = new QAction(QIcon(":/icons/export"), tr("&Export..."), this);
 -    exportAction->setToolTip(tr("Export the current view to a file"));
 +    exportAction->setToolTip(tr("Export the data in the current tab to a file"));
      encryptWalletAction = new QAction(QIcon(":/icons/lock_closed"), tr("&Encrypt Wallet"), this);
      encryptWalletAction->setToolTip(tr("Encrypt or decrypt wallet"));
      encryptWalletAction->setCheckable(true);
 +    backupWalletAction = new QAction(QIcon(":/icons/filesave"), tr("&Backup Wallet"), this);
 +    backupWalletAction->setToolTip(tr("Backup wallet to another location"));
      changePassphraseAction = new QAction(QIcon(":/icons/key"), tr("&Change Passphrase"), this);
      changePassphraseAction->setToolTip(tr("Change the passphrase used for wallet encryption"));
  
      connect(optionsAction, SIGNAL(triggered()), this, SLOT(optionsClicked()));
      connect(aboutAction, SIGNAL(triggered()), this, SLOT(aboutClicked()));
      connect(aboutQtAction, SIGNAL(triggered()), qApp, SLOT(aboutQt()));
 -    connect(openBitcoinAction, SIGNAL(triggered()), this, SLOT(showNormal()));
 +    connect(openBitcoinAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized()));
      connect(encryptWalletAction, SIGNAL(triggered(bool)), this, SLOT(encryptWallet(bool)));
 +    connect(backupWalletAction, SIGNAL(triggered()), this, SLOT(backupWallet()));
      connect(changePassphraseAction, SIGNAL(triggered()), this, SLOT(changePassphrase()));
  }
  
@@@ -271,12 -252,6 +271,12 @@@ void BitcoinGUI::createMenuBar(
  
      // Configure the menus
      QMenu *file = appMenuBar->addMenu(tr("&File"));
 +    file->addAction(backupWalletAction);
 +    file->addAction(exportAction);
 +#ifndef FIRST_CLASS_MESSAGING
 +    file->addAction(messageAction);
 +#endif
 +    file->addSeparator();
      file->addAction(quitAction);
  
      QMenu *settings = appMenuBar->addMenu(tr("&Settings"));
@@@ -299,9 -274,6 +299,9 @@@ void BitcoinGUI::createToolBars(
      toolbar->addAction(receiveCoinsAction);
      toolbar->addAction(historyAction);
      toolbar->addAction(addressBookAction);
 +#ifdef FIRST_CLASS_MESSAGING
 +    toolbar->addAction(messageAction);
 +#endif
  
      QToolBar *toolbar2 = addToolBar(tr("Actions toolbar"));
      toolbar2->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
@@@ -356,7 -328,6 +356,7 @@@ void BitcoinGUI::setWalletModel(WalletM
          addressBookPage->setModel(walletModel->getAddressTableModel());
          receiveCoinsPage->setModel(walletModel->getAddressTableModel());
          sendCoinsPage->setModel(walletModel);
 +        messagePage->setModel(walletModel);
  
          setEncryptionStatus(walletModel->getEncryptionStatus());
          connect(walletModel, SIGNAL(encryptionStatusChanged(int)), this, SLOT(setEncryptionStatus(int)));
@@@ -392,10 -363,6 +392,10 @@@ void BitcoinGUI::createTrayIcon(
      // Configuration of the tray icon (or dock icon) icon menu
      trayIconMenu->addAction(openBitcoinAction);
      trayIconMenu->addSeparator();
 +    trayIconMenu->addAction(messageAction);
 +#ifndef FIRST_CLASS_MESSAGING
 +    trayIconMenu->addSeparator();
 +#endif
      trayIconMenu->addAction(receiveCoinsAction);
      trayIconMenu->addAction(sendCoinsAction);
      trayIconMenu->addSeparator();
@@@ -552,16 -519,12 +552,12 @@@ void BitcoinGUI::refreshStatusBar(
      setNumBlocks(clientModel->getNumBlocks());
  }
  
- bool HACK_SHUTDOWN = false;
  void BitcoinGUI::error(const QString &title, const QString &message, bool modal)
  {
      // Report errors from network/worker thread
      if (modal)
      {
          QMessageBox::critical(this, title, message, QMessageBox::Ok, QMessageBox::Ok);
-         if (HACK_SHUTDOWN)
-             QMetaObject::invokeMethod(QCoreApplication::instance(), "quit", Qt::QueuedConnection);
      } else {
          notificator->notify(Notificator::Critical, title, message);
      }
@@@ -697,26 -660,6 +693,26 @@@ void BitcoinGUI::gotoSendCoinsPage(
      disconnect(exportAction, SIGNAL(triggered()), 0, 0);
  }
  
 +void BitcoinGUI::gotoMessagePage()
 +{
 +#ifdef FIRST_CLASS_MESSAGING
 +    messageAction->setChecked(true);
 +    centralWidget->setCurrentWidget(messagePage);
 +
 +    exportAction->setEnabled(false);
 +    disconnect(exportAction, SIGNAL(triggered()), 0, 0);
 +#else
 +    messagePage->show();
 +    messagePage->setFocus();
 +#endif
 +}
 +
 +void BitcoinGUI::gotoMessagePage(QString addr)
 +{
 +    gotoMessagePage();
 +    messagePage->setAddress(addr);
 +}
 +
  void BitcoinGUI::dragEnterEvent(QDragEnterEvent *event)
  {
      // Accept only URIs
@@@ -732,24 -675,13 +728,24 @@@ void BitcoinGUI::dropEvent(QDropEvent *
          QList<QUrl> uris = event->mimeData()->urls();
          foreach(const QUrl &uri, uris)
          {
 -            sendCoinsPage->handleURI(&uri);
 +            sendCoinsPage->handleURI(uri.toString());
          }
      }
  
      event->acceptProposedAction();
  }
  
 +void BitcoinGUI::handleURI(QString strURI)
 +{
 +    gotoSendCoinsPage();
 +    sendCoinsPage->handleURI(strURI);
 +
 +    if(!isActiveWindow())
 +        activateWindow();
 +
 +    showNormalIfMinimized();
 +}
 +
  void BitcoinGUI::setEncryptionStatus(int status)
  {
      switch(status)
@@@ -791,17 -723,6 +787,17 @@@ void BitcoinGUI::encryptWallet(bool sta
      setEncryptionStatus(walletModel->getEncryptionStatus());
  }
  
 +void BitcoinGUI::backupWallet()
 +{
 +    QString saveDir = QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation);
 +    QString filename = QFileDialog::getSaveFileName(this, tr("Backup Wallet"), saveDir, tr("Wallet Data (*.dat)"));
 +    if(!filename.isEmpty()) {
 +        if(!walletModel->backupWallet(filename)) {
 +            QMessageBox::warning(this, tr("Backup Failed"), tr("There was an error trying to save the wallet data to the new location."));
 +        }
 +    }
 +}
 +
  void BitcoinGUI::changePassphrase()
  {
      AskPassphraseDialog dlg(AskPassphraseDialog::ChangePass, this);
@@@ -821,11 -742,3 +817,11 @@@ void BitcoinGUI::unlockWallet(
          dlg.exec();
      }
  }
 +
 +void BitcoinGUI::showNormalIfMinimized()
 +{
 +    if(!isVisible()) // Show, if hidden
 +        show();
 +    if(isMinimized()) // Unminimize, if minimized
 +        showNormal();
 +}
diff --combined src/qtui.h
@@@ -42,10 -42,10 +42,11 @@@ extern int MyMessageBox(const std::stri
  #define wxMessageBox  MyMessageBox
  extern int ThreadSafeMessageBox(const std::string& message, const std::string& caption, int style=wxOK, wxWindow* parent=NULL, int x=-1, int y=-1);
  extern bool ThreadSafeAskFee(int64 nFeeRequired, const std::string& strCaption, wxWindow* parent);
 +extern void ThreadSafeHandleURI(const std::string& strURI);
  extern void CalledSetStatusBar(const std::string& strText, int nField);
  extern void UIThreadCall(boost::function0<void> fn);
  extern void MainFrameRepaint();
+ extern void QueueShutdown();
  extern void InitMessage(const std::string &message);
  extern std::string _(const char* psz);
  
@@@ -1,28 -1,29 +1,34 @@@
  #define BOOST_TEST_MODULE Bitcoin Test Suite
  #include <boost/test/unit_test.hpp>
  
 -#include "../main.h"
 -#include "../wallet.h"
 -
 -#include "uint160_tests.cpp"
 -#include "uint256_tests.cpp"
 -#include "script_tests.cpp"
 -#include "transaction_tests.cpp"
 -#include "DoS_tests.cpp"
 -#include "base64_tests.cpp"
 -#include "util_tests.cpp"
 -#include "base58_tests.cpp"
 -#include "miner_tests.cpp"
 -#include "Checkpoints_tests.cpp"
 +#include "main.h"
 +#include "wallet.h"
  
  CWallet* pwalletMain;
  
 +extern bool fPrintToConsole;
 +struct TestingSetup {
 +    TestingSetup() {
 +        fPrintToConsole = true; // don't want to write to debug.log file
 +        pwalletMain = new CWallet();
 +        RegisterWallet(pwalletMain);
 +    }
 +    ~TestingSetup()
 +    {
 +        delete pwalletMain;
 +        pwalletMain = NULL;
 +    }
 +};
 +
 +BOOST_GLOBAL_FIXTURE(TestingSetup);
 +
  void Shutdown(void* parg)
  {
    exit(0);
  }
+ void StartShutdown()
+ {
+   exit(0);
+ }
diff --combined src/util.cpp
@@@ -4,7 -4,6 +4,7 @@@
  // file COPYING or http://www.opensource.org/licenses/mit-license.php.
  #include "headers.h"
  #include "strlcpy.h"
 +#include <boost/algorithm/string/join.hpp>
  
  // Work around clang compilation problem in Boost 1.46:
  // /usr/include/boost/program_options/detail/config_file.hpp:163:17: error: call to function 'to_internal' that is neither visible in the template definition nor found by argument-dependent lookup
@@@ -23,6 -22,7 +23,7 @@@ namespace boost 
  #include <boost/interprocess/sync/interprocess_mutex.hpp>
  #include <boost/interprocess/sync/interprocess_recursive_mutex.hpp>
  #include <boost/foreach.hpp>
+ #include <boost/thread.hpp>
  
  using namespace std;
  using namespace boost;
@@@ -42,7 -42,7 +43,7 @@@ string strMiscWarning
  bool fTestNet = false;
  bool fNoListen = false;
  bool fLogTimestamps = false;
 -
 +CMedianFilter<int64> vTimeOffsets(200,0);
  
  
  
@@@ -144,7 -144,7 +145,7 @@@ uint64 GetRand(uint64 nMax
  
      // The range of the random source must be a multiple of the modulus
      // to give every possible output value an equal possibility
 -    uint64 nRange = (UINT64_MAX / nMax) * nMax;
 +    uint64 nRange = (std::numeric_limits<uint64>::max() / nMax) * nMax;
      uint64 nRand = 0;
      do
          RAND_bytes((unsigned char*)&nRand, sizeof(nRand));
@@@ -194,6 -194,8 +195,8 @@@ inline int OutputDebugStringF(const cha
          if (fileout)
          {
              static bool fStartedNewLine = true;
+             static boost::mutex mutexDebugLog;
+             boost::mutex::scoped_lock scoped_lock(mutexDebugLog);
  
              // Debug print useful for profiling
              if (fLogTimestamps && fStartedNewLine)
@@@ -411,36 -413,26 +414,36 @@@ bool ParseMoney(const char* pszIn, int6
  }
  
  
 -vector<unsigned char> ParseHex(const char* psz)
 +static signed char phexdigit[256] =
 +{ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
 +  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
 +  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
 +  0,1,2,3,4,5,6,7,8,9,-1,-1,-1,-1,-1,-1,
 +  -1,0xa,0xb,0xc,0xd,0xe,0xf,-1,-1,-1,-1,-1,-1,-1,-1,-1,
 +  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
 +  -1,0xa,0xb,0xc,0xd,0xe,0xf,-1,-1,-1,-1,-1,-1,-1,-1,-1,
 +  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
 +  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
 +  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
 +  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
 +  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
 +  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
 +  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
 +  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
 +  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, };
 +
 +bool IsHex(const string& str)
  {
 -    static signed char phexdigit[256] =
 -    { -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
 -      -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
 -      -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
 -      0,1,2,3,4,5,6,7,8,9,-1,-1,-1,-1,-1,-1,
 -      -1,0xa,0xb,0xc,0xd,0xe,0xf,-1,-1,-1,-1,-1,-1,-1,-1,-1,
 -      -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
 -      -1,0xa,0xb,0xc,0xd,0xe,0xf,-1,-1,-1,-1,-1,-1,-1,-1,-1,
 -      -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
 -      -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
 -      -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
 -      -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
 -      -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
 -      -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
 -      -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
 -      -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
 -      -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, };
 +    BOOST_FOREACH(unsigned char c, str)
 +    {
 +        if (phexdigit[c] < 0)
 +            return false;
 +    }
 +    return (str.size() > 0) && (str.size()%2 == 0);
 +}
  
 +vector<unsigned char> ParseHex(const char* psz)
 +{
      // convert hex dump to vector
      vector<unsigned char> vch;
      loop
@@@ -465,22 -457,7 +468,22 @@@ vector<unsigned char> ParseHex(const st
      return ParseHex(str.c_str());
  }
  
 -void ParseParameters(int argc, char* argv[])
 +static void InterpretNegativeSetting(string name, map<string, string>& mapSettingsRet)
 +{
 +    // interpret -nofoo as -foo=0 (and -nofoo=0 as -foo=1) as long as -foo not set
 +    if (name.find("-no") == 0)
 +    {
 +        std::string positive("-");
 +        positive.append(name.begin()+3, name.end());
 +        if (mapSettingsRet.count(positive) == 0)
 +        {
 +            bool value = !GetBoolArg(name);
 +            mapSettingsRet[positive] = (value ? "1" : "0");
 +        }
 +    }
 +}
 +
 +void ParseParameters(int argc, const char*const argv[])
  {
      mapArgs.clear();
      mapMultiArgs.clear();
          #endif
          if (psz[0] != '-')
              break;
 +
          mapArgs[psz] = pszValue;
          mapMultiArgs[psz].push_back(pszValue);
      }
 +
 +    // New 0.6 features:
 +    BOOST_FOREACH(const PAIRTYPE(string,string)& entry, mapArgs)
 +    {
 +        string name = entry.first;
 +
 +        //  interpret --foo as -foo (as long as both are not set)
 +        if (name.find("--") == 0)
 +        {
 +            std::string singleDash(name.begin()+1, name.end());
 +            if (mapArgs.count(singleDash) == 0)
 +                mapArgs[singleDash] = entry.second;
 +            name = singleDash;
 +        }
 +
 +        // interpret -nofoo as -foo=0 (and -nofoo=0 as -foo=1) as long as -foo not set
 +        InterpretNegativeSetting(name, mapArgs);
 +    }
 +}
 +
 +std::string GetArg(const std::string& strArg, const std::string& strDefault)
 +{
 +    if (mapArgs.count(strArg))
 +        return mapArgs[strArg];
 +    return strDefault;
 +}
 +
 +int64 GetArg(const std::string& strArg, int64 nDefault)
 +{
 +    if (mapArgs.count(strArg))
 +        return atoi64(mapArgs[strArg]);
 +    return nDefault;
 +}
 +
 +bool GetBoolArg(const std::string& strArg, bool fDefault)
 +{
 +    if (mapArgs.count(strArg))
 +    {
 +        if (mapArgs[strArg].empty())
 +            return true;
 +        return (atoi(mapArgs[strArg]) != 0);
 +    }
 +    return fDefault;
  }
  
  bool SoftSetArg(const std::string& strArg, const std::string& strValue)
      return true;
  }
  
 -bool SoftSetArg(const std::string& strArg, bool fValue)
 +bool SoftSetBoolArg(const std::string& strArg, bool fValue)
  {
      if (fValue)
          return SoftSetArg(strArg, std::string("1"));
@@@ -778,6 -711,17 +781,6 @@@ void PrintException(std::exception* pex
      throw;
  }
  
 -void ThreadOneMessageBox(string strMessage)
 -{
 -    // Skip message boxes if one is already open
 -    static bool fMessageBoxOpen;
 -    if (fMessageBoxOpen)
 -        return;
 -    fMessageBoxOpen = true;
 -    ThreadSafeMessageBox(strMessage, "Bitcoin", wxOK | wxICON_EXCLAMATION);
 -    fMessageBoxOpen = false;
 -}
 -
  void PrintExceptionContinue(std::exception* pex, const char* pszThread)
  {
      char pszMessage[10000];
      strMiscWarning = pszMessage;
  }
  
 -
 -
 -
 -
 -
 -
 -
  #ifdef WIN32
 -typedef WINSHELLAPI BOOL (WINAPI *PSHGETSPECIALFOLDERPATHA)(HWND hwndOwner, LPSTR lpszPath, int nFolder, BOOL fCreate);
 -
  string MyGetSpecialFolderPath(int nFolder, bool fCreate)
  {
 -    char pszPath[MAX_PATH+100] = "";
 -
 -    // SHGetSpecialFolderPath isn't always available on old Windows versions
 -    HMODULE hShell32 = LoadLibraryA("shell32.dll");
 -    if (hShell32)
 +    char pszPath[MAX_PATH] = "";
 +    if(SHGetSpecialFolderPathA(NULL, pszPath, nFolder, fCreate))
      {
 -        PSHGETSPECIALFOLDERPATHA pSHGetSpecialFolderPath =
 -            (PSHGETSPECIALFOLDERPATHA)GetProcAddress(hShell32, "SHGetSpecialFolderPathA");
 -        bool fSuccess = false;
 -        if (pSHGetSpecialFolderPath)
 -            fSuccess =
 -            (*pSHGetSpecialFolderPath)(NULL, pszPath, nFolder, fCreate);
 -        FreeModule(hShell32);
 -        if (fSuccess)
 -            return pszPath;
 +        return pszPath;
      }
 -
 -    // Backup option
 -    std::string strPath;
 +    else if (nFolder == CSIDL_STARTUP)
      {
 -        const char *pszEnv;
 -        if (nFolder == CSIDL_STARTUP)
 -        {
 -            pszEnv = getenv("USERPROFILE");
 -            if (pszEnv)
 -                strPath = pszEnv;
 -            strPath += "\\Start Menu\\Programs\\Startup";
 -        }
 -        else if (nFolder == CSIDL_APPDATA)
 -        {
 -            pszEnv = getenv("APPDATA");
 -            if (pszEnv)
 -                strPath = pszEnv;
 -        }
 +        return string(getenv("USERPROFILE")) + "\\Start Menu\\Programs\\Startup";
      }
 -
 -    return strPath;
 +    else if (nFolder == CSIDL_APPDATA)
 +    {
 +        return getenv("APPDATA");
 +    }
 +    return "";
  }
  #endif
  
@@@ -885,28 -861,15 +888,28 @@@ string GetConfigFile(
      return pathConfig.string();
  }
  
 -void ReadConfigFile(map<string, string>& mapSettingsRet,
 +bool ReadConfigFile(map<string, string>& mapSettingsRet,
                      map<string, vector<string> >& mapMultiSettingsRet)
  {
      namespace fs = boost::filesystem;
      namespace pod = boost::program_options::detail;
  
 +    if (mapSettingsRet.count("-datadir"))
 +    {
 +        if (fs::is_directory(fs::system_complete(mapSettingsRet["-datadir"])))
 +        {
 +            fs::path pathDataDir = fs::system_complete(mapSettingsRet["-datadir"]);
 +            strlcpy(pszSetDataDir, pathDataDir.string().c_str(), sizeof(pszSetDataDir));
 +        }
 +        else
 +        {
 +            return false;
 +        }
 +    }
 +
      fs::ifstream streamConfig(GetConfigFile());
      if (!streamConfig.good())
 -        return;
 +        return true; // No bitcoin.conf file is OK
  
      set<string> setOptions;
      setOptions.insert("*");
          // Don't overwrite existing settings so command line settings override bitcoin.conf
          string strKey = string("-") + it->string_key;
          if (mapSettingsRet.count(strKey) == 0)
 +        {
              mapSettingsRet[strKey] = it->value[0];
 +            //  interpret nofoo=1 as foo=0 (and nofoo=0 as foo=1) as long as foo not set)
 +            InterpretNegativeSetting(strKey, mapSettingsRet);
 +        }
          mapMultiSettingsRet[strKey].push_back(it->value[0]);
      }
 +    return true;
  }
  
  string GetPidFile()
@@@ -1012,22 -970,25 +1015,22 @@@ int64 GetAdjustedTime(
      return GetTime() + nTimeOffset;
  }
  
 -void AddTimeData(unsigned int ip, int64 nTime)
 +void AddTimeData(const CNetAddr& ip, int64 nTime)
  {
      int64 nOffsetSample = nTime - GetTime();
  
      // Ignore duplicates
 -    static set<unsigned int> setKnown;
 +    static set<CNetAddr> setKnown;
      if (!setKnown.insert(ip).second)
          return;
  
      // Add data
 -    static vector<int64> vTimeOffsets;
 -    if (vTimeOffsets.empty())
 -        vTimeOffsets.push_back(0);
 -    vTimeOffsets.push_back(nOffsetSample);
 -    printf("Added time data, samples %d, offset %+"PRI64d" (%+"PRI64d" minutes)\n", vTimeOffsets.size(), vTimeOffsets.back(), vTimeOffsets.back()/60);
 +    vTimeOffsets.input(nOffsetSample);
 +    printf("Added time data, samples %d, offset %+"PRI64d" (%+"PRI64d" minutes)\n", vTimeOffsets.size(), nOffsetSample, nOffsetSample/60);
      if (vTimeOffsets.size() >= 5 && vTimeOffsets.size() % 2 == 1)
      {
 -        sort(vTimeOffsets.begin(), vTimeOffsets.end());
 -        int64 nMedian = vTimeOffsets[vTimeOffsets.size()/2];
 +        int64 nMedian = vTimeOffsets.median();
 +        std::vector<int64> vSorted = vTimeOffsets.sorted();
          // Only let other nodes change our time by so much
          if (abs64(nMedian) < 70 * 60)
          {
              {
                  // If nobody has a time different than ours but within 5 minutes of ours, give a warning
                  bool fMatch = false;
 -                BOOST_FOREACH(int64 nOffset, vTimeOffsets)
 +                BOOST_FOREACH(int64 nOffset, vSorted)
                      if (nOffset != 0 && abs64(nOffset) < 5 * 60)
                          fMatch = true;
  
                  }
              }
          }
 -        BOOST_FOREACH(int64 n, vTimeOffsets)
 -            printf("%+"PRI64d"  ", n);
 -        printf("|  nTimeOffset = %+"PRI64d"  (%+"PRI64d" minutes)\n", nTimeOffset, nTimeOffset/60);
 +        if (fDebug) {
 +            BOOST_FOREACH(int64 n, vSorted)
 +                printf("%+"PRI64d"  ", n);
 +            printf("|  ");
 +        }
 +        printf("nTimeOffset = %+"PRI64d"  (%+"PRI64d" minutes)\n", nTimeOffset, nTimeOffset/60);
      }
  }
  
  
  
  
 -
  string FormatVersion(int nVersion)
  {
      if (nVersion%100 == 0)
  
  string FormatFullVersion()
  {
 -    string s = FormatVersion(VERSION) + pszSubVer;
 +    string s = FormatVersion(CLIENT_VERSION);
      if (VERSION_IS_BETA) {
          s += "-";
          s += _("beta");
      return s;
  }
  
 +// Format the subversion field according to BIP 14 spec (https://en.bitcoin.it/wiki/BIP_0014)
 +std::string FormatSubVersion(const std::string& name, int nClientVersion, const std::vector<std::string>& comments)
 +{
 +    std::ostringstream ss;
 +    ss << "/";
 +    ss << name << ":" << FormatVersion(nClientVersion);
 +    if (!comments.empty())
 +        ss << "(" << boost::algorithm::join(comments, "; ") << ")";
 +    ss << "/";
 +    return ss.str();
 +}
  
  
  
@@@ -1207,18 -1155,7 +1210,18 @@@ static void pop_lock(
  void CCriticalSection::Enter(const char* pszName, const char* pszFile, int nLine)
  {
      push_lock(this, CLockLocation(pszName, pszFile, nLine));
 +#ifdef DEBUG_LOCKCONTENTION
 +    bool result = mutex.try_lock();
 +    if (!result)
 +    {
 +        printf("LOCKCONTENTION: %s\n", pszName);
 +        printf("Locker: %s:%d\n", pszFile, nLine);
 +        mutex.lock();
 +        printf("Locked\n");
 +    }
 +#else
      mutex.lock();
 +#endif
  }
  void CCriticalSection::Leave()
  {
@@@ -1235,19 -1172,9 +1238,19 @@@ bool CCriticalSection::TryEnter(const c
  
  #else
  
 -void CCriticalSection::Enter(const char*, const char*, int)
 +void CCriticalSection::Enter(const char* pszName, const char* pszFile, int nLine)
  {
 +#ifdef DEBUG_LOCKCONTENTION
 +    bool result = mutex.try_lock();
 +    if (!result)
 +    {
 +        printf("LOCKCONTENTION: %s\n", pszName);
 +        printf("Locker: %s:%d\n", pszFile, nLine);
 +        mutex.lock();
 +    }
 +#else
      mutex.lock();
 +#endif
  }
  
  void CCriticalSection::Leave()
@@@ -1262,4 -1189,3 +1265,4 @@@ bool CCriticalSection::TryEnter(const c
  }
  
  #endif /* DEBUG_LOCKORDER */
 +