diff --git a/src/governance.cpp b/src/governance.cpp index cef9ab4c42..90967f7cfc 100644 --- a/src/governance.cpp +++ b/src/governance.cpp @@ -146,7 +146,6 @@ void CGovernanceManager::ProcessMessage(CNode* pfrom, std::string& strCommand, C // A NEW GOVERNANCE OBJECT HAS ARRIVED else if (strCommand == NetMsgType::MNGOVERNANCEOBJECT) - { // MAKE SURE WE HAVE A VALID REFERENCE TO THE TIP BEFORE CONTINUING @@ -185,7 +184,7 @@ void CGovernanceManager::ProcessMessage(CNode* pfrom, std::string& strCommand, C } bool fRateCheckBypassed = false; - if(!MasternodeRateCheck(govobj, UPDATE_FAIL_ONLY, false, fRateCheckBypassed)) { + if(!MasternodeRateCheck(govobj, true, false, fRateCheckBypassed)) { LogPrintf("MNGOVERNANCEOBJECT -- masternode rate check failed - %s - (current block height %d) \n", strHash, nCachedBlockHeight); return; } @@ -198,7 +197,7 @@ void CGovernanceManager::ProcessMessage(CNode* pfrom, std::string& strCommand, C bool fIsValid = govobj.IsValidLocally(strError, fMasternodeMissing, fMissingConfirmations, true); if(fRateCheckBypassed && (fIsValid || fMasternodeMissing)) { - if(!MasternodeRateCheck(govobj, UPDATE_FAIL_ONLY)) { + if(!MasternodeRateCheck(govobj, true)) { LogPrintf("MNGOVERNANCEOBJECT -- masternode rate check failed (after signature verification) - %s - (current block height %d) \n", strHash, nCachedBlockHeight); return; } @@ -382,7 +381,7 @@ void CGovernanceManager::AddGovernanceObject(CGovernanceObject& govobj, CNode* p govobj.Relay(); // Update the rate buffer - MasternodeRateCheck(govobj, UPDATE_TRUE); + MasternodeRateUpdate(govobj); masternodeSync.BumpAssetLastTime("CGovernanceManager::AddGovernanceObject"); @@ -558,8 +557,9 @@ void CGovernanceManager::UpdateCachesAndClean() // forget about expired deleted objects hash_time_m_it s_it = mapErasedGovernanceObjects.begin(); + nNow = GetTime(); while(s_it != mapErasedGovernanceObjects.end()) { - if(s_it->second < GetTime()) + if(s_it->second < nNow) mapErasedGovernanceObjects.erase(s_it++); else ++s_it; @@ -839,13 +839,40 @@ 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, update_mode_enum_t eUpdateLast) + +void CGovernanceManager::MasternodeRateUpdate(const CGovernanceObject& govobj) { - bool fRateCheckBypassed; - return MasternodeRateCheck(govobj, eUpdateLast, true, fRateCheckBypassed); + int nObjectType = govobj.GetObjectType(); + if((nObjectType != GOVERNANCE_OBJECT_TRIGGER) && (nObjectType != GOVERNANCE_OBJECT_WATCHDOG)) + return; + + const CTxIn& vin = govobj.GetMasternodeVin(); + txout_m_it it = mapLastMasternodeObject.find(vin.prevout); + + if(it == mapLastMasternodeObject.end()) + it = mapLastMasternodeObject.insert(txout_m_t::value_type(vin.prevout, last_object_rec(true))).first; + + int64_t nTimestamp = govobj.GetCreationTime(); + if (GOVERNANCE_OBJECT_TRIGGER == nObjectType) + it->second.triggerBuffer.AddTimestamp(nTimestamp); + else if (GOVERNANCE_OBJECT_WATCHDOG == nObjectType) + it->second.watchdogBuffer.AddTimestamp(nTimestamp); + + if (nTimestamp > GetTime() + MAX_TIME_FUTURE_DEVIATION - RELIABLE_PROPAGATION_TIME) { + // schedule additional relay for the object + setAdditionalRelayObjects.insert(govobj.GetHash()); + } + + it->second.fStatusOK = true; } -bool CGovernanceManager::MasternodeRateCheck(const CGovernanceObject& govobj, update_mode_enum_t eUpdateLast, bool fForce, bool& fRateCheckBypassed) +bool CGovernanceManager::MasternodeRateCheck(const CGovernanceObject& govobj, bool fUpdateFailStatus) +{ + bool fRateCheckBypassed; + return MasternodeRateCheck(govobj, fUpdateFailStatus, true, fRateCheckBypassed); +} + +bool CGovernanceManager::MasternodeRateCheck(const CGovernanceObject& govobj, bool fUpdateFailStatus, bool fForce, bool& fRateCheckBypassed) { LOCK(cs); @@ -864,36 +891,11 @@ bool CGovernanceManager::MasternodeRateCheck(const CGovernanceObject& govobj, up return true; } + const CTxIn& vin = govobj.GetMasternodeVin(); int64_t nTimestamp = govobj.GetCreationTime(); int64_t nNow = GetTime(); int64_t nSuperblockCycleSeconds = Params().GetConsensus().nSuperblockCycle * Params().GetConsensus().nPowTargetSpacing; - const CTxIn& vin = govobj.GetMasternodeVin(); - - txout_m_it it = mapLastMasternodeObject.find(vin.prevout); - - if(it == mapLastMasternodeObject.end()) { - 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: - it->second.triggerBuffer.AddTimestamp(nTimestamp); - break; - case GOVERNANCE_OBJECT_WATCHDOG: - it->second.watchdogBuffer.AddTimestamp(nTimestamp); - break; - default: - break; - } - } - return true; - } - - if(it->second.fStatusOK && !fForce) { - fRateCheckBypassed = true; - return true; - } - std::string strHash = govobj.GetHash().ToString(); if(nTimestamp < nNow - 2 * nSuperblockCycleSeconds) { @@ -902,71 +904,53 @@ bool CGovernanceManager::MasternodeRateCheck(const CGovernanceObject& govobj, up return false; } - bool fAdditionalRelay = false; if(nTimestamp > nNow + MAX_TIME_FUTURE_DEVIATION) { LogPrintf("CGovernanceManager::MasternodeRateCheck -- object %s rejected due to too new (future) timestamp, masternode vin = %s, timestamp = %d, current time = %d\n", strHash, vin.prevout.ToStringShort(), nTimestamp, nNow); return false; - } else if (nTimestamp > nNow + MAX_TIME_FUTURE_DEVIATION - RELIABLE_PROPAGATION_TIME) { - // schedule additional relay for the object - fAdditionalRelay = true; + } + + txout_m_it it = mapLastMasternodeObject.find(vin.prevout); + if(it == mapLastMasternodeObject.end()) + return true; + + if(it->second.fStatusOK && !fForce) { + fRateCheckBypassed = true; + return true; } 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; + buffer = it->second.triggerBuffer; dMaxRate = 2 * 1.1 / double(nSuperblockCycleSeconds); break; case GOVERNANCE_OBJECT_WATCHDOG: - pBuffer = &it->second.watchdogBuffer; + buffer = it->second.watchdogBuffer; dMaxRate = 2 * 1.1 / 3600.; break; default: break; } - 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 ); - if (eUpdateLast == UPDATE_TRUE && fAdditionalRelay) - setAdditionalRelayObjects.insert(govobj.GetHash()); - - 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(!fRateOK) + { 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); + + if (fUpdateFailStatus) + it->second.fStatusOK = false; } - return false; + + return fRateOK; } bool CGovernanceManager::ProcessVote(CNode* pfrom, const CGovernanceVote& vote, CGovernanceException& exception) diff --git a/src/governance.h b/src/governance.h index d06010b4e6..a85d474257 100644 --- a/src/governance.h +++ b/src/governance.h @@ -117,7 +117,7 @@ public: double GetRate() { int nCount = GetCount(); - if(nCount < 2) { + if(nCount < RATE_BUFFER_SIZE) { return 0.0; } int64_t nMin = GetMinTimestamp(); @@ -141,12 +141,6 @@ public: } }; -enum update_mode_enum_t { - UPDATE_FALSE, - UPDATE_TRUE, - UPDATE_FAIL_ONLY -}; - // // Governance Manager : Contains all proposals for the budget // @@ -401,9 +395,11 @@ public: void AddSeenVote(uint256 nHash, int status); - bool MasternodeRateCheck(const CGovernanceObject& govobj, update_mode_enum_t eUpdateLast = UPDATE_FALSE); + void MasternodeRateUpdate(const CGovernanceObject& govobj); - bool MasternodeRateCheck(const CGovernanceObject& govobj, update_mode_enum_t eUpdateLast, bool fForce, bool& fRateCheckBypassed); + bool MasternodeRateCheck(const CGovernanceObject& govobj, bool fUpdateFailStatus = false); + + bool MasternodeRateCheck(const CGovernanceObject& govobj, bool fUpdateFailStatus, bool fForce, bool& fRateCheckBypassed); bool ProcessVoteAndRelay(const CGovernanceVote& vote, CGovernanceException& exception) { bool fOK = ProcessVote(NULL, vote, exception); diff --git a/src/rpc/governance.cpp b/src/rpc/governance.cpp index c57aa48a4a..99f9f149ea 100644 --- a/src/rpc/governance.cpp +++ b/src/rpc/governance.cpp @@ -273,11 +273,6 @@ UniValue gobject(const UniValue& params, bool fHelp) LogPrintf("gobject(submit) -- Object submission rejected because of rate check failure - hash = %s\n", strHash); throw JSONRPCError(RPC_INVALID_PARAMETER, "Object creation rate limit exceeded"); } - // This check should always pass, update buffer - 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"); - } LogPrintf("gobject(submit) -- Adding locally created governance object - %s\n", strHash); diff --git a/src/test/ratecheck_tests.cpp b/src/test/ratecheck_tests.cpp index 9d3769c67e..90104de969 100644 --- a/src/test/ratecheck_tests.cpp +++ b/src/test/ratecheck_tests.cpp @@ -30,7 +30,8 @@ BOOST_AUTO_TEST_CASE(ratecheck_test) BOOST_CHECK(buffer.GetCount() == 2); BOOST_CHECK(buffer.GetMinTimestamp() == 1); BOOST_CHECK(buffer.GetMaxTimestamp() == 2); - BOOST_CHECK(fabs(buffer.GetRate() - 2.0) < 1.0e-9); + //BOOST_CHECK(fabs(buffer.GetRate() - 2.0) < 1.0e-9); + BOOST_CHECK(buffer.GetRate() == 0.0); buffer.AddTimestamp(3); BOOST_CHECK(buffer.GetCount() == 3); @@ -46,13 +47,15 @@ BOOST_AUTO_TEST_CASE(ratecheck_test) std::cout << "nMax = " << nMax << std::endl; std::cout << "buffer.GetRate() = " << dRate << std::endl; - BOOST_CHECK(fabs(buffer.GetRate() - (3.0/2.0)) < 1.0e-9); + //BOOST_CHECK(fabs(buffer.GetRate() - (3.0/2.0)) < 1.0e-9); + BOOST_CHECK(buffer.GetRate() == 0.0); buffer.AddTimestamp(4); BOOST_CHECK(buffer.GetCount() == 4); BOOST_CHECK(buffer.GetMinTimestamp() == 1); BOOST_CHECK(buffer.GetMaxTimestamp() == 4); - BOOST_CHECK(fabs(buffer.GetRate() - (4.0/3.0)) < 1.0e-9); + //BOOST_CHECK(fabs(buffer.GetRate() - (4.0/3.0)) < 1.0e-9); + BOOST_CHECK(buffer.GetRate() == 0.0); buffer.AddTimestamp(5); BOOST_CHECK(buffer.GetCount() == 5);