Prevent stuck download: correct solution
authorPieter Wuille <pieter.wuille@gmail.com>
Sat, 5 May 2012 02:04:38 +0000 (04:04 +0200)
committerLuke Dashjr <luke-jr+git@utopios.org>
Mon, 7 May 2012 02:45:08 +0000 (02:45 +0000)
Pull request #948 introduced a fix for nodes stuck on a long side branch
of the main chain. The fix was non-functional however, as the additional
getdata request was created in a first step of processing, but dropped
in a second step as it was considered redundant. This commits fixes it
by sending the request directly.

src/main.cpp

index 167e282..a2fc738 100644 (file)
@@ -2177,6 +2177,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
         if (vInv.size() > 50000)
             return error("message inv size() = %d", vInv.size());
 
+        // find last block in inv vector
+        unsigned int nLastBlock = (unsigned int)(-1);
+        for (unsigned int nInv = 0; nInv < vInv.size(); nInv++) {
+            if (vInv[vInv.size() - 1 - nInv].type == MSG_BLOCK)
+                nLastBlock = vInv.size() - 1 - nInv;
+        }
         CTxDB txdb("r");
         for (int nInv = 0; nInv < vInv.size(); nInv++)
         {
@@ -2193,9 +2199,15 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
             // Always request the last block in an inv bundle (even if we already have it), as it is the
             // trigger for the other side to send further invs. If we are stuck on a (very long) side chain,
             // this is necessary to connect earlier received orphan blocks to the chain again.
-            if (!fAlreadyHave || (inv.type == MSG_BLOCK && nInv==vInv.size()-1))
+            if (fAlreadyHave && nInv == nLastBlock) {
+                // bypass mapAskFor, and send request directly; it must go through.
+                std::vector<CInv> vGetData(1,inv);
+                pfrom->PushMessage("getdata", vGetData);
+            }
+
+            if (!fAlreadyHave)
                 pfrom->AskFor(inv);
-            if (inv.type == MSG_BLOCK && mapOrphanBlocks.count(inv.hash))
+            else if (inv.type == MSG_BLOCK && mapOrphanBlocks.count(inv.hash))
                 pfrom->PushGetBlocks(pindexBest, GetOrphanRoot(mapOrphanBlocks[inv.hash]));
 
             // Track requests for our stuff