mirror of
https://github.com/dashpay/dash.git
synced 2024-12-25 20:12:57 +01:00
Fix MasternodeRateCheck (#1490)
* fixed an issue with MasternodeRateCheck always returns true * additioanal fixes and refactoring (rebase) * slightly improved CRateBuffer synchronization for newly started nodes
This commit is contained in:
parent
ae909d0a09
commit
4ed838cb5d
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user