BIP 0031: pong message
[novacoin.git] / src / main.cpp
index d795ca1..fbe9232 100644 (file)
@@ -18,11 +18,6 @@ using namespace boost;
 // Global state
 //
 
-// Name of client reported in the 'version' message. Report the same name
-// for both bitcoind and bitcoin-qt, to make it harder for attackers to
-// target servers or GUI users specifically.
-const std::string CLIENT_NAME("Satoshi");
-
 CCriticalSection cs_setpwalletRegistered;
 set<CWallet*> setpwalletRegistered;
 
@@ -75,16 +70,16 @@ int64 nTransactionFee = 0;
 
 void RegisterWallet(CWallet* pwalletIn)
 {
-    CRITICAL_BLOCK(cs_setpwalletRegistered)
     {
+        LOCK(cs_setpwalletRegistered);
         setpwalletRegistered.insert(pwalletIn);
     }
 }
 
 void UnregisterWallet(CWallet* pwalletIn)
 {
-    CRITICAL_BLOCK(cs_setpwalletRegistered)
     {
+        LOCK(cs_setpwalletRegistered);
         setpwalletRegistered.erase(pwalletIn);
     }
 }
@@ -478,9 +473,11 @@ bool CTransaction::AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs, bool* pfMi
 
     // Do we already have it?
     uint256 hash = GetHash();
-    CRITICAL_BLOCK(cs_mapTransactions)
+    {
+        LOCK(cs_mapTransactions);
         if (mapTransactions.count(hash))
             return false;
+    }
     if (fCheckInputs)
         if (txdb.ContainsTx(hash))
             return false;
@@ -552,8 +549,8 @@ bool CTransaction::AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs, bool* pfMi
             static int64 nLastTime;
             int64 nNow = GetTime();
 
-            CRITICAL_BLOCK(cs)
             {
+                LOCK(cs);
                 // Use an exponentially decaying ~10-minute window:
                 dFreeCount *= pow(1.0 - 1.0/600.0, (double)(nNow - nLastTime));
                 nLastTime = nNow;
@@ -576,8 +573,8 @@ bool CTransaction::AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs, bool* pfMi
     }
 
     // Store transaction in memory
-    CRITICAL_BLOCK(cs_mapTransactions)
     {
+        LOCK(cs_mapTransactions);
         if (ptxOld)
         {
             printf("AcceptToMemoryPool() : replacing tx %s with new version\n", ptxOld->GetHash().ToString().c_str());
@@ -608,8 +605,8 @@ bool CTransaction::AddToMemoryPoolUnchecked()
     printf("AcceptToMemoryPoolUnchecked(): size %lu\n",  mapTransactions.size());
     // Add to memory pool without checking anything.  Don't call this directly,
     // call AcceptToMemoryPool to properly check the transaction first.
-    CRITICAL_BLOCK(cs_mapTransactions)
     {
+        LOCK(cs_mapTransactions);
         uint256 hash = GetHash();
         mapTransactions[hash] = *this;
         for (int i = 0; i < vin.size(); i++)
@@ -624,8 +621,8 @@ bool CTransaction::AddToMemoryPoolUnchecked()
 bool CTransaction::RemoveFromMemoryPool()
 {
     // Remove transaction from memory pool
-    CRITICAL_BLOCK(cs_mapTransactions)
     {
+        LOCK(cs_mapTransactions);
         uint256 hash = GetHash();
         if (mapTransactions.count(hash))
         {
@@ -702,8 +699,9 @@ bool CMerkleTx::AcceptToMemoryPool()
 
 bool CWalletTx::AcceptWalletTransaction(CTxDB& txdb, bool fCheckInputs)
 {
-    CRITICAL_BLOCK(cs_mapTransactions)
+
     {
+        LOCK(cs_mapTransactions);
         // Add previous supporting transactions first
         BOOST_FOREACH(CMerkleTx& tx, vtxPrev)
         {
@@ -1024,8 +1022,8 @@ bool CTransaction::FetchInputs(CTxDB& txdb, const map<uint256, CTxIndex>& mapTes
         if (!fFound || txindex.pos == CDiskTxPos(1,1,1))
         {
             // Get prev tx from single transactions in memory
-            CRITICAL_BLOCK(cs_mapTransactions)
             {
+                LOCK(cs_mapTransactions);
                 if (!mapTransactions.count(prevout.hash))
                     return error("FetchInputs() : %s mapTransactions prev not found %s", GetHash().ToString().substr(0,10).c_str(),  prevout.hash.ToString().substr(0,10).c_str());
                 txPrev = mapTransactions[prevout.hash];
@@ -1190,8 +1188,8 @@ bool CTransaction::ClientConnectInputs()
         return false;
 
     // Take over previous transactions' spent pointers
-    CRITICAL_BLOCK(cs_mapTransactions)
     {
+        LOCK(cs_mapTransactions);
         int64 nValueIn = 0;
         for (int i = 0; i < vin.size(); i++)
         {
@@ -1707,10 +1705,12 @@ bool CBlock::AcceptBlock()
     // Relay inventory, but don't relay old inventory during initial block download
     int nBlockEstimate = Checkpoints::GetTotalBlocksEstimate();
     if (hashBestChain == hash)
-        CRITICAL_BLOCK(cs_vNodes)
-            BOOST_FOREACH(CNode* pnode, vNodes)
-                if (nBestHeight > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : nBlockEstimate))
-                    pnode->PushInventory(CInv(MSG_BLOCK, hash));
+    {
+        LOCK(cs_vNodes);
+        BOOST_FOREACH(CNode* pnode, vNodes)
+            if (nBestHeight > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : nBlockEstimate))
+                pnode->PushInventory(CInv(MSG_BLOCK, hash));
+    }
 
     return true;
 }
@@ -1811,8 +1811,8 @@ bool CheckDiskSpace(uint64 nAdditionalBytes)
         string strMessage = _("Warning: Disk space is low  ");
         strMiscWarning = strMessage;
         printf("*** %s\n", strMessage.c_str());
-        ThreadSafeMessageBox(strMessage, "Bitcoin", wxOK | wxICON_EXCLAMATION);
-        CreateThread(Shutdown, NULL);
+        ThreadSafeMessageBox(strMessage, "Bitcoin", wxOK | wxICON_EXCLAMATION | wxMODAL);
+        QueueShutdown();
         return false;
     }
     return true;
@@ -1822,7 +1822,7 @@ FILE* OpenBlockFile(unsigned int nFile, unsigned int nBlockPos, const char* pszM
 {
     if (nFile == -1)
         return NULL;
-    FILE* file = fopen(strprintf("%s/blk%04d.dat", GetDataDir().c_str(), nFile).c_str(), pszMode);
+    FILE* file = fopen((GetDataDir() / strprintf("blk%04d.dat", nFile)).string().c_str(), pszMode);
     if (!file)
         return NULL;
     if (nBlockPos != 0 && !strchr(pszMode, 'a') && !strchr(pszMode, 'w'))
@@ -2052,8 +2052,8 @@ string GetWarnings(string strFor)
     }
 
     // Alerts
-    CRITICAL_BLOCK(cs_mapAlerts)
     {
+        LOCK(cs_mapAlerts);
         BOOST_FOREACH(PAIRTYPE(const uint256, CAlert)& item, mapAlerts)
         {
             const CAlert& alert = item.second;
@@ -2080,8 +2080,8 @@ bool CAlert::ProcessAlert()
     if (!IsInEffect())
         return false;
 
-    CRITICAL_BLOCK(cs_mapAlerts)
     {
+        LOCK(cs_mapAlerts);
         // Cancel previous alerts
         for (map<uint256, CAlert>::iterator mi = mapAlerts.begin(); mi != mapAlerts.end();)
         {
@@ -2260,9 +2260,11 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
         }
 
         // Relay alerts
-        CRITICAL_BLOCK(cs_mapAlerts)
+        {
+            LOCK(cs_mapAlerts);
             BOOST_FOREACH(PAIRTYPE(const uint256, CAlert)& item, mapAlerts)
                 item.second.RelayTo(pfrom);
+        }
 
         pfrom->fSuccessfullyConnected = true;
 
@@ -2316,8 +2318,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
             if (addr.nTime > nSince && !pfrom->fGetAddr && vAddr.size() <= 10 && addr.IsRoutable())
             {
                 // Relay to a limited number of other nodes
-                CRITICAL_BLOCK(cs_vNodes)
                 {
+                    LOCK(cs_vNodes);
                     // Use deterministic randomness to send to the same nodes for 24 hours
                     // at a time so the setAddrKnowns of the chosen nodes prevent repeats
                     static uint256 hashSalt;
@@ -2428,8 +2430,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
             else if (inv.IsKnownType())
             {
                 // Send stream from relay memory
-                CRITICAL_BLOCK(cs_mapRelay)
                 {
+                    LOCK(cs_mapRelay);
                     map<CInv, CDataStream>::iterator mi = mapRelay.find(inv);
                     if (mi != mapRelay.end())
                         pfrom->PushMessage(inv.GetCommand(), (*mi).second);
@@ -2504,8 +2506,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
         }
 
         vector<CBlock> vHeaders;
-        int nLimit = 2000 + locator.GetDistanceBack();
-        printf("getheaders %d to %s limit %d\n", (pindex ? pindex->nHeight : -1), hashStop.ToString().substr(0,20).c_str(), nLimit);
+        int nLimit = 2000;
+        printf("getheaders %d to %s\n", (pindex ? pindex->nHeight : -1), hashStop.ToString().substr(0,20).c_str());
         for (; pindex; pindex = pindex->pnext)
         {
             vHeaders.push_back(pindex->GetBlockHeader());
@@ -2634,8 +2636,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
         vRecv >> hashReply;
 
         CRequestTracker tracker;
-        CRITICAL_BLOCK(pfrom->cs_mapRequests)
         {
+            LOCK(pfrom->cs_mapRequests);
             map<uint256, CRequestTracker>::iterator mi = pfrom->mapRequests.find(hashReply);
             if (mi != pfrom->mapRequests.end())
             {
@@ -2650,6 +2652,23 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
 
     else if (strCommand == "ping")
     {
+        if (pfrom->nVersion > BIP0031_VERSION)
+        {
+            uint64 nonce = 0;
+            vRecv >> nonce;
+            // Echo the message back with the nonce. This allows for two useful features:
+            //
+            // 1) A remote node can quickly check if the connection is operational
+            // 2) Remote nodes can measure the latency of the network thread. If this node
+            //    is overloaded it won't respond to pings quickly and the remote node can
+            //    avoid sending us more work, like chain download requests.
+            //
+            // The nonce stops the remote getting confused between different pings: without
+            // it, if the remote node sends a ping once per second and this node takes 5
+            // seconds to respond to each, the 5th ping the remote sends would appear to
+            // return very quickly.
+            pfrom->PushMessage("pong", nonce);
+        }
     }
 
 
@@ -2662,9 +2681,11 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
         {
             // Relay
             pfrom->setKnown.insert(alert.GetHash());
-            CRITICAL_BLOCK(cs_vNodes)
+            {
+                LOCK(cs_vNodes);
                 BOOST_FOREACH(CNode* pnode, vNodes)
                     alert.RelayTo(pnode);
+            }
         }
     }
 
@@ -2763,8 +2784,10 @@ bool ProcessMessages(CNode* pfrom)
         bool fRet = false;
         try
         {
-            CRITICAL_BLOCK(cs_main)
+            {
+                LOCK(cs_main);
                 fRet = ProcessMessage(pfrom, strCommand, vMsg);
+            }
             if (fShutdown)
                 return true;
         }
@@ -2802,15 +2825,20 @@ bool ProcessMessages(CNode* pfrom)
 
 bool SendMessages(CNode* pto, bool fSendTrickle)
 {
-    CRITICAL_BLOCK(cs_main)
     {
+        LOCK(cs_main);
         // Don't send anything until we get their version message
         if (pto->nVersion == 0)
             return true;
 
-        // Keep-alive ping
-        if (pto->nLastSend && GetTime() - pto->nLastSend > 30 * 60 && pto->vSend.empty())
-            pto->PushMessage("ping");
+        // Keep-alive ping. We send a nonce of zero because we don't use it anywhere 
+        // right now.
+        if (pto->nLastSend && GetTime() - pto->nLastSend > 30 * 60 && pto->vSend.empty()) {
+            if (pto->nVersion > BIP0031_VERSION)
+                pto->PushMessage("ping", 0);
+            else
+                pto->PushMessage("ping");
+        }
 
         // Resend wallet transactions that haven't gotten in a block yet
         ResendWalletTransactions();
@@ -2819,8 +2847,8 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
         static int64 nLastRebroadcast;
         if (!IsInitialBlockDownload() && (GetTime() - nLastRebroadcast > 24 * 60 * 60))
         {
-            CRITICAL_BLOCK(cs_vNodes)
             {
+                LOCK(cs_vNodes);
                 BOOST_FOREACH(CNode* pnode, vNodes)
                 {
                     // Periodically clear setAddrKnown to allow refresh broadcasts
@@ -2871,8 +2899,8 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
         //
         vector<CInv> vInv;
         vector<CInv> vInvWait;
-        CRITICAL_BLOCK(pto->cs_inventory)
         {
+            LOCK(pto->cs_inventory);
             vInv.reserve(pto->vInventoryToSend.size());
             vInvWait.reserve(pto->vInventoryToSend.size());
             BOOST_FOREACH(const CInv& inv, pto->vInventoryToSend)
@@ -3087,9 +3115,8 @@ CBlock* CreateNewBlock(CReserveKey& reservekey)
 
     // Collect memory pool transactions into the block
     int64 nFees = 0;
-    CRITICAL_BLOCK(cs_main)
-    CRITICAL_BLOCK(cs_mapTransactions)
     {
+        LOCK2(cs_main, cs_mapTransactions);
         CTxDB txdb("r");
 
         // Priority order to process transactions
@@ -3317,8 +3344,8 @@ bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey)
     printf("generated %s\n", FormatMoney(pblock->vtx[0].vout[0].nValue).c_str());
 
     // Found a solution
-    CRITICAL_BLOCK(cs_main)
     {
+        LOCK(cs_main);
         if (pblock->hashPrevBlock != hashBestChain)
             return error("BitcoinMiner : generated block is stale");
 
@@ -3326,8 +3353,10 @@ bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey)
         reservekey.KeepKey();
 
         // Track how many getdata requests this block gets
-        CRITICAL_BLOCK(wallet.cs_wallet)
+        {
+            LOCK(wallet.cs_wallet);
             wallet.mapRequestCount[pblock->GetHash()] = 0;
+        }
 
         // Process this block the same as if we had received it from another node
         if (!ProcessBlock(NULL, pblock))
@@ -3443,15 +3472,13 @@ void static BitcoinMiner(CWallet *pwallet)
             if (GetTimeMillis() - nHPSTimerStart > 4000)
             {
                 static CCriticalSection cs;
-                CRITICAL_BLOCK(cs)
                 {
+                    LOCK(cs);
                     if (GetTimeMillis() - nHPSTimerStart > 4000)
                     {
                         dHashesPerSec = 1000.0 * nHashCounter / (GetTimeMillis() - nHPSTimerStart);
                         nHPSTimerStart = GetTimeMillis();
                         nHashCounter = 0;
-                        string strStatus = strprintf("    %.0f khash/s", dHashesPerSec/1000.0);
-                        UIThreadCall(boost::bind(CalledSetStatusBar, strStatus, 0));
                         static int64 nLogTime;
                         if (GetTime() - nLogTime > 30 * 60)
                         {
@@ -3508,7 +3535,6 @@ void static ThreadBitcoinMiner(void* parg)
         vnThreadsRunning[THREAD_MINER]--;
         PrintException(NULL, "ThreadBitcoinMiner()");
     }
-    UIThreadCall(boost::bind(CalledSetStatusBar, "", 0));
     nHPSTimerStart = 0;
     if (vnThreadsRunning[THREAD_MINER] == 0)
         dHashesPerSec = 0;