changeset 153:de492f5bf245 draft

automatically change displayed address whenever it receives anything, added help and -? for daemon command line rpc commands, only relay addr messages to 5 random nodes to save bandwidth, started setting wtx.fFromMe flag, trickle out tx inventory messages to protect privacy -- version 0.2.10
author s_nakamoto <s_nakamoto@1a98c847-1fd6-4fd8-948a-caf3550aa51b>
date Thu, 10 Jun 2010 23:10:30 +0000
parents 4c6e1d4a4fb0
children 90df831d0789
files db.cpp db.h init.cpp irc.cpp main.cpp main.h net.cpp net.h rpc.cpp serialize.h ui.cpp uibase.cpp uibase.h uint256.h uiproject.fbp util.h
diffstat 16 files changed, 265 insertions(+), 140 deletions(-) [+]
line wrap: on
line diff
--- a/db.cpp
+++ b/db.cpp
@@ -511,9 +511,9 @@
 // CWalletDB
 //
 
-bool CWalletDB::LoadWallet(vector<unsigned char>& vchDefaultKeyRet)
+bool CWalletDB::LoadWallet()
 {
-    vchDefaultKeyRet.clear();
+    vchDefaultKey.clear();
     int nFileVersion = 0;
 
     // Modify defaults
@@ -587,7 +587,7 @@
             }
             else if (strType == "defaultkey")
             {
-                ssValue >> vchDefaultKeyRet;
+                ssValue >> vchDefaultKey;
             }
             else if (strType == "version")
             {
@@ -650,8 +650,7 @@
 bool LoadWallet(bool& fFirstRunRet)
 {
     fFirstRunRet = false;
-    vector<unsigned char> vchDefaultKey;
-    if (!CWalletDB("cr+").LoadWallet(vchDefaultKey))
+    if (!CWalletDB("cr+").LoadWallet())
         return false;
     fFirstRunRet = vchDefaultKey.empty();
 
--- a/db.h
+++ b/db.h
@@ -14,9 +14,11 @@
 
 extern map<string, string> mapAddressBook;
 extern CCriticalSection cs_mapAddressBook;
+extern vector<unsigned char> vchDefaultKey;
 extern bool fClient;
 
 
+
 extern unsigned int nWalletDBUpdated;
 extern DbEnv dbenv;
 
@@ -373,6 +375,7 @@
 
     bool WriteDefaultKey(const vector<unsigned char>& vchPubKey)
     {
+        vchDefaultKey = vchPubKey;
         nWalletDBUpdated++;
         return Write(string("defaultkey"), vchPubKey);
     }
@@ -390,7 +393,7 @@
         return Write(make_pair(string("setting"), strKey), value);
     }
 
-    bool LoadWallet(vector<unsigned char>& vchDefaultKeyRet);
+    bool LoadWallet();
 };
 
 bool LoadWallet(bool& fFirstRunRet);
--- a/init.cpp
+++ b/init.cpp
@@ -339,22 +339,27 @@
     if (mapArgs.count("-?") || mapArgs.count("--help"))
     {
         wxString strUsage = string() +
-            _("Usage: bitcoin [options]") + "\t\t\t\t\t\t\n" +
-            _("Options:\n") +
-            "  -gen            \t\t  " + _("Generate coins\n") +
-            "  -gen=0          \t\t  " + _("Don't generate coins\n") +
-            "  -min            \t\t  " + _("Start minimized\n") +
-            "  -datadir=<dir>  \t  "   + _("Specify data directory\n") +
-            "  -proxy=<ip:port>\t  "   + _("Connect through socks4 proxy\n") +
-            "  -addnode=<ip>   \t  "   + _("Add a node to connect to\n") +
-            "  -connect=<ip>   \t  "   + _("Connect only to the specified node\n") +
-            "  -?              \t\t  " + _("This help message\n");
+          _("Usage:") + "\t\t\t\t\t\t\t\t\t\t\n" +
+            "  bitcoin [options]       \t" + "\n" +
+            "  bitcoin [command]       \t" + _("Send command to bitcoin running with -server or -daemon\n") +
+            "  bitcoin [command] -?    \t" + _("Get help for a command\n") +
+            "  bitcoin help            \t" + _("List commands\n") +
+          _("Options:\n") +
+            "  -gen            \t  " + _("Generate coins\n") +
+            "  -gen=0          \t  " + _("Don't generate coins\n") +
+            "  -min            \t  " + _("Start minimized\n") +
+            "  -datadir=<dir>  \t  " + _("Specify data directory\n") +
+            "  -proxy=<ip:port>\t  " + _("Connect through socks4 proxy\n") +
+            "  -addnode=<ip>   \t  " + _("Add a node to connect to\n") +
+            "  -connect=<ip>   \t  " + _("Connect only to the specified node\n") +
+            "  -server         \t  " + _("Accept command line and JSON-RPC commands\n") +
+            "  -daemon         \t  " + _("Run in the background as a daemon and accept commands\n") +
+            "  -?              \t  " + _("This help message\n");
+
 
         if (fWindows && fGUI)
         {
-            // Remove spaces, the tabs make the columns line up in the message box
-            for (int i = 0; i < 50; i++)
-                strUsage.Replace(" \t", "\t");
+            // Tabs make the columns line up in the message box
             wxMessageBox(strUsage, "Bitcoin", wxOK);
         }
         else
--- a/irc.cpp
+++ b/irc.cpp
@@ -159,7 +159,6 @@
 void ThreadIRCSeed(void* parg)
 {
     printf("ThreadIRCSeed started\n");
-    SetThreadPriority(THREAD_PRIORITY_NORMAL);
     int nErrorWait = 10;
     int nRetryWait = 10;
     bool fNameInUse = false;
--- a/main.cpp
+++ b/main.cpp
@@ -49,6 +49,8 @@
 map<string, string> mapAddressBook;
 CCriticalSection cs_mapAddressBook;
 
+vector<unsigned char> vchDefaultKey;
+
 // Settings
 int fGenerateBitcoins = false;
 int64 nTransactionFee = 0;
@@ -142,6 +144,19 @@
             if (!wtx.WriteToDisk())
                 return false;
 
+        // If default receiving address gets used, replace it with a new one
+        CScript scriptDefaultKey;
+        scriptDefaultKey.SetBitcoinAddress(vchDefaultKey);
+        foreach(const CTxOut& txout, wtx.vout)
+        {
+            if (txout.scriptPubKey == scriptDefaultKey)
+            {
+                CWalletDB walletdb;
+                walletdb.WriteDefaultKey(GenerateNewKey());
+                walletdb.WriteName(PubKeyToAddress(vchDefaultKey), "");
+            }
+        }
+
         // Notify UI
         vWalletUpdated.push_back(hash);
     }
@@ -1753,8 +1768,6 @@
         {
             // Rewind and wait for rest of message
             ///// need a mechanism to give up waiting for overlong message size error
-            if (fDebug)
-                printf("message-break\n");
             vRecv.insert(vRecv.begin(), vHeaderSave.begin(), vHeaderSave.end());
             break;
         }
@@ -1922,19 +1935,26 @@
             if (fShutdown)
                 return true;
             addr.nTime = GetAdjustedTime() - 2 * 60 * 60;
-            if (pfrom->fGetAddr)
+            if (pfrom->fGetAddr || vAddr.size() > 10)
                 addr.nTime -= 5 * 24 * 60 * 60;
             AddAddress(addr, false);
             pfrom->AddAddressKnown(addr);
             if (!pfrom->fGetAddr && addr.IsRoutable())
             {
-                // Put on lists to send to other nodes
+                // Relay to a limited number of other nodes
                 CRITICAL_BLOCK(cs_vNodes)
+                {
+                    multimap<int, CNode*> mapMix;
                     foreach(CNode* pnode, vNodes)
-                        pnode->PushAddress(addr);
+                        mapMix.insert(make_pair(GetRand(INT_MAX), pnode));
+                    int nRelayNodes = 5;
+                    for (multimap<int, CNode*>::iterator mi = mapMix.begin(); mi != mapMix.end() && nRelayNodes-- > 0; ++mi)
+                        ((*mi).second)->PushAddress(addr);
+                }
             }
         }
-        pfrom->fGetAddr = false;
+        if (vAddr.size() < 1000)
+            pfrom->fGetAddr = false;
     }
 
 
@@ -2177,6 +2197,7 @@
         uint256 hashReply;
         CWalletTx wtxNew;
         vRecv >> hashReply >> wtxNew;
+        wtxNew.fFromMe = false;
 
         // Broadcast
         if (!wtxNew.AcceptWalletTransaction())
@@ -2242,7 +2263,7 @@
 
 
 
-bool SendMessages(CNode* pto)
+bool SendMessages(CNode* pto, bool fSendTrickle)
 {
     CRITICAL_BLOCK(cs_main)
     {
@@ -2273,15 +2294,6 @@
             }
         }
 
-        // Delay tx inv messages to protect privacy,
-        // trickle them out to a few nodes at a time.
-        bool fSendTxInv = false;
-        if (GetTimeMillis() > pto->nNextSendTxInv)
-        {
-            pto->nNextSendTxInv = GetTimeMillis() + 3000 + GetRand(2000);
-            fSendTxInv = true;
-        }
-
         // Resend wallet transactions that haven't gotten in a block yet
         ResendWalletTransactions();
 
@@ -2289,24 +2301,27 @@
         //
         // Message: addr
         //
-        vector<CAddress> vAddr;
-        vAddr.reserve(pto->vAddrToSend.size());
-        foreach(const CAddress& addr, pto->vAddrToSend)
+        if (fSendTrickle)
         {
-            // returns true if wasn't already contained in the set
-            if (pto->setAddrKnown.insert(addr).second)
+            vector<CAddress> vAddr;
+            vAddr.reserve(pto->vAddrToSend.size());
+            foreach(const CAddress& addr, pto->vAddrToSend)
             {
-                vAddr.push_back(addr);
-                if (vAddr.size() >= 1000)
+                // returns true if wasn't already contained in the set
+                if (pto->setAddrKnown.insert(addr).second)
                 {
-                    pto->PushMessage("addr", vAddr);
-                    vAddr.clear();
+                    vAddr.push_back(addr);
+                    if (vAddr.size() >= 1000)
+                    {
+                        pto->PushMessage("addr", vAddr);
+                        vAddr.clear();
+                    }
                 }
             }
+            pto->vAddrToSend.clear();
+            if (!vAddr.empty())
+                pto->PushMessage("addr", vAddr);
         }
-        pto->vAddrToSend.clear();
-        if (!vAddr.empty())
-            pto->PushMessage("addr", vAddr);
 
 
         //
@@ -2320,11 +2335,40 @@
             vInvWait.reserve(pto->vInventoryToSend.size());
             foreach(const CInv& inv, pto->vInventoryToSend)
             {
-                // delay txes
-                if (!fSendTxInv && inv.type == MSG_TX)
+                if (pto->setInventoryKnown.count(inv))
+                    continue;
+
+                // trickle out tx inv to protect privacy
+                if (inv.type == MSG_TX && !fSendTrickle)
                 {
-                    vInvWait.push_back(inv);
-                    continue;
+                    // 1/4 of tx invs blast to all immediately
+                    static uint256 hashSalt;
+                    if (hashSalt == 0)
+                        RAND_bytes((unsigned char*)&hashSalt, sizeof(hashSalt));
+                    uint256 hashRand = (inv.hash ^ hashSalt);
+                    hashRand = Hash(BEGIN(hashRand), END(hashRand));
+                    bool fTrickleWait = ((hashRand & 3) != 0);
+
+                    // always trickle our own transactions
+                    if (!fTrickleWait)
+                    {
+                        TRY_CRITICAL_BLOCK(cs_mapWallet)
+                        {
+                            map<uint256, CWalletTx>::iterator mi = mapWallet.find(inv.hash);
+                            if (mi != mapWallet.end())
+                            {
+                                CWalletTx& wtx = (*mi).second;
+                                if (wtx.fFromMe)
+                                    fTrickleWait = true;
+                            }
+                        }
+                    }
+
+                    if (fTrickleWait)
+                    {
+                        vInvWait.push_back(inv);
+                        continue;
+                    }
                 }
 
                 // returns true if wasn't already contained in the set
@@ -2852,6 +2896,7 @@
             {
                 wtxNew.vin.clear();
                 wtxNew.vout.clear();
+                wtxNew.fFromMe = true;
                 if (nValue < 0)
                     return false;
                 int64 nValueOut = nValue;
--- a/main.h
+++ b/main.h
@@ -38,6 +38,7 @@
 extern CCriticalSection cs_mapRequestCount;
 extern map<string, string> mapAddressBook;
 extern CCriticalSection cs_mapAddressBook;
+extern vector<unsigned char> vchDefaultKey;
 
 // Settings
 extern int fGenerateBitcoins;
@@ -66,7 +67,7 @@
 void PrintBlockTree();
 bool ProcessMessages(CNode* pfrom);
 bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv);
-bool SendMessages(CNode* pto);
+bool SendMessages(CNode* pto, bool fSendTrickle);
 int64 GetBalance();
 bool CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, CKey& keyRet, int64& nFeeRequiredRet);
 bool CommitTransaction(CWalletTx& wtxNew, const CKey& key);
--- a/net.cpp
+++ b/net.cpp
@@ -1019,7 +1019,6 @@
     SetThreadPriority(THREAD_PRIORITY_BELOW_NORMAL);
     while (!fShutdown)
     {
-        // Poll the connected nodes for messages
         vector<CNode*> vNodesCopy;
         CRITICAL_BLOCK(cs_vNodes)
         {
@@ -1027,6 +1026,11 @@
             foreach(CNode* pnode, vNodesCopy)
                 pnode->AddRef();
         }
+
+        // Poll the connected nodes for messages
+        CNode* pnodeTrickle = NULL;
+        if (!vNodesCopy.empty())
+            pnodeTrickle = vNodesCopy[GetRand(vNodesCopy.size())];
         foreach(CNode* pnode, vNodesCopy)
         {
             // Receive messages
@@ -1037,10 +1041,11 @@
 
             // Send messages
             TRY_CRITICAL_BLOCK(pnode->cs_vSend)
-                SendMessages(pnode);
+                SendMessages(pnode, pnode == pnodeTrickle);
             if (fShutdown)
                 return;
         }
+
         CRITICAL_BLOCK(cs_vNodes)
         {
             foreach(CNode* pnode, vNodesCopy)
--- a/net.h
+++ b/net.h
@@ -12,7 +12,7 @@
 
 
 
-static const unsigned short DEFAULT_PORT = htons(8333);
+#define DEFAULT_PORT    htons(8333)
 static const unsigned int PUBLISH_HOPS = 5;
 enum
 {
@@ -522,7 +522,6 @@
     vector<CInv> vInventoryToSend;
     CCriticalSection cs_inventory;
     multimap<int64, CInv> mapAskFor;
-    int64 nNextSendTxInv;
 
     // publish and subscription
     vector<char> vfSubscribe;
@@ -536,6 +535,12 @@
         vSend.SetVersion(0);
         vRecv.SetType(SER_NETWORK);
         vRecv.SetVersion(0);
+        // Version 0.2 obsoletes 20 Feb 2012
+        if (GetTime() > 1329696000)
+        {
+            vSend.SetVersion(209);
+            vRecv.SetVersion(209);
+        }
         nLastSend = 0;
         nLastRecv = 0;
         nLastSendEmpty = GetTime();
@@ -556,7 +561,6 @@
         hashLastGetBlocksEnd = 0;
         nStartingHeight = -1;
         fGetAddr = false;
-        nNextSendTxInv = 0;
         vfSubscribe.assign(256, false);
 
         // Push a version message
--- a/rpc.cpp
+++ b/rpc.cpp
@@ -18,6 +18,8 @@
 using namespace json_spirit;
 
 void ThreadRPCServer2(void* parg);
+typedef Value(*rpcfn_type)(const Array& params, bool fHelp);
+extern map<string, rpcfn_type> mapCallTable;
 
 
 
@@ -31,11 +33,40 @@
 
 
 
-Value stop(const Array& params)
+Value help(const Array& params, bool fHelp)
 {
-    if (params.size() != 0)
+    if (fHelp || params.size() != 0)
         throw runtime_error(
-            "stop (no parameters)\n"
+            "help\n"
+            "List commands.");
+
+    string strRet;
+    for (map<string, rpcfn_type>::iterator mi = mapCallTable.begin(); mi != mapCallTable.end(); ++mi)
+    {
+        try
+        {
+            Array params;
+            (*(*mi).second)(params, true);
+        }
+        catch (std::exception& e)
+        {
+            // Help text is returned in an exception
+            string strHelp = string(e.what());
+            if (strHelp.find('\n') != -1)
+                strHelp = strHelp.substr(0, strHelp.find('\n'));
+            strRet += strHelp + "\n";
+        }
+    }
+    strRet = strRet.substr(0,strRet.size()-1);
+    return strRet;
+}
+
+
+Value stop(const Array& params, bool fHelp)
+{
+    if (fHelp || params.size() != 0)
+        throw runtime_error(
+            "stop\n"
             "Stop bitcoin server.");
 
     // Shutdown will take long enough that the response should get back
@@ -44,33 +75,33 @@
 }
 
 
-Value getblockcount(const Array& params)
+Value getblockcount(const Array& params, bool fHelp)
 {
-    if (params.size() != 0)
+    if (fHelp || params.size() != 0)
         throw runtime_error(
-            "getblockcount (no parameters)\n"
+            "getblockcount\n"
             "Returns the number of blocks in the longest block chain.");
 
     return nBestHeight + 1;
 }
 
 
-Value getblocknumber(const Array& params)
+Value getblocknumber(const Array& params, bool fHelp)
 {
-    if (params.size() != 0)
+    if (fHelp || params.size() != 0)
         throw runtime_error(
-            "getblocknumber (no parameters)\n"
+            "getblocknumber\n"
             "Returns the block number of the latest block in the longest block chain.");
 
     return nBestHeight;
 }
 
 
-Value getconnectioncount(const Array& params)
+Value getconnectioncount(const Array& params, bool fHelp)
 {
-    if (params.size() != 0)
+    if (fHelp || params.size() != 0)
         throw runtime_error(
-            "getconnectioncount (no parameters)\n"
+            "getconnectioncount\n"
             "Returns the number of connections to other nodes.");
 
     return (int)vNodes.size();
@@ -89,42 +120,42 @@
     return dMinimum / dCurrently;
 }
 
-Value getdifficulty(const Array& params)
+Value getdifficulty(const Array& params, bool fHelp)
 {
-    if (params.size() != 0)
+    if (fHelp || params.size() != 0)
         throw runtime_error(
-            "getdifficulty (no parameters)\n"
+            "getdifficulty\n"
             "Returns the proof-of-work difficulty as a multiple of the minimum difficulty.");
 
     return GetDifficulty();
 }
 
 
-Value getbalance(const Array& params)
+Value getbalance(const Array& params, bool fHelp)
 {
-    if (params.size() != 0)
+    if (fHelp || params.size() != 0)
         throw runtime_error(
-            "getbalance (no parameters)\n"
+            "getbalance\n"
             "Returns the server's available balance.");
 
     return ((double)GetBalance() / (double)COIN);
 }
 
 
-Value getgenerate(const Array& params)
+Value getgenerate(const Array& params, bool fHelp)
 {
-    if (params.size() != 0)
+    if (fHelp || params.size() != 0)
         throw runtime_error(
-            "getgenerate (no parameters)\n"
+            "getgenerate\n"
             "Returns true or false.");
 
     return (bool)fGenerateBitcoins;
 }
 
 
-Value setgenerate(const Array& params)
+Value setgenerate(const Array& params, bool fHelp)
 {
-    if (params.size() < 1 || params.size() > 2)
+    if (fHelp || params.size() < 1 || params.size() > 2)
         throw runtime_error(
             "setgenerate <generate> [genproclimit]\n"
             "<generate> is true or false to turn generation on or off.\n"
@@ -148,11 +179,11 @@
 }
 
 
-Value getinfo(const Array& params)
+Value getinfo(const Array& params, bool fHelp)
 {
-    if (params.size() != 0)
+    if (fHelp || params.size() != 0)
         throw runtime_error(
-            "getinfo (no parameters)");
+            "getinfo");
 
     Object obj;
     obj.push_back(Pair("balance",       (double)GetBalance() / (double)COIN));
@@ -166,9 +197,9 @@
 }
 
 
-Value getnewaddress(const Array& params)
+Value getnewaddress(const Array& params, bool fHelp)
 {
-    if (params.size() > 1)
+    if (fHelp || params.size() > 1)
         throw runtime_error(
             "getnewaddress [label]\n"
             "Returns a new bitcoin address for receiving payments.  "
@@ -188,9 +219,9 @@
 }
 
 
-Value setlabel(const Array& params)
+Value setlabel(const Array& params, bool fHelp)
 {
-    if (params.size() < 1 || params.size() > 2)
+    if (fHelp || params.size() < 1 || params.size() > 2)
         throw runtime_error(
             "setlabel <bitcoinaddress> <label>\n"
             "Sets the label associated with the given address.");
@@ -205,9 +236,9 @@
 }
 
 
-Value getlabel(const Array& params)
+Value getlabel(const Array& params, bool fHelp)
 {
-    if (params.size() != 1)
+    if (fHelp || params.size() != 1)
         throw runtime_error(
             "getlabel <bitcoinaddress>\n"
             "Returns the label associated with the given address.");
@@ -225,9 +256,9 @@
 }
 
 
-Value getaddressesbylabel(const Array& params)
+Value getaddressesbylabel(const Array& params, bool fHelp)
 {
-    if (params.size() != 1)
+    if (fHelp || params.size() != 1)
         throw runtime_error(
             "getaddressesbylabel <label>\n"
             "Returns the list of addresses with the given label.");
@@ -255,9 +286,9 @@
 }
 
 
-Value sendtoaddress(const Array& params)
+Value sendtoaddress(const Array& params, bool fHelp)
 {
-    if (params.size() < 2 || params.size() > 4)
+    if (fHelp || params.size() < 2 || params.size() > 4)
         throw runtime_error(
             "sendtoaddress <bitcoinaddress> <amount> [comment] [comment-to]\n"
             "<amount> is a real and is rounded to the nearest 0.01");
@@ -283,9 +314,9 @@
 }
 
 
-Value listtransactions(const Array& params)
+Value listtransactions(const Array& params, bool fHelp)
 {
-    if (params.size() > 2)
+    if (fHelp || params.size() > 2)
         throw runtime_error(
             "listtransactions [count=10] [includegenerated=false]\n"
             "Returns up to [count] most recent transactions.");
@@ -304,9 +335,9 @@
 }
 
 
-Value getreceivedbyaddress(const Array& params)
+Value getreceivedbyaddress(const Array& params, bool fHelp)
 {
-    if (params.size() < 1 || params.size() > 2)
+    if (fHelp || params.size() < 1 || params.size() > 2)
         throw runtime_error(
             "getreceivedbyaddress <bitcoinaddress> [minconf=1]\n"
             "Returns the total amount received by <bitcoinaddress> in transactions with at least [minconf] confirmations.");
@@ -345,9 +376,9 @@
 }
 
 
-Value getreceivedbylabel(const Array& params)
+Value getreceivedbylabel(const Array& params, bool fHelp)
 {
-    if (params.size() < 1 || params.size() > 2)
+    if (fHelp || params.size() < 1 || params.size() > 2)
         throw runtime_error(
             "getreceivedbylabel <label> [minconf=1]\n"
             "Returns the total amount received by addresses with <label> in transactions with at least [minconf] confirmations.");
@@ -508,9 +539,9 @@
     return ret;
 }
 
-Value listreceivedbyaddress(const Array& params)
+Value listreceivedbyaddress(const Array& params, bool fHelp)
 {
-    if (params.size() > 2)
+    if (fHelp || params.size() > 2)
         throw runtime_error(
             "listreceivedbyaddress [minconf=1] [includeempty=false]\n"
             "[minconf] is the minimum number of confirmations before payments are included.\n"
@@ -524,9 +555,9 @@
     return ListReceived(params, false);
 }
 
-Value listreceivedbylabel(const Array& params)
+Value listreceivedbylabel(const Array& params, bool fHelp)
 {
-    if (params.size() > 2)
+    if (fHelp || params.size() > 2)
         throw runtime_error(
             "listreceivedbylabel [minconf=1] [includeempty=false]\n"
             "[minconf] is the minimum number of confirmations before payments are included.\n"
@@ -555,9 +586,9 @@
 // Call Table
 //
 
-typedef Value(*rpcfn_type)(const Array& params);
 pair<string, rpcfn_type> pCallTable[] =
 {
+    make_pair("help",                  &help),
     make_pair("stop",                  &stop),
     make_pair("getblockcount",         &getblockcount),
     make_pair("getblocknumber",        &getblocknumber),
@@ -760,7 +791,7 @@
                 map<string, rpcfn_type>::iterator mi = mapCallTable.find(strMethod);
                 if (mi == mapCallTable.end())
                     throw runtime_error("Method not found.");
-                Value result = (*(*mi).second)(params);
+                Value result = (*(*mi).second)(params, false);
 
                 // Send reply
                 string strReply = JSONRPCReply(result, Value::null, id);
@@ -847,32 +878,50 @@
         if (!mapCallTable.count(strMethod))
             throw runtime_error(strprintf("unknown command: %s", strMethod.c_str()));
 
-        // Parameters default to strings
-        Array params;
-        for (int i = 2; i < argc; i++)
-            params.push_back(argv[i]);
-        int n = params.size();
+        Value result;
+        if (argc == 3 && strcmp(argv[2], "-?") == 0)
+        {
+            // Call help locally, help text is returned in an exception
+            try
+            {
+                map<string, rpcfn_type>::iterator mi = mapCallTable.find(strMethod);
+                Array params;
+                (*(*mi).second)(params, true);
+            }
+            catch (std::exception& e)
+            {
+                result = e.what();
+            }
+        }
+        else
+        {
+            // Parameters default to strings
+            Array params;
+            for (int i = 2; i < argc; i++)
+                params.push_back(argv[i]);
+            int n = params.size();
 
-        //
-        // Special case other types
-        //
-        if (strMethod == "setgenerate"            && n > 0) ConvertTo<bool>(params[0]);
-        if (strMethod == "setgenerate"            && n > 1) ConvertTo<boost::int64_t>(params[1]);
-        if (strMethod == "sendtoaddress"          && n > 1) ConvertTo<double>(params[1]);
-        if (strMethod == "listtransactions"       && n > 0) ConvertTo<boost::int64_t>(params[0]);
-        if (strMethod == "listtransactions"       && n > 1) ConvertTo<bool>(params[1]);
-        if (strMethod == "getamountreceived"      && n > 1) ConvertTo<boost::int64_t>(params[1]); // deprecated
-        if (strMethod == "getreceivedbyaddress"   && n > 1) ConvertTo<boost::int64_t>(params[1]);
-        if (strMethod == "getreceivedbylabel"     && n > 1) ConvertTo<boost::int64_t>(params[1]);
-        if (strMethod == "getallreceived"         && n > 0) ConvertTo<boost::int64_t>(params[0]); // deprecated
-        if (strMethod == "getallreceived"         && n > 1) ConvertTo<bool>(params[1]);
-        if (strMethod == "listreceivedbyaddress"  && n > 0) ConvertTo<boost::int64_t>(params[0]);
-        if (strMethod == "listreceivedbyaddress"  && n > 1) ConvertTo<bool>(params[1]);
-        if (strMethod == "listreceivedbylabel"    && n > 0) ConvertTo<boost::int64_t>(params[0]);
-        if (strMethod == "listreceivedbylabel"    && n > 1) ConvertTo<bool>(params[1]);
+            //
+            // Special case non-string parameter types
+            //
+            if (strMethod == "setgenerate"            && n > 0) ConvertTo<bool>(params[0]);
+            if (strMethod == "setgenerate"            && n > 1) ConvertTo<boost::int64_t>(params[1]);
+            if (strMethod == "sendtoaddress"          && n > 1) ConvertTo<double>(params[1]);
+            if (strMethod == "listtransactions"       && n > 0) ConvertTo<boost::int64_t>(params[0]);
+            if (strMethod == "listtransactions"       && n > 1) ConvertTo<bool>(params[1]);
+            if (strMethod == "getamountreceived"      && n > 1) ConvertTo<boost::int64_t>(params[1]); // deprecated
+            if (strMethod == "getreceivedbyaddress"   && n > 1) ConvertTo<boost::int64_t>(params[1]);
+            if (strMethod == "getreceivedbylabel"     && n > 1) ConvertTo<boost::int64_t>(params[1]);
+            if (strMethod == "getallreceived"         && n > 0) ConvertTo<boost::int64_t>(params[0]); // deprecated
+            if (strMethod == "getallreceived"         && n > 1) ConvertTo<bool>(params[1]);
+            if (strMethod == "listreceivedbyaddress"  && n > 0) ConvertTo<boost::int64_t>(params[0]);
+            if (strMethod == "listreceivedbyaddress"  && n > 1) ConvertTo<bool>(params[1]);
+            if (strMethod == "listreceivedbylabel"    && n > 0) ConvertTo<boost::int64_t>(params[0]);
+            if (strMethod == "listreceivedbylabel"    && n > 1) ConvertTo<bool>(params[1]);
 
-        // Execute
-        Value result = CallRPC(strMethod, params);
+            // Execute
+            result = CallRPC(strMethod, params);
+        }
 
         // Print result
         string strResult = (result.type() == str_type ? result.get_str() : write_string(result, true));
--- a/serialize.h
+++ b/serialize.h
@@ -19,7 +19,7 @@
 class CDataStream;
 class CAutoFile;
 
-static const int VERSION = 209;
+static const int VERSION = 210;
 static const char* pszSubVer = ".0";
 
 
--- a/ui.cpp
+++ b/ui.cpp
@@ -1016,6 +1016,11 @@
 
     if (fDebug && GetTime() - nThreadSocketHandlerHeartbeat > 60)
         m_statusBar->SetStatusText("     ERROR: ThreadSocketHandler has stopped", 0);
+
+    // Update receiving address
+    string strDefaultAddress = PubKeyToAddress(vchDefaultKey);
+    if (m_textCtrlAddress->GetValue() != strDefaultAddress)
+        m_textCtrlAddress->SetValue(strDefaultAddress);
 }
 
 
@@ -2087,7 +2092,9 @@
         }
 
         // Send payment tx to seller, with response going to OnReply3 via event handler
-        pnode->PushRequest("submitorder", wtx, SendingDialogOnReply3, this);
+        CWalletTx wtxSend = wtx;
+        wtxSend.fFromMe = false;
+        pnode->PushRequest("submitorder", wtxSend, SendingDialogOnReply3, this);
 
         Status(_("Waiting for confirmation..."));
         MainFrameRepaint();
--- a/uibase.cpp
+++ b/uibase.cpp
@@ -616,7 +616,7 @@
 	
 	fgSizer1->Add( 0, 0, 0, wxEXPAND, 5 );
 	
-	m_staticTextInstructions = new wxStaticText( this, wxID_ANY, _("Enter the recipient's IP address (e.g. 123.45.6.7) for online transfer with comments and confirmation, \nor Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJED9L) if recipient is not online."), wxDefaultPosition, wxDefaultSize, 0 );
+	m_staticTextInstructions = new wxStaticText( this, wxID_ANY, _("Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJED9L) or IP address (e.g. 123.45.6.7)"), wxDefaultPosition, wxDefaultSize, 0 );
 	m_staticTextInstructions->Wrap( -1 );
 	fgSizer1->Add( m_staticTextInstructions, 0, wxTOP|wxRIGHT|wxLEFT, 5 );
 	
--- a/uibase.h
+++ b/uibase.h
@@ -275,7 +275,7 @@
 		
 	
 	public:
-		CSendDialogBase( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Send Coins"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 675,312 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER );
+		CSendDialogBase( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Send Coins"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 675,298 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER );
 		~CSendDialogBase();
 	
 };
--- a/uint256.h
+++ b/uint256.h
@@ -388,7 +388,6 @@
 //
 // uint160 and uint256 could be implemented as templates, but to keep
 // compile errors and debugging cleaner, they're copy and pasted.
-// It's safe to search and replace 160 with 256 and vice versa.
 //
 
 
@@ -405,6 +404,8 @@
 
     uint160()
     {
+        for (int i = 0; i < WIDTH; i++)
+            pn[i] = 0;
     }
 
     uint160(const basetype& b)
@@ -517,6 +518,8 @@
 
     uint256()
     {
+        for (int i = 0; i < WIDTH; i++)
+            pn[i] = 0;
     }
 
     uint256(const basetype& b)
--- a/uiproject.fbp
+++ b/uiproject.fbp
@@ -18,7 +18,7 @@
         <property name="relative_path">1</property>
         <property name="use_enum">0</property>
         <property name="use_microsoft_bom">0</property>
-        <object class="Frame" expanded="1">
+        <object class="Frame" expanded="0">
             <property name="bg">wxSYS_COLOUR_BTNFACE</property>
             <property name="center"></property>
             <property name="context_help"></property>
@@ -3317,7 +3317,7 @@
             <property name="minimum_size"></property>
             <property name="name">CSendDialogBase</property>
             <property name="pos"></property>
-            <property name="size">675,312</property>
+            <property name="size">675,298</property>
             <property name="style">wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER</property>
             <property name="subclass"></property>
             <property name="title">Send Coins</property>
@@ -3408,7 +3408,7 @@
                                 <property name="font"></property>
                                 <property name="hidden">0</property>
                                 <property name="id">wxID_ANY</property>
-                                <property name="label">Enter the recipient&apos;s IP address (e.g. 123.45.6.7) for online transfer with comments and confirmation, &#x0A;or Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJED9L) if recipient is not online.</property>
+                                <property name="label">Enter a Bitcoin address (e.g. 1NS17iag9jJgTHD1VXjvLCEnZuQ3rJED9L) or IP address (e.g. 123.45.6.7)</property>
                                 <property name="maximum_size"></property>
                                 <property name="minimum_size"></property>
                                 <property name="name">m_staticTextInstructions</property>
--- a/util.h
+++ b/util.h
@@ -520,8 +520,13 @@
 
 inline void SetThreadPriority(int nPriority)
 {
-    // threads are processes on linux, so PRIO_PROCESS affects just the one thread
-    setpriority(PRIO_PROCESS, getpid(), nPriority);
+    // It's unclear if it's even possible to change thread priorities on Linux,
+    // but we really and truly need it for the generation threads.
+#ifdef PRIO_THREAD
+    setpriority(PRIO_THREAD, 0, nPriority);
+#else
+    setpriority(PRIO_PROCESS, 0, nPriority);
+#endif
 }
 
 inline bool TerminateThread(pthread_t hthread, unsigned int nExitCode)