2016-12-20 14:26:45 +01:00
// Copyright (c) 2014-2017 The Dash Core developers
2016-04-09 21:57:53 +02:00
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
2016-04-09 22:55:52 +02:00
# include "governance.h"
2016-11-24 19:12:05 +01:00
# include "governance-object.h"
2016-04-14 00:41:40 +02:00
# include "governance-vote.h"
2016-08-17 09:08:25 +02:00
# include "governance-classes.h"
2017-08-09 02:19:06 +02:00
# include "net_processing.h"
2016-11-25 20:01:56 +01:00
# include "netmessagemaker.h"
2016-04-09 21:57:53 +02:00
# include "masternode.h"
# include "masternode-sync.h"
2016-12-20 14:27:59 +01:00
# include "masternodeman.h"
2017-04-12 09:04:06 +02:00
# include "messagesigner.h"
2016-09-27 09:50:04 +02:00
# include "netfulfilledman.h"
2016-04-09 21:57:53 +02:00
# include "util.h"
2016-04-10 16:46:19 +02:00
CGovernanceManager governance ;
2016-04-09 21:57:53 +02:00
int nSubmittedFinalBudget ;
2017-07-12 22:08:06 +02:00
const std : : string CGovernanceManager : : SERIALIZATION_VERSION_STRING = " CGovernanceManager-Version-12 " ;
2017-07-05 02:31:50 +02:00
const int CGovernanceManager : : MAX_TIME_FUTURE_DEVIATION = 60 * 60 ;
const int CGovernanceManager : : RELIABLE_PROPAGATION_TIME = 60 ;
2016-11-13 18:52:34 +01:00
2016-09-05 01:44:10 +02:00
CGovernanceManager : : CGovernanceManager ( )
2017-08-25 14:57:05 +02:00
: nTimeLastDiff ( 0 ) ,
2016-09-05 01:44:10 +02:00
nCachedBlockHeight ( 0 ) ,
mapObjects ( ) ,
2017-07-12 22:08:06 +02:00
mapErasedGovernanceObjects ( ) ,
2016-11-12 02:51:45 +01:00
mapMasternodeOrphanObjects ( ) ,
2018-02-06 12:08:43 +01:00
cmapVoteToObject ( MAX_CACHE_SIZE ) ,
cmapInvalidVotes ( MAX_CACHE_SIZE ) ,
cmmapOrphanVotes ( MAX_CACHE_SIZE ) ,
2016-12-08 21:00:49 +01:00
mapLastMasternodeObject ( ) ,
2016-11-13 18:52:34 +01:00
setRequestedObjects ( ) ,
2016-11-18 15:17:22 +01:00
fRateChecksEnabled ( true ) ,
2016-09-05 01:44:10 +02:00
cs ( )
{ }
2016-04-09 21:57:53 +02:00
2016-08-17 09:08:25 +02:00
// Accessors for thread-safe access to maps
2016-09-12 09:40:00 +02:00
bool CGovernanceManager : : HaveObjectForHash ( uint256 nHash ) {
2016-08-17 09:08:25 +02:00
LOCK ( cs ) ;
2017-07-05 02:31:50 +02:00
return ( mapObjects . count ( nHash ) = = 1 | | mapPostponedObjects . count ( nHash ) = = 1 ) ;
2016-08-17 09:08:25 +02:00
}
2016-11-13 18:52:34 +01:00
bool CGovernanceManager : : SerializeObjectForHash ( uint256 nHash , CDataStream & ss )
{
2016-08-17 09:08:25 +02:00
LOCK ( cs ) ;
object_m_it it = mapObjects . find ( nHash ) ;
2016-09-12 09:40:00 +02:00
if ( it = = mapObjects . end ( ) ) {
2017-07-05 02:31:50 +02:00
it = mapPostponedObjects . find ( nHash ) ;
if ( it = = mapPostponedObjects . end ( ) )
return false ;
2016-08-17 09:08:25 +02:00
}
ss < < it - > second ;
return true ;
}
2016-11-13 18:52:34 +01:00
bool CGovernanceManager : : HaveVoteForHash ( uint256 nHash )
{
2016-08-17 09:08:25 +02:00
LOCK ( cs ) ;
2016-11-13 18:52:34 +01:00
CGovernanceObject * pGovobj = NULL ;
2018-02-06 12:08:43 +01:00
if ( ! cmapVoteToObject . Get ( nHash , pGovobj ) ) {
2016-11-13 18:52:34 +01:00
return false ;
}
if ( ! pGovobj - > GetVoteFile ( ) . HasVote ( nHash ) ) {
2016-08-17 09:08:25 +02:00
return false ;
}
return true ;
}
2017-02-17 21:08:41 +01:00
int CGovernanceManager : : GetVoteCount ( ) const
{
LOCK ( cs ) ;
2018-02-06 12:08:43 +01:00
return ( int ) cmapVoteToObject . GetSize ( ) ;
2017-02-17 21:08:41 +01:00
}
2016-11-13 18:52:34 +01:00
bool CGovernanceManager : : SerializeVoteForHash ( uint256 nHash , CDataStream & ss )
2016-08-17 09:08:25 +02:00
{
LOCK ( cs ) ;
2016-11-13 18:52:34 +01:00
CGovernanceObject * pGovobj = NULL ;
2018-02-06 12:08:43 +01:00
if ( ! cmapVoteToObject . Get ( nHash , pGovobj ) ) {
2016-11-13 18:52:34 +01:00
return false ;
}
2018-02-21 17:35:37 +01:00
if ( ! pGovobj - > GetVoteFile ( ) . SerializeVoteToStream ( nHash , ss ) ) {
2016-11-13 18:52:34 +01:00
return false ;
}
return true ;
2016-08-17 09:08:25 +02:00
}
2017-02-06 14:31:37 +01:00
void CGovernanceManager : : ProcessMessage ( CNode * pfrom , const std : : string & strCommand , CDataStream & vRecv , CConnman & connman )
2016-06-08 08:57:16 +02:00
{
// lite mode is not supported
if ( fLiteMode ) return ;
if ( ! masternodeSync . IsBlockchainSynced ( ) ) return ;
2016-09-28 22:03:54 +02:00
if ( pfrom - > nVersion < MIN_GOVERNANCE_PEER_PROTO_VERSION ) return ;
2016-08-05 18:25:03 +02:00
2016-08-17 09:08:25 +02:00
// ANOTHER USER IS ASKING US TO HELP THEM SYNC GOVERNANCE OBJECT DATA
2016-06-08 08:57:16 +02:00
if ( strCommand = = NetMsgType : : MNGOVERNANCESYNC )
{
2016-09-12 09:40:00 +02:00
// Ignore such requests until we are fully synced.
// We could start processing this after masternode list is synced
// but this is a heavy one so it's better to finish sync first.
2016-08-05 18:25:03 +02:00
if ( ! masternodeSync . IsSynced ( ) ) return ;
2016-06-08 08:57:16 +02:00
uint256 nProp ;
2017-02-02 09:50:44 +01:00
CBloomFilter filter ;
2016-06-08 08:57:16 +02:00
vRecv > > nProp ;
2017-02-02 09:50:44 +01:00
if ( pfrom - > nVersion > = GOVERNANCE_FILTER_PROTO_VERSION ) {
vRecv > > filter ;
filter . UpdateEmptyFull ( ) ;
}
else {
filter . clear ( ) ;
}
2016-09-27 09:50:04 +02:00
if ( nProp = = uint256 ( ) ) {
2018-02-12 13:49:28 +01:00
SyncAll ( pfrom , connman ) ;
} else {
SyncSingleObjAndItsVotes ( pfrom , nProp , filter , connman ) ;
2016-06-08 08:57:16 +02:00
}
2016-10-22 18:52:14 +02:00
LogPrint ( " gobject " , " MNGOVERNANCESYNC -- syncing governance objects to our peer at %s \n " , pfrom - > addr . ToString ( ) ) ;
2016-06-08 08:57:16 +02:00
}
2016-08-17 09:08:25 +02:00
// A NEW GOVERNANCE OBJECT HAS ARRIVED
2016-06-08 08:57:16 +02:00
else if ( strCommand = = NetMsgType : : MNGOVERNANCEOBJECT )
{
2016-06-10 07:16:32 +02:00
// MAKE SURE WE HAVE A VALID REFERENCE TO THE TIP BEFORE CONTINUING
2017-11-22 15:27:06 +01:00
CGovernanceObject govobj ;
vRecv > > govobj ;
uint256 nHash = govobj . GetHash ( ) ;
pfrom - > setAskFor . erase ( nHash ) ;
2016-06-08 08:57:16 +02:00
2017-01-17 21:02:38 +01:00
if ( ! masternodeSync . IsMasternodeListSynced ( ) ) {
LogPrint ( " gobject " , " MNGOVERNANCEOBJECT -- masternode list not synced \n " ) ;
return ;
}
2016-11-13 18:52:34 +01:00
std : : string strHash = nHash . ToString ( ) ;
2016-12-06 17:40:37 +01:00
LogPrint ( " gobject " , " MNGOVERNANCEOBJECT -- Received object: %s \n " , strHash ) ;
2016-11-13 18:52:34 +01:00
if ( ! AcceptObjectMessage ( nHash ) ) {
2016-12-06 17:40:37 +01:00
LogPrintf ( " MNGOVERNANCEOBJECT -- Received unrequested object: %s \n " , strHash ) ;
2016-11-13 18:52:34 +01:00
return ;
}
2017-01-09 16:09:42 +01:00
LOCK2 ( cs_main , cs ) ;
2016-11-28 15:21:50 +01:00
2017-07-12 22:08:06 +02:00
if ( mapObjects . count ( nHash ) | | mapPostponedObjects . count ( nHash ) | |
mapErasedGovernanceObjects . count ( nHash ) | | mapMasternodeOrphanObjects . count ( nHash ) ) {
2016-06-08 08:57:16 +02:00
// TODO - print error code? what if it's GOVOBJ_ERROR_IMMATURE?
2016-12-06 17:40:37 +01:00
LogPrint ( " gobject " , " MNGOVERNANCEOBJECT -- Received already seen object: %s \n " , strHash ) ;
2016-06-08 08:57:16 +02:00
return ;
}
2016-12-11 07:17:38 +01:00
bool fRateCheckBypassed = false ;
2017-08-23 16:22:23 +02:00
if ( ! MasternodeRateCheck ( govobj , true , false , fRateCheckBypassed ) ) {
2016-12-08 21:00:49 +01:00
LogPrintf ( " MNGOVERNANCEOBJECT -- masternode rate check failed - %s - (current block height %d) \n " , strHash , nCachedBlockHeight ) ;
return ;
}
2016-06-08 08:57:16 +02:00
std : : string strError = " " ;
2016-09-12 09:40:00 +02:00
// CHECK OBJECT AGAINST LOCAL BLOCKCHAIN
2016-08-17 09:08:25 +02:00
2016-11-12 02:51:45 +01:00
bool fMasternodeMissing = false ;
2017-07-05 02:31:50 +02:00
bool fMissingConfirmations = false ;
bool fIsValid = govobj . IsValidLocally ( strError , fMasternodeMissing , fMissingConfirmations , true ) ;
2016-09-12 09:40:00 +02:00
2017-07-05 02:31:50 +02:00
if ( fRateCheckBypassed & & ( fIsValid | | fMasternodeMissing ) ) {
2017-08-23 16:22:23 +02:00
if ( ! MasternodeRateCheck ( govobj , true ) ) {
2016-12-11 07:17:38 +01:00
LogPrintf ( " MNGOVERNANCEOBJECT -- masternode rate check failed (after signature verification) - %s - (current block height %d) \n " , strHash , nCachedBlockHeight ) ;
return ;
}
}
2017-07-05 02:31:50 +02:00
if ( ! fIsValid ) {
if ( fMasternodeMissing ) {
2017-07-13 11:38:00 +02:00
2018-02-15 08:29:44 +01:00
int & count = mapMasternodeOrphanCounter [ govobj . GetMasternodeOutpoint ( ) ] ;
2017-07-13 11:38:00 +02:00
if ( count > = 10 ) {
2018-02-15 08:29:44 +01:00
LogPrint ( " gobject " , " MNGOVERNANCEOBJECT -- Too many orphan objects, missing masternode=%s \n " , govobj . GetMasternodeOutpoint ( ) . ToStringShort ( ) ) ;
2017-07-13 11:38:00 +02:00
// ask for this object again in 2 minutes
CInv inv ( MSG_GOVERNANCE_OBJECT , govobj . GetHash ( ) ) ;
pfrom - > AskFor ( inv ) ;
return ;
}
count + + ;
ExpirationInfo info ( pfrom - > GetId ( ) , GetAdjustedTime ( ) + GOVERNANCE_ORPHAN_EXPIRATION_TIME ) ;
mapMasternodeOrphanObjects . insert ( std : : make_pair ( nHash , object_info_pair_t ( govobj , info ) ) ) ;
2017-07-05 02:31:50 +02:00
LogPrintf ( " MNGOVERNANCEOBJECT -- Missing masternode for: %s, strError = %s \n " , strHash , strError ) ;
} else if ( fMissingConfirmations ) {
AddPostponedObject ( govobj ) ;
LogPrintf ( " MNGOVERNANCEOBJECT -- Not enough fee confirmations for: %s, strError = %s \n " , strHash , strError ) ;
} else {
LogPrintf ( " MNGOVERNANCEOBJECT -- Governance object is invalid - %s \n " , strError ) ;
2017-07-13 11:38:00 +02:00
// apply node's ban score
Misbehaving ( pfrom - > GetId ( ) , 20 ) ;
2017-07-05 02:31:50 +02:00
}
2016-06-08 08:57:16 +02:00
2017-07-05 02:31:50 +02:00
return ;
2017-03-24 11:34:10 +01:00
}
2017-09-19 16:51:38 +02:00
AddGovernanceObject ( govobj , connman , pfrom ) ;
2016-06-08 08:57:16 +02:00
}
2016-08-17 09:08:25 +02:00
// A NEW GOVERNANCE OBJECT VOTE HAS ARRIVED
2016-08-05 18:25:03 +02:00
else if ( strCommand = = NetMsgType : : MNGOVERNANCEOBJECTVOTE )
2016-06-08 08:57:16 +02:00
{
2017-11-22 15:27:06 +01:00
CGovernanceVote vote ;
vRecv > > vote ;
uint256 nHash = vote . GetHash ( ) ;
pfrom - > setAskFor . erase ( nHash ) ;
2016-08-29 21:11:34 +02:00
// Ignore such messages until masternode list is synced
2016-11-12 12:14:50 +01:00
if ( ! masternodeSync . IsMasternodeListSynced ( ) ) {
2016-12-06 17:40:37 +01:00
LogPrint ( " gobject " , " MNGOVERNANCEOBJECTVOTE -- masternode list not synced \n " ) ;
2016-11-12 12:14:50 +01:00
return ;
}
2016-08-29 21:11:34 +02:00
2016-12-06 17:40:37 +01:00
LogPrint ( " gobject " , " MNGOVERNANCEOBJECTVOTE -- Received vote: %s \n " , vote . ToString ( ) ) ;
2016-08-17 09:08:25 +02:00
2016-12-06 17:40:37 +01:00
std : : string strHash = nHash . ToString ( ) ;
if ( ! AcceptVoteMessage ( nHash ) ) {
LogPrint ( " gobject " , " MNGOVERNANCEOBJECTVOTE -- Received unrequested vote object: %s, hash: %s, peer = %d \n " ,
vote . ToString ( ) , strHash , pfrom - > GetId ( ) ) ;
2016-06-08 08:57:16 +02:00
return ;
}
2016-11-13 18:52:34 +01:00
CGovernanceException exception ;
2017-09-19 16:51:38 +02:00
if ( ProcessVote ( pfrom , vote , exception , connman ) ) {
2016-12-06 17:40:37 +01:00
LogPrint ( " gobject " , " MNGOVERNANCEOBJECTVOTE -- %s new \n " , strHash ) ;
2017-08-09 18:07:03 +02:00
masternodeSync . BumpAssetLastTime ( " MNGOVERNANCEOBJECTVOTE " ) ;
2017-09-19 16:51:38 +02:00
vote . Relay ( connman ) ;
2016-11-13 18:52:34 +01:00
}
else {
2016-12-06 17:40:37 +01:00
LogPrint ( " gobject " , " MNGOVERNANCEOBJECTVOTE -- Rejected vote, error = %s \n " , exception . what ( ) ) ;
2016-11-13 18:52:34 +01:00
if ( ( exception . GetNodePenalty ( ) ! = 0 ) & & masternodeSync . IsSynced ( ) ) {
Misbehaving ( pfrom - > GetId ( ) , exception . GetNodePenalty ( ) ) ;
}
return ;
2016-06-08 08:57:16 +02:00
}
}
}
2017-09-19 16:51:38 +02:00
void CGovernanceManager : : CheckOrphanVotes ( CGovernanceObject & govobj , CGovernanceException & exception , CConnman & connman )
2016-04-09 21:57:53 +02:00
{
2016-11-13 18:52:34 +01:00
uint256 nHash = govobj . GetHash ( ) ;
2016-11-24 19:12:05 +01:00
std : : vector < vote_time_pair_t > vecVotePairs ;
2018-02-06 12:08:43 +01:00
cmmapOrphanVotes . GetAll ( nHash , vecVotePairs ) ;
2016-11-24 19:12:05 +01:00
2017-09-15 20:05:03 +02:00
ScopedLockBool guard ( cs , fRateChecksEnabled , false ) ;
2017-07-05 02:31:50 +02:00
2016-11-24 19:12:05 +01:00
int64_t nNow = GetAdjustedTime ( ) ;
for ( size_t i = 0 ; i < vecVotePairs . size ( ) ; + + i ) {
bool fRemove = false ;
vote_time_pair_t & pairVote = vecVotePairs [ i ] ;
CGovernanceVote & vote = pairVote . first ;
2016-11-13 18:52:34 +01:00
CGovernanceException exception ;
2016-11-24 19:12:05 +01:00
if ( pairVote . second < nNow ) {
fRemove = true ;
}
2017-09-19 16:51:38 +02:00
else if ( govobj . ProcessVote ( NULL , vote , exception , connman ) ) {
vote . Relay ( connman ) ;
2016-11-24 19:12:05 +01:00
fRemove = true ;
2016-11-13 18:52:34 +01:00
}
2016-11-24 19:12:05 +01:00
if ( fRemove ) {
2018-02-06 12:08:43 +01:00
cmmapOrphanVotes . Erase ( nHash , pairVote ) ;
2016-11-24 19:12:05 +01:00
}
2016-04-09 21:57:53 +02:00
}
2017-07-05 02:31:50 +02:00
}
2017-09-19 16:51:38 +02:00
void CGovernanceManager : : AddGovernanceObject ( CGovernanceObject & govobj , CConnman & connman , CNode * pfrom )
2017-07-05 02:31:50 +02:00
{
2018-02-21 21:24:28 +01:00
DBG ( std : : cout < < " CGovernanceManager::AddGovernanceObject START " < < std : : endl ; ) ;
2017-07-12 22:08:06 +02:00
2017-07-05 02:31:50 +02:00
uint256 nHash = govobj . GetHash ( ) ;
std : : string strHash = nHash . ToString ( ) ;
// UPDATE CACHED VARIABLES FOR THIS OBJECT AND ADD IT TO OUR MANANGED DATA
govobj . UpdateSentinelVariables ( ) ; //this sets local vars in object
2017-01-09 16:09:42 +01:00
LOCK2 ( cs_main , cs ) ;
2016-04-09 21:57:53 +02:00
std : : string strError = " " ;
2016-08-17 09:08:25 +02:00
// MAKE SURE THIS OBJECT IS OK
2017-01-03 19:32:52 +01:00
if ( ! govobj . IsValidLocally ( strError , true ) ) {
LogPrintf ( " CGovernanceManager::AddGovernanceObject -- invalid governance object - %s - (nCachedBlockHeight %d) \n " , strError , nCachedBlockHeight ) ;
2017-07-12 22:08:06 +02:00
return ;
2016-04-09 21:57:53 +02:00
}
2016-08-17 09:08:25 +02:00
// IF WE HAVE THIS OBJECT ALREADY, WE DON'T WANT ANOTHER COPY
2016-11-25 15:08:48 +01:00
if ( mapObjects . count ( nHash ) ) {
2016-11-30 02:33:47 +01:00
LogPrintf ( " CGovernanceManager::AddGovernanceObject -- already have governance object %s \n " , nHash . ToString ( ) ) ;
2017-07-12 22:08:06 +02:00
return ;
2016-04-09 21:57:53 +02:00
}
2017-07-05 02:31:50 +02:00
LogPrint ( " gobject " , " CGovernanceManager::AddGovernanceObject -- Adding object: hash = %s, type = %d \n " , nHash . ToString ( ) , govobj . GetObjectType ( ) ) ;
2016-12-14 16:27:46 +01:00
2016-08-17 09:08:25 +02:00
// INSERT INTO OUR GOVERNANCE OBJECT MEMORY
2016-11-25 15:08:48 +01:00
mapObjects . insert ( std : : make_pair ( nHash , govobj ) ) ;
2016-08-17 09:08:25 +02:00
// SHOULD WE ADD THIS OBJECT TO ANY OTHER MANANGERS?
2018-02-21 21:24:28 +01:00
DBG ( std : : cout < < " CGovernanceManager::AddGovernanceObject Before trigger block, GetDataAsPlainString = "
2018-02-15 15:43:17 +01:00
< < govobj . GetDataAsPlainString ( )
2016-08-17 09:08:25 +02:00
< < " , nObjectType = " < < govobj . nObjectType
2018-02-21 21:24:28 +01:00
< < std : : endl ; ) ;
2016-08-17 09:08:25 +02:00
2018-02-25 06:33:27 +01:00
if ( govobj . nObjectType = = GOVERNANCE_OBJECT_TRIGGER ) {
2018-02-21 21:24:28 +01:00
DBG ( std : : cout < < " CGovernanceManager::AddGovernanceObject Before AddNewTrigger " < < std : : endl ; ) ;
2016-11-25 15:08:48 +01:00
triggerman . AddNewTrigger ( nHash ) ;
2018-02-21 21:24:28 +01:00
DBG ( std : : cout < < " CGovernanceManager::AddGovernanceObject After AddNewTrigger " < < std : : endl ; ) ;
2016-08-17 09:08:25 +02:00
}
2018-02-26 12:10:20 +01:00
LogPrintf ( " CGovernanceManager::AddGovernanceObject -- %s new, received from %s \n " , strHash , pfrom ? pfrom - > GetAddrName ( ) : " NULL " ) ;
2017-09-19 16:51:38 +02:00
govobj . Relay ( connman ) ;
2016-08-17 09:08:25 +02:00
2017-07-12 22:08:06 +02:00
// Update the rate buffer
2017-08-23 16:22:23 +02:00
MasternodeRateUpdate ( govobj ) ;
2017-07-12 22:08:06 +02:00
2017-08-09 18:07:03 +02:00
masternodeSync . BumpAssetLastTime ( " CGovernanceManager::AddGovernanceObject " ) ;
2017-07-12 22:08:06 +02:00
// WE MIGHT HAVE PENDING/ORPHAN VOTES FOR THIS OBJECT
CGovernanceException exception ;
2017-09-19 16:51:38 +02:00
CheckOrphanVotes ( govobj , exception , connman ) ;
2017-07-12 22:08:06 +02:00
2018-02-21 21:24:28 +01:00
DBG ( std : : cout < < " CGovernanceManager::AddGovernanceObject END " < < std : : endl ; ) ;
2016-04-09 21:57:53 +02:00
}
2016-08-17 09:08:25 +02:00
void CGovernanceManager : : UpdateCachesAndClean ( )
2016-04-09 21:57:53 +02:00
{
2016-10-22 18:52:14 +02:00
LogPrint ( " gobject " , " CGovernanceManager::UpdateCachesAndClean \n " ) ;
2016-08-17 09:08:25 +02:00
2016-10-17 20:54:28 +02:00
std : : vector < uint256 > vecDirtyHashes = mnodeman . GetAndClearDirtyGovernanceObjectHashes ( ) ;
2017-07-17 10:06:15 +02:00
LOCK2 ( cs_main , cs ) ;
2016-04-09 21:57:53 +02:00
2016-10-17 20:54:28 +02:00
for ( size_t i = 0 ; i < vecDirtyHashes . size ( ) ; + + i ) {
object_m_it it = mapObjects . find ( vecDirtyHashes [ i ] ) ;
if ( it = = mapObjects . end ( ) ) {
continue ;
}
2016-11-13 18:52:34 +01:00
it - > second . ClearMasternodeVotes ( ) ;
2016-10-17 20:54:28 +02:00
it - > second . fDirtyCache = true ;
}
2017-09-15 20:05:03 +02:00
ScopedLockBool guard ( cs , fRateChecksEnabled , false ) ;
2016-12-04 21:33:39 +01:00
2016-08-17 09:08:25 +02:00
// UPDATE CACHE FOR EACH OBJECT THAT IS FLAGGED DIRTYCACHE=TRUE
2016-05-24 20:11:59 +02:00
2016-09-12 09:40:00 +02:00
object_m_it it = mapObjects . begin ( ) ;
2016-08-17 09:08:25 +02:00
// Clean up any expired or invalid triggers
triggerman . CleanAndRemove ( ) ;
2018-02-25 06:33:27 +01:00
int64_t nNow = GetAdjustedTime ( ) ;
2016-05-24 20:11:59 +02:00
while ( it ! = mapObjects . end ( ) )
2016-09-12 09:40:00 +02:00
{
2016-05-24 20:11:59 +02:00
CGovernanceObject * pObj = & ( ( * it ) . second ) ;
2016-09-12 09:40:00 +02:00
if ( ! pObj ) {
2016-08-17 09:08:25 +02:00
+ + it ;
continue ;
}
2016-05-24 20:11:59 +02:00
2017-02-22 19:29:30 +01:00
uint256 nHash = it - > first ;
std : : string strHash = nHash . ToString ( ) ;
2016-12-14 16:27:46 +01:00
2016-08-17 09:08:25 +02:00
// IF CACHE IS NOT DIRTY, WHY DO THIS?
2016-11-13 18:52:34 +01:00
if ( pObj - > IsSetDirtyCache ( ) ) {
2016-08-17 09:08:25 +02:00
// UPDATE LOCAL VALIDITY AGAINST CRYPTO DATA
2017-01-03 19:32:52 +01:00
pObj - > UpdateLocalValidity ( ) ;
2016-09-12 09:40:00 +02:00
2016-08-17 09:08:25 +02:00
// UPDATE SENTINEL SIGNALING VARIABLES
2016-12-11 07:17:38 +01:00
pObj - > UpdateSentinelVariables ( ) ;
2016-08-17 09:08:25 +02:00
}
2016-04-09 22:55:52 +02:00
2016-08-17 09:08:25 +02:00
// IF DELETE=TRUE, THEN CLEAN THE MESS UP!
2016-05-24 20:11:59 +02:00
2018-02-25 06:33:27 +01:00
int64_t nTimeSinceDeletion = nNow - pObj - > GetDeletionTime ( ) ;
2016-11-18 15:17:00 +01:00
2016-12-14 16:27:46 +01:00
LogPrint ( " gobject " , " CGovernanceManager::UpdateCachesAndClean -- Checking object for deletion: %s, deletion time = %d, time since deletion = %d, delete flag = %d, expired flag = %d \n " ,
strHash , pObj - > GetDeletionTime ( ) , nTimeSinceDeletion , pObj - > IsSetCachedDelete ( ) , pObj - > IsSetExpired ( ) ) ;
2016-11-18 15:17:00 +01:00
if ( ( pObj - > IsSetCachedDelete ( ) | | pObj - > IsSetExpired ( ) ) & &
( nTimeSinceDeletion > = GOVERNANCE_DELETION_DELAY ) ) {
2016-11-05 17:13:30 +01:00
LogPrintf ( " CGovernanceManager::UpdateCachesAndClean -- erase obj %s \n " , ( * it ) . first . ToString ( ) ) ;
2016-10-17 20:54:28 +02:00
mnodeman . RemoveGovernanceObject ( pObj - > GetHash ( ) ) ;
2016-11-13 18:52:34 +01:00
// Remove vote references
2018-02-06 12:08:43 +01:00
const object_ref_cm_t : : list_t & listItems = cmapVoteToObject . GetItemList ( ) ;
object_ref_cm_t : : list_cit lit = listItems . begin ( ) ;
2016-11-13 18:52:34 +01:00
while ( lit ! = listItems . end ( ) ) {
if ( lit - > value = = pObj ) {
uint256 nKey = lit - > key ;
+ + lit ;
2018-02-06 12:08:43 +01:00
cmapVoteToObject . Erase ( nKey ) ;
2016-11-13 18:52:34 +01:00
}
else {
+ + lit ;
}
}
2017-07-12 22:08:06 +02:00
2018-02-25 06:33:27 +01:00
int64_t nTimeExpired { 0 } ;
2017-07-12 22:08:06 +02:00
2018-02-25 06:33:27 +01:00
if ( pObj - > GetObjectType ( ) = = GOVERNANCE_OBJECT_PROPOSAL ) {
2017-07-12 22:08:06 +02:00
// keep hashes of deleted proposals forever
nTimeExpired = std : : numeric_limits < int64_t > : : max ( ) ;
2018-02-25 06:33:27 +01:00
} else {
int64_t nSuperblockCycleSeconds = Params ( ) . GetConsensus ( ) . nSuperblockCycle * Params ( ) . GetConsensus ( ) . nPowTargetSpacing ;
nTimeExpired = pObj - > GetCreationTime ( ) + 2 * nSuperblockCycleSeconds + GOVERNANCE_DELETION_DELAY ;
2017-02-17 01:48:42 +01:00
}
2017-07-12 22:08:06 +02:00
mapErasedGovernanceObjects . insert ( std : : make_pair ( nHash , nTimeExpired ) ) ;
2016-08-17 09:08:25 +02:00
mapObjects . erase ( it + + ) ;
} else {
+ + it ;
}
2016-05-23 23:39:10 +02:00
}
2016-12-04 21:33:39 +01:00
2017-07-12 22:08:06 +02:00
// forget about expired deleted objects
hash_time_m_it s_it = mapErasedGovernanceObjects . begin ( ) ;
while ( s_it ! = mapErasedGovernanceObjects . end ( ) ) {
2017-08-23 16:22:23 +02:00
if ( s_it - > second < nNow )
2017-07-12 22:08:06 +02:00
mapErasedGovernanceObjects . erase ( s_it + + ) ;
else
+ + s_it ;
}
2017-06-06 01:47:23 +02:00
LogPrintf ( " CGovernanceManager::UpdateCachesAndClean -- %s \n " , ToString ( ) ) ;
2016-04-09 21:57:53 +02:00
}
2016-06-08 08:57:16 +02:00
CGovernanceObject * CGovernanceManager : : FindGovernanceObject ( const uint256 & nHash )
2016-04-09 21:57:53 +02:00
{
LOCK ( cs ) ;
2016-05-13 18:03:01 +02:00
if ( mapObjects . count ( nHash ) )
return & mapObjects [ nHash ] ;
2016-04-09 21:57:53 +02:00
return NULL ;
}
2016-11-13 18:52:34 +01:00
std : : vector < CGovernanceVote > CGovernanceManager : : GetMatchingVotes ( const uint256 & nParentHash )
2016-08-17 09:08:25 +02:00
{
2016-11-13 18:52:34 +01:00
LOCK ( cs ) ;
std : : vector < CGovernanceVote > vecResult ;
2016-08-17 09:08:25 +02:00
2016-11-13 18:52:34 +01:00
object_m_it it = mapObjects . find ( nParentHash ) ;
if ( it = = mapObjects . end ( ) ) {
return vecResult ;
2016-08-17 09:08:25 +02:00
}
2016-11-13 18:52:34 +01:00
CGovernanceObject & govobj = it - > second ;
2016-08-17 09:08:25 +02:00
2016-11-13 18:52:34 +01:00
return govobj . GetVoteFile ( ) . GetVotes ( ) ;
2016-08-17 09:08:25 +02:00
}
2017-09-11 16:13:48 +02:00
std : : vector < CGovernanceVote > CGovernanceManager : : GetCurrentVotes ( const uint256 & nParentHash , const COutPoint & mnCollateralOutpointFilter )
2016-11-22 20:26:36 +01:00
{
LOCK ( cs ) ;
std : : vector < CGovernanceVote > vecResult ;
// Find the governance object or short-circuit.
object_m_it it = mapObjects . find ( nParentHash ) ;
if ( it = = mapObjects . end ( ) ) return vecResult ;
CGovernanceObject & govobj = it - > second ;
2017-09-11 16:13:48 +02:00
CMasternode mn ;
std : : map < COutPoint , CMasternode > mapMasternodes ;
2018-02-21 17:32:08 +01:00
if ( mnCollateralOutpointFilter . IsNull ( ) ) {
2017-09-11 16:13:48 +02:00
mapMasternodes = mnodeman . GetFullMasternodeMap ( ) ;
} else if ( mnodeman . Get ( mnCollateralOutpointFilter , mn ) ) {
mapMasternodes [ mnCollateralOutpointFilter ] = mn ;
2016-11-22 20:26:36 +01:00
}
// Loop thru each MN collateral outpoint and get the votes for the `nParentHash` governance object
2018-02-06 12:09:33 +01:00
for ( const auto & mnpair : mapMasternodes )
2016-11-22 20:26:36 +01:00
{
// get a vote_rec_t from the govobj
vote_rec_t voteRecord ;
2017-09-11 16:13:48 +02:00
if ( ! govobj . GetCurrentMNVotes ( mnpair . first , voteRecord ) ) continue ;
2016-11-22 20:26:36 +01:00
for ( vote_instance_m_it it3 = voteRecord . mapInstances . begin ( ) ; it3 ! = voteRecord . mapInstances . end ( ) ; + + it3 ) {
int signal = ( it3 - > first ) ;
int outcome = ( ( it3 - > second ) . eOutcome ) ;
2017-02-23 13:29:00 +01:00
int64_t nCreationTime = ( ( it3 - > second ) . nCreationTime ) ;
2016-11-22 20:26:36 +01:00
2017-09-11 16:13:48 +02:00
CGovernanceVote vote = CGovernanceVote ( mnpair . first , nParentHash , ( vote_signal_enum_t ) signal , ( vote_outcome_enum_t ) outcome ) ;
2017-02-23 13:29:00 +01:00
vote . SetTime ( nCreationTime ) ;
2016-11-22 20:26:36 +01:00
vecResult . push_back ( vote ) ;
}
}
return vecResult ;
}
2016-08-17 09:08:25 +02:00
std : : vector < CGovernanceObject * > CGovernanceManager : : GetAllNewerThan ( int64_t nMoreThanTime )
2016-04-09 21:57:53 +02:00
{
LOCK ( cs ) ;
2016-05-28 12:31:44 +02:00
std : : vector < CGovernanceObject * > vGovObjs ;
2016-04-09 21:57:53 +02:00
2016-09-12 09:40:00 +02:00
object_m_it it = mapObjects . begin ( ) ;
2016-05-13 18:03:01 +02:00
while ( it ! = mapObjects . end ( ) )
2016-04-09 21:57:53 +02:00
{
2016-08-17 09:08:25 +02:00
// IF THIS OBJECT IS OLDER THAN TIME, CONTINUE
2016-11-13 18:52:34 +01:00
if ( ( * it ) . second . GetCreationTime ( ) < nMoreThanTime ) {
2016-08-17 09:08:25 +02:00
+ + it ;
continue ;
}
// ADD GOVERNANCE OBJECT TO LIST
2016-04-09 21:57:53 +02:00
2016-05-28 12:31:44 +02:00
CGovernanceObject * pGovObj = & ( ( * it ) . second ) ;
vGovObjs . push_back ( pGovObj ) ;
2016-04-09 21:57:53 +02:00
2016-08-17 09:08:25 +02:00
// NEXT
2016-04-09 21:57:53 +02:00
+ + it ;
}
2016-05-28 12:31:44 +02:00
return vGovObjs ;
2016-04-09 21:57:53 +02:00
}
//
// Sort by votes, if there's a tie sort by their feeHash TX
//
struct sortProposalsByVotes {
2016-04-16 19:19:17 +02:00
bool operator ( ) ( const std : : pair < CGovernanceObject * , int > & left , const std : : pair < CGovernanceObject * , int > & right ) {
2016-09-12 09:40:00 +02:00
if ( left . second ! = right . second )
return ( left . second > right . second ) ;
2016-11-13 18:52:34 +01:00
return ( UintToArith256 ( left . first - > GetCollateralHash ( ) ) > UintToArith256 ( right . first - > GetCollateralHash ( ) ) ) ;
2016-04-09 21:57:53 +02:00
}
} ;
2017-09-19 16:51:38 +02:00
void CGovernanceManager : : DoMaintenance ( CConnman & connman )
2016-04-09 21:57:53 +02:00
{
2017-08-25 14:57:05 +02:00
if ( fLiteMode | | ! masternodeSync . IsSynced ( ) ) return ;
2016-08-29 21:11:34 +02:00
2016-08-17 09:08:25 +02:00
// CHECK OBJECTS WE'VE ASKED FOR, REMOVE OLD ENTRIES
2016-04-09 21:57:53 +02:00
2017-03-06 08:46:59 +01:00
CleanOrphanObjects ( ) ;
2017-09-19 16:51:38 +02:00
RequestOrphanObjects ( connman ) ;
2016-04-09 21:57:53 +02:00
2016-08-17 09:08:25 +02:00
// CHECK AND REMOVE - REPROCESS GOVERNANCE OBJECTS
2016-04-09 21:57:53 +02:00
2016-08-17 09:08:25 +02:00
UpdateCachesAndClean ( ) ;
2016-04-09 21:57:53 +02:00
}
2016-11-13 18:52:34 +01:00
bool CGovernanceManager : : ConfirmInventoryRequest ( const CInv & inv )
{
2017-08-09 18:07:03 +02:00
// do not request objects until it's time to sync
if ( ! masternodeSync . IsWinnersListSynced ( ) ) return false ;
2016-11-13 18:52:34 +01:00
LOCK ( cs ) ;
LogPrint ( " gobject " , " CGovernanceManager::ConfirmInventoryRequest inv = %s \n " , inv . ToString ( ) ) ;
// First check if we've already recorded this object
switch ( inv . type ) {
case MSG_GOVERNANCE_OBJECT :
{
2017-07-05 02:31:50 +02:00
if ( mapObjects . count ( inv . hash ) = = 1 | | mapPostponedObjects . count ( inv . hash ) = = 1 ) {
2016-11-13 18:52:34 +01:00
LogPrint ( " gobject " , " CGovernanceManager::ConfirmInventoryRequest already have governance object, returning false \n " ) ;
return false ;
}
}
break ;
case MSG_GOVERNANCE_OBJECT_VOTE :
{
2018-02-06 12:08:43 +01:00
if ( cmapVoteToObject . HasKey ( inv . hash ) ) {
2016-11-13 18:52:34 +01:00
LogPrint ( " gobject " , " CGovernanceManager::ConfirmInventoryRequest already have governance vote, returning false \n " ) ;
return false ;
}
}
break ;
default :
LogPrint ( " gobject " , " CGovernanceManager::ConfirmInventoryRequest unknown type, returning false \n " ) ;
return false ;
}
hash_s_t * setHash = NULL ;
switch ( inv . type ) {
case MSG_GOVERNANCE_OBJECT :
setHash = & setRequestedObjects ;
break ;
case MSG_GOVERNANCE_OBJECT_VOTE :
setHash = & setRequestedVotes ;
break ;
default :
return false ;
}
hash_s_cit it = setHash - > find ( inv . hash ) ;
if ( it = = setHash - > end ( ) ) {
setHash - > insert ( inv . hash ) ;
LogPrint ( " gobject " , " CGovernanceManager::ConfirmInventoryRequest added inv to requested set \n " ) ;
}
LogPrint ( " gobject " , " CGovernanceManager::ConfirmInventoryRequest reached end, returning true \n " ) ;
return true ;
}
2018-02-12 13:49:28 +01:00
void CGovernanceManager : : SyncSingleObjAndItsVotes ( CNode * pnode , const uint256 & nProp , const CBloomFilter & filter , CConnman & connman )
2016-04-09 21:57:53 +02:00
{
2017-02-16 16:14:42 +01:00
// do not provide any data until our node is synced
2017-12-14 01:33:58 +01:00
if ( ! masternodeSync . IsSynced ( ) ) return ;
2017-02-16 16:14:42 +01:00
2016-12-06 17:40:37 +01:00
int nVoteCount = 0 ;
2016-04-09 21:57:53 +02:00
2016-05-24 20:11:59 +02:00
// SYNC GOVERNANCE OBJECTS WITH OTHER CLIENT
2018-02-12 13:49:28 +01:00
LogPrint ( " gobject " , " CGovernanceManager::%s -- syncing single object to peer=%d, nProp = %s \n " , __func__ , pnode - > id , nProp . ToString ( ) ) ;
2016-12-04 21:33:39 +01:00
2018-02-12 13:49:28 +01:00
LOCK2 ( cs_main , cs ) ;
2016-11-13 18:52:34 +01:00
2018-02-12 13:49:28 +01:00
// single valid object and its valid votes
object_m_it it = mapObjects . find ( nProp ) ;
if ( it = = mapObjects . end ( ) ) {
LogPrint ( " gobject " , " CGovernanceManager::%s -- no matching object for hash %s, peer=%d \n " , __func__ , nProp . ToString ( ) , pnode - > id ) ;
return ;
}
CGovernanceObject & govobj = it - > second ;
std : : string strHash = it - > first . ToString ( ) ;
2016-12-04 21:33:39 +01:00
2018-02-12 13:49:28 +01:00
LogPrint ( " gobject " , " CGovernanceManager::%s -- attempting to sync govobj: %s, peer=%d \n " , __func__ , strHash , pnode - > id ) ;
2016-12-06 17:40:37 +01:00
2018-02-12 13:49:28 +01:00
if ( govobj . IsSetCachedDelete ( ) | | govobj . IsSetExpired ( ) ) {
LogPrintf ( " CGovernanceManager::%s -- not syncing deleted/expired govobj: %s, peer=%d \n " , __func__ ,
strHash , pnode - > id ) ;
return ;
}
2016-12-04 21:33:39 +01:00
2018-02-12 13:49:28 +01:00
// Push the govobj inventory message over to the other client
LogPrint ( " gobject " , " CGovernanceManager::%s -- syncing govobj: %s, peer=%d \n " , __func__ , strHash , pnode - > id ) ;
pnode - > PushInventory ( CInv ( MSG_GOVERNANCE_OBJECT , it - > first ) ) ;
std : : vector < CGovernanceVote > vecVotes = govobj . GetVoteFile ( ) . GetVotes ( ) ;
for ( size_t i = 0 ; i < vecVotes . size ( ) ; + + i ) {
if ( filter . contains ( vecVotes [ i ] . GetHash ( ) ) ) {
continue ;
}
if ( ! vecVotes [ i ] . IsValid ( true ) ) {
continue ;
}
pnode - > PushInventory ( CInv ( MSG_GOVERNANCE_OBJECT_VOTE , vecVotes [ i ] . GetHash ( ) ) ) ;
+ + nVoteCount ;
}
2017-01-17 21:02:38 +01:00
2018-02-12 13:49:28 +01:00
CNetMsgMaker msgMaker ( pnode - > GetSendVersion ( ) ) ;
connman . PushMessage ( pnode , msgMaker . Make ( NetMsgType : : SYNCSTATUSCOUNT , MASTERNODE_SYNC_GOVOBJ , 1 ) ) ;
connman . PushMessage ( pnode , msgMaker . Make ( NetMsgType : : SYNCSTATUSCOUNT , MASTERNODE_SYNC_GOVOBJ_VOTE , nVoteCount ) ) ;
LogPrintf ( " CGovernanceManager::%s -- sent 1 object and %d votes to peer=%d \n " , __func__ , nVoteCount , pnode - > id ) ;
}
2016-12-04 21:33:39 +01:00
2018-02-12 13:49:28 +01:00
void CGovernanceManager : : SyncAll ( CNode * pnode , CConnman & connman )
{
// do not provide any data until our node is synced
if ( ! masternodeSync . IsSynced ( ) ) return ;
2016-12-04 21:33:39 +01:00
2018-02-12 13:49:28 +01:00
if ( netfulfilledman . HasFulfilledRequest ( pnode - > addr , NetMsgType : : MNGOVERNANCESYNC ) ) {
// Asking for the whole list multiple times in a short period of time is no good
LogPrint ( " gobject " , " CGovernanceManager::%s -- peer already asked me for the list \n " , __func__ ) ;
Misbehaving ( pnode - > GetId ( ) , 20 ) ;
return ;
}
netfulfilledman . AddFulfilledRequest ( pnode - > addr , NetMsgType : : MNGOVERNANCESYNC ) ;
2016-11-13 18:52:34 +01:00
2018-02-12 13:49:28 +01:00
int nObjCount = 0 ;
int nVoteCount = 0 ;
// SYNC GOVERNANCE OBJECTS WITH OTHER CLIENT
LogPrint ( " gobject " , " CGovernanceManager::%s -- syncing all objects to peer=%d \n " , __func__ , pnode - > id ) ;
LOCK2 ( cs_main , cs ) ;
// all valid objects, no votes
for ( object_m_it it = mapObjects . begin ( ) ; it ! = mapObjects . end ( ) ; + + it ) {
CGovernanceObject & govobj = it - > second ;
std : : string strHash = it - > first . ToString ( ) ;
LogPrint ( " gobject " , " CGovernanceManager::%s -- attempting to sync govobj: %s, peer=%d \n " , __func__ , strHash , pnode - > id ) ;
if ( govobj . IsSetCachedDelete ( ) | | govobj . IsSetExpired ( ) ) {
LogPrintf ( " CGovernanceManager::%s -- not syncing deleted/expired govobj: %s, peer=%d \n " , __func__ ,
strHash , pnode - > id ) ;
continue ;
2016-11-13 18:52:34 +01:00
}
2018-02-12 13:49:28 +01:00
// Push the inventory budget proposal message over to the other client
LogPrint ( " gobject " , " CGovernanceManager::%s -- syncing govobj: %s, peer=%d \n " , __func__ , strHash , pnode - > id ) ;
pnode - > PushInventory ( CInv ( MSG_GOVERNANCE_OBJECT , it - > first ) ) ;
+ + nObjCount ;
2016-04-14 00:41:40 +02:00
}
2018-02-12 13:49:28 +01:00
CNetMsgMaker msgMaker ( pnode - > GetSendVersion ( ) ) ;
connman . PushMessage ( pnode , msgMaker . Make ( NetMsgType : : SYNCSTATUSCOUNT , MASTERNODE_SYNC_GOVOBJ , nObjCount ) ) ;
connman . PushMessage ( pnode , msgMaker . Make ( NetMsgType : : SYNCSTATUSCOUNT , MASTERNODE_SYNC_GOVOBJ_VOTE , nVoteCount ) ) ;
LogPrintf ( " CGovernanceManager::%s -- sent %d objects and %d votes to peer=%d \n " , __func__ , nObjCount , nVoteCount , pnode - > id ) ;
2016-04-09 21:57:53 +02:00
}
2017-08-23 16:22:23 +02:00
void CGovernanceManager : : MasternodeRateUpdate ( const CGovernanceObject & govobj )
{
2018-02-25 06:33:27 +01:00
if ( govobj . GetObjectType ( ) ! = GOVERNANCE_OBJECT_TRIGGER )
2017-08-23 16:22:23 +02:00
return ;
2018-02-15 08:29:44 +01:00
const COutPoint & masternodeOutpoint = govobj . GetMasternodeOutpoint ( ) ;
txout_m_it it = mapLastMasternodeObject . find ( masternodeOutpoint ) ;
2017-08-23 16:22:23 +02:00
if ( it = = mapLastMasternodeObject . end ( ) )
2018-02-15 08:29:44 +01:00
it = mapLastMasternodeObject . insert ( txout_m_t : : value_type ( masternodeOutpoint , last_object_rec ( true ) ) ) . first ;
2017-08-23 16:22:23 +02:00
int64_t nTimestamp = govobj . GetCreationTime ( ) ;
2018-02-25 06:33:27 +01:00
it - > second . triggerBuffer . AddTimestamp ( nTimestamp ) ;
2017-08-23 16:22:23 +02:00
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 , bool fUpdateFailStatus )
2016-12-11 07:17:38 +01:00
{
2017-07-05 02:31:50 +02:00
bool fRateCheckBypassed ;
2017-08-23 16:22:23 +02:00
return MasternodeRateCheck ( govobj , fUpdateFailStatus , true , fRateCheckBypassed ) ;
2016-12-11 07:17:38 +01:00
}
2017-08-23 16:22:23 +02:00
bool CGovernanceManager : : MasternodeRateCheck ( const CGovernanceObject & govobj , bool fUpdateFailStatus , bool fForce , bool & fRateCheckBypassed )
2016-09-05 01:44:10 +02:00
{
LOCK ( cs ) ;
2016-10-17 20:54:28 +02:00
2016-12-11 07:17:38 +01:00
fRateCheckBypassed = false ;
2016-12-08 21:00:49 +01:00
if ( ! masternodeSync . IsSynced ( ) ) {
return true ;
}
2016-11-18 15:17:22 +01:00
if ( ! fRateChecksEnabled ) {
return true ;
}
2018-02-25 06:33:27 +01:00
if ( govobj . GetObjectType ( ) ! = GOVERNANCE_OBJECT_TRIGGER ) {
2016-12-08 21:00:49 +01:00
return true ;
}
2018-02-15 08:29:44 +01:00
const COutPoint & masternodeOutpoint = govobj . GetMasternodeOutpoint ( ) ;
2016-12-11 07:17:38 +01:00
int64_t nTimestamp = govobj . GetCreationTime ( ) ;
2017-08-29 01:51:44 +02:00
int64_t nNow = GetAdjustedTime ( ) ;
2016-12-11 07:17:38 +01:00
int64_t nSuperblockCycleSeconds = Params ( ) . GetConsensus ( ) . nSuperblockCycle * Params ( ) . GetConsensus ( ) . nPowTargetSpacing ;
std : : string strHash = govobj . GetHash ( ) . ToString ( ) ;
if ( nTimestamp < nNow - 2 * nSuperblockCycleSeconds ) {
2018-02-15 08:29:44 +01:00
LogPrintf ( " CGovernanceManager::MasternodeRateCheck -- object %s rejected due to too old timestamp, masternode = %s, timestamp = %d, current time = %d \n " ,
strHash , masternodeOutpoint . ToStringShort ( ) , nTimestamp , nNow ) ;
2016-12-11 07:17:38 +01:00
return false ;
}
2017-07-05 02:31:50 +02:00
if ( nTimestamp > nNow + MAX_TIME_FUTURE_DEVIATION ) {
2018-02-15 08:29:44 +01:00
LogPrintf ( " CGovernanceManager::MasternodeRateCheck -- object %s rejected due to too new (future) timestamp, masternode = %s, timestamp = %d, current time = %d \n " ,
strHash , masternodeOutpoint . ToStringShort ( ) , nTimestamp , nNow ) ;
2016-12-11 07:17:38 +01:00
return false ;
2017-08-23 16:22:23 +02:00
}
2018-02-15 08:29:44 +01:00
txout_m_it it = mapLastMasternodeObject . find ( masternodeOutpoint ) ;
2017-08-23 16:22:23 +02:00
if ( it = = mapLastMasternodeObject . end ( ) )
return true ;
if ( it - > second . fStatusOK & & ! fForce ) {
fRateCheckBypassed = true ;
return true ;
2016-12-11 07:17:38 +01:00
}
2017-07-05 02:31:50 +02:00
2018-02-25 06:33:27 +01:00
// Allow 1 trigger per mn per cycle, with a small fudge factor
double dMaxRate = 2 * 1.1 / double ( nSuperblockCycleSeconds ) ;
// Temporary copy to check rate after new timestamp is added
CRateCheckBuffer buffer = it - > second . triggerBuffer ;
2016-10-17 20:54:28 +02:00
2017-04-05 18:30:08 +02:00
buffer . AddTimestamp ( nTimestamp ) ;
2018-02-25 06:33:27 +01:00
double dRate = buffer . GetRate ( ) ;
2017-04-05 18:30:08 +02:00
2018-02-25 06:33:27 +01:00
if ( dRate < dMaxRate ) {
return true ;
}
2017-04-05 18:30:08 +02:00
2018-02-25 06:33:27 +01:00
LogPrintf ( " CGovernanceManager::MasternodeRateCheck -- Rate too high: object hash = %s, masternode = %s, object timestamp = %d, rate = %f, max rate = %f \n " ,
strHash , masternodeOutpoint . ToStringShort ( ) , nTimestamp , dRate , dMaxRate ) ;
2017-07-05 02:31:50 +02:00
2018-02-25 06:33:27 +01:00
if ( fUpdateFailStatus )
it - > second . fStatusOK = false ;
2016-09-15 08:49:24 +02:00
2018-02-25 06:33:27 +01:00
return false ;
2016-09-05 01:44:10 +02:00
}
2017-09-19 16:51:38 +02:00
bool CGovernanceManager : : ProcessVote ( CNode * pfrom , const CGovernanceVote & vote , CGovernanceException & exception , CConnman & connman )
2016-11-13 18:52:34 +01:00
{
2017-07-21 11:47:38 +02:00
ENTER_CRITICAL_SECTION ( cs ) ;
2016-11-13 18:52:34 +01:00
uint256 nHashVote = vote . GetHash ( ) ;
2018-02-06 12:08:43 +01:00
uint256 nHashGovobj = vote . GetParentHash ( ) ;
if ( cmapVoteToObject . HasKey ( nHashVote ) ) {
LogPrint ( " gobject " , " CGovernanceObject::ProcessVote -- skipping known valid vote %s for object %s \n " , nHashVote . ToString ( ) , nHashGovobj . ToString ( ) ) ;
LEAVE_CRITICAL_SECTION ( cs ) ;
return false ;
}
if ( cmapInvalidVotes . HasKey ( nHashVote ) ) {
2016-11-13 18:52:34 +01:00
std : : ostringstream ostr ;
ostr < < " CGovernanceManager::ProcessVote -- Old invalid vote "
2017-09-11 16:13:48 +02:00
< < " , MN outpoint = " < < vote . GetMasternodeOutpoint ( ) . ToStringShort ( )
2018-02-06 12:08:43 +01:00
< < " , governance object hash = " < < nHashGovobj . ToString ( ) ;
2017-06-06 01:47:23 +02:00
LogPrintf ( " %s \n " , ostr . str ( ) ) ;
2016-11-13 18:52:34 +01:00
exception = CGovernanceException ( ostr . str ( ) , GOVERNANCE_EXCEPTION_PERMANENT_ERROR , 20 ) ;
2017-07-21 11:47:38 +02:00
LEAVE_CRITICAL_SECTION ( cs ) ;
2016-11-13 18:52:34 +01:00
return false ;
}
object_m_it it = mapObjects . find ( nHashGovobj ) ;
if ( it = = mapObjects . end ( ) ) {
2016-11-14 21:26:53 +01:00
std : : ostringstream ostr ;
2018-02-06 12:08:43 +01:00
ostr < < " CGovernanceManager::ProcessVote -- Unknown parent object " < < nHashGovobj . ToString ( )
< < " , MN outpoint = " < < vote . GetMasternodeOutpoint ( ) . ToStringShort ( ) ;
2016-11-14 21:26:53 +01:00
exception = CGovernanceException ( ostr . str ( ) , GOVERNANCE_EXCEPTION_WARNING ) ;
2018-02-06 12:08:43 +01:00
if ( cmmapOrphanVotes . Insert ( nHashGovobj , vote_time_pair_t ( vote , GetAdjustedTime ( ) + GOVERNANCE_ORPHAN_EXPIRATION_TIME ) ) ) {
2017-07-21 11:47:38 +02:00
LEAVE_CRITICAL_SECTION ( cs ) ;
2017-09-19 16:51:38 +02:00
RequestGovernanceObject ( pfrom , nHashGovobj , connman ) ;
2017-06-06 01:47:23 +02:00
LogPrintf ( " %s \n " , ostr . str ( ) ) ;
2017-07-21 11:47:38 +02:00
return false ;
2016-11-14 21:26:53 +01:00
}
2017-07-21 11:47:38 +02:00
LogPrint ( " gobject " , " %s \n " , ostr . str ( ) ) ;
LEAVE_CRITICAL_SECTION ( cs ) ;
2016-11-13 18:52:34 +01:00
return false ;
}
CGovernanceObject & govobj = it - > second ;
2017-02-22 19:29:30 +01:00
if ( govobj . IsSetCachedDelete ( ) | | govobj . IsSetExpired ( ) ) {
LogPrint ( " gobject " , " CGovernanceObject::ProcessVote -- ignoring vote for expired or deleted object, hash = %s \n " , nHashGovobj . ToString ( ) ) ;
2017-07-21 11:47:38 +02:00
LEAVE_CRITICAL_SECTION ( cs ) ;
2017-02-22 19:29:30 +01:00
return false ;
}
2018-02-06 12:08:43 +01:00
bool fOk = govobj . ProcessVote ( pfrom , vote , exception , connman ) & & cmapVoteToObject . Insert ( nHashVote , & govobj ) ;
2017-07-21 11:47:38 +02:00
LEAVE_CRITICAL_SECTION ( cs ) ;
2016-11-13 18:52:34 +01:00
return fOk ;
}
2017-09-19 16:51:38 +02:00
void CGovernanceManager : : CheckMasternodeOrphanVotes ( CConnman & connman )
2016-11-13 18:52:34 +01:00
{
2017-02-02 00:07:24 +01:00
LOCK2 ( cs_main , cs ) ;
2017-07-05 02:31:50 +02:00
2017-09-15 20:05:03 +02:00
ScopedLockBool guard ( cs , fRateChecksEnabled , false ) ;
2017-07-05 02:31:50 +02:00
2016-11-13 18:52:34 +01:00
for ( object_m_it it = mapObjects . begin ( ) ; it ! = mapObjects . end ( ) ; + + it ) {
2017-09-19 16:51:38 +02:00
it - > second . CheckOrphanVotes ( connman ) ;
2016-11-13 18:52:34 +01:00
}
}
2017-09-19 16:51:38 +02:00
void CGovernanceManager : : CheckMasternodeOrphanObjects ( CConnman & connman )
2016-11-12 02:51:45 +01:00
{
2017-02-02 00:07:24 +01:00
LOCK2 ( cs_main , cs ) ;
2016-11-24 19:12:05 +01:00
int64_t nNow = GetAdjustedTime ( ) ;
2017-09-15 20:05:03 +02:00
ScopedLockBool guard ( cs , fRateChecksEnabled , false ) ;
2017-07-13 11:38:00 +02:00
object_info_m_it it = mapMasternodeOrphanObjects . begin ( ) ;
2016-11-12 02:51:45 +01:00
while ( it ! = mapMasternodeOrphanObjects . end ( ) ) {
2017-07-13 11:38:00 +02:00
object_info_pair_t & pair = it - > second ;
2016-11-24 19:12:05 +01:00
CGovernanceObject & govobj = pair . first ;
2017-07-13 11:38:00 +02:00
if ( pair . second . nExpirationTime > = nNow ) {
2018-02-21 20:26:53 +01:00
std : : string strError ;
2017-07-13 11:38:00 +02:00
bool fMasternodeMissing = false ;
bool fConfirmationsMissing = false ;
bool fIsValid = govobj . IsValidLocally ( strError , fMasternodeMissing , fConfirmationsMissing , true ) ;
2016-11-12 02:51:45 +01:00
2017-07-13 11:38:00 +02:00
if ( fIsValid ) {
2017-09-19 16:51:38 +02:00
AddGovernanceObject ( govobj , connman ) ;
2017-07-13 11:38:00 +02:00
} else if ( fMasternodeMissing ) {
2016-11-12 02:51:45 +01:00
+ + it ;
2017-07-13 11:38:00 +02:00
continue ;
2016-11-12 02:51:45 +01:00
}
2017-07-13 11:38:00 +02:00
} else {
// apply node's ban score
Misbehaving ( pair . second . idFrom , 20 ) ;
2016-11-12 02:51:45 +01:00
}
2018-02-15 08:29:44 +01:00
auto it_count = mapMasternodeOrphanCounter . find ( govobj . GetMasternodeOutpoint ( ) ) ;
2017-07-13 11:38:00 +02:00
if ( - - it_count - > second = = 0 )
mapMasternodeOrphanCounter . erase ( it_count ) ;
2017-07-05 02:31:50 +02:00
mapMasternodeOrphanObjects . erase ( it + + ) ;
}
}
2017-09-19 16:51:38 +02:00
void CGovernanceManager : : CheckPostponedObjects ( CConnman & connman )
2017-07-05 02:31:50 +02:00
{
2017-08-09 18:07:03 +02:00
if ( ! masternodeSync . IsSynced ( ) ) return ;
2017-07-05 02:31:50 +02:00
LOCK2 ( cs_main , cs ) ;
// Check postponed proposals
for ( object_m_it it = mapPostponedObjects . begin ( ) ; it ! = mapPostponedObjects . end ( ) ; ) {
const uint256 & nHash = it - > first ;
CGovernanceObject & govobj = it - > second ;
2018-02-25 06:33:27 +01:00
assert ( govobj . GetObjectType ( ) ! = GOVERNANCE_OBJECT_TRIGGER ) ;
2017-07-05 02:31:50 +02:00
std : : string strError ;
bool fMissingConfirmations ;
if ( govobj . IsCollateralValid ( strError , fMissingConfirmations ) )
{
if ( govobj . IsValidLocally ( strError , false ) )
2017-09-19 16:51:38 +02:00
AddGovernanceObject ( govobj , connman ) ;
2017-07-05 02:31:50 +02:00
else
LogPrintf ( " CGovernanceManager::CheckPostponedObjects -- %s invalid \n " , nHash . ToString ( ) ) ;
} else if ( fMissingConfirmations ) {
// wait for more confirmations
2016-11-12 02:51:45 +01:00
+ + it ;
2017-07-05 02:31:50 +02:00
continue ;
}
// remove processed or invalid object from the queue
mapPostponedObjects . erase ( it + + ) ;
}
2018-02-25 06:33:27 +01:00
// Perform additional relays for triggers
2017-08-29 01:51:44 +02:00
int64_t nNow = GetAdjustedTime ( ) ;
2017-07-05 02:31:50 +02:00
int64_t nSuperblockCycleSeconds = Params ( ) . GetConsensus ( ) . nSuperblockCycle * Params ( ) . GetConsensus ( ) . nPowTargetSpacing ;
for ( hash_s_it it = setAdditionalRelayObjects . begin ( ) ; it ! = setAdditionalRelayObjects . end ( ) ; ) {
object_m_it itObject = mapObjects . find ( * it ) ;
if ( itObject ! = mapObjects . end ( ) ) {
CGovernanceObject & govobj = itObject - > second ;
int64_t nTimestamp = govobj . GetCreationTime ( ) ;
bool fValid = ( nTimestamp < = nNow + MAX_TIME_FUTURE_DEVIATION ) & & ( nTimestamp > = nNow - 2 * nSuperblockCycleSeconds ) ;
bool fReady = ( nTimestamp < = nNow + MAX_TIME_FUTURE_DEVIATION - RELIABLE_PROPAGATION_TIME ) ;
if ( fValid ) {
if ( fReady ) {
LogPrintf ( " CGovernanceManager::CheckPostponedObjects -- additional relay: hash = %s \n " , govobj . GetHash ( ) . ToString ( ) ) ;
2017-09-19 16:51:38 +02:00
govobj . Relay ( connman ) ;
2017-07-05 02:31:50 +02:00
} else {
it + + ;
continue ;
}
}
} else {
LogPrintf ( " CGovernanceManager::CheckPostponedObjects -- additional relay of unknown object: %s \n " , it - > ToString ( ) ) ;
2016-11-12 02:51:45 +01:00
}
2017-07-05 02:31:50 +02:00
setAdditionalRelayObjects . erase ( it + + ) ;
2016-11-12 02:51:45 +01:00
}
}
2017-09-19 16:51:38 +02:00
void CGovernanceManager : : RequestGovernanceObject ( CNode * pfrom , const uint256 & nHash , CConnman & connman , bool fUseFilter )
2016-11-13 18:52:34 +01:00
{
if ( ! pfrom ) {
return ;
}
2017-03-06 08:46:59 +01:00
LogPrint ( " gobject " , " CGovernanceObject::RequestGovernanceObject -- hash = %s (peer=%d) \n " , nHash . ToString ( ) , pfrom - > GetId ( ) ) ;
2016-11-25 20:01:56 +01:00
CNetMsgMaker msgMaker ( pfrom - > GetSendVersion ( ) ) ;
2017-02-02 09:50:44 +01:00
if ( pfrom - > nVersion < GOVERNANCE_FILTER_PROTO_VERSION ) {
2016-11-25 20:01:56 +01:00
connman . PushMessage ( pfrom , msgMaker . Make ( NetMsgType : : MNGOVERNANCESYNC , nHash ) ) ;
2017-02-02 09:50:44 +01:00
return ;
}
CBloomFilter filter ;
filter . clear ( ) ;
2017-06-06 01:47:23 +02:00
int nVoteCount = 0 ;
2017-02-02 09:50:44 +01:00
if ( fUseFilter ) {
2017-03-08 23:36:40 +01:00
LOCK ( cs ) ;
2017-02-02 09:50:44 +01:00
CGovernanceObject * pObj = FindGovernanceObject ( nHash ) ;
if ( pObj ) {
filter = CBloomFilter ( Params ( ) . GetConsensus ( ) . nGovernanceFilterElements , GOVERNANCE_FILTER_FP_RATE , GetRandInt ( 999999 ) , BLOOM_UPDATE_ALL ) ;
std : : vector < CGovernanceVote > vecVotes = pObj - > GetVoteFile ( ) . GetVotes ( ) ;
2017-06-06 01:47:23 +02:00
nVoteCount = vecVotes . size ( ) ;
2017-02-02 09:50:44 +01:00
for ( size_t i = 0 ; i < vecVotes . size ( ) ; + + i ) {
filter . insert ( vecVotes [ i ] . GetHash ( ) ) ;
}
}
}
2017-06-06 01:47:23 +02:00
LogPrint ( " gobject " , " CGovernanceManager::RequestGovernanceObject -- nHash %s nVoteCount %d peer=%d \n " , nHash . ToString ( ) , nVoteCount , pfrom - > id ) ;
2016-11-25 20:01:56 +01:00
connman . PushMessage ( pfrom , msgMaker . Make ( NetMsgType : : MNGOVERNANCESYNC , nHash , filter ) ) ;
2016-11-13 18:52:34 +01:00
}
2017-09-19 16:51:38 +02:00
int CGovernanceManager : : RequestGovernanceObjectVotes ( CNode * pnode , CConnman & connman )
2017-01-17 21:02:38 +01:00
{
2017-02-17 21:08:41 +01:00
if ( pnode - > nVersion < MIN_GOVERNANCE_PEER_PROTO_VERSION ) return - 3 ;
2017-01-17 21:02:38 +01:00
std : : vector < CNode * > vNodesCopy ;
vNodesCopy . push_back ( pnode ) ;
2017-09-19 16:51:38 +02:00
return RequestGovernanceObjectVotes ( vNodesCopy , connman ) ;
2017-01-17 21:02:38 +01:00
}
2017-09-19 16:51:38 +02:00
int CGovernanceManager : : RequestGovernanceObjectVotes ( const std : : vector < CNode * > & vNodesCopy , CConnman & connman )
2017-01-17 21:02:38 +01:00
{
2017-02-02 14:04:45 +01:00
static std : : map < uint256 , std : : map < CService , int64_t > > mapAskedRecently ;
2017-02-17 21:08:41 +01:00
if ( vNodesCopy . empty ( ) ) return - 1 ;
2017-02-02 14:04:45 +01:00
int64_t nNow = GetTime ( ) ;
int nTimeout = 60 * 60 ;
size_t nPeersPerHashMax = 3 ;
2017-03-08 23:36:40 +01:00
std : : vector < CGovernanceObject * > vpGovObjsTmp ;
std : : vector < CGovernanceObject * > vpGovObjsTriggersTmp ;
2017-02-02 14:04:45 +01:00
// This should help us to get some idea about an impact this can bring once deployed on mainnet.
// Testnet is ~40 times smaller in masternode count, but only ~1000 masternodes usually vote,
// so 1 obj on mainnet == ~10 objs or ~1000 votes on testnet. However we want to test a higher
// number of votes to make sure it's robust enough, so aim at 2000 votes per masternode per request.
2017-02-03 10:17:47 +01:00
// On mainnet nMaxObjRequestsPerNode is always set to 1.
int nMaxObjRequestsPerNode = 1 ;
2017-02-02 14:04:45 +01:00
size_t nProjectedVotes = 2000 ;
2017-02-03 10:17:47 +01:00
if ( Params ( ) . NetworkIDString ( ) ! = CBaseChainParams : : MAIN ) {
nMaxObjRequestsPerNode = std : : max ( 1 , int ( nProjectedVotes / std : : max ( 1 , mnodeman . size ( ) ) ) ) ;
}
2017-02-02 14:04:45 +01:00
2017-03-08 23:36:40 +01:00
{
LOCK2 ( cs_main , cs ) ;
2017-02-02 14:04:45 +01:00
2017-03-08 23:36:40 +01:00
if ( mapObjects . empty ( ) ) return - 2 ;
for ( object_m_it it = mapObjects . begin ( ) ; it ! = mapObjects . end ( ) ; + + it ) {
if ( mapAskedRecently . count ( it - > first ) ) {
std : : map < CService , int64_t > : : iterator it1 = mapAskedRecently [ it - > first ] . begin ( ) ;
while ( it1 ! = mapAskedRecently [ it - > first ] . end ( ) ) {
if ( it1 - > second < nNow ) {
mapAskedRecently [ it - > first ] . erase ( it1 + + ) ;
} else {
+ + it1 ;
}
2017-02-02 14:04:45 +01:00
}
2017-03-08 23:36:40 +01:00
if ( mapAskedRecently [ it - > first ] . size ( ) > = nPeersPerHashMax ) continue ;
}
if ( it - > second . nObjectType = = GOVERNANCE_OBJECT_TRIGGER ) {
vpGovObjsTriggersTmp . push_back ( & ( it - > second ) ) ;
} else {
vpGovObjsTmp . push_back ( & ( it - > second ) ) ;
2017-02-02 14:04:45 +01:00
}
}
2017-01-17 21:02:38 +01:00
}
2017-02-02 14:04:45 +01:00
2017-02-17 21:08:41 +01:00
LogPrint ( " gobject " , " CGovernanceManager::RequestGovernanceObjectVotes -- start: vpGovObjsTriggersTmp %d vpGovObjsTmp %d mapAskedRecently %d \n " ,
2017-02-02 14:04:45 +01:00
vpGovObjsTriggersTmp . size ( ) , vpGovObjsTmp . size ( ) , mapAskedRecently . size ( ) ) ;
2018-01-12 16:37:39 +01:00
FastRandomContext insecure_rand ;
2017-02-02 14:04:45 +01:00
// shuffle pointers
2018-01-12 16:37:39 +01:00
std : : random_shuffle ( vpGovObjsTriggersTmp . begin ( ) , vpGovObjsTriggersTmp . end ( ) , insecure_rand ) ;
std : : random_shuffle ( vpGovObjsTmp . begin ( ) , vpGovObjsTmp . end ( ) , insecure_rand ) ;
2017-02-02 14:04:45 +01:00
for ( int i = 0 ; i < nMaxObjRequestsPerNode ; + + i ) {
2017-01-17 21:02:38 +01:00
uint256 nHashGovobj ;
2017-02-02 14:04:45 +01:00
2017-01-17 21:02:38 +01:00
// ask for triggers first
if ( vpGovObjsTriggersTmp . size ( ) ) {
2017-02-02 14:04:45 +01:00
nHashGovobj = vpGovObjsTriggersTmp . back ( ) - > GetHash ( ) ;
} else {
if ( vpGovObjsTmp . empty ( ) ) break ;
nHashGovobj = vpGovObjsTmp . back ( ) - > GetHash ( ) ;
}
bool fAsked = false ;
2018-02-06 12:09:33 +01:00
for ( const auto & pnode : vNodesCopy ) {
2017-07-03 15:14:07 +02:00
// Only use regular peers, don't try to ask from outbound "masternode" connections -
2017-02-16 16:14:42 +01:00
// they stay connected for a short period of time and it's possible that we won't get everything we should.
// Only use outbound connections - inbound connection could be a "masternode" connection
2017-07-03 15:14:07 +02:00
// initiated from another node, so skip it too.
2018-01-26 02:11:01 +01:00
if ( pnode - > fMasternode | | ( fMasternodeMode & & pnode - > fInbound ) ) continue ;
2017-02-02 14:04:45 +01:00
// only use up to date peers
if ( pnode - > nVersion < MIN_GOVERNANCE_PEER_PROTO_VERSION ) continue ;
// stop early to prevent setAskFor overflow
size_t nProjectedSize = pnode - > setAskFor . size ( ) + nProjectedVotes ;
if ( nProjectedSize > SETASKFOR_MAX_SZ / 2 ) continue ;
// to early to ask the same node
if ( mapAskedRecently [ nHashGovobj ] . count ( pnode - > addr ) ) continue ;
2017-09-19 16:51:38 +02:00
RequestGovernanceObject ( pnode , nHashGovobj , connman , true ) ;
2017-02-02 14:04:45 +01:00
mapAskedRecently [ nHashGovobj ] [ pnode - > addr ] = nNow + nTimeout ;
fAsked = true ;
// stop loop if max number of peers per obj was asked
if ( mapAskedRecently [ nHashGovobj ] . size ( ) > = nPeersPerHashMax ) break ;
}
// NOTE: this should match `if` above (the one before `while`)
if ( vpGovObjsTriggersTmp . size ( ) ) {
vpGovObjsTriggersTmp . pop_back ( ) ;
2017-01-17 21:02:38 +01:00
} else {
2017-02-02 14:04:45 +01:00
vpGovObjsTmp . pop_back ( ) ;
2017-01-17 21:02:38 +01:00
}
2017-02-02 14:04:45 +01:00
if ( ! fAsked ) i - - ;
2017-01-17 21:02:38 +01:00
}
2017-02-17 21:08:41 +01:00
LogPrint ( " gobject " , " CGovernanceManager::RequestGovernanceObjectVotes -- end: vpGovObjsTriggersTmp %d vpGovObjsTmp %d mapAskedRecently %d \n " ,
2017-02-02 14:04:45 +01:00
vpGovObjsTriggersTmp . size ( ) , vpGovObjsTmp . size ( ) , mapAskedRecently . size ( ) ) ;
2017-02-17 21:08:41 +01:00
return int ( vpGovObjsTriggersTmp . size ( ) + vpGovObjsTmp . size ( ) ) ;
2017-01-17 21:02:38 +01:00
}
2016-11-13 18:52:34 +01:00
bool CGovernanceManager : : AcceptObjectMessage ( const uint256 & nHash )
{
LOCK ( cs ) ;
return AcceptMessage ( nHash , setRequestedObjects ) ;
}
bool CGovernanceManager : : AcceptVoteMessage ( const uint256 & nHash )
{
LOCK ( cs ) ;
return AcceptMessage ( nHash , setRequestedVotes ) ;
}
bool CGovernanceManager : : AcceptMessage ( const uint256 & nHash , hash_s_t & setHash )
{
hash_s_it it = setHash . find ( nHash ) ;
if ( it = = setHash . end ( ) ) {
// We never requested this
return false ;
}
// Only accept one response
setHash . erase ( it ) ;
return true ;
}
void CGovernanceManager : : RebuildIndexes ( )
{
2018-03-09 15:15:48 +01:00
LOCK ( cs ) ;
2018-02-06 12:08:43 +01:00
cmapVoteToObject . Clear ( ) ;
2016-11-13 18:52:34 +01:00
for ( object_m_it it = mapObjects . begin ( ) ; it ! = mapObjects . end ( ) ; + + it ) {
CGovernanceObject & govobj = it - > second ;
std : : vector < CGovernanceVote > vecVotes = govobj . GetVoteFile ( ) . GetVotes ( ) ;
for ( size_t i = 0 ; i < vecVotes . size ( ) ; + + i ) {
2018-02-06 12:08:43 +01:00
cmapVoteToObject . Insert ( vecVotes [ i ] . GetHash ( ) , & govobj ) ;
2016-11-13 18:52:34 +01:00
}
}
}
2016-11-05 17:13:30 +01:00
void CGovernanceManager : : AddCachedTriggers ( )
{
LOCK ( cs ) ;
for ( object_m_it it = mapObjects . begin ( ) ; it ! = mapObjects . end ( ) ; + + it ) {
CGovernanceObject & govobj = it - > second ;
2017-07-05 02:31:50 +02:00
2016-11-05 17:13:30 +01:00
if ( govobj . nObjectType ! = GOVERNANCE_OBJECT_TRIGGER ) {
continue ;
}
triggerman . AddNewTrigger ( govobj . GetHash ( ) ) ;
2016-11-13 18:52:34 +01:00
}
}
2016-11-28 15:21:50 +01:00
void CGovernanceManager : : InitOnLoad ( )
{
LOCK ( cs ) ;
2016-11-30 02:33:47 +01:00
int64_t nStart = GetTimeMillis ( ) ;
LogPrintf ( " Preparing masternode indexes and governance triggers... \n " ) ;
2016-11-28 15:21:50 +01:00
RebuildIndexes ( ) ;
AddCachedTriggers ( ) ;
2016-11-30 02:33:47 +01:00
LogPrintf ( " Masternode indexes and governance triggers prepared %dms \n " , GetTimeMillis ( ) - nStart ) ;
LogPrintf ( " %s \n " , ToString ( ) ) ;
2016-11-28 15:21:50 +01:00
}
2016-04-09 22:55:52 +02:00
std : : string CGovernanceManager : : ToString ( ) const
2016-04-09 21:57:53 +02:00
{
2016-12-12 02:44:46 +01:00
LOCK ( cs ) ;
int nProposalCount = 0 ;
int nTriggerCount = 0 ;
int nOtherCount = 0 ;
2016-04-09 21:57:53 +02:00
2016-12-12 02:44:46 +01:00
object_m_cit it = mapObjects . begin ( ) ;
while ( it ! = mapObjects . end ( ) ) {
switch ( it - > second . GetObjectType ( ) ) {
case GOVERNANCE_OBJECT_PROPOSAL :
nProposalCount + + ;
break ;
case GOVERNANCE_OBJECT_TRIGGER :
nTriggerCount + + ;
break ;
default :
nOtherCount + + ;
break ;
}
+ + it ;
}
2016-04-09 21:57:53 +02:00
2018-02-25 06:33:27 +01:00
return strprintf ( " Governance Objects: %d (Proposals: %d, Triggers: %d, Other: %d; Erased: %d), Votes: %d " ,
2016-12-12 02:44:46 +01:00
( int ) mapObjects . size ( ) ,
2018-02-25 06:33:27 +01:00
nProposalCount , nTriggerCount , nOtherCount , ( int ) mapErasedGovernanceObjects . size ( ) ,
2018-02-06 12:08:43 +01:00
( int ) cmapVoteToObject . GetSize ( ) ) ;
2016-04-09 21:57:53 +02:00
}
2017-09-19 16:51:38 +02:00
void CGovernanceManager : : UpdatedBlockTip ( const CBlockIndex * pindex , CConnman & connman )
2016-04-09 21:57:53 +02:00
{
2016-08-17 09:08:25 +02:00
// Note this gets called from ActivateBestChain without cs_main being held
// so it should be safe to lock our mutex here without risking a deadlock
2016-09-12 09:40:00 +02:00
// On the other hand it should be safe for us to access pindex without holding a lock
2016-08-17 09:08:25 +02:00
// on cs_main because the CBlockIndex objects are dynamically allocated and
// presumably never deleted.
2016-11-12 12:14:50 +01:00
if ( ! pindex ) {
return ;
}
2017-08-25 14:57:05 +02:00
nCachedBlockHeight = pindex - > nHeight ;
LogPrint ( " gobject " , " CGovernanceManager::UpdatedBlockTip -- nCachedBlockHeight: %d \n " , nCachedBlockHeight ) ;
2017-07-05 02:31:50 +02:00
2017-09-19 16:51:38 +02:00
CheckPostponedObjects ( connman ) ;
2018-02-12 19:35:10 +01:00
CSuperblockManager : : ExecuteBestSuperblock ( pindex - > nHeight ) ;
2017-03-06 08:46:59 +01:00
}
2017-09-19 16:51:38 +02:00
void CGovernanceManager : : RequestOrphanObjects ( CConnman & connman )
2017-03-06 08:46:59 +01:00
{
2018-01-22 14:17:11 +01:00
std : : vector < CNode * > vNodesCopy = connman . CopyNodeVector ( CConnman : : FullyConnectedOnly ) ;
2017-03-06 08:46:59 +01:00
2017-03-08 23:36:40 +01:00
std : : vector < uint256 > vecHashesFiltered ;
2017-03-06 08:46:59 +01:00
{
std : : vector < uint256 > vecHashes ;
2017-03-08 23:36:40 +01:00
LOCK ( cs ) ;
2018-02-06 12:08:43 +01:00
cmmapOrphanVotes . GetKeys ( vecHashes ) ;
2017-03-06 08:46:59 +01:00
for ( size_t i = 0 ; i < vecHashes . size ( ) ; + + i ) {
const uint256 & nHash = vecHashes [ i ] ;
2017-03-08 23:36:40 +01:00
if ( mapObjects . find ( nHash ) = = mapObjects . end ( ) ) {
vecHashesFiltered . push_back ( nHash ) ;
2017-03-06 08:46:59 +01:00
}
2017-03-08 23:36:40 +01:00
}
}
LogPrint ( " gobject " , " CGovernanceObject::RequestOrphanObjects -- number objects = %d \n " , vecHashesFiltered . size ( ) ) ;
for ( size_t i = 0 ; i < vecHashesFiltered . size ( ) ; + + i ) {
const uint256 & nHash = vecHashesFiltered [ i ] ;
for ( size_t j = 0 ; j < vNodesCopy . size ( ) ; + + j ) {
CNode * pnode = vNodesCopy [ j ] ;
if ( pnode - > fMasternode ) {
continue ;
2017-03-06 08:46:59 +01:00
}
2017-09-19 16:51:38 +02:00
RequestGovernanceObject ( pnode , nHash , connman ) ;
2017-03-06 08:46:59 +01:00
}
}
2017-09-19 16:51:38 +02:00
connman . ReleaseNodeVector ( vNodesCopy ) ;
2017-03-06 08:46:59 +01:00
}
void CGovernanceManager : : CleanOrphanObjects ( )
{
2016-08-17 09:08:25 +02:00
LOCK ( cs ) ;
2018-02-06 12:08:43 +01:00
const vote_cmm_t : : list_t & items = cmmapOrphanVotes . GetItemList ( ) ;
2016-08-17 09:08:25 +02:00
2017-03-06 08:46:59 +01:00
int64_t nNow = GetAdjustedTime ( ) ;
2016-04-09 21:57:53 +02:00
2018-02-06 12:08:43 +01:00
vote_cmm_t : : list_cit it = items . begin ( ) ;
2017-03-06 08:46:59 +01:00
while ( it ! = items . end ( ) ) {
2018-02-06 12:08:43 +01:00
vote_cmm_t : : list_cit prevIt = it ;
2017-03-06 08:46:59 +01:00
+ + it ;
const vote_time_pair_t & pairVote = prevIt - > value ;
if ( pairVote . second < nNow ) {
2018-02-06 12:08:43 +01:00
cmmapOrphanVotes . Erase ( prevIt - > key , prevIt - > value ) ;
2017-03-06 08:46:59 +01:00
}
}
2016-04-09 21:57:53 +02:00
}