Merge branch '0.6.0.x' into 0.6.x
authorLuke Dashjr <luke-jr+git@utopios.org>
Thu, 14 Jun 2012 18:21:07 +0000 (18:21 +0000)
committerLuke Dashjr <luke-jr+git@utopios.org>
Thu, 14 Jun 2012 18:21:07 +0000 (18:21 +0000)
Conflicts:
.gitignore
src/bitcoinrpc.cpp
src/main.cpp
src/qt/bitcoingui.cpp
src/ui_interface.h
src/util.cpp

1  2 
.gitignore
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/util.cpp

diff --combined .gitignore
@@@ -1,7 -1,7 +1,8 @@@
  src/*.exe
  src/bitcoin
  src/bitcoind
+ src/test_bitcoin
 +src/build.h
  .*.swp
  *.*~*
  *.bak
diff --combined doc/release-process.txt
@@@ -2,7 -2,7 +2,7 @@@
  
  * update (commit) version in sources
    bitcoin-qt.pro
 -  src/main.h      (CLIENT_VERSION : PROTOCOL_VERSION in serialize.h is updated only on protocol changes)
 +  src/version.h
    share/setup.nsi
    doc/README*
  
@@@ -79,7 -79,7 +79,7 @@@
    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
 +  qmake RELEASE=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)
@@@ -98,6 -98,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
@@@ -3,15 -3,10 +3,15 @@@
  // Distributed under the MIT/X11 software license, see the accompanying
  // file COPYING or http://www.opensource.org/licenses/mit-license.php.
  
 -#include "headers.h"
 +#include "main.h"
 +#include "wallet.h"
  #include "db.h"
 +#include "walletdb.h"
  #include "net.h"
  #include "init.h"
 +#include "ui_interface.h"
 +#include "bitcoinrpc.h"
 +
  #undef printf
  #include <boost/asio.hpp>
  #include <boost/filesystem.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>
  #include <boost/filesystem/fstream.hpp>
  typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> SSLStream;
 -#endif
 -#include "json/json_spirit_reader_template.h"
 -#include "json/json_spirit_writer_template.h"
 -#include "json/json_spirit_utils.h"
 +
  #define printf OutputDebugStringF
  // MinGW 3.4.5 gets "fatal error: had to relocate PCH" if the json headers are
  // precompiled in headers.h.  The problem might be when the pch file goes over
@@@ -35,6 -35,8 +35,6 @@@ using namespace boost::asio
  using namespace json_spirit;
  
  void ThreadRPCServer2(void* parg);
 -typedef Value(*rpcfn_type)(const Array& params, bool fHelp);
 -extern map<string, rpcfn_type> mapCallTable;
  
  static std::string strRPCUserColonPass;
  
@@@ -138,7 -140,7 +138,7 @@@ Object blockToJSON(const CBlock& block
  {
      Object result;
      result.push_back(Pair("hash", block.GetHash().GetHex()));
 -    result.push_back(Pair("size", (int)::GetSerializeSize(block, SER_NETWORK)));
 +    result.push_back(Pair("size", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION)));
      result.push_back(Pair("height", blockindex->nHeight));
      result.push_back(Pair("version", block.nVersion));
      result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex()));
  /// Note: This interface may still be subject to change.
  ///
  
 -
 -Value help(const Array& params, bool fHelp)
 +string CRPCTable::help(string strCommand) const
  {
 -    if (fHelp || params.size() > 1)
 -        throw runtime_error(
 -            "help [command]\n"
 -            "List commands, or get help for a command.");
 -
 -    string strCommand;
 -    if (params.size() > 0)
 -        strCommand = params[0].get_str();
 -
      string strRet;
      set<rpcfn_type> setDone;
 -    for (map<string, rpcfn_type>::iterator mi = mapCallTable.begin(); mi != mapCallTable.end(); ++mi)
 +    for (map<string, const CRPCCommand*>::const_iterator mi = mapCommands.begin(); mi != mapCommands.end(); ++mi)
      {
 -        string strMethod = (*mi).first;
 +        const CRPCCommand *pcmd = mi->second;
 +        string strMethod = mi->first;
          // We already filter duplicates, but these deprecated screw up the sort order
          if (strMethod == "getamountreceived" ||
              strMethod == "getallreceived" ||
          try
          {
              Array params;
 -            rpcfn_type pfn = (*mi).second;
 +            rpcfn_type pfn = pcmd->actor;
              if (setDone.insert(pfn).second)
                  (*pfn)(params, true);
          }
      return strRet;
  }
  
 +Value help(const Array& params, bool fHelp)
 +{
 +    if (fHelp || params.size() > 1)
 +        throw runtime_error(
 +            "help [command]\n"
 +            "List commands, or get help for a command.");
 +
 +    string strCommand;
 +    if (params.size() > 0)
 +        strCommand = params[0].get_str();
 +
 +    return tableRPC.help(strCommand);
 +}
 +
  
  Value stop(const Array& params, bool fHelp)
  {
          throw runtime_error(
              "stop\n"
              "Stop bitcoin server.");
 -#ifndef QT_GUI
      // Shutdown will take long enough that the response should get back
-     QueueShutdown();
 -    // 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");
 -#endif
  }
  
  
@@@ -368,7 -370,7 +368,7 @@@ Value getmininginfo(const Array& params
      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("pooledtx",      (uint64_t)mempool.size()));
      obj.push_back(Pair("testnet",       fTestNet));
      return obj;
  }
@@@ -603,7 -605,7 +603,7 @@@ Value signmessage(const Array& params, 
      if (!pwalletMain->GetKey(addr, key))
          throw JSONRPCError(-4, "Private key not available");
  
 -    CDataStream ss(SER_GETHASH);
 +    CDataStream ss(SER_GETHASH, 0);
      ss << strMessageMagic;
      ss << strMessage;
  
@@@ -635,7 -637,7 +635,7 @@@ Value verifymessage(const Array& params
      if (fInvalid)
          throw JSONRPCError(-5, "Malformed base64 encoding");
  
 -    CDataStream ss(SER_GETHASH);
 +    CDataStream ss(SER_GETHASH, 0);
      ss << strMessageMagic;
      ss << strMessage;
  
@@@ -993,6 -995,8 +993,6 @@@ Value addmultisigaddress(const Array& p
              "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();
      // Gather public keys
      if (nRequired < 1)
          throw runtime_error("a multisignature address must require at least one key to redeem");
 -    if (keys.size() < nRequired)
 +    if ((int)keys.size() < nRequired)
          throw runtime_error(
              strprintf("not enough keys supplied "
                        "(got %d keys, but need at least %d to redeem)", keys.size(), nRequired));
@@@ -1335,10 -1339,8 +1335,10 @@@ Value listtransactions(const Array& par
      }
      // ret is newest to oldest
      
 -    if (nFrom > ret.size()) nFrom = ret.size();
 -    if (nFrom+nCount > ret.size()) nCount = ret.size()-nFrom;
 +    if (nFrom > (int)ret.size())
 +        nFrom = ret.size();
 +    if ((nFrom + nCount) > (int)ret.size())
 +        nCount = ret.size() - nFrom;
      Array::iterator first = ret.begin();
      std::advance(first, nFrom);
      Array::iterator last = ret.begin();
@@@ -1669,8 -1671,8 +1669,8 @@@ Value walletlock(const Array& params, b
      if (!pwalletMain->IsCrypted())
          throw JSONRPCError(-15, "Error: running with an unencrypted wallet, but walletlock was called.");
  
 -    CRITICAL_BLOCK(cs_nWalletUnlockTime)
      {
 +        LOCK(cs_nWalletUnlockTime);
          pwalletMain->Lock();
          nWalletUnlockTime = 0;
      }
@@@ -1690,6 -1692,11 +1690,6 @@@ Value encryptwallet(const Array& params
      if (pwalletMain->IsCrypted())
          throw JSONRPCError(-15, "Error: running with an encrypted wallet, but encryptwallet was called.");
  
 -#ifdef QT_GUI
 -    // shutting down via RPC while the GUI is running does not work (yet):
 -    throw runtime_error("Not Yet Implemented: use GUI to encrypt wallet, not RPC command");
 -#endif
 -
      // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
      // Alternately, find a way to make params[0] mlock()'d to begin with.
      SecureString strWalletPass;
      // 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:
-     QueueShutdown();
+     StartShutdown();
      return "wallet encrypted; bitcoin server stopping, restart to run with encrypted wallet";
  }
  
@@@ -1927,7 -1934,7 +1927,7 @@@ Value getmemorypool(const Array& params
              if(tx.IsCoinBase())
                  continue;
  
 -            CDataStream ssTx;
 +            CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
              ssTx << tx;
  
              transactions.push_back(HexStr(ssTx.begin(), ssTx.end()));
      else
      {
          // Parse parameters
 -        CDataStream ssBlock(ParseHex(params[0].get_str()));
 +        CDataStream ssBlock(ParseHex(params[0].get_str()), SER_NETWORK, PROTOCOL_VERSION);
          CBlock pblock;
          ssBlock >> pblock;
  
@@@ -2009,77 -2016,86 +2009,77 @@@ Value getblock(const Array& params, boo
  // Call Table
  //
  
 -pair<string, rpcfn_type> pCallTable[] =
 -{
 -    make_pair("help",                   &help),
 -    make_pair("stop",                   &stop),
 -    make_pair("getblockcount",          &getblockcount),
 -    make_pair("getblocknumber",         &getblocknumber),
 -    make_pair("getconnectioncount",     &getconnectioncount),
 -    make_pair("getdifficulty",          &getdifficulty),
 -    make_pair("getgenerate",            &getgenerate),
 -    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("getaccount",             &getaccount),
 -    make_pair("getaddressesbyaccount",  &getaddressesbyaccount),
 -    make_pair("sendtoaddress",          &sendtoaddress),
 -    make_pair("getreceivedbyaddress",   &getreceivedbyaddress),
 -    make_pair("getreceivedbyaccount",   &getreceivedbyaccount),
 -    make_pair("listreceivedbyaddress",  &listreceivedbyaddress),
 -    make_pair("listreceivedbyaccount",  &listreceivedbyaccount),
 -    make_pair("backupwallet",           &backupwallet),
 -    make_pair("keypoolrefill",          &keypoolrefill),
 -    make_pair("walletpassphrase",       &walletpassphrase),
 -    make_pair("walletpassphrasechange", &walletpassphrasechange),
 -    make_pair("walletlock",             &walletlock),
 -    make_pair("encryptwallet",          &encryptwallet),
 -    make_pair("validateaddress",        &validateaddress),
 -    make_pair("getbalance",             &getbalance),
 -    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("getwork",                &getwork),
 -    make_pair("listaccounts",           &listaccounts),
 -    make_pair("settxfee",               &settxfee),
 -    make_pair("getmemorypool",          &getmemorypool),
 -    make_pair("listsinceblock",         &listsinceblock),
 -    make_pair("dumpprivkey",            &dumpprivkey),
 -    make_pair("importprivkey",          &importprivkey)
 -};
 -map<string, rpcfn_type> mapCallTable(pCallTable, pCallTable + sizeof(pCallTable)/sizeof(pCallTable[0]));
 -
 -string pAllowInSafeMode[] =
 -{
 -    "help",
 -    "stop",
 -    "getblockcount",
 -    "getblocknumber",  // deprecated
 -    "getconnectioncount",
 -    "getdifficulty",
 -    "getgenerate",
 -    "setgenerate",
 -    "gethashespersec",
 -    "getinfo",
 -    "getmininginfo",
 -    "getnewaddress",
 -    "getaccountaddress",
 -    "getaccount",
 -    "getaddressesbyaccount",
 -    "backupwallet",
 -    "keypoolrefill",
 -    "walletpassphrase",
 -    "walletlock",
 -    "validateaddress",
 -    "getwork",
 -    "getmemorypool",
 +
 +static const CRPCCommand vRPCCommands[] =
 +{ //  name                      function                 safe mode?
 +  //  ------------------------  -----------------------  ----------
 +    { "help",                   &help,                   true },
 +    { "stop",                   &stop,                   true },
 +    { "getblockcount",          &getblockcount,          true },
 +    { "getblocknumber",         &getblocknumber,         true },
 +    { "getconnectioncount",     &getconnectioncount,     true },
 +    { "getdifficulty",          &getdifficulty,          true },
 +    { "getgenerate",            &getgenerate,            true },
 +    { "setgenerate",            &setgenerate,            true },
 +    { "gethashespersec",        &gethashespersec,        true },
 +    { "getinfo",                &getinfo,                true },
 +    { "getmininginfo",          &getmininginfo,          true },
 +    { "getnewaddress",          &getnewaddress,          true },
 +    { "getaccountaddress",      &getaccountaddress,      true },
 +    { "setaccount",             &setaccount,             true },
 +    { "getaccount",             &getaccount,             false },
 +    { "getaddressesbyaccount",  &getaddressesbyaccount,  true },
 +    { "sendtoaddress",          &sendtoaddress,          false },
 +    { "getreceivedbyaddress",   &getreceivedbyaddress,   false },
 +    { "getreceivedbyaccount",   &getreceivedbyaccount,   false },
 +    { "listreceivedbyaddress",  &listreceivedbyaddress,  false },
 +    { "listreceivedbyaccount",  &listreceivedbyaccount,  false },
 +    { "backupwallet",           &backupwallet,           true },
 +    { "keypoolrefill",          &keypoolrefill,          true },
 +    { "walletpassphrase",       &walletpassphrase,       true },
 +    { "walletpassphrasechange", &walletpassphrasechange, false },
 +    { "walletlock",             &walletlock,             true },
 +    { "encryptwallet",          &encryptwallet,          false },
 +    { "validateaddress",        &validateaddress,        true },
 +    { "getbalance",             &getbalance,             false },
 +    { "move",                   &movecmd,                false },
 +    { "sendfrom",               &sendfrom,               false },
 +    { "sendmany",               &sendmany,               false },
 +    { "addmultisigaddress",     &addmultisigaddress,     false },
 +    { "getblock",               &getblock,               false },
 +    { "getblockhash",           &getblockhash,           false },
 +    { "gettransaction",         &gettransaction,         false },
 +    { "listtransactions",       &listtransactions,       false },
 +    { "signmessage",            &signmessage,            false },
 +    { "verifymessage",          &verifymessage,          false },
 +    { "getwork",                &getwork,                true },
 +    { "listaccounts",           &listaccounts,           false },
 +    { "settxfee",               &settxfee,               false },
 +    { "getmemorypool",          &getmemorypool,          true },
 +    { "listsinceblock",         &listsinceblock,         false },
 +    { "dumpprivkey",            &dumpprivkey,            false },
 +    { "importprivkey",          &importprivkey,          false },
  };
 -set<string> setAllowInSafeMode(pAllowInSafeMode, pAllowInSafeMode + sizeof(pAllowInSafeMode)/sizeof(pAllowInSafeMode[0]));
  
 +CRPCTable::CRPCTable()
 +{
 +    unsigned int vcidx;
 +    for (vcidx = 0; vcidx < (sizeof(vRPCCommands) / sizeof(vRPCCommands[0])); vcidx++)
 +    {
 +        const CRPCCommand *pcmd;
  
 +        pcmd = &vRPCCommands[vcidx];
 +        mapCommands[pcmd->name] = pcmd;
 +    }
 +}
  
 +const CRPCCommand *CRPCTable::operator[](string name) const
 +{
 +    map<string, const CRPCCommand*>::const_iterator it = mapCommands.find(name);
 +    if (it == mapCommands.end())
 +        return NULL;
 +    return (*it).second;
 +}
  
  //
  // HTTP protocol
@@@ -2207,7 -2223,7 +2207,7 @@@ int ReadHTTP(std::basic_istream<char>& 
  
      // Read header
      int nLen = ReadHTTPHeader(stream, mapHeadersRet);
 -    if (nLen < 0 || nLen > MAX_SIZE)
 +    if (nLen < 0 || nLen > (int)MAX_SIZE)
          return 500;
  
      // Read message
@@@ -2284,6 -2300,7 +2284,6 @@@ bool ClientAllowed(const string& strAdd
      return false;
  }
  
 -#ifdef USE_SSL
  //
  // IOStream device that speaks SSL but can also speak non-SSL
  //
@@@ -2335,6 -2352,7 +2335,6 @@@ private
      bool fUseSSL;
      SSLStream& stream;
  };
 -#endif
  
  void ThreadRPCServer(void* parg)
  {
@@@ -2377,10 -2395,12 +2377,10 @@@ void ThreadRPCServer2(void* parg
                "(you do not need to remember this password)\n"
                "If the file does not exist, create it with owner-readable-only file permissions.\n"),
                  strWhatAmI.c_str(),
 -                GetConfigFile().c_str(),
 +                GetConfigFile().string().c_str(),
                  EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32).c_str()),
              _("Error"), wxOK | wxMODAL);
-         QueueShutdown();
 -#ifndef QT_GUI
+         StartShutdown();
 -#endif
          return;
      }
  
  
      asio::io_service io_service;
      ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", 8332));
 -#ifndef QT_GUI
 -    ip::tcp::acceptor acceptor(io_service, endpoint);
 -
 -    acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
 -#else
      ip::tcp::acceptor acceptor(io_service);
      try
      {
      {
          ThreadSafeMessageBox(strprintf(_("An error occured while setting up the RPC port %i for listening: %s"), endpoint.port(), e.what()),
                               _("Error"), wxOK | wxMODAL);
-         QueueShutdown();
+         StartShutdown();
          return;
      }
 -#endif
  
 -#ifdef USE_SSL
      ssl::context context(io_service, ssl::context::sslv23);
      if (fUseSSL)
      {
          context.set_options(ssl::context::no_sslv2);
 -        filesystem::path certfile = GetArg("-rpcsslcertificatechainfile", "server.cert");
 -        if (!certfile.is_complete()) certfile = filesystem::path(GetDataDir()) / certfile;
 -        if (filesystem::exists(certfile)) context.use_certificate_chain_file(certfile.string().c_str());
 -        else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", certfile.string().c_str());
 -        filesystem::path pkfile = GetArg("-rpcsslprivatekeyfile", "server.pem");
 -        if (!pkfile.is_complete()) pkfile = filesystem::path(GetDataDir()) / pkfile;
 -        if (filesystem::exists(pkfile)) context.use_private_key_file(pkfile.string().c_str(), ssl::context::pem);
 -        else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pkfile.string().c_str());
 -
 -        string ciphers = GetArg("-rpcsslciphers",
 -                                         "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH");
 -        SSL_CTX_set_cipher_list(context.impl(), ciphers.c_str());
 -    }
 -#else
 -    if (fUseSSL)
 -        throw runtime_error("-rpcssl=1, but bitcoin compiled without full openssl libraries.");
 -#endif
 +
 +        filesystem::path pathCertFile(GetArg("-rpcsslcertificatechainfile", "server.cert"));
 +        if (!pathCertFile.is_complete()) pathCertFile = filesystem::path(GetDataDir()) / pathCertFile;
 +        if (filesystem::exists(pathCertFile)) context.use_certificate_chain_file(pathCertFile.string());
 +        else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", pathCertFile.string().c_str());
 +
 +        filesystem::path pathPKFile(GetArg("-rpcsslprivatekeyfile", "server.pem"));
 +        if (!pathPKFile.is_complete()) pathPKFile = filesystem::path(GetDataDir()) / pathPKFile;
 +        if (filesystem::exists(pathPKFile)) context.use_private_key_file(pathPKFile.string(), ssl::context::pem);
 +        else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pathPKFile.string().c_str());
 +
 +        string strCiphers = GetArg("-rpcsslciphers", "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH");
 +        SSL_CTX_set_cipher_list(context.impl(), strCiphers.c_str());
 +    }
  
      loop
      {
          // Accept connection
          SSLStream sslStream(io_service, context);
          SSLIOStreamDevice d(sslStream, fUseSSL);
          iostreams::stream<SSLIOStreamDevice> stream(d);
  
          ip::tcp::endpoint peer;
          vnThreadsRunning[THREAD_RPCSERVER]--;
 -#ifdef USE_SSL
          acceptor.accept(sslStream.lowest_layer(), peer);
 -#else
 -        acceptor.accept(*stream.rdbuf(), peer);
 -#endif
          vnThreadsRunning[4]++;
          if (fShutdown)
              return;
                  throw JSONRPCError(-32600, "Params must be an array");
  
              // Find method
 -            map<string, rpcfn_type>::iterator mi = mapCallTable.find(strMethod);
 -            if (mi == mapCallTable.end())
 +            const CRPCCommand *pcmd = tableRPC[strMethod];
 +            if (!pcmd)
                  throw JSONRPCError(-32601, "Method not found");
  
              // Observe safe mode
              string strWarning = GetWarnings("rpc");
 -            if (strWarning != "" && !GetBoolArg("-disablesafemode") && !setAllowInSafeMode.count(strMethod))
 +            if (strWarning != "" && !GetBoolArg("-disablesafemode") &&
 +                !pcmd->okSafeMode)
                  throw JSONRPCError(-2, string("Safe mode: ") + strWarning);
  
              try
              {
                  // Execute
                  Value result;
 -                CRITICAL_BLOCK(cs_main)
 -                CRITICAL_BLOCK(pwalletMain->cs_wallet)
 -                    result = (*(*mi).second)(params, false);
 +                {
 +                    LOCK2(cs_main, pwalletMain->cs_wallet);
 +                    result = pcmd->actor(params, false);
 +                }
  
                  // Send reply
                  string strReply = JSONRPCReply(result, Value::null, id);
@@@ -2558,10 -2594,11 +2558,10 @@@ Object CallRPC(const string& strMethod
          throw runtime_error(strprintf(
              _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
                "If the file does not exist, create it with owner-readable-only file permissions."),
 -                GetConfigFile().c_str()));
 +                GetConfigFile().string().c_str()));
  
      // Connect to localhost
      bool fUseSSL = GetBoolArg("-rpcssl");
 -#ifdef USE_SSL
      asio::io_service io_service;
      ssl::context context(io_service, ssl::context::sslv23);
      context.set_options(ssl::context::no_sslv2);
      iostreams::stream<SSLIOStreamDevice> stream(d);
      if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332")))
          throw runtime_error("couldn't connect to server");
 -#else
 -    if (fUseSSL)
 -        throw runtime_error("-rpcssl=1, but bitcoin compiled without full openssl libraries.");
 -
 -    ip::tcp::iostream stream(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332"));
 -    if (stream.fail())
 -        throw runtime_error("couldn't connect to server");
 -#endif
 -
  
      // HTTP basic authentication
      string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
@@@ -2767,5 -2813,3 +2767,5 @@@ int main(int argc, char *argv[]
      return 0;
  }
  #endif
 +
 +const CRPCTable tableRPC;
diff --combined src/init.cpp
@@@ -2,20 -2,26 +2,20 @@@
  // 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.
 -#include "headers.h"
  #include "db.h"
 +#include "walletdb.h"
  #include "bitcoinrpc.h"
  #include "net.h"
  #include "init.h"
 -#include "strlcpy.h"
 +#include "util.h"
 +#include "ui_interface.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)
 -#define _BITCOIN_QT_PLUGINS_INCLUDED
 -#define __INSURE__
 -#include <QtPlugin>
 -Q_IMPORT_PLUGIN(qcncodecs)
 -Q_IMPORT_PLUGIN(qjpcodecs)
 -Q_IMPORT_PLUGIN(qtwcodecs)
 -Q_IMPORT_PLUGIN(qkrcodecs)
 -Q_IMPORT_PLUGIN(qtaccessiblewidgets)
 +#ifndef WIN32
 +#include <signal.h>
  #endif
  
  using namespace std;
@@@ -36,18 -42,26 +36,29 @@@ 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;
      static bool fTaken;
      bool fFirstThread = false;
 -    TRY_CRITICAL_BLOCK(cs_Shutdown)
      {
 -        fFirstThread = !fTaken;
 -        fTaken = true;
 +        TRY_LOCK(cs_Shutdown, lockShutdown);
 +        if (lockShutdown)
 +        {
 +            fFirstThread = !fTaken;
 +            fTaken = true;
 +        }
      }
      static bool fExit;
      if (fFirstThread)
          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,12 -167,11 +164,12 @@@ bool AppInit2(int argc, char* argv[]
      // If Qt is used, parameters/bitcoin.conf are parsed in qt/bitcoin.cpp's main()
  #if !defined(QT_GUI)
      ParseParameters(argc, argv);
 -    if (!ReadConfigFile(mapArgs, mapMultiArgs))
 +    if (!boost::filesystem::is_directory(GetDataDir(false)))
      {
          fprintf(stderr, "Error: Specified directory does not exist\n");
          Shutdown(NULL);
      }
 +    ReadConfigFile(mapArgs, mapMultiArgs);
  #endif
  
      if (mapArgs.count("-?") || mapArgs.count("--help"))
              "  -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" +
 +            "  -dblogsize=<n>   \t\t  " + _("Set database disk log size in megabytes (default: 100)") + "\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" +
  #else
              "  -upnp            \t  "   + _("Use Universal Plug and Play to map the listening port (default: 0)") + "\n" +
  #endif
 +            "  -detachdb        \t  "   + _("Detach block and address databases. Increases shutdown time (default: 0)") + "\n" +
  #endif
              "  -paytxfee=<amt>  \t  "   + _("Fee per KB to add to transactions you send") + "\n" +
  #ifdef QT_GUI
              "  -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";
 -#endif
  
          strUsage += string() +
              "  -?               \t\t  " + _("This help message") + "\n";
          strUsage.erase(std::remove(strUsage.begin(), strUsage.end(), '\t'), strUsage.end());
  #if defined(QT_GUI) && defined(WIN32)
          // On windows, show a message box, as there is no stderr
 -        wxMessageBox(strUsage, "Usage");
 +        ThreadSafeMessageBox(strUsage, _("Usage"), wxOK | wxMODAL);
  #else
          fprintf(stderr, "%s", strUsage.c_str());
  #endif
      }
  
      fDebug = GetBoolArg("-debug");
 +    fDetachDB = GetBoolArg("-detachdb", false);
  
  #if !defined(WIN32) && !defined(QT_GUI)
      fDaemon = GetBoolArg("-daemon");
      }
  #endif
  
 -    if (!fDebug && !pszSetDataDir[0])
 +    if (!fDebug)
          ShrinkDebugFile();
      printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
 -    printf("Bitcoin version %s\n", FormatFullVersion().c_str());
 -    printf("Default data directory %s\n", GetDefaultDataDir().c_str());
 +    printf("Bitcoin version %s (%s)\n", FormatFullVersion().c_str(), CLIENT_DATE.c_str());
 +    printf("Default data directory %s\n", GetDefaultDataDir().string().c_str());
  
      if (GetBoolArg("-loadblockindextest"))
      {
      }
  
      // Make sure only a single bitcoin process is using the data directory.
 -    string strLockFile = GetDataDir() + "/.lock";
 -    FILE* file = fopen(strLockFile.c_str(), "a"); // empty lock file; created if it doesn't exist.
 +    boost::filesystem::path pathLockFile = GetDataDir() / ".lock";
 +    FILE* file = fopen(pathLockFile.string().c_str(), "a"); // empty lock file; created if it doesn't exist.
      if (file) fclose(file);
 -    static boost::interprocess::file_lock lock(strLockFile.c_str());
 +    static boost::interprocess::file_lock lock(pathLockFile.string().c_str());
      if (!lock.try_lock())
      {
 -        wxMessageBox(strprintf(_("Cannot obtain a lock on data directory %s.  Bitcoin is probably already running."), GetDataDir().c_str()), "Bitcoin");
 +        ThreadSafeMessageBox(strprintf(_("Cannot obtain a lock on data directory %s.  Bitcoin is probably already running."), GetDataDir().string().c_str()), _("Bitcoin"), wxOK|wxMODAL);
          return false;
      }
  
      nStart = GetTimeMillis();
      if (!LoadBlockIndex())
          strErrors << _("Error loading blkindex.dat") << "\n";
 +
 +    // as LoadBlockIndex can take several minutes, it's possible the user
 +    // requested to kill bitcoin-qt during the last operation. If so, exit.
 +    // As the program has not fully started yet, Shutdown() is possibly overkill.
 +    if (fRequestShutdown)
 +    {
 +        printf("Shutdown requested. Exiting.\n");
 +        return false;
 +    }
      printf(" block index %15"PRI64d"ms\n", GetTimeMillis() - nStart);
  
      InitMessage(_("Loading wallet..."));
          {
              strErrors << _("Wallet needed to be rewritten: restart Bitcoin to complete") << "\n";
              printf("%s", strErrors.str().c_str());
 -            wxMessageBox(strErrors.str(), "Bitcoin", wxOK | wxICON_ERROR);
 +            ThreadSafeMessageBox(strErrors.str(), _("Bitcoin"), wxOK | wxICON_ERROR | wxMODAL);
              return false;
          }
          else
  
      if (!strErrors.str().empty())
      {
 -        wxMessageBox(strErrors.str(), "Bitcoin", wxOK | wxICON_ERROR);
 +        ThreadSafeMessageBox(strErrors.str(), _("Bitcoin"), wxOK | wxICON_ERROR | wxMODAL);
          return false;
      }
  
          addrProxy = CService(mapArgs["-proxy"], 9050);
          if (!addrProxy.IsValid())
          {
 -            wxMessageBox(_("Invalid -proxy address"), "Bitcoin");
 +            ThreadSafeMessageBox(_("Invalid -proxy address"), _("Bitcoin"), wxOK | wxMODAL);
              return false;
          }
      }
          std::string strError;
          if (!BindListenPort(strError))
          {
 -            wxMessageBox(strError, "Bitcoin");
 +            ThreadSafeMessageBox(strError, _("Bitcoin"), wxOK | wxMODAL);
              return false;
          }
      }
      {
          if (!ParseMoney(mapArgs["-paytxfee"], nTransactionFee))
          {
 -            wxMessageBox(_("Invalid amount for -paytxfee=<amount>"), "Bitcoin");
 +            ThreadSafeMessageBox(_("Invalid amount for -paytxfee=<amount>"), _("Bitcoin"), wxOK | wxMODAL);
              return false;
          }
          if (nTransactionFee > 0.25 * COIN)
 -            wxMessageBox(_("Warning: -paytxfee is set very high.  This is the transaction fee you will pay if you send a transaction."), "Bitcoin", wxOK | wxICON_EXCLAMATION);
 +            ThreadSafeMessageBox(_("Warning: -paytxfee is set very high.  This is the transaction fee you will pay if you send a transaction."), _("Bitcoin"), wxOK | wxICON_EXCLAMATION | wxMODAL);
      }
  
      //
      RandAddSeedPerfmon();
  
      if (!CreateThread(StartNode, NULL))
 -        wxMessageBox(_("Error: CreateThread(StartNode) failed"), "Bitcoin");
 +        ThreadSafeMessageBox(_("Error: CreateThread(StartNode) failed"), _("Bitcoin"), wxOK | wxMODAL);
  
      if (fServer)
          CreateThread(ThreadRPCServer, NULL);
  
  #ifdef QT_GUI
 -    if(GetStartOnSystemStartup())
 -        SetStartOnSystemStartup(true); // Remove startup links to bitcoin-wx
 +    if (GetStartOnSystemStartup())
 +        SetStartOnSystemStartup(true); // Remove startup links
  #endif
  
  #if !defined(QT_GUI)
      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
@@@ -5,12 -5,14 +5,13 @@@
  #ifndef BITCOIN_INIT_H
  #define BITCOIN_INIT_H
  
 +#include "wallet.h"
 +
  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
@@@ -3,11 -3,11 +3,11 @@@
  // Distributed under the MIT/X11 software license, see the accompanying
  // file COPYING or http://www.opensource.org/licenses/mit-license.php.
  
 -#include "headers.h"
  #include "checkpoints.h"
  #include "db.h"
  #include "net.h"
  #include "init.h"
 +#include "ui_interface.h"
  #include <boost/algorithm/string/replace.hpp>
  #include <boost/filesystem.hpp>
  #include <boost/filesystem/fstream.hpp>
@@@ -19,13 -19,20 +19,13 @@@ 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;
  
  CCriticalSection cs_main;
  
 -static map<uint256, CTransaction> mapTransactions;
 -CCriticalSection cs_mapTransactions;
 +CTxMemPool mempool;
  unsigned int nTransactionsUpdated = 0;
 -map<COutPoint, CInPoint> mapNextTx;
  
  map<uint256, CBlockIndex*> mapBlockIndex;
  uint256 hashGenesisBlock("0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f");
@@@ -69,16 -76,16 +69,16 @@@ int64 nTransactionFee = 0
  
  void RegisterWallet(CWallet* pwalletIn)
  {
 -    CRITICAL_BLOCK(cs_setpwalletRegistered)
      {
 +        LOCK(cs_setpwalletRegistered);
          setpwalletRegistered.insert(pwalletIn);
      }
  }
  
  void UnregisterWallet(CWallet* pwalletIn)
  {
 -    CRITICAL_BLOCK(cs_setpwalletRegistered)
      {
 +        LOCK(cs_setpwalletRegistered);
          setpwalletRegistered.erase(pwalletIn);
      }
  }
@@@ -196,9 -203,9 +196,9 @@@ void static EraseOrphanTx(uint256 hash
      mapOrphanTransactions.erase(hash);
  }
  
 -int LimitOrphanTxSize(int nMaxOrphans)
 +unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans)
  {
 -    int nEvicted = 0;
 +    unsigned int nEvicted = 0;
      while (mapOrphanTransactions.size() > nMaxOrphans)
      {
          // Evict a random orphan:
@@@ -336,10 -343,10 +336,10 @@@ bool CTransaction::AreInputsStandard(co
      return true;
  }
  
 -int
 +unsigned int
  CTransaction::GetLegacySigOpCount() const
  {
 -    int nSigOps = 0;
 +    unsigned int nSigOps = 0;
      BOOST_FOREACH(const CTxIn& txin, vin)
      {
          nSigOps += txin.scriptSig.GetSigOpCount(false);
@@@ -377,10 -384,10 +377,10 @@@ int CMerkleTx::SetMerkleBranch(const CB
          hashBlock = pblock->GetHash();
  
          // Locate the transaction
 -        for (nIndex = 0; nIndex < pblock->vtx.size(); nIndex++)
 +        for (nIndex = 0; nIndex < (int)pblock->vtx.size(); nIndex++)
              if (pblock->vtx[nIndex] == *(CTransaction*)this)
                  break;
 -        if (nIndex == pblock->vtx.size())
 +        if (nIndex == (int)pblock->vtx.size())
          {
              vMerkleBranch.clear();
              nIndex = -1;
@@@ -417,7 -424,7 +417,7 @@@ bool CTransaction::CheckTransaction() c
      if (vout.empty())
          return DoS(10, error("CTransaction::CheckTransaction() : vout empty"));
      // Size limits
 -    if (::GetSerializeSize(*this, SER_NETWORK) > MAX_BLOCK_SIZE)
 +    if (::GetSerializeSize(*this, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE)
          return DoS(100, error("CTransaction::CheckTransaction() : size limits failed"));
  
      // Check for negative or overflow output values
      return true;
  }
  
 -bool CTransaction::AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs, bool* pfMissingInputs)
 +bool CTxMemPool::accept(CTxDB& txdb, CTransaction &tx, bool fCheckInputs,
 +                        bool* pfMissingInputs)
  {
      if (pfMissingInputs)
          *pfMissingInputs = false;
  
 -    if (!CheckTransaction())
 -        return error("AcceptToMemoryPool() : CheckTransaction failed");
 +    if (!tx.CheckTransaction())
 +        return error("CTxMemPool::accept() : CheckTransaction failed");
  
      // Coinbase is only valid in a block, not as a loose transaction
 -    if (IsCoinBase())
 -        return DoS(100, error("AcceptToMemoryPool() : coinbase as individual tx"));
 +    if (tx.IsCoinBase())
 +        return tx.DoS(100, error("CTxMemPool::accept() : coinbase as individual tx"));
  
      // To help v0.1.5 clients who would see it as a negative number
 -    if ((int64)nLockTime > std::numeric_limits<int>::max())
 -        return error("AcceptToMemoryPool() : not accepting nLockTime beyond 2038 yet");
 +    if ((int64)tx.nLockTime > std::numeric_limits<int>::max())
 +        return error("CTxMemPool::accept() : not accepting nLockTime beyond 2038 yet");
  
      // Rather not work on nonstandard transactions (unless -testnet)
 -    if (!fTestNet && !IsStandard())
 -        return error("AcceptToMemoryPool() : nonstandard transaction type");
 +    if (!fTestNet && !tx.IsStandard())
 +        return error("CTxMemPool::accept() : nonstandard transaction type");
  
      // Do we already have it?
 -    uint256 hash = GetHash();
 -    CRITICAL_BLOCK(cs_mapTransactions)
 -        if (mapTransactions.count(hash))
 +    uint256 hash = tx.GetHash();
 +    {
 +        LOCK(cs);
 +        if (mapTx.count(hash))
              return false;
 +    }
      if (fCheckInputs)
          if (txdb.ContainsTx(hash))
              return false;
  
      // Check for conflicts with in-memory transactions
      CTransaction* ptxOld = NULL;
 -    for (unsigned int i = 0; i < vin.size(); i++)
 +    for (unsigned int i = 0; i < tx.vin.size(); i++)
      {
 -        COutPoint outpoint = vin[i].prevout;
 +        COutPoint outpoint = tx.vin[i].prevout;
          if (mapNextTx.count(outpoint))
          {
              // Disable replacement feature for now
              ptxOld = mapNextTx[outpoint].ptx;
              if (ptxOld->IsFinal())
                  return false;
 -            if (!IsNewerThan(*ptxOld))
 +            if (!tx.IsNewerThan(*ptxOld))
                  return false;
 -            for (unsigned int i = 0; i < vin.size(); i++)
 +            for (unsigned int i = 0; i < tx.vin.size(); i++)
              {
 -                COutPoint outpoint = vin[i].prevout;
 +                COutPoint outpoint = tx.vin[i].prevout;
                  if (!mapNextTx.count(outpoint) || mapNextTx[outpoint].ptx != ptxOld)
                      return false;
              }
          MapPrevTx mapInputs;
          map<uint256, CTxIndex> mapUnused;
          bool fInvalid = false;
 -        if (!FetchInputs(txdb, mapUnused, false, false, mapInputs, fInvalid))
 +        if (!tx.FetchInputs(txdb, mapUnused, false, false, mapInputs, fInvalid))
          {
              if (fInvalid)
 -                return error("AcceptToMemoryPool() : FetchInputs found invalid tx %s", hash.ToString().substr(0,10).c_str());
 +                return error("CTxMemPool::accept() : FetchInputs found invalid tx %s", hash.ToString().substr(0,10).c_str());
              if (pfMissingInputs)
                  *pfMissingInputs = true;
 -            return error("AcceptToMemoryPool() : FetchInputs failed %s", hash.ToString().substr(0,10).c_str());
 +            return error("CTxMemPool::accept() : FetchInputs failed %s", hash.ToString().substr(0,10).c_str());
          }
  
          // Check for non-standard pay-to-script-hash in inputs
 -        if (!AreInputsStandard(mapInputs) && !fTestNet)
 -            return error("AcceptToMemoryPool() : nonstandard transaction input");
 +        if (!tx.AreInputsStandard(mapInputs) && !fTestNet)
 +            return error("CTxMemPool::accept() : 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);
 +        int64 nFees = tx.GetValueIn(mapInputs)-tx.GetValueOut();
 +        unsigned int nSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
  
          // Don't accept it if it can't get into a block
 -        if (nFees < GetMinFee(1000, true, GMF_RELAY))
 -            return error("AcceptToMemoryPool() : not enough fees");
 +        if (nFees < tx.GetMinFee(1000, true, GMF_RELAY))
 +            return error("CTxMemPool::accept() : not enough fees");
  
          // Continuously rate-limit free transactions
          // This mitigates 'penny-flooding' -- sending thousands of free transactions just to
              static int64 nLastTime;
              int64 nNow = GetTime();
  
 -            CRITICAL_BLOCK(cs)
              {
 +                LOCK(cs);
                  // Use an exponentially decaying ~10-minute window:
                  dFreeCount *= pow(1.0 - 1.0/600.0, (double)(nNow - nLastTime));
                  nLastTime = nNow;
                  // -limitfreerelay unit is thousand-bytes-per-minute
                  // At default rate it would take over a month to fill 1GB
 -                if (dFreeCount > GetArg("-limitfreerelay", 15)*10*1000 && !IsFromMe(*this))
 -                    return error("AcceptToMemoryPool() : free transaction rejected by rate limiter");
 +                if (dFreeCount > GetArg("-limitfreerelay", 15)*10*1000 && !IsFromMe(tx))
 +                    return error("CTxMemPool::accept() : free transaction rejected by rate limiter");
                  if (fDebug)
                      printf("Rate limit dFreeCount: %g => %g\n", dFreeCount, dFreeCount+nSize);
                  dFreeCount += nSize;
  
          // Check against previous transactions
          // This is done last to help prevent CPU exhaustion denial-of-service attacks.
 -        if (!ConnectInputs(mapInputs, mapUnused, CDiskTxPos(1,1,1), pindexBest, false, false))
 +        if (!tx.ConnectInputs(mapInputs, mapUnused, CDiskTxPos(1,1,1), pindexBest, false, false))
          {
 -            return error("AcceptToMemoryPool() : ConnectInputs failed %s", hash.ToString().substr(0,10).c_str());
 +            return error("CTxMemPool::accept() : ConnectInputs failed %s", hash.ToString().substr(0,10).c_str());
          }
      }
  
      // Store transaction in memory
 -    CRITICAL_BLOCK(cs_mapTransactions)
      {
 +        LOCK(cs);
          if (ptxOld)
          {
 -            printf("AcceptToMemoryPool() : replacing tx %s with new version\n", ptxOld->GetHash().ToString().c_str());
 -            ptxOld->RemoveFromMemoryPool();
 +            printf("CTxMemPool::accept() : replacing tx %s with new version\n", ptxOld->GetHash().ToString().c_str());
 +            remove(*ptxOld);
          }
 -        AddToMemoryPoolUnchecked();
 +        addUnchecked(tx);
      }
  
      ///// are we sure this is ok when loading transactions or restoring block txes
      if (ptxOld)
          EraseFromWallets(ptxOld->GetHash());
  
 -    printf("AcceptToMemoryPool(): accepted %s\n", hash.ToString().substr(0,10).c_str());
 +    printf("CTxMemPool::accept() : accepted %s\n", hash.ToString().substr(0,10).c_str());
      return true;
  }
  
 -bool CTransaction::AcceptToMemoryPool(bool fCheckInputs, bool* pfMissingInputs)
 +bool CTransaction::AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs, bool* pfMissingInputs)
  {
 -    CTxDB txdb("r");
 -    return AcceptToMemoryPool(txdb, fCheckInputs, pfMissingInputs);
 +    return mempool.accept(txdb, *this, fCheckInputs, pfMissingInputs);
  }
  
 -uint64 nPooledTx = 0;
 -
 -bool CTransaction::AddToMemoryPoolUnchecked()
 +bool CTxMemPool::addUnchecked(CTransaction &tx)
  {
 -    printf("AcceptToMemoryPoolUnchecked(): size %lu\n",  mapTransactions.size());
 +    printf("addUnchecked(): size %lu\n",  mapTx.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)
 +    // call CTxMemPool::accept to properly check the transaction first.
      {
 -        uint256 hash = GetHash();
 -        mapTransactions[hash] = *this;
 -        for (unsigned int i = 0; i < vin.size(); i++)
 -            mapNextTx[vin[i].prevout] = CInPoint(&mapTransactions[hash], i);
 +        LOCK(cs);
 +        uint256 hash = tx.GetHash();
 +        mapTx[hash] = tx;
 +        for (unsigned int i = 0; i < tx.vin.size(); i++)
 +            mapNextTx[tx.vin[i].prevout] = CInPoint(&mapTx[hash], i);
          nTransactionsUpdated++;
 -        ++nPooledTx;
      }
      return true;
  }
  
  
 -bool CTransaction::RemoveFromMemoryPool()
 +bool CTxMemPool::remove(CTransaction &tx)
  {
      // Remove transaction from memory pool
 -    CRITICAL_BLOCK(cs_mapTransactions)
      {
 -        uint256 hash = GetHash();
 -        if (mapTransactions.count(hash))
 +        LOCK(cs);
 +        uint256 hash = tx.GetHash();
 +        if (mapTx.count(hash))
          {
 -            BOOST_FOREACH(const CTxIn& txin, vin)
 +            BOOST_FOREACH(const CTxIn& txin, tx.vin)
                  mapNextTx.erase(txin.prevout);
 -            mapTransactions.erase(hash);
 +            mapTx.erase(hash);
              nTransactionsUpdated++;
 -            --nPooledTx;
          }
      }
      return true;
@@@ -701,16 -710,15 +701,16 @@@ bool CMerkleTx::AcceptToMemoryPool(
  
  bool CWalletTx::AcceptWalletTransaction(CTxDB& txdb, bool fCheckInputs)
  {
 -    CRITICAL_BLOCK(cs_mapTransactions)
 +
      {
 +        LOCK(mempool.cs);
          // Add previous supporting transactions first
          BOOST_FOREACH(CMerkleTx& tx, vtxPrev)
          {
              if (!tx.IsCoinBase())
              {
                  uint256 hash = tx.GetHash();
 -                if (!mapTransactions.count(hash) && !txdb.ContainsTx(hash))
 +                if (!mempool.exists(hash) && !txdb.ContainsTx(hash))
                      tx.AcceptToMemoryPool(txdb, fCheckInputs);
              }
          }
@@@ -1024,11 -1032,11 +1024,11 @@@ bool CTransaction::FetchInputs(CTxDB& t
          if (!fFound || txindex.pos == CDiskTxPos(1,1,1))
          {
              // Get prev tx from single transactions in memory
 -            CRITICAL_BLOCK(cs_mapTransactions)
              {
 -                if (!mapTransactions.count(prevout.hash))
 -                    return error("FetchInputs() : %s mapTransactions prev not found %s", GetHash().ToString().substr(0,10).c_str(),  prevout.hash.ToString().substr(0,10).c_str());
 -                txPrev = mapTransactions[prevout.hash];
 +                LOCK(mempool.cs);
 +                if (!mempool.exists(prevout.hash))
 +                    return error("FetchInputs() : %s mempool Tx prev not found %s", GetHash().ToString().substr(0,10).c_str(),  prevout.hash.ToString().substr(0,10).c_str());
 +                txPrev = mempool.lookup(prevout.hash);
              }
              if (!fFound)
                  txindex.vSpent.resize(txPrev.vout.size());
@@@ -1087,12 -1095,12 +1087,12 @@@ int64 CTransaction::GetValueIn(const Ma
  
  }
  
 -int CTransaction::GetP2SHSigOpCount(const MapPrevTx& inputs) const
 +unsigned int CTransaction::GetP2SHSigOpCount(const MapPrevTx& inputs) const
  {
      if (IsCoinBase())
          return 0;
  
 -    int nSigOps = 0;
 +    unsigned int nSigOps = 0;
      for (unsigned int i = 0; i < vin.size(); i++)
      {
          const CTxOut& prevout = GetOutputFor(vin[i], inputs);
@@@ -1190,16 -1198,16 +1190,16 @@@ bool CTransaction::ClientConnectInputs(
          return false;
  
      // Take over previous transactions' spent pointers
 -    CRITICAL_BLOCK(cs_mapTransactions)
      {
 +        LOCK(mempool.cs);
          int64 nValueIn = 0;
          for (unsigned int i = 0; i < vin.size(); i++)
          {
              // Get prev tx from single transactions in memory
              COutPoint prevout = vin[i].prevout;
 -            if (!mapTransactions.count(prevout.hash))
 +            if (!mempool.exists(prevout.hash))
                  return false;
 -            CTransaction& txPrev = mapTransactions[prevout.hash];
 +            CTransaction& txPrev = mempool.lookup(prevout.hash);
  
              if (prevout.n >= txPrev.vout.size())
                  return false;
              if (!VerifySignature(txPrev, *this, i, true, 0))
                  return error("ConnectInputs() : VerifySignature failed");
  
 -            ///// this is redundant with the mapNextTx stuff, not sure which I want to get rid of
 +            ///// this is redundant with the mempool.mapNextTx stuff,
 +            ///// not sure which I want to get rid of
              ///// this has to go away now that posNext is gone
              // // Check for conflicts
              // if (!txPrev.vout[prevout.n].posNext.IsNull())
@@@ -1288,11 -1295,11 +1288,11 @@@ bool CBlock::ConnectBlock(CTxDB& txdb, 
      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());
 +    unsigned int nTxPos = pindex->nBlockPos + ::GetSerializeSize(CBlock(), SER_DISK, CLIENT_VERSION) - 1 + GetSizeOfCompactSize(vtx.size());
  
      map<uint256, CTxIndex> mapQueuedChanges;
      int64 nFees = 0;
 -    int nSigOps = 0;
 +    unsigned int nSigOps = 0;
      BOOST_FOREACH(CTransaction& tx, vtx)
      {
          nSigOps += tx.GetLegacySigOpCount();
              return DoS(100, error("ConnectBlock() : too many sigops"));
  
          CDiskTxPos posThisTx(pindex->nFile, pindex->nBlockPos, nTxPos);
 -        nTxPos += ::GetSerializeSize(tx, SER_DISK);
 +        nTxPos += ::GetSerializeSize(tx, SER_DISK, CLIENT_VERSION);
  
          MapPrevTx mapInputs;
          if (!tx.IsCoinBase())
@@@ -1445,7 -1452,7 +1445,7 @@@ bool static Reorganize(CTxDB& txdb, CBl
  
      // Delete redundant memory transactions that are in the connected branch
      BOOST_FOREACH(CTransaction& tx, vDelete)
 -        tx.RemoveFromMemoryPool();
 +        mempool.remove(tx);
  
      printf("REORGANIZE: done\n");
  
@@@ -1481,7 -1488,7 +1481,7 @@@ bool CBlock::SetBestChainInner(CTxDB& t
  
      // Delete redundant memory transactions
      BOOST_FOREACH(CTransaction& tx, vtx)
 -        tx.RemoveFromMemoryPool();
 +        mempool.remove(tx);
  
      return true;
  }
@@@ -1636,7 -1643,7 +1636,7 @@@ bool CBlock::CheckBlock() cons
      // that can be verified before saving an orphan block.
  
      // Size limits
 -    if (vtx.empty() || vtx.size() > MAX_BLOCK_SIZE || ::GetSerializeSize(*this, SER_NETWORK) > MAX_BLOCK_SIZE)
 +    if (vtx.empty() || vtx.size() > MAX_BLOCK_SIZE || ::GetSerializeSize(*this, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE)
          return DoS(100, error("CheckBlock() : size limits failed"));
  
      // Check proof of work matches claimed amount
      if (uniqueTx.size() != vtx.size())
          return DoS(100, error("CheckBlock() : duplicate transaction"));
  
 -    int nSigOps = 0;
 +    unsigned int nSigOps = 0;
      BOOST_FOREACH(const CTransaction& tx, vtx)
      {
          nSigOps += tx.GetLegacySigOpCount();
@@@ -1716,7 -1723,7 +1716,7 @@@ bool CBlock::AcceptBlock(
          return DoS(100, error("AcceptBlock() : rejected by checkpoint lockin at %d", nHeight));
  
      // Write block to history file
 -    if (!CheckDiskSpace(::GetSerializeSize(*this, SER_DISK)))
 +    if (!CheckDiskSpace(::GetSerializeSize(*this, SER_DISK, CLIENT_VERSION)))
          return error("AcceptBlock() : out of disk space");
      unsigned int nFile = -1;
      unsigned int nBlockPos = 0;
      // Relay inventory, but don't relay old inventory during initial block download
      int nBlockEstimate = Checkpoints::GetTotalBlocksEstimate();
      if (hashBestChain == hash)
 -        CRITICAL_BLOCK(cs_vNodes)
 -            BOOST_FOREACH(CNode* pnode, vNodes)
 -                if (nBestHeight > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : nBlockEstimate))
 -                    pnode->PushInventory(CInv(MSG_BLOCK, hash));
 +    {
 +        LOCK(cs_vNodes);
 +        BOOST_FOREACH(CNode* pnode, vNodes)
 +            if (nBestHeight > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : nBlockEstimate))
 +                pnode->PushInventory(CInv(MSG_BLOCK, hash));
 +    }
  
      return true;
  }
@@@ -1834,8 -1839,8 +1834,8 @@@ bool CheckDiskSpace(uint64 nAdditionalB
          string strMessage = _("Warning: Disk space is low");
          strMiscWarning = strMessage;
          printf("*** %s\n", strMessage.c_str());
 -        ThreadSafeMessageBox(strMessage, "Bitcoin", wxOK | wxICON_EXCLAMATION);
 +        ThreadSafeMessageBox(strMessage, "Bitcoin", wxOK | wxICON_EXCLAMATION | wxMODAL);
-         QueueShutdown();
+         StartShutdown();
          return false;
      }
      return true;
@@@ -1845,7 -1850,7 +1845,7 @@@ FILE* OpenBlockFile(unsigned int nFile
  {
      if (nFile == -1)
          return NULL;
 -    FILE* file = fopen(strprintf("%s/blk%04d.dat", GetDataDir().c_str(), nFile).c_str(), pszMode);
 +    FILE* file = fopen((GetDataDir() / strprintf("blk%04d.dat", nFile)).string().c_str(), pszMode);
      if (!file)
          return NULL;
      if (nBlockPos != 0 && !strchr(pszMode, 'a') && !strchr(pszMode, 'w'))
@@@ -2075,8 -2080,8 +2075,8 @@@ string GetWarnings(string strFor
      }
  
      // Alerts
 -    CRITICAL_BLOCK(cs_mapAlerts)
      {
 +        LOCK(cs_mapAlerts);
          BOOST_FOREACH(PAIRTYPE(const uint256, CAlert)& item, mapAlerts)
          {
              const CAlert& alert = item.second;
@@@ -2103,8 -2108,8 +2103,8 @@@ bool CAlert::ProcessAlert(
      if (!IsInEffect())
          return false;
  
 -    CRITICAL_BLOCK(cs_mapAlerts)
      {
 +        LOCK(cs_mapAlerts);
          // Cancel previous alerts
          for (map<uint256, CAlert>::iterator mi = mapAlerts.begin(); mi != mapAlerts.end();)
          {
@@@ -2163,18 -2168,16 +2163,18 @@@ bool static AlreadyHave(CTxDB& txdb, co
      case MSG_TX:
          {
          bool txInMap = false;
 -        CRITICAL_BLOCK(cs_mapTransactions)
 -        {
 -            txInMap = (mapTransactions.count(inv.hash) != 0);
 -        }
 +            {
 +            LOCK(mempool.cs);
 +            txInMap = (mempool.exists(inv.hash));
 +            }
          return txInMap ||
                 mapOrphanTransactions.count(inv.hash) ||
                 txdb.ContainsTx(inv.hash);
          }
  
 -    case MSG_BLOCK: return mapBlockIndex.count(inv.hash) || mapOrphanBlocks.count(inv.hash);
 +    case MSG_BLOCK:
 +        return mapBlockIndex.count(inv.hash) ||
 +               mapOrphanBlocks.count(inv.hash);
      }
      // Don't know what it is, just say we already got one
      return true;
@@@ -2221,7 -2224,7 +2221,7 @@@ bool static ProcessMessage(CNode* pfrom
          CAddress addrFrom;
          uint64 nNonce = 1;
          vRecv >> pfrom->nVersion >> pfrom->nServices >> nTime >> addrMe;
 -        if (pfrom->nVersion < 209)
 +        if (pfrom->nVersion < MIN_PROTO_VERSION)
          {
              // Since February 20, 2012, the protocol is initiated at version 209,
              // and earlier versions are no longer supported
              }
  
              // Get recent addresses
 -            if (pfrom->nVersion >= 31402 || addrman.size() < 1000)
 +            if (pfrom->nVersion >= CADDR_TIME_VERSION || addrman.size() < 1000)
              {
                  pfrom->PushMessage("getaddr");
                  pfrom->fGetAddr = true;
          // Ask the first connected node for block updates
          static int nAskedForBlocks = 0;
          if (!pfrom->fClient &&
 -            (pfrom->nVersion < 32000 || pfrom->nVersion >= 32400) &&
 +            (pfrom->nVersion < NOBLKS_VERSION_START ||
 +             pfrom->nVersion >= NOBLKS_VERSION_END) &&
               (nAskedForBlocks < 1 || vNodes.size() <= 1))
          {
              nAskedForBlocks++;
          }
  
          // Relay alerts
 -        CRITICAL_BLOCK(cs_mapAlerts)
 +        {
 +            LOCK(cs_mapAlerts);
              BOOST_FOREACH(PAIRTYPE(const uint256, CAlert)& item, mapAlerts)
                  item.second.RelayTo(pfrom);
 +        }
  
          pfrom->fSuccessfullyConnected = true;
  
          vRecv >> vAddr;
  
          // Don't want addr from older versions unless seeding
 -        if (pfrom->nVersion < 31402 && addrman.size() > 1000)
 +        if (pfrom->nVersion < CADDR_TIME_VERSION && addrman.size() > 1000)
              return true;
          if (vAddr.size() > 1000)
          {
              if (addr.nTime > nSince && !pfrom->fGetAddr && vAddr.size() <= 10 && addr.IsRoutable())
              {
                  // Relay to a limited number of other nodes
 -                CRITICAL_BLOCK(cs_vNodes)
                  {
 +                    LOCK(cs_vNodes);
                      // Use deterministic randomness to send to the same nodes for 24 hours
                      // at a time so the setAddrKnowns of the chosen nodes prevent repeats
                      static uint256 hashSalt;
                      multimap<uint256, CNode*> mapMix;
                      BOOST_FOREACH(CNode* pnode, vNodes)
                      {
 -                        if (pnode->nVersion < 31402)
 +                        if (pnode->nVersion < CADDR_TIME_VERSION)
                              continue;
                          unsigned int nPointer;
                          memcpy(&nPointer, &pnode, sizeof(nPointer));
              else if (inv.IsKnownType())
              {
                  // Send stream from relay memory
 -                CRITICAL_BLOCK(cs_mapRelay)
                  {
 +                    LOCK(cs_mapRelay);
                      map<CInv, CDataStream>::iterator mi = mapRelay.find(inv);
                      if (mi != mapRelay.end())
                          pfrom->PushMessage(inv.GetCommand(), (*mi).second);
              pfrom->PushInventory(CInv(MSG_BLOCK, pindex->GetBlockHash()));
              CBlock block;
              block.ReadFromDisk(pindex, true);
 -            nBytes += block.GetSerializeSize(SER_NETWORK);
 +            nBytes += block.GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION);
              if (--nLimit <= 0 || nBytes >= SendBufferSize()/2)
              {
                  // When this block is requested, we'll send an inv that'll make them
          }
  
          vector<CBlock> vHeaders;
 -        int nLimit = 2000 + locator.GetDistanceBack();
 -        printf("getheaders %d to %s limit %d\n", (pindex ? pindex->nHeight : -1), hashStop.ToString().substr(0,20).c_str(), nLimit);
 +        int nLimit = 2000;
 +        printf("getheaders %d to %s\n", (pindex ? pindex->nHeight : -1), hashStop.ToString().substr(0,20).c_str());
          for (; pindex; pindex = pindex->pnext)
          {
              vHeaders.push_back(pindex->GetBlockHeader());
      {
          vector<uint256> vWorkQueue;
          CDataStream vMsg(vRecv);
 +        CTxDB txdb("r");
          CTransaction tx;
          vRecv >> tx;
  
          pfrom->AddInventoryKnown(inv);
  
          bool fMissingInputs = false;
 -        if (tx.AcceptToMemoryPool(true, &fMissingInputs))
 +        if (tx.AcceptToMemoryPool(txdb, true, &fMissingInputs))
          {
              SyncWithWallets(tx, NULL, true);
              RelayMessage(inv, vMsg);
                      CDataStream(vMsg) >> tx;
                      CInv inv(MSG_TX, tx.GetHash());
  
 -                    if (tx.AcceptToMemoryPool(true))
 +                    if (tx.AcceptToMemoryPool(txdb, true))
                      {
                          printf("   accepted orphan tx %s\n", inv.hash.ToString().substr(0,10).c_str());
                          SyncWithWallets(tx, NULL, true);
              AddOrphanTx(vMsg);
  
              // DoS prevention: do not allow mapOrphanTransactions to grow unbounded
 -            int nEvicted = LimitOrphanTxSize(MAX_ORPHAN_TRANSACTIONS);
 +            unsigned int nEvicted = LimitOrphanTxSize(MAX_ORPHAN_TRANSACTIONS);
              if (nEvicted > 0)
 -                printf("mapOrphan overflow, removed %d tx\n", nEvicted);
 +                printf("mapOrphan overflow, removed %u tx\n", nEvicted);
          }
          if (tx.nDoS) pfrom->Misbehaving(tx.nDoS);
      }
          vRecv >> hashReply;
  
          CRequestTracker tracker;
 -        CRITICAL_BLOCK(pfrom->cs_mapRequests)
          {
 +            LOCK(pfrom->cs_mapRequests);
              map<uint256, CRequestTracker>::iterator mi = pfrom->mapRequests.find(hashReply);
              if (mi != pfrom->mapRequests.end())
              {
  
      else if (strCommand == "ping")
      {
 +        if (pfrom->nVersion > BIP0031_VERSION)
 +        {
 +            uint64 nonce = 0;
 +            vRecv >> nonce;
 +            // Echo the message back with the nonce. This allows for two useful features:
 +            //
 +            // 1) A remote node can quickly check if the connection is operational
 +            // 2) Remote nodes can measure the latency of the network thread. If this node
 +            //    is overloaded it won't respond to pings quickly and the remote node can
 +            //    avoid sending us more work, like chain download requests.
 +            //
 +            // The nonce stops the remote getting confused between different pings: without
 +            // it, if the remote node sends a ping once per second and this node takes 5
 +            // seconds to respond to each, the 5th ping the remote sends would appear to
 +            // return very quickly.
 +            pfrom->PushMessage("pong", nonce);
 +        }
      }
  
  
          {
              // Relay
              pfrom->setKnown.insert(alert.GetHash());
 -            CRITICAL_BLOCK(cs_vNodes)
 +            {
 +                LOCK(cs_vNodes);
                  BOOST_FOREACH(CNode* pnode, vNodes)
                      alert.RelayTo(pnode);
 +            }
          }
      }
  
@@@ -2781,7 -2761,7 +2781,7 @@@ bool ProcessMessages(CNode* pfrom
          int nHeaderSize = vRecv.GetSerializeSize(CMessageHeader());
          if (vRecv.end() - pstart < nHeaderSize)
          {
 -            if (vRecv.size() > nHeaderSize)
 +            if ((int)vRecv.size() > nHeaderSize)
              {
                  printf("\n\nPROCESSMESSAGE MESSAGESTART NOT FOUND\n\n");
                  vRecv.erase(vRecv.begin(), vRecv.end() - nHeaderSize);
          bool fRet = false;
          try
          {
 -            CRITICAL_BLOCK(cs_main)
 +            {
 +                LOCK(cs_main);
                  fRet = ProcessMessage(pfrom, strCommand, vMsg);
 +            }
              if (fShutdown)
                  return true;
          }
  
  bool SendMessages(CNode* pto, bool fSendTrickle)
  {
 -    TRY_CRITICAL_BLOCK(cs_main)
 -    {
 +    TRY_LOCK(cs_main, lockMain);
 +    if (lockMain) {
          // Don't send anything until we get their version message
          if (pto->nVersion == 0)
              return true;
  
 -        // Keep-alive ping
 -        if (pto->nLastSend && GetTime() - pto->nLastSend > 30 * 60 && pto->vSend.empty())
 -            pto->PushMessage("ping");
 +        // Keep-alive ping. We send a nonce of zero because we don't use it anywhere 
 +        // right now.
 +        if (pto->nLastSend && GetTime() - pto->nLastSend > 30 * 60 && pto->vSend.empty()) {
 +            uint64 nonce = 0;
 +            if (pto->nVersion > BIP0031_VERSION)
 +                pto->PushMessage("ping", nonce);
 +            else
 +                pto->PushMessage("ping");
 +        }
  
          // Resend wallet transactions that haven't gotten in a block yet
          ResendWalletTransactions();
          static int64 nLastRebroadcast;
          if (!IsInitialBlockDownload() && (GetTime() - nLastRebroadcast > 24 * 60 * 60))
          {
 -            CRITICAL_BLOCK(cs_vNodes)
              {
 +                LOCK(cs_vNodes);
                  BOOST_FOREACH(CNode* pnode, vNodes)
                  {
                      // Periodically clear setAddrKnown to allow refresh broadcasts
          //
          vector<CInv> vInv;
          vector<CInv> vInvWait;
 -        CRITICAL_BLOCK(pto->cs_inventory)
          {
 +            LOCK(pto->cs_inventory);
              vInv.reserve(pto->vInventoryToSend.size());
              vInvWait.reserve(pto->vInventoryToSend.size());
              BOOST_FOREACH(const CInv& inv, pto->vInventoryToSend)
@@@ -3116,7 -3088,7 +3116,7 @@@ unsigned int static ScanHash_CryptoPP(c
          if ((nNonce & 0xffff) == 0)
          {
              nHashesDone = 0xffff+1;
 -            return -1;
 +            return (unsigned int) -1;
          }
      }
  }
@@@ -3168,15 -3140,16 +3168,15 @@@ CBlock* CreateNewBlock(CReserveKey& res
  
      // Collect memory pool transactions into the block
      int64 nFees = 0;
 -    CRITICAL_BLOCK(cs_main)
 -    CRITICAL_BLOCK(cs_mapTransactions)
      {
 +        LOCK2(cs_main, mempool.cs);
          CTxDB txdb("r");
  
          // Priority order to process transactions
          list<COrphan> vOrphan; // list memory doesn't move
          map<uint256, vector<COrphan*> > mapDependers;
          multimap<double, CTransaction*> mapPriority;
 -        for (map<uint256, CTransaction>::iterator mi = mapTransactions.begin(); mi != mapTransactions.end(); ++mi)
 +        for (map<uint256, CTransaction>::iterator mi = mempool.mapTx.begin(); mi != mempool.mapTx.end(); ++mi)
          {
              CTransaction& tx = (*mi).second;
              if (tx.IsCoinBase() || !tx.IsFinal())
              }
  
              // Priority is sum(valuein * age) / txsize
 -            dPriority /= ::GetSerializeSize(tx, SER_NETWORK);
 +            dPriority /= ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
  
              if (porphan)
                  porphan->dPriority = dPriority;
              mapPriority.erase(mapPriority.begin());
  
              // Size limits
 -            unsigned int nTxSize = ::GetSerializeSize(tx, SER_NETWORK);
 +            unsigned int nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
              if (nBlockSize + nTxSize >= MAX_BLOCK_SIZE_GEN)
                  continue;
  
              // Legacy limits on sigOps:
 -            int nTxSigOps = tx.GetLegacySigOpCount();
 +            unsigned int nTxSigOps = tx.GetLegacySigOpCount();
              if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS)
                  continue;
  
@@@ -3397,8 -3370,8 +3397,8 @@@ bool CheckWork(CBlock* pblock, CWallet
      printf("generated %s\n", FormatMoney(pblock->vtx[0].vout[0].nValue).c_str());
  
      // Found a solution
 -    CRITICAL_BLOCK(cs_main)
      {
 +        LOCK(cs_main);
          if (pblock->hashPrevBlock != hashBestChain)
              return error("BitcoinMiner : generated block is stale");
  
          reservekey.KeepKey();
  
          // Track how many getdata requests this block gets
 -        CRITICAL_BLOCK(wallet.cs_wallet)
 +        {
 +            LOCK(wallet.cs_wallet);
              wallet.mapRequestCount[pblock->GetHash()] = 0;
 +        }
  
          // Process this block the same as if we had received it from another node
          if (!ProcessBlock(NULL, pblock))
@@@ -3436,6 -3407,8 +3436,6 @@@ void static BitcoinMiner(CWallet *pwall
  
      while (fGenerateBitcoins)
      {
 -        if (AffinityBugWorkaround(ThreadBitcoinMiner))
 -            return;
          if (fShutdown)
              return;
          while (vNodes.empty() || IsInitialBlockDownload())
                                              (char*)&hash, nHashesDone);
  
              // Check if something found
 -            if (nNonceFound != -1)
 +            if (nNonceFound != (unsigned int) -1)
              {
                  for (unsigned int i = 0; i < sizeof(hash)/4; i++)
                      ((unsigned int*)&hash)[i] = ByteReverse(((unsigned int*)&hash)[i]);
              if (GetTimeMillis() - nHPSTimerStart > 4000)
              {
                  static CCriticalSection cs;
 -                CRITICAL_BLOCK(cs)
                  {
 +                    LOCK(cs);
                      if (GetTimeMillis() - nHPSTimerStart > 4000)
                      {
                          dHashesPerSec = 1000.0 * nHashCounter / (GetTimeMillis() - nHPSTimerStart);
                          nHPSTimerStart = GetTimeMillis();
                          nHashCounter = 0;
 -                        string strStatus = strprintf("    %.0f khash/s", dHashesPerSec/1000.0);
 -                        UIThreadCall(boost::bind(CalledSetStatusBar, strStatus, 0));
                          static int64 nLogTime;
                          if (GetTime() - nLogTime > 30 * 60)
                          {
@@@ -3586,6 -3561,7 +3586,6 @@@ void static ThreadBitcoinMiner(void* pa
          vnThreadsRunning[THREAD_MINER]--;
          PrintException(NULL, "ThreadBitcoinMiner()");
      }
 -    UIThreadCall(boost::bind(CalledSetStatusBar, "", 0));
      nHPSTimerStart = 0;
      if (vnThreadsRunning[THREAD_MINER] == 0)
          dHashesPerSec = 0;
diff --combined src/net.cpp
@@@ -3,16 -3,18 +3,16 @@@
  // Distributed under the MIT/X11 software license, see the accompanying
  // file COPYING or http://www.opensource.org/licenses/mit-license.php.
  
 -#include "headers.h"
  #include "irc.h"
  #include "db.h"
  #include "net.h"
  #include "init.h"
  #include "strlcpy.h"
  #include "addrman.h"
 +#include "ui_interface.h"
  
  #ifdef WIN32
  #include <string.h>
 -#else
 -#include <netinet/in.h>
  #endif
  
  #ifdef USE_UPNP
@@@ -35,7 -37,7 +35,7 @@@ void ThreadOpenAddedConnections2(void* 
  void ThreadMapPort2(void* parg);
  #endif
  void ThreadDNSAddressSeed2(void* parg);
 -bool OpenNetworkConnection(const CAddress& addrConnect);
 +bool OpenNetworkConnection(const CAddress& addrConnect, bool fUseGrant = true);
  
  
  
@@@ -64,7 -66,7 +64,7 @@@ map<CInv, int64> mapAlreadyAskedFor
  set<CNetAddr> setservAddNodeAddresses;
  CCriticalSection cs_setservAddNodeAddresses;
  
 -
 +static CSemaphore *semOutbound = NULL;
  
  unsigned short GetListenPort()
  {
@@@ -269,11 -271,9 +269,11 @@@ void ThreadGetMyExternalIP(void* parg
              // setAddrKnown automatically filters any duplicate sends.
              CAddress addr(addrLocalHost);
              addr.nTime = GetAdjustedTime();
 -            CRITICAL_BLOCK(cs_vNodes)
 +            {
 +                LOCK(cs_vNodes);
                  BOOST_FOREACH(CNode* pnode, vNodes)
                      pnode->PushAddress(addr);
 +            }
          }
      }
  }
@@@ -291,12 -291,111 +291,12 @@@ void AddressCurrentlyConnected(const CS
  
  
  
 -void AbandonRequests(void (*fn)(void*, CDataStream&), void* param1)
 -{
 -    // If the dialog might get closed before the reply comes back,
 -    // call this in the destructor so it doesn't get called after it's deleted.
 -    CRITICAL_BLOCK(cs_vNodes)
 -    {
 -        BOOST_FOREACH(CNode* pnode, vNodes)
 -        {
 -            CRITICAL_BLOCK(pnode->cs_mapRequests)
 -            {
 -                for (map<uint256, CRequestTracker>::iterator mi = pnode->mapRequests.begin(); mi != pnode->mapRequests.end();)
 -                {
 -                    CRequestTracker& tracker = (*mi).second;
 -                    if (tracker.fn == fn && tracker.param1 == param1)
 -                        pnode->mapRequests.erase(mi++);
 -                    else
 -                        mi++;
 -                }
 -            }
 -        }
 -    }
 -}
 -
 -
 -
 -
 -
 -
 -
 -//
 -// Subscription methods for the broadcast and subscription system.
 -// Channel numbers are message numbers, i.e. MSG_TABLE and MSG_PRODUCT.
 -//
 -// The subscription system uses a meet-in-the-middle strategy.
 -// With 100,000 nodes, if senders broadcast to 1000 random nodes and receivers
 -// subscribe to 1000 random nodes, 99.995% (1 - 0.99^1000) of messages will get through.
 -//
 -
 -bool AnySubscribed(unsigned int nChannel)
 -{
 -    if (pnodeLocalHost->IsSubscribed(nChannel))
 -        return true;
 -    CRITICAL_BLOCK(cs_vNodes)
 -        BOOST_FOREACH(CNode* pnode, vNodes)
 -            if (pnode->IsSubscribed(nChannel))
 -                return true;
 -    return false;
 -}
 -
 -bool CNode::IsSubscribed(unsigned int nChannel)
 -{
 -    if (nChannel >= vfSubscribe.size())
 -        return false;
 -    return vfSubscribe[nChannel];
 -}
 -
 -void CNode::Subscribe(unsigned int nChannel, unsigned int nHops)
 -{
 -    if (nChannel >= vfSubscribe.size())
 -        return;
 -
 -    if (!AnySubscribed(nChannel))
 -    {
 -        // Relay subscribe
 -        CRITICAL_BLOCK(cs_vNodes)
 -            BOOST_FOREACH(CNode* pnode, vNodes)
 -                if (pnode != this)
 -                    pnode->PushMessage("subscribe", nChannel, nHops);
 -    }
 -
 -    vfSubscribe[nChannel] = true;
 -}
 -
 -void CNode::CancelSubscribe(unsigned int nChannel)
 -{
 -    if (nChannel >= vfSubscribe.size())
 -        return;
 -
 -    // Prevent from relaying cancel if wasn't subscribed
 -    if (!vfSubscribe[nChannel])
 -        return;
 -    vfSubscribe[nChannel] = false;
 -
 -    if (!AnySubscribed(nChannel))
 -    {
 -        // Relay subscription cancel
 -        CRITICAL_BLOCK(cs_vNodes)
 -            BOOST_FOREACH(CNode* pnode, vNodes)
 -                if (pnode != this)
 -                    pnode->PushMessage("sub-cancel", nChannel);
 -    }
 -}
 -
 -
 -
 -
 -
 -
 -
  
  
  CNode* FindNode(const CNetAddr& ip)
  {
 -    CRITICAL_BLOCK(cs_vNodes)
      {
 +        LOCK(cs_vNodes);
          BOOST_FOREACH(CNode* pnode, vNodes)
              if ((CNetAddr)pnode->addr == ip)
                  return (pnode);
  
  CNode* FindNode(const CService& addr)
  {
 -    CRITICAL_BLOCK(cs_vNodes)
      {
 +        LOCK(cs_vNodes);
          BOOST_FOREACH(CNode* pnode, vNodes)
              if ((CService)pnode->addr == addr)
                  return (pnode);
@@@ -361,10 -460,8 +361,10 @@@ CNode* ConnectNode(CAddress addrConnect
              pnode->AddRef(nTimeout);
          else
              pnode->AddRef();
 -        CRITICAL_BLOCK(cs_vNodes)
 +        {
 +            LOCK(cs_vNodes);
              vNodes.push_back(pnode);
 +        }
  
          pnode->nTimeConnected = GetTime();
          return pnode;
@@@ -391,6 -488,13 +391,6 @@@ void CNode::CloseSocketDisconnect(
  
  void CNode::Cleanup()
  {
 -    // All of a nodes broadcasts and subscriptions are automatically torn down
 -    // when it goes down, so a node has to stay up to keep its broadcast going.
 -
 -    // Cancel subscriptions
 -    for (unsigned int nChannel = 0; nChannel < vfSubscribe.size(); nChannel++)
 -        if (vfSubscribe[nChannel])
 -            CancelSubscribe(nChannel);
  }
  
  
@@@ -420,8 -524,8 +420,8 @@@ void CNode::ClearBanned(
  bool CNode::IsBanned(CNetAddr ip)
  {
      bool fResult = false;
 -    CRITICAL_BLOCK(cs_setBanned)
      {
 +        LOCK(cs_setBanned);
          std::map<CNetAddr, int64>::iterator i = setBanned.find(ip);
          if (i != setBanned.end())
          {
@@@ -445,11 -549,9 +445,11 @@@ bool CNode::Misbehaving(int howmuch
      if (nMisbehavior >= GetArg("-banscore", 100))
      {
          int64 banTime = GetTime()+GetArg("-bantime", 60*60*24);  // Default 24-hour ban
 -        CRITICAL_BLOCK(cs_setBanned)
 +        {
 +            LOCK(cs_setBanned);
              if (setBanned[addr] < banTime)
                  setBanned[addr] = banTime;
 +        }
          CloseSocketDisconnect();
          printf("Disconnected %s for misbehavior (score=%d)\n", addr.ToString().c_str(), nMisbehavior);
          return true;
@@@ -491,15 -593,15 +491,15 @@@ void ThreadSocketHandler2(void* parg
  {
      printf("ThreadSocketHandler started\n");
      list<CNode*> vNodesDisconnected;
 -    int nPrevNodeCount = 0;
 +    unsigned int nPrevNodeCount = 0;
  
      loop
      {
          //
          // Disconnect nodes
          //
 -        CRITICAL_BLOCK(cs_vNodes)
          {
 +            LOCK(cs_vNodes);
              // Disconnect unused nodes
              vector<CNode*> vNodesCopy = vNodes;
              BOOST_FOREACH(CNode* pnode, vNodesCopy)
                      // remove from vNodes
                      vNodes.erase(remove(vNodes.begin(), vNodes.end(), pnode), vNodes.end());
  
 +                    if (pnode->fHasGrant)
 +                        semOutbound->post();
 +                    pnode->fHasGrant = false;
 +
                      // close socket and cleanup
                      pnode->CloseSocketDisconnect();
                      pnode->Cleanup();
                  if (pnode->GetRefCount() <= 0)
                  {
                      bool fDelete = false;
 -                    TRY_CRITICAL_BLOCK(pnode->cs_vSend)
 -                     TRY_CRITICAL_BLOCK(pnode->cs_vRecv)
 -                      TRY_CRITICAL_BLOCK(pnode->cs_mapRequests)
 -                       TRY_CRITICAL_BLOCK(pnode->cs_inventory)
 -                        fDelete = true;
 +                    {
 +                        TRY_LOCK(pnode->cs_vSend, lockSend);
 +                        if (lockSend)
 +                        {
 +                            TRY_LOCK(pnode->cs_vRecv, lockRecv);
 +                            if (lockRecv)
 +                            {
 +                                TRY_LOCK(pnode->cs_mapRequests, lockReq);
 +                                if (lockReq)
 +                                {
 +                                    TRY_LOCK(pnode->cs_inventory, lockInv);
 +                                    if (lockInv)
 +                                        fDelete = true;
 +                                }
 +                            }
 +                        }
 +                    }
                      if (fDelete)
                      {
                          vNodesDisconnected.remove(pnode);
          if(hListenSocket != INVALID_SOCKET)
              FD_SET(hListenSocket, &fdsetRecv);
          hSocketMax = max(hSocketMax, hListenSocket);
 -        CRITICAL_BLOCK(cs_vNodes)
          {
 +            LOCK(cs_vNodes);
              BOOST_FOREACH(CNode* pnode, vNodes)
              {
                  if (pnode->hSocket == INVALID_SOCKET)
                  FD_SET(pnode->hSocket, &fdsetRecv);
                  FD_SET(pnode->hSocket, &fdsetError);
                  hSocketMax = max(hSocketMax, pnode->hSocket);
 -                TRY_CRITICAL_BLOCK(pnode->cs_vSend)
 -                    if (!pnode->vSend.empty())
 +                {
 +                    TRY_LOCK(pnode->cs_vSend, lockSend);
 +                    if (lockSend && !pnode->vSend.empty())
                          FD_SET(pnode->hSocket, &fdsetSend);
 +                }
              }
          }
  
          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++)
              if (hSocket != INVALID_SOCKET)
                  addr = CAddress(sockaddr);
  
 -            CRITICAL_BLOCK(cs_vNodes)
 +            {
 +                LOCK(cs_vNodes);
                  BOOST_FOREACH(CNode* pnode, vNodes)
 -                if (pnode->fInbound)
 -                    nInbound++;
 +                    if (pnode->fInbound)
 +                        nInbound++;
 +            }
  
              if (hSocket == INVALID_SOCKET)
              {
              }
              else if (nInbound >= GetArg("-maxconnections", 125) - MAX_OUTBOUND_CONNECTIONS)
              {
 -                CRITICAL_BLOCK(cs_setservAddNodeAddresses)
 +                {
 +                    LOCK(cs_setservAddNodeAddresses);
                      if (!setservAddNodeAddresses.count(addr))
                          closesocket(hSocket);
 +                }
              }
              else if (CNode::IsBanned(addr))
              {
                  printf("accepted connection %s\n", addr.ToString().c_str());
                  CNode* pnode = new CNode(hSocket, addr, true);
                  pnode->AddRef();
 -                CRITICAL_BLOCK(cs_vNodes)
 +                {
 +                    LOCK(cs_vNodes);
                      vNodes.push_back(pnode);
 +                }
              }
          }
  
          // Service each socket
          //
          vector<CNode*> vNodesCopy;
 -        CRITICAL_BLOCK(cs_vNodes)
          {
 +            LOCK(cs_vNodes);
              vNodesCopy = vNodes;
              BOOST_FOREACH(CNode* pnode, vNodesCopy)
                  pnode->AddRef();
                  continue;
              if (FD_ISSET(pnode->hSocket, &fdsetRecv) || FD_ISSET(pnode->hSocket, &fdsetError))
              {
 -                TRY_CRITICAL_BLOCK(pnode->cs_vRecv)
 +                TRY_LOCK(pnode->cs_vRecv, lockRecv);
 +                if (lockRecv)
                  {
                      CDataStream& vRecv = pnode->vRecv;
                      unsigned int nPos = vRecv.size();
                  continue;
              if (FD_ISSET(pnode->hSocket, &fdsetSend))
              {
 -                TRY_CRITICAL_BLOCK(pnode->cs_vSend)
 +                TRY_LOCK(pnode->cs_vSend, lockSend);
 +                if (lockSend)
                  {
                      CDataStream& vSend = pnode->vSend;
                      if (!vSend.empty())
                  }
              }
          }
 -        CRITICAL_BLOCK(cs_vNodes)
          {
 +            LOCK(cs_vNodes);
              BOOST_FOREACH(CNode* pnode, vNodesCopy)
                  pnode->Release();
          }
@@@ -1189,7 -1265,7 +1189,7 @@@ void ThreadOpenConnections2(void* parg
              {
                  CAddress addr(CService(strAddr, GetDefaultPort(), fAllowDNS));
                  if (addr.IsValid())
 -                    OpenNetworkConnection(addr);
 +                    OpenNetworkConnection(addr, false);
                  for (int i = 0; i < 10 && i < nLoop; i++)
                  {
                      Sleep(500);
      int64 nStart = GetTime();
      loop
      {
 -        int nOutbound = 0;
 -
          vnThreadsRunning[THREAD_OPENCONNECTIONS]--;
          Sleep(500);
          vnThreadsRunning[THREAD_OPENCONNECTIONS]++;
          if (fShutdown)
              return;
  
 -        // Limit outbound connections
 -        loop
 -        {
 -            nOutbound = 0;
 -            CRITICAL_BLOCK(cs_vNodes)
 -                BOOST_FOREACH(CNode* pnode, vNodes)
 -                    if (!pnode->fInbound)
 -                        nOutbound++;
 -            int nMaxOutboundConnections = MAX_OUTBOUND_CONNECTIONS;
 -            nMaxOutboundConnections = min(nMaxOutboundConnections, (int)GetArg("-maxconnections", 125));
 -            if (nOutbound < nMaxOutboundConnections)
 -                break;
 -            vnThreadsRunning[THREAD_OPENCONNECTIONS]--;
 -            Sleep(2000);
 -            vnThreadsRunning[THREAD_OPENCONNECTIONS]++;
 -            if (fShutdown)
 -                return;
 -        }
 +
 +        vnThreadsRunning[THREAD_OPENCONNECTIONS]--;
 +        semOutbound->wait();
 +        vnThreadsRunning[THREAD_OPENCONNECTIONS]++;
 +        if (fShutdown)
 +            return;
  
          // Add seed nodes if IRC isn't working
          bool fTOR = (fUseProxy && addrProxy.GetPort() == 9050);
  
          // Only connect to one address per a.b.?.? range.
          // Do this here so we don't have to critsect vNodes inside mapAddresses critsect.
 +        int nOutbound = 0;
          set<vector<unsigned char> > setConnected;
 -        CRITICAL_BLOCK(cs_vNodes)
 -            BOOST_FOREACH(CNode* pnode, vNodes)
 +        {
 +            LOCK(cs_vNodes);
 +            BOOST_FOREACH(CNode* pnode, vNodes) {
                  setConnected.insert(pnode->addr.GetGroup());
 +                if (!pnode->fInbound)
 +                    nOutbound++;
 +            }
 +        }
  
          int64 nANow = GetAdjustedTime();
  
  
          if (addrConnect.IsValid())
              OpenNetworkConnection(addrConnect);
 +        else
 +            semOutbound->post();
      }
  }
  
@@@ -1322,11 -1404,9 +1322,11 @@@ void ThreadOpenAddedConnections2(void* 
          if(Lookup(strAddNode.c_str(), vservNode, GetDefaultPort(), fAllowDNS, 0))
          {
              vservAddressesToAdd.push_back(vservNode);
 -            CRITICAL_BLOCK(cs_setservAddNodeAddresses)
 +            {
 +                LOCK(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)
 +        {
 +            LOCK(cs_vNodes);
              BOOST_FOREACH(CNode* pnode, vNodes)
                  for (vector<vector<CService> >::iterator it = vservConnectAddresses.begin(); it != vservConnectAddresses.end(); it++)
                      BOOST_FOREACH(CService& addrNode, *(it))
                              it--;
                              break;
                          }
 +        }
          BOOST_FOREACH(vector<CService>& vserv, vservConnectAddresses)
          {
 +            semOutbound->wait();
              OpenNetworkConnection(CAddress(*(vserv.begin())));
              Sleep(500);
              if (fShutdown)
      }
  }
  
 -bool OpenNetworkConnection(const CAddress& addrConnect)
 +bool static ReleaseGrant(bool fUseGrant) {
 +    if (fUseGrant)
 +        semOutbound->post();
 +    return false;
 +}
 +
 +// only call this function when semOutbound has been waited for
 +bool OpenNetworkConnection(const CAddress& addrConnect, bool fUseGrant)
  {
      //
      // Initiate outbound network connection
          return false;
      if ((CNetAddr)addrConnect == (CNetAddr)addrLocalHost || !addrConnect.IsIPv4() ||
          FindNode((CNetAddr)addrConnect) || CNode::IsBanned(addrConnect))
 -        return false;
 +        return ReleaseGrant(fUseGrant);
  
      vnThreadsRunning[THREAD_OPENCONNECTIONS]--;
      CNode* pnode = ConnectNode(addrConnect);
      if (fShutdown)
          return false;
      if (!pnode)
 -        return false;
 +        return ReleaseGrant(fUseGrant);
 +    if (pnode->fHasGrant) {
 +        // node already has connection grant, release the one that was passed to us
 +        ReleaseGrant(fUseGrant);
 +    } else {
 +        pnode->fHasGrant = fUseGrant;
 +    }
      pnode->fNetworkNode = true;
  
      return true;
@@@ -1433,8 -1497,8 +1433,8 @@@ void ThreadMessageHandler2(void* parg
      while (!fShutdown)
      {
          vector<CNode*> vNodesCopy;
 -        CRITICAL_BLOCK(cs_vNodes)
          {
 +            LOCK(cs_vNodes);
              vNodesCopy = vNodes;
              BOOST_FOREACH(CNode* pnode, vNodesCopy)
                  pnode->AddRef();
          BOOST_FOREACH(CNode* pnode, vNodesCopy)
          {
              // Receive messages
 -            TRY_CRITICAL_BLOCK(pnode->cs_vRecv)
 -                ProcessMessages(pnode);
 +            {
 +                TRY_LOCK(pnode->cs_vRecv, lockRecv);
 +                if (lockRecv)
 +                    ProcessMessages(pnode);
 +            }
              if (fShutdown)
                  return;
  
              // Send messages
 -            TRY_CRITICAL_BLOCK(pnode->cs_vSend)
 -                SendMessages(pnode, pnode == pnodeTrickle);
 +            {
 +                TRY_LOCK(pnode->cs_vSend, lockSend);
 +                if (lockSend)
 +                    SendMessages(pnode, pnode == pnodeTrickle);
 +            }
              if (fShutdown)
                  return;
          }
  
 -        CRITICAL_BLOCK(cs_vNodes)
          {
 +            LOCK(cs_vNodes);
              BOOST_FOREACH(CNode* pnode, vNodesCopy)
                  pnode->Release();
          }
          vnThreadsRunning[THREAD_MESSAGEHANDLER]--;
          Sleep(100);
          if (fRequestShutdown)
-             Shutdown(NULL);
+             StartShutdown();
          vnThreadsRunning[THREAD_MESSAGEHANDLER]++;
          if (fShutdown)
              return;
@@@ -1571,12 -1629,6 +1571,12 @@@ bool BindListenPort(string& strError
  
  void StartNode(void* parg)
  {
 +    if (semOutbound == NULL) {
 +        // initialize semaphore
 +        int nMaxOutbound = min(MAX_OUTBOUND_CONNECTIONS, (int)GetArg("-maxconnections", 125));
 +        semOutbound = new CSemaphore(nMaxOutbound);
 +    }
 +
  #ifdef USE_UPNP
  #if USE_UPNP
      fUseUPnP = GetBoolArg("-upnp", true);
      {
          vector<CNetAddr> vaddr;
          if (LookupHost(pszHostName, vaddr))
 +        {
              BOOST_FOREACH (const CNetAddr &addr, vaddr)
 +            {
                  if (!addr.IsLocal())
                  {
                      addrLocalHost.SetIP(addr);
                      break;
                  }
 +            }
 +        }
      }
  #else
      // Get local host ip
@@@ -1703,9 -1751,6 +1703,9 @@@ bool StopNode(
      fShutdown = true;
      nTransactionsUpdated++;
      int64 nStart = GetTime();
 +    if (semOutbound)
 +        for (int i=0; i<MAX_OUTBOUND_CONNECTIONS; i++)
 +            semOutbound->post();
      do
      {
          int nThreadsRunning = 0;
@@@ -43,19 -43,15 +43,19 @@@ AddressBookPage::AddressBookPage(Mode m
          ui->tableView->setFocus();
          break;
      case ForEditing:
 -        ui->buttonBox->hide();
 +        ui->buttonBox->setVisible(false);
          break;
      }
      switch(tab)
      {
      case SendingTab:
 -        ui->labelExplanation->hide();
 +        ui->labelExplanation->setVisible(false);
 +        ui->deleteButton->setVisible(true);
 +        ui->signMessage->setVisible(false);
          break;
      case ReceivingTab:
 +        ui->deleteButton->setVisible(false);
 +        ui->signMessage->setVisible(true);
          break;
      }
      ui->tableView->setTabKeyNavigation(false);
@@@ -94,6 -90,8 +94,6 @@@ void AddressBookPage::setModel(AddressT
      this->model = model;
      if(!model)
          return;
 -    // Refresh list from core
 -    model->updateList();
  
      proxyModel = new QSortFilterProxyModel(this);
      proxyModel->setSourceModel(model);
      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();
  }
  
@@@ -135,7 -128,6 +130,7 @@@ void AddressBookPage::on_copyToClipboar
  {
      GUIUtil::copyEntryData(ui->tableView, AddressTableModel::Address);
  }
 +
  void AddressBookPage::onCopyLabelAction()
  {
      GUIUtil::copyEntryData(ui->tableView, AddressTableModel::Label);
@@@ -227,18 -219,14 +222,18 @@@ void AddressBookPage::selectionChanged(
          case SendingTab:
              // In sending tab, allow deletion of selection
              ui->deleteButton->setEnabled(true);
 +            ui->deleteButton->setVisible(true);
              deleteAction->setEnabled(true);
              ui->signMessage->setEnabled(false);
 +            ui->signMessage->setVisible(false);
              break;
          case ReceivingTab:
              // Deleting receiving addresses, however, is not allowed
              ui->deleteButton->setEnabled(false);
 +            ui->deleteButton->setVisible(false);
              deleteAction->setEnabled(false);
              ui->signMessage->setEnabled(true);
 +            ui->signMessage->setVisible(true);
              break;
          }
          ui->copyToClipboard->setEnabled(true);
@@@ -310,12 -298,16 +305,12 @@@ void AddressBookPage::on_showQRCode_cli
      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);
 +        QString address = index.data().toString(), label = index.sibling(index.row(), 0).data(Qt::EditRole).toString();
  
 -        QRCodeDialog *d = new QRCodeDialog(title, address, label, tab == ReceivingTab, this);
 -        d->show();
 +        QRCodeDialog *dialog = new QRCodeDialog(address, label, tab == ReceivingTab, this);
 +        dialog->show();
      }
  #endif
  }
diff --combined src/qt/bitcoin.cpp
@@@ -5,14 -5,15 +5,14 @@@
  #include "clientmodel.h"
  #include "walletmodel.h"
  #include "optionsmodel.h"
 +#include "guiutil.h"
  
 -#include "headers.h"
  #include "init.h"
 +#include "ui_interface.h"
  #include "qtipcserver.h"
  
  #include <QApplication>
  #include <QMessageBox>
 -#include <QThread>
  #include <QTextCodec>
  #include <QLocale>
  #include <QTranslator>
  
  #include <boost/interprocess/ipc/message_queue.hpp>
  
 -// Need a global reference for the notifications to find the GUI
 -BitcoinGUI *guiref;
 -QSplashScreen *splashref;
 +#if defined(BITCOIN_NEED_QT_PLUGINS) && !defined(_BITCOIN_QT_PLUGINS_INCLUDED)
 +#define _BITCOIN_QT_PLUGINS_INCLUDED
 +#define __INSURE__
 +#include <QtPlugin>
 +Q_IMPORT_PLUGIN(qcncodecs)
 +Q_IMPORT_PLUGIN(qjpcodecs)
 +Q_IMPORT_PLUGIN(qtwcodecs)
 +Q_IMPORT_PLUGIN(qkrcodecs)
 +Q_IMPORT_PLUGIN(qtaccessiblewidgets)
 +#endif
  
 -int MyMessageBox(const std::string& message, const std::string& caption, int style, wxWindow* parent, int x, int y)
 -{
 -    // 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;
 -}
 +// Need a global reference for the notifications to find the GUI
 +static BitcoinGUI *guiref;
 +static QSplashScreen *splashref;
 +static WalletModel *walletmodel;
 +static ClientModel *clientmodel;
  
 -int ThreadSafeMessageBox(const std::string& message, const std::string& caption, int style, wxWindow* parent, int x, int y)
 +int ThreadSafeMessageBox(const std::string& message, const std::string& caption, int style)
  {
      // Message from network thread
      if(guiref)
      {
 -        QMetaObject::invokeMethod(guiref, "error", Qt::QueuedConnection,
 +        bool modal = (style & wxMODAL);
 +        // in case of modal message, use blocking connection to wait for user to click OK
 +        QMetaObject::invokeMethod(guiref, "error",
 +                                   modal ? GUIUtil::blockingGUIThreadConnection() : Qt::QueuedConnection,
                                     Q_ARG(QString, QString::fromStdString(caption)),
                                     Q_ARG(QString, QString::fromStdString(message)),
                                     Q_ARG(bool, modal));
@@@ -59,7 -59,7 +59,7 @@@
      return 4;
  }
  
 -bool ThreadSafeAskFee(int64 nFeeRequired, const std::string& strCaption, wxWindow* parent)
 +bool ThreadSafeAskFee(int64 nFeeRequired, const std::string& strCaption)
  {
      if(!guiref)
          return false;
          return true;
      bool payFee = false;
  
 -    // 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, "askFee", connectionType,
 +    QMetaObject::invokeMethod(guiref, "askFee", GUIUtil::blockingGUIThreadConnection(),
                                 Q_ARG(qint64, nFeeRequired),
                                 Q_ARG(bool*, &payFee));
  
@@@ -79,22 -87,31 +79,22 @@@ void ThreadSafeHandleURI(const std::str
      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,
 +    QMetaObject::invokeMethod(guiref, "handleURI", GUIUtil::blockingGUIThreadConnection(),
                                 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
 -}
 -
 -void UIThreadCall(boost::function0<void> fn)
 +void MainFrameRepaint()
  {
 -    // Only used for built-in mining, which is disabled, simple ignore
 +    if(clientmodel)
 +        QMetaObject::invokeMethod(clientmodel, "update", Qt::QueuedConnection);
 +    if(walletmodel)
 +        QMetaObject::invokeMethod(walletmodel, "update", Qt::QueuedConnection);
  }
  
 -void MainFrameRepaint()
 +void AddressBookRepaint()
  {
 -    if(guiref)
 -        QMetaObject::invokeMethod(guiref, "refreshStatusBar", Qt::QueuedConnection);
 +    if(walletmodel)
 +        QMetaObject::invokeMethod(walletmodel, "updateAddressList", Qt::QueuedConnection);
  }
  
  void InitMessage(const std::string &message)
@@@ -128,9 -145,6 +128,9 @@@ static void handleRunawayException(std:
      exit(1);
  }
  
 +#ifdef WIN32
 +#define strncasecmp strnicmp
 +#endif
  #ifndef BITCOIN_QT_TEST
  int main(int argc, char *argv[])
  {
      ParseParameters(argc, argv);
  
      // ... then bitcoin.conf:
 -    if (!ReadConfigFile(mapArgs, mapMultiArgs))
 +    if (!boost::filesystem::is_directory(GetDataDir(false)))
      {
          fprintf(stderr, "Error: Specified directory does not exist\n");
          return 1;
      }
 +    ReadConfigFile(mapArgs, mapMultiArgs);
  
      // Application identification (must be set before OptionsModel is initialized,
      // as it is used to locate QSettings)
  
      try
      {
 +        BitcoinGUI window;
 +        guiref = &window;
          if(AppInit2(argc, argv))
          {
              {
 -                // Put this in a block, so that BitcoinGUI is cleaned up properly before
 -                // calling Shutdown() in case of exceptions.
 +                // Put this in a block, so that the Model objects are cleaned up before
 +                // calling Shutdown().
  
                  optionsModel.Upgrade(); // Must be done after AppInit2
  
 -                BitcoinGUI window;
                  if (splashref)
                      splash.finish(&window);
  
                  ClientModel clientModel(&optionsModel);
 +                clientmodel = &clientModel;
                  WalletModel walletModel(pwalletMain, &optionsModel);
 +                walletmodel = &walletModel;
  
 -                guiref = &window;
                  window.setClientModel(&clientModel);
                  window.setWalletModel(&walletModel);
  
                  app.exec();
  
                  window.hide();
 +                window.setClientModel(0);
 +                window.setWalletModel(0);
                  guiref = 0;
 +                clientmodel = 0;
 +                walletmodel = 0;
              }
+             // Shutdown the core and it's threads, but don't exit Bitcoin-Qt here
              Shutdown(NULL);
          }
          else
diff --combined src/qt/bitcoingui.cpp
@@@ -4,6 -4,9 +4,6 @@@
   * W.J. van der Laan 2011-2012
   * The Bitcoin Developers 2011-2012
   */
 -
 -#include "checkpoints.h"
 -
  #include "bitcoingui.h"
  #include "transactiontablemodel.h"
  #include "addressbookpage.h"
@@@ -23,7 -26,6 +23,7 @@@
  #include "guiconstants.h"
  #include "askpassphrasedialog.h"
  #include "notificator.h"
 +#include "guiutil.h"
  
  #ifdef Q_WS_MAC
  #include "macdockiconhandler.h"
@@@ -139,11 -141,11 +139,11 @@@ BitcoinGUI::BitcoinGUI(QWidget *parent)
      frameBlocksLayout->addWidget(labelBlocksIcon);
      frameBlocksLayout->addStretch();
  
 -    // Progress bar for blocks download
 -    progressBarLabel = new QLabel(tr("Synchronizing with network..."));
 +    // Progress bar and label for blocks download
 +    progressBarLabel = new QLabel();
      progressBarLabel->setVisible(false);
      progressBar = new QProgressBar();
 -    progressBar->setToolTip(tr("Block chain synchronization in progress"));
 +    progressBar->setAlignment(Qt::AlignCenter);
      progressBar->setVisible(false);
  
      statusBar()->addWidget(progressBarLabel);
  
  BitcoinGUI::~BitcoinGUI()
  {
-     if(trayIcon) // Hide tray icon, as deleting will let it linger until quit (on Ubuntu)
-         trayIcon->hide();
  #ifdef Q_WS_MAC
      delete appMenuBar;
  #endif
@@@ -237,8 -237,8 +235,8 @@@ void BitcoinGUI::createActions(
      optionsAction = new QAction(QIcon(":/icons/options"), tr("&Options..."), this);
      optionsAction->setToolTip(tr("Modify configuration options for bitcoin"));
      optionsAction->setMenuRole(QAction::PreferencesRole);
 -    openBitcoinAction = new QAction(QIcon(":/icons/bitcoin"), tr("Open &Bitcoin"), this);
 -    openBitcoinAction->setToolTip(tr("Show the Bitcoin window"));
 +    toggleHideAction = new QAction(QIcon(":/icons/bitcoin"), tr("Show/Hide &Bitcoin"), this);
 +    toggleHideAction->setToolTip(tr("Show or hide the Bitcoin window"));
      exportAction = new QAction(QIcon(":/icons/export"), tr("&Export..."), this);
      exportAction->setToolTip(tr("Export the data in the current tab to a file"));
      encryptWalletAction = new QAction(QIcon(":/icons/lock_closed"), tr("&Encrypt Wallet"), this);
      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(showNormalIfMinimized()));
 +    connect(toggleHideAction, SIGNAL(triggered()), this, SLOT(toggleHidden()));
      connect(encryptWalletAction, SIGNAL(triggered(bool)), this, SLOT(encryptWallet(bool)));
      connect(backupWalletAction, SIGNAL(triggered()), this, SLOT(backupWallet()));
      connect(changePassphraseAction, SIGNAL(triggered()), this, SLOT(changePassphrase()));
@@@ -337,7 -337,7 +335,7 @@@ void BitcoinGUI::setClientModel(ClientM
          connect(clientModel, SIGNAL(numBlocksChanged(int)), this, SLOT(setNumBlocks(int)));
  
          // Report errors from network/worker thread
 -        connect(clientModel, SIGNAL(error(QString,QString)), this, SLOT(error(QString,QString)));
 +        connect(clientModel, SIGNAL(error(QString,QString, bool)), this, SLOT(error(QString,QString,bool)));
      }
  }
  
@@@ -347,7 -347,7 +345,7 @@@ void BitcoinGUI::setWalletModel(WalletM
      if(walletModel)
      {
          // Report errors from wallet thread
 -        connect(walletModel, SIGNAL(error(QString,QString)), this, SLOT(error(QString,QString)));
 +        connect(walletModel, SIGNAL(error(QString,QString,bool)), this, SLOT(error(QString,QString,bool)));
  
          // Put transaction list in tabs
          transactionView->setModel(walletModel);
@@@ -377,7 -377,7 +375,7 @@@ void BitcoinGUI::createTrayIcon(
      trayIcon = new QSystemTrayIcon(this);
      trayIconMenu = new QMenu(this);
      trayIcon->setContextMenu(trayIconMenu);
 -    trayIcon->setToolTip("Bitcoin client");
 +    trayIcon->setToolTip(tr("Bitcoin client"));
      trayIcon->setIcon(QIcon(":/icons/toolbar"));
      connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
              this, SLOT(trayIconActivated(QSystemTrayIcon::ActivationReason)));
  #else
      // Note: On Mac, the dock icon is used to provide the tray's functionality.
      MacDockIconHandler *dockIconHandler = MacDockIconHandler::instance();
 -    connect(dockIconHandler, SIGNAL(dockIconClicked()), openBitcoinAction, SLOT(trigger()));
      trayIconMenu = dockIconHandler->dockMenu();
  #endif
  
      // Configuration of the tray icon (or dock icon) icon menu
 -    trayIconMenu->addAction(openBitcoinAction);
 +    trayIconMenu->addAction(toggleHideAction);
      trayIconMenu->addSeparator();
      trayIconMenu->addAction(messageAction);
  #ifndef FIRST_CLASS_MESSAGING
@@@ -412,34 -413,12 +410,34 @@@ void BitcoinGUI::trayIconActivated(QSys
  {
      if(reason == QSystemTrayIcon::Trigger)
      {
 -        // Click on system tray icon triggers "open bitcoin"
 -        openBitcoinAction->trigger();
 +        // Click on system tray icon triggers "show/hide bitcoin"
 +        toggleHideAction->trigger();
      }
  }
  #endif
  
 +void BitcoinGUI::toggleHidden()
 +{
 +    // activateWindow() (sometimes) helps with keyboard focus on Windows
 +    if (isHidden())
 +    {
 +        show();
 +        activateWindow();
 +    }
 +    else if (isMinimized())
 +    {
 +        showNormal();
 +        activateWindow();
 +    }
 +    else if (GUIUtil::isObscured(this))
 +    {
 +        raise();
 +        activateWindow();
 +    }
 +    else
 +        hide();
 +}
 +
  void BitcoinGUI::optionsClicked()
  {
      if(!clientModel || !clientModel->getOptionsModel())
@@@ -473,31 -452,20 +471,31 @@@ void BitcoinGUI::setNumConnections(int 
  
  void BitcoinGUI::setNumBlocks(int count)
  {
 -    if(!clientModel)
 +    // don't show / hide progressBar and it's label if we have no connection(s) to the network
 +    if (!clientModel || clientModel->getNumConnections() == 0)
 +    {
 +        progressBarLabel->setVisible(false);
 +        progressBar->setVisible(false);
 +
          return;
 -    int total = clientModel->getNumBlocksOfPeers();
 +    }
 +
 +    int nTotalBlocks = clientModel->getNumBlocksOfPeers();
      QString tooltip;
  
 -    if(count < total)
 +    if(count < nTotalBlocks)
      {
 +        int nRemainingBlocks = nTotalBlocks - count;
 +        float nPercentageDone = count / (nTotalBlocks * 0.01f);
 +
          if (clientModel->getStatusBarWarnings() == "")
          {
 -            progressBarLabel->setVisible(true);
              progressBarLabel->setText(tr("Synchronizing with network..."));
 -            progressBar->setVisible(true);
 -            progressBar->setMaximum(total);
 +            progressBarLabel->setVisible(true);
 +            progressBar->setFormat(tr("~%n block(s) remaining", "", nRemainingBlocks));
 +            progressBar->setMaximum(nTotalBlocks);
              progressBar->setValue(count);
 +            progressBar->setVisible(true);
          }
          else
          {
              progressBarLabel->setVisible(true);
              progressBar->setVisible(false);
          }
 -        tooltip = tr("Downloaded %1 of %2 blocks of transaction history.").arg(count).arg(total);
 +        tooltip = tr("Downloaded %1 of %2 blocks of transaction history (%3% done).").arg(count).arg(nTotalBlocks).arg(nPercentageDone, 0, 'f', 2);
      }
      else
      {
      }
  
      // Set icon state: spinning if catching up, tick otherwise
 -    if(secs < 90*60 && count >= Checkpoints::GetTotalBlocksEstimate())
 +    if(secs < 90*60 && count >= nTotalBlocks)
      {
          tooltip = tr("Up to date") + QString(".\n") + tooltip;
 -        labelBlocksIcon->setPixmap(QIcon(":/icons/synced").pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE));
 +        labelBlocksIcon->setPixmap(QIcon(":/icons/synced").pixmap(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE));
      }
      else
      {
      progressBar->setToolTip(tooltip);
  }
  
  void BitcoinGUI::error(const QString &title, const QString &message, bool modal)
  {
      // Report errors from network/worker thread
 -    if (modal)
 +    if(modal)
      {
          QMessageBox::critical(this, title, message, QMessageBox::Ok, QMessageBox::Ok);
      } else {
diff --combined src/util.cpp
@@@ -2,11 -2,8 +2,11 @@@
  // 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.
 -#include "headers.h"
 +
 +#include "util.h"
  #include "strlcpy.h"
 +#include "version.h"
 +#include "ui_interface.h"
  #include <boost/algorithm/string/join.hpp>
  
  // Work around clang compilation problem in Boost 1.46:
@@@ -26,31 -23,7 +26,32 @@@ 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>
 +#include <openssl/crypto.h>
 +#include <openssl/rand.h>
 +
 +#ifdef WIN32
 +#ifdef _MSC_VER
 +#pragma warning(disable:4786)
 +#pragma warning(disable:4804)
 +#pragma warning(disable:4805)
 +#pragma warning(disable:4717)
 +#endif
 +#ifdef _WIN32_WINNT
 +#undef _WIN32_WINNT
 +#endif
 +#define _WIN32_WINNT 0x0501
 +#ifdef _WIN32_IE
 +#undef _WIN32_IE
 +#endif
 +#define _WIN32_IE 0x0400
 +#define WIN32_LEAN_AND_MEAN 1
 +#ifndef NOMINMAX
 +#define NOMINMAX
 +#endif
 +#include "shlobj.h"
 +#include "shlwapi.h"
 +#endif
  
  using namespace std;
  using namespace boost;
@@@ -60,6 -33,7 +61,6 @@@ map<string, vector<string> > mapMultiAr
  bool fDebug = false;
  bool fPrintToConsole = false;
  bool fPrintToDebugger = false;
 -char pszSetDataDir[MAX_PATH] = "";
  bool fRequestShutdown = false;
  bool fShutdown = false;
  bool fDaemon = false;
@@@ -71,6 -45,16 +72,6 @@@ bool fNoListen = false
  bool fLogTimestamps = false;
  CMedianFilter<int64> vTimeOffsets(200,0);
  
 -
 -
 -// Workaround for "multiple definition of `_tls_used'"
 -// http://svn.boost.org/trac/boost/ticket/4258
 -extern "C" void tss_cleanup_implemented() { }
 -
 -
 -
 -
 -
  // Init openssl library multithreading support
  static boost::interprocess::interprocess_mutex** ppmutexOpenSSL;
  void locking_callback(int mode, int i, const char* file, int line)
@@@ -202,13 -186,17 +203,15 @@@ inline int OutputDebugStringF(const cha
  
          if (!fileout)
          {
 -            char pszFile[MAX_PATH+100];
 -            GetDataDir(pszFile);
 -            strlcat(pszFile, "/debug.log", sizeof(pszFile));
 -            fileout = fopen(pszFile, "a");
 +            boost::filesystem::path pathDebug = GetDataDir() / "debug.log";
 +            fileout = fopen(pathDebug.string().c_str(), "a");
              if (fileout) setbuf(fileout, NULL); // unbuffered
          }
          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)
          static CCriticalSection cs_OutputDebugStringF;
  
          // accumulate a line at a time
 -        CRITICAL_BLOCK(cs_OutputDebugStringF)
          {
 +            LOCK(cs_OutputDebugStringF);
              static char pszBuffer[50000];
              static char* pend;
              if (pend == NULL)
@@@ -283,7 -271,7 +286,7 @@@ int my_snprintf(char* buffer, size_t li
      va_start(arg_ptr, format);
      int ret = _vsnprintf(buffer, limit, format, arg_ptr);
      va_end(arg_ptr);
 -    if (ret < 0 || ret >= limit)
 +    if (ret < 0 || ret >= (int)limit)
      {
          ret = limit - 1;
          buffer[limit-1] = 0;
      return ret;
  }
  
 -string strprintf(const std::string &format, ...)
 +string real_strprintf(const std::string &format, int dummy, ...)
  {
      char buffer[50000];
      char* p = buffer;
      loop
      {
          va_list arg_ptr;
 -        va_start(arg_ptr, format);
 +        va_start(arg_ptr, dummy);
          ret = _vsnprintf(p, limit, format.c_str(), arg_ptr);
          va_end(arg_ptr);
          if (ret >= 0 && ret < limit)
      return str;
  }
  
 -bool error(const std::string &format, ...)
 +bool error(const char *format, ...)
  {
      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);
 +    int ret = _vsnprintf(buffer, limit, format, arg_ptr);
      va_end(arg_ptr);
      if (ret < 0 || ret >= limit)
      {
 -        ret = limit - 1;
          buffer[limit-1] = 0;
      }
      printf("ERROR: %s\n", buffer);
@@@ -802,113 -791,129 +805,113 @@@ void PrintExceptionContinue(std::except
  }
  
  #ifdef WIN32
 -string MyGetSpecialFolderPath(int nFolder, bool fCreate)
 +boost::filesystem::path MyGetSpecialFolderPath(int nFolder, bool fCreate)
  {
 +    namespace fs = boost::filesystem;
 +
      char pszPath[MAX_PATH] = "";
      if(SHGetSpecialFolderPathA(NULL, pszPath, nFolder, fCreate))
      {
 -        return pszPath;
 +        return fs::path(pszPath);
      }
      else if (nFolder == CSIDL_STARTUP)
      {
 -        return string(getenv("USERPROFILE")) + "\\Start Menu\\Programs\\Startup";
 +        return fs::path(getenv("USERPROFILE")) / "Start Menu" / "Programs" / "Startup";
      }
      else if (nFolder == CSIDL_APPDATA)
      {
 -        return getenv("APPDATA");
 +        return fs::path(getenv("APPDATA"));
      }
 -    return "";
 +    return fs::path("");
  }
  #endif
  
 -string GetDefaultDataDir()
 +boost::filesystem::path GetDefaultDataDir()
  {
 +    namespace fs = boost::filesystem;
 +
      // Windows: C:\Documents and Settings\username\Application Data\Bitcoin
      // Mac: ~/Library/Application Support/Bitcoin
      // Unix: ~/.bitcoin
  #ifdef WIN32
      // Windows
 -    return MyGetSpecialFolderPath(CSIDL_APPDATA, true) + "\\Bitcoin";
 +    return MyGetSpecialFolderPath(CSIDL_APPDATA, true) / "Bitcoin";
  #else
 +    fs::path pathRet;
      char* pszHome = getenv("HOME");
      if (pszHome == NULL || strlen(pszHome) == 0)
 -        pszHome = (char*)"/";
 -    string strHome = pszHome;
 -    if (strHome[strHome.size()-1] != '/')
 -        strHome += '/';
 +        pathRet = fs::path("/");
 +    else
 +        pathRet = fs::path(pszHome);
  #ifdef MAC_OSX
      // Mac
 -    strHome += "Library/Application Support/";
 -    filesystem::create_directory(strHome.c_str());
 -    return strHome + "Bitcoin";
 +    pathRet /= "Library/Application Support";
 +    fs::create_directory(pathRet);
 +    return pathRet / "Bitcoin";
  #else
      // Unix
 -    return strHome + ".bitcoin";
 +    return pathRet / ".bitcoin";
  #endif
  #endif
  }
  
 -void GetDataDir(char* pszDir)
 +const boost::filesystem::path &GetDataDir(bool fNetSpecific)
  {
 -    // pszDir must be at least MAX_PATH length.
 -    int nVariation;
 -    if (pszSetDataDir[0] != 0)
 -    {
 -        strlcpy(pszDir, pszSetDataDir, MAX_PATH);
 -        nVariation = 0;
 -    }
 -    else
 -    {
 -        // This can be called during exceptions by printf, so we cache the
 -        // value so we don't have to do memory allocations after that.
 -        static char pszCachedDir[MAX_PATH];
 -        if (pszCachedDir[0] == 0)
 -            strlcpy(pszCachedDir, GetDefaultDataDir().c_str(), sizeof(pszCachedDir));
 -        strlcpy(pszDir, pszCachedDir, MAX_PATH);
 -        nVariation = 1;
 -    }
 -    if (fTestNet)
 -    {
 -        char* p = pszDir + strlen(pszDir);
 -        if (p > pszDir && p[-1] != '/' && p[-1] != '\\')
 -            *p++ = '/';
 -        strcpy(p, "testnet");
 -        nVariation += 2;
 -    }
 -    static bool pfMkdir[4];
 -    if (!pfMkdir[nVariation])
 -    {
 -        pfMkdir[nVariation] = true;
 -        boost::filesystem::create_directory(pszDir);
 +    namespace fs = boost::filesystem;
 +
 +    static fs::path pathCached[2];
 +    static CCriticalSection csPathCached;
 +    static bool cachedPath[2] = {false, false};
 +
 +    fs::path &path = pathCached[fNetSpecific];
 +
 +    // This can be called during exceptions by printf, so we cache the
 +    // value so we don't have to do memory allocations after that.
 +    if (cachedPath[fNetSpecific])
 +        return path;
 +
 +    LOCK(csPathCached);
 +
 +    if (mapArgs.count("-datadir")) {
 +        path = fs::system_complete(mapArgs["-datadir"]);
 +        if (!fs::is_directory(path)) {
 +            path = "";
 +            return path;
 +        }
 +    } else {
 +        path = GetDefaultDataDir();
      }
 -}
 +    if (fNetSpecific && GetBoolArg("-testnet", false))
 +        path /= "testnet";
  
 -string GetDataDir()
 -{
 -    char pszDir[MAX_PATH];
 -    GetDataDir(pszDir);
 -    return pszDir;
 +    fs::create_directory(path);
 +
 +    cachedPath[fNetSpecific]=true;
 +    return path;
  }
  
 -string GetConfigFile()
 +boost::filesystem::path GetConfigFile()
  {
      namespace fs = boost::filesystem;
 -    fs::path pathConfig(GetArg("-conf", "bitcoin.conf"));
 -    if (!pathConfig.is_complete())
 -        pathConfig = fs::path(GetDataDir()) / pathConfig;
 -    return pathConfig.string();
 +
 +    fs::path pathConfigFile(GetArg("-conf", "bitcoin.conf"));
 +    if (!pathConfigFile.is_complete()) pathConfigFile = GetDataDir(false) / pathConfigFile;
 +    return pathConfigFile;
  }
  
 -bool ReadConfigFile(map<string, string>& mapSettingsRet,
 +void 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 true; // No bitcoin.conf file is OK
 +        return; // No bitcoin.conf file is OK
  
      set<string> setOptions;
      setOptions.insert("*");
 -    
 +
      for (pod::config_file_iterator it(streamConfig, setOptions), end; it != end; ++it)
      {
          // Don't overwrite existing settings so command line settings override bitcoin.conf
          }
          mapMultiSettingsRet[strKey].push_back(it->value[0]);
      }
 -    return true;
  }
  
 -string GetPidFile()
 +boost::filesystem::path GetPidFile()
  {
      namespace fs = boost::filesystem;
 -    fs::path pathConfig(GetArg("-pid", "bitcoind.pid"));
 -    if (!pathConfig.is_complete())
 -        pathConfig = fs::path(GetDataDir()) / pathConfig;
 -    return pathConfig.string();
 +
 +    fs::path pathPidFile(GetArg("-pid", "bitcoind.pid"));
 +    if (!pathPidFile.is_complete()) pathPidFile = GetDataDir() / pathPidFile;
 +    return pathPidFile;
  }
  
 -void CreatePidFile(string pidFile, pid_t pid)
 +void CreatePidFile(const boost::filesystem::path &path, pid_t pid)
  {
 -    FILE* file = fopen(pidFile.c_str(), "w");
 +    FILE* file = fopen(path.string().c_str(), "w");
      if (file)
      {
          fprintf(file, "%d\n", pid);
@@@ -955,8 -961,8 +958,8 @@@ int GetFilesize(FILE* file
  void ShrinkDebugFile()
  {
      // Scroll debug.log if it's getting too big
 -    string strFile = GetDataDir() + "/debug.log";
 -    FILE* file = fopen(strFile.c_str(), "r");
 +    boost::filesystem::path pathLog = GetDataDir() / "debug.log";
 +    FILE* file = fopen(pathLog.string().c_str(), "r");
      if (file && GetFilesize(file) > 10 * 1000000)
      {
          // Restart the file with some of the end
          int nBytes = fread(pch, 1, sizeof(pch), file);
          fclose(file);
  
 -        file = fopen(strFile.c_str(), "w");
 +        file = fopen(pathLog.string().c_str(), "w");
          if (file)
          {
              fwrite(pch, 1, nBytes, file);
@@@ -1049,7 -1055,7 +1052,7 @@@ void AddTimeData(const CNetAddr& ip, in
                      string strMessage = _("Warning: Please check that your computer's date and time are correct.  If your clock is wrong Bitcoin will not work properly.");
                      strMiscWarning = strMessage;
                      printf("*** %s\n", strMessage.c_str());
 -                    boost::thread(boost::bind(ThreadSafeMessageBox, strMessage+" ", string("Bitcoin"), wxOK | wxICON_EXCLAMATION, (wxWindow*)NULL, -1, -1));
 +                    ThreadSafeMessageBox(strMessage+" ", string("Bitcoin"), wxOK | wxICON_EXCLAMATION);
                  }
              }
          }
@@@ -1079,7 -1085,12 +1082,7 @@@ string FormatVersion(int nVersion
  
  string FormatFullVersion()
  {
 -    string s = FormatVersion(CLIENT_VERSION);
 -    if (VERSION_IS_BETA) {
 -        s += "-";
 -        s += _("beta");
 -    }
 -    return s;
 +    return CLIENT_BUILD;
  }
  
  // Format the subversion field according to BIP 14 spec (https://en.bitcoin.it/wiki/BIP_0014)
@@@ -1094,149 -1105,6 +1097,149 @@@ std::string FormatSubVersion(const std:
      return ss.str();
  }
  
 +#ifdef WIN32
 +boost::filesystem::path static StartupShortcutPath()
 +{
 +    return MyGetSpecialFolderPath(CSIDL_STARTUP, true) / "Bitcoin.lnk";
 +}
 +
 +bool GetStartOnSystemStartup()
 +{
 +    return filesystem::exists(StartupShortcutPath());
 +}
 +
 +bool SetStartOnSystemStartup(bool fAutoStart)
 +{
 +    // If the shortcut exists already, remove it for updating
 +    boost::filesystem::remove(StartupShortcutPath());
 +
 +    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().string().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 static GetAutostartDir()
 +{
 +    namespace fs = boost::filesystem;
 +
 +    char* pszConfigHome = getenv("XDG_CONFIG_HOME");
 +    if (pszConfigHome) return fs::path(pszConfigHome) / "autostart";
 +    char* pszHome = getenv("HOME");
 +    if (pszHome) return fs::path(pszHome) / ".config" / "autostart";
 +    return fs::path();
 +}
 +
 +boost::filesystem::path static GetAutostartFilePath()
 +{
 +    return GetAutostartDir() / "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)
 +        boost::filesystem::remove(GetAutostartFilePath());
 +    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
 +
  
  
  #ifdef DEBUG_LOCKORDER
@@@ -1271,25 -1139,25 +1274,25 @@@ private
      int sourceLine;
  };
  
 -typedef std::vector< std::pair<CCriticalSection*, CLockLocation> > LockStack;
 +typedef std::vector< std::pair<void*, CLockLocation> > LockStack;
  
  static boost::interprocess::interprocess_mutex dd_mutex;
 -static std::map<std::pair<CCriticalSection*, CCriticalSection*>, LockStack> lockorders;
 +static std::map<std::pair<void*, void*>, LockStack> lockorders;
  static boost::thread_specific_ptr<LockStack> lockstack;
  
  
 -static void potential_deadlock_detected(const std::pair<CCriticalSection*, CCriticalSection*>& mismatch, const LockStack& s1, const LockStack& s2)
 +static void potential_deadlock_detected(const std::pair<void*, void*>& mismatch, const LockStack& s1, const LockStack& s2)
  {
      printf("POTENTIAL DEADLOCK DETECTED\n");
      printf("Previous lock order was:\n");
 -    BOOST_FOREACH(const PAIRTYPE(CCriticalSection*, CLockLocation)& i, s2)
 +    BOOST_FOREACH(const PAIRTYPE(void*, CLockLocation)& i, s2)
      {
          if (i.first == mismatch.first) printf(" (1)");
          if (i.first == mismatch.second) printf(" (2)");
          printf(" %s\n", i.second.ToString().c_str());
      }
      printf("Current lock order is:\n");
 -    BOOST_FOREACH(const PAIRTYPE(CCriticalSection*, CLockLocation)& i, s1)
 +    BOOST_FOREACH(const PAIRTYPE(void*, CLockLocation)& i, s1)
      {
          if (i.first == mismatch.first) printf(" (1)");
          if (i.first == mismatch.second) printf(" (2)");
      }
  }
  
 -static void push_lock(CCriticalSection* c, const CLockLocation& locklocation)
 +static void push_lock(void* c, const CLockLocation& locklocation, bool fTry)
  {
      bool fOrderOK = true;
      if (lockstack.get() == NULL)
  
      (*lockstack).push_back(std::make_pair(c, locklocation));
  
 -    BOOST_FOREACH(const PAIRTYPE(CCriticalSection*, CLockLocation)& i, (*lockstack))
 +    if (!fTry) BOOST_FOREACH(const PAIRTYPE(void*, CLockLocation)& i, (*lockstack))
      {
          if (i.first == c) break;
  
 -        std::pair<CCriticalSection*, CCriticalSection*> p1 = std::make_pair(i.first, c);
 +        std::pair<void*, void*> p1 = std::make_pair(i.first, c);
          if (lockorders.count(p1))
              continue;
          lockorders[p1] = (*lockstack);
  
 -        std::pair<CCriticalSection*, CCriticalSection*> p2 = std::make_pair(c, i.first);
 +        std::pair<void*, void*> p2 = std::make_pair(c, i.first);
          if (lockorders.count(p2))
          {
              potential_deadlock_detected(p1, lockorders[p2], lockorders[p1]);
@@@ -1339,14 -1207,62 +1342,14 @@@ static void pop_lock(
      dd_mutex.unlock();
  }
  
 -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()
 +void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry)
  {
 -    mutex.unlock();
 -    pop_lock();
 -}
 -bool CCriticalSection::TryEnter(const char* pszName, const char* pszFile, int nLine)
 -{
 -    push_lock(this, CLockLocation(pszName, pszFile, nLine));
 -    bool result = mutex.try_lock();
 -    if (!result) pop_lock();
 -    return result;
 -}
 -
 -#else
 -
 -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()
 -{
 -    mutex.unlock();
 +    push_lock(cs, CLockLocation(pszName, pszFile, nLine), fTry);
  }
  
 -bool CCriticalSection::TryEnter(const char*, const char*, int)
 +void LeaveCritical()
  {
 -    bool result = mutex.try_lock();
 -    return result;
 +    pop_lock();
  }
  
  #endif /* DEBUG_LOCKORDER */
 -