From 399330d42d39e3d272d8749a11bd2b94f00d979d Mon Sep 17 00:00:00 2001 From: Tim Flynn Date: Thu, 2 Feb 2017 03:50:44 -0500 Subject: [PATCH] Improve governance syncing efficiency with bloom filter (#1299) * Use bloom filter for governance vote syncing Modify masternode-sync to send bloom filters Correctly initialize bloom filter Set fUseFilter argument Increase bloom filter size to account for multiple signals Set bloom filter parameters Use constants for bloom filter parameters Added filter size check Added filter size check in masternode-sync Update bloom filter Changed bloom parameters * Bump protocol version * Update sync time for inv's * Changes based on code review comments * Make bloom filter size network dependent * Fix network dependent filter parameters * Remove unneeded constant definition * Move constant definition * Add blank line --- src/chainparams.cpp | 3 +++ src/consensus/params.h | 3 ++- src/governance-object.h | 3 +++ src/governance.cpp | 46 ++++++++++++++++++++++++++++++++++++----- src/governance.h | 5 +++-- src/masternode-sync.cpp | 18 +++++++++++++--- src/masternode-sync.h | 2 ++ 7 files changed, 69 insertions(+), 11 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index d6fd18bb9..c4364465c 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -84,6 +84,7 @@ public: consensus.nSuperblockStartBlock = 600000; // TODO, the block at which 12.1 goes live. consensus.nSuperblockCycle = 16616; // ~(60*24*30)/2.6, actual number of blocks per month is 200700 / 12 = 16725 consensus.nGovernanceMinQuorum = 10; + consensus.nGovernanceFilterElements = 20000; consensus.nMasternodeMinimumConfirmations = 15; consensus.nMajorityEnforceBlockUpgrade = 750; consensus.nMajorityRejectBlockOutdated = 950; @@ -207,6 +208,7 @@ public: consensus.nSuperblockStartBlock = 61000; // NOTE: Should satisfy nSuperblockStartBlock > nBudgetPeymentsStartBlock consensus.nSuperblockCycle = 24; // Superblocks can be issued hourly on testnet consensus.nGovernanceMinQuorum = 1; + consensus.nGovernanceFilterElements = 500; consensus.nMasternodeMinimumConfirmations = 1; consensus.nMajorityEnforceBlockUpgrade = 51; consensus.nMajorityRejectBlockOutdated = 75; @@ -313,6 +315,7 @@ public: consensus.nSuperblockStartBlock = 1500; consensus.nSuperblockCycle = 10; consensus.nGovernanceMinQuorum = 1; + consensus.nGovernanceFilterElements = 100; consensus.nMasternodeMinimumConfirmations = 1; consensus.nMajorityEnforceBlockUpgrade = 750; consensus.nMajorityRejectBlockOutdated = 950; diff --git a/src/consensus/params.h b/src/consensus/params.h index 23fa8f301..504577f40 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -47,7 +47,8 @@ struct Params { int nBudgetProposalEstablishingTime; // in seconds int nSuperblockStartBlock; int nSuperblockCycle; // in blocks - int nGovernanceMinQuorum; // Min absolute vote count to trigger an action + int nGovernanceMinQuorum; // Min absolute vote count to trigger an action + int nGovernanceFilterElements; int nMasternodeMinimumConfirmations; /** Used to check majorities for block version upgrade */ int nMajorityEnforceBlockUpgrade; diff --git a/src/governance-object.h b/src/governance-object.h index e37fbc770..b8e8b3144 100644 --- a/src/governance-object.h +++ b/src/governance-object.h @@ -25,6 +25,9 @@ class CGovernanceVote; static const int MAX_GOVERNANCE_OBJECT_DATA_SIZE = 16 * 1024; static const int MIN_GOVERNANCE_PEER_PROTO_VERSION = 70204; +static const int GOVERNANCE_FILTER_PROTO_VERSION = 70206; + +static const double GOVERNANCE_FILTER_FP_RATE = 0.001; static const int GOVERNANCE_OBJECT_UNKNOWN = 0; static const int GOVERNANCE_OBJECT_PROPOSAL = 1; diff --git a/src/governance.cpp b/src/governance.cpp index 10d6bf1c1..8ef883d70 100644 --- a/src/governance.cpp +++ b/src/governance.cpp @@ -113,8 +113,18 @@ void CGovernanceManager::ProcessMessage(CNode* pfrom, std::string& strCommand, C if (!masternodeSync.IsSynced()) return; uint256 nProp; + CBloomFilter filter; + vRecv >> nProp; + if(pfrom->nVersion >= GOVERNANCE_FILTER_PROTO_VERSION) { + vRecv >> filter; + filter.UpdateEmptyFull(); + } + else { + filter.clear(); + } + if(nProp == uint256()) { if(netfulfilledman.HasFulfilledRequest(pfrom->addr, NetMsgType::MNGOVERNANCESYNC)) { // Asking for the whole list multiple times in a short period of time is no good @@ -125,7 +135,7 @@ void CGovernanceManager::ProcessMessage(CNode* pfrom, std::string& strCommand, C netfulfilledman.AddFulfilledRequest(pfrom->addr, NetMsgType::MNGOVERNANCESYNC); } - Sync(pfrom, nProp); + Sync(pfrom, nProp, filter); LogPrint("gobject", "MNGOVERNANCESYNC -- syncing governance objects to our peer at %s\n", pfrom->addr.ToString()); } @@ -640,11 +650,14 @@ bool CGovernanceManager::ConfirmInventoryRequest(const CInv& inv) LogPrint("gobject", "CGovernanceManager::ConfirmInventoryRequest added inv to requested set\n"); } + // Keep sync alive + masternodeSync.AddedGovernanceItem(); + LogPrint("gobject", "CGovernanceManager::ConfirmInventoryRequest reached end, returning true\n"); return true; } -void CGovernanceManager::Sync(CNode* pfrom, uint256 nProp) +void CGovernanceManager::Sync(CNode* pfrom, const uint256& nProp, const CBloomFilter& filter) { /* @@ -709,6 +722,9 @@ void CGovernanceManager::Sync(CNode* pfrom, uint256 nProp) if(!vecVotes[i].IsValid(true)) { continue; } + if(filter.contains(vecVotes[i].GetHash())) { + continue; + } pfrom->PushInventory(CInv(MSG_GOVERNANCE_OBJECT_VOTE, vecVotes[i].GetHash())); ++nVoteCount; } @@ -927,13 +943,33 @@ void CGovernanceManager::CheckMasternodeOrphanObjects() fRateChecksEnabled = true; } -void CGovernanceManager::RequestGovernanceObject(CNode* pfrom, const uint256& nHash) +void CGovernanceManager::RequestGovernanceObject(CNode* pfrom, const uint256& nHash, bool fUseFilter) { if(!pfrom) { return; } - pfrom->PushMessage(NetMsgType::MNGOVERNANCESYNC, nHash); + if(pfrom->nVersion < GOVERNANCE_FILTER_PROTO_VERSION) { + pfrom->PushMessage(NetMsgType::MNGOVERNANCESYNC, nHash); + return; + } + + CBloomFilter filter; + filter.clear(); + + if(fUseFilter) { + CGovernanceObject* pObj = FindGovernanceObject(nHash); + + if(pObj) { + filter = CBloomFilter(Params().GetConsensus().nGovernanceFilterElements, GOVERNANCE_FILTER_FP_RATE, GetRandInt(999999), BLOOM_UPDATE_ALL); + std::vector vecVotes = pObj->GetVoteFile().GetVotes(); + for(size_t i = 0; i < vecVotes.size(); ++i) { + filter.insert(vecVotes[i].GetHash()); + } + } + } + + pfrom->PushMessage(NetMsgType::MNGOVERNANCESYNC, nHash, filter); } void CGovernanceManager::RequestGovernanceObjectVotes(CNode* pnode) @@ -979,7 +1015,7 @@ void CGovernanceManager::RequestGovernanceObjectVotes(const std::vector& vpGovObjsTmp.erase(vpGovObjsTmp.begin() + r); } LogPrintf("CGovernanceManager::RequestGovernanceObjectVotes -- Requesting votes for %s, peer=%d\n", nHashGovobj.ToString(), pnode->id); - RequestGovernanceObject(pnode, nHashGovobj); + RequestGovernanceObject(pnode, nHashGovobj, true); mapAskedRecently[nHashGovobj] = nNow + mapObjects.size() * 60; // ask again after full cycle } } diff --git a/src/governance.h b/src/governance.h index 67318491b..99f84a4b5 100644 --- a/src/governance.h +++ b/src/governance.h @@ -7,6 +7,7 @@ //#define ENABLE_DASH_DEBUG +#include "bloom.h" #include "cachemap.h" #include "cachemultimap.h" #include "chain.h" @@ -271,7 +272,7 @@ public: */ bool ConfirmInventoryRequest(const CInv& inv); - void Sync(CNode* node, uint256 nProp); + void Sync(CNode* node, const uint256& nProp, const CBloomFilter& filter); void ProcessMessage(CNode* pfrom, std::string& strCommand, CDataStream& vRecv); @@ -379,7 +380,7 @@ public: void RequestGovernanceObjectVotes(const std::vector& vNodesCopy); private: - void RequestGovernanceObject(CNode* pfrom, const uint256& nHash); + void RequestGovernanceObject(CNode* pfrom, const uint256& nHash, bool fUseFilter = false); void AddInvalidVote(const CGovernanceVote& vote) { diff --git a/src/masternode-sync.cpp b/src/masternode-sync.cpp index 0f982fc8e..c90067344 100644 --- a/src/masternode-sync.cpp +++ b/src/masternode-sync.cpp @@ -344,8 +344,7 @@ void CMasternodeSync::ProcessTick() } else if(nRequestedMasternodeAttempt < 6) { int nMnCount = mnodeman.CountMasternodes(); pnode->PushMessage(NetMsgType::MASTERNODEPAYMENTSYNC, nMnCount); //sync payment votes - uint256 n = uint256(); - pnode->PushMessage(NetMsgType::MNGOVERNANCESYNC, n); //sync masternode votes + SendGovernanceSyncRequest(pnode); } else { nRequestedMasternodeAssets = MASTERNODE_SYNC_FINISHED; } @@ -497,7 +496,7 @@ void CMasternodeSync::ProcessTick() if (pnode->nVersion < MIN_GOVERNANCE_PEER_PROTO_VERSION) continue; nRequestedMasternodeAttempt++; - pnode->PushMessage(NetMsgType::MNGOVERNANCESYNC, uint256()); //sync masternode votes + SendGovernanceSyncRequest(pnode); ReleaseNodes(vNodesCopy); return; //this will cause each peer to get one request each six seconds for the various assets we need @@ -508,6 +507,19 @@ void CMasternodeSync::ProcessTick() ReleaseNodes(vNodesCopy); } +void CMasternodeSync::SendGovernanceSyncRequest(CNode* pnode) +{ + if(pnode->nVersion >= GOVERNANCE_FILTER_PROTO_VERSION) { + CBloomFilter filter; + filter.clear(); + + pnode->PushMessage(NetMsgType::MNGOVERNANCESYNC, uint256(), filter); + } + else { + pnode->PushMessage(NetMsgType::MNGOVERNANCESYNC, uint256()); + } +} + void CMasternodeSync::UpdatedBlockTip(const CBlockIndex *pindex) { pCurrentBlockIndex = pindex; diff --git a/src/masternode-sync.h b/src/masternode-sync.h index 447e230e3..7f4666dac 100644 --- a/src/masternode-sync.h +++ b/src/masternode-sync.h @@ -67,6 +67,8 @@ public: void AddedPaymentVote() { nTimeLastPaymentVote = GetTime(); } void AddedGovernanceItem() { nTimeLastGovernanceItem = GetTime(); }; + void SendGovernanceSyncRequest(CNode* pnode); + bool IsFailed() { return nRequestedMasternodeAssets == MASTERNODE_SYNC_FAILED; } bool IsBlockchainSynced(bool fBlockAccepted = false); bool IsMasternodeListSynced() { return nRequestedMasternodeAssets > MASTERNODE_SYNC_LIST; }