changeset 96:bac8d598b07a draft

addr relaying fixes, proxy option and privacy patches, detect connect to self, non-final tx locktime changes, fix hide unconfirmed generated
author s_nakamoto <s_nakamoto@1a98c847-1fd6-4fd8-948a-caf3550aa51b>
date Thu, 29 Oct 2009 02:52:48 +0000
parents 8624fa6eca6a
children 6772ea5d0b47
files build.txt db.cpp headers.h irc.cpp key.h main.cpp main.h makefile net.cpp net.h serialize.h strlcpy.h ui.cpp ui.h uibase.cpp uibase.h uiproject.fbp util.cpp util.h
diffstat 19 files changed, 1209 insertions(+), 339 deletions(-) [+]
line wrap: on
line diff
--- a/build.txt
+++ b/build.txt
@@ -1,4 +1,4 @@
-BitCoin v0.1.6 ALPHA
+BitCoin v0.1.6 BETA
 
 Copyright (c) 2009 Satoshi Nakamoto
 Distributed under the MIT/X11 software license, see the accompanying
@@ -19,10 +19,10 @@
 Libraries you need to obtain separately to build:
 
               default path   download
-wxWidgets      \wxWidgets     http://www.wxwidgets.org/downloads/
-OpenSSL        \OpenSSL       http://www.openssl.org/source/
-Berkeley DB    \DB            http://www.oracle.com/technology/software/products/berkeley-db/index.html
-Boost          \Boost         http://www.boost.org/users/download/
+wxWidgets      \wxwidgets     http://www.wxwidgets.org/downloads/
+OpenSSL        \openssl       http://www.openssl.org/source/
+Berkeley DB    \db            http://www.oracle.com/technology/software/products/berkeley-db/index.html
+Boost          \boost         http://www.boost.org/users/download/
 
 Their licenses:
 wxWidgets      LGPL 2.1 with very liberal exceptions
@@ -75,7 +75,7 @@
 Berkeley DB
 -----------
 Using MinGW and MSYS:
-cd \DB\build_unix
+cd \db\build_unix
 sh ../dist/configure --enable-mingw --enable-cxx
 make
 
--- a/db.cpp
+++ b/db.cpp
@@ -121,10 +121,12 @@
     pdb->close(0);
     delete pdb;
     pdb = NULL;
-    dbenv.txn_checkpoint(0, 0, 0);
 
     CRITICAL_BLOCK(cs_db)
+    {
+        dbenv.txn_checkpoint(0, 0, 0);
         --mapFileUseCount[strFile];
+    }
 
     RandAddSeed();
 }
@@ -376,11 +378,11 @@
     {
         if (pindexGenesisBlock == NULL)
             return true;
-        return error("CTxDB::LoadBlockIndex() : hashBestChain not found\n");
+        return error("CTxDB::LoadBlockIndex() : hashBestChain not found");
     }
 
     if (!mapBlockIndex.count(hashBestChain))
-        return error("CTxDB::LoadBlockIndex() : blockindex for hashBestChain not found\n");
+        return error("CTxDB::LoadBlockIndex() : blockindex for hashBestChain not found");
     pindexBest = mapBlockIndex[hashBestChain];
     nBestHeight = pindexBest->nHeight;
     printf("LoadBlockIndex(): hashBestChain=%s  height=%d\n", hashBestChain.ToString().substr(0,14).c_str(), nBestHeight);
@@ -500,16 +502,15 @@
 CWalletDB::~CWalletDB()
 {
     // Flush whenever all handles to wallet.dat are closed
-    Close();
     CRITICAL_BLOCK(cs_db)
     {
+        Close(); // close includes a txn_checkpoint
         map<string, int>::iterator mi = mapFileUseCount.find(strFile);
         if (mi != mapFileUseCount.end())
         {
             int nRefCount = (*mi).second;
             if (nRefCount == 0)
             {
-                dbenv.txn_checkpoint(0, 0, 0);
                 dbenv.lsn_reset(strFile.c_str(), 0);
                 mapFileUseCount.erase(mi++);
             }
@@ -600,6 +601,9 @@
                 if (strKey == "nLimitProcessors")   ssValue >> nLimitProcessors;
                 if (strKey == "fMinimizeToTray")    ssValue >> fMinimizeToTray;
                 if (strKey == "fMinimizeOnClose")   ssValue >> fMinimizeOnClose;
+                if (strKey == "fUseProxy")          ssValue >> fUseProxy;
+                if (strKey == "addrProxy")          ssValue >> addrProxy;
+
             }
         }
     }
@@ -610,6 +614,9 @@
     printf("addrIncoming = %s\n", addrIncoming.ToString().c_str());
     printf("fMinimizeToTray = %d\n", fMinimizeToTray);
     printf("fMinimizeOnClose = %d\n", fMinimizeOnClose);
+    printf("fUseProxy = %d\n", fUseProxy);
+    printf("addrProxy = %s\n", addrProxy.ToString().c_str());
+
 
     // The transaction fee setting won't be needed for many years to come.
     // Setting it to zero here in case they set it to something in an earlier version.
@@ -639,7 +646,7 @@
     else
     {
         // Create new keyUser and set as default key
-        RandAddSeed(true);
+        RandAddSeedPerfmon();
         keyUser.MakeNewKey();
         if (!AddKey(keyUser))
             return false;
--- a/headers.h
+++ b/headers.h
@@ -5,6 +5,7 @@
 #ifdef _MSC_VER
 #pragma warning(disable:4786)
 #pragma warning(disable:4804)
+#pragma warning(disable:4805)
 #pragma warning(disable:4717)
 #endif
 #ifdef _WIN32_WINNT
@@ -62,6 +63,7 @@
 
 
 
+#include "strlcpy.h"
 #include "serialize.h"
 #include "uint256.h"
 #include "util.h"
--- a/irc.cpp
+++ b/irc.cpp
@@ -163,6 +163,9 @@
     int nErrorWait = 10;
     int nRetryWait = 10;
 
+    if (fUseProxy && addrProxy.port == htons(9050))
+        return;
+
     while (!fShutdown)
     {
         CAddress addrConnect("216.155.130.130:6667");
@@ -191,9 +194,10 @@
                 return;
         }
 
-        string strMyName = EncodeAddress(addrLocalHost);
-
-        if (!addrLocalHost.IsRoutable())
+        string strMyName;
+        if (addrLocalHost.IsRoutable() && !fUseProxy)
+            strMyName = EncodeAddress(addrLocalHost);
+        else
             strMyName = strprintf("x%u", GetRand(1000000000));
 
 
--- a/key.h
+++ b/key.h
@@ -35,7 +35,7 @@
 };
 
 
-// secure_allocator is defined is serialize.h
+// secure_allocator is defined in serialize.h
 typedef vector<unsigned char, secure_allocator<unsigned char> > CPrivKey;
 
 
--- a/main.cpp
+++ b/main.cpp
@@ -415,6 +415,10 @@
     if (!CheckTransaction())
         return error("AcceptTransaction() : CheckTransaction failed");
 
+    // To help v0.1.5 clients who would see it as negative number. please delete this later.
+    if (nLockTime > INT_MAX)
+        return error("AcceptTransaction() : not accepting nLockTime beyond 2038");
+
     // Do we already have it?
     uint256 hash = GetHash();
     CRITICAL_BLOCK(cs_mapTransactions)
@@ -1214,6 +1218,12 @@
     if (nTime <= pindexPrev->GetMedianTimePast())
         return error("AcceptBlock() : block's timestamp is too early");
 
+    // Check that all transactions are finalized (starting around 30 Nov 2009)
+    if (nBestHeight > 31000) // 25620 + 5320
+        foreach(const CTransaction& tx, vtx)
+            if (!tx.IsFinal(nTime))
+                return error("AcceptBlock() : contains a non-final transaction");
+
     // Check proof of work
     if (nBits != GetNextWorkRequired(pindexPrev))
         return error("AcceptBlock() : incorrect proof of work");
@@ -1649,7 +1659,7 @@
     CDataStream& vRecv = pfrom->vRecv;
     if (vRecv.empty())
         return true;
-    printf("ProcessMessages(%d bytes)\n", vRecv.size());
+    //printf("ProcessMessages(%d bytes)\n", vRecv.size());
 
     //
     // Message format
@@ -1692,7 +1702,7 @@
         {
             // Rewind and wait for rest of message
             ///// need a mechanism to give up waiting for overlong message size error
-            printf("MESSAGE-BREAK\n");
+            //printf("message-break\n");
             vRecv.insert(vRecv.begin(), BEGIN(hdr), END(hdr));
             Sleep(100);
             break;
@@ -1711,7 +1721,20 @@
                 fRet = ProcessMessage(pfrom, strCommand, vMsg);
             CheckForShutdown(2);
         }
-        CATCH_PRINT_EXCEPTION("ProcessMessage()")
+        catch (std::ios_base::failure& e) {
+            if (strstr(e.what(), "CDataStream::read() : end of data"))
+            {
+                // Allow exceptions from underlength message on vRecv
+                LogException(&e, "ProcessMessage()");
+            }
+            else
+                PrintException(&e, "ProcessMessage()");
+        } catch (std::exception& e) {
+            PrintException(&e, "ProcessMessage()");
+        } catch (...) {
+            PrintException(NULL, "ProcessMessage()");
+        }
+
         if (!fRet)
             printf("ProcessMessage(%s, %d bytes) FAILED\n", strCommand.c_str(), nMessageSize);
     }
@@ -1726,7 +1749,8 @@
 bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
 {
     static map<unsigned int, vector<unsigned char> > mapReuseKey;
-    printf("received: %-12s (%d bytes)\n", strCommand.c_str(), vRecv.size());
+    RandAddSeedPerfmon();
+    printf("received: %s (%d bytes)\n", strCommand.c_str(), vRecv.size());
     if (nDropMessagesTest > 0 && GetRand(nDropMessagesTest) == 0)
     {
         printf("dropmessages DROPPING RECV MESSAGE\n");
@@ -1735,18 +1759,32 @@
 
 
 
+
     if (strCommand == "version")
     {
-        // Can only do this once
+        // Each connection can only send one version message
         if (pfrom->nVersion != 0)
             return false;
 
         int64 nTime;
         CAddress addrMe;
+        CAddress addrFrom;
+        uint64 nNonce = 1;
         vRecv >> pfrom->nVersion >> pfrom->nServices >> nTime >> addrMe;
+        if (pfrom->nVersion >= 106 && !vRecv.empty())
+            vRecv >> addrFrom >> nNonce;
         if (pfrom->nVersion == 0)
             return false;
 
+        // Disconnect if we connected to ourself
+        if (nNonce == nLocalHostNonce)
+        {
+            pfrom->fDisconnect = true;
+            pfrom->vRecv.clear();
+            pfrom->vSend.clear();
+            return true;
+        }
+
         pfrom->vSend.SetVersion(min(pfrom->nVersion, VERSION));
         pfrom->vRecv.SetVersion(min(pfrom->nVersion, VERSION));
 
@@ -1767,6 +1805,8 @@
             pfrom->PushMessage("getblocks", CBlockLocator(pindexBest), uint256(0));
         }
 
+        pfrom->fSuccessfullyConnected = true;
+
         printf("version message: version %d\n", pfrom->nVersion);
     }
 
@@ -1800,16 +1840,16 @@
             if (fShutdown)
                 return true;
             AddAddress(addrdb, addr);
-            if (addr.IsRoutable() && addr.ip != addrLocalHost.ip)
+            pfrom->AddAddressKnown(addr);
+            if (!pfrom->fGetAddr && addr.IsRoutable())
             {
                 // Put on lists to send to other nodes
-                pfrom->setAddrKnown.insert(addr);
                 CRITICAL_BLOCK(cs_vNodes)
                     foreach(CNode* pnode, vNodes)
-                        if (!pnode->setAddrKnown.count(addr))
-                            pnode->vAddrToSend.push_back(addr);
+                        pnode->PushAddress(addr);
             }
         }
+        pfrom->fGetAddr = false;
     }
 
 
@@ -2009,7 +2049,7 @@
                     return true;
                 const CAddress& addr = item.second;
                 if (addr.nTime > nSince)
-                    pfrom->vAddrToSend.push_back(addr);
+                    pfrom->PushAddress(addr);
             }
         }
     }
@@ -2108,8 +2148,11 @@
         vector<CAddress> vAddrToSend;
         vAddrToSend.reserve(pto->vAddrToSend.size());
         foreach(const CAddress& addr, pto->vAddrToSend)
-            if (!pto->setAddrKnown.count(addr))
+        {
+            // returns true if wasn't already contained in the set
+            if (pto->setAddrKnown.insert(addr).second)
                 vAddrToSend.push_back(addr);
+        }
         pto->vAddrToSend.clear();
         if (!vAddrToSend.empty())
             pto->PushMessage("addr", vAddrToSend);
@@ -2193,7 +2236,7 @@
         if (fLimitProcessors && nProcessors > nLimitProcessors)
             nProcessors = nLimitProcessors;
         int nAddThreads = nProcessors - vnThreadsRunning[3];
-        printf("starting %d bitcoinminer threads\n", nAddThreads);
+        printf("Starting %d BitcoinMiner threads\n", nAddThreads);
         for (int i = 0; i < nAddThreads; i++)
             if (_beginthread(ThreadBitcoinMiner, 0, NULL) == -1)
                 printf("Error: _beginthread(ThreadBitcoinMiner) failed\n");
@@ -2207,7 +2250,7 @@
     try
     {
         bool fRet = BitcoinMiner();
-        printf("BitcoinMiner returned %s\n\n\n", fRet ? "true" : "false");
+        printf("BitcoinMiner returned %s\n", fRet ? "true" : "false");
         vnThreadsRunning[3]--;
     }
     catch (std::exception& e) {
@@ -2737,7 +2780,7 @@
             else
                 strError = "Error: Transaction creation failed  ";
             wxMessageBox(strError, "Sending...");
-            return error("SendMoney() : %s\n", strError.c_str());
+            return error("SendMoney() : %s", strError.c_str());
         }
         if (!CommitTransactionSpent(wtxNew, key))
         {
--- a/main.h
+++ b/main.h
@@ -366,7 +366,7 @@
     int nVersion;
     vector<CTxIn> vin;
     vector<CTxOut> vout;
-    int nLockTime;
+    unsigned int nLockTime;
 
 
     CTransaction()
@@ -401,9 +401,15 @@
         return SerializeHash(*this);
     }
 
-    bool IsFinal() const
+    bool IsFinal(int64 nBlockTime=0) const
     {
-        if (nLockTime == 0 || nLockTime < nBestHeight)
+        // Time based nLockTime implemented in 0.1.6,
+        // do not use time based until most 0.1.5 nodes have upgraded.
+        if (nBlockTime == 0)
+            nBlockTime = GetAdjustedTime();
+        if (nLockTime == 0)
+            return true;
+        if (nLockTime < (nLockTime < 500000000 ? nBestHeight : nBlockTime))
             return true;
         foreach(const CTxIn& txin, vin)
             if (!txin.IsFinal())
@@ -686,8 +692,9 @@
     char fSpent;
     //// probably need to sign the order info so know it came from payer
 
-    // memory only
+    // memory only UI hints
     mutable unsigned int nTimeDisplayed;
+    mutable int nLinesDisplayed;
 
 
     CWalletTx()
@@ -712,6 +719,7 @@
         fFromMe = false;
         fSpent = false;
         nTimeDisplayed = 0;
+        nLinesDisplayed = 0;
     }
 
     IMPLEMENT_SERIALIZE
--- a/makefile
+++ b/makefile
@@ -17,8 +17,8 @@
 
 
 
-INCLUDEPATHS=-I"/boost" -I"/DB/build_unix" -I"/OpenSSL/include" -I"/wxWidgets/lib/vc_lib/mswd" -I"/wxWidgets/include"
-LIBPATHS=-L"/DB/build_unix" -L"/OpenSSL/out" -L"/wxWidgets/lib/gcc_lib"
+INCLUDEPATHS=-I"/boost" -I"/db/build_unix" -I"/openssl/include" -I"/wxwidgets/lib/vc_lib/mswd" -I"/wxwidgets/include"
+LIBPATHS=-L"/db/build_unix" -L"/openssl/out" -L"/wxwidgets/lib/gcc_lib"
 LIBS= \
  -l db_cxx \
  -l eay32 \
--- a/net.cpp
+++ b/net.cpp
@@ -8,6 +8,7 @@
 void ThreadMessageHandler2(void* parg);
 void ThreadSocketHandler2(void* parg);
 void ThreadOpenConnections2(void* parg);
+bool OpenNetworkConnection(const CAddress& addrConnect);
 
 
 
@@ -22,8 +23,10 @@
 CAddress addrLocalHost(0, DEFAULT_PORT, nLocalServices);
 CNode nodeLocalHost(INVALID_SOCKET, CAddress("127.0.0.1", nLocalServices));
 CNode* pnodeLocalHost = &nodeLocalHost;
+uint64 nLocalHostNonce = 0;
 bool fShutdown = false;
 array<int, 10> vnThreadsRunning;
+SOCKET hListenSocket = INVALID_SOCKET;
 
 vector<CNode*> vNodes;
 CCriticalSection cs_vNodes;
@@ -34,9 +37,11 @@
 CCriticalSection cs_mapRelay;
 map<CInv, int64> mapAlreadyAskedFor;
 
+// Settings
+int fUseProxy = false;
+CAddress addrProxy("127.0.0.1:9050");
 
 
-CAddress addrProxy;
 
 bool ConnectSocket(const CAddress& addrConnect, SOCKET& hSocketRet)
 {
@@ -47,7 +52,7 @@
         return false;
 
     bool fRoutable = !(addrConnect.GetByte(3) == 10 || (addrConnect.GetByte(3) == 192 && addrConnect.GetByte(2) == 168));
-    bool fProxy = (addrProxy.ip && fRoutable);
+    bool fProxy = (fUseProxy && fRoutable);
     struct sockaddr_in sockaddr = (fProxy ? addrProxy.GetSockAddr() : addrConnect.GetSockAddr());
 
     if (connect(hSocket, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) == SOCKET_ERROR)
@@ -69,18 +74,18 @@
         if (ret != nSize)
         {
             closesocket(hSocket);
-            return error("Error sending to proxy\n");
+            return error("Error sending to proxy");
         }
         char pchRet[8];
         if (recv(hSocket, pchRet, 8, 0) != 8)
         {
             closesocket(hSocket);
-            return error("Error reading proxy response\n");
+            return error("Error reading proxy response");
         }
         if (pchRet[1] != 0x5a)
         {
             closesocket(hSocket);
-            return error("Proxy returned error %d\n", pchRet[1]);
+            return error("Proxy returned error %d", pchRet[1]);
         }
         printf("Proxy connection established %s\n", addrConnect.ToStringLog().c_str());
     }
@@ -95,7 +100,7 @@
 {
     SOCKET hSocket;
     if (!ConnectSocket(addrConnect, hSocket))
-        return error("GetMyExternalIP() : connection to %s failed\n", addrConnect.ToString().c_str());
+        return error("GetMyExternalIP() : connection to %s failed", addrConnect.ToString().c_str());
 
     send(hSocket, pszGet, strlen(pszGet), 0);
 
@@ -131,7 +136,7 @@
         }
     }
     closesocket(hSocket);
-    return error("GetMyExternalIP() : connection closed\n");
+    return error("GetMyExternalIP() : connection closed");
 }
 
 
@@ -141,6 +146,9 @@
     char* pszGet;
     char* pszKeyword;
 
+    if (fUseProxy)
+        return false;
+
     for (int nLookup = 0; nLookup <= 1; nLookup++)
     for (int nHost = 1; nHost <= 2; nHost++)
     {
@@ -416,14 +424,14 @@
     }
 }
 
-void CNode::Disconnect()
+void CNode::DoDisconnect()
 {
     printf("disconnecting node %s\n", addr.ToStringLog().c_str());
 
     closesocket(hSocket);
 
     // If outbound and never got version message, mark address as failed
-    if (!fInbound && nVersion == 0)
+    if (!fInbound && !fSuccessfullyConnected)
         CRITICAL_BLOCK(cs_mapAddresses)
             mapAddresses[addr.GetKey()].nLastFailed = GetTime();
 
@@ -458,18 +466,18 @@
 
     loop
     {
-        vnThreadsRunning[0] = true;
+        vnThreadsRunning[0]++;
         CheckForShutdown(0);
         try
         {
             ThreadSocketHandler2(parg);
-            vnThreadsRunning[0] = false;
+            vnThreadsRunning[0]--;
         }
         catch (std::exception& e) {
-            vnThreadsRunning[0] = false;
+            vnThreadsRunning[0]--;
             PrintException(&e, "ThreadSocketHandler()");
         } catch (...) {
-            vnThreadsRunning[0] = false;
+            vnThreadsRunning[0]--;
             PrintException(NULL, "ThreadSocketHandler()");
         }
         Sleep(5000);
@@ -479,7 +487,6 @@
 void ThreadSocketHandler2(void* parg)
 {
     printf("ThreadSocketHandler started\n");
-    SOCKET hListenSocket = *(SOCKET*)parg;
     list<CNode*> vNodesDisconnected;
     int nPrevNodeCount = 0;
 
@@ -498,7 +505,7 @@
                 {
                     // remove from vNodes
                     vNodes.erase(remove(vNodes.begin(), vNodes.end(), pnode), vNodes.end());
-                    pnode->Disconnect();
+                    pnode->DoDisconnect();
 
                     // hold in disconnected pool until all refs are released
                     pnode->nReleaseTime = max(pnode->nReleaseTime, GetTime() + 5 * 60);
@@ -562,9 +569,9 @@
             }
         }
 
-        vnThreadsRunning[0] = false;
+        vnThreadsRunning[0]--;
         int nSelect = select(hSocketMax + 1, &fdsetRecv, &fdsetSend, NULL, &timeout);
-        vnThreadsRunning[0] = true;
+        vnThreadsRunning[0]++;
         CheckForShutdown(0);
         if (nSelect == SOCKET_ERROR)
         {
@@ -577,7 +584,6 @@
             }
             Sleep(timeout.tv_usec/1000);
         }
-        RandAddSeed();
 
         //// debug print
         //foreach(CNode* pnode, vNodes)
@@ -711,18 +717,18 @@
 
     loop
     {
-        vnThreadsRunning[1] = true;
+        vnThreadsRunning[1]++;
         CheckForShutdown(1);
         try
         {
             ThreadOpenConnections2(parg);
-            vnThreadsRunning[1] = false;
+            vnThreadsRunning[1]--;
         }
         catch (std::exception& e) {
-            vnThreadsRunning[1] = false;
+            vnThreadsRunning[1]--;
             PrintException(&e, "ThreadOpenConnections()");
         } catch (...) {
-            vnThreadsRunning[1] = false;
+            vnThreadsRunning[1]--;
             PrintException(NULL, "ThreadOpenConnections()");
         }
         Sleep(5000);
@@ -733,6 +739,13 @@
 {
     printf("ThreadOpenConnections started\n");
 
+    // Connect to one specified address
+    while (mapArgs.count("/connect"))
+    {
+        OpenNetworkConnection(CAddress(mapArgs["/connect"].c_str()));
+        Sleep(10000);
+    }
+
     // Initiate network connections
     int nTry = 0;
     bool fIRCOnly = false;
@@ -740,14 +753,14 @@
     loop
     {
         // Wait
-        vnThreadsRunning[1] = false;
+        vnThreadsRunning[1]--;
         Sleep(500);
         while (vNodes.size() >= nMaxConnections || vNodes.size() >= mapAddresses.size())
         {
             CheckForShutdown(1);
             Sleep(2000);
         }
-        vnThreadsRunning[1] = true;
+        vnThreadsRunning[1]++;
         CheckForShutdown(1);
 
 
@@ -835,43 +848,48 @@
 
         // Once we've chosen an IP, we'll try every given port before moving on
         foreach(const CAddress& addrConnect, (*mi).second)
-        {
-            //
-            // Initiate outbound network connection
-            //
-            CheckForShutdown(1);
-            if (addrConnect.ip == addrLocalHost.ip || !addrConnect.IsIPv4() || FindNode(addrConnect.ip))
-                continue;
+            if (OpenNetworkConnection(addrConnect))
+                break;
+    }
+}
 
-            vnThreadsRunning[1] = false;
-            CNode* pnode = ConnectNode(addrConnect);
-            vnThreadsRunning[1] = true;
-            CheckForShutdown(1);
-            if (!pnode)
-                continue;
-            pnode->fNetworkNode = true;
+bool OpenNetworkConnection(const CAddress& addrConnect)
+{
+    //
+    // Initiate outbound network connection
+    //
+    CheckForShutdown(1);
+    if (addrConnect.ip == addrLocalHost.ip || !addrConnect.IsIPv4() || FindNode(addrConnect.ip))
+        return false;
 
-            if (addrLocalHost.IsRoutable())
-            {
-                // Advertise our address
-                vector<CAddress> vAddrToSend;
-                vAddrToSend.push_back(addrLocalHost);
-                pnode->PushMessage("addr", vAddrToSend);
-            }
-
-            // Get as many addresses as we can
-            pnode->PushMessage("getaddr");
+    vnThreadsRunning[1]--;
+    CNode* pnode = ConnectNode(addrConnect);
+    vnThreadsRunning[1]++;
+    CheckForShutdown(1);
+    if (!pnode)
+        return false;
+    pnode->fNetworkNode = true;
 
-            ////// should the one on the receiving end do this too?
-            // Subscribe our local subscription list
-            const unsigned int nHops = 0;
-            for (unsigned int nChannel = 0; nChannel < pnodeLocalHost->vfSubscribe.size(); nChannel++)
-                if (pnodeLocalHost->vfSubscribe[nChannel])
-                    pnode->PushMessage("subscribe", nChannel, nHops);
+    if (addrLocalHost.IsRoutable() && !fUseProxy)
+    {
+        // Advertise our address
+        vector<CAddress> vAddrToSend;
+        vAddrToSend.push_back(addrLocalHost);
+        pnode->PushMessage("addr", vAddrToSend);
+    }
 
-            break;
-        }
-    }
+    // Get as many addresses as we can
+    pnode->PushMessage("getaddr");
+    pnode->fGetAddr = true; // don't relay the results of the getaddr
+
+    ////// should the one on the receiving end do this too?
+    // Subscribe our local subscription list
+    const unsigned int nHops = 0;
+    for (unsigned int nChannel = 0; nChannel < pnodeLocalHost->vfSubscribe.size(); nChannel++)
+        if (pnodeLocalHost->vfSubscribe[nChannel])
+            pnode->PushMessage("subscribe", nChannel, nHops);
+
+    return true;
 }
 
 
@@ -887,18 +905,18 @@
 
     loop
     {
-        vnThreadsRunning[2] = true;
+        vnThreadsRunning[2]++;
         CheckForShutdown(2);
         try
         {
             ThreadMessageHandler2(parg);
-            vnThreadsRunning[2] = false;
+            vnThreadsRunning[2]--;
         }
         catch (std::exception& e) {
-            vnThreadsRunning[2] = false;
+            vnThreadsRunning[2]--;
             PrintException(&e, "ThreadMessageHandler()");
         } catch (...) {
-            vnThreadsRunning[2] = false;
+            vnThreadsRunning[2]--;
             PrintException(NULL, "ThreadMessageHandler()");
         }
         Sleep(5000);
@@ -931,9 +949,9 @@
         }
 
         // Wait and allow messages to bunch up
-        vnThreadsRunning[2] = false;
+        vnThreadsRunning[2]--;
         Sleep(100);
-        vnThreadsRunning[2] = true;
+        vnThreadsRunning[2]++;
         CheckForShutdown(2);
     }
 }
@@ -982,7 +1000,7 @@
     printf("addrLocalHost = %s\n", addrLocalHost.ToString().c_str());
 
     // Create socket for listening for incoming connections
-    SOCKET hListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    hListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
     if (hListenSocket == INVALID_SOCKET)
     {
         strError = strprintf("Error: Couldn't open socket for incoming connections (socket returned error %d)", WSAGetLastError());
@@ -1024,13 +1042,21 @@
     }
 
     // Get our external IP address for incoming connections
-    if (addrIncoming.ip)
-        addrLocalHost.ip = addrIncoming.ip;
+    if (fUseProxy)
+    {
+        // Proxies can't take incoming connections
+        addrLocalHost.ip = CAddress("0.0.0.0").ip;
+    }
+    else
+    {
+        if (addrIncoming.ip)
+            addrLocalHost.ip = addrIncoming.ip;
 
-    if (GetMyExternalIP(addrLocalHost.ip))
-    {
-        addrIncoming = addrLocalHost;
-        CWalletDB().WriteSetting("addrIncoming", addrIncoming);
+        if (GetMyExternalIP(addrLocalHost.ip))
+        {
+            addrIncoming = addrLocalHost;
+            CWalletDB().WriteSetting("addrIncoming", addrIncoming);
+        }
     }
 
     // Get addresses from IRC and advertise ours
@@ -1040,7 +1066,7 @@
     //
     // Start threads
     //
-    if (_beginthread(ThreadSocketHandler, 0, new SOCKET(hListenSocket)) == -1)
+    if (_beginthread(ThreadSocketHandler, 0, NULL) == -1)
     {
         strError = "Error: _beginthread(ThreadSocketHandler) failed";
         printf("%s\n", strError.c_str());
@@ -1094,10 +1120,15 @@
     if (fShutdown)
     {
         if (n != -1)
-            vnThreadsRunning[n] = false;
+            if (--vnThreadsRunning[n] < 0)
+                vnThreadsRunning[n] = 0;
         if (n == 0)
+        {
             foreach(CNode* pnode, vNodes)
                 closesocket(pnode->hSocket);
+            closesocket(hListenSocket);
+        }
+        printf("Thread %d exiting\n", n);
         _endthread();
     }
 }
--- a/net.h
+++ b/net.h
@@ -174,7 +174,7 @@
     {
         nServices = nServicesIn;
         memcpy(pchReserved, pchIPv4, sizeof(pchReserved));
-        ip = 0;
+        ip = INADDR_NONE;
         port = DEFAULT_PORT;
         nTime = GetAdjustedTime();
         nLastFailed = 0;
@@ -183,7 +183,7 @@
         if (strlen(pszIn) > ARRAYLEN(psz)-1)
             return;
         strcpy(psz, pszIn);
-        unsigned int a, b, c, d, e;
+        unsigned int a=0, b=0, c=0, d=0, e=0;
         if (sscanf(psz, "%u.%u.%u.%u:%u", &a, &b, &c, &d, &e) < 4)
             return;
         char* pszPort = strchr(psz, ':');
@@ -191,6 +191,10 @@
         {
             *pszPort++ = '\0';
             port = htons(atoi(pszPort));
+            if (atoi(pszPort) > USHRT_MAX)
+                port = htons(USHRT_MAX);
+            if (atoi(pszPort) < 0)
+                port = htons(0);
         }
         ip = inet_addr(psz);
     }
@@ -215,6 +219,11 @@
                 a.port == b.port);
     }
 
+    friend inline bool operator!=(const CAddress& a, const CAddress& b)
+    {
+        return (!(a == b));
+    }
+
     friend inline bool operator<(const CAddress& a, const CAddress& b)
     {
         int ret = memcmp(a.pchReserved, b.pchReserved, sizeof(a.pchReserved));
@@ -277,6 +286,11 @@
         return strprintf("%u.%u.%u.%u", GetByte(3), GetByte(2), GetByte(1), GetByte(0));
     }
 
+    string ToStringPort() const
+    {
+        return strprintf("%u", ntohs(port));
+    }
+
     string ToStringLog() const
     {
         return "";
@@ -416,6 +430,7 @@
 extern uint64 nLocalServices;
 extern CAddress addrLocalHost;
 extern CNode* pnodeLocalHost;
+extern uint64 nLocalHostNonce;
 extern bool fShutdown;
 extern array<int, 10> vnThreadsRunning;
 extern vector<CNode*> vNodes;
@@ -426,6 +441,9 @@
 extern deque<pair<int64, CInv> > vRelayExpiration;
 extern CCriticalSection cs_mapRelay;
 extern map<CInv, int64> mapAlreadyAskedFor;
+
+// Settings
+extern int fUseProxy;
 extern CAddress addrProxy;
 
 
@@ -448,6 +466,7 @@
     bool fClient;
     bool fInbound;
     bool fNetworkNode;
+    bool fSuccessfullyConnected;
     bool fDisconnect;
 protected:
     int nRefCount;
@@ -459,6 +478,7 @@
     // flood
     vector<CAddress> vAddrToSend;
     set<CAddress> setAddrKnown;
+    bool fGetAddr;
 
     // inventory based relay
     set<CInv> setInventoryKnown;
@@ -483,15 +503,20 @@
         fClient = false; // set by version message
         fInbound = fInboundIn;
         fNetworkNode = false;
+        fSuccessfullyConnected = false;
         fDisconnect = false;
         nRefCount = 0;
         nReleaseTime = 0;
+        fGetAddr = false;
         vfSubscribe.assign(256, false);
 
         // Push a version message
         /// when NTP implemented, change to just nTime = GetAdjustedTime()
         int64 nTime = (fInbound ? GetAdjustedTime() : GetTime());
-        PushMessage("version", VERSION, nLocalServices, nTime, addr);
+        CAddress addrYou = (fUseProxy ? CAddress("0.0.0.0") : addr);
+        CAddress addrMe = (fUseProxy ? CAddress("0.0.0.0") : addrLocalHost);
+        RAND_bytes((unsigned char*)&nLocalHostNonce, sizeof(nLocalHostNonce));
+        PushMessage("version", VERSION, nLocalServices, nTime, addrYou, addrMe, nLocalHostNonce);
     }
 
     ~CNode()
@@ -531,6 +556,21 @@
 
 
 
+    void AddAddressKnown(const CAddress& addr)
+    {
+        setAddrKnown.insert(addr);
+    }
+
+    void PushAddress(const CAddress& addr)
+    {
+        // Known checking here is only to save space from duplicates.
+        // SendMessages will filter it again for knowns that were added
+        // after addresses were pushed.
+        if (!setAddrKnown.count(addr))
+            vAddrToSend.push_back(addr);
+    }
+
+
     void AddInventoryKnown(const CInv& inv)
     {
         CRITICAL_BLOCK(cs_inventory)
@@ -562,7 +602,6 @@
     }
 
 
-
     void BeginMessage(const char* pszCommand)
     {
         EnterCriticalSection(&cs_vSend);
@@ -570,7 +609,7 @@
             AbortMessage();
         nPushPos = vSend.size();
         vSend << CMessageHeader(pszCommand, 0);
-        printf("sending: %-12s ", pszCommand);
+        printf("sending: %s ", pszCommand);
     }
 
     void AbortMessage()
@@ -706,6 +745,86 @@
         }
     }
 
+    template<typename T1, typename T2, typename T3, typename T4, typename T5>
+    void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5)
+    {
+        try
+        {
+            BeginMessage(pszCommand);
+            vSend << a1 << a2 << a3 << a4 << a5;
+            EndMessage();
+        }
+        catch (...)
+        {
+            AbortMessage();
+            throw;
+        }
+    }
+
+    template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
+    void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5, const T6& a6)
+    {
+        try
+        {
+            BeginMessage(pszCommand);
+            vSend << a1 << a2 << a3 << a4 << a5 << a6;
+            EndMessage();
+        }
+        catch (...)
+        {
+            AbortMessage();
+            throw;
+        }
+    }
+
+    template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7>
+    void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5, const T6& a6, const T7& a7)
+    {
+        try
+        {
+            BeginMessage(pszCommand);
+            vSend << a1 << a2 << a3 << a4 << a5 << a6 << a7;
+            EndMessage();
+        }
+        catch (...)
+        {
+            AbortMessage();
+            throw;
+        }
+    }
+
+    template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8>
+    void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5, const T6& a6, const T7& a7, const T8& a8)
+    {
+        try
+        {
+            BeginMessage(pszCommand);
+            vSend << a1 << a2 << a3 << a4 << a5 << a6 << a7 << a8;
+            EndMessage();
+        }
+        catch (...)
+        {
+            AbortMessage();
+            throw;
+        }
+    }
+
+    template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9>
+    void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5, const T6& a6, const T7& a7, const T8& a8, const T9& a9)
+    {
+        try
+        {
+            BeginMessage(pszCommand);
+            vSend << a1 << a2 << a3 << a4 << a5 << a6 << a7 << a8 << a9;
+            EndMessage();
+        }
+        catch (...)
+        {
+            AbortMessage();
+            throw;
+        }
+    }
+
 
     void PushRequest(const char* pszCommand,
                      void (*fn)(void*, CDataStream&), void* param1)
@@ -750,7 +869,7 @@
     bool IsSubscribed(unsigned int nChannel);
     void Subscribe(unsigned int nChannel, unsigned int nHops=0);
     void CancelSubscribe(unsigned int nChannel);
-    void Disconnect();
+    void DoDisconnect();
 };
 
 
--- a/serialize.h
+++ b/serialize.h
@@ -19,7 +19,7 @@
 class CDataStream;
 class CAutoFile;
 
-static const int VERSION = 105;
+static const int VERSION = 106;
 
 
 
new file mode 100644
--- /dev/null
+++ b/strlcpy.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Copy src to string dst of size siz.  At most siz-1 characters
+ * will be copied.  Always NUL terminates (unless siz == 0).
+ * Returns strlen(src); if retval >= siz, truncation occurred.
+ */
+inline size_t strlcpy(char *dst, const char *src, size_t siz)
+{
+    char *d = dst;
+    const char *s = src;
+    size_t n = siz;
+
+    /* Copy as many bytes as will fit */
+    if (n != 0)
+    {
+        while (--n != 0)
+        {
+            if ((*d++ = *s++) == '\0')
+                break;
+        }
+    }
+
+    /* Not enough room in dst, add NUL and traverse rest of src */
+    if (n == 0)
+    {
+        if (siz != 0)
+            *d = '\0';  /* NUL-terminate dst */
+        while (*s++)
+            ;
+    }
+
+    return(s - src - 1); /* count does not include NUL */
+}
+
+/*
+ * Appends src to string dst of size siz (unlike strncat, siz is the
+ * full size of dst, not space left).  At most siz-1 characters
+ * will be copied.  Always NUL terminates (unless siz <= strlen(dst)).
+ * Returns strlen(src) + MIN(siz, strlen(initial dst)).
+ * If retval >= siz, truncation occurred.
+ */
+inline size_t strlcat(char *dst, const char *src, size_t siz)
+{
+    char *d = dst;
+    const char *s = src;
+    size_t n = siz;
+    size_t dlen;
+
+    /* Find the end of dst and adjust bytes left but don't go past end */
+    while (n-- != 0 && *d != '\0')
+        d++;
+    dlen = d - dst;
+    n = siz - dlen;
+
+    if (n == 0)
+        return(dlen + strlen(s));
+    while (*s != '\0')
+    {
+        if (n != 1)
+        {
+            *d++ = *s;
+            n--;
+        }
+        s++;
+    }
+    *d = '\0';
+
+    return(dlen + (s - src)); /* count does not include NUL */
+}
--- a/ui.cpp
+++ b/ui.cpp
@@ -497,7 +497,7 @@
     return strOut;
 }
 
-void CMainFrame::InsertTransaction(const CWalletTx& wtx, bool fNew, int nIndex)
+bool CMainFrame::InsertTransaction(const CWalletTx& wtx, bool fNew, int nIndex)
 {
     int64 nTime = wtx.nTimeDisplayed = wtx.GetTxTime();
     int64 nCredit = wtx.GetCredit();
@@ -506,14 +506,11 @@
     uint256 hash = wtx.GetHash();
     string strStatus = FormatTxStatus(wtx);
     map<string, string> mapValue = wtx.mapValue;
+    wtx.nLinesDisplayed = 1;
 
     // Filter
     if (wtx.IsCoinBase())
     {
-        // View->Show Generated
-        if (!fShowGenerated)
-            return;
-
         // Don't show generated coin until confirmed by at least one block after it
         // so we don't get the user's hopes up until it looks like it's probably accepted.
         //
@@ -527,10 +524,13 @@
         //
         if (wtx.GetDepthInMainChain() < 2)
         {
-            // In case it was previously displayed
-            DeleteLine(hash);
-            return;
+            wtx.nLinesDisplayed = 0;
+            return false;
         }
+
+        // View->Show Generated
+        if (!fShowGenerated)
+            return false;
     }
 
     // Find the block the tx is in
@@ -644,6 +644,7 @@
             // Debit
             //
             int64 nTxFee = nDebit - wtx.GetValueOut();
+            wtx.nLinesDisplayed = 0;
             for (int nOut = 0; nOut < wtx.vout.size(); nOut++)
             {
                 const CTxOut& txout = wtx.vout[nOut];
@@ -685,6 +686,7 @@
                            SingleLine(strDescription),
                            FormatMoney(-nValue, true),
                            "");
+                wtx.nLinesDisplayed++;
             }
         }
         else
@@ -706,12 +708,14 @@
                        "");
         }
     }
+
+    return true;
 }
 
 void CMainFrame::RefreshStatus()
 {
     static int nLastTop;
-    int nTop = m_listCtrl->GetTopItem();
+    int nTop = max((int)m_listCtrl->GetTopItem(), 0);
     if (nTop == nLastTop && pindexBestLast == pindexBest)
         return;
 
@@ -729,7 +733,7 @@
         nLastTop = nTop;
         pindexBestLast = pindexBest;
 
-        for (int nIndex = nStart; nIndex < nEnd; nIndex++)
+        for (int nIndex = nStart; nIndex < min(nEnd, m_listCtrl->GetItemCount()); nIndex++)
         {
             uint256 hash((string)GetItemText(m_listCtrl, nIndex, 1));
             map<uint256, CWalletTx>::iterator mi = mapWallet.find(hash);
@@ -738,9 +742,12 @@
                 printf("CMainFrame::RefreshStatus() : tx not found in mapWallet\n");
                 continue;
             }
-            const CWalletTx& wtx = (*mi).second;
+            CWalletTx& wtx = (*mi).second;
             if (wtx.IsCoinBase() || wtx.GetTxTime() != wtx.nTimeDisplayed)
-                InsertTransaction(wtx, false, nIndex);
+            {
+                if (!InsertTransaction(wtx, false, nIndex))
+                    m_listCtrl->DeleteItem(nIndex--);
+            }
             else
                 m_listCtrl->SetItem(nIndex, 2, FormatTxStatus(wtx));
         }
@@ -801,6 +808,9 @@
         }
 
         printf("RefreshListCtrl done\n");
+
+        // Update transaction total display
+        MainFrameRepaint();
     }
     else
     {
@@ -834,31 +844,54 @@
         return;
     fOneThread = true;
     Sleep(1000);
+    printf("DelayedRepaint()\n");
     MainFrameRepaint();
     fOneThread = false;
 }
 
 void CMainFrame::OnPaintListCtrl(wxPaintEvent& event)
 {
+    if (ptaskbaricon)
+        ptaskbaricon->UpdateTooltip();
+
     // Update listctrl contents
     if (!vWalletUpdated.empty())
     {
         TRY_CRITICAL_BLOCK(cs_mapWallet)
         {
+            bool fInserted = false;
             foreach(uint256 hash, vWalletUpdated)
             {
                 map<uint256, CWalletTx>::iterator mi = mapWallet.find(hash);
                 if (mi != mapWallet.end())
-                    InsertTransaction((*mi).second, false);
+                    fInserted |= InsertTransaction((*mi).second, false);
             }
-            m_listCtrl->ScrollList(0, INT_MAX);
             vWalletUpdated.clear();
+            if (fInserted)
+                m_listCtrl->ScrollList(0, INT_MAX);
         }
     }
 
     // Update status column of visible items only
     RefreshStatus();
 
+    // Balance total
+    bool fRefreshed = false;
+    static int nTransactionCount;
+    TRY_CRITICAL_BLOCK(cs_mapWallet)
+    {
+        fRefreshed = true;
+        m_staticTextBalance->SetLabel(FormatMoney(GetBalance()) + "  ");
+
+        // Count hidden and multi-line transactions
+        nTransactionCount = 0;
+        for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
+        {
+            CWalletTx& wtx = (*it).second;
+            nTransactionCount += wtx.nLinesDisplayed;
+        }
+    }
+
     // Update status bar
     string strGen = "";
     if (fGenerateBitcoins)
@@ -867,17 +900,9 @@
         strGen = "(not connected)";
     m_statusBar->SetStatusText(strGen, 1);
 
-    string strStatus = strprintf("     %d connections     %d blocks     %d transactions", vNodes.size(), nBestHeight + 1, m_listCtrl->GetItemCount());
+    string strStatus = strprintf("     %d connections     %d blocks     %d transactions", vNodes.size(), nBestHeight + 1, nTransactionCount);
     m_statusBar->SetStatusText(strStatus, 2);
 
-    // Balance total
-    bool fRefreshed = false;
-    TRY_CRITICAL_BLOCK(cs_mapWallet)
-    {
-        m_staticTextBalance->SetLabel(FormatMoney(GetBalance()) + "  ");
-        fRefreshed = true;
-    }
-
     // mapWallet was locked, try again later
     if (!vWalletUpdated.empty() || !fRefreshed)
         _beginthread(DelayedRepaint, 0, NULL);
@@ -1350,6 +1375,14 @@
     m_checkBoxMinimizeOnClose->Enable(fMinimizeToTray);
     m_checkBoxMinimizeOnClose->SetValue(fMinimizeToTray && fMinimizeOnClose);
     fTmpMinimizeOnClose = fMinimizeOnClose;
+    m_checkBoxUseProxy->SetValue(fUseProxy);
+    m_textCtrlProxyIP->Enable(fUseProxy);
+    m_textCtrlProxyPort->Enable(fUseProxy);
+    m_staticTextProxyIP->Enable(fUseProxy);
+    m_staticTextProxyPort->Enable(fUseProxy);
+    m_textCtrlProxyIP->SetValue(addrProxy.ToStringIP());
+    m_textCtrlProxyPort->SetValue(addrProxy.ToStringPort());
+
     m_buttonOK->SetFocus();
 }
 
@@ -1395,6 +1428,34 @@
 
 }
 
+void COptionsDialog::OnCheckBoxUseProxy(wxCommandEvent& event)
+{
+    m_textCtrlProxyIP->Enable(event.IsChecked());
+    m_textCtrlProxyPort->Enable(event.IsChecked());
+    m_staticTextProxyIP->Enable(event.IsChecked());
+    m_staticTextProxyPort->Enable(event.IsChecked());
+}
+
+CAddress COptionsDialog::GetProxyAddr()
+{
+    // Be careful about byte order, addr.ip and addr.port are big endian
+    CAddress addr(m_textCtrlProxyIP->GetValue() + ":" + m_textCtrlProxyPort->GetValue());
+    if (addr.ip == INADDR_NONE)
+        addr.ip = addrProxy.ip;
+    int nPort = atoi(m_textCtrlProxyPort->GetValue());
+    addr.port = htons(nPort);
+    if (nPort <= 0 || nPort > USHRT_MAX)
+        addr.port = addrProxy.port;
+    return addr;
+}
+
+void COptionsDialog::OnKillFocusProxy(wxFocusEvent& event)
+{
+    m_textCtrlProxyIP->SetValue(GetProxyAddr().ToStringIP());
+    m_textCtrlProxyPort->SetValue(GetProxyAddr().ToStringPort());
+}
+
+
 void COptionsDialog::OnButtonOK(wxCommandEvent& event)
 {
     OnButtonApply(event);
@@ -1446,6 +1507,18 @@
         fMinimizeOnClose = (fMinimizeToTray ? m_checkBoxMinimizeOnClose->GetValue() : fTmpMinimizeOnClose);
         walletdb.WriteSetting("fMinimizeOnClose", fMinimizeOnClose);
     }
+
+    if (fUseProxy != m_checkBoxUseProxy->GetValue())
+    {
+        fUseProxy = m_checkBoxUseProxy->GetValue();
+        walletdb.WriteSetting("fUseProxy", fUseProxy);
+    }
+
+    if (addrProxy != GetProxyAddr())
+    {
+        addrProxy = GetProxyAddr();
+        walletdb.WriteSetting("addrProxy", addrProxy);
+    }
 }
 
 
@@ -1657,7 +1730,7 @@
     nPrice = nPriceIn;
     wtx = wtxIn;
     start = wxDateTime::UNow();
-    strStatus = "";
+    memset(pszStatus, 0, sizeof(pszStatus));
     fCanCancel = true;
     fAbort = false;
     fSuccess = false;
@@ -1721,10 +1794,10 @@
 
 void CSendingDialog::OnPaint(wxPaintEvent& event)
 {
-    if (strStatus.size() > 130)
-        m_textCtrlStatus->SetValue(string("\n") + strStatus);
+    if (strlen(pszStatus) > 130)
+        m_textCtrlStatus->SetValue(string("\n") + pszStatus);
     else
-        m_textCtrlStatus->SetValue(string("\n\n") + strStatus);
+        m_textCtrlStatus->SetValue(string("\n\n") + pszStatus);
     m_staticTextSending->SetFocus();
     if (!fCanCancel)
         m_buttonCancel->Enable(false);
@@ -1736,7 +1809,7 @@
     }
     if (fAbort && fCanCancel && IsShown())
     {
-        strStatus = "CANCELLED";
+        strcpy(pszStatus, "CANCELLED");
         m_buttonOK->Enable(true);
         m_buttonOK->SetFocus();
         m_buttonCancel->Enable(false);
@@ -1777,7 +1850,8 @@
     }
     if (fAbort && fCanCancel)
     {
-        strStatus = "CANCELLED";
+        memset(pszStatus, 0, 10);
+        strcpy(pszStatus, "CANCELLED");
         Repaint();
         fWorkDone = true;
         return false;
@@ -1789,7 +1863,12 @@
 {
     if (!Status())
         return false;
-    strStatus = str;
+
+    // This can be read by the UI thread at any time,
+    // so copy in a way that can be read cleanly at all times.
+    memset(pszStatus, 0, min(str.size()+1, sizeof(pszStatus)));
+    strlcpy(pszStatus, str.c_str(), sizeof(pszStatus));
+
     Repaint();
     return true;
 }
@@ -1950,8 +2029,8 @@
         if (nRet > 0)
         {
             Error("The payment was sent, but the recipient was unable to verify it.\n"
-                  "The transaction is recorded and will credit to the recipient if it is valid,\n"
-                  "but without comment information.");
+                  "The transaction is recorded and will credit to the recipient,\n"
+                  "but the comment information will be blank.");
             return;
         }
     }
@@ -3092,6 +3171,7 @@
 
 void CMyTaskBarIcon::Show(bool fShow)
 {
+    static char pszPrevTip[200];
     if (fShow)
     {
         string strTooltip = "Bitcoin";
@@ -3099,10 +3179,17 @@
             strTooltip = "Bitcoin - Generating";
         if (fGenerateBitcoins && vNodes.empty())
             strTooltip = "Bitcoin - (not connected)";
-        SetIcon(wxICON(bitcoin), strTooltip);
+
+        // Optimization, only update when changed, using char array to be reentrant
+        if (strncmp(pszPrevTip, strTooltip.c_str(), sizeof(pszPrevTip)-1) != 0)
+        {
+            strlcpy(pszPrevTip, strTooltip.c_str(), sizeof(pszPrevTip));
+            SetIcon(wxICON(bitcoin), strTooltip);
+        }
     }
     else
     {
+        strlcpy(pszPrevTip, "", sizeof(pszPrevTip));
         RemoveIcon();
     }
 }
@@ -3301,12 +3388,12 @@
     if (mapArgs.count("/datadir"))
         strSetDataDir = mapArgs["/datadir"];
 
-    if (mapArgs.count("/proxy"))
-        addrProxy = CAddress(mapArgs["/proxy"].c_str());
-
     if (mapArgs.count("/debug"))
         fDebug = true;
 
+    if (mapArgs.count("/printtodebugger"))
+        fPrintToDebugger = true;
+
     if (mapArgs.count("/dropmessages"))
     {
         nDropMessagesTest = atoi(mapArgs["/dropmessages"]);
@@ -3380,6 +3467,20 @@
         return false;
     }
 
+    if (mapArgs.count("/proxy"))
+    {
+        fUseProxy = true;
+        addrProxy = CAddress(mapArgs["/proxy"].c_str());
+        if (addrProxy.ip == INADDR_NONE)
+        {
+            wxMessageBox("Invalid /proxy address", "Bitcoin");
+            OnExit();
+        }
+        CWalletDB walletdb;
+        walletdb.WriteSetting("fUseProxy", fUseProxy);
+        walletdb.WriteSetting("addrProxy", addrProxy);
+    }
+
     if (mapArgs.count("/gen"))
     {
         if (mapArgs["/gen"].empty())
@@ -3404,7 +3505,7 @@
         return false;
     }
 
-    //RandAddSeedPerfmon();
+    RandAddSeedPerfmon();
 
     if (!StartNode(strErrors))
         wxMessageBox(strErrors, "Bitcoin");
@@ -3514,7 +3615,7 @@
 
 void MainFrameRepaint()
 {
-    // This is called by network code that shouldn't access pframeMain and ptaskbaricon
+    // This is called by network code that shouldn't access pframeMain
     // directly because it could still be running after the UI is closed.
     if (pframeMain)
     {
@@ -3523,20 +3624,47 @@
         pframeMain->Refresh();
         pframeMain->AddPendingEvent(event);
     }
-    if (ptaskbaricon)
-        ptaskbaricon->UpdateTooltip();
 }
 
 
 
+typedef WINSHELLAPI BOOL WINAPI (*PSHGETSPECIALFOLDERPATHA)(HWND hwndOwner, LPSTR lpszPath, int nFolder, BOOL fCreate);
+
+string MyGetSpecialFolderPath(int nFolder, bool fCreate)
+{
+    char pszPath[MAX_PATH+100] = "";
+
+    // SHGetSpecialFolderPath is not usually available on NT 4.0
+    HMODULE hShell32 = LoadLibrary("shell32.dll");
+    if (hShell32)
+    {
+        PSHGETSPECIALFOLDERPATHA pSHGetSpecialFolderPath =
+            (PSHGETSPECIALFOLDERPATHA)GetProcAddress(hShell32, "SHGetSpecialFolderPathA");
+        if (pSHGetSpecialFolderPath)
+            (*pSHGetSpecialFolderPath)(NULL, pszPath, nFolder, fCreate);
+        FreeModule(hShell32);
+    }
+
+    // Backup option
+    if (pszPath[0] == '\0')
+    {
+        if (nFolder == CSIDL_STARTUP)
+        {
+            strcpy(pszPath, getenv("USERPROFILE"));
+            strcat(pszPath, "\\Start Menu\\Programs\\Startup");
+        }
+        else if (nFolder == CSIDL_APPDATA)
+        {
+            strcpy(pszPath, getenv("APPDATA"));
+        }
+    }
+
+    return pszPath;
+}
+
 string StartupShortcutPath()
 {
-    // Get the startup folder shortcut path
-    char pszLinkPath[MAX_PATH+100];
-    pszLinkPath[0] = '\0';
-    SHGetSpecialFolderPath(0, pszLinkPath, CSIDL_STARTUP, 0);
-    strcat(pszLinkPath, "\\Bitcoin.lnk");
-    return pszLinkPath;
+    return MyGetSpecialFolderPath(CSIDL_STARTUP, true) + "\\Bitcoin.lnk";
 }
 
 bool GetStartOnSystemStartup()
@@ -3630,7 +3758,8 @@
         if (GetBalance() < nValue)
         {
             wxMessageBox("Out of money  ");
-            return;
+            while (GetBalance() < 1000)
+                Sleep(1000);
         }
         nValue += (nRep % 100) * CENT;
 
--- a/ui.h
+++ b/ui.h
@@ -89,7 +89,7 @@
     void OnCrossThreadCall(wxCommandEvent& event);
     void InsertLine(bool fNew, int nIndex, uint256 hashKey, string strSort, const wxString& str1, const wxString& str2, const wxString& str3, const wxString& str4, const wxString& str5);
     bool DeleteLine(uint256 hashKey);
-    void InsertTransaction(const CWalletTx& wtx, bool fNew, int nIndex=-1);
+    bool InsertTransaction(const CWalletTx& wtx, bool fNew, int nIndex=-1);
     void RefreshListCtrl();
     void RefreshStatus();
 };
@@ -121,6 +121,9 @@
     void OnKillFocusTransactionFee(wxFocusEvent& event);
     void OnCheckBoxLimitProcessors(wxCommandEvent& event);
     void OnCheckBoxMinimizeToTray(wxCommandEvent& event);
+    void OnCheckBoxUseProxy(wxCommandEvent& event);
+    void OnKillFocusProxy(wxFocusEvent& event);
+
     void OnButtonOK(wxCommandEvent& event);
     void OnButtonCancel(wxCommandEvent& event);
     void OnButtonApply(wxCommandEvent& event);
@@ -133,6 +136,7 @@
     bool fTmpStartOnSystemStartup;
     bool fTmpMinimizeOnClose;
     void SelectPage(int nPage);
+    CAddress GetProxyAddr();
 };
 
 
@@ -193,7 +197,7 @@
     int64 nPrice;
     CWalletTx wtx;
     wxDateTime start;
-    string strStatus;
+    char pszStatus[10000];
     bool fCanCancel;
     bool fAbort;
     bool fSuccess;
--- a/uibase.cpp
+++ b/uibase.cpp
@@ -380,7 +380,7 @@
 	bSizer69 = new wxBoxSizer( wxVERTICAL );
 	
 	
-	bSizer69->Add( 0, 14, 0, wxEXPAND, 5 );
+	bSizer69->Add( 0, 16, 0, wxEXPAND, 5 );
 	
 	m_staticText32 = new wxStaticText( m_panelMain, wxID_ANY, wxT("Optional transaction fee you give to the nodes that process your transactions."), wxDefaultPosition, wxDefaultSize, 0 );
 	m_staticText32->Wrap( -1 );
@@ -412,7 +412,7 @@
 	bSizer71->Add( m_checkBoxLimitProcessors, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
 	
 	m_spinCtrlLimitProcessors = new wxSpinCtrl( m_panelMain, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize( 48,-1 ), wxSP_ARROW_KEYS, 1, 999, 1 );
-	bSizer71->Add( m_spinCtrlLimitProcessors, 0, wxTOP|wxBOTTOM, 5 );
+	bSizer71->Add( m_spinCtrlLimitProcessors, 0, wxALIGN_CENTER_VERTICAL, 5 );
 	
 	m_staticText35 = new wxStaticText( m_panelMain, wxID_ANY, wxT("processors"), wxDefaultPosition, wxDefaultSize, 0 );
 	m_staticText35->Wrap( -1 );
@@ -434,12 +434,45 @@
 	
 	bSizer101->Add( 16, 0, 0, 0, 5 );
 	
-	m_checkBoxMinimizeOnClose = new wxCheckBox( m_panelMain, wxID_ANY, wxT("M&inimize to system tray on close"), wxDefaultPosition, wxDefaultSize, 0 );
+	m_checkBoxMinimizeOnClose = new wxCheckBox( m_panelMain, wxID_ANY, wxT("Mi&nimize to system tray on close"), wxDefaultPosition, wxDefaultSize, 0 );
 	
-	bSizer101->Add( m_checkBoxMinimizeOnClose, 0, wxALL, 5 );
+	bSizer101->Add( m_checkBoxMinimizeOnClose, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
 	
 	bSizer69->Add( bSizer101, 1, wxEXPAND, 5 );
 	
+	wxBoxSizer* bSizer102;
+	bSizer102 = new wxBoxSizer( wxHORIZONTAL );
+	
+	m_checkBoxUseProxy = new wxCheckBox( m_panelMain, wxID_ANY, wxT("&Connect through socks4 proxy: "), wxDefaultPosition, wxDefaultSize, 0 );
+	
+	bSizer102->Add( m_checkBoxUseProxy, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
+	
+	bSizer69->Add( bSizer102, 1, wxEXPAND, 5 );
+	
+	wxBoxSizer* bSizer103;
+	bSizer103 = new wxBoxSizer( wxHORIZONTAL );
+	
+	
+	bSizer103->Add( 18, 0, 0, 0, 5 );
+	
+	m_staticTextProxyIP = new wxStaticText( m_panelMain, wxID_ANY, wxT("Proxy &IP:"), wxDefaultPosition, wxDefaultSize, 0 );
+	m_staticTextProxyIP->Wrap( -1 );
+	bSizer103->Add( m_staticTextProxyIP, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
+	
+	m_textCtrlProxyIP = new wxTextCtrl( m_panelMain, wxID_PROXYIP, wxEmptyString, wxDefaultPosition, wxSize( 140,-1 ), 0 );
+	m_textCtrlProxyIP->SetMaxLength( 15 ); 
+	bSizer103->Add( m_textCtrlProxyIP, 0, wxALIGN_CENTER_VERTICAL, 5 );
+	
+	m_staticTextProxyPort = new wxStaticText( m_panelMain, wxID_ANY, wxT(" &Port:"), wxDefaultPosition, wxDefaultSize, 0 );
+	m_staticTextProxyPort->Wrap( -1 );
+	bSizer103->Add( m_staticTextProxyPort, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
+	
+	m_textCtrlProxyPort = new wxTextCtrl( m_panelMain, wxID_PROXYPORT, wxEmptyString, wxDefaultPosition, wxSize( 55,-1 ), 0 );
+	m_textCtrlProxyPort->SetMaxLength( 5 ); 
+	bSizer103->Add( m_textCtrlProxyPort, 0, wxALIGN_CENTER_VERTICAL, 5 );
+	
+	bSizer69->Add( bSizer103, 1, wxEXPAND, 5 );
+	
 	m_panelMain->SetSizer( bSizer69 );
 	m_panelMain->Layout();
 	bSizer69->Fit( m_panelMain );
@@ -450,13 +483,13 @@
 	bSizer64 = new wxBoxSizer( wxVERTICAL );
 	
 	
-	bSizer64->Add( 0, 14, 0, wxEXPAND, 5 );
+	bSizer64->Add( 0, 16, 0, wxEXPAND, 5 );
 	
 	m_staticText321 = new wxStaticText( m_panelTest2, wxID_ANY, wxT("Test panel 2 for future expansion"), wxDefaultPosition, wxDefaultSize, 0 );
 	m_staticText321->Wrap( -1 );
 	bSizer64->Add( m_staticText321, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
 	
-	m_staticText69 = new wxStaticText( m_panelTest2, wxID_ANY, wxT("MyLabel"), wxDefaultPosition, wxDefaultSize, 0 );
+	m_staticText69 = new wxStaticText( m_panelTest2, wxID_ANY, wxT("Let's not start multiple pages until the first page is filled up"), wxDefaultPosition, wxDefaultSize, 0 );
 	m_staticText69->Wrap( -1 );
 	bSizer64->Add( m_staticText69, 0, wxALL, 5 );
 	
@@ -506,6 +539,9 @@
 	m_textCtrlTransactionFee->Connect( wxEVT_KILL_FOCUS, wxFocusEventHandler( COptionsDialogBase::OnKillFocusTransactionFee ), NULL, this );
 	m_checkBoxLimitProcessors->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( COptionsDialogBase::OnCheckBoxLimitProcessors ), NULL, this );
 	m_checkBoxMinimizeToTray->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( COptionsDialogBase::OnCheckBoxMinimizeToTray ), NULL, this );
+	m_checkBoxUseProxy->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( COptionsDialogBase::OnCheckBoxUseProxy ), NULL, this );
+	m_textCtrlProxyIP->Connect( wxEVT_KILL_FOCUS, wxFocusEventHandler( COptionsDialogBase::OnKillFocusProxy ), NULL, this );
+	m_textCtrlProxyPort->Connect( wxEVT_KILL_FOCUS, wxFocusEventHandler( COptionsDialogBase::OnKillFocusProxy ), NULL, this );
 	m_buttonOK->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( COptionsDialogBase::OnButtonOK ), NULL, this );
 	m_buttonCancel->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( COptionsDialogBase::OnButtonCancel ), NULL, this );
 	m_buttonApply->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( COptionsDialogBase::OnButtonApply ), NULL, this );
@@ -518,6 +554,9 @@
 	m_textCtrlTransactionFee->Disconnect( wxEVT_KILL_FOCUS, wxFocusEventHandler( COptionsDialogBase::OnKillFocusTransactionFee ), NULL, this );
 	m_checkBoxLimitProcessors->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( COptionsDialogBase::OnCheckBoxLimitProcessors ), NULL, this );
 	m_checkBoxMinimizeToTray->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( COptionsDialogBase::OnCheckBoxMinimizeToTray ), NULL, this );
+	m_checkBoxUseProxy->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( COptionsDialogBase::OnCheckBoxUseProxy ), NULL, this );
+	m_textCtrlProxyIP->Disconnect( wxEVT_KILL_FOCUS, wxFocusEventHandler( COptionsDialogBase::OnKillFocusProxy ), NULL, this );
+	m_textCtrlProxyPort->Disconnect( wxEVT_KILL_FOCUS, wxFocusEventHandler( COptionsDialogBase::OnKillFocusProxy ), NULL, this );
 	m_buttonOK->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( COptionsDialogBase::OnButtonOK ), NULL, this );
 	m_buttonCancel->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( COptionsDialogBase::OnButtonCancel ), NULL, this );
 	m_buttonApply->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( COptionsDialogBase::OnButtonApply ), NULL, this );
--- a/uibase.h
+++ b/uibase.h
@@ -50,50 +50,52 @@
 #define wxID_BUTTONCOPY 1006
 #define wxID_BUTTONCHANGE 1007
 #define wxID_TRANSACTIONFEE 1008
-#define wxID_TEXTCTRLPAYTO 1009
-#define wxID_BUTTONPASTE 1010
-#define wxID_BUTTONADDRESSBOOK 1011
-#define wxID_TEXTCTRLAMOUNT 1012
-#define wxID_CHOICETRANSFERTYPE 1013
-#define wxID_LISTCTRL 1014
-#define wxID_BUTTONRENAME 1015
-#define wxID_BUTTONNEW 1016
-#define wxID_BUTTONEDIT 1017
-#define wxID_BUTTONDELETE 1018
-#define wxID_DEL0 1019
-#define wxID_DEL1 1020
-#define wxID_DEL2 1021
-#define wxID_DEL3 1022
-#define wxID_DEL4 1023
-#define wxID_DEL5 1024
-#define wxID_DEL6 1025
-#define wxID_DEL7 1026
-#define wxID_DEL8 1027
-#define wxID_DEL9 1028
-#define wxID_DEL10 1029
-#define wxID_DEL11 1030
-#define wxID_DEL12 1031
-#define wxID_DEL13 1032
-#define wxID_DEL14 1033
-#define wxID_DEL15 1034
-#define wxID_DEL16 1035
-#define wxID_DEL17 1036
-#define wxID_DEL18 1037
-#define wxID_DEL19 1038
-#define wxID_BUTTONPREVIEW 1039
-#define wxID_BUTTONSAMPLE 1040
-#define wxID_CANCEL2 1041
-#define wxID_BUTTONBACK 1042
-#define wxID_BUTTONNEXT 1043
-#define wxID_SUBMIT 1044
-#define wxID_OPENNEWTABLE 1045
-#define wxID_DEALHAND 1046
-#define wxID_FOLD 1047
-#define wxID_CALL 1048
-#define wxID_RAISE 1049
-#define wxID_LEAVETABLE 1050
-#define wxID_DITCHPLAYER 1051
-#define wxID_TEXTCTRL 1052
+#define wxID_PROXYIP 1009
+#define wxID_PROXYPORT 1010
+#define wxID_TEXTCTRLPAYTO 1011
+#define wxID_BUTTONPASTE 1012
+#define wxID_BUTTONADDRESSBOOK 1013
+#define wxID_TEXTCTRLAMOUNT 1014
+#define wxID_CHOICETRANSFERTYPE 1015
+#define wxID_LISTCTRL 1016
+#define wxID_BUTTONRENAME 1017
+#define wxID_BUTTONNEW 1018
+#define wxID_BUTTONEDIT 1019
+#define wxID_BUTTONDELETE 1020
+#define wxID_DEL0 1021
+#define wxID_DEL1 1022
+#define wxID_DEL2 1023
+#define wxID_DEL3 1024
+#define wxID_DEL4 1025
+#define wxID_DEL5 1026
+#define wxID_DEL6 1027
+#define wxID_DEL7 1028
+#define wxID_DEL8 1029
+#define wxID_DEL9 1030
+#define wxID_DEL10 1031
+#define wxID_DEL11 1032
+#define wxID_DEL12 1033
+#define wxID_DEL13 1034
+#define wxID_DEL14 1035
+#define wxID_DEL15 1036
+#define wxID_DEL16 1037
+#define wxID_DEL17 1038
+#define wxID_DEL18 1039
+#define wxID_DEL19 1040
+#define wxID_BUTTONPREVIEW 1041
+#define wxID_BUTTONSAMPLE 1042
+#define wxID_CANCEL2 1043
+#define wxID_BUTTONBACK 1044
+#define wxID_BUTTONNEXT 1045
+#define wxID_SUBMIT 1046
+#define wxID_OPENNEWTABLE 1047
+#define wxID_DEALHAND 1048
+#define wxID_FOLD 1049
+#define wxID_CALL 1050
+#define wxID_RAISE 1051
+#define wxID_LEAVETABLE 1052
+#define wxID_DITCHPLAYER 1053
+#define wxID_TEXTCTRL 1054
 
 ///////////////////////////////////////////////////////////////////////////////
 /// Class CMainFrameBase
@@ -211,6 +213,12 @@
 		wxCheckBox* m_checkBoxMinimizeToTray;
 		
 		wxCheckBox* m_checkBoxMinimizeOnClose;
+		wxCheckBox* m_checkBoxUseProxy;
+		
+		wxStaticText* m_staticTextProxyIP;
+		wxTextCtrl* m_textCtrlProxyIP;
+		wxStaticText* m_staticTextProxyPort;
+		wxTextCtrl* m_textCtrlProxyPort;
 		wxPanel* m_panelTest2;
 		
 		wxStaticText* m_staticText321;
@@ -226,6 +234,8 @@
 		virtual void OnKillFocusTransactionFee( wxFocusEvent& event ){ event.Skip(); }
 		virtual void OnCheckBoxLimitProcessors( wxCommandEvent& event ){ event.Skip(); }
 		virtual void OnCheckBoxMinimizeToTray( wxCommandEvent& event ){ event.Skip(); }
+		virtual void OnCheckBoxUseProxy( wxCommandEvent& event ){ event.Skip(); }
+		virtual void OnKillFocusProxy( wxFocusEvent& event ){ event.Skip(); }
 		virtual void OnButtonOK( wxCommandEvent& event ){ event.Skip(); }
 		virtual void OnButtonCancel( wxCommandEvent& event ){ event.Skip(); }
 		virtual void OnButtonApply( wxCommandEvent& event ){ event.Skip(); }
--- a/uiproject.fbp
+++ b/uiproject.fbp
@@ -1912,7 +1912,7 @@
                                                     <property name="flag">wxEXPAND</property>
                                                     <property name="proportion">0</property>
                                                     <object class="spacer" expanded="1">
-                                                        <property name="height">14</property>
+                                                        <property name="height">16</property>
                                                         <property name="permission">protected</property>
                                                         <property name="width">0</property>
                                                     </object>
@@ -2148,7 +2148,7 @@
                                                         </object>
                                                         <object class="sizeritem" expanded="1">
                                                             <property name="border">5</property>
-                                                            <property name="flag">wxTOP|wxBOTTOM</property>
+                                                            <property name="flag">wxALIGN_CENTER_VERTICAL</property>
                                                             <property name="proportion">0</property>
                                                             <object class="wxSpinCtrl" expanded="1">
                                                                 <property name="bg"></property>
@@ -2379,7 +2379,7 @@
                                                         </object>
                                                         <object class="sizeritem" expanded="1">
                                                             <property name="border">5</property>
-                                                            <property name="flag">wxALL</property>
+                                                            <property name="flag">wxALL|wxALIGN_CENTER_VERTICAL</property>
                                                             <property name="proportion">0</property>
                                                             <object class="wxCheckBox" expanded="1">
                                                                 <property name="bg"></property>
@@ -2390,7 +2390,7 @@
                                                                 <property name="font"></property>
                                                                 <property name="hidden">0</property>
                                                                 <property name="id">wxID_ANY</property>
-                                                                <property name="label">M&amp;inimize to system tray on close</property>
+                                                                <property name="label">Mi&amp;nimize to system tray on close</property>
                                                                 <property name="maximum_size"></property>
                                                                 <property name="minimum_size"></property>
                                                                 <property name="name">m_checkBoxMinimizeOnClose</property>
@@ -2431,6 +2431,302 @@
                                                         </object>
                                                     </object>
                                                 </object>
+                                                <object class="sizeritem" expanded="1">
+                                                    <property name="border">5</property>
+                                                    <property name="flag">wxEXPAND</property>
+                                                    <property name="proportion">1</property>
+                                                    <object class="wxBoxSizer" expanded="1">
+                                                        <property name="minimum_size"></property>
+                                                        <property name="name">bSizer102</property>
+                                                        <property name="orient">wxHORIZONTAL</property>
+                                                        <property name="permission">none</property>
+                                                        <object class="sizeritem" expanded="1">
+                                                            <property name="border">5</property>
+                                                            <property name="flag">wxALL|wxALIGN_CENTER_VERTICAL</property>
+                                                            <property name="proportion">0</property>
+                                                            <object class="wxCheckBox" expanded="1">
+                                                                <property name="bg"></property>
+                                                                <property name="checked">0</property>
+                                                                <property name="context_help"></property>
+                                                                <property name="enabled">1</property>
+                                                                <property name="fg"></property>
+                                                                <property name="font"></property>
+                                                                <property name="hidden">0</property>
+                                                                <property name="id">wxID_ANY</property>
+                                                                <property name="label">&amp;Connect through socks4 proxy: </property>
+                                                                <property name="maximum_size"></property>
+                                                                <property name="minimum_size"></property>
+                                                                <property name="name">m_checkBoxUseProxy</property>
+                                                                <property name="permission">protected</property>
+                                                                <property name="pos"></property>
+                                                                <property name="size"></property>
+                                                                <property name="style"></property>
+                                                                <property name="subclass"></property>
+                                                                <property name="tooltip"></property>
+                                                                <property name="window_extra_style"></property>
+                                                                <property name="window_name"></property>
+                                                                <property name="window_style"></property>
+                                                                <event name="OnChar"></event>
+                                                                <event name="OnCheckBox">OnCheckBoxUseProxy</event>
+                                                                <event name="OnEnterWindow"></event>
+                                                                <event name="OnEraseBackground"></event>
+                                                                <event name="OnKeyDown"></event>
+                                                                <event name="OnKeyUp"></event>
+                                                                <event name="OnKillFocus"></event>
+                                                                <event name="OnLeaveWindow"></event>
+                                                                <event name="OnLeftDClick"></event>
+                                                                <event name="OnLeftDown"></event>
+                                                                <event name="OnLeftUp"></event>
+                                                                <event name="OnMiddleDClick"></event>
+                                                                <event name="OnMiddleDown"></event>
+                                                                <event name="OnMiddleUp"></event>
+                                                                <event name="OnMotion"></event>
+                                                                <event name="OnMouseEvents"></event>
+                                                                <event name="OnMouseWheel"></event>
+                                                                <event name="OnPaint"></event>
+                                                                <event name="OnRightDClick"></event>
+                                                                <event name="OnRightDown"></event>
+                                                                <event name="OnRightUp"></event>
+                                                                <event name="OnSetFocus"></event>
+                                                                <event name="OnSize"></event>
+                                                                <event name="OnUpdateUI"></event>
+                                                            </object>
+                                                        </object>
+                                                    </object>
+                                                </object>
+                                                <object class="sizeritem" expanded="1">
+                                                    <property name="border">5</property>
+                                                    <property name="flag">wxEXPAND</property>
+                                                    <property name="proportion">1</property>
+                                                    <object class="wxBoxSizer" expanded="1">
+                                                        <property name="minimum_size"></property>
+                                                        <property name="name">bSizer103</property>
+                                                        <property name="orient">wxHORIZONTAL</property>
+                                                        <property name="permission">none</property>
+                                                        <object class="sizeritem" expanded="1">
+                                                            <property name="border">5</property>
+                                                            <property name="flag"></property>
+                                                            <property name="proportion">0</property>
+                                                            <object class="spacer" expanded="1">
+                                                                <property name="height">0</property>
+                                                                <property name="permission">protected</property>
+                                                                <property name="width">18</property>
+                                                            </object>
+                                                        </object>
+                                                        <object class="sizeritem" expanded="1">
+                                                            <property name="border">5</property>
+                                                            <property name="flag">wxALL|wxALIGN_CENTER_VERTICAL</property>
+                                                            <property name="proportion">0</property>
+                                                            <object class="wxStaticText" expanded="1">
+                                                                <property name="bg"></property>
+                                                                <property name="context_help"></property>
+                                                                <property name="enabled">1</property>
+                                                                <property name="fg"></property>
+                                                                <property name="font"></property>
+                                                                <property name="hidden">0</property>
+                                                                <property name="id">wxID_ANY</property>
+                                                                <property name="label">Proxy &amp;IP:</property>
+                                                                <property name="maximum_size"></property>
+                                                                <property name="minimum_size"></property>
+                                                                <property name="name">m_staticTextProxyIP</property>
+                                                                <property name="permission">protected</property>
+                                                                <property name="pos"></property>
+                                                                <property name="size"></property>
+                                                                <property name="style"></property>
+                                                                <property name="subclass"></property>
+                                                                <property name="tooltip"></property>
+                                                                <property name="window_extra_style"></property>
+                                                                <property name="window_name"></property>
+                                                                <property name="window_style"></property>
+                                                                <property name="wrap">-1</property>
+                                                                <event name="OnChar"></event>
+                                                                <event name="OnEnterWindow"></event>
+                                                                <event name="OnEraseBackground"></event>
+                                                                <event name="OnKeyDown"></event>
+                                                                <event name="OnKeyUp"></event>
+                                                                <event name="OnKillFocus"></event>
+                                                                <event name="OnLeaveWindow"></event>
+                                                                <event name="OnLeftDClick"></event>
+                                                                <event name="OnLeftDown"></event>
+                                                                <event name="OnLeftUp"></event>
+                                                                <event name="OnMiddleDClick"></event>
+                                                                <event name="OnMiddleDown"></event>
+                                                                <event name="OnMiddleUp"></event>
+                                                                <event name="OnMotion"></event>
+                                                                <event name="OnMouseEvents"></event>
+                                                                <event name="OnMouseWheel"></event>
+                                                                <event name="OnPaint"></event>
+                                                                <event name="OnRightDClick"></event>
+                                                                <event name="OnRightDown"></event>
+                                                                <event name="OnRightUp"></event>
+                                                                <event name="OnSetFocus"></event>
+                                                                <event name="OnSize"></event>
+                                                                <event name="OnUpdateUI"></event>
+                                                            </object>
+                                                        </object>
+                                                        <object class="sizeritem" expanded="1">
+                                                            <property name="border">5</property>
+                                                            <property name="flag">wxALIGN_CENTER_VERTICAL</property>
+                                                            <property name="proportion">0</property>
+                                                            <object class="wxTextCtrl" expanded="1">
+                                                                <property name="bg"></property>
+                                                                <property name="context_help"></property>
+                                                                <property name="enabled">1</property>
+                                                                <property name="fg"></property>
+                                                                <property name="font"></property>
+                                                                <property name="hidden">0</property>
+                                                                <property name="id">wxID_PROXYIP</property>
+                                                                <property name="maximum_size"></property>
+                                                                <property name="maxlength">15</property>
+                                                                <property name="minimum_size"></property>
+                                                                <property name="name">m_textCtrlProxyIP</property>
+                                                                <property name="permission">protected</property>
+                                                                <property name="pos"></property>
+                                                                <property name="size">140,-1</property>
+                                                                <property name="style"></property>
+                                                                <property name="subclass"></property>
+                                                                <property name="tooltip"></property>
+                                                                <property name="value"></property>
+                                                                <property name="window_extra_style"></property>
+                                                                <property name="window_name"></property>
+                                                                <property name="window_style"></property>
+                                                                <event name="OnChar"></event>
+                                                                <event name="OnEnterWindow"></event>
+                                                                <event name="OnEraseBackground"></event>
+                                                                <event name="OnKeyDown"></event>
+                                                                <event name="OnKeyUp"></event>
+                                                                <event name="OnKillFocus">OnKillFocusProxy</event>
+                                                                <event name="OnLeaveWindow"></event>
+                                                                <event name="OnLeftDClick"></event>
+                                                                <event name="OnLeftDown"></event>
+                                                                <event name="OnLeftUp"></event>
+                                                                <event name="OnMiddleDClick"></event>
+                                                                <event name="OnMiddleDown"></event>
+                                                                <event name="OnMiddleUp"></event>
+                                                                <event name="OnMotion"></event>
+                                                                <event name="OnMouseEvents"></event>
+                                                                <event name="OnMouseWheel"></event>
+                                                                <event name="OnPaint"></event>
+                                                                <event name="OnRightDClick"></event>
+                                                                <event name="OnRightDown"></event>
+                                                                <event name="OnRightUp"></event>
+                                                                <event name="OnSetFocus"></event>
+                                                                <event name="OnSize"></event>
+                                                                <event name="OnText"></event>
+                                                                <event name="OnTextEnter"></event>
+                                                                <event name="OnTextMaxLen"></event>
+                                                                <event name="OnTextURL"></event>
+                                                                <event name="OnUpdateUI"></event>
+                                                            </object>
+                                                        </object>
+                                                        <object class="sizeritem" expanded="1">
+                                                            <property name="border">5</property>
+                                                            <property name="flag">wxALL|wxALIGN_CENTER_VERTICAL</property>
+                                                            <property name="proportion">0</property>
+                                                            <object class="wxStaticText" expanded="1">
+                                                                <property name="bg"></property>
+                                                                <property name="context_help"></property>
+                                                                <property name="enabled">1</property>
+                                                                <property name="fg"></property>
+                                                                <property name="font"></property>
+                                                                <property name="hidden">0</property>
+                                                                <property name="id">wxID_ANY</property>
+                                                                <property name="label"> &amp;Port:</property>
+                                                                <property name="maximum_size"></property>
+                                                                <property name="minimum_size"></property>
+                                                                <property name="name">m_staticTextProxyPort</property>
+                                                                <property name="permission">protected</property>
+                                                                <property name="pos"></property>
+                                                                <property name="size"></property>
+                                                                <property name="style"></property>
+                                                                <property name="subclass"></property>
+                                                                <property name="tooltip"></property>
+                                                                <property name="window_extra_style"></property>
+                                                                <property name="window_name"></property>
+                                                                <property name="window_style"></property>
+                                                                <property name="wrap">-1</property>
+                                                                <event name="OnChar"></event>
+                                                                <event name="OnEnterWindow"></event>
+                                                                <event name="OnEraseBackground"></event>
+                                                                <event name="OnKeyDown"></event>
+                                                                <event name="OnKeyUp"></event>
+                                                                <event name="OnKillFocus"></event>
+                                                                <event name="OnLeaveWindow"></event>
+                                                                <event name="OnLeftDClick"></event>
+                                                                <event name="OnLeftDown"></event>
+                                                                <event name="OnLeftUp"></event>
+                                                                <event name="OnMiddleDClick"></event>
+                                                                <event name="OnMiddleDown"></event>
+                                                                <event name="OnMiddleUp"></event>
+                                                                <event name="OnMotion"></event>
+                                                                <event name="OnMouseEvents"></event>
+                                                                <event name="OnMouseWheel"></event>
+                                                                <event name="OnPaint"></event>
+                                                                <event name="OnRightDClick"></event>
+                                                                <event name="OnRightDown"></event>
+                                                                <event name="OnRightUp"></event>
+                                                                <event name="OnSetFocus"></event>
+                                                                <event name="OnSize"></event>
+                                                                <event name="OnUpdateUI"></event>
+                                                            </object>
+                                                        </object>
+                                                        <object class="sizeritem" expanded="1">
+                                                            <property name="border">5</property>
+                                                            <property name="flag">wxALIGN_CENTER_VERTICAL</property>
+                                                            <property name="proportion">0</property>
+                                                            <object class="wxTextCtrl" expanded="1">
+                                                                <property name="bg"></property>
+                                                                <property name="context_help"></property>
+                                                                <property name="enabled">1</property>
+                                                                <property name="fg"></property>
+                                                                <property name="font"></property>
+                                                                <property name="hidden">0</property>
+                                                                <property name="id">wxID_PROXYPORT</property>
+                                                                <property name="maximum_size"></property>
+                                                                <property name="maxlength">5</property>
+                                                                <property name="minimum_size"></property>
+                                                                <property name="name">m_textCtrlProxyPort</property>
+                                                                <property name="permission">protected</property>
+                                                                <property name="pos"></property>
+                                                                <property name="size">55,-1</property>
+                                                                <property name="style"></property>
+                                                                <property name="subclass"></property>
+                                                                <property name="tooltip"></property>
+                                                                <property name="value"></property>
+                                                                <property name="window_extra_style"></property>
+                                                                <property name="window_name"></property>
+                                                                <property name="window_style"></property>
+                                                                <event name="OnChar"></event>
+                                                                <event name="OnEnterWindow"></event>
+                                                                <event name="OnEraseBackground"></event>
+                                                                <event name="OnKeyDown"></event>
+                                                                <event name="OnKeyUp"></event>
+                                                                <event name="OnKillFocus">OnKillFocusProxy</event>
+                                                                <event name="OnLeaveWindow"></event>
+                                                                <event name="OnLeftDClick"></event>
+                                                                <event name="OnLeftDown"></event>
+                                                                <event name="OnLeftUp"></event>
+                                                                <event name="OnMiddleDClick"></event>
+                                                                <event name="OnMiddleDown"></event>
+                                                                <event name="OnMiddleUp"></event>
+                                                                <event name="OnMotion"></event>
+                                                                <event name="OnMouseEvents"></event>
+                                                                <event name="OnMouseWheel"></event>
+                                                                <event name="OnPaint"></event>
+                                                                <event name="OnRightDClick"></event>
+                                                                <event name="OnRightDown"></event>
+                                                                <event name="OnRightUp"></event>
+                                                                <event name="OnSetFocus"></event>
+                                                                <event name="OnSize"></event>
+                                                                <event name="OnText"></event>
+                                                                <event name="OnTextEnter"></event>
+                                                                <event name="OnTextMaxLen"></event>
+                                                                <event name="OnTextURL"></event>
+                                                                <event name="OnUpdateUI"></event>
+                                                            </object>
+                                                        </object>
+                                                    </object>
+                                                </object>
                                             </object>
                                         </object>
                                     </object>
@@ -2490,7 +2786,7 @@
                                                     <property name="flag">wxEXPAND</property>
                                                     <property name="proportion">0</property>
                                                     <object class="spacer" expanded="1">
-                                                        <property name="height">14</property>
+                                                        <property name="height">16</property>
                                                         <property name="permission">protected</property>
                                                         <property name="width">0</property>
                                                     </object>
@@ -2558,7 +2854,7 @@
                                                         <property name="font"></property>
                                                         <property name="hidden">0</property>
                                                         <property name="id">wxID_ANY</property>
-                                                        <property name="label">MyLabel</property>
+                                                        <property name="label">Let&apos;s not start multiple pages until the first page is filled up</property>
                                                         <property name="maximum_size"></property>
                                                         <property name="minimum_size"></property>
                                                         <property name="name">m_staticText69</property>
--- a/util.cpp
+++ b/util.cpp
@@ -5,8 +5,9 @@
 #include "headers.h"
 
 
-
 bool fDebug = false;
+bool fPrintToDebugger = false;
+bool fPrintToConsole = false;
 
 
 
@@ -37,8 +38,8 @@
         // Seed random number generator with screen scrape and other hardware sources
         RAND_screen();
 
-        // Seed random number generator with perfmon data
-        RandAddSeed(true);
+        // Seed random number generator with performance counter
+        RandAddSeed();
     }
     ~CInit()
     {
@@ -54,40 +55,43 @@
 
 
 
-void RandAddSeed(bool fPerfmon)
+void RandAddSeed()
 {
     // Seed with CPU performance counter
     LARGE_INTEGER PerformanceCount;
     QueryPerformanceCounter(&PerformanceCount);
     RAND_add(&PerformanceCount, sizeof(PerformanceCount), 1.5);
     memset(&PerformanceCount, 0, sizeof(PerformanceCount));
+}
 
+void RandAddSeedPerfmon()
+{
+    // This can take up to 2 seconds, so only do it every 10 minutes
     static int64 nLastPerfmon;
-    if (fPerfmon || GetTime() > nLastPerfmon + 5 * 60)
-    {
-        nLastPerfmon = GetTime();
+    if (GetTime() < nLastPerfmon + 10 * 60)
+        return;
+    nLastPerfmon = GetTime();
 
-        // Seed with the entire set of perfmon data
-        unsigned char pdata[250000];
-        memset(pdata, 0, sizeof(pdata));
-        unsigned long nSize = sizeof(pdata);
-        long ret = RegQueryValueEx(HKEY_PERFORMANCE_DATA, "Global", NULL, NULL, pdata, &nSize);
-        RegCloseKey(HKEY_PERFORMANCE_DATA);
-        if (ret == ERROR_SUCCESS)
-        {
-            uint256 hash;
-            SHA256(pdata, nSize, (unsigned char*)&hash);
-            RAND_add(&hash, sizeof(hash), min(nSize/500.0, (double)sizeof(hash)));
-            hash = 0;
-            memset(pdata, 0, nSize);
+    // Seed with the entire set of perfmon data
+    unsigned char pdata[250000];
+    memset(pdata, 0, sizeof(pdata));
+    unsigned long nSize = sizeof(pdata);
+    long ret = RegQueryValueEx(HKEY_PERFORMANCE_DATA, "Global", NULL, NULL, pdata, &nSize);
+    RegCloseKey(HKEY_PERFORMANCE_DATA);
+    if (ret == ERROR_SUCCESS)
+    {
+        uint256 hash;
+        SHA256(pdata, nSize, (unsigned char*)&hash);
+        RAND_add(&hash, sizeof(hash), min(nSize/500.0, (double)sizeof(hash)));
+        hash = 0;
+        memset(pdata, 0, nSize);
 
-            time_t nTime;
-            time(&nTime);
-            struct tm* ptmTime = gmtime(&nTime);
-            char pszTime[200];
-            strftime(pszTime, sizeof(pszTime), "%x %H:%M:%S", ptmTime);
-            printf("%s RandAddSeed() %d bytes\n", pszTime, nSize);
-        }
+        time_t nTime;
+        time(&nTime);
+        struct tm* ptmTime = gmtime(&nTime);
+        char pszTime[200];
+        strftime(pszTime, sizeof(pszTime), "%x %H:%M:%S", ptmTime);
+        printf("%s RandAddSeed() %d bytes\n", pszTime, nSize);
     }
 }
 
@@ -99,7 +103,6 @@
 
 
 
-
 // Safer snprintf
 //  - prints up to limit-1 characters
 //  - output string is always null terminated even if limit reached
@@ -172,27 +175,6 @@
 }
 
 
-void PrintException(std::exception* pex, const char* pszThread)
-{
-    char pszModule[MAX_PATH];
-    pszModule[0] = '\0';
-    GetModuleFileName(NULL, pszModule, sizeof(pszModule));
-    _strlwr(pszModule);
-    char pszMessage[1000];
-    if (pex)
-        snprintf(pszMessage, sizeof(pszMessage),
-            "EXCEPTION: %s       \n%s       \n%s in %s       \n", typeid(*pex).name(), pex->what(), pszModule, pszThread);
-    else
-        snprintf(pszMessage, sizeof(pszMessage),
-            "UNKNOWN EXCEPTION       \n%s in %s       \n", pszModule, pszThread);
-    printf("\n\n************************\n%s", pszMessage);
-    if (wxTheApp)
-        wxMessageBox(pszMessage, "Error", wxOK | wxICON_ERROR);
-    throw;
-    //DebugBreak();
-}
-
-
 void ParseString(const string& str, char c, vector<string>& v)
 {
     unsigned int i1 = 0;
@@ -268,6 +250,92 @@
 }
 
 
+vector<unsigned char> ParseHex(const char* psz)
+{
+    vector<unsigned char> vch;
+    while (isspace(*psz))
+        psz++;
+    vch.reserve((strlen(psz)+1)/3);
+
+    static char phexdigit[256] =
+    { -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+      -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+      -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+      0,1,2,3,4,5,6,7,8,9,-1,-1,-1,-1,-1,-1,
+      -1,0xa,0xb,0xc,0xd,0xe,0xf,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+      -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+      -1,0xa,0xb,0xc,0xd,0xe,0xf,-1,-1,-1,-1,-1,-1,-1,-1,-1
+      -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+      -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+      -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+      -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+      -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+      -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+      -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+      -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+      -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, };
+
+    while (*psz)
+    {
+        char c = phexdigit[(unsigned char)*psz++];
+        if (c == -1)
+            break;
+        unsigned char n = (c << 4);
+        if (*psz)
+        {
+            char c = phexdigit[(unsigned char)*psz++];
+            if (c == -1)
+                break;
+            n |= c;
+            vch.push_back(n);
+        }
+        while (isspace(*psz))
+            psz++;
+    }
+
+    return vch;
+}
+
+vector<unsigned char> ParseHex(const std::string& str)
+{
+    return ParseHex(str.c_str());
+}
+
+
+
+
+
+
+void FormatException(char* pszMessage, std::exception* pex, const char* pszThread)
+{
+    char pszModule[MAX_PATH];
+    pszModule[0] = '\0';
+    GetModuleFileName(NULL, pszModule, sizeof(pszModule));
+    if (pex)
+        snprintf(pszMessage, 1000,
+            "EXCEPTION: %s       \n%s       \n%s in %s       \n", typeid(*pex).name(), pex->what(), pszModule, pszThread);
+    else
+        snprintf(pszMessage, 1000,
+            "UNKNOWN EXCEPTION       \n%s in %s       \n", pszModule, pszThread);
+}
+
+void LogException(std::exception* pex, const char* pszThread)
+{
+    char pszMessage[1000];
+    FormatException(pszMessage, pex, pszThread);
+    printf("\n%s", pszMessage);
+}
+
+void PrintException(std::exception* pex, const char* pszThread)
+{
+    char pszMessage[1000];
+    FormatException(pszMessage, pex, pszThread);
+    printf("\n\n************************\n%s\n", pszMessage);
+    if (wxTheApp)
+        wxMessageBox(pszMessage, "Error", wxOK | wxICON_ERROR);
+    throw;
+    //DebugBreak();
+}
 
 
 
@@ -363,7 +431,7 @@
     if (vTimeOffsets.empty())
         vTimeOffsets.push_back(0);
     vTimeOffsets.push_back(nOffsetSample);
-    printf("Added time data, samples %d, ip %08x, offset %+I64d (%+I64d minutes)\n", vTimeOffsets.size(), ip, vTimeOffsets.back(), vTimeOffsets.back()/60);
+    printf("Added time data, samples %d, offset %+I64d (%+I64d minutes)\n", vTimeOffsets.size(), vTimeOffsets.back(), vTimeOffsets.back()/60);
     if (vTimeOffsets.size() >= 5 && vTimeOffsets.size() % 2 == 1)
     {
         sort(vTimeOffsets.begin(), vTimeOffsets.end());
--- a/util.h
+++ b/util.h
@@ -67,15 +67,22 @@
 
 
 extern bool fDebug;
+extern bool fPrintToDebugger;
+extern bool fPrintToConsole;
+extern map<string, string> mapArgs;
 
-void RandAddSeed(bool fPerfmon=false);
+void RandAddSeed();
+void RandAddSeedPerfmon();
 int my_snprintf(char* buffer, size_t limit, const char* format, ...);
 string strprintf(const char* format, ...);
 bool error(const char* format, ...);
 void PrintException(std::exception* pex, const char* pszThread);
+void LogException(std::exception* pex, const char* pszThread);
 void ParseString(const string& str, char c, vector<string>& v);
 string FormatMoney(int64 n, bool fPlus=false);
 bool ParseMoney(const char* pszIn, int64& nRet);
+vector<unsigned char> ParseHex(const char* psz);
+vector<unsigned char> ParseHex(const std::string& str);
 bool FileExists(const char* psz);
 int GetFilesize(FILE* file);
 uint64 GetRand(uint64 nMax);
@@ -94,6 +101,7 @@
 
 
 
+
 // Wrapper to automatically initialize critical section
 // Could use wxCriticalSection for portability, but it doesn't support TryEnterCriticalSection
 class CCriticalSection
@@ -156,6 +164,85 @@
 
 
 
+inline int OutputDebugStringF(const char* pszFormat, ...)
+{
+    int ret = 0;
+#ifdef __WXDEBUG__
+    if (!fPrintToConsole)
+    {
+        // print to debug.log
+        FILE* fileout = fopen("debug.log", "a");
+        if (fileout)
+        {
+            va_list arg_ptr;
+            va_start(arg_ptr, pszFormat);
+            ret = vfprintf(fileout, pszFormat, arg_ptr);
+            va_end(arg_ptr);
+            fclose(fileout);
+        }
+    }
+
+    if (fPrintToDebugger)
+    {
+        // accumulate a line at a time
+        static CCriticalSection cs_OutputDebugStringF;
+        CRITICAL_BLOCK(cs_OutputDebugStringF)
+        {
+            static char pszBuffer[50000];
+            static char* pend;
+            if (pend == NULL)
+                pend = pszBuffer;
+            va_list arg_ptr;
+            va_start(arg_ptr, pszFormat);
+            int limit = END(pszBuffer) - pend - 2;
+            int ret = _vsnprintf(pend, limit, pszFormat, arg_ptr);
+            va_end(arg_ptr);
+            if (ret < 0 || ret >= limit)
+            {
+                pend = END(pszBuffer) - 2;
+                *pend++ = '\n';
+            }
+            else
+                pend += ret;
+            *pend = '\0';
+            char* p1 = pszBuffer;
+            char* p2;
+            while (p2 = strchr(p1, '\n'))
+            {
+                p2++;
+                char c = *p2;
+                *p2 = '\0';
+                OutputDebugString(p1);
+                *p2 = c;
+                p1 = p2;
+            }
+            if (p1 != pszBuffer)
+                memmove(pszBuffer, p1, pend - p1 + 1);
+            pend -= (p1 - pszBuffer);
+        }
+    }
+#endif
+
+    if (fPrintToConsole)
+    {
+        // print to console
+        va_list arg_ptr;
+        va_start(arg_ptr, pszFormat);
+        ret = vprintf(pszFormat, arg_ptr);
+        va_end(arg_ptr);
+    }
+    return ret;
+}
+
+
+
+
+
+
+
+
+
+
 inline string i64tostr(int64 n)
 {
     return strprintf("%"PRId64, n);
@@ -205,6 +292,11 @@
     return str;
 }
 
+inline string HexStr(vector<unsigned char> vch, bool fSpaces=true)
+{
+    return HexStr(vch.begin(), vch.end(), fSpaces);
+}
+
 template<typename T>
 string HexNumStr(const T itbegin, const T itend, bool f0x=true)
 {
@@ -222,75 +314,9 @@
     printf(pszFormat, HexStr(pbegin, pend, fSpaces).c_str());
 }
 
-
-
-
-
-
-
-
-inline int OutputDebugStringF(const char* pszFormat, ...)
+inline void PrintHex(vector<unsigned char> vch, const char* pszFormat="%s", bool fSpaces=true)
 {
-#ifdef __WXDEBUG__
-    // log file
-    FILE* fileout = fopen("debug.log", "a");
-    if (fileout)
-    {
-        va_list arg_ptr;
-        va_start(arg_ptr, pszFormat);
-        vfprintf(fileout, pszFormat, arg_ptr);
-        va_end(arg_ptr);
-        fclose(fileout);
-    }
-
-    // accumulate a line at a time
-    static CCriticalSection cs_OutputDebugStringF;
-    CRITICAL_BLOCK(cs_OutputDebugStringF)
-    {
-        static char pszBuffer[50000];
-        static char* pend;
-        if (pend == NULL)
-            pend = pszBuffer;
-        va_list arg_ptr;
-        va_start(arg_ptr, pszFormat);
-        int limit = END(pszBuffer) - pend - 2;
-        int ret = _vsnprintf(pend, limit, pszFormat, arg_ptr);
-        va_end(arg_ptr);
-        if (ret < 0 || ret >= limit)
-        {
-            pend = END(pszBuffer) - 2;
-            *pend++ = '\n';
-        }
-        else
-            pend += ret;
-        *pend = '\0';
-        char* p1 = pszBuffer;
-        char* p2;
-        while (p2 = strchr(p1, '\n'))
-        {
-            p2++;
-            char c = *p2;
-            *p2 = '\0';
-            OutputDebugString(p1);
-            *p2 = c;
-            p1 = p2;
-        }
-        if (p1 != pszBuffer)
-            memmove(pszBuffer, p1, pend - p1 + 1);
-        pend -= (p1 - pszBuffer);
-        return ret;
-    }
-#endif
-
-    if (!wxTheApp)
-    {
-        // print to console
-        va_list arg_ptr;
-        va_start(arg_ptr, pszFormat);
-        vprintf(pszFormat, arg_ptr);
-        va_end(arg_ptr);
-    }
-    return 0;
+    printf(pszFormat, HexStr(vch, fSpaces).c_str());
 }