From 86525601d5915f380976c9d2e686ad7f66db991f Mon Sep 17 00:00:00 2001 From: Tim Flynn Date: Wed, 5 Apr 2017 12:30:08 -0400 Subject: [PATCH] V0.12.1.x multiple wd rate check (#1426) * Modify MasternodeRateCheck to support updating buffers only on failure * Update rate check buffer only when fAddToSeen is true --- src/governance.cpp | 66 +++++++++++++++++++++++++------------------ src/governance.h | 10 +++++-- src/rpcgovernance.cpp | 2 +- 3 files changed, 48 insertions(+), 30 deletions(-) diff --git a/src/governance.cpp b/src/governance.cpp index 772cc58385..ace46ef170 100644 --- a/src/governance.cpp +++ b/src/governance.cpp @@ -186,7 +186,7 @@ void CGovernanceManager::ProcessMessage(CNode* pfrom, std::string& strCommand, C } bool fRateCheckBypassed = false; - if(!MasternodeRateCheck(govobj, true, false, fRateCheckBypassed)) { + if(!MasternodeRateCheck(govobj, UPDATE_FAIL_ONLY, false, fRateCheckBypassed)) { LogPrintf("MNGOVERNANCEOBJECT -- masternode rate check failed - %s - (current block height %d) \n", strHash, nCachedBlockHeight); return; } @@ -209,7 +209,7 @@ void CGovernanceManager::ProcessMessage(CNode* pfrom, std::string& strCommand, C } if(fRateCheckBypassed) { - if(!MasternodeRateCheck(govobj, true, true, fRateCheckBypassed)) { + if(!MasternodeRateCheck(govobj, UPDATE_FAIL_ONLY, true, fRateCheckBypassed)) { LogPrintf("MNGOVERNANCEOBJECT -- masternode rate check failed (after signature verification) - %s - (current block height %d) \n", strHash, nCachedBlockHeight); return; } @@ -229,6 +229,8 @@ void CGovernanceManager::ProcessMessage(CNode* pfrom, std::string& strCommand, C if(fAddToSeen) { // UPDATE THAT WE'VE SEEN THIS OBJECT mapSeenGovernanceObjects.insert(std::make_pair(nHash, SEEN_OBJECT_IS_VALID)); + // Update the rate buffer + MasternodeRateCheck(govobj, UPDATE_TRUE, true, fRateCheckBypassed); } masternodeSync.AddedGovernanceItem(); @@ -814,13 +816,13 @@ void CGovernanceManager::Sync(CNode* pfrom, const uint256& nProp, const CBloomFi LogPrintf("CGovernanceManager::Sync -- sent %d objects and %d votes to peer=%d\n", nObjCount, nVoteCount, pfrom->id); } -bool CGovernanceManager::MasternodeRateCheck(const CGovernanceObject& govobj, bool fUpdateLast) +bool CGovernanceManager::MasternodeRateCheck(const CGovernanceObject& govobj, update_mode_enum_t eUpdateLast) { bool fRateCheckBypassed = false; - return MasternodeRateCheck(govobj, fUpdateLast, true, fRateCheckBypassed); + return MasternodeRateCheck(govobj, eUpdateLast, true, fRateCheckBypassed); } -bool CGovernanceManager::MasternodeRateCheck(const CGovernanceObject& govobj, bool fUpdateLast, bool fForce, bool& fRateCheckBypassed) +bool CGovernanceManager::MasternodeRateCheck(const CGovernanceObject& govobj, update_mode_enum_t eUpdateLast, bool fForce, bool& fRateCheckBypassed) { LOCK(cs); @@ -848,7 +850,7 @@ bool CGovernanceManager::MasternodeRateCheck(const CGovernanceObject& govobj, bo txout_m_it it = mapLastMasternodeObject.find(vin.prevout); if(it == mapLastMasternodeObject.end()) { - if(fUpdateLast) { + if(eUpdateLast == UPDATE_TRUE) { it = mapLastMasternodeObject.insert(txout_m_t::value_type(vin.prevout, last_object_rec(true))).first; switch(nObjectType) { case GOVERNANCE_OBJECT_TRIGGER: @@ -886,44 +888,54 @@ bool CGovernanceManager::MasternodeRateCheck(const CGovernanceObject& govobj, bo double dMaxRate = 1.1 / nSuperblockCycleSeconds; double dRate = 0.0; CRateCheckBuffer buffer; + CRateCheckBuffer* pBuffer = NULL; switch(nObjectType) { case GOVERNANCE_OBJECT_TRIGGER: // Allow 1 trigger per mn per cycle, with a small fudge factor + pBuffer = &it->second.triggerBuffer; dMaxRate = 2 * 1.1 / double(nSuperblockCycleSeconds); - buffer = it->second.triggerBuffer; - buffer.AddTimestamp(nTimestamp); - dRate = buffer.GetRate(); - if(fUpdateLast) { - it->second.triggerBuffer.AddTimestamp(nTimestamp); - } break; case GOVERNANCE_OBJECT_WATCHDOG: + pBuffer = &it->second.watchdogBuffer; dMaxRate = 2 * 1.1 / 3600.; - buffer = it->second.watchdogBuffer; - buffer.AddTimestamp(nTimestamp); - dRate = buffer.GetRate(); - if(fUpdateLast) { - it->second.watchdogBuffer.AddTimestamp(nTimestamp); - } break; default: break; } - if(dRate < dMaxRate) { - if(fUpdateLast) { - it->second.fStatusOK = true; + if(!pBuffer) { + LogPrintf("CGovernanceManager::MasternodeRateCheck -- Internal Error returning false, NULL ptr found for object %s masternode vin = %s, timestamp = %d, current time = %d\n", + strHash, vin.prevout.ToStringShort(), nTimestamp, nNow); + return false; + } + + buffer = *pBuffer; + buffer.AddTimestamp(nTimestamp); + dRate = buffer.GetRate(); + + bool fRateOK = ( dRate < dMaxRate ); + + switch(eUpdateLast) { + case UPDATE_TRUE: + pBuffer->AddTimestamp(nTimestamp); + it->second.fStatusOK = fRateOK; + break; + case UPDATE_FAIL_ONLY: + if(!fRateOK) { + pBuffer->AddTimestamp(nTimestamp); + it->second.fStatusOK = false; } + default: + return true; + } + + if(fRateOK) { return true; } else { - if(fUpdateLast) { - it->second.fStatusOK = false; - } + LogPrintf("CGovernanceManager::MasternodeRateCheck -- Rate too high: object hash = %s, masternode vin = %s, object timestamp = %d, rate = %f, max rate = %f\n", + strHash, vin.prevout.ToStringShort(), nTimestamp, dRate, dMaxRate); } - - LogPrintf("CGovernanceManager::MasternodeRateCheck -- Rate too high: object hash = %s, masternode vin = %s, object timestamp = %d, rate = %f, max rate = %f\n", - strHash, vin.prevout.ToStringShort(), nTimestamp, dRate, dMaxRate); return false; } diff --git a/src/governance.h b/src/governance.h index bca0c39643..da2a78b0c2 100644 --- a/src/governance.h +++ b/src/governance.h @@ -134,6 +134,12 @@ public: } }; +enum update_mode_enum_t { + UPDATE_FALSE, + UPDATE_TRUE, + UPDATE_FAIL_ONLY +}; + // // Governance Manager : Contains all proposals for the budget // @@ -362,9 +368,9 @@ public: void AddSeenVote(uint256 nHash, int status); - bool MasternodeRateCheck(const CGovernanceObject& govobj, bool fUpdateLast = false); + bool MasternodeRateCheck(const CGovernanceObject& govobj, update_mode_enum_t eUpdateLast = UPDATE_FALSE); - bool MasternodeRateCheck(const CGovernanceObject& govobj, bool fUpdateLast, bool fForce, bool& fRateCheckBypassed); + bool MasternodeRateCheck(const CGovernanceObject& govobj, update_mode_enum_t eUpdateLast, bool fForce, bool& fRateCheckBypassed); bool ProcessVoteAndRelay(const CGovernanceVote& vote, CGovernanceException& exception) { bool fOK = ProcessVote(NULL, vote, exception); diff --git a/src/rpcgovernance.cpp b/src/rpcgovernance.cpp index 4e4f7c13c7..4bf99751cb 100644 --- a/src/rpcgovernance.cpp +++ b/src/rpcgovernance.cpp @@ -214,7 +214,7 @@ UniValue gobject(const UniValue& params, bool fHelp) throw JSONRPCError(RPC_INVALID_PARAMETER, "Object creation rate limit exceeded"); } // This check should always pass, update buffer - if(!governance.MasternodeRateCheck(govobj, true)) { + if(!governance.MasternodeRateCheck(govobj, UPDATE_TRUE)) { LogPrintf("gobject(submit) -- Object submission rejected because of rate check failure (buffer updated) - hash = %s\n", strHash); throw JSONRPCError(RPC_INVALID_PARAMETER, "Object creation rate limit exceeded"); }