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-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 ( )
2016-11-13 18:52:34 +01:00
: pCurrentBlockIndex ( NULL ) ,
2016-09-05 01:44:10 +02:00
nTimeLastDiff ( 0 ) ,
nCachedBlockHeight ( 0 ) ,
mapObjects ( ) ,
2017-07-12 22:08:06 +02:00
mapErasedGovernanceObjects ( ) ,
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-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
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-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 ) {
2017-07-13 11:38:00 +02:00
int & count = mapMasternodeOrphanCounter [ govobj . GetMasternodeVin ( ) . prevout ] ;
if ( count > = 10 ) {
LogPrint ( " gobject " , " MNGOVERNANCEOBJECT -- Too many orphan objects, missing masternode=%s \n " , govobj . GetMasternodeVin ( ) . prevout . ToStringShort ( ) ) ;
// 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-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 )
{
2017-07-12 22:08:06 +02:00
DBG ( cout < < " CGovernanceManager::AddGovernanceObject START " < < endl ; ) ;
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
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 ( ) ) ;
2017-07-12 22:08:06 +02:00
return ;
2017-02-22 19:29:30 +01:00
}
if ( ! UpdateCurrentWatchdog ( govobj ) ) {
2017-03-24 11:34:10 +01:00
// Allow wd's which are not current to be reprocessed
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 ( ) ) ;
2017-07-12 22:08:06 +02:00
return ;
2017-02-22 19:29:30 +01:00
}
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
}
2017-07-12 22:08:06 +02:00
LogPrintf ( " AddGovernanceObject -- %s new, received form %s \n " , strHash , pfrom ? pfrom - > addrName : " NULL " ) ;
govobj . Relay ( ) ;
2016-08-17 09:08:25 +02:00
2017-07-12 22:08:06 +02:00
// Update the rate buffer
MasternodeRateCheck ( govobj , UPDATE_TRUE ) ;
masternodeSync . AddedGovernanceItem ( ) ;
// WE MIGHT HAVE PENDING/ORPHAN VOTES FOR THIS OBJECT
CGovernanceException exception ;
CheckOrphanVotes ( govobj , exception ) ;
DBG ( cout < < " CGovernanceManager::AddGovernanceObject END " < < endl ; ) ;
2016-04-09 21:57:53 +02:00
}
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 ( ) ;
2017-07-17 10:06:15 +02:00
LOCK2 ( cs_main , 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-07-12 22:08:06 +02:00
int64_t nSuperblockCycleSeconds = Params ( ) . GetConsensus ( ) . nSuperblockCycle * Params ( ) . GetConsensus ( ) . nPowTargetSpacing ;
int64_t nTimeExpired = pObj - > GetCreationTime ( ) + 2 * nSuperblockCycleSeconds + GOVERNANCE_DELETION_DELAY ;
if ( pObj - > GetObjectType ( ) = = GOVERNANCE_OBJECT_WATCHDOG ) {
mapWatchdogObjects . erase ( nHash ) ;
} else if ( pObj - > GetObjectType ( ) ! = GOVERNANCE_OBJECT_TRIGGER ) {
// keep hashes of deleted proposals forever
nTimeExpired = std : : numeric_limits < int64_t > : : max ( ) ;
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 ( ) ) {
if ( s_it - > second < GetTime ( ) )
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
}
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
}
2017-07-27 16:28:05 +02:00
g_connman - > PushMessage ( pfrom , NetMsgType : : SYNCSTATUSCOUNT , MASTERNODE_SYNC_GOVOBJ , nObjCount ) ;
g_connman - > PushMessage ( pfrom , NetMsgType : : SYNCSTATUSCOUNT , MASTERNODE_SYNC_GOVOBJ_VOTE , nVoteCount ) ;
2016-12-06 17:40:37 +01:00
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 )
{
2017-07-21 11:47:38 +02:00
ENTER_CRITICAL_SECTION ( cs ) ;
2016-11-13 18:52:34 +01:00
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 ) ;
2017-07-21 11:47:38 +02:00
LEAVE_CRITICAL_SECTION ( cs ) ;
2016-11-13 18:52:34 +01:00
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 ) ) ) {
2017-07-21 11:47:38 +02:00
LEAVE_CRITICAL_SECTION ( cs ) ;
2016-11-14 19:22:50 +01:00
RequestGovernanceObject ( pfrom , nHashGovobj ) ;
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 ;
}
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
}
}
2017-07-21 11:47:38 +02:00
LEAVE_CRITICAL_SECTION ( cs ) ;
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 ) ;
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 ) {
string strError ;
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 ) {
AddGovernanceObject ( govobj ) ;
} 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
}
2017-07-13 11:38:00 +02:00
auto it_count = mapMasternodeOrphanCounter . find ( govobj . GetMasternodeVin ( ) . prevout ) ;
if ( - - it_count - > second = = 0 )
mapMasternodeOrphanCounter . erase ( it_count ) ;
2017-07-05 02:31:50 +02:00
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 ) {
2017-07-27 16:28:05 +02:00
g_connman - > PushMessage ( pfrom , 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 ) ;
2017-07-27 16:28:05 +02:00
g_connman - > PushMessage ( pfrom , 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-07-12 22:08:06 +02:00
return strprintf ( " Governance Objects: %d (Proposals: %d, Triggers: %d, Watchdogs: %d/%d, Other: %d; Erased: %d), Votes: %d " ,
2016-12-12 02:44:46 +01:00
( int ) mapObjects . size ( ) ,
2017-07-12 22:08:06 +02:00
nProposalCount , nTriggerCount , nWatchdogCount , mapWatchdogObjects . size ( ) , nOtherCount , ( int ) mapErasedGovernanceObjects . 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 ( )
{
Backport Bitcoin PR#8085: p2p: Begin encapsulation (#1537)
* net: move CBanDB and CAddrDB out of net.h/cpp
This will eventually solve a circular dependency
* net: Create CConnman to encapsulate p2p connections
* net: Move socket binding into CConnman
* net: move OpenNetworkConnection into CConnman
* net: move ban and addrman functions into CConnman
* net: Add oneshot functions to CConnman
* net: move added node functions to CConnman
* net: Add most functions needed for vNodes to CConnman
* net: handle nodesignals in CConnman
* net: Pass CConnection to wallet rather than using the global
* net: Add rpc error for missing/disabled p2p functionality
* net: Pass CConnman around as needed
* gui: add NodeID to the peer table
* net: create generic functor accessors and move vNodes to CConnman
* net: move whitelist functions into CConnman
* net: move nLastNodeId to CConnman
* net: move nLocalHostNonce to CConnman
This behavior seems to have been quite racy and broken.
Move nLocalHostNonce into CNode, and check received nonces against all
non-fully-connected nodes. If there's a match, assume we've connected
to ourself.
* net: move messageHandlerCondition to CConnman
* net: move send/recv statistics to CConnman
* net: move SendBufferSize/ReceiveFloodSize to CConnman
* net: move nLocalServices/nRelevantServices to CConnman
These are in-turn passed to CNode at connection time. This allows us to offer
different services to different peers (or test the effects of doing so).
* net: move semOutbound and semMasternodeOutbound to CConnman
* net: SocketSendData returns written size
* net: move max/max-outbound to CConnman
* net: Pass best block known height into CConnman
CConnman then passes the current best height into CNode at creation time.
This way CConnman/CNode have no dependency on main for height, and the signals
only move in one direction.
This also helps to prevent identity leakage a tiny bit. Before this change, an
attacker could theoretically make 2 connections on different interfaces. They
would connect fully on one, and only establish the initial connection on the
other. Once they receive a new block, they would relay it to your first
connection, and immediately commence the version handshake on the second. Since
the new block height is reflected immediately, they could attempt to learn
whether the two connections were correlated.
This is, of course, incredibly unlikely to work due to the small timings
involved and receipt from other senders. But it doesn't hurt to lock-in
nBestHeight at the time of connection, rather than letting the remote choose
the time.
* net: pass CClientUIInterface into CConnman
* net: Drop StartNode/StopNode and use CConnman directly
* net: Introduce CConnection::Options to avoid passing so many params
* net: add nSendBufferMaxSize/nReceiveFloodSize to CConnection::Options
* net: move vNodesDisconnected into CConnman
* Made the ForEachNode* functions in src/net.cpp more pragmatic and self documenting
* Convert ForEachNode* functions to take a templated function argument rather than a std::function to eliminate std::function overhead
* net: move MAX_FEELER_CONNECTIONS into connman
2017-07-21 11:35:19 +02:00
std : : vector < CNode * > vNodesCopy = g_connman - > CopyNodeVector ( ) ;
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 ) ;
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
}
}
Backport Bitcoin PR#8085: p2p: Begin encapsulation (#1537)
* net: move CBanDB and CAddrDB out of net.h/cpp
This will eventually solve a circular dependency
* net: Create CConnman to encapsulate p2p connections
* net: Move socket binding into CConnman
* net: move OpenNetworkConnection into CConnman
* net: move ban and addrman functions into CConnman
* net: Add oneshot functions to CConnman
* net: move added node functions to CConnman
* net: Add most functions needed for vNodes to CConnman
* net: handle nodesignals in CConnman
* net: Pass CConnection to wallet rather than using the global
* net: Add rpc error for missing/disabled p2p functionality
* net: Pass CConnman around as needed
* gui: add NodeID to the peer table
* net: create generic functor accessors and move vNodes to CConnman
* net: move whitelist functions into CConnman
* net: move nLastNodeId to CConnman
* net: move nLocalHostNonce to CConnman
This behavior seems to have been quite racy and broken.
Move nLocalHostNonce into CNode, and check received nonces against all
non-fully-connected nodes. If there's a match, assume we've connected
to ourself.
* net: move messageHandlerCondition to CConnman
* net: move send/recv statistics to CConnman
* net: move SendBufferSize/ReceiveFloodSize to CConnman
* net: move nLocalServices/nRelevantServices to CConnman
These are in-turn passed to CNode at connection time. This allows us to offer
different services to different peers (or test the effects of doing so).
* net: move semOutbound and semMasternodeOutbound to CConnman
* net: SocketSendData returns written size
* net: move max/max-outbound to CConnman
* net: Pass best block known height into CConnman
CConnman then passes the current best height into CNode at creation time.
This way CConnman/CNode have no dependency on main for height, and the signals
only move in one direction.
This also helps to prevent identity leakage a tiny bit. Before this change, an
attacker could theoretically make 2 connections on different interfaces. They
would connect fully on one, and only establish the initial connection on the
other. Once they receive a new block, they would relay it to your first
connection, and immediately commence the version handshake on the second. Since
the new block height is reflected immediately, they could attempt to learn
whether the two connections were correlated.
This is, of course, incredibly unlikely to work due to the small timings
involved and receipt from other senders. But it doesn't hurt to lock-in
nBestHeight at the time of connection, rather than letting the remote choose
the time.
* net: pass CClientUIInterface into CConnman
* net: Drop StartNode/StopNode and use CConnman directly
* net: Introduce CConnection::Options to avoid passing so many params
* net: add nSendBufferMaxSize/nReceiveFloodSize to CConnection::Options
* net: move vNodesDisconnected into CConnman
* Made the ForEachNode* functions in src/net.cpp more pragmatic and self documenting
* Convert ForEachNode* functions to take a templated function argument rather than a std::function to eliminate std::function overhead
* net: move MAX_FEELER_CONNECTIONS into connman
2017-07-21 11:35:19 +02:00
g_connman - > ReleaseNodeVector ( vNodesCopy ) ;
2017-03-06 08:46:59 +01:00
}
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
}