changeset 23714:5fb3536615a8

Created new NetMessage type GET_XTHIN a GET_XTHIN message consists of an inv for an XTHINBLOCK with a seeded bloom filter appended to it. This prevents the bloom filter from being processed at the other end after the thinblock request, which can happen when the deque's are backed up under heavy load.
author Peter Tschipper <peter.tschipper@gmailcom>
date Mon, 29 Feb 2016 13:15:11 -0800
parents bac3c81409ed
children 638b30bb60c8
files src/main.cpp src/protocol.cpp src/protocol.h src/unlimited.cpp src/unlimited.h src/version.h
diffstat 6 files changed, 85 insertions(+), 42 deletions(-) [+]
line wrap: on
line diff
--- a/src/main.cpp	Thu Feb 25 14:44:27 2016 -0500
+++ b/src/main.cpp	Mon Feb 29 13:15:11 2016 -0800
@@ -4203,13 +4203,8 @@
                         pfrom->PushMessage(NetMsgType::BLOCK, block);
 
                     // BUIP010 Xtreme Thinblocks: begin section
-                    else if (inv.type == MSG_THINBLOCK || inv.type == MSG_XTHINBLOCK)
-                      {                 
+                    else if (inv.type == MSG_THINBLOCK || inv.type == MSG_XTHINBLOCK)               
                         SendXThinBlock(block, pfrom, inv);
-                        //LOCK(pfrom->cs_filter);  // PROPOSED: clean up this filter; it will no longer be relevant to the next block
-                        //if (pfrom->pfilter) delete pfrom->pfilter;
-                        //pfrom->pfilter=NULL;
-                      }
                     // BUIP010 Xtreme Thinblocks: end section
 
                     else // MSG_FILTERED_BLOCK)
@@ -4612,14 +4607,18 @@
                         nodestate->nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
                         // BUIP010 Xtreme Thinblocks: begin section
                         CInv inv2(inv);
+                        CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
+                        CBloomFilter filterMemPool;
                         if (IsThinBlocksEnabled() && IsChainNearlySyncd()) {
                             if (HaveConnectThinblockNodes() || (HaveThinblockNodes() && CheckThinblockTimer(inv.hash))) {
                                 // Must download a block from a ThinBlock peer
                                 if (pfrom->mapThinBlocksInFlight.size() < 1 && pfrom->nVersion >= THINBLOCKS_VERSION) { // We can only send one thinblock per peer at a time
                                     pfrom->mapThinBlocksInFlight[inv2.hash] = GetTime();
                                     inv2.type = MSG_XTHINBLOCK;
-                                    vToFetch.push_back(inv2);
-                                    SendSeededBloomFilter(pfrom);
+                                    BuildSeededBloomFilter(filterMemPool);
+                                    ss << inv2;
+                                    ss << filterMemPool;
+                                    pfrom->PushMessage(NetMsgType::GET_XTHIN, ss);
                                     MarkBlockAsInFlight(pfrom->GetId(), inv.hash, chainparams.GetConsensus());
                                     LogPrint("thin", "Requesting Thinblock %s from peer %s (%d)\n", inv2.hash.ToString(), pfrom->addrName.c_str(),pfrom->id);
                                 }
@@ -4629,13 +4628,17 @@
                                 if (pfrom->mapThinBlocksInFlight.size() < 1 && pfrom->nVersion >= THINBLOCKS_VERSION) { // We can only send one thinblock per peer at a time
                                     pfrom->mapThinBlocksInFlight[inv2.hash] = GetTime();
                                     inv2.type = MSG_XTHINBLOCK;
-                                    SendSeededBloomFilter(pfrom);
+                                    BuildSeededBloomFilter(filterMemPool);
+                                    ss << inv2;
+                                    ss << filterMemPool;
+                                    pfrom->PushMessage(NetMsgType::GET_XTHIN, ss);
                                     LogPrint("thin", "Requesting Thinblock %s from peer %s (%d)\n", inv2.hash.ToString(), pfrom->addrName.c_str(),pfrom->id);
                                 }
-                                else
+                                else {
                                     LogPrint("thin", "Requesting Regular Block %s from peer %s (%d)\n", inv2.hash.ToString(), pfrom->addrName.c_str(),pfrom->id);
+                                    vToFetch.push_back(inv2);
+                                }
                                 MarkBlockAsInFlight(pfrom->GetId(), inv.hash, chainparams.GetConsensus());
-                                vToFetch.push_back(inv2);
                             }
                         }
                         else {
@@ -5026,6 +5029,16 @@
     }
 
     // BUIP010 Xtreme Thinblocks: begin section
+    else if (strCommand == NetMsgType::GET_XTHIN && !fImporting && !fReindex) // Ignore blocks received while importing
+    {
+        CBloomFilter filterMemPool;
+        CInv inv;
+        vRecv >> inv >> filterMemPool;
+
+        LoadFilter(pfrom, &filterMemPool);
+        pfrom->vRecvGetData.insert(pfrom->vRecvGetData.end(), inv);
+        ProcessGetData(pfrom, chainparams.GetConsensus());
+    }
     else if (strCommand == NetMsgType::XTHINBLOCK  && !fImporting && !fReindex) // Ignore blocks received while importing
     {
         CXThinBlock thinBlock;
@@ -5487,18 +5500,24 @@
     {
         CBloomFilter filter;
         vRecv >> filter;
-
-        if (!filter.IsWithinSizeConstraints())
-            // There is no excuse for sending a too-large filter
-            Misbehaving(pfrom->GetId(), 100);
-        else
-        {
-            LOCK(pfrom->cs_filter);
-            delete pfrom->pfilter;
-            pfrom->pfilter = new CBloomFilter(filter);
-            pfrom->pfilter->UpdateEmptyFull();
-        }
-        pfrom->fRelayTxes = true;
+    
+        // BUIP010 Xtreme Thinblocks - begin section
+        LoadFilter(pfrom, &filter);
+
+        //if (!filter.IsWithinSizeConstraints())
+        //    // There is no excuse for sending a too-large filter
+        //    Misbehaving(pfrom->GetId(), 100);
+        //else
+        //{
+        //    LOCK(pfrom->cs_filter);
+        //    delete pfrom->pfilter;
+        //    pfrom->pfilter = new CBloomFilter(filter);
+        //    pfrom->pfilter->UpdateEmptyFull();
+        //}
+        //pfrom->fRelayTxes = true;
+
+        // BUIP010 Xtreme Thinblocks - end section
+
     }
 
 
@@ -6006,12 +6025,16 @@
             BOOST_FOREACH(CBlockIndex *pindex, vToDownload) {
                 // BUIP010 Xtreme Thinblocks: begin section
                 if (IsThinBlocksEnabled() && IsChainNearlySyncd()) {
+                    CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
+                    CBloomFilter filterMemPool;
                     if (HaveConnectThinblockNodes() || (HaveThinblockNodes() && CheckThinblockTimer(pindex->GetBlockHash()))) {
                         // Must download a block from a ThinBlock peer
                         if (pto->mapThinBlocksInFlight.size() < 1 && pto->nVersion >= THINBLOCKS_VERSION) { // We can only send one thinblock per peer at a time
                             pto->mapThinBlocksInFlight[pindex->GetBlockHash()] = GetTime();
-                            vGetData.push_back(CInv(MSG_XTHINBLOCK, pindex->GetBlockHash())); 
-                            SendSeededBloomFilter(pto);
+                            BuildSeededBloomFilter(filterMemPool);
+                            ss << CInv(MSG_XTHINBLOCK, pindex->GetBlockHash());
+                            ss << filterMemPool;
+                            pto->PushMessage(NetMsgType::GET_XTHIN, ss);
                             MarkBlockAsInFlight(pto->GetId(), pindex->GetBlockHash(), consensusParams, pindex);
                             LogPrint("thin", "Requesting thinblock %s (%d) from peer %s (%d)\n", pindex->GetBlockHash().ToString(),
                                      pindex->nHeight, pto->addrName.c_str(), pto->id);
@@ -6021,8 +6044,10 @@
                         // Try to download a thinblock if possible otherwise just download a regular block
                         if (pto->mapThinBlocksInFlight.size() < 1 && pto->nVersion >= THINBLOCKS_VERSION) { // We can only send one thinblock per peer at a time
                             pto->mapThinBlocksInFlight[pindex->GetBlockHash()] = GetTime();
-                            vGetData.push_back(CInv(MSG_XTHINBLOCK, pindex->GetBlockHash())); 
-                            SendSeededBloomFilter(pto);
+                            BuildSeededBloomFilter(filterMemPool);
+                            ss << CInv(MSG_XTHINBLOCK, pindex->GetBlockHash());
+                            ss << filterMemPool;
+                            pto->PushMessage(NetMsgType::GET_XTHIN, ss);
                             LogPrint("thin", "Requesting Thinblock %s (%d) from peer %s (%d)\n", pindex->GetBlockHash().ToString(),
                                      pindex->nHeight, pto->addrName.c_str(), pto->id);
                         }
--- a/src/protocol.cpp	Thu Feb 25 14:44:27 2016 -0500
+++ b/src/protocol.cpp	Mon Feb 29 13:15:11 2016 -0800
@@ -40,6 +40,7 @@
 const char *XTHINBLOCK="xthinblock";
 const char *XBLOCKTX="xblocktx";
 const char *GET_XBLOCKTX="get_xblocktx";
+const char *GET_XTHIN="get_xthin";
 // BUIP010 Xtreme Thinblocks - end section
 };
 
@@ -88,6 +89,7 @@
     NetMsgType::XTHINBLOCK,
     NetMsgType::XBLOCKTX,
     NetMsgType::GET_XBLOCKTX,
+    NetMsgType::GET_XTHIN,
     // BUIP010 Xtreme Thinbocks - end section
 };
 const static std::vector<std::string> allNetMessageTypesVec(allNetMessageTypes, allNetMessageTypes+ARRAYLEN(allNetMessageTypes));
--- a/src/protocol.h	Thu Feb 25 14:44:27 2016 -0500
+++ b/src/protocol.h	Mon Feb 29 13:15:11 2016 -0800
@@ -154,6 +154,11 @@
  */
 extern const char *GET_XBLOCKTX;
 /**
+ * BUIP010 Xtreme Thinblocks: The get_xthin message transmits a single serialized get_xthin.
+ */
+extern const char *GET_XTHIN;
+
+/**
  * The getaddr message requests an addr message from the receiving node,
  * preferably one with lots of IP addresses of other receiving nodes.
  * @see https://bitcoin.org/en/developer-reference#getaddr
--- a/src/unlimited.cpp	Thu Feb 25 14:44:27 2016 -0500
+++ b/src/unlimited.cpp	Mon Feb 29 13:15:11 2016 -0800
@@ -519,30 +519,40 @@
     return true;
 }
 
-void SendSeededBloomFilter(CNode *pto)
+void BuildSeededBloomFilter(CBloomFilter& filterMemPool)
 {
     LogPrint("thin", "Starting creation of bloom filter\n");
     seed_insecure_rand();
-    CBloomFilter memPoolFilter;
     double nBloomPoolSize = (double)mempool.mapTx.size();
     if (nBloomPoolSize > MAX_BLOOM_FILTER_SIZE / 1.8)
         nBloomPoolSize = MAX_BLOOM_FILTER_SIZE / 1.8;
     double nBloomDecay = 1.5 - (nBloomPoolSize * 1.8 / MAX_BLOOM_FILTER_SIZE);  // We should never go below 0.5 as we will start seeing re-requests for tx's
     int nElements = std::max((int)((int)mempool.mapTx.size() * nBloomDecay), 1); // Must make sure nElements is greater than zero or will assert
-                                                                // TODO: we should probably rather fix the bloom.cpp constructor
     double nFPRate = .001 + (((double)nElements * 1.8 / MAX_BLOOM_FILTER_SIZE) * .004); // The false positive rate in percent decays as the mempool grows
-    memPoolFilter = CBloomFilter(nElements, nFPRate, insecure_rand(), BLOOM_UPDATE_ALL);
+    filterMemPool = CBloomFilter(nElements, nFPRate, insecure_rand(), BLOOM_UPDATE_ALL);
     LogPrint("thin", "Bloom multiplier: %f FPrate: %f Num elements in bloom filter: %d num mempool entries: %d\n", nBloomDecay, nFPRate, nElements, (int)mempool.mapTx.size());
 
     // Seed the filter with the transactions in the memory pool
     LOCK(cs_main);
-    std::vector<uint256> memPoolHashes;
-    mempool.queryHashes(memPoolHashes);
-    for (uint64_t i = 0; i < memPoolHashes.size(); i++)
-         memPoolFilter.insert(memPoolHashes[i]);
+    std::vector<uint256> vMemPoolHashes;
+    mempool.queryHashes(vMemPoolHashes);
+    for (uint64_t i = 0; i < vMemPoolHashes.size(); i++)
+         filterMemPool.insert(vMemPoolHashes[i]);
+}
 
-    LogPrint("thin", "Sending bloom filter: %d bytes peer=%d\n",::GetSerializeSize(memPoolFilter, SER_NETWORK, PROTOCOL_VERSION), pto->id);
-    pto->PushMessage(NetMsgType::FILTERLOAD, memPoolFilter);
+void LoadFilter(CNode *pfrom, CBloomFilter *filter)
+{
+    if (!filter->IsWithinSizeConstraints())
+        // There is no excuse for sending a too-large filter
+        Misbehaving(pfrom->GetId(), 100);
+    else
+    {
+        LOCK(pfrom->cs_filter);
+        delete pfrom->pfilter;
+        pfrom->pfilter = new CBloomFilter(*filter);
+        pfrom->pfilter->UpdateEmptyFull();
+    }
+    pfrom->fRelayTxes = true;
 }
 
 void HandleBlockMessage(CNode *pfrom, const string &strCommand, CBlock &block, const CInv &inv)
@@ -566,7 +576,7 @@
             Misbehaving(pfrom->GetId(), nDoS);
         }
     }
-    LogPrint("thin", "Processed thinblock %s in %.2f seconds\n", inv.hash.ToString(), (double)(GetTimeMicros() - startTime) / 1000000.0);
+    LogPrint("thin", "Processed Block %s in %.2f seconds\n", inv.hash.ToString(), (double)(GetTimeMicros() - startTime) / 1000000.0);
     
     // When we request a thinblock we may get back a regular block if it is smaller than a thinblock
     // Therefore we have to remove the thinblock in flight if it exists and we also need to check that 
--- a/src/unlimited.h	Thu Feb 25 14:44:27 2016 -0500
+++ b/src/unlimited.h	Mon Feb 29 13:15:11 2016 -0800
@@ -71,7 +71,8 @@
 extern void ClearThinblockTimer(uint256 hash);
 extern bool IsThinBlocksEnabled();
 extern bool IsChainNearlySyncd();
-extern void SendSeededBloomFilter(CNode *pto);
+extern void BuildSeededBloomFilter(CBloomFilter& memPoolFilter);
+extern void LoadFilter(CNode *pfrom, CBloomFilter *filter);
 extern void HandleBlockMessage(CNode *pfrom, const std::string &strCommand, CBlock &block, const CInv &inv);
 extern void ConnectToThinBlockNodes();
 extern void CheckNodeSupportForThinBlocks();
--- a/src/version.h	Thu Feb 25 14:44:27 2016 -0500
+++ b/src/version.h	Mon Feb 29 13:15:11 2016 -0800
@@ -9,7 +9,7 @@
  * network protocol versioning
  */
 
-static const int PROTOCOL_VERSION = 80000;
+static const int PROTOCOL_VERSION = 80001;
 
 //! initial proto version, to be increased after version/verack negotiation
 static const int INIT_PROTO_VERSION = 209;
@@ -40,7 +40,7 @@
 //! "sendheaders" command and announcing blocks with headers starts with this version
 static const int SENDHEADERS_VERSION = 70012;
 
-//! Thinblocks enabled in this version
-static const int THINBLOCKS_VERSION = 80000;
+//! Xtreme Thinblocks enabled in this version
+static const int THINBLOCKS_VERSION = 80001;
 
 #endif // BITCOIN_VERSION_H