Satoshi MailBeta Open in Satoshi Mail

addr relaying fixes, proxy option and privacy patches, detect connect to self, non-final tx locktime changes, fix hide unconfirmed generated

Commit by Satoshi Nakamoto (s_nakamoto) on 29 October 2009 · SVN r18 · release v0.2.0 · 19 files, +1,209 −339

Open in Satoshi Mail View on GitHub

Files changed

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 @@ Dependencies
 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 @@ If you want to use it with MSVC, generate the .lib file
 Berkeley DB
 -----------
 Using MinGW and MSYS:
-cd \DB\build_unix
+cd \db\build_unix
 sh ../dist/configure --enable-mingw --enable-cxx
 make
 
db.cpp
@@ -121,10 +121,12 @@ void CDB::Close()
     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 @@ bool CTxDB::LoadBlockIndex()
     {
         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 @@ bool CReviewDB::WriteReviews(uint256 hash, const vector<CReview>& vReviews)
 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 @@ bool CWalletDB::LoadWallet(vector<unsigned char>& vchDefaultKeyRet)
                 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 @@ bool CWalletDB::LoadWallet(vector<unsigned char>& vchDefaultKeyRet)
     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 @@ bool LoadWallet(bool& fFirstRunRet)
     else
     {
         // Create new keyUser and set as default key
-        RandAddSeed(true);
+        RandAddSeedPerfmon();
         keyUser.MakeNewKey();
         if (!AddKey(keyUser))
             return false;
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 @@ using namespace boost;
 
 
 
+#include "strlcpy.h"
 #include "serialize.h"
 #include "uint256.h"
 #include "util.h"
irc.cpp
@@ -163,6 +163,9 @@ void ThreadIRCSeed(void* parg)
     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 @@ void ThreadIRCSeed(void* parg)
                 return;
         }
 
-        string strMyName = EncodeAddress(addrLocalHost);
-
-        if (!addrLocalHost.IsRoutable())
+        string strMyName;
+        if (addrLocalHost.IsRoutable() && !fUseProxy)
+            strMyName = EncodeAddress(addrLocalHost);
+        else
             strMyName = strprintf("x%u", GetRand(1000000000));
 
 
key.h
@@ -35,7 +35,7 @@ public:
 };
 
 
-// secure_allocator is defined is serialize.h
+// secure_allocator is defined in serialize.h
 typedef vector<unsigned char, secure_allocator<unsigned char> > CPrivKey;
 
 
main.cpp
@@ -415,6 +415,10 @@ bool CTransaction::AcceptTransaction(CTxDB& txdb, bool fCheckInputs, bool* pfMis
     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 @@ bool CBlock::AcceptBlock()
     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 @@ bool ProcessMessages(CNode* pfrom)
     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 @@ bool ProcessMessages(CNode* pfrom)
         {
             // 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 @@ bool ProcessMessages(CNode* pfrom)
                 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 ProcessMessages(CNode* pfrom)
 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 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
 
 
 
+
     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 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
             pfrom->PushMessage("getblocks", CBlockLocator(pindexBest), uint256(0));
         }
 
+        pfrom->fSuccessfullyConnected = true;
+
         printf("version message: version %d\n", pfrom->nVersion);
     }
 
@@ -1800,16 +1840,16 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
             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 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
                     return true;
                 const CAddress& addr = item.second;
                 if (addr.nTime > nSince)
-                    pfrom->vAddrToSend.push_back(addr);
+                    pfrom->PushAddress(addr);
             }
         }
     }
@@ -2108,8 +2148,11 @@ bool SendMessages(CNode* pto)
         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 @@ void GenerateBitcoins(bool fGenerate)
         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 @@ void ThreadBitcoinMiner(void* parg)
     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 @@ bool SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew)
             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))
         {
main.h
@@ -366,7 +366,7 @@ public:
     int nVersion;
     vector<CTxIn> vin;
     vector<CTxOut> vout;
-    int nLockTime;
+    unsigned int nLockTime;
 
 
     CTransaction()
@@ -401,9 +401,15 @@ public:
         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 @@ public:
     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 @@ public:
         fFromMe = false;
         fSpent = false;
         nTimeDisplayed = 0;
+        nLinesDisplayed = 0;
     }
 
     IMPLEMENT_SERIALIZE
makefile
@@ -17,8 +17,8 @@ endif
 
 
 
-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 \
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 @@ uint64 nLocalServices = (fClient ? 0 : NODE_NETWORK);
 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 @@ deque<pair<int64, CInv> > vRelayExpiration;
 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 @@ bool ConnectSocket(const CAddress& addrConnect, SOCKET& hSocketRet)
         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 @@ bool ConnectSocket(const CAddress& addrConnect, SOCKET& hSocketRet)
         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 @@ bool GetMyExternalIP2(const CAddress& addrConnect, const char* pszGet, const cha
 {
     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 @@ bool GetMyExternalIP2(const CAddress& addrConnect, const char* pszGet, const cha
         }
     }
     closesocket(hSocket);
-    return error("GetMyExternalIP() : connection closed\n");
+    return error("GetMyExternalIP() : connection closed");
 }
 
 
@@ -141,6 +146,9 @@ bool GetMyExternalIP(unsigned int& ipRet)
     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 @@ CNode* ConnectNode(CAddress addrConnect, int64 nTimeout)
     }
 }
 
-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 @@ void ThreadSocketHandler(void* parg)
 
     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 ThreadSocketHandler(void* parg)
 void ThreadSocketHandler2(void* parg)
 {
     printf("ThreadSocketHandler started\n");
-    SOCKET hListenSocket = *(SOCKET*)parg;
     list<CNode*> vNodesDisconnected;
     int nPrevNodeCount = 0;
 
@@ -498,7 +505,7 @@ void ThreadSocketHandler2(void* parg)
                 {
                     // 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 @@ void ThreadSocketHandler2(void* parg)
             }
         }
 
-        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 @@ void ThreadSocketHandler2(void* parg)
             }
             Sleep(timeout.tv_usec/1000);
         }
-        RandAddSeed();
 
         //// debug print
         //foreach(CNode* pnode, vNodes)
@@ -711,18 +717,18 @@ void ThreadOpenConnections(void* parg)
 
     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 @@ void ThreadOpenConnections2(void* parg)
 {
     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 @@ void ThreadOpenConnections2(void* parg)
     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 @@ void ThreadOpenConnections2(void* parg)
 
         // 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);
-            }
+    vnThreadsRunning[1]--;
+    CNode* pnode = ConnectNode(addrConnect);
+    vnThreadsRunning[1]++;
+    CheckForShutdown(1);
+    if (!pnode)
+        return false;
+    pnode->fNetworkNode = true;
 
-            // Get as many addresses as we can
-            pnode->PushMessage("getaddr");
+    if (addrLocalHost.IsRoutable() && !fUseProxy)
+    {
+        // Advertise our address
+        vector<CAddress> vAddrToSend;
+        vAddrToSend.push_back(addrLocalHost);
+        pnode->PushMessage("addr", vAddrToSend);
+    }
 
-            ////// 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);
+    // Get as many addresses as we can
+    pnode->PushMessage("getaddr");
+    pnode->fGetAddr = true; // don't relay the results of the getaddr
 
-            break;
-        }
-    }
+    ////// 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;
net.h
@@ -174,7 +174,7 @@ public:
     {
         nServices = nServicesIn;
         memcpy(pchReserved, pchIPv4, sizeof(pchReserved));
-        ip = 0;
+        ip = INADDR_NONE;
         port = DEFAULT_PORT;
         nTime = GetAdjustedTime();
         nLastFailed = 0;
@@ -183,7 +183,7 @@ public:
         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 @@ public:
         {
             *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 @@ public:
                 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 @@ public:
         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 bool fClient;
 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 map<CInv, CDataStream> mapRelay;
 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 @@ public:
     bool fClient;
     bool fInbound;
     bool fNetworkNode;
+    bool fSuccessfullyConnected;
     bool fDisconnect;
 protected:
     int nRefCount;
@@ -459,6 +478,7 @@ public:
     // flood
     vector<CAddress> vAddrToSend;
     set<CAddress> setAddrKnown;
+    bool fGetAddr;
 
     // inventory based relay
     set<CInv> setInventoryKnown;
@@ -483,15 +503,20 @@ public:
         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 @@ public:
 
 
 
+    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 @@ public:
     }
 
 
-
     void BeginMessage(const char* pszCommand)
     {
         EnterCriticalSection(&cs_vSend);
@@ -570,7 +609,7 @@ public:
             AbortMessage();
         nPushPos = vSend.size();
         vSend << CMessageHeader(pszCommand, 0);
-        printf("sending: %-12s ", pszCommand);
+        printf("sending: %s ", pszCommand);
     }
 
     void AbortMessage()
@@ -706,6 +745,86 @@ public:
         }
     }
 
+    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 @@ public:
     bool IsSubscribed(unsigned int nChannel);
     void Subscribe(unsigned int nChannel, unsigned int nHops=0);
     void CancelSubscribe(unsigned int nChannel);
-    void Disconnect();
+    void DoDisconnect();
 };
 
 
serialize.h
@@ -19,7 +19,7 @@ class CScript;
 class CDataStream;
 class CAutoFile;
 
-static const int VERSION = 105;
+static const int VERSION = 106;
 
 
 
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 */
+}
ui.cpp
@@ -497,7 +497,7 @@ string SingleLine(const string& strIn)
     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 @@ void CMainFrame::InsertTransaction(const CWalletTx& wtx, bool fNew, int nIndex)
     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 @@ void CMainFrame::InsertTransaction(const CWalletTx& wtx, bool fNew, int nIndex)
         //
         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 @@ void CMainFrame::InsertTransaction(const CWalletTx& wtx, bool fNew, int nIndex)
             // 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 @@ void CMainFrame::InsertTransaction(const CWalletTx& wtx, bool fNew, int nIndex)
                            SingleLine(strDescription),
                            FormatMoney(-nValue, true),
                            "");
+                wtx.nLinesDisplayed++;
             }
         }
         else
@@ -706,12 +708,14 @@ void CMainFrame::InsertTransaction(const CWalletTx& wtx, bool fNew, int nIndex)
                        "");
         }
     }
+
+    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 @@ void CMainFrame::RefreshStatus()
         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 @@ void CMainFrame::RefreshStatus()
                 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 @@ void CMainFrame::OnIdle(wxIdleEvent& event)
         }
 
         printf("RefreshListCtrl done\n");
+
+        // Update transaction total display
+        MainFrameRepaint();
     }
     else
     {
@@ -834,31 +844,54 @@ void DelayedRepaint(void* parg)
         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 @@ void CMainFrame::OnPaintListCtrl(wxPaintEvent& event)
         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 @@ COptionsDialog::COptionsDialog(wxWindow* parent) : COptionsDialogBase(parent)
     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::OnCheckBoxMinimizeToTray(wxCommandEvent& event)
 
 }
 
+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 @@ void COptionsDialog::OnButtonApply(wxCommandEvent& event)
         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 @@ CSendingDialog::CSendingDialog(wxWindow* parent, const CAddress& addrIn, int64 n
     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::OnButtonCancel(wxCommandEvent& event)
 
 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 @@ void CSendingDialog::OnPaint(wxPaintEvent& event)
     }
     if (fAbort && fCanCancel && IsShown())
     {
-        strStatus = "CANCELLED";
+        strcpy(pszStatus, "CANCELLED");
         m_buttonOK->Enable(true);
         m_buttonOK->SetFocus();
         m_buttonCancel->Enable(false);
@@ -1777,7 +1850,8 @@ bool CSendingDialog::Status()
     }
     if (fAbort && fCanCancel)
     {
-        strStatus = "CANCELLED";
+        memset(pszStatus, 0, 10);
+        strcpy(pszStatus, "CANCELLED");
         Repaint();
         fWorkDone = true;
         return false;
@@ -1789,7 +1863,12 @@ bool CSendingDialog::Status(const string& str)
 {
     if (!Status())
         return false;
-    strStatus = str;
ui.h
@@ -89,7 +89,7 @@ public:
     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 @@ protected:
     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 @@ public:
     bool fTmpStartOnSystemStartup;
     bool fTmpMinimizeOnClose;
     void SelectPage(int nPage);
+    CAddress GetProxyAddr();
 };
 
 
@@ -193,7 +197,7 @@ public:
     int64 nPrice;
     CWalletTx wtx;
     wxDateTime start;
-    string strStatus;
+    char pszStatus[10000];
     bool fCanCancel;
     bool fAbort;
     bool fSuccess;
uibase.cpp
@@ -380,7 +380,7 @@ COptionsDialogBase::COptionsDialogBase( wxWindow* parent, wxWindowID id, const w
 	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 @@ COptionsDialogBase::COptionsDialogBase( wxWindow* parent, wxWindowID id, const w
 	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 @@ COptionsDialogBase::COptionsDialogBase( wxWindow* parent, wxWindowID id, const w
 	
 	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 @@ COptionsDialogBase::COptionsDialogBase( wxWindow* parent, wxWindowID id, const w
 	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 @@ COptionsDialogBase::COptionsDialogBase( wxWindow* parent, wxWindowID id, const w
 	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 @@ COptionsDialogBase::~COptionsDialogBase()
 	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 );
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
uiproject.fbp
util.cpp
util.h