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"
2016-12-20 14:27:59 +01:00
# include "main.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-02-23 13:29:00 +01:00
const std : : string CGovernanceManager : : SERIALIZATION_VERSION_STRING = " CGovernanceManager-Version-11 " ;
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 ( )
2016-11-13 18:52:34 +01:00
: pCurrentBlockIndex ( NULL ) ,
2016-09-05 01:44:10 +02:00
nTimeLastDiff ( 0 ) ,
nCachedBlockHeight ( 0 ) ,
mapObjects ( ) ,
mapSeenGovernanceObjects ( ) ,
2016-11-12 02:51:45 +01:00
mapMasternodeOrphanObjects ( ) ,
2016-11-25 15:08:48 +01:00
mapWatchdogObjects ( ) ,
2017-02-22 19:29:30 +01:00
nHashWatchdogCurrent ( ) ,
nTimeWatchdogCurrent ( 0 ) ,
2016-11-13 18:52:34 +01:00
mapVoteToObject ( MAX_CACHE_SIZE ) ,
mapInvalidVotes ( MAX_CACHE_SIZE ) ,
mapOrphanVotes ( 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 ;
if ( ! mapVoteToObject . Get ( nHash , pGovobj ) ) {
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 ) ;
return ( int ) mapVoteToObject . GetSize ( ) ;
}
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 ;
if ( ! mapVoteToObject . Get ( nHash , pGovobj ) ) {
return false ;
}
CGovernanceVote vote ;
if ( ! pGovobj - > GetVoteFile ( ) . GetVote ( nHash , vote ) ) {
return false ;
}
ss < < vote ;
return true ;
2016-08-17 09:08:25 +02:00
}
2016-11-13 18:52:34 +01:00
void CGovernanceManager : : AddSeenGovernanceObject ( uint256 nHash , int status )
2016-08-17 09:08:25 +02:00
{
LOCK ( cs ) ;
2016-11-13 18:52:34 +01:00
mapSeenGovernanceObjects [ nHash ] = status ;
2016-08-17 09:08:25 +02:00
}
2016-06-08 08:57:16 +02:00
void CGovernanceManager : : ProcessMessage ( CNode * pfrom , std : : string & strCommand , CDataStream & vRecv )
{
// 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 ( ) ) {
if ( netfulfilledman . HasFulfilledRequest ( pfrom - > addr , NetMsgType : : MNGOVERNANCESYNC ) ) {
// Asking for the whole list multiple times in a short period of time is no good
2016-10-22 18:52:14 +02:00
LogPrint ( " gobject " , " MNGOVERNANCESYNC -- peer already asked me for the list \n " ) ;
2016-09-27 09:50:04 +02:00
Misbehaving ( pfrom - > GetId ( ) , 20 ) ;
return ;
2016-06-08 08:57:16 +02:00
}
2016-09-27 09:50:04 +02:00
netfulfilledman . AddFulfilledRequest ( pfrom - > addr , NetMsgType : : MNGOVERNANCESYNC ) ;
2016-06-08 08:57:16 +02:00
}
2017-02-02 09:50:44 +01:00
Sync ( pfrom , nProp , filter ) ;
2016-10-22 18:52:14 +02:00
LogPrint ( " gobject " , " MNGOVERNANCESYNC -- syncing governance objects to our peer at %s \n " , pfrom - > addr . ToString ( ) ) ;
2016-09-12 09:40:00 +02:00
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
2016-11-12 12:14:50 +01:00
if ( ! pCurrentBlockIndex ) {
2016-12-06 17:40:37 +01:00
LogPrintf ( " MNGOVERNANCEOBJECT -- pCurrentBlockIndex is NULL \n " ) ;
2016-11-12 12:14:50 +01:00
return ;
}
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-06-08 08:57:16 +02:00
CGovernanceObject govobj ;
vRecv > > govobj ;
2016-11-13 18:52:34 +01:00
uint256 nHash = govobj . GetHash ( ) ;
std : : string strHash = nHash . ToString ( ) ;
2017-01-17 21:02:59 +01:00
pfrom - > setAskFor . erase ( nHash ) ;
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
2016-11-13 18:52:34 +01:00
if ( mapSeenGovernanceObjects . 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-04-05 18:30:08 +02:00
if ( ! MasternodeRateCheck ( govobj , UPDATE_FAIL_ONLY , 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 ) ) {
if ( ! MasternodeRateCheck ( govobj , UPDATE_FAIL_ONLY ) ) {
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 ) {
mapMasternodeOrphanObjects . insert ( std : : make_pair ( nHash , object_time_pair_t ( govobj , GetAdjustedTime ( ) + GOVERNANCE_ORPHAN_EXPIRATION_TIME ) ) ) ;
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 ) ;
}
2016-06-08 08:57:16 +02:00
2017-07-05 02:31:50 +02:00
mapSeenGovernanceObjects . insert ( std : : make_pair ( nHash , SEEN_OBJECT_ERROR_INVALID ) ) ;
return ;
2017-03-24 11:34:10 +01:00
}
2017-07-05 02:31:50 +02:00
AddGovernanceObject ( govobj , 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
{
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-06-08 08:57:16 +02:00
CGovernanceVote vote ;
vRecv > > vote ;
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
uint256 nHash = vote . GetHash ( ) ;
std : : string strHash = nHash . ToString ( ) ;
2017-01-17 21:02:59 +01:00
pfrom - > setAskFor . erase ( nHash ) ;
2016-12-06 17:40:37 +01:00
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 ;
if ( ProcessVote ( pfrom , vote , exception ) ) {
2016-12-06 17:40:37 +01:00
LogPrint ( " gobject " , " MNGOVERNANCEOBJECTVOTE -- %s new \n " , strHash ) ;
masternodeSync . AddedGovernanceItem ( ) ;
2016-12-07 05:16:34 +01:00
vote . Relay ( ) ;
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
}
}
}
2016-12-02 13:53:18 +01:00
void CGovernanceManager : : CheckOrphanVotes ( CGovernanceObject & govobj , CGovernanceException & exception )
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 ;
mapOrphanVotes . GetAll ( nHash , vecVotePairs ) ;
2017-07-05 02:31:50 +02:00
CRateChecksGuard guard ( false , * this ) ;
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 ;
}
2016-12-02 13:53:18 +01:00
else if ( govobj . ProcessVote ( NULL , vote , exception ) ) {
2016-12-15 17:27:09 +01:00
vote . Relay ( ) ;
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 ) {
mapOrphanVotes . Erase ( nHash , pairVote ) ;
}
2016-04-09 21:57:53 +02:00
}
2017-07-05 02:31:50 +02:00
}
void CGovernanceManager : : AddGovernanceObject ( CGovernanceObject & govobj , CNode * pfrom )
{
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
bool fAddToSeen = true ;
if ( AddGovernanceObject ( govobj , fAddToSeen , pfrom ) )
{
LogPrintf ( " AddGovernanceObject -- %s new, received form %s \n " , strHash , pfrom ? pfrom - > addrName : " NULL " ) ;
govobj . Relay ( ) ;
}
// PROCESS OBJECT EXACTLY THE SAME WAY AS USUAL
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 ) ;
}
masternodeSync . AddedGovernanceItem ( ) ;
// WE MIGHT HAVE PENDING/ORPHAN VOTES FOR THIS OBJECT
CGovernanceException exception ;
CheckOrphanVotes ( govobj , exception ) ;
2016-04-09 21:57:53 +02:00
}
2017-03-24 11:34:10 +01:00
bool CGovernanceManager : : AddGovernanceObject ( CGovernanceObject & govobj , bool & fAddToSeen , CNode * pfrom )
2016-04-09 21:57:53 +02:00
{
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
DBG ( cout < < " CGovernanceManager::AddGovernanceObject START " < < endl ; ) ;
2017-03-24 11:34:10 +01:00
fAddToSeen = true ;
2016-11-25 15:08:48 +01:00
uint256 nHash = govobj . GetHash ( ) ;
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 ) ;
2016-04-09 21:57:53 +02:00
return false ;
}
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 ( ) ) ;
2016-04-09 21:57:53 +02:00
return false ;
}
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
2017-02-22 19:29:30 +01:00
if ( govobj . nObjectType = = GOVERNANCE_OBJECT_WATCHDOG ) {
// If it's a watchdog, make sure it fits required time bounds
if ( ( govobj . GetCreationTime ( ) < GetAdjustedTime ( ) - GOVERNANCE_WATCHDOG_EXPIRATION_TIME | |
govobj . GetCreationTime ( ) > GetAdjustedTime ( ) + GOVERNANCE_WATCHDOG_EXPIRATION_TIME )
) {
// drop it
LogPrint ( " gobject " , " CGovernanceManager::AddGovernanceObject -- CreationTime is out of bounds: hash = %s \n " , nHash . ToString ( ) ) ;
return false ;
}
if ( ! UpdateCurrentWatchdog ( govobj ) ) {
2017-03-24 11:34:10 +01:00
// Allow wd's which are not current to be reprocessed
fAddToSeen = false ;
2017-02-22 19:29:30 +01:00
if ( pfrom & & ( nHashWatchdogCurrent ! = uint256 ( ) ) ) {
pfrom - > PushInventory ( CInv ( MSG_GOVERNANCE_OBJECT , nHashWatchdogCurrent ) ) ;
}
LogPrint ( " gobject " , " CGovernanceManager::AddGovernanceObject -- Watchdog not better than current: hash = %s \n " , nHash . ToString ( ) ) ;
return false ;
}
2017-02-17 01:48:42 +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?
DBG ( cout < < " CGovernanceManager::AddGovernanceObject Before trigger block, strData = "
< < govobj . GetDataAsString ( )
< < " , nObjectType = " < < govobj . nObjectType
< < endl ; ) ;
2016-10-17 20:54:28 +02:00
switch ( govobj . nObjectType ) {
case GOVERNANCE_OBJECT_TRIGGER :
2016-08-17 09:08:25 +02:00
DBG ( cout < < " CGovernanceManager::AddGovernanceObject Before AddNewTrigger " < < endl ; ) ;
2016-11-25 15:08:48 +01:00
triggerman . AddNewTrigger ( nHash ) ;
2016-08-17 09:08:25 +02:00
DBG ( cout < < " CGovernanceManager::AddGovernanceObject After AddNewTrigger " < < endl ; ) ;
2016-10-17 20:54:28 +02:00
break ;
2016-11-25 15:08:48 +01:00
case GOVERNANCE_OBJECT_WATCHDOG :
2017-02-17 01:48:42 +01:00
mapWatchdogObjects [ nHash ] = govobj . GetCreationTime ( ) + GOVERNANCE_WATCHDOG_EXPIRATION_TIME ;
LogPrint ( " gobject " , " CGovernanceManager::AddGovernanceObject -- Added watchdog to map: hash = %s \n " , nHash . ToString ( ) ) ;
2016-11-25 15:08:48 +01:00
break ;
2016-10-17 20:54:28 +02:00
default :
break ;
2016-08-17 09:08:25 +02:00
}
DBG ( cout < < " CGovernanceManager::AddGovernanceObject END " < < endl ; ) ;
2016-04-09 21:57:53 +02:00
return true ;
}
2017-02-22 19:29:30 +01:00
bool CGovernanceManager : : UpdateCurrentWatchdog ( CGovernanceObject & watchdogNew )
{
bool fAccept = false ;
arith_uint256 nHashNew = UintToArith256 ( watchdogNew . GetHash ( ) ) ;
arith_uint256 nHashCurrent = UintToArith256 ( nHashWatchdogCurrent ) ;
int64_t nExpirationDelay = GOVERNANCE_WATCHDOG_EXPIRATION_TIME / 2 ;
int64_t nNow = GetTime ( ) ;
2017-02-23 18:23:30 +01:00
if ( nHashWatchdogCurrent = = uint256 ( ) | | // no known current OR
( ( nNow - watchdogNew . GetCreationTime ( ) < nExpirationDelay ) & & // (new one is NOT expired AND
( ( nNow - nTimeWatchdogCurrent > nExpirationDelay ) | | ( nHashNew > nHashCurrent ) ) ) // (current is expired OR
// its hash is lower))
) {
2017-02-22 19:29:30 +01:00
LOCK ( cs ) ;
object_m_it it = mapObjects . find ( nHashWatchdogCurrent ) ;
if ( it ! = mapObjects . end ( ) ) {
LogPrint ( " gobject " , " CGovernanceManager::UpdateCurrentWatchdog -- Expiring previous current watchdog, hash = %s \n " , nHashWatchdogCurrent . ToString ( ) ) ;
it - > second . fExpired = true ;
if ( it - > second . nDeletionTime = = 0 ) {
it - > second . nDeletionTime = nNow ;
}
}
nHashWatchdogCurrent = watchdogNew . GetHash ( ) ;
nTimeWatchdogCurrent = watchdogNew . GetCreationTime ( ) ;
fAccept = true ;
LogPrint ( " gobject " , " CGovernanceManager::UpdateCurrentWatchdog -- Current watchdog updated to: hash = %s \n " ,
ArithToUint256 ( nHashNew ) . ToString ( ) ) ;
}
return fAccept ;
}
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 ( ) ;
2016-08-17 09:08:25 +02:00
LOCK ( cs ) ;
2016-04-09 21:57:53 +02:00
2016-11-25 15:08:48 +01:00
// Flag expired watchdogs for removal
int64_t nNow = GetAdjustedTime ( ) ;
2016-12-14 16:27:46 +01:00
LogPrint ( " gobject " , " CGovernanceManager::UpdateCachesAndClean -- Number watchdogs in map: %d, current time = %d \n " , mapWatchdogObjects . size ( ) , nNow ) ;
2016-11-25 15:08:48 +01:00
if ( mapWatchdogObjects . size ( ) > 1 ) {
hash_time_m_it it = mapWatchdogObjects . begin ( ) ;
while ( it ! = mapWatchdogObjects . end ( ) ) {
2016-12-14 16:27:46 +01:00
LogPrint ( " gobject " , " CGovernanceManager::UpdateCachesAndClean -- Checking watchdog: %s, expiration time = %d \n " , it - > first . ToString ( ) , it - > second ) ;
2016-11-25 15:08:48 +01:00
if ( it - > second < nNow ) {
2016-12-14 16:27:46 +01:00
LogPrint ( " gobject " , " CGovernanceManager::UpdateCachesAndClean -- Attempting to expire watchdog: %s, expiration time = %d \n " , it - > first . ToString ( ) , it - > second ) ;
2016-11-25 15:08:48 +01:00
object_m_it it2 = mapObjects . find ( it - > first ) ;
if ( it2 ! = mapObjects . end ( ) ) {
2016-12-14 16:27:46 +01:00
LogPrint ( " gobject " , " CGovernanceManager::UpdateCachesAndClean -- Expiring watchdog: %s, expiration time = %d \n " , it - > first . ToString ( ) , it - > second ) ;
2016-11-25 15:08:48 +01:00
it2 - > second . fExpired = true ;
2016-12-14 16:27:46 +01:00
if ( it2 - > second . nDeletionTime = = 0 ) {
it2 - > second . nDeletionTime = nNow ;
}
2016-11-25 15:08:48 +01:00
}
2017-02-22 19:29:30 +01:00
if ( it - > first = = nHashWatchdogCurrent ) {
nHashWatchdogCurrent = uint256 ( ) ;
}
2016-11-25 15:08:48 +01:00
mapWatchdogObjects . erase ( it + + ) ;
}
else {
+ + it ;
}
}
}
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 ;
}
2016-06-10 07:16:32 +02:00
// DOUBLE CHECK THAT WE HAVE A VALID POINTER TO TIP
if ( ! pCurrentBlockIndex ) return ;
2017-07-05 02:31:50 +02:00
CRateChecksGuard guard ( false , * this ) ;
2016-12-04 21:33:39 +01:00
2016-11-05 17:13:30 +01:00
LogPrint ( " gobject " , " CGovernanceManager::UpdateCachesAndClean -- After pCurrentBlockIndex (not NULL) \n " ) ;
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 ( ) ;
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
2017-02-22 19:29:30 +01:00
if ( pObj - > IsSetCachedDelete ( ) & & ( nHash = = nHashWatchdogCurrent ) ) {
nHashWatchdogCurrent = uint256 ( ) ;
}
2016-08-17 09:08:25 +02:00
// IF DELETE=TRUE, THEN CLEAN THE MESS UP!
2016-05-24 20:11:59 +02:00
2016-11-18 15:17:00 +01:00
int64_t nTimeSinceDeletion = GetAdjustedTime ( ) - pObj - > GetDeletionTime ( ) ;
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
const object_ref_cache_t : : list_t & listItems = mapVoteToObject . GetItemList ( ) ;
object_ref_cache_t : : list_cit lit = listItems . begin ( ) ;
while ( lit ! = listItems . end ( ) ) {
if ( lit - > value = = pObj ) {
uint256 nKey = lit - > key ;
+ + lit ;
mapVoteToObject . Erase ( nKey ) ;
}
else {
+ + lit ;
}
}
2017-02-22 19:29:30 +01:00
if ( pObj - > nObjectType = = GOVERNANCE_OBJECT_WATCHDOG ) {
2017-02-17 01:48:42 +01:00
mapWatchdogObjects . erase ( it - > first ) ;
}
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-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
}
2016-11-22 20:26:36 +01:00
std : : vector < CGovernanceVote > CGovernanceManager : : GetCurrentVotes ( const uint256 & nParentHash , const CTxIn & mnCollateralOutpointFilter )
{
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 ;
// Compile a list of Masternode collateral outpoints for which to get votes
std : : vector < CTxIn > vecMNTxIn ;
if ( mnCollateralOutpointFilter = = CTxIn ( ) ) {
std : : vector < CMasternode > mnlist = mnodeman . GetFullMasternodeVector ( ) ;
for ( std : : vector < CMasternode > : : iterator it = mnlist . begin ( ) ; it ! = mnlist . end ( ) ; + + it )
{
vecMNTxIn . push_back ( it - > vin ) ;
}
}
else {
vecMNTxIn . push_back ( mnCollateralOutpointFilter ) ;
}
// Loop thru each MN collateral outpoint and get the votes for the `nParentHash` governance object
for ( std : : vector < CTxIn > : : iterator it = vecMNTxIn . begin ( ) ; it ! = vecMNTxIn . end ( ) ; + + it )
{
CTxIn & mnCollateralOutpoint = * it ;
// get a vote_rec_t from the govobj
vote_rec_t voteRecord ;
if ( ! govobj . GetCurrentMNVotes ( mnCollateralOutpoint , voteRecord ) ) continue ;
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
CGovernanceVote vote = CGovernanceVote ( mnCollateralOutpoint , 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-03-06 08:46:59 +01:00
void CGovernanceManager : : DoMaintenance ( )
2016-04-09 21:57:53 +02:00
{
2017-03-06 08:46:59 +01:00
// NOTHING TO DO IN LITEMODE
if ( fLiteMode ) {
return ;
}
2016-08-17 09:08:25 +02:00
// IF WE'RE NOT SYNCED, EXIT
if ( ! masternodeSync . IsSynced ( ) ) return ;
2016-04-09 21:57:53 +02:00
2017-01-09 16:09:42 +01:00
if ( ! pCurrentBlockIndex ) 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 ( ) ;
RequestOrphanObjects ( ) ;
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 )
{
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 :
{
if ( mapVoteToObject . HasKey ( inv . hash ) ) {
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 " ) ;
}
2017-02-02 09:50:44 +01:00
// Keep sync alive
masternodeSync . AddedGovernanceItem ( ) ;
2016-11-13 18:52:34 +01:00
LogPrint ( " gobject " , " CGovernanceManager::ConfirmInventoryRequest reached end, returning true \n " ) ;
return true ;
}
2017-02-02 09:50:44 +01:00
void CGovernanceManager : : Sync ( CNode * pfrom , const uint256 & nProp , const CBloomFilter & filter )
2016-04-09 21:57:53 +02:00
{
/*
This code checks each of the hash maps for all known budget proposals and finalized budget proposals , then checks them against the
budget object to see if they ' re OK . If all checks pass , we ' ll send it to the peer .
*/
2017-02-16 16:14:42 +01:00
// do not provide any data until our node is synced
if ( fMasterNode & & ! masternodeSync . IsSynced ( ) ) return ;
2016-12-06 17:40:37 +01:00
int nObjCount = 0 ;
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
2016-12-04 21:33:39 +01:00
LogPrint ( " gobject " , " CGovernanceManager::Sync -- syncing to peer=%d, nProp = %s \n " , pfrom - > id , nProp . ToString ( ) ) ;
2016-08-17 09:08:25 +02:00
{
2017-01-09 16:09:42 +01:00
LOCK2 ( cs_main , cs ) ;
2016-11-13 18:52:34 +01:00
2017-01-17 21:02:38 +01:00
if ( nProp = = uint256 ( ) ) {
// 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 ( ) ;
2016-12-04 21:33:39 +01:00
2017-01-17 21:02:38 +01:00
LogPrint ( " gobject " , " CGovernanceManager::Sync -- attempting to sync govobj: %s, peer=%d \n " , strHash , pfrom - > id ) ;
2016-12-06 17:40:37 +01:00
2017-02-17 01:48:42 +01:00
if ( govobj . IsSetCachedDelete ( ) | | govobj . IsSetExpired ( ) ) {
LogPrintf ( " CGovernanceManager::Sync -- not syncing deleted/expired govobj: %s, peer=%d \n " ,
2017-01-18 16:24:04 +01:00
strHash , pfrom - > id ) ;
2017-01-17 21:02:38 +01:00
continue ;
}
2016-12-04 21:33:39 +01:00
2017-01-17 21:02:38 +01:00
// Push the inventory budget proposal message over to the other client
LogPrint ( " gobject " , " CGovernanceManager::Sync -- syncing govobj: %s, peer=%d \n " , strHash , pfrom - > id ) ;
pfrom - > PushInventory ( CInv ( MSG_GOVERNANCE_OBJECT , it - > first ) ) ;
+ + nObjCount ;
2016-12-04 21:33:39 +01:00
}
2017-01-17 21:02:38 +01:00
} else {
// single valid object and its valid votes
object_m_it it = mapObjects . find ( nProp ) ;
if ( it = = mapObjects . end ( ) ) {
LogPrint ( " gobject " , " CGovernanceManager::Sync -- no matching object for hash %s, peer=%d \n " , nProp . ToString ( ) , pfrom - > id ) ;
return ;
}
CGovernanceObject & govobj = it - > second ;
std : : string strHash = it - > first . ToString ( ) ;
LogPrint ( " gobject " , " CGovernanceManager::Sync -- attempting to sync govobj: %s, peer=%d \n " , strHash , pfrom - > id ) ;
2016-12-04 21:33:39 +01:00
2017-02-17 01:48:42 +01:00
if ( govobj . IsSetCachedDelete ( ) | | govobj . IsSetExpired ( ) ) {
LogPrintf ( " CGovernanceManager::Sync -- not syncing deleted/expired govobj: %s, peer=%d \n " ,
2017-01-18 16:24:04 +01:00
strHash , pfrom - > id ) ;
2017-01-17 21:02:38 +01:00
return ;
2016-12-04 21:33:39 +01:00
}
// Push the inventory budget proposal message over to the other client
2016-12-06 17:40:37 +01:00
LogPrint ( " gobject " , " CGovernanceManager::Sync -- syncing govobj: %s, peer=%d \n " , strHash , pfrom - > id ) ;
2017-01-17 21:02:38 +01:00
pfrom - > PushInventory ( CInv ( MSG_GOVERNANCE_OBJECT , it - > first ) ) ;
2016-12-06 17:40:37 +01:00
+ + nObjCount ;
2016-11-13 18:52:34 +01:00
2016-12-04 21:33:39 +01:00
std : : vector < CGovernanceVote > vecVotes = govobj . GetVoteFile ( ) . GetVotes ( ) ;
for ( size_t i = 0 ; i < vecVotes . size ( ) ; + + i ) {
if ( ! vecVotes [ i ] . IsValid ( true ) ) {
continue ;
2016-11-13 18:52:34 +01:00
}
2017-02-02 09:50:44 +01:00
if ( filter . contains ( vecVotes [ i ] . GetHash ( ) ) ) {
continue ;
}
2016-12-04 21:33:39 +01:00
pfrom - > PushInventory ( CInv ( MSG_GOVERNANCE_OBJECT_VOTE , vecVotes [ i ] . GetHash ( ) ) ) ;
2016-12-06 17:40:37 +01:00
+ + nVoteCount ;
2016-11-13 18:52:34 +01:00
}
}
2016-04-14 00:41:40 +02:00
}
2016-12-06 17:40:37 +01:00
pfrom - > PushMessage ( NetMsgType : : SYNCSTATUSCOUNT , MASTERNODE_SYNC_GOVOBJ , nObjCount ) ;
pfrom - > PushMessage ( NetMsgType : : SYNCSTATUSCOUNT , MASTERNODE_SYNC_GOVOBJ_VOTE , nVoteCount ) ;
LogPrintf ( " CGovernanceManager::Sync -- sent %d objects and %d votes to peer=%d \n " , nObjCount , nVoteCount , pfrom - > id ) ;
2016-04-09 21:57:53 +02:00
}
2017-04-05 18:30:08 +02:00
bool CGovernanceManager : : MasternodeRateCheck ( const CGovernanceObject & govobj , update_mode_enum_t eUpdateLast )
2016-12-11 07:17:38 +01:00
{
2017-07-05 02:31:50 +02:00
bool fRateCheckBypassed ;
2017-04-05 18:30:08 +02:00
return MasternodeRateCheck ( govobj , eUpdateLast , true , fRateCheckBypassed ) ;
2016-12-11 07:17:38 +01:00
}
2017-04-05 18:30:08 +02:00
bool CGovernanceManager : : MasternodeRateCheck ( const CGovernanceObject & govobj , update_mode_enum_t eUpdateLast , 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 ;
}
2016-12-08 21:00:49 +01:00
int nObjectType = govobj . GetObjectType ( ) ;
if ( ( nObjectType ! = GOVERNANCE_OBJECT_TRIGGER ) & & ( nObjectType ! = GOVERNANCE_OBJECT_WATCHDOG ) ) {
return true ;
}
2016-12-11 07:17:38 +01:00
int64_t nTimestamp = govobj . GetCreationTime ( ) ;
int64_t nNow = GetTime ( ) ;
int64_t nSuperblockCycleSeconds = Params ( ) . GetConsensus ( ) . nSuperblockCycle * Params ( ) . GetConsensus ( ) . nPowTargetSpacing ;
2016-12-08 21:00:49 +01:00
const CTxIn & vin = govobj . GetMasternodeVin ( ) ;
txout_m_it it = mapLastMasternodeObject . find ( vin . prevout ) ;
if ( it = = mapLastMasternodeObject . end ( ) ) {
2017-04-05 18:30:08 +02:00
if ( eUpdateLast = = UPDATE_TRUE ) {
2016-12-14 16:28:55 +01:00
it = mapLastMasternodeObject . insert ( txout_m_t : : value_type ( vin . prevout , last_object_rec ( true ) ) ) . first ;
2016-12-08 21:00:49 +01:00
switch ( nObjectType ) {
case GOVERNANCE_OBJECT_TRIGGER :
2016-12-14 16:28:55 +01:00
it - > second . triggerBuffer . AddTimestamp ( nTimestamp ) ;
2016-12-08 21:00:49 +01:00
break ;
case GOVERNANCE_OBJECT_WATCHDOG :
2016-12-14 16:28:55 +01:00
it - > second . watchdogBuffer . AddTimestamp ( nTimestamp ) ;
2016-12-08 21:00:49 +01:00
break ;
default :
break ;
}
}
return true ;
}
2016-12-11 07:17:38 +01:00
if ( it - > second . fStatusOK & & ! fForce ) {
fRateCheckBypassed = true ;
return true ;
}
std : : string strHash = govobj . GetHash ( ) . ToString ( ) ;
if ( nTimestamp < nNow - 2 * nSuperblockCycleSeconds ) {
LogPrintf ( " CGovernanceManager::MasternodeRateCheck -- object %s rejected due to too old timestamp, masternode vin = %s, timestamp = %d, current time = %d \n " ,
strHash , vin . prevout . ToStringShort ( ) , nTimestamp , nNow ) ;
return false ;
}
2017-07-05 02:31:50 +02:00
bool fAdditionalRelay = false ;
if ( nTimestamp > nNow + MAX_TIME_FUTURE_DEVIATION ) {
2016-12-11 07:17:38 +01:00
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 ;
2017-07-05 02:31:50 +02:00
} else if ( nTimestamp > nNow + MAX_TIME_FUTURE_DEVIATION - RELIABLE_PROPAGATION_TIME ) {
// schedule additional relay for the object
fAdditionalRelay = true ;
2016-12-11 07:17:38 +01:00
}
2017-07-05 02:31:50 +02:00
2016-12-14 16:28:55 +01:00
double dMaxRate = 1.1 / nSuperblockCycleSeconds ;
double dRate = 0.0 ;
CRateCheckBuffer buffer ;
2017-04-05 18:30:08 +02:00
CRateCheckBuffer * pBuffer = NULL ;
2016-10-17 20:54:28 +02:00
switch ( nObjectType ) {
case GOVERNANCE_OBJECT_TRIGGER :
2016-12-08 21:00:49 +01:00
// Allow 1 trigger per mn per cycle, with a small fudge factor
2017-04-05 18:30:08 +02:00
pBuffer = & it - > second . triggerBuffer ;
2016-12-15 17:27:09 +01:00
dMaxRate = 2 * 1.1 / double ( nSuperblockCycleSeconds ) ;
2016-10-17 20:54:28 +02:00
break ;
case GOVERNANCE_OBJECT_WATCHDOG :
2017-04-05 18:30:08 +02:00
pBuffer = & it - > second . watchdogBuffer ;
2016-12-15 17:27:09 +01:00
dMaxRate = 2 * 1.1 / 3600. ;
2016-10-17 20:54:28 +02:00
break ;
default :
break ;
}
2017-04-05 18:30:08 +02:00
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 ;
2016-09-05 01:44:10 +02:00
}
2017-04-05 18:30:08 +02:00
buffer = * pBuffer ;
buffer . AddTimestamp ( nTimestamp ) ;
dRate = buffer . GetRate ( ) ;
bool fRateOK = ( dRate < dMaxRate ) ;
2017-07-05 02:31:50 +02:00
if ( eUpdateLast = = UPDATE_TRUE & & fAdditionalRelay )
setAdditionalRelayObjects . insert ( govobj . GetHash ( ) ) ;
2017-04-05 18:30:08 +02:00
switch ( eUpdateLast ) {
case UPDATE_TRUE :
pBuffer - > AddTimestamp ( nTimestamp ) ;
it - > second . fStatusOK = fRateOK ;
break ;
case UPDATE_FAIL_ONLY :
if ( ! fRateOK ) {
pBuffer - > AddTimestamp ( nTimestamp ) ;
2016-12-11 07:17:38 +01:00
it - > second . fStatusOK = false ;
}
2017-04-05 18:30:08 +02:00
default :
return true ;
2016-12-11 07:17:38 +01:00
}
2016-09-15 08:49:24 +02:00
2017-04-05 18:30:08 +02:00
if ( fRateOK ) {
return true ;
}
else {
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 ) ;
}
2016-09-05 01:44:10 +02:00
return false ;
}
2016-11-13 18:52:34 +01:00
bool CGovernanceManager : : ProcessVote ( CNode * pfrom , const CGovernanceVote & vote , CGovernanceException & exception )
{
LOCK ( cs ) ;
uint256 nHashVote = vote . GetHash ( ) ;
if ( mapInvalidVotes . HasKey ( nHashVote ) ) {
std : : ostringstream ostr ;
ostr < < " CGovernanceManager::ProcessVote -- Old invalid vote "
< < " , MN outpoint = " < < vote . GetVinMasternode ( ) . prevout . ToStringShort ( )
2017-06-06 01:47:23 +02:00
< < " , governance object hash = " < < vote . GetParentHash ( ) . ToString ( ) ;
LogPrintf ( " %s \n " , ostr . str ( ) ) ;
2016-11-13 18:52:34 +01:00
exception = CGovernanceException ( ostr . str ( ) , GOVERNANCE_EXCEPTION_PERMANENT_ERROR , 20 ) ;
return false ;
}
uint256 nHashGovobj = vote . GetParentHash ( ) ;
object_m_it it = mapObjects . find ( nHashGovobj ) ;
if ( it = = mapObjects . end ( ) ) {
2016-11-14 21:26:53 +01:00
std : : ostringstream ostr ;
ostr < < " CGovernanceManager::ProcessVote -- Unknown parent object "
< < " , MN outpoint = " < < vote . GetVinMasternode ( ) . prevout . ToStringShort ( )
2017-06-06 01:47:23 +02:00
< < " , governance object hash = " < < vote . GetParentHash ( ) . ToString ( ) ;
2016-11-14 21:26:53 +01:00
exception = CGovernanceException ( ostr . str ( ) , GOVERNANCE_EXCEPTION_WARNING ) ;
2016-11-24 19:12:05 +01:00
if ( mapOrphanVotes . Insert ( nHashGovobj , vote_time_pair_t ( vote , GetAdjustedTime ( ) + GOVERNANCE_ORPHAN_EXPIRATION_TIME ) ) ) {
2016-11-14 19:22:50 +01:00
RequestGovernanceObject ( pfrom , nHashGovobj ) ;
2017-06-06 01:47:23 +02:00
LogPrintf ( " %s \n " , ostr . str ( ) ) ;
2016-11-14 21:26:53 +01:00
}
else {
2017-06-06 01:47:23 +02:00
LogPrint ( " gobject " , " %s \n " , ostr . str ( ) ) ;
2016-11-14 19:22:50 +01:00
}
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 ( ) ) ;
return false ;
}
2016-11-13 18:52:34 +01:00
bool fOk = govobj . ProcessVote ( pfrom , vote , exception ) ;
if ( fOk ) {
2016-12-06 17:40:37 +01:00
mapVoteToObject . Insert ( nHashVote , & govobj ) ;
2016-11-13 18:52:34 +01:00
if ( govobj . GetObjectType ( ) = = GOVERNANCE_OBJECT_WATCHDOG ) {
mnodeman . UpdateWatchdogVoteTime ( vote . GetVinMasternode ( ) ) ;
2017-06-06 01:47:23 +02:00
LogPrint ( " gobject " , " CGovernanceObject::ProcessVote -- GOVERNANCE_OBJECT_WATCHDOG vote for %s \n " , vote . GetParentHash ( ) . ToString ( ) ) ;
2016-11-13 18:52:34 +01:00
}
}
return fOk ;
}
void CGovernanceManager : : CheckMasternodeOrphanVotes ( )
{
2017-02-02 00:07:24 +01:00
LOCK2 ( cs_main , cs ) ;
2017-07-05 02:31:50 +02:00
CRateChecksGuard guard ( false , * this ) ;
2016-11-13 18:52:34 +01:00
for ( object_m_it it = mapObjects . begin ( ) ; it ! = mapObjects . end ( ) ; + + it ) {
it - > second . CheckOrphanVotes ( ) ;
}
}
2016-11-12 02:51:45 +01:00
void CGovernanceManager : : CheckMasternodeOrphanObjects ( )
{
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-07-05 02:31:50 +02:00
CRateChecksGuard guard ( false , * this ) ;
2016-11-24 19:12:05 +01:00
object_time_m_it it = mapMasternodeOrphanObjects . begin ( ) ;
2016-11-12 02:51:45 +01:00
while ( it ! = mapMasternodeOrphanObjects . end ( ) ) {
2016-11-24 19:12:05 +01:00
object_time_pair_t & pair = it - > second ;
CGovernanceObject & govobj = pair . first ;
if ( pair . second < nNow ) {
mapMasternodeOrphanObjects . erase ( it + + ) ;
continue ;
}
2016-11-12 02:51:45 +01:00
string strError ;
bool fMasternodeMissing = false ;
2017-07-05 02:31:50 +02:00
bool fConfirmationsMissing = false ;
bool fIsValid = govobj . IsValidLocally ( strError , fMasternodeMissing , fConfirmationsMissing , true ) ;
2016-11-12 02:51:45 +01:00
if ( ! fIsValid ) {
if ( ! fMasternodeMissing ) {
mapMasternodeOrphanObjects . erase ( it + + ) ;
}
else {
+ + it ;
}
2016-11-16 23:28:10 +01:00
continue ;
2016-11-12 02:51:45 +01:00
}
2017-07-05 02:31:50 +02:00
AddGovernanceObject ( govobj ) ;
mapMasternodeOrphanObjects . erase ( it + + ) ;
}
}
void CGovernanceManager : : CheckPostponedObjects ( )
{
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 ;
assert ( govobj . GetObjectType ( ) ! = GOVERNANCE_OBJECT_WATCHDOG & &
govobj . GetObjectType ( ) ! = GOVERNANCE_OBJECT_TRIGGER ) ;
std : : string strError ;
bool fMissingConfirmations ;
if ( govobj . IsCollateralValid ( strError , fMissingConfirmations ) )
{
if ( govobj . IsValidLocally ( strError , false ) )
AddGovernanceObject ( govobj ) ;
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 + + ) ;
}
// Perform additional relays for triggers/watchdogs
int64_t nNow = GetTime ( ) ;
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 ( ) ) ;
govobj . Relay ( ) ;
} 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-02-02 09:50:44 +01:00
void CGovernanceManager : : RequestGovernanceObject ( CNode * pfrom , const uint256 & nHash , 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 ( ) ) ;
2017-02-02 09:50:44 +01:00
if ( pfrom - > nVersion < GOVERNANCE_FILTER_PROTO_VERSION ) {
pfrom - > PushMessage ( NetMsgType : : MNGOVERNANCESYNC , nHash ) ;
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 ) ;
2017-02-02 09:50:44 +01:00
pfrom - > PushMessage ( NetMsgType : : MNGOVERNANCESYNC , nHash , filter ) ;
2016-11-13 18:52:34 +01:00
}
2017-02-17 21:08:41 +01:00
int CGovernanceManager : : RequestGovernanceObjectVotes ( CNode * pnode )
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-02-17 21:08:41 +01:00
return RequestGovernanceObjectVotes ( vNodesCopy ) ;
2017-01-17 21:02:38 +01:00
}
2017-02-17 21:08:41 +01:00
int CGovernanceManager : : RequestGovernanceObjectVotes ( const std : : vector < CNode * > & vNodesCopy )
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 ( ) ) ;
InsecureRand insecureRand ;
// shuffle pointers
std : : random_shuffle ( vpGovObjsTriggersTmp . begin ( ) , vpGovObjsTriggersTmp . end ( ) , insecureRand ) ;
std : : random_shuffle ( vpGovObjsTmp . begin ( ) , vpGovObjsTmp . end ( ) , insecureRand ) ;
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 ;
BOOST_FOREACH ( CNode * 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.
2017-02-16 16:14:42 +01:00
if ( pnode - > fMasternode | | ( fMasterNode & & 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 ;
RequestGovernanceObject ( pnode , nHashGovobj , true ) ;
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 ( )
{
mapVoteToObject . Clear ( ) ;
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 ) {
mapVoteToObject . Insert ( vecVotes [ i ] . GetHash ( ) , & govobj ) ;
}
}
}
int CGovernanceManager : : GetMasternodeIndex ( const CTxIn & masternodeVin )
{
LOCK ( cs ) ;
bool fIndexRebuilt = false ;
int nMNIndex = mnodeman . GetMasternodeIndex ( masternodeVin , fIndexRebuilt ) ;
2017-02-05 10:24:34 +01:00
if ( fIndexRebuilt ) {
2016-11-13 18:52:34 +01:00
RebuildVoteMaps ( ) ;
nMNIndex = mnodeman . GetMasternodeIndex ( masternodeVin , fIndexRebuilt ) ;
2017-02-05 10:24:34 +01:00
if ( fIndexRebuilt ) {
LogPrintf ( " CGovernanceManager::GetMasternodeIndex -- WARNING: vote map rebuild failed \n " ) ;
}
2016-11-13 18:52:34 +01:00
}
return nMNIndex ;
}
void CGovernanceManager : : RebuildVoteMaps ( )
{
for ( object_m_it it = mapObjects . begin ( ) ; it ! = mapObjects . end ( ) ; + + it ) {
it - > second . RebuildVoteMap ( ) ;
}
2017-02-05 10:24:34 +01:00
mnodeman . ClearOldMasternodeIndex ( ) ;
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 nWatchdogCount = 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 ;
case GOVERNANCE_OBJECT_WATCHDOG :
nWatchdogCount + + ;
break ;
default :
nOtherCount + + ;
break ;
}
+ + it ;
}
2016-04-09 21:57:53 +02:00
2017-02-17 01:48:42 +01:00
return strprintf ( " Governance Objects: %d (Proposals: %d, Triggers: %d, Watchdogs: %d/%d, Other: %d; Seen: %d), Votes: %d " ,
2016-12-12 02:44:46 +01:00
( int ) mapObjects . size ( ) ,
2017-02-17 01:48:42 +01:00
nProposalCount , nTriggerCount , nWatchdogCount , mapWatchdogObjects . size ( ) , nOtherCount , ( int ) mapSeenGovernanceObjects . size ( ) ,
2016-12-12 02:44:46 +01:00
( int ) mapVoteToObject . GetSize ( ) ) ;
2016-04-09 21:57:53 +02:00
}
2016-04-09 22:55:52 +02:00
void CGovernanceManager : : UpdatedBlockTip ( const CBlockIndex * pindex )
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-03-06 08:46:59 +01:00
{
LOCK ( cs ) ;
pCurrentBlockIndex = pindex ;
nCachedBlockHeight = pCurrentBlockIndex - > nHeight ;
LogPrint ( " gobject " , " CGovernanceManager::UpdatedBlockTip pCurrentBlockIndex->nHeight: %d \n " , pCurrentBlockIndex - > nHeight ) ;
}
2017-07-05 02:31:50 +02:00
CheckPostponedObjects ( ) ;
2017-03-06 08:46:59 +01:00
}
void CGovernanceManager : : RequestOrphanObjects ( )
{
std : : vector < CNode * > vNodesCopy = CopyNodeVector ( ) ;
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 ) ;
2017-03-06 08:46:59 +01:00
mapOrphanVotes . GetKeys ( vecHashes ) ;
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-03-08 23:36:40 +01:00
RequestGovernanceObject ( pnode , nHash ) ;
2017-03-06 08:46:59 +01:00
}
}
ReleaseNodeVector ( vNodesCopy ) ;
}
void CGovernanceManager : : CleanOrphanObjects ( )
{
2016-08-17 09:08:25 +02:00
LOCK ( cs ) ;
2017-03-06 08:46:59 +01:00
const vote_mcache_t : : list_t & items = mapOrphanVotes . 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
2017-03-06 08:46:59 +01:00
vote_mcache_t : : list_cit it = items . begin ( ) ;
while ( it ! = items . end ( ) ) {
vote_mcache_t : : list_cit prevIt = it ;
+ + it ;
const vote_time_pair_t & pairVote = prevIt - > value ;
if ( pairVote . second < nNow ) {
mapOrphanVotes . Erase ( prevIt - > key , prevIt - > value ) ;
}
}
2016-04-09 21:57:53 +02:00
}