diff --git a/db.cpp b/db.cpp index 51cbb309b..e0a672b1e 100644 --- a/db.cpp +++ b/db.cpp @@ -511,9 +511,9 @@ bool LoadAddresses() // CWalletDB // -bool CWalletDB::LoadWallet(vector& vchDefaultKeyRet) +bool CWalletDB::LoadWallet() { - vchDefaultKeyRet.clear(); + vchDefaultKey.clear(); int nFileVersion = 0; // Modify defaults @@ -587,7 +587,7 @@ bool CWalletDB::LoadWallet(vector& vchDefaultKeyRet) } else if (strType == "defaultkey") { - ssValue >> vchDefaultKeyRet; + ssValue >> vchDefaultKey; } else if (strType == "version") { @@ -650,8 +650,7 @@ bool CWalletDB::LoadWallet(vector& vchDefaultKeyRet) bool LoadWallet(bool& fFirstRunRet) { fFirstRunRet = false; - vector vchDefaultKey; - if (!CWalletDB("cr+").LoadWallet(vchDefaultKey)) + if (!CWalletDB("cr+").LoadWallet()) return false; fFirstRunRet = vchDefaultKey.empty(); diff --git a/db.h b/db.h index 0b778d5fe..29ff1994c 100644 --- a/db.h +++ b/db.h @@ -14,9 +14,11 @@ class CWalletTx; extern map mapAddressBook; extern CCriticalSection cs_mapAddressBook; +extern vector vchDefaultKey; extern bool fClient; + extern unsigned int nWalletDBUpdated; extern DbEnv dbenv; @@ -373,6 +375,7 @@ public: bool WriteDefaultKey(const vector& vchPubKey) { + vchDefaultKey = vchPubKey; nWalletDBUpdated++; return Write(string("defaultkey"), vchPubKey); } @@ -390,7 +393,7 @@ public: return Write(make_pair(string("setting"), strKey), value); } - bool LoadWallet(vector& vchDefaultKeyRet); + bool LoadWallet(); }; bool LoadWallet(bool& fFirstRunRet); diff --git a/init.cpp b/init.cpp index 833a8a3f0..ecb1709c1 100644 --- a/init.cpp +++ b/init.cpp @@ -339,22 +339,27 @@ bool CMyApp::OnInit2() 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= \t " + _("Specify data directory\n") + - " -proxy=\t " + _("Connect through socks4 proxy\n") + - " -addnode= \t " + _("Add a node to connect to\n") + - " -connect= \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= \t " + _("Specify data directory\n") + + " -proxy=\t " + _("Connect through socks4 proxy\n") + + " -addnode= \t " + _("Add a node to connect to\n") + + " -connect= \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 diff --git a/irc.cpp b/irc.cpp index de0b997ab..673baebeb 100644 --- a/irc.cpp +++ b/irc.cpp @@ -159,7 +159,6 @@ bool Wait(int nSeconds) void ThreadIRCSeed(void* parg) { printf("ThreadIRCSeed started\n"); - SetThreadPriority(THREAD_PRIORITY_NORMAL); int nErrorWait = 10; int nRetryWait = 10; bool fNameInUse = false; diff --git a/main.cpp b/main.cpp index 05a182c18..aef68838c 100644 --- a/main.cpp +++ b/main.cpp @@ -49,6 +49,8 @@ CCriticalSection cs_mapRequestCount; map mapAddressBook; CCriticalSection cs_mapAddressBook; +vector vchDefaultKey; + // Settings int fGenerateBitcoins = false; int64 nTransactionFee = 0; @@ -142,6 +144,19 @@ bool AddToWallet(const CWalletTx& wtxIn) 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 @@ bool ProcessMessages(CNode* pfrom) { // 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 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) 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 mapMix; foreach(CNode* pnode, vNodes) - pnode->PushAddress(addr); + mapMix.insert(make_pair(GetRand(INT_MAX), pnode)); + int nRelayNodes = 5; + for (multimap::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 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) uint256 hashReply; CWalletTx wtxNew; vRecv >> hashReply >> wtxNew; + wtxNew.fFromMe = false; // Broadcast if (!wtxNew.AcceptWalletTransaction()) @@ -2242,7 +2263,7 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) -bool SendMessages(CNode* pto) +bool SendMessages(CNode* pto, bool fSendTrickle) { CRITICAL_BLOCK(cs_main) { @@ -2273,15 +2294,6 @@ bool SendMessages(CNode* pto) } } - // 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 @@ bool SendMessages(CNode* pto) // // Message: addr // - vector 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 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 @@ bool SendMessages(CNode* pto) vInvWait.reserve(pto->vInventoryToSend.size()); foreach(const CInv& inv, pto->vInventoryToSend) { - // delay txes - if (!fSendTxInv && inv.type == MSG_TX) - { - vInvWait.push_back(inv); + if (pto->setInventoryKnown.count(inv)) continue; + + // trickle out tx inv to protect privacy + if (inv.type == MSG_TX && !fSendTrickle) + { + // 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::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 @@ bool CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, CK { wtxNew.vin.clear(); wtxNew.vout.clear(); + wtxNew.fFromMe = true; if (nValue < 0) return false; int64 nValueOut = nValue; diff --git a/main.h b/main.h index 83b846993..d8f257b7d 100644 --- a/main.h +++ b/main.h @@ -38,6 +38,7 @@ extern map mapRequestCount; extern CCriticalSection cs_mapRequestCount; extern map mapAddressBook; extern CCriticalSection cs_mapAddressBook; +extern vector vchDefaultKey; // Settings extern int fGenerateBitcoins; @@ -66,7 +67,7 @@ bool LoadBlockIndex(bool fAllowNew=true); 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); diff --git a/net.cpp b/net.cpp index fbfa74622..c5659dc92 100644 --- a/net.cpp +++ b/net.cpp @@ -1019,7 +1019,6 @@ void ThreadMessageHandler2(void* parg) SetThreadPriority(THREAD_PRIORITY_BELOW_NORMAL); while (!fShutdown) { - // Poll the connected nodes for messages vector vNodesCopy; CRITICAL_BLOCK(cs_vNodes) { @@ -1027,6 +1026,11 @@ void ThreadMessageHandler2(void* parg) 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 @@ void ThreadMessageHandler2(void* parg) // 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) diff --git a/net.h b/net.h index 46344ed92..9ce848f63 100644 --- a/net.h +++ b/net.h @@ -12,7 +12,7 @@ extern int nBestHeight; -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 @@ public: vector vInventoryToSend; CCriticalSection cs_inventory; multimap mapAskFor; - int64 nNextSendTxInv; // publish and subscription vector vfSubscribe; @@ -536,6 +535,12 @@ public: 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 @@ public: hashLastGetBlocksEnd = 0; nStartingHeight = -1; fGetAddr = false; - nNextSendTxInv = 0; vfSubscribe.assign(256, false); // Push a version message diff --git a/rpc.cpp b/rpc.cpp index d988786ef..a9f16e635 100644 --- a/rpc.cpp +++ b/rpc.cpp @@ -18,6 +18,8 @@ using boost::asio::ip::tcp; using namespace json_spirit; void ThreadRPCServer2(void* parg); +typedef Value(*rpcfn_type)(const Array& params, bool fHelp); +extern map mapCallTable; @@ -31,11 +33,40 @@ void ThreadRPCServer2(void* parg); -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::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 stop(const Array& params) } -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 @@ double GetDifficulty() 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 [genproclimit]\n" " is true or false to turn generation on or off.\n" @@ -148,11 +179,11 @@ Value setgenerate(const Array& params) } -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 getinfo(const Array& params) } -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 getnewaddress(const Array& params) } -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