2019-01-29 15:53:14 +01:00
// Copyright (c) 2014-2019 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"
2018-09-28 09:56:17 +02:00
# include "consensus/validation.h"
# include "governance-classes.h"
2016-11-24 19:12:05 +01:00
# include "governance-object.h"
2018-03-21 12:09:13 +01:00
# include "governance-validators.h"
2016-04-14 00:41:40 +02:00
# include "governance-vote.h"
2018-11-01 22:58:17 +01:00
# include "init.h"
2019-05-21 15:26:15 +02:00
# include "masternode/masternode-meta.h"
# include "masternode/masternode-sync.h"
2017-04-12 09:04:06 +02:00
# include "messagesigner.h"
2018-09-28 09:56:17 +02:00
# include "net_processing.h"
2016-09-27 09:50:04 +02:00
# include "netfulfilledman.h"
2018-09-28 09:56:17 +02:00
# include "netmessagemaker.h"
2019-01-03 21:08:34 +01:00
# include "spork.h"
2016-04-09 21:57:53 +02:00
# include "util.h"
2019-01-03 21:08:34 +01:00
# include "validation.h"
2018-09-28 09:56:17 +02:00
# include "validationinterface.h"
2016-04-09 21:57:53 +02:00
2016-04-10 16:46:19 +02:00
CGovernanceManager governance ;
2016-04-09 21:57:53 +02:00
int nSubmittedFinalBudget ;
2019-07-09 07:59:57 +02:00
const std : : string CGovernanceManager : : SERIALIZATION_VERSION_STRING = " CGovernanceManager-Version-15 " ;
2018-09-28 09:56:17 +02:00
const int CGovernanceManager : : MAX_TIME_FUTURE_DEVIATION = 60 * 60 ;
2017-07-05 02:31:50 +02:00
const int CGovernanceManager : : RELIABLE_PROPAGATION_TIME = 60 ;
2016-11-13 18:52:34 +01:00
2018-09-28 09:56:17 +02:00
CGovernanceManager : : CGovernanceManager ( ) :
nTimeLastDiff ( 0 ) ,
nCachedBlockHeight ( 0 ) ,
mapObjects ( ) ,
mapErasedGovernanceObjects ( ) ,
cmapVoteToObject ( MAX_CACHE_SIZE ) ,
cmapInvalidVotes ( MAX_CACHE_SIZE ) ,
cmmapOrphanVotes ( MAX_CACHE_SIZE ) ,
mapLastMasternodeObject ( ) ,
setRequestedObjects ( ) ,
fRateChecksEnabled ( true ) ,
cs ( )
{
}
2016-04-09 21:57:53 +02:00
2016-08-17 09:08:25 +02:00
// Accessors for thread-safe access to maps
2018-03-20 12:04:59 +01:00
bool CGovernanceManager : : HaveObjectForHash ( const uint256 & nHash ) const
{
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
}
2018-03-20 12:04:59 +01:00
bool CGovernanceManager : : SerializeObjectForHash ( const uint256 & nHash , CDataStream & ss ) const
2016-11-13 18:52:34 +01:00
{
2016-08-17 09:08:25 +02:00
LOCK ( cs ) ;
2018-03-20 12:04:59 +01:00
object_m_cit 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 ;
}
2018-03-20 12:04:59 +01:00
bool CGovernanceManager : : HaveVoteForHash ( const uint256 & nHash ) const
2016-11-13 18:52:34 +01:00
{
2016-08-17 09:08:25 +02:00
LOCK ( cs ) ;
2016-11-13 18:52:34 +01:00
2018-07-12 11:08:43 +02:00
CGovernanceObject * pGovobj = nullptr ;
2018-03-20 12:04:59 +01:00
return cmapVoteToObject . Get ( nHash , pGovobj ) & & pGovobj - > GetVoteFile ( ) . HasVote ( nHash ) ;
2016-08-17 09:08:25 +02:00
}
2017-02-17 21:08:41 +01:00
int CGovernanceManager : : GetVoteCount ( ) const
{
LOCK ( cs ) ;
2018-02-06 12:08:43 +01:00
return ( int ) cmapVoteToObject . GetSize ( ) ;
2017-02-17 21:08:41 +01:00
}
2018-03-20 12:04:59 +01:00
bool CGovernanceManager : : SerializeVoteForHash ( const uint256 & nHash , CDataStream & ss ) const
2016-08-17 09:08:25 +02:00
{
LOCK ( cs ) ;
2016-11-13 18:52:34 +01:00
2018-07-12 11:08:43 +02:00
CGovernanceObject * pGovobj = nullptr ;
2018-09-28 09:56:17 +02:00
return cmapVoteToObject . Get ( nHash , pGovobj ) & & pGovobj - > GetVoteFile ( ) . SerializeVoteToStream ( nHash , ss ) ;
2016-08-17 09:08:25 +02:00
}
2017-02-06 14:31:37 +01:00
void CGovernanceManager : : ProcessMessage ( CNode * pfrom , const std : : string & strCommand , CDataStream & vRecv , CConnman & connman )
2016-06-08 08:57:16 +02:00
{
// lite mode is not supported
2018-09-28 09:56:17 +02:00
if ( fLiteMode ) return ;
if ( ! masternodeSync . IsBlockchainSynced ( ) ) return ;
2016-06-08 08:57:16 +02:00
2016-08-17 09:08:25 +02:00
// ANOTHER USER IS ASKING US TO HELP THEM SYNC GOVERNANCE OBJECT DATA
2018-09-28 09:56:17 +02:00
if ( strCommand = = NetMsgType : : MNGOVERNANCESYNC ) {
if ( pfrom - > nVersion < MIN_GOVERNANCE_PEER_PROTO_VERSION ) {
2017-05-07 09:59:42 +02:00
LogPrint ( BCLog : : GOBJECT , " MNGOVERNANCESYNC -- peer=%d using obsolete version %i \n " , pfrom - > GetId ( ) , pfrom - > nVersion ) ;
2018-09-28 09:56:17 +02:00
connman . PushMessage ( pfrom , CNetMsgMaker ( pfrom - > GetSendVersion ( ) ) . Make ( NetMsgType : : REJECT , strCommand , REJECT_OBSOLETE , strprintf ( " Version must be %d or greater " , MIN_GOVERNANCE_PEER_PROTO_VERSION ) ) ) ;
2018-03-15 10:21:43 +01:00
return ;
}
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 ;
2018-09-28 09:56:17 +02:00
if ( pfrom - > nVersion > = GOVERNANCE_FILTER_PROTO_VERSION ) {
2017-02-02 09:50:44 +01:00
vRecv > > filter ;
filter . UpdateEmptyFull ( ) ;
2018-09-28 09:56:17 +02:00
} else {
2017-02-02 09:50:44 +01:00
filter . clear ( ) ;
}
2018-09-28 09:56:17 +02:00
if ( nProp = = uint256 ( ) ) {
2019-02-04 10:51:37 +01:00
SyncObjects ( pfrom , connman ) ;
2018-02-12 13:49:28 +01:00
} else {
2019-02-04 10:51:37 +01:00
SyncSingleObjVotes ( pfrom , nProp , filter , connman ) ;
2016-06-08 08:57:16 +02:00
}
2019-09-22 22:48:15 +02:00
LogPrint ( BCLog : : GOBJECT , " MNGOVERNANCESYNC -- syncing governance objects to our peer %s \n " , pfrom - > GetLogString ( ) ) ;
2016-06-08 08:57:16 +02:00
}
2016-08-17 09:08:25 +02:00
// A NEW GOVERNANCE OBJECT HAS ARRIVED
2018-09-28 09:56:17 +02:00
else if ( strCommand = = NetMsgType : : MNGOVERNANCEOBJECT ) {
2016-06-10 07:16:32 +02:00
// MAKE SURE WE HAVE A VALID REFERENCE TO THE TIP BEFORE CONTINUING
2017-11-22 15:27:06 +01:00
CGovernanceObject govobj ;
vRecv > > govobj ;
uint256 nHash = govobj . GetHash ( ) ;
2018-10-26 18:42:11 +02:00
{
LOCK ( cs_main ) ;
connman . RemoveAskFor ( nHash ) ;
}
2016-06-08 08:57:16 +02:00
2018-09-28 09:56:17 +02:00
if ( pfrom - > nVersion < MIN_GOVERNANCE_PEER_PROTO_VERSION ) {
2017-05-07 09:59:42 +02:00
LogPrint ( BCLog : : GOBJECT , " MNGOVERNANCEOBJECT -- peer=%d using obsolete version %i \n " , pfrom - > GetId ( ) , pfrom - > nVersion ) ;
2018-09-28 09:56:17 +02:00
connman . PushMessage ( pfrom , CNetMsgMaker ( pfrom - > GetSendVersion ( ) ) . Make ( NetMsgType : : REJECT , strCommand , REJECT_OBSOLETE , strprintf ( " Version must be %d or greater " , MIN_GOVERNANCE_PEER_PROTO_VERSION ) ) ) ;
2018-03-15 10:21:43 +01:00
return ;
}
2019-01-03 10:17:43 +01:00
if ( ! masternodeSync . IsBlockchainSynced ( ) ) {
2019-05-22 23:51:39 +02:00
LogPrint ( BCLog : : GOBJECT , " MNGOVERNANCEOBJECT -- masternode list not synced \n " ) ;
2017-01-17 21:02:38 +01:00
return ;
}
2016-11-13 18:52:34 +01:00
std : : string strHash = nHash . ToString ( ) ;
2019-05-22 23:51:39 +02:00
LogPrint ( BCLog : : GOBJECT , " MNGOVERNANCEOBJECT -- Received object: %s \n " , strHash ) ;
2016-11-13 18:52:34 +01:00
2018-09-28 09:56:17 +02: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
2019-05-29 20:19:53 +02:00
if ( mapObjects . count ( nHash ) | | mapPostponedObjects . count ( nHash ) | | mapErasedGovernanceObjects . count ( nHash ) ) {
2016-06-08 08:57:16 +02:00
// TODO - print error code? what if it's GOVOBJ_ERROR_IMMATURE?
2019-05-22 23:51:39 +02:00
LogPrint ( BCLog : : 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 ;
2018-09-28 09:56:17 +02:00
if ( ! MasternodeRateCheck ( govobj , true , false , fRateCheckBypassed ) ) {
2016-12-08 21:00:49 +01:00
LogPrintf ( " MNGOVERNANCEOBJECT -- masternode rate check failed - %s - (current block height %d) \n " , strHash , nCachedBlockHeight ) ;
return ;
}
2016-06-08 08:57:16 +02:00
std : : string strError = " " ;
2016-09-12 09:40:00 +02:00
// CHECK OBJECT AGAINST LOCAL BLOCKCHAIN
2016-08-17 09:08:25 +02:00
2017-07-05 02:31:50 +02:00
bool fMissingConfirmations = false ;
2019-05-29 20:19:53 +02:00
bool fIsValid = govobj . IsValidLocally ( strError , fMissingConfirmations , true ) ;
2016-09-12 09:40:00 +02:00
2019-05-29 20:19:53 +02:00
if ( fRateCheckBypassed & & fIsValid ) {
2018-09-28 09:56:17 +02:00
if ( ! MasternodeRateCheck ( govobj , true ) ) {
2019-04-30 14:48:21 +02:00
LogPrintf ( " MNGOVERNANCEOBJECT -- masternode rate check failed (after signature verification) - %s - (current block height %d) \n " , strHash , nCachedBlockHeight ) ;
2016-12-11 07:17:38 +01:00
return ;
}
}
2018-09-28 09:56:17 +02:00
if ( ! fIsValid ) {
2019-05-29 20:19:53 +02:00
if ( fMissingConfirmations ) {
2017-07-05 02:31:50 +02:00
AddPostponedObject ( govobj ) ;
LogPrintf ( " MNGOVERNANCEOBJECT -- Not enough fee confirmations for: %s, strError = %s \n " , strHash , strError ) ;
} else {
LogPrintf ( " MNGOVERNANCEOBJECT -- Governance object is invalid - %s \n " , strError ) ;
2017-07-13 11:38:00 +02:00
// apply node's ban score
Misbehaving ( pfrom - > GetId ( ) , 20 ) ;
2017-07-05 02:31:50 +02:00
}
2016-06-08 08:57:16 +02:00
2017-07-05 02:31:50 +02:00
return ;
2017-03-24 11:34:10 +01:00
}
2017-09-19 16:51:38 +02:00
AddGovernanceObject ( govobj , connman , pfrom ) ;
2016-06-08 08:57:16 +02:00
}
2016-08-17 09:08:25 +02:00
// A NEW GOVERNANCE OBJECT VOTE HAS ARRIVED
2018-09-28 09:56:17 +02:00
else if ( strCommand = = NetMsgType : : MNGOVERNANCEOBJECTVOTE ) {
2017-11-22 15:27:06 +01:00
CGovernanceVote vote ;
vRecv > > vote ;
uint256 nHash = vote . GetHash ( ) ;
2018-10-26 18:42:11 +02:00
{
LOCK ( cs_main ) ;
connman . RemoveAskFor ( nHash ) ;
}
2017-11-22 15:27:06 +01:00
2018-09-28 09:56:17 +02:00
if ( pfrom - > nVersion < MIN_GOVERNANCE_PEER_PROTO_VERSION ) {
2017-05-07 09:59:42 +02:00
LogPrint ( BCLog : : GOBJECT , " MNGOVERNANCEOBJECTVOTE -- peer=%d using obsolete version %i \n " , pfrom - > GetId ( ) , pfrom - > nVersion ) ;
2018-09-28 09:56:17 +02:00
connman . PushMessage ( pfrom , CNetMsgMaker ( pfrom - > GetSendVersion ( ) ) . Make ( NetMsgType : : REJECT , strCommand , REJECT_OBSOLETE , strprintf ( " Version must be %d or greater " , MIN_GOVERNANCE_PEER_PROTO_VERSION ) ) ) ;
2018-03-15 10:21:43 +01:00
}
2016-08-29 21:11:34 +02:00
// Ignore such messages until masternode list is synced
2019-01-03 10:17:43 +01:00
if ( ! masternodeSync . IsBlockchainSynced ( ) ) {
2019-05-22 23:51:39 +02:00
LogPrint ( BCLog : : GOBJECT , " MNGOVERNANCEOBJECTVOTE -- masternode list not synced \n " ) ;
2016-11-12 12:14:50 +01:00
return ;
}
2016-08-29 21:11:34 +02:00
2019-05-22 23:51:39 +02:00
LogPrint ( BCLog : : GOBJECT , " MNGOVERNANCEOBJECTVOTE -- Received vote: %s \n " , vote . ToString ( ) ) ;
2016-08-17 09:08:25 +02:00
2016-12-06 17:40:37 +01:00
std : : string strHash = nHash . ToString ( ) ;
2018-09-28 09:56:17 +02:00
if ( ! AcceptVoteMessage ( nHash ) ) {
2019-05-22 23:51:39 +02:00
LogPrint ( BCLog : : GOBJECT , " MNGOVERNANCEOBJECTVOTE -- Received unrequested vote object: %s, hash: %s, peer = %d \n " ,
2018-09-28 09:56:17 +02:00
vote . ToString ( ) , strHash , pfrom - > GetId ( ) ) ;
2016-06-08 08:57:16 +02:00
return ;
}
2016-11-13 18:52:34 +01:00
CGovernanceException exception ;
2018-09-28 09:56:17 +02:00
if ( ProcessVote ( pfrom , vote , exception , connman ) ) {
2019-05-22 23:51:39 +02:00
LogPrint ( BCLog : : GOBJECT , " MNGOVERNANCEOBJECTVOTE -- %s new \n " , strHash ) ;
2017-08-09 18:07:03 +02:00
masternodeSync . BumpAssetLastTime ( " MNGOVERNANCEOBJECTVOTE " ) ;
2017-09-19 16:51:38 +02:00
vote . Relay ( connman ) ;
2018-09-28 09:56:17 +02:00
} else {
2019-05-22 23:51:39 +02:00
LogPrint ( BCLog : : GOBJECT , " MNGOVERNANCEOBJECTVOTE -- Rejected vote, error = %s \n " , exception . what ( ) ) ;
2018-09-28 09:56:17 +02:00
if ( ( exception . GetNodePenalty ( ) ! = 0 ) & & masternodeSync . IsSynced ( ) ) {
2018-03-19 14:09:29 +01:00
LOCK ( cs_main ) ;
2016-11-13 18:52:34 +01:00
Misbehaving ( pfrom - > GetId ( ) , exception . GetNodePenalty ( ) ) ;
}
return ;
2016-06-08 08:57:16 +02:00
}
2018-07-12 11:06:30 +02:00
// SEND NOTIFICATION TO SCRIPT/ZMQ
GetMainSignals ( ) . NotifyGovernanceVote ( vote ) ;
2016-06-08 08:57:16 +02:00
}
}
2017-09-19 16:51:38 +02:00
void CGovernanceManager : : CheckOrphanVotes ( CGovernanceObject & govobj , CGovernanceException & exception , CConnman & connman )
2016-04-09 21:57:53 +02:00
{
2016-11-13 18:52:34 +01:00
uint256 nHash = govobj . GetHash ( ) ;
2016-11-24 19:12:05 +01:00
std : : vector < vote_time_pair_t > vecVotePairs ;
2018-02-06 12:08:43 +01:00
cmmapOrphanVotes . GetAll ( nHash , vecVotePairs ) ;
2016-11-24 19:12:05 +01:00
2017-09-15 20:05:03 +02:00
ScopedLockBool guard ( cs , fRateChecksEnabled , false ) ;
2017-07-05 02:31:50 +02:00
2016-11-24 19:12:05 +01:00
int64_t nNow = GetAdjustedTime ( ) ;
2018-10-11 16:33:48 +02:00
for ( auto & pairVote : vecVotePairs ) {
2016-11-24 19:12:05 +01:00
bool fRemove = false ;
CGovernanceVote & vote = pairVote . first ;
2016-11-13 18:52:34 +01:00
CGovernanceException exception ;
2018-09-28 09:56:17 +02:00
if ( pairVote . second < nNow ) {
2016-11-24 19:12:05 +01:00
fRemove = true ;
2018-09-28 09:56:17 +02:00
} else if ( govobj . ProcessVote ( nullptr , vote , exception , connman ) ) {
2017-09-19 16:51:38 +02:00
vote . Relay ( connman ) ;
2016-11-24 19:12:05 +01:00
fRemove = true ;
2016-11-13 18:52:34 +01:00
}
2018-09-28 09:56:17 +02:00
if ( fRemove ) {
2018-02-06 12:08:43 +01:00
cmmapOrphanVotes . Erase ( nHash , pairVote ) ;
2016-11-24 19:12:05 +01:00
}
2016-04-09 21:57:53 +02:00
}
2017-07-05 02:31:50 +02:00
}
2017-09-19 16:51:38 +02:00
void CGovernanceManager : : AddGovernanceObject ( CGovernanceObject & govobj , CConnman & connman , CNode * pfrom )
2017-07-05 02:31:50 +02:00
{
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
2018-09-28 09:56:17 +02:00
if ( ! govobj . IsValidLocally ( strError , true ) ) {
2017-01-03 19:32:52 +01:00
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
}
2019-05-22 23:51:39 +02:00
LogPrint ( BCLog : : GOBJECT , " CGovernanceManager::AddGovernanceObject -- Adding object: hash = %s, type = %d \n " , nHash . ToString ( ) , govobj . GetObjectType ( ) ) ;
2018-06-06 17:56:33 +02:00
// INSERT INTO OUR GOVERNANCE OBJECT MEMORY
2016-08-17 09:08:25 +02:00
// IF WE HAVE THIS OBJECT ALREADY, WE DON'T WANT ANOTHER COPY
2018-06-06 17:56:33 +02:00
auto objpair = mapObjects . emplace ( nHash , govobj ) ;
2016-08-17 09:08:25 +02:00
2018-09-28 09:56:17 +02:00
if ( ! objpair . second ) {
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
}
2016-08-17 09:08:25 +02:00
// SHOULD WE ADD THIS OBJECT TO ANY OTHER MANANGERS?
2019-05-22 23:51:39 +02:00
LogPrint ( BCLog : : GOBJECT , " CGovernanceManager::AddGovernanceObject -- Before trigger block, GetDataAsPlainString = %s, nObjectType = %d \n " ,
2019-08-23 20:03:05 +02:00
govobj . GetDataAsPlainString ( ) , govobj . GetObjectType ( ) ) ;
2016-08-17 09:08:25 +02:00
2019-08-23 20:03:05 +02:00
if ( govobj . GetObjectType ( ) = = GOVERNANCE_OBJECT_TRIGGER ) {
2018-06-06 17:56:33 +02:00
if ( ! triggerman . AddNewTrigger ( nHash ) ) {
2019-05-22 23:51:39 +02:00
LogPrint ( BCLog : : GOBJECT , " CGovernanceManager::AddGovernanceObject -- undo adding invalid trigger object: hash = %s \n " , nHash . ToString ( ) ) ;
2019-08-23 20:03:05 +02:00
objpair . first - > second . PrepareDeletion ( GetAdjustedTime ( ) ) ;
2018-06-06 17:56:33 +02:00
return ;
}
2016-08-17 09:08:25 +02:00
}
2019-09-22 22:48:15 +02:00
LogPrintf ( " CGovernanceManager::AddGovernanceObject -- %s new, received from peer %s \n " , strHash , pfrom ? pfrom - > GetLogString ( ) : " nullptr " ) ;
2017-09-19 16:51:38 +02:00
govobj . Relay ( connman ) ;
2016-08-17 09:08:25 +02:00
2017-07-12 22:08:06 +02:00
// Update the rate buffer
2017-08-23 16:22:23 +02:00
MasternodeRateUpdate ( govobj ) ;
2017-07-12 22:08:06 +02:00
2017-08-09 18:07:03 +02:00
masternodeSync . BumpAssetLastTime ( " CGovernanceManager::AddGovernanceObject " ) ;
2017-07-12 22:08:06 +02:00
// WE MIGHT HAVE PENDING/ORPHAN VOTES FOR THIS OBJECT
CGovernanceException exception ;
2017-09-19 16:51:38 +02:00
CheckOrphanVotes ( govobj , exception , connman ) ;
2017-07-12 22:08:06 +02:00
2018-07-12 11:06:30 +02:00
// SEND NOTIFICATION TO SCRIPT/ZMQ
GetMainSignals ( ) . NotifyGovernanceObject ( govobj ) ;
2016-04-09 21:57:53 +02:00
}
2016-08-17 09:08:25 +02:00
void CGovernanceManager : : UpdateCachesAndClean ( )
2016-04-09 21:57:53 +02:00
{
2019-09-17 14:09:04 +02:00
// Return on initial sync, spammed the debug.log and provided no use
if ( ! masternodeSync . IsBlockchainSynced ( ) ) {
return ;
}
2019-05-22 23:51:39 +02:00
LogPrint ( BCLog : : GOBJECT , " CGovernanceManager::UpdateCachesAndClean \n " ) ;
2016-08-17 09:08:25 +02:00
2019-01-03 21:08:34 +01:00
std : : vector < uint256 > vecDirtyHashes = mmetaman . GetAndClearDirtyGovernanceObjectHashes ( ) ;
2016-10-17 20:54:28 +02:00
2017-07-17 10:06:15 +02:00
LOCK2 ( cs_main , cs ) ;
2016-04-09 21:57:53 +02:00
2018-10-11 16:33:48 +02:00
for ( const uint256 & nHash : vecDirtyHashes ) {
object_m_it it = mapObjects . find ( nHash ) ;
2018-09-28 09:56:17 +02:00
if ( it = = mapObjects . end ( ) ) {
2016-10-17 20:54:28 +02:00
continue ;
}
2016-11-13 18:52:34 +01:00
it - > second . ClearMasternodeVotes ( ) ;
2016-10-17 20:54:28 +02:00
}
2017-09-15 20:05:03 +02:00
ScopedLockBool guard ( cs , fRateChecksEnabled , false ) ;
2016-12-04 21:33:39 +01:00
2016-08-17 09:08:25 +02:00
// Clean up any expired or invalid triggers
triggerman . CleanAndRemove ( ) ;
2018-06-06 17:56:33 +02:00
object_m_it it = mapObjects . begin ( ) ;
2018-02-25 06:33:27 +01:00
int64_t nNow = GetAdjustedTime ( ) ;
2018-09-28 09:56:17 +02:00
while ( it ! = mapObjects . end ( ) ) {
2016-05-24 20:11:59 +02:00
CGovernanceObject * pObj = & ( ( * it ) . second ) ;
2018-09-28 09:56:17 +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?
2018-09-28 09:56:17 +02:00
if ( pObj - > IsSetDirtyCache ( ) ) {
2016-08-17 09:08:25 +02:00
// UPDATE LOCAL VALIDITY AGAINST CRYPTO DATA
2017-01-03 19:32:52 +01:00
pObj - > UpdateLocalValidity ( ) ;
2016-09-12 09:40:00 +02:00
2016-08-17 09:08:25 +02:00
// UPDATE SENTINEL SIGNALING VARIABLES
2016-12-11 07:17:38 +01:00
pObj - > UpdateSentinelVariables ( ) ;
2016-08-17 09:08:25 +02:00
}
2016-04-09 22:55:52 +02:00
2016-08-17 09:08:25 +02:00
// IF DELETE=TRUE, THEN CLEAN THE MESS UP!
2016-05-24 20:11:59 +02:00
2018-02-25 06:33:27 +01:00
int64_t nTimeSinceDeletion = nNow - pObj - > GetDeletionTime ( ) ;
2016-11-18 15:17:00 +01:00
2019-05-22 23:51:39 +02:00
LogPrint ( BCLog : : GOBJECT , " CGovernanceManager::UpdateCachesAndClean -- Checking object for deletion: %s, deletion time = %d, time since deletion = %d, delete flag = %d, expired flag = %d \n " ,
2018-09-28 09:56:17 +02:00
strHash , pObj - > GetDeletionTime ( ) , nTimeSinceDeletion , pObj - > IsSetCachedDelete ( ) , pObj - > IsSetExpired ( ) ) ;
2016-12-14 16:27:46 +01:00
2018-09-28 09:56:17 +02: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 ( ) ) ;
2019-01-03 21:08:34 +01:00
mmetaman . RemoveGovernanceObject ( pObj - > GetHash ( ) ) ;
2016-11-13 18:52:34 +01:00
// Remove vote references
2018-02-06 12:08:43 +01:00
const object_ref_cm_t : : list_t & listItems = cmapVoteToObject . GetItemList ( ) ;
object_ref_cm_t : : list_cit lit = listItems . begin ( ) ;
2018-09-28 09:56:17 +02:00
while ( lit ! = listItems . end ( ) ) {
if ( lit - > value = = pObj ) {
2016-11-13 18:52:34 +01:00
uint256 nKey = lit - > key ;
+ + lit ;
2018-02-06 12:08:43 +01:00
cmapVoteToObject . Erase ( nKey ) ;
2018-09-28 09:56:17 +02:00
} else {
2016-11-13 18:52:34 +01:00
+ + lit ;
}
}
2017-07-12 22:08:06 +02:00
2018-02-25 06:33:27 +01:00
int64_t nTimeExpired { 0 } ;
2017-07-12 22:08:06 +02:00
2018-09-28 09:56:17 +02:00
if ( pObj - > GetObjectType ( ) = = GOVERNANCE_OBJECT_PROPOSAL ) {
2017-07-12 22:08:06 +02:00
// keep hashes of deleted proposals forever
nTimeExpired = std : : numeric_limits < int64_t > : : max ( ) ;
2018-02-25 06:33:27 +01:00
} else {
int64_t nSuperblockCycleSeconds = Params ( ) . GetConsensus ( ) . nSuperblockCycle * Params ( ) . GetConsensus ( ) . nPowTargetSpacing ;
nTimeExpired = pObj - > GetCreationTime ( ) + 2 * nSuperblockCycleSeconds + GOVERNANCE_DELETION_DELAY ;
2017-02-17 01:48:42 +01:00
}
2017-07-12 22:08:06 +02:00
mapErasedGovernanceObjects . insert ( std : : make_pair ( nHash , nTimeExpired ) ) ;
2016-08-17 09:08:25 +02:00
mapObjects . erase ( it + + ) ;
} else {
2018-06-06 17:56:33 +02:00
// NOTE: triggers are handled via triggerman
2018-06-06 18:06:23 +02:00
if ( pObj - > GetObjectType ( ) = = GOVERNANCE_OBJECT_PROPOSAL ) {
2019-02-26 11:44:43 +01:00
CProposalValidator validator ( pObj - > GetDataAsHexString ( ) , true ) ;
2018-03-21 12:09:13 +01:00
if ( ! validator . Validate ( ) ) {
2019-04-30 14:48:21 +02:00
LogPrintf ( " CGovernanceManager::UpdateCachesAndClean -- set for deletion expired obj %s \n " , strHash ) ;
2019-08-23 20:03:05 +02:00
pObj - > PrepareDeletion ( nNow ) ;
2018-03-21 12:09:13 +01:00
}
}
2016-08-17 09:08:25 +02:00
+ + 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 ( ) ;
2018-09-28 09:56:17 +02:00
while ( s_it ! = mapErasedGovernanceObjects . end ( ) ) {
if ( s_it - > second < nNow ) {
2017-07-12 22:08:06 +02:00
mapErasedGovernanceObjects . erase ( s_it + + ) ;
2018-09-28 09:56:17 +02:00
} else {
2017-07-12 22:08:06 +02:00
+ + s_it ;
2018-09-28 09:56:17 +02:00
}
2017-07-12 22:08:06 +02:00
}
2017-06-06 01:47:23 +02:00
LogPrintf ( " CGovernanceManager::UpdateCachesAndClean -- %s \n " , ToString ( ) ) ;
2016-04-09 21:57:53 +02:00
}
2018-03-20 12:04:59 +01:00
CGovernanceObject * CGovernanceManager : : FindGovernanceObject ( const uint256 & nHash )
2016-04-09 21:57:53 +02:00
{
LOCK ( cs ) ;
2018-09-28 09:56:17 +02:00
if ( mapObjects . count ( nHash ) ) return & mapObjects [ nHash ] ;
2016-04-09 21:57:53 +02:00
2018-07-12 11:08:43 +02:00
return nullptr ;
2016-04-09 21:57:53 +02:00
}
2018-03-20 12:04:59 +01:00
std : : vector < CGovernanceVote > CGovernanceManager : : GetCurrentVotes ( const uint256 & nParentHash , const COutPoint & mnCollateralOutpointFilter ) const
2016-11-22 20:26:36 +01:00
{
LOCK ( cs ) ;
std : : vector < CGovernanceVote > vecResult ;
// Find the governance object or short-circuit.
2018-03-20 12:04:59 +01:00
object_m_cit it = mapObjects . find ( nParentHash ) ;
2018-09-28 09:56:17 +02:00
if ( it = = mapObjects . end ( ) ) return vecResult ;
2018-03-20 12:04:59 +01:00
const CGovernanceObject & govobj = it - > second ;
2016-11-22 20:26:36 +01:00
2018-12-17 13:34:52 +01:00
auto mnList = deterministicMNManager - > GetListAtChainTip ( ) ;
std : : map < COutPoint , CDeterministicMNCPtr > mapMasternodes ;
2018-09-28 09:56:17 +02:00
if ( mnCollateralOutpointFilter . IsNull ( ) ) {
2019-06-13 11:03:20 +02:00
mnList . ForEachMN ( false , [ & ] ( const CDeterministicMNCPtr & dmn ) {
2018-12-17 13:34:52 +01:00
mapMasternodes . emplace ( dmn - > collateralOutpoint , dmn ) ;
} ) ;
} else {
2019-06-13 11:03:20 +02:00
auto dmn = mnList . GetMNByCollateral ( mnCollateralOutpointFilter ) ;
2018-12-17 13:34:52 +01:00
if ( dmn ) {
mapMasternodes . emplace ( dmn - > collateralOutpoint , dmn ) ;
}
2016-11-22 20:26:36 +01:00
}
// Loop thru each MN collateral outpoint and get the votes for the `nParentHash` governance object
2018-09-28 09:56:17 +02:00
for ( const auto & mnpair : mapMasternodes ) {
2016-11-22 20:26:36 +01:00
// get a vote_rec_t from the govobj
vote_rec_t voteRecord ;
2017-09-11 16:13:48 +02:00
if ( ! govobj . GetCurrentMNVotes ( mnpair . first , voteRecord ) ) continue ;
2016-11-22 20:26:36 +01:00
2018-07-12 11:07:51 +02:00
for ( const auto & voteInstancePair : voteRecord . mapInstances ) {
int signal = voteInstancePair . first ;
int outcome = voteInstancePair . second . eOutcome ;
int64_t nCreationTime = voteInstancePair . second . nCreationTime ;
2016-11-22 20:26:36 +01:00
2017-09-11 16:13:48 +02:00
CGovernanceVote vote = CGovernanceVote ( mnpair . first , nParentHash , ( vote_signal_enum_t ) signal , ( vote_outcome_enum_t ) outcome ) ;
2017-02-23 13:29:00 +01:00
vote . SetTime ( nCreationTime ) ;
2016-11-22 20:26:36 +01:00
vecResult . push_back ( vote ) ;
}
}
return vecResult ;
}
2018-03-20 12:04:59 +01:00
std : : vector < const CGovernanceObject * > CGovernanceManager : : GetAllNewerThan ( int64_t nMoreThanTime ) const
2016-04-09 21:57:53 +02:00
{
LOCK ( cs ) ;
2018-03-20 12:04:59 +01:00
std : : vector < const CGovernanceObject * > vGovObjs ;
2016-04-09 21:57:53 +02:00
2018-07-12 11:07:51 +02:00
for ( const auto & objPair : mapObjects ) {
2016-08-17 09:08:25 +02:00
// IF THIS OBJECT IS OLDER THAN TIME, CONTINUE
2018-09-28 09:56:17 +02:00
if ( objPair . second . GetCreationTime ( ) < nMoreThanTime ) {
2016-08-17 09:08:25 +02:00
continue ;
}
// ADD GOVERNANCE OBJECT TO LIST
2018-07-12 11:07:51 +02:00
const CGovernanceObject * pGovObj = & ( objPair . second ) ;
2016-05-28 12:31:44 +02:00
vGovObjs . push_back ( pGovObj ) ;
2016-04-09 21:57:53 +02:00
}
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 {
2018-09-28 09:56:17 +02:00
bool operator ( ) ( const std : : pair < CGovernanceObject * , int > & left , const std : : pair < CGovernanceObject * , int > & right )
{
if ( left . second ! = right . second ) return ( left . second > right . second ) ;
2016-11-13 18:52:34 +01:00
return ( UintToArith256 ( left . first - > GetCollateralHash ( ) ) > UintToArith256 ( right . first - > GetCollateralHash ( ) ) ) ;
2016-04-09 21:57:53 +02:00
}
} ;
2017-09-19 16:51:38 +02:00
void CGovernanceManager : : DoMaintenance ( CConnman & connman )
2016-04-09 21:57:53 +02:00
{
2018-11-01 22:58:17 +01:00
if ( fLiteMode | | ! masternodeSync . IsSynced ( ) | | ShutdownRequested ( ) ) return ;
2016-08-29 21:11:34 +02:00
2016-08-17 09:08:25 +02:00
// CHECK OBJECTS WE'VE ASKED FOR, REMOVE OLD ENTRIES
2016-04-09 21:57:53 +02:00
2017-03-06 08:46:59 +01:00
CleanOrphanObjects ( ) ;
2017-09-19 16:51:38 +02:00
RequestOrphanObjects ( connman ) ;
2016-04-09 21:57:53 +02:00
2016-08-17 09:08:25 +02:00
// CHECK AND REMOVE - REPROCESS GOVERNANCE OBJECTS
2016-04-09 21:57:53 +02:00
2016-08-17 09:08:25 +02:00
UpdateCachesAndClean ( ) ;
2016-04-09 21:57:53 +02:00
}
2016-11-13 18:52:34 +01:00
bool CGovernanceManager : : ConfirmInventoryRequest ( const CInv & inv )
{
2017-08-09 18:07:03 +02:00
// do not request objects until it's time to sync
2019-01-03 10:17:43 +01:00
if ( ! masternodeSync . IsBlockchainSynced ( ) ) return false ;
2017-08-09 18:07:03 +02:00
2016-11-13 18:52:34 +01:00
LOCK ( cs ) ;
2019-05-22 23:51:39 +02:00
LogPrint ( BCLog : : GOBJECT , " CGovernanceManager::ConfirmInventoryRequest inv = %s \n " , inv . ToString ( ) ) ;
2016-11-13 18:52:34 +01:00
// First check if we've already recorded this object
2018-09-28 09:56:17 +02:00
switch ( inv . type ) {
case MSG_GOVERNANCE_OBJECT : {
if ( mapObjects . count ( inv . hash ) = = 1 | | mapPostponedObjects . count ( inv . hash ) = = 1 ) {
2019-05-22 23:51:39 +02:00
LogPrint ( BCLog : : GOBJECT , " CGovernanceManager::ConfirmInventoryRequest already have governance object, returning false \n " ) ;
2016-11-13 18:52:34 +01:00
return false ;
}
2018-09-28 09:56:17 +02:00
break ;
}
case MSG_GOVERNANCE_OBJECT_VOTE : {
if ( cmapVoteToObject . HasKey ( inv . hash ) ) {
2019-05-22 23:51:39 +02:00
LogPrint ( BCLog : : GOBJECT , " CGovernanceManager::ConfirmInventoryRequest already have governance vote, returning false \n " ) ;
2016-11-13 18:52:34 +01:00
return false ;
}
2018-09-28 09:56:17 +02:00
break ;
}
2016-11-13 18:52:34 +01:00
default :
2019-05-22 23:51:39 +02:00
LogPrint ( BCLog : : GOBJECT , " CGovernanceManager::ConfirmInventoryRequest unknown type, returning false \n " ) ;
2016-11-13 18:52:34 +01:00
return false ;
}
2018-07-12 11:08:43 +02:00
hash_s_t * setHash = nullptr ;
2018-09-28 09:56:17 +02:00
switch ( inv . type ) {
2016-11-13 18:52:34 +01:00
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 ) ;
2018-09-28 09:56:17 +02:00
if ( it = = setHash - > end ( ) ) {
2016-11-13 18:52:34 +01:00
setHash - > insert ( inv . hash ) ;
2019-05-22 23:51:39 +02:00
LogPrint ( BCLog : : GOBJECT , " CGovernanceManager::ConfirmInventoryRequest added inv to requested set \n " ) ;
2016-11-13 18:52:34 +01:00
}
2019-05-22 23:51:39 +02:00
LogPrint ( BCLog : : GOBJECT , " CGovernanceManager::ConfirmInventoryRequest reached end, returning true \n " ) ;
2016-11-13 18:52:34 +01:00
return true ;
}
2019-02-04 10:51:37 +01:00
void CGovernanceManager : : SyncSingleObjVotes ( CNode * pnode , const uint256 & nProp , const CBloomFilter & filter , CConnman & connman )
2016-04-09 21:57:53 +02:00
{
2017-02-16 16:14:42 +01:00
// do not provide any data until our node is synced
2018-09-28 09:56:17 +02:00
if ( ! masternodeSync . IsSynced ( ) ) return ;
2017-02-16 16:14:42 +01:00
2016-12-06 17:40:37 +01:00
int nVoteCount = 0 ;
2016-04-09 21:57:53 +02:00
2016-05-24 20:11:59 +02:00
// SYNC GOVERNANCE OBJECTS WITH OTHER CLIENT
2017-05-07 09:59:42 +02:00
LogPrint ( BCLog : : GOBJECT , " CGovernanceManager::%s -- syncing single object to peer=%d, nProp = %s \n " , __func__ , pnode - > GetId ( ) , nProp . ToString ( ) ) ;
2016-12-04 21:33:39 +01:00
2018-02-12 13:49:28 +01:00
LOCK2 ( cs_main , cs ) ;
2016-11-13 18:52:34 +01:00
2018-02-12 13:49:28 +01:00
// single valid object and its valid votes
object_m_it it = mapObjects . find ( nProp ) ;
2018-09-28 09:56:17 +02:00
if ( it = = mapObjects . end ( ) ) {
2017-05-07 09:59:42 +02:00
LogPrint ( BCLog : : GOBJECT , " CGovernanceManager::%s -- no matching object for hash %s, peer=%d \n " , __func__ , nProp . ToString ( ) , pnode - > GetId ( ) ) ;
2018-02-12 13:49:28 +01:00
return ;
}
CGovernanceObject & govobj = it - > second ;
std : : string strHash = it - > first . ToString ( ) ;
2016-12-04 21:33:39 +01:00
2017-05-07 09:59:42 +02:00
LogPrint ( BCLog : : GOBJECT , " CGovernanceManager::%s -- attempting to sync govobj: %s, peer=%d \n " , __func__ , strHash , pnode - > GetId ( ) ) ;
2016-12-06 17:40:37 +01:00
2018-09-28 09:56:17 +02:00
if ( govobj . IsSetCachedDelete ( ) | | govobj . IsSetExpired ( ) ) {
2018-02-12 13:49:28 +01:00
LogPrintf ( " CGovernanceManager::%s -- not syncing deleted/expired govobj: %s, peer=%d \n " , __func__ ,
2017-05-07 09:59:42 +02:00
strHash , pnode - > GetId ( ) ) ;
2018-02-12 13:49:28 +01:00
return ;
}
2016-12-04 21:33:39 +01:00
2018-03-20 12:04:59 +01:00
auto fileVotes = govobj . GetVoteFile ( ) ;
for ( const auto & vote : fileVotes . GetVotes ( ) ) {
uint256 nVoteHash = vote . GetHash ( ) ;
2018-08-31 15:31:59 +02:00
2018-12-20 14:27:48 +01:00
bool onlyVotingKeyAllowed = govobj . GetObjectType ( ) = = GOVERNANCE_OBJECT_PROPOSAL & & vote . GetSignal ( ) = = VOTE_SIGNAL_FUNDING ;
2018-08-31 15:31:59 +02:00
2018-12-20 14:27:48 +01:00
if ( filter . contains ( nVoteHash ) | | ! vote . IsValid ( onlyVotingKeyAllowed ) ) {
2018-02-12 13:49:28 +01:00
continue ;
}
2018-03-20 12:04:59 +01:00
pnode - > PushInventory ( CInv ( MSG_GOVERNANCE_OBJECT_VOTE , nVoteHash ) ) ;
2018-02-12 13:49:28 +01:00
+ + nVoteCount ;
}
2017-01-17 21:02:38 +01:00
2018-02-12 13:49:28 +01:00
CNetMsgMaker msgMaker ( pnode - > GetSendVersion ( ) ) ;
connman . PushMessage ( pnode , msgMaker . Make ( NetMsgType : : SYNCSTATUSCOUNT , MASTERNODE_SYNC_GOVOBJ_VOTE , nVoteCount ) ) ;
2017-05-07 09:59:42 +02:00
LogPrintf ( " CGovernanceManager::%s -- sent %d votes to peer=%d \n " , __func__ , nVoteCount , pnode - > GetId ( ) ) ;
2018-02-12 13:49:28 +01:00
}
2016-12-04 21:33:39 +01:00
2019-02-04 10:51:37 +01:00
void CGovernanceManager : : SyncObjects ( CNode * pnode , CConnman & connman ) const
2018-02-12 13:49:28 +01:00
{
// do not provide any data until our node is synced
2018-09-28 09:56:17 +02:00
if ( ! masternodeSync . IsSynced ( ) ) return ;
2016-12-04 21:33:39 +01:00
2018-09-28 09:56:17 +02:00
if ( netfulfilledman . HasFulfilledRequest ( pnode - > addr , NetMsgType : : MNGOVERNANCESYNC ) ) {
2018-03-19 14:09:29 +01:00
LOCK ( cs_main ) ;
2018-02-12 13:49:28 +01:00
// Asking for the whole list multiple times in a short period of time is no good
2019-05-22 23:51:39 +02:00
LogPrint ( BCLog : : GOBJECT , " CGovernanceManager::%s -- peer already asked me for the list \n " , __func__ ) ;
2018-02-12 13:49:28 +01:00
Misbehaving ( pnode - > GetId ( ) , 20 ) ;
return ;
}
netfulfilledman . AddFulfilledRequest ( pnode - > addr , NetMsgType : : MNGOVERNANCESYNC ) ;
2016-11-13 18:52:34 +01:00
2018-02-12 13:49:28 +01:00
int nObjCount = 0 ;
// SYNC GOVERNANCE OBJECTS WITH OTHER CLIENT
2017-05-07 09:59:42 +02:00
LogPrint ( BCLog : : GOBJECT , " CGovernanceManager::%s -- syncing all objects to peer=%d \n " , __func__ , pnode - > GetId ( ) ) ;
2018-02-12 13:49:28 +01:00
LOCK2 ( cs_main , cs ) ;
// all valid objects, no votes
2018-07-12 11:07:51 +02:00
for ( const auto & objPair : mapObjects ) {
uint256 nHash = objPair . first ;
const CGovernanceObject & govobj = objPair . second ;
std : : string strHash = nHash . ToString ( ) ;
2018-02-12 13:49:28 +01:00
2017-05-07 09:59:42 +02:00
LogPrint ( BCLog : : GOBJECT , " CGovernanceManager::%s -- attempting to sync govobj: %s, peer=%d \n " , __func__ , strHash , pnode - > GetId ( ) ) ;
2018-02-12 13:49:28 +01:00
2018-09-28 09:56:17 +02:00
if ( govobj . IsSetCachedDelete ( ) | | govobj . IsSetExpired ( ) ) {
2018-02-12 13:49:28 +01:00
LogPrintf ( " CGovernanceManager::%s -- not syncing deleted/expired govobj: %s, peer=%d \n " , __func__ ,
2017-05-07 09:59:42 +02:00
strHash , pnode - > GetId ( ) ) ;
2018-02-12 13:49:28 +01:00
continue ;
2016-11-13 18:52:34 +01:00
}
2018-02-12 13:49:28 +01:00
// Push the inventory budget proposal message over to the other client
2017-05-07 09:59:42 +02:00
LogPrint ( BCLog : : GOBJECT , " CGovernanceManager::%s -- syncing govobj: %s, peer=%d \n " , __func__ , strHash , pnode - > GetId ( ) ) ;
2018-07-12 11:07:51 +02:00
pnode - > PushInventory ( CInv ( MSG_GOVERNANCE_OBJECT , nHash ) ) ;
2018-02-12 13:49:28 +01:00
+ + nObjCount ;
2016-04-14 00:41:40 +02:00
}
2018-02-12 13:49:28 +01:00
CNetMsgMaker msgMaker ( pnode - > GetSendVersion ( ) ) ;
connman . PushMessage ( pnode , msgMaker . Make ( NetMsgType : : SYNCSTATUSCOUNT , MASTERNODE_SYNC_GOVOBJ , nObjCount ) ) ;
2017-05-07 09:59:42 +02:00
LogPrintf ( " CGovernanceManager::%s -- sent %d objects to peer=%d \n " , __func__ , nObjCount , pnode - > GetId ( ) ) ;
2016-04-09 21:57:53 +02:00
}
2017-08-23 16:22:23 +02:00
void CGovernanceManager : : MasternodeRateUpdate ( const CGovernanceObject & govobj )
{
2018-09-28 09:56:17 +02:00
if ( govobj . GetObjectType ( ) ! = GOVERNANCE_OBJECT_TRIGGER ) return ;
2017-08-23 16:22:23 +02:00
2018-02-15 08:29:44 +01:00
const COutPoint & masternodeOutpoint = govobj . GetMasternodeOutpoint ( ) ;
2018-09-28 09:56:17 +02:00
txout_m_it it = mapLastMasternodeObject . find ( masternodeOutpoint ) ;
2017-08-23 16:22:23 +02:00
2018-09-28 09:56:17 +02:00
if ( it = = mapLastMasternodeObject . end ( ) ) {
2018-02-15 08:29:44 +01:00
it = mapLastMasternodeObject . insert ( txout_m_t : : value_type ( masternodeOutpoint , last_object_rec ( true ) ) ) . first ;
2018-09-28 09:56:17 +02:00
}
2017-08-23 16:22:23 +02:00
int64_t nTimestamp = govobj . GetCreationTime ( ) ;
2018-02-25 06:33:27 +01:00
it - > second . triggerBuffer . AddTimestamp ( nTimestamp ) ;
2017-08-23 16:22:23 +02:00
if ( nTimestamp > GetTime ( ) + MAX_TIME_FUTURE_DEVIATION - RELIABLE_PROPAGATION_TIME ) {
// schedule additional relay for the object
setAdditionalRelayObjects . insert ( govobj . GetHash ( ) ) ;
}
it - > second . fStatusOK = true ;
}
bool CGovernanceManager : : MasternodeRateCheck ( const CGovernanceObject & govobj , bool fUpdateFailStatus )
2016-12-11 07:17:38 +01:00
{
2017-07-05 02:31:50 +02:00
bool fRateCheckBypassed ;
2017-08-23 16:22:23 +02:00
return MasternodeRateCheck ( govobj , fUpdateFailStatus , true , fRateCheckBypassed ) ;
2016-12-11 07:17:38 +01:00
}
2017-08-23 16:22:23 +02:00
bool CGovernanceManager : : MasternodeRateCheck ( const CGovernanceObject & govobj , bool fUpdateFailStatus , bool fForce , bool & fRateCheckBypassed )
2016-09-05 01:44:10 +02:00
{
LOCK ( cs ) ;
2016-10-17 20:54:28 +02:00
2016-12-11 07:17:38 +01:00
fRateCheckBypassed = false ;
2018-09-28 09:56:17 +02:00
if ( ! masternodeSync . IsSynced ( ) | | ! fRateChecksEnabled ) {
2016-12-08 21:00:49 +01:00
return true ;
}
2018-09-28 09:56:17 +02:00
if ( govobj . GetObjectType ( ) ! = GOVERNANCE_OBJECT_TRIGGER ) {
2016-12-08 21:00:49 +01:00
return true ;
}
2018-02-15 08:29:44 +01:00
const COutPoint & masternodeOutpoint = govobj . GetMasternodeOutpoint ( ) ;
2016-12-11 07:17:38 +01:00
int64_t nTimestamp = govobj . GetCreationTime ( ) ;
2017-08-29 01:51:44 +02:00
int64_t nNow = GetAdjustedTime ( ) ;
2016-12-11 07:17:38 +01:00
int64_t nSuperblockCycleSeconds = Params ( ) . GetConsensus ( ) . nSuperblockCycle * Params ( ) . GetConsensus ( ) . nPowTargetSpacing ;
std : : string strHash = govobj . GetHash ( ) . ToString ( ) ;
2018-09-28 09:56:17 +02:00
if ( nTimestamp < nNow - 2 * nSuperblockCycleSeconds ) {
2018-02-15 08:29:44 +01:00
LogPrintf ( " CGovernanceManager::MasternodeRateCheck -- object %s rejected due to too old timestamp, masternode = %s, timestamp = %d, current time = %d \n " ,
2018-09-28 09:56:17 +02:00
strHash , masternodeOutpoint . ToStringShort ( ) , nTimestamp , nNow ) ;
2016-12-11 07:17:38 +01:00
return false ;
}
2018-09-28 09:56:17 +02:00
if ( nTimestamp > nNow + MAX_TIME_FUTURE_DEVIATION ) {
2018-02-15 08:29:44 +01:00
LogPrintf ( " CGovernanceManager::MasternodeRateCheck -- object %s rejected due to too new (future) timestamp, masternode = %s, timestamp = %d, current time = %d \n " ,
2018-09-28 09:56:17 +02:00
strHash , masternodeOutpoint . ToStringShort ( ) , nTimestamp , nNow ) ;
2016-12-11 07:17:38 +01:00
return false ;
2017-08-23 16:22:23 +02:00
}
2018-09-28 09:56:17 +02:00
txout_m_it it = mapLastMasternodeObject . find ( masternodeOutpoint ) ;
if ( it = = mapLastMasternodeObject . end ( ) ) return true ;
2017-08-23 16:22:23 +02:00
2018-09-28 09:56:17 +02:00
if ( it - > second . fStatusOK & & ! fForce ) {
2017-08-23 16:22:23 +02:00
fRateCheckBypassed = true ;
return true ;
2016-12-11 07:17:38 +01:00
}
2017-07-05 02:31:50 +02:00
2018-02-25 06:33:27 +01:00
// Allow 1 trigger per mn per cycle, with a small fudge factor
double dMaxRate = 2 * 1.1 / double ( nSuperblockCycleSeconds ) ;
// Temporary copy to check rate after new timestamp is added
CRateCheckBuffer buffer = it - > second . triggerBuffer ;
2016-10-17 20:54:28 +02:00
2017-04-05 18:30:08 +02:00
buffer . AddTimestamp ( nTimestamp ) ;
2018-02-25 06:33:27 +01:00
double dRate = buffer . GetRate ( ) ;
2017-04-05 18:30:08 +02:00
2018-09-28 09:56:17 +02:00
if ( dRate < dMaxRate ) {
2018-02-25 06:33:27 +01:00
return true ;
}
2017-04-05 18:30:08 +02:00
2018-02-25 06:33:27 +01:00
LogPrintf ( " CGovernanceManager::MasternodeRateCheck -- Rate too high: object hash = %s, masternode = %s, object timestamp = %d, rate = %f, max rate = %f \n " ,
2018-09-28 09:56:17 +02:00
strHash , masternodeOutpoint . ToStringShort ( ) , nTimestamp , dRate , dMaxRate ) ;
2017-07-05 02:31:50 +02:00
2018-09-28 09:56:17 +02:00
if ( fUpdateFailStatus ) {
2018-02-25 06:33:27 +01:00
it - > second . fStatusOK = false ;
2018-09-28 09:56:17 +02:00
}
2016-09-15 08:49:24 +02:00
2018-02-25 06:33:27 +01:00
return false ;
2016-09-05 01:44:10 +02:00
}
2017-09-19 16:51:38 +02:00
bool CGovernanceManager : : ProcessVote ( CNode * pfrom , const CGovernanceVote & vote , CGovernanceException & exception , CConnman & connman )
2016-11-13 18:52:34 +01:00
{
2017-07-21 11:47:38 +02:00
ENTER_CRITICAL_SECTION ( cs ) ;
2016-11-13 18:52:34 +01:00
uint256 nHashVote = vote . GetHash ( ) ;
2018-02-06 12:08:43 +01:00
uint256 nHashGovobj = vote . GetParentHash ( ) ;
2018-09-28 09:56:17 +02:00
if ( cmapVoteToObject . HasKey ( nHashVote ) ) {
2019-05-22 23:51:39 +02:00
LogPrint ( BCLog : : GOBJECT , " CGovernanceObject::ProcessVote -- skipping known valid vote %s for object %s \n " , nHashVote . ToString ( ) , nHashGovobj . ToString ( ) ) ;
2018-02-06 12:08:43 +01:00
LEAVE_CRITICAL_SECTION ( cs ) ;
return false ;
}
2018-09-28 09:56:17 +02:00
if ( cmapInvalidVotes . HasKey ( nHashVote ) ) {
2016-11-13 18:52:34 +01:00
std : : ostringstream ostr ;
ostr < < " CGovernanceManager::ProcessVote -- Old invalid vote "
2018-09-28 09:56:17 +02:00
< < " , MN outpoint = " < < vote . GetMasternodeOutpoint ( ) . ToStringShort ( )
< < " , governance object hash = " < < nHashGovobj . ToString ( ) ;
2017-06-06 01:47:23 +02:00
LogPrintf ( " %s \n " , ostr . str ( ) ) ;
2016-11-13 18:52:34 +01:00
exception = CGovernanceException ( ostr . str ( ) , GOVERNANCE_EXCEPTION_PERMANENT_ERROR , 20 ) ;
2017-07-21 11:47:38 +02:00
LEAVE_CRITICAL_SECTION ( cs ) ;
2016-11-13 18:52:34 +01:00
return false ;
}
object_m_it it = mapObjects . find ( nHashGovobj ) ;
2018-09-28 09:56:17 +02:00
if ( it = = mapObjects . end ( ) ) {
2016-11-14 21:26:53 +01:00
std : : ostringstream ostr ;
2018-02-06 12:08:43 +01:00
ostr < < " CGovernanceManager::ProcessVote -- Unknown parent object " < < nHashGovobj . ToString ( )
< < " , MN outpoint = " < < vote . GetMasternodeOutpoint ( ) . ToStringShort ( ) ;
2016-11-14 21:26:53 +01:00
exception = CGovernanceException ( ostr . str ( ) , GOVERNANCE_EXCEPTION_WARNING ) ;
2018-09-28 09:56:17 +02:00
if ( cmmapOrphanVotes . Insert ( nHashGovobj , vote_time_pair_t ( vote , GetAdjustedTime ( ) + GOVERNANCE_ORPHAN_EXPIRATION_TIME ) ) ) {
2017-07-21 11:47:38 +02:00
LEAVE_CRITICAL_SECTION ( cs ) ;
2017-09-19 16:51:38 +02:00
RequestGovernanceObject ( pfrom , nHashGovobj , connman ) ;
2017-06-06 01:47:23 +02:00
LogPrintf ( " %s \n " , ostr . str ( ) ) ;
2017-07-21 11:47:38 +02:00
return false ;
2016-11-14 21:26:53 +01:00
}
2017-07-21 11:47:38 +02:00
2019-05-22 23:51:39 +02:00
LogPrint ( BCLog : : GOBJECT , " %s \n " , ostr . str ( ) ) ;
2017-07-21 11:47:38 +02:00
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
2018-09-28 09:56:17 +02:00
if ( govobj . IsSetCachedDelete ( ) | | govobj . IsSetExpired ( ) ) {
2019-05-22 23:51:39 +02:00
LogPrint ( BCLog : : GOBJECT , " CGovernanceObject::ProcessVote -- ignoring vote for expired or deleted object, hash = %s \n " , nHashGovobj . ToString ( ) ) ;
2017-07-21 11:47:38 +02:00
LEAVE_CRITICAL_SECTION ( cs ) ;
2017-02-22 19:29:30 +01:00
return false ;
}
2018-02-06 12:08:43 +01:00
bool fOk = govobj . ProcessVote ( pfrom , vote , exception , connman ) & & cmapVoteToObject . Insert ( nHashVote , & govobj ) ;
2017-07-21 11:47:38 +02:00
LEAVE_CRITICAL_SECTION ( cs ) ;
2016-11-13 18:52:34 +01:00
return fOk ;
}
2017-09-19 16:51:38 +02:00
void CGovernanceManager : : CheckPostponedObjects ( CConnman & connman )
2017-07-05 02:31:50 +02:00
{
2018-09-28 09:56:17 +02:00
if ( ! masternodeSync . IsSynced ( ) ) return ;
2017-08-09 18:07:03 +02:00
2017-07-05 02:31:50 +02:00
LOCK2 ( cs_main , cs ) ;
// Check postponed proposals
2018-09-28 09:56:17 +02:00
for ( object_m_it it = mapPostponedObjects . begin ( ) ; it ! = mapPostponedObjects . end ( ) ; ) {
2017-07-05 02:31:50 +02:00
const uint256 & nHash = it - > first ;
CGovernanceObject & govobj = it - > second ;
2018-02-25 06:33:27 +01:00
assert ( govobj . GetObjectType ( ) ! = GOVERNANCE_OBJECT_TRIGGER ) ;
2017-07-05 02:31:50 +02:00
std : : string strError ;
bool fMissingConfirmations ;
2018-09-28 09:56:17 +02:00
if ( govobj . IsCollateralValid ( strError , fMissingConfirmations ) ) {
if ( govobj . IsValidLocally ( strError , false ) ) {
2017-09-19 16:51:38 +02:00
AddGovernanceObject ( govobj , connman ) ;
2018-09-28 09:56:17 +02:00
} else {
2017-07-05 02:31:50 +02:00
LogPrintf ( " CGovernanceManager::CheckPostponedObjects -- %s invalid \n " , nHash . ToString ( ) ) ;
2018-09-28 09:56:17 +02:00
}
2017-07-05 02:31:50 +02:00
2018-09-28 09:56:17 +02:00
} else if ( fMissingConfirmations ) {
2017-07-05 02:31:50 +02:00
// wait for more confirmations
2016-11-12 02:51:45 +01:00
+ + it ;
2017-07-05 02:31:50 +02:00
continue ;
}
// remove processed or invalid object from the queue
mapPostponedObjects . erase ( it + + ) ;
}
2018-02-25 06:33:27 +01:00
// Perform additional relays for triggers
2017-08-29 01:51:44 +02:00
int64_t nNow = GetAdjustedTime ( ) ;
2017-07-05 02:31:50 +02:00
int64_t nSuperblockCycleSeconds = Params ( ) . GetConsensus ( ) . nSuperblockCycle * Params ( ) . GetConsensus ( ) . nPowTargetSpacing ;
2018-09-28 09:56:17 +02:00
for ( hash_s_it it = setAdditionalRelayObjects . begin ( ) ; it ! = setAdditionalRelayObjects . end ( ) ; ) {
2017-07-05 02:31:50 +02:00
object_m_it itObject = mapObjects . find ( * it ) ;
2018-09-28 09:56:17 +02:00
if ( itObject ! = mapObjects . end ( ) ) {
2017-07-05 02:31:50 +02:00
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 ) ;
2018-09-28 09:56:17 +02:00
if ( fValid ) {
if ( fReady ) {
2017-07-05 02:31:50 +02:00
LogPrintf ( " CGovernanceManager::CheckPostponedObjects -- additional relay: hash = %s \n " , govobj . GetHash ( ) . ToString ( ) ) ;
2017-09-19 16:51:38 +02:00
govobj . Relay ( connman ) ;
2017-07-05 02:31:50 +02:00
} else {
it + + ;
continue ;
}
}
} else {
LogPrintf ( " CGovernanceManager::CheckPostponedObjects -- additional relay of unknown object: %s \n " , it - > ToString ( ) ) ;
2016-11-12 02:51:45 +01:00
}
2017-07-05 02:31:50 +02:00
setAdditionalRelayObjects . erase ( it + + ) ;
2016-11-12 02:51:45 +01:00
}
}
2017-09-19 16:51:38 +02:00
void CGovernanceManager : : RequestGovernanceObject ( CNode * pfrom , const uint256 & nHash , CConnman & connman , bool fUseFilter )
2016-11-13 18:52:34 +01:00
{
2018-09-28 09:56:17 +02:00
if ( ! pfrom ) {
2016-11-13 18:52:34 +01:00
return ;
}
2019-05-22 23:51:39 +02:00
LogPrint ( BCLog : : GOBJECT , " CGovernanceManager::RequestGovernanceObject -- nHash %s peer=%d \n " , nHash . ToString ( ) , pfrom - > GetId ( ) ) ;
2017-03-06 08:46:59 +01:00
2016-11-25 20:01:56 +01:00
CNetMsgMaker msgMaker ( pfrom - > GetSendVersion ( ) ) ;
2018-09-28 09:56:17 +02:00
if ( pfrom - > nVersion < GOVERNANCE_FILTER_PROTO_VERSION ) {
2016-11-25 20:01:56 +01:00
connman . PushMessage ( pfrom , msgMaker . Make ( NetMsgType : : MNGOVERNANCESYNC , nHash ) ) ;
2017-02-02 09:50:44 +01:00
return ;
}
CBloomFilter filter ;
filter . clear ( ) ;
2017-06-06 01:47:23 +02:00
int nVoteCount = 0 ;
2018-09-28 09:56:17 +02: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 ) ;
2018-09-28 09:56:17 +02:00
if ( pObj ) {
2017-02-02 09:50:44 +01:00
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 ( ) ;
2018-10-11 16:33:48 +02:00
for ( const auto & vote : vecVotes ) {
filter . insert ( vote . GetHash ( ) ) ;
2017-02-02 09:50:44 +01:00
}
}
}
2017-05-07 09:59:42 +02:00
LogPrint ( BCLog : : GOBJECT , " CGovernanceManager::RequestGovernanceObject -- nHash %s nVoteCount %d peer=%d \n " , nHash . ToString ( ) , nVoteCount , pfrom - > GetId ( ) ) ;
2016-11-25 20:01:56 +01:00
connman . PushMessage ( pfrom , msgMaker . Make ( NetMsgType : : MNGOVERNANCESYNC , nHash , filter ) ) ;
2016-11-13 18:52:34 +01:00
}
2017-09-19 16:51:38 +02:00
int CGovernanceManager : : RequestGovernanceObjectVotes ( CNode * pnode , CConnman & connman )
2017-01-17 21:02:38 +01:00
{
2018-09-28 09:56:17 +02:00
if ( pnode - > nVersion < MIN_GOVERNANCE_PEER_PROTO_VERSION ) return - 3 ;
2017-01-17 21:02:38 +01:00
std : : vector < CNode * > vNodesCopy ;
vNodesCopy . push_back ( pnode ) ;
2017-09-19 16:51:38 +02:00
return RequestGovernanceObjectVotes ( vNodesCopy , connman ) ;
2017-01-17 21:02:38 +01:00
}
2017-09-19 16:51:38 +02:00
int CGovernanceManager : : RequestGovernanceObjectVotes ( const std : : vector < CNode * > & vNodesCopy , CConnman & connman )
2017-01-17 21:02:38 +01:00
{
2017-02-02 14:04:45 +01:00
static std : : map < uint256 , std : : map < CService , int64_t > > mapAskedRecently ;
2018-09-28 09:56:17 +02: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 ;
2018-07-25 17:09:30 +02:00
std : : vector < uint256 > vTriggerObjHashes ;
std : : vector < uint256 > vOtherObjHashes ;
2017-03-08 23:36:40 +01:00
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 ;
2018-09-28 09:56:17 +02:00
if ( Params ( ) . NetworkIDString ( ) ! = CBaseChainParams : : MAIN ) {
2018-12-17 15:39:21 +01:00
nMaxObjRequestsPerNode = std : : max ( 1 , int ( nProjectedVotes / std : : max ( 1 , ( int ) deterministicMNManager - > GetListAtChainTip ( ) . GetValidMNsCount ( ) ) ) ) ;
2017-02-03 10:17:47 +01:00
}
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
2018-09-28 09:56:17 +02:00
if ( mapObjects . empty ( ) ) return - 2 ;
2017-03-08 23:36:40 +01:00
2018-07-12 11:07:51 +02:00
for ( const auto & objPair : mapObjects ) {
uint256 nHash = objPair . first ;
2018-09-28 09:56:17 +02:00
if ( mapAskedRecently . count ( nHash ) ) {
2018-07-12 11:07:51 +02:00
auto it = mapAskedRecently [ nHash ] . begin ( ) ;
2018-09-28 09:56:17 +02:00
while ( it ! = mapAskedRecently [ nHash ] . end ( ) ) {
if ( it - > second < nNow ) {
2018-07-12 11:07:51 +02:00
mapAskedRecently [ nHash ] . erase ( it + + ) ;
2017-03-08 23:36:40 +01:00
} else {
2018-07-12 11:07:51 +02:00
+ + it ;
2017-03-08 23:36:40 +01:00
}
2017-02-02 14:04:45 +01:00
}
2018-09-28 09:56:17 +02:00
if ( mapAskedRecently [ nHash ] . size ( ) > = nPeersPerHashMax ) continue ;
2017-03-08 23:36:40 +01:00
}
2018-07-12 11:07:51 +02:00
2019-08-23 20:03:05 +02:00
if ( objPair . second . GetObjectType ( ) = = GOVERNANCE_OBJECT_TRIGGER ) {
2018-07-25 17:09:30 +02:00
vTriggerObjHashes . push_back ( nHash ) ;
2017-03-08 23:36:40 +01:00
} else {
2018-07-25 17:09:30 +02:00
vOtherObjHashes . push_back ( nHash ) ;
2017-02-02 14:04:45 +01:00
}
}
2017-01-17 21:02:38 +01:00
}
2017-02-02 14:04:45 +01:00
2019-05-22 23:51:39 +02:00
LogPrint ( BCLog : : GOBJECT , " CGovernanceManager::RequestGovernanceObjectVotes -- start: vTriggerObjHashes %d vOtherObjHashes %d mapAskedRecently %d \n " ,
2018-09-28 09:56:17 +02:00
vTriggerObjHashes . size ( ) , vOtherObjHashes . size ( ) , mapAskedRecently . size ( ) ) ;
2017-02-02 14:04:45 +01:00
2018-01-12 16:37:39 +01:00
FastRandomContext insecure_rand ;
2018-07-25 17:09:30 +02:00
std : : random_shuffle ( vTriggerObjHashes . begin ( ) , vTriggerObjHashes . end ( ) , insecure_rand ) ;
std : : random_shuffle ( vOtherObjHashes . begin ( ) , vOtherObjHashes . end ( ) , insecure_rand ) ;
2017-02-02 14:04:45 +01:00
for ( int i = 0 ; i < nMaxObjRequestsPerNode ; + + i ) {
2017-01-17 21:02:38 +01:00
uint256 nHashGovobj ;
2017-02-02 14:04:45 +01:00
2017-01-17 21:02:38 +01:00
// ask for triggers first
2018-09-28 09:56:17 +02:00
if ( vTriggerObjHashes . size ( ) ) {
2018-07-25 17:09:30 +02:00
nHashGovobj = vTriggerObjHashes . back ( ) ;
2017-02-02 14:04:45 +01:00
} else {
2018-09-28 09:56:17 +02:00
if ( vOtherObjHashes . empty ( ) ) break ;
2018-07-25 17:09:30 +02:00
nHashGovobj = vOtherObjHashes . back ( ) ;
2017-02-02 14:04:45 +01:00
}
bool fAsked = false ;
2018-02-06 12:09:33 +01:00
for ( const auto & pnode : vNodesCopy ) {
2017-07-03 15:14:07 +02:00
// Only use regular peers, don't try to ask from outbound "masternode" connections -
2017-02-16 16:14:42 +01:00
// they stay connected for a short period of time and it's possible that we won't get everything we should.
// Only use outbound connections - inbound connection could be a "masternode" connection
2017-07-03 15:14:07 +02:00
// initiated from another node, so skip it too.
2018-09-28 09:56:17 +02:00
if ( pnode - > fMasternode | | ( fMasternodeMode & & pnode - > fInbound ) ) continue ;
2017-02-02 14:04:45 +01:00
// only use up to date peers
2018-09-28 09:56:17 +02:00
if ( pnode - > nVersion < MIN_GOVERNANCE_PEER_PROTO_VERSION ) continue ;
2017-02-02 14:04:45 +01:00
// stop early to prevent setAskFor overflow
2018-10-26 18:42:11 +02:00
{
LOCK ( cs_main ) ;
size_t nProjectedSize = pnode - > setAskFor . size ( ) + nProjectedVotes ;
if ( nProjectedSize > SETASKFOR_MAX_SZ / 2 ) continue ;
// to early to ask the same node
if ( mapAskedRecently [ nHashGovobj ] . count ( pnode - > addr ) ) continue ;
}
2017-02-02 14:04:45 +01:00
2017-09-19 16:51:38 +02:00
RequestGovernanceObject ( pnode , nHashGovobj , connman , true ) ;
2017-02-02 14:04:45 +01:00
mapAskedRecently [ nHashGovobj ] [ pnode - > addr ] = nNow + nTimeout ;
fAsked = true ;
// stop loop if max number of peers per obj was asked
2018-09-28 09:56:17 +02:00
if ( mapAskedRecently [ nHashGovobj ] . size ( ) > = nPeersPerHashMax ) break ;
2017-02-02 14:04:45 +01:00
}
// NOTE: this should match `if` above (the one before `while`)
2018-09-28 09:56:17 +02:00
if ( vTriggerObjHashes . size ( ) ) {
2018-07-25 17:09:30 +02:00
vTriggerObjHashes . pop_back ( ) ;
2017-01-17 21:02:38 +01:00
} else {
2018-07-25 17:09:30 +02:00
vOtherObjHashes . pop_back ( ) ;
2017-01-17 21:02:38 +01:00
}
2018-09-28 09:56:17 +02:00
if ( ! fAsked ) i - - ;
2017-01-17 21:02:38 +01:00
}
2019-05-22 23:51:39 +02:00
LogPrint ( BCLog : : GOBJECT , " CGovernanceManager::RequestGovernanceObjectVotes -- end: vTriggerObjHashes %d vOtherObjHashes %d mapAskedRecently %d \n " ,
2018-09-28 09:56:17 +02:00
vTriggerObjHashes . size ( ) , vOtherObjHashes . size ( ) , mapAskedRecently . size ( ) ) ;
2017-02-17 21:08:41 +01:00
2018-07-25 17:09:30 +02:00
return int ( vTriggerObjHashes . size ( ) + vOtherObjHashes . 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 ) ;
2018-09-28 09:56:17 +02:00
if ( it = = setHash . end ( ) ) {
2016-11-13 18:52:34 +01:00
// We never requested this
return false ;
}
// Only accept one response
setHash . erase ( it ) ;
return true ;
}
void CGovernanceManager : : RebuildIndexes ( )
{
2018-03-09 15:15:48 +01:00
LOCK ( cs ) ;
2018-02-06 12:08:43 +01:00
cmapVoteToObject . Clear ( ) ;
2018-07-12 11:07:51 +02:00
for ( auto & objPair : mapObjects ) {
CGovernanceObject & govobj = objPair . second ;
2016-11-13 18:52:34 +01:00
std : : vector < CGovernanceVote > vecVotes = govobj . GetVoteFile ( ) . GetVotes ( ) ;
2018-09-28 09:56:17 +02:00
for ( size_t i = 0 ; i < vecVotes . size ( ) ; + + i ) {
2018-02-06 12:08:43 +01:00
cmapVoteToObject . Insert ( vecVotes [ i ] . GetHash ( ) , & govobj ) ;
2016-11-13 18:52:34 +01:00
}
}
}
2016-11-05 17:13:30 +01:00
void CGovernanceManager : : AddCachedTriggers ( )
{
LOCK ( cs ) ;
2018-06-06 17:56:33 +02:00
for ( auto & objpair : mapObjects ) {
CGovernanceObject & govobj = objpair . second ;
2017-07-05 02:31:50 +02:00
2019-08-23 20:03:05 +02:00
if ( govobj . GetObjectType ( ) ! = GOVERNANCE_OBJECT_TRIGGER ) {
2016-11-05 17:13:30 +01:00
continue ;
}
2018-06-06 17:56:33 +02:00
if ( ! triggerman . AddNewTrigger ( govobj . GetHash ( ) ) ) {
2019-08-23 20:03:05 +02:00
govobj . PrepareDeletion ( GetAdjustedTime ( ) ) ;
2018-06-06 17:56:33 +02:00
}
2016-11-13 18:52:34 +01:00
}
}
2016-11-28 15:21:50 +01:00
void CGovernanceManager : : InitOnLoad ( )
{
LOCK ( cs ) ;
2016-11-30 02:33:47 +01:00
int64_t nStart = GetTimeMillis ( ) ;
LogPrintf ( " Preparing masternode indexes and governance triggers... \n " ) ;
2016-11-28 15:21:50 +01:00
RebuildIndexes ( ) ;
AddCachedTriggers ( ) ;
2016-11-30 02:33:47 +01:00
LogPrintf ( " Masternode indexes and governance triggers prepared %dms \n " , GetTimeMillis ( ) - nStart ) ;
LogPrintf ( " %s \n " , ToString ( ) ) ;
2016-11-28 15:21:50 +01:00
}
2016-04-09 22:55:52 +02:00
std : : string CGovernanceManager : : ToString ( ) const
2016-04-09 21:57:53 +02:00
{
2016-12-12 02:44:46 +01:00
LOCK ( cs ) ;
int nProposalCount = 0 ;
int nTriggerCount = 0 ;
int nOtherCount = 0 ;
2016-04-09 21:57:53 +02:00
2018-07-12 11:07:51 +02:00
for ( const auto & objPair : mapObjects ) {
2018-09-28 09:56:17 +02:00
switch ( objPair . second . GetObjectType ( ) ) {
case GOVERNANCE_OBJECT_PROPOSAL :
nProposalCount + + ;
break ;
case GOVERNANCE_OBJECT_TRIGGER :
nTriggerCount + + ;
break ;
default :
nOtherCount + + ;
break ;
2016-12-12 02:44:46 +01:00
}
}
2016-04-09 21:57:53 +02:00
2018-02-25 06:33:27 +01:00
return strprintf ( " Governance Objects: %d (Proposals: %d, Triggers: %d, Other: %d; Erased: %d), Votes: %d " ,
2018-09-28 09:56:17 +02:00
( int ) mapObjects . size ( ) ,
nProposalCount , nTriggerCount , nOtherCount , ( int ) mapErasedGovernanceObjects . size ( ) ,
( int ) cmapVoteToObject . GetSize ( ) ) ;
2016-04-09 21:57:53 +02:00
}
2018-03-15 20:09:06 +01:00
UniValue CGovernanceManager : : ToJson ( ) const
{
LOCK ( cs ) ;
int nProposalCount = 0 ;
int nTriggerCount = 0 ;
int nOtherCount = 0 ;
for ( const auto & objpair : mapObjects ) {
2018-09-28 09:56:17 +02:00
switch ( objpair . second . GetObjectType ( ) ) {
case GOVERNANCE_OBJECT_PROPOSAL :
nProposalCount + + ;
break ;
case GOVERNANCE_OBJECT_TRIGGER :
nTriggerCount + + ;
break ;
default :
nOtherCount + + ;
break ;
2018-03-15 20:09:06 +01:00
}
}
UniValue jsonObj ( UniValue : : VOBJ ) ;
jsonObj . push_back ( Pair ( " objects_total " , ( int ) mapObjects . size ( ) ) ) ;
jsonObj . push_back ( Pair ( " proposals " , nProposalCount ) ) ;
jsonObj . push_back ( Pair ( " triggers " , nTriggerCount ) ) ;
jsonObj . push_back ( Pair ( " other " , nOtherCount ) ) ;
jsonObj . push_back ( Pair ( " erased " , ( int ) mapErasedGovernanceObjects . size ( ) ) ) ;
jsonObj . push_back ( Pair ( " votes " , ( int ) cmapVoteToObject . GetSize ( ) ) ) ;
return jsonObj ;
}
2018-09-28 09:56:17 +02:00
void CGovernanceManager : : UpdatedBlockTip ( const CBlockIndex * pindex , CConnman & connman )
2016-04-09 21:57:53 +02:00
{
2016-08-17 09:08:25 +02:00
// Note this gets called from ActivateBestChain without cs_main being held
// so it should be safe to lock our mutex here without risking a deadlock
2016-09-12 09:40:00 +02:00
// On the other hand it should be safe for us to access pindex without holding a lock
2016-08-17 09:08:25 +02:00
// on cs_main because the CBlockIndex objects are dynamically allocated and
// presumably never deleted.
2018-09-28 09:56:17 +02:00
if ( ! pindex ) {
2016-11-12 12:14:50 +01:00
return ;
}
2017-08-25 14:57:05 +02:00
nCachedBlockHeight = pindex - > nHeight ;
2019-05-22 23:51:39 +02:00
LogPrint ( BCLog : : GOBJECT , " CGovernanceManager::UpdatedBlockTip -- nCachedBlockHeight: %d \n " , nCachedBlockHeight ) ;
2017-07-05 02:31:50 +02:00
2019-01-29 15:54:38 +01:00
if ( deterministicMNManager - > IsDIP3Enforced ( pindex - > nHeight ) ) {
2019-03-30 15:54:22 +01:00
RemoveInvalidVotes ( ) ;
2018-11-29 19:51:53 +01:00
}
2017-09-19 16:51:38 +02:00
CheckPostponedObjects ( connman ) ;
2018-02-12 19:35:10 +01:00
CSuperblockManager : : ExecuteBestSuperblock ( pindex - > nHeight ) ;
2017-03-06 08:46:59 +01:00
}
2017-09-19 16:51:38 +02:00
void CGovernanceManager : : RequestOrphanObjects ( CConnman & connman )
2017-03-06 08:46:59 +01:00
{
2018-01-22 14:17:11 +01:00
std : : vector < CNode * > vNodesCopy = connman . CopyNodeVector ( CConnman : : FullyConnectedOnly ) ;
2017-03-06 08:46:59 +01:00
2017-03-08 23:36:40 +01:00
std : : vector < uint256 > vecHashesFiltered ;
2017-03-06 08:46:59 +01:00
{
std : : vector < uint256 > vecHashes ;
2017-03-08 23:36:40 +01:00
LOCK ( cs ) ;
2018-02-06 12:08:43 +01:00
cmmapOrphanVotes . GetKeys ( vecHashes ) ;
2018-10-11 16:33:48 +02:00
for ( const uint256 & nHash : vecHashes ) {
2018-09-28 09:56:17 +02:00
if ( mapObjects . find ( nHash ) = = mapObjects . end ( ) ) {
2017-03-08 23:36:40 +01:00
vecHashesFiltered . push_back ( nHash ) ;
2017-03-06 08:46:59 +01:00
}
2017-03-08 23:36:40 +01:00
}
}
2019-05-22 23:51:39 +02:00
LogPrint ( BCLog : : GOBJECT , " CGovernanceObject::RequestOrphanObjects -- number objects = %d \n " , vecHashesFiltered . size ( ) ) ;
2018-10-11 16:33:48 +02:00
for ( const uint256 & nHash : vecHashesFiltered ) {
for ( CNode * pnode : vNodesCopy ) {
2018-09-28 09:56:17 +02:00
if ( pnode - > fMasternode ) {
2017-03-08 23:36:40 +01:00
continue ;
2017-03-06 08:46:59 +01:00
}
2017-09-19 16:51:38 +02:00
RequestGovernanceObject ( pnode , nHash , connman ) ;
2017-03-06 08:46:59 +01:00
}
}
2017-09-19 16:51:38 +02:00
connman . ReleaseNodeVector ( vNodesCopy ) ;
2017-03-06 08:46:59 +01:00
}
void CGovernanceManager : : CleanOrphanObjects ( )
{
2016-08-17 09:08:25 +02:00
LOCK ( cs ) ;
2018-02-06 12:08:43 +01:00
const vote_cmm_t : : list_t & items = cmmapOrphanVotes . GetItemList ( ) ;
2016-08-17 09:08:25 +02:00
2017-03-06 08:46:59 +01:00
int64_t nNow = GetAdjustedTime ( ) ;
2016-04-09 21:57:53 +02:00
2018-02-06 12:08:43 +01:00
vote_cmm_t : : list_cit it = items . begin ( ) ;
2018-09-28 09:56:17 +02:00
while ( it ! = items . end ( ) ) {
2018-02-06 12:08:43 +01:00
vote_cmm_t : : list_cit prevIt = it ;
2017-03-06 08:46:59 +01:00
+ + it ;
const vote_time_pair_t & pairVote = prevIt - > value ;
2018-09-28 09:56:17 +02:00
if ( pairVote . second < nNow ) {
2018-02-06 12:08:43 +01:00
cmmapOrphanVotes . Erase ( prevIt - > key , prevIt - > value ) ;
2017-03-06 08:46:59 +01:00
}
}
2016-04-09 21:57:53 +02:00
}
2018-11-29 19:51:53 +01:00
2019-03-30 15:54:22 +01:00
void CGovernanceManager : : RemoveInvalidVotes ( )
2018-12-20 14:27:48 +01:00
{
2019-04-08 07:38:13 +02:00
if ( ! masternodeSync . IsSynced ( ) ) {
return ;
}
2018-12-20 14:27:48 +01:00
LOCK ( cs ) ;
2019-04-08 07:38:13 +02:00
auto curMNList = deterministicMNManager - > GetListAtChainTip ( ) ;
auto diff = lastMNListForVotingKeys . BuildDiff ( curMNList ) ;
2018-12-20 14:27:48 +01:00
std : : vector < COutPoint > changedKeyMNs ;
for ( const auto & p : diff . updatedMNs ) {
2019-07-09 07:59:57 +02:00
auto oldDmn = lastMNListForVotingKeys . GetMNByInternalId ( p . first ) ;
if ( ( p . second . fields & CDeterministicMNStateDiff : : Field_keyIDVoting ) & & p . second . state . keyIDVoting ! = oldDmn - > pdmnState - > keyIDVoting ) {
2018-12-20 14:27:48 +01:00
changedKeyMNs . emplace_back ( oldDmn - > collateralOutpoint ) ;
2019-07-09 07:59:57 +02:00
} else if ( ( p . second . fields & CDeterministicMNStateDiff : : Field_pubKeyOperator ) & & p . second . state . pubKeyOperator ! = oldDmn - > pdmnState - > pubKeyOperator ) {
2019-03-30 15:54:22 +01:00
changedKeyMNs . emplace_back ( oldDmn - > collateralOutpoint ) ;
2018-12-20 14:27:48 +01:00
}
}
2019-07-09 07:59:57 +02:00
for ( const auto & id : diff . removedMns ) {
auto oldDmn = lastMNListForVotingKeys . GetMNByInternalId ( id ) ;
2018-12-20 14:27:48 +01:00
changedKeyMNs . emplace_back ( oldDmn - > collateralOutpoint ) ;
}
for ( const auto & outpoint : changedKeyMNs ) {
for ( auto & p : mapObjects ) {
2019-03-30 15:54:22 +01:00
auto removed = p . second . RemoveInvalidVotes ( outpoint ) ;
2018-12-20 14:27:48 +01:00
if ( removed . empty ( ) ) {
continue ;
}
for ( auto & voteHash : removed ) {
cmapVoteToObject . Erase ( voteHash ) ;
cmapInvalidVotes . Erase ( voteHash ) ;
cmmapOrphanVotes . Erase ( voteHash ) ;
setRequestedVotes . erase ( voteHash ) ;
}
}
}
// store current MN list for the next run so that we can determine which keys changed
lastMNListForVotingKeys = curMNList ;
}