2016-04-09 22:31:01 +02:00
//# ----
2016-04-09 21:57:53 +02:00
// Copyright (c) 2014-2016 The Dash Core developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
# include "core_io.h"
# include "main.h"
# include "init.h"
# include "masternode-budget.h"
# include "masternode.h"
# include "darksend.h"
# include "masternodeman.h"
# include "masternode-sync.h"
# include "util.h"
# include "addrman.h"
# include <boost/filesystem.hpp>
# include <boost/lexical_cast.hpp>
CBudgetManager budget ;
CCriticalSection cs_budget ;
std : : map < uint256 , int64_t > askedForSourceProposalOrBudget ;
std : : vector < CBudgetProposalBroadcast > vecImmatureBudgetProposals ;
int nSubmittedFinalBudget ;
bool IsBudgetCollateralValid ( uint256 nTxCollateralHash , uint256 nExpectedHash , std : : string & strError , int64_t & nTime , int & nConf )
{
CTransaction txCollateral ;
uint256 nBlockHash ;
if ( ! GetTransaction ( nTxCollateralHash , txCollateral , Params ( ) . GetConsensus ( ) , nBlockHash , true ) ) {
strError = strprintf ( " Can't find collateral tx %s " , txCollateral . ToString ( ) ) ;
LogPrintf ( " CBudgetProposalBroadcast::IsBudgetCollateralValid - %s \n " , strError ) ;
return false ;
}
if ( txCollateral . vout . size ( ) < 1 ) return false ;
if ( txCollateral . nLockTime ! = 0 ) return false ;
CScript findScript ;
findScript < < OP_RETURN < < ToByteVector ( nExpectedHash ) ;
bool foundOpReturn = false ;
BOOST_FOREACH ( const CTxOut o , txCollateral . vout ) {
if ( ! o . scriptPubKey . IsNormalPaymentScript ( ) & & ! o . scriptPubKey . IsUnspendable ( ) ) {
strError = strprintf ( " Invalid Script %s " , txCollateral . ToString ( ) ) ;
LogPrintf ( " CBudgetProposalBroadcast::IsBudgetCollateralValid - %s \n " , strError ) ;
return false ;
}
if ( o . scriptPubKey = = findScript & & o . nValue > = BUDGET_FEE_TX ) foundOpReturn = true ;
}
if ( ! foundOpReturn ) {
strError = strprintf ( " Couldn't find opReturn %s in %s " , nExpectedHash . ToString ( ) , txCollateral . ToString ( ) ) ;
LogPrintf ( " CBudgetProposalBroadcast::IsBudgetCollateralValid - %s \n " , strError ) ;
return false ;
}
LOCK ( cs_main ) ;
int conf = GetIXConfirmations ( nTxCollateralHash ) ;
if ( nBlockHash ! = uint256 ( ) ) {
BlockMap : : iterator mi = mapBlockIndex . find ( nBlockHash ) ;
if ( mi ! = mapBlockIndex . end ( ) & & ( * mi ) . second ) {
CBlockIndex * pindex = ( * mi ) . second ;
if ( chainActive . Contains ( pindex ) ) {
conf + = chainActive . Height ( ) - pindex - > nHeight + 1 ;
nTime = pindex - > nTime ;
}
}
}
nConf = conf ;
//if we're syncing we won't have instantX information, so accept 1 confirmation
if ( conf > = BUDGET_FEE_CONFIRMATIONS ) {
return true ;
} else {
strError = strprintf ( " Collateral requires at least %d confirmations - %d confirmations " , BUDGET_FEE_CONFIRMATIONS , conf ) ;
LogPrintf ( " CBudgetProposalBroadcast::IsBudgetCollateralValid - %s - %d confirmations \n " , strError , conf ) ;
return false ;
}
}
void CBudgetManager : : CheckOrphanVotes ( )
{
LOCK ( cs ) ;
std : : string strError = " " ;
std : : map < uint256 , CBudgetVote > : : iterator it1 = mapOrphanMasternodeBudgetVotes . begin ( ) ;
while ( it1 ! = mapOrphanMasternodeBudgetVotes . end ( ) ) {
if ( budget . UpdateProposal ( ( ( * it1 ) . second ) , NULL , strError ) ) {
LogPrintf ( " CBudgetManager::CheckOrphanVotes - Proposal/Budget is known, activating and removing orphan vote \n " ) ;
mapOrphanMasternodeBudgetVotes . erase ( it1 + + ) ;
} else {
+ + it1 ;
}
}
}
//
// CBudgetDB
//
CBudgetDB : : CBudgetDB ( )
{
pathDB = GetDataDir ( ) / " budget.dat " ;
strMagicMessage = " MasternodeBudget " ;
}
bool CBudgetDB : : Write ( const CBudgetManager & objToSave )
{
LOCK ( objToSave . cs ) ;
int64_t nStart = GetTimeMillis ( ) ;
// serialize, checksum data up to that point, then append checksum
CDataStream ssObj ( SER_DISK , CLIENT_VERSION ) ;
ssObj < < strMagicMessage ; // masternode cache file specific magic message
ssObj < < FLATDATA ( Params ( ) . MessageStart ( ) ) ; // network specific magic number
ssObj < < objToSave ;
uint256 hash = Hash ( ssObj . begin ( ) , ssObj . end ( ) ) ;
ssObj < < hash ;
// open output file, and associate with CAutoFile
FILE * file = fopen ( pathDB . string ( ) . c_str ( ) , " wb " ) ;
CAutoFile fileout ( file , SER_DISK , CLIENT_VERSION ) ;
if ( fileout . IsNull ( ) )
return error ( " %s : Failed to open file %s " , __func__ , pathDB . string ( ) ) ;
// Write and commit header, data
try {
fileout < < ssObj ;
}
catch ( std : : exception & e ) {
return error ( " %s : Serialize or I/O error - %s " , __func__ , e . what ( ) ) ;
}
fileout . fclose ( ) ;
LogPrintf ( " Written info to budget.dat %dms \n " , GetTimeMillis ( ) - nStart ) ;
LogPrintf ( " Budget manager - %s \n " , objToSave . ToString ( ) ) ;
return true ;
}
CBudgetDB : : ReadResult CBudgetDB : : Read ( CBudgetManager & objToLoad , bool fDryRun )
{
//LOCK(objToLoad.cs);
int64_t nStart = GetTimeMillis ( ) ;
// open input file, and associate with CAutoFile
FILE * file = fopen ( pathDB . string ( ) . c_str ( ) , " rb " ) ;
CAutoFile filein ( file , SER_DISK , CLIENT_VERSION ) ;
if ( filein . IsNull ( ) )
{
error ( " %s : Failed to open file %s " , __func__ , pathDB . string ( ) ) ;
return FileError ;
}
// use file size to size memory buffer
int fileSize = boost : : filesystem : : file_size ( pathDB ) ;
int dataSize = fileSize - sizeof ( uint256 ) ;
// Don't try to resize to a negative number if file is small
if ( dataSize < 0 )
dataSize = 0 ;
vector < unsigned char > vchData ;
vchData . resize ( dataSize ) ;
uint256 hashIn ;
// read data and checksum from file
try {
filein . read ( ( char * ) & vchData [ 0 ] , dataSize ) ;
filein > > hashIn ;
}
catch ( std : : exception & e ) {
error ( " %s : Deserialize or I/O error - %s " , __func__ , e . what ( ) ) ;
return HashReadError ;
}
filein . fclose ( ) ;
CDataStream ssObj ( vchData , SER_DISK , CLIENT_VERSION ) ;
// verify stored checksum matches input data
uint256 hashTmp = Hash ( ssObj . begin ( ) , ssObj . end ( ) ) ;
if ( hashIn ! = hashTmp )
{
error ( " %s : Checksum mismatch, data corrupted " , __func__ ) ;
return IncorrectHash ;
}
unsigned char pchMsgTmp [ 4 ] ;
std : : string strMagicMessageTmp ;
try {
// de-serialize file header (masternode cache file specific magic message) and ..
ssObj > > strMagicMessageTmp ;
// ... verify the message matches predefined one
if ( strMagicMessage ! = strMagicMessageTmp )
{
error ( " %s : Invalid masternode cache magic message " , __func__ ) ;
return IncorrectMagicMessage ;
}
// de-serialize file header (network specific magic number) and ..
ssObj > > FLATDATA ( pchMsgTmp ) ;
// ... verify the network matches ours
if ( memcmp ( pchMsgTmp , Params ( ) . MessageStart ( ) , sizeof ( pchMsgTmp ) ) )
{
error ( " %s : Invalid network magic number " , __func__ ) ;
return IncorrectMagicNumber ;
}
// de-serialize data into CBudgetManager object
ssObj > > objToLoad ;
}
catch ( std : : exception & e ) {
objToLoad . Clear ( ) ;
error ( " %s : Deserialize or I/O error - %s " , __func__ , e . what ( ) ) ;
return IncorrectFormat ;
}
LogPrintf ( " Loaded info from budget.dat %dms \n " , GetTimeMillis ( ) - nStart ) ;
LogPrintf ( " %s \n " , objToLoad . ToString ( ) ) ;
if ( ! fDryRun ) {
LogPrintf ( " Budget manager - cleaning.... \n " ) ;
objToLoad . CheckAndRemove ( ) ;
LogPrintf ( " Budget manager - %s \n " , objToLoad . ToString ( ) ) ;
}
return Ok ;
}
void DumpBudgets ( )
{
int64_t nStart = GetTimeMillis ( ) ;
CBudgetDB budgetdb ;
CBudgetManager tempBudget ;
LogPrintf ( " Verifying budget.dat format... \n " ) ;
CBudgetDB : : ReadResult readResult = budgetdb . Read ( tempBudget , true ) ;
// there was an error and it was not an error on file opening => do not proceed
if ( readResult = = CBudgetDB : : FileError )
LogPrintf ( " Missing budgets file - budget.dat, will try to recreate \n " ) ;
else if ( readResult ! = CBudgetDB : : Ok )
{
LogPrintf ( " Error reading budget.dat: " ) ;
if ( readResult = = CBudgetDB : : IncorrectFormat )
LogPrintf ( " magic is ok but data has invalid format, will try to recreate \n " ) ;
else
{
LogPrintf ( " file format is unknown or invalid, please fix it manually \n " ) ;
return ;
}
}
LogPrintf ( " Writting info to budget.dat... \n " ) ;
budgetdb . Write ( budget ) ;
LogPrintf ( " Budget dump finished %dms \n " , GetTimeMillis ( ) - nStart ) ;
}
bool CBudgetManager : : AddProposal ( CBudgetProposal & budgetProposal )
{
LOCK ( cs ) ;
std : : string strError = " " ;
if ( ! budgetProposal . IsValid ( pCurrentBlockIndex , strError ) ) {
LogPrintf ( " CBudgetManager::AddProposal - invalid budget proposal - %s \n " , strError ) ;
return false ;
}
if ( mapProposals . count ( budgetProposal . GetHash ( ) ) ) {
return false ;
}
mapProposals . insert ( make_pair ( budgetProposal . GetHash ( ) , budgetProposal ) ) ;
return true ;
}
void CBudgetManager : : CheckAndRemove ( )
{
LogPrintf ( " CBudgetManager::CheckAndRemove \n " ) ;
if ( ! pCurrentBlockIndex ) return ;
std : : map < uint256 , CBudgetProposal > : : iterator it2 = mapProposals . begin ( ) ;
while ( it2 ! = mapProposals . end ( ) )
{
CBudgetProposal * pbudgetProposal = & ( ( * it2 ) . second ) ;
pbudgetProposal - > fValid = pbudgetProposal - > IsValid ( pCurrentBlockIndex , strError ) ;
+ + it2 ;
}
}
CBudgetProposal * CBudgetManager : : FindProposal ( const std : : string & strProposalName )
{
//find the prop with the highest yes count
int nYesCount = - 99999 ;
CBudgetProposal * pbudgetProposal = NULL ;
std : : map < uint256 , CBudgetProposal > : : iterator it = mapProposals . begin ( ) ;
while ( it ! = mapProposals . end ( ) ) {
if ( ( * it ) . second . strProposalName = = strProposalName & & ( * it ) . second . GetYesCount ( ) > nYesCount ) {
pbudgetProposal = & ( ( * it ) . second ) ;
nYesCount = pbudgetProposal - > GetYesCount ( ) ;
}
+ + it ;
}
if ( nYesCount = = - 99999 ) return NULL ;
return pbudgetProposal ;
}
CBudgetProposal * CBudgetManager : : FindProposal ( uint256 nHash )
{
LOCK ( cs ) ;
if ( mapProposals . count ( nHash ) )
return & mapProposals [ nHash ] ;
return NULL ;
}
bool CBudgetManager : : IsTransactionValid ( const CTransaction & txNew , int nBlockHeight )
{
LOCK ( cs ) ;
int nHighestCount = 0 ;
std : : vector < CFinalizedBudget * > ret ;
// ------- Grab The Highest Count
std : : map < uint256 , CFinalizedBudget > : : iterator it = mapFinalizedBudgets . begin ( ) ;
while ( it ! = mapFinalizedBudgets . end ( ) )
{
CFinalizedBudget * pfinalizedBudget = & ( ( * it ) . second ) ;
if ( pfinalizedBudget - > GetVoteCount ( ) > nHighestCount & &
nBlockHeight > = pfinalizedBudget - > GetBlockStart ( ) & &
nBlockHeight < = pfinalizedBudget - > GetBlockEnd ( ) ) {
nHighestCount = pfinalizedBudget - > GetVoteCount ( ) ;
}
+ + it ;
}
/*
If budget doesn ' t have 5 % of the network votes , then we should pay a masternode instead
*/
if ( nHighestCount < mnodeman . CountEnabled ( MIN_BUDGET_PEER_PROTO_VERSION ) / 20 ) return false ;
// check the highest finalized budgets (+/- 10% to assist in consensus)
it = mapFinalizedBudgets . begin ( ) ;
while ( it ! = mapFinalizedBudgets . end ( ) )
{
CFinalizedBudget * pfinalizedBudget = & ( ( * it ) . second ) ;
if ( pfinalizedBudget - > GetVoteCount ( ) > nHighestCount - mnodeman . CountEnabled ( MIN_BUDGET_PEER_PROTO_VERSION ) / 10 ) {
if ( nBlockHeight > = pfinalizedBudget - > GetBlockStart ( ) & & nBlockHeight < = pfinalizedBudget - > GetBlockEnd ( ) ) {
if ( pfinalizedBudget - > IsTransactionValid ( txNew , nBlockHeight ) ) {
return true ;
}
}
}
+ + it ;
}
//we looked through all of the known budgets
return false ;
}
std : : vector < CBudgetProposal * > CBudgetManager : : GetAllProposals ( )
{
LOCK ( cs ) ;
std : : vector < CBudgetProposal * > vBudgetProposalRet ;
std : : map < uint256 , CBudgetProposal > : : iterator it = mapProposals . begin ( ) ;
while ( it ! = mapProposals . end ( ) )
{
( * it ) . second . CleanAndRemove ( false ) ;
CBudgetProposal * pbudgetProposal = & ( ( * it ) . second ) ;
vBudgetProposalRet . push_back ( pbudgetProposal ) ;
+ + it ;
}
return vBudgetProposalRet ;
}
//
// Sort by votes, if there's a tie sort by their feeHash TX
//
struct sortProposalsByVotes {
bool operator ( ) ( const std : : pair < CBudgetProposal * , int > & left , const std : : pair < CBudgetProposal * , int > & right ) {
if ( left . second ! = right . second )
return ( left . second > right . second ) ;
return ( UintToArith256 ( left . first - > nFeeTXHash ) > UintToArith256 ( right . first - > nFeeTXHash ) ) ;
}
} ;
//Need to review this function
std : : vector < CBudgetProposal * > CBudgetManager : : GetBudget ( )
{
LOCK ( cs ) ;
// ------- Sort budgets by Yes Count
std : : vector < std : : pair < CBudgetProposal * , int > > vBudgetPorposalsSort ;
std : : map < uint256 , CBudgetProposal > : : iterator it = mapProposals . begin ( ) ;
while ( it ! = mapProposals . end ( ) ) {
( * it ) . second . CleanAndRemove ( false ) ;
vBudgetPorposalsSort . push_back ( make_pair ( & ( ( * it ) . second ) , ( * it ) . second . GetYesCount ( ) - ( * it ) . second . GetNoCount ( ) ) ) ;
+ + it ;
}
std : : sort ( vBudgetPorposalsSort . begin ( ) , vBudgetPorposalsSort . end ( ) , sortProposalsByVotes ( ) ) ;
// ------- Grab The Budgets In Order
std : : vector < CBudgetProposal * > vBudgetProposalsRet ;
CAmount nBudgetAllocated = 0 ;
if ( ! pCurrentBlockIndex ) return vBudgetProposalsRet ;
int nBlockStart = pCurrentBlockIndex - > nHeight - pCurrentBlockIndex - > nHeight % Params ( ) . GetConsensus ( ) . nBudgetPaymentsCycleBlocks + Params ( ) . GetConsensus ( ) . nBudgetPaymentsCycleBlocks ;
int nBlockEnd = nBlockStart + Params ( ) . GetConsensus ( ) . nBudgetPaymentsWindowBlocks ;
CAmount nTotalBudget = GetTotalBudget ( nBlockStart ) ;
std : : vector < std : : pair < CBudgetProposal * , int > > : : iterator it2 = vBudgetPorposalsSort . begin ( ) ;
while ( it2 ! = vBudgetPorposalsSort . end ( ) )
{
CBudgetProposal * pbudgetProposal = ( * it2 ) . first ;
printf ( " -> Budget Name : %s \n " , pbudgetProposal - > strProposalName . c_str ( ) ) ;
printf ( " ------- nBlockStart : %d \n " , pbudgetProposal - > nBlockStart ) ;
printf ( " ------- nBlockEnd : %d \n " , pbudgetProposal - > nBlockEnd ) ;
printf ( " ------- nBlockStart2 : %d \n " , nBlockStart ) ;
printf ( " ------- nBlockEnd2 : %d \n " , nBlockEnd ) ;
printf ( " ------- 1 : %d \n " , pbudgetProposal - > fValid & & pbudgetProposal - > nBlockStart < = nBlockStart ) ;
printf ( " ------- 2 : %d \n " , pbudgetProposal - > nBlockEnd > = nBlockEnd ) ;
printf ( " ------- 3 : %d \n " , pbudgetProposal - > GetYesCount ( ) - pbudgetProposal - > GetNoCount ( ) > mnodeman . CountEnabled ( MIN_BUDGET_PEER_PROTO_VERSION ) / 10 ) ;
printf ( " ------- 4 : %d \n " , pbudgetProposal - > IsEstablished ( ) ) ;
//prop start/end should be inside this period
if ( pbudgetProposal - > fValid & & pbudgetProposal - > nBlockStart < = nBlockStart & &
pbudgetProposal - > nBlockEnd > = nBlockEnd & &
pbudgetProposal - > GetYesCount ( ) - pbudgetProposal - > GetNoCount ( ) > mnodeman . CountEnabled ( MIN_BUDGET_PEER_PROTO_VERSION ) / 10 & &
pbudgetProposal - > IsEstablished ( ) )
{
printf ( " ------- In range \n " ) ;
if ( pbudgetProposal - > GetAmount ( ) + nBudgetAllocated < = nTotalBudget ) {
pbudgetProposal - > SetAllotted ( pbudgetProposal - > GetAmount ( ) ) ;
nBudgetAllocated + = pbudgetProposal - > GetAmount ( ) ;
vBudgetProposalsRet . push_back ( pbudgetProposal ) ;
printf ( " ------- YES \n " ) ;
} else {
pbudgetProposal - > SetAllotted ( 0 ) ;
}
}
+ + it2 ;
}
return vBudgetProposalsRet ;
}
struct sortFinalizedBudgetsByVotes {
bool operator ( ) ( const std : : pair < CFinalizedBudget * , int > & left , const std : : pair < CFinalizedBudget * , int > & right ) {
return left . second > right . second ;
}
} ;
void CBudgetManager : : NewBlock ( )
{
TRY_LOCK ( cs , fBudgetNewBlock ) ;
if ( ! fBudgetNewBlock ) return ;
if ( ! pCurrentBlockIndex ) return ;
// todo - 12.1 - add govobj sync
if ( masternodeSync . RequestedMasternodeAssets < = MASTERNODE_SYNC_BUDGET ) return ;
//this function should be called 1/6 blocks, allowing up to 100 votes per day on all proposals
if ( pCurrentBlockIndex - > nHeight % 6 ! = 0 ) return ;
// incremental sync with our peers
if ( masternodeSync . IsSynced ( ) ) {
LogPrintf ( " CBudgetManager::NewBlock - incremental sync started \n " ) ;
if ( pCurrentBlockIndex - > nHeight % 600 = = rand ( ) % 600 ) {
ClearSeen ( ) ;
ResetSync ( ) ;
}
LOCK ( cs_vNodes ) ;
BOOST_FOREACH ( CNode * pnode , vNodes )
if ( pnode - > nVersion > = MIN_BUDGET_PEER_PROTO_VERSION )
Sync ( pnode , uint256 ( ) , true ) ;
MarkSynced ( ) ;
}
CheckAndRemove ( ) ;
//remove invalid votes once in a while (we have to check the signatures and validity of every vote, somewhat CPU intensive)
std : : map < uint256 , int64_t > : : iterator it = askedForSourceProposalOrBudget . begin ( ) ;
while ( it ! = askedForSourceProposalOrBudget . end ( ) ) {
if ( ( * it ) . second > GetTime ( ) - ( 60 * 60 * 24 ) ) {
+ + it ;
} else {
askedForSourceProposalOrBudget . erase ( it + + ) ;
}
}
std : : map < uint256 , CBudgetProposal > : : iterator it2 = mapProposals . begin ( ) ;
while ( it2 ! = mapProposals . end ( ) ) {
( * it2 ) . second . CleanAndRemove ( false ) ;
+ + it2 ;
}
std : : vector < CBudgetProposalBroadcast > : : iterator it4 = vecImmatureBudgetProposals . begin ( ) ;
while ( it4 ! = vecImmatureBudgetProposals . end ( ) )
{
std : : string strError = " " ;
int nConf = 0 ;
if ( ! IsBudgetCollateralValid ( ( * it4 ) . nFeeTXHash , ( * it4 ) . GetHash ( ) , strError , ( * it4 ) . nTime , nConf ) ) {
+ + it4 ;
continue ;
}
if ( ! ( * it4 ) . IsValid ( pCurrentBlockIndex , strError ) ) {
LogPrintf ( " mprop (immature) - invalid budget proposal - %s \n " , strError ) ;
it4 = vecImmatureBudgetProposals . erase ( it4 ) ;
continue ;
}
CBudgetProposal budgetProposal ( ( * it4 ) ) ;
if ( AddProposal ( budgetProposal ) ) { ( * it4 ) . Relay ( ) ; }
LogPrintf ( " mprop (immature) - new budget - %s \n " , ( * it4 ) . GetHash ( ) . ToString ( ) ) ;
it4 = vecImmatureBudgetProposals . erase ( it4 ) ;
}
}
void CBudgetManager : : ProcessMessage ( CNode * pfrom , std : : string & strCommand , CDataStream & vRecv )
{
// lite mode is not supported
if ( fLiteMode ) return ;
if ( ! masternodeSync . IsBlockchainSynced ( ) ) return ;
LOCK ( cs_budget ) ;
2016-04-09 22:31:01 +02:00
// todo - 12.1 - change to MNGOVERNANCEVOTESYNC
2016-04-09 21:57:53 +02:00
if ( strCommand = = NetMsgType : : MNBUDGETVOTESYNC ) { //Masternode vote sync
uint256 nProp ;
vRecv > > nProp ;
if ( Params ( ) . NetworkIDString ( ) = = CBaseChainParams : : MAIN ) {
if ( nProp = = uint256 ( ) ) {
if ( pfrom - > HasFulfilledRequest ( NetMsgType : : MNBUDGETVOTESYNC ) ) {
LogPrintf ( " mnvs - peer already asked me for the list \n " ) ;
Misbehaving ( pfrom - > GetId ( ) , 20 ) ;
return ;
}
pfrom - > FulfilledRequest ( NetMsgType : : MNBUDGETVOTESYNC ) ;
}
}
Sync ( pfrom , nProp ) ;
LogPrintf ( " mnvs - Sent Masternode votes to %s \n " , pfrom - > addr . ToString ( ) ) ;
}
2016-04-09 22:31:01 +02:00
// todo - 12.1 - change to MNGOVERNANCEPROPOSAL
2016-04-09 21:57:53 +02:00
if ( strCommand = = NetMsgType : : MNBUDGETPROPOSAL ) { //Masternode Proposal
CBudgetProposalBroadcast budgetProposalBroadcast ;
vRecv > > budgetProposalBroadcast ;
if ( mapSeenMasternodeBudgetProposals . count ( budgetProposalBroadcast . GetHash ( ) ) ) {
masternodeSync . AddedBudgetItem ( budgetProposalBroadcast . GetHash ( ) ) ;
return ;
}
std : : string strError = " " ;
int nConf = 0 ;
if ( ! IsBudgetCollateralValid ( budgetProposalBroadcast . nFeeTXHash , budgetProposalBroadcast . GetHash ( ) , strError , budgetProposalBroadcast . nTime , nConf ) ) {
LogPrintf ( " Proposal FeeTX is not valid - %s - %s \n " , budgetProposalBroadcast . nFeeTXHash . ToString ( ) , strError ) ;
if ( nConf > = 1 ) vecImmatureBudgetProposals . push_back ( budgetProposalBroadcast ) ;
return ;
}
mapSeenMasternodeBudgetProposals . insert ( make_pair ( budgetProposalBroadcast . GetHash ( ) , budgetProposalBroadcast ) ) ;
if ( ! budgetProposalBroadcast . IsValid ( pCurrentBlockIndex , strError ) ) {
LogPrintf ( " mprop - invalid budget proposal - %s \n " , strError ) ;
return ;
}
CBudgetProposal budgetProposal ( budgetProposalBroadcast ) ;
if ( AddProposal ( budgetProposal ) ) { budgetProposalBroadcast . Relay ( ) ; }
masternodeSync . AddedBudgetItem ( budgetProposalBroadcast . GetHash ( ) ) ;
LogPrintf ( " mprop - new budget - %s \n " , budgetProposalBroadcast . GetHash ( ) . ToString ( ) ) ;
//We might have active votes for this proposal that are valid now
CheckOrphanVotes ( ) ;
}
2016-04-09 22:31:01 +02:00
// todo - 12.1 - change to MNGOVERNANCEVOTE
2016-04-09 21:57:53 +02:00
if ( strCommand = = NetMsgType : : MNBUDGETVOTE ) { //Masternode Vote
CBudgetVote vote ;
vRecv > > vote ;
vote . fValid = true ;
if ( mapSeenMasternodeBudgetVotes . count ( vote . GetHash ( ) ) ) {
masternodeSync . AddedBudgetItem ( vote . GetHash ( ) ) ;
return ;
}
CMasternode * pmn = mnodeman . Find ( vote . vin ) ;
if ( pmn = = NULL ) {
LogPrint ( " mnbudget " , " mvote - unknown masternode - vin: %s \n " , vote . vin . ToString ( ) ) ;
mnodeman . AskForMN ( pfrom , vote . vin ) ;
return ;
}
mapSeenMasternodeBudgetVotes . insert ( make_pair ( vote . GetHash ( ) , vote ) ) ;
if ( ! vote . IsValid ( true ) ) {
LogPrintf ( " mvote - signature invalid \n " ) ;
if ( masternodeSync . IsSynced ( ) ) Misbehaving ( pfrom - > GetId ( ) , 20 ) ;
// it could just be a non-synced masternode
mnodeman . AskForMN ( pfrom , vote . vin ) ;
return ;
}
std : : string strError = " " ;
if ( UpdateProposal ( vote , pfrom , strError ) ) {
vote . Relay ( ) ;
masternodeSync . AddedBudgetItem ( vote . GetHash ( ) ) ;
}
LogPrintf ( " mvote - new budget vote - %s \n " , vote . GetHash ( ) . ToString ( ) ) ;
}
if ( strCommand = = NetMsgType : : MNBUDGETFINAL ) { //Finalized Budget Suggestion
CFinalizedBudgetBroadcast finalizedBudgetBroadcast ;
vRecv > > finalizedBudgetBroadcast ;
if ( mapSeenFinalizedBudgets . count ( finalizedBudgetBroadcast . GetHash ( ) ) ) {
masternodeSync . AddedBudgetItem ( finalizedBudgetBroadcast . GetHash ( ) ) ;
return ;
}
std : : string strError = " " ;
int nConf = 0 ;
if ( ! IsBudgetCollateralValid ( finalizedBudgetBroadcast . nFeeTXHash , finalizedBudgetBroadcast . GetHash ( ) , strError , finalizedBudgetBroadcast . nTime , nConf ) ) {
LogPrintf ( " Finalized Budget FeeTX is not valid - %s - %s \n " , finalizedBudgetBroadcast . nFeeTXHash . ToString ( ) , strError ) ;
if ( nConf > = 1 ) vecImmatureFinalizedBudgets . push_back ( finalizedBudgetBroadcast ) ;
return ;
}
mapSeenFinalizedBudgets . insert ( make_pair ( finalizedBudgetBroadcast . GetHash ( ) , finalizedBudgetBroadcast ) ) ;
if ( ! finalizedBudgetBroadcast . IsValid ( pCurrentBlockIndex , strError ) ) {
LogPrintf ( " fbs - invalid finalized budget - %s \n " , strError ) ;
return ;
}
LogPrintf ( " fbs - new finalized budget - %s \n " , finalizedBudgetBroadcast . GetHash ( ) . ToString ( ) ) ;
CFinalizedBudget finalizedBudget ( finalizedBudgetBroadcast ) ;
if ( AddFinalizedBudget ( finalizedBudget ) ) { finalizedBudgetBroadcast . Relay ( ) ; }
masternodeSync . AddedBudgetItem ( finalizedBudgetBroadcast . GetHash ( ) ) ;
//we might have active votes for this budget that are now valid
CheckOrphanVotes ( ) ;
}
}
//todo - 12.1 - terrible name - maybe DoesObjectExist?
bool CBudgetManager : : PropExists ( uint256 nHash )
{
if ( mapProposals . count ( nHash ) ) return true ;
return false ;
}
//mark that a full sync is needed
void CBudgetManager : : ResetSync ( )
{
LOCK ( cs ) ;
std : : map < uint256 , CBudgetProposalBroadcast > : : iterator it1 = mapSeenMasternodeBudgetProposals . begin ( ) ;
while ( it1 ! = mapSeenMasternodeBudgetProposals . end ( ) ) {
CBudgetProposal * pbudgetProposal = FindProposal ( ( * it1 ) . first ) ;
if ( pbudgetProposal & & pbudgetProposal - > fValid ) {
//mark votes
std : : map < uint256 , CBudgetVote > : : iterator it2 = pbudgetProposal - > mapVotes . begin ( ) ;
while ( it2 ! = pbudgetProposal - > mapVotes . end ( ) ) {
( * it2 ) . second . fSynced = false ;
+ + it2 ;
}
}
+ + it1 ;
}
}
void CBudgetManager : : MarkSynced ( )
{
LOCK ( cs ) ;
/*
Mark that we ' ve sent all valid items
*/
std : : map < uint256 , CBudgetProposalBroadcast > : : iterator it1 = mapSeenMasternodeBudgetProposals . begin ( ) ;
while ( it1 ! = mapSeenMasternodeBudgetProposals . end ( ) ) {
CBudgetProposal * pbudgetProposal = FindProposal ( ( * it1 ) . first ) ;
if ( pbudgetProposal & & pbudgetProposal - > fValid ) {
//mark votes
std : : map < uint256 , CBudgetVote > : : iterator it2 = pbudgetProposal - > mapVotes . begin ( ) ;
while ( it2 ! = pbudgetProposal - > mapVotes . end ( ) ) {
if ( ( * it2 ) . second . fValid )
( * it2 ) . second . fSynced = true ;
+ + it2 ;
}
}
+ + it1 ;
}
}
void CBudgetManager : : Sync ( CNode * pfrom , uint256 nProp , bool fPartial )
{
LOCK ( cs ) ;
/*
Sync with a client on the network
- -
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 .
*/
int nInvCount = 0 ;
// todo - why does this code not always sync properly?
// the next place this data arrives at is main.cpp:4024 and main.cpp:4030
std : : map < uint256 , CBudgetProposalBroadcast > : : iterator it1 = mapSeenMasternodeBudgetProposals . begin ( ) ;
while ( it1 ! = mapSeenMasternodeBudgetProposals . end ( ) ) {
CBudgetProposal * pbudgetProposal = FindProposal ( ( * it1 ) . first ) ;
if ( pbudgetProposal & & pbudgetProposal - > fValid & & ( nProp = = uint256 ( ) | | ( * it1 ) . first = = nProp ) ) {
// Push the inventory budget proposal message over to the other client
pfrom - > PushInventory ( CInv ( MSG_BUDGET_PROPOSAL , ( * it1 ) . second . GetHash ( ) ) ) ;
nInvCount + + ;
//send votes, at the same time. We should collect votes and store them if we don't have the proposal yet on the other side
std : : map < uint256 , CBudgetVote > : : iterator it2 = pbudgetProposal - > mapVotes . begin ( ) ;
while ( it2 ! = pbudgetProposal - > mapVotes . end ( ) ) {
if ( ( * it2 ) . second . fValid ) {
if ( ( fPartial & & ! ( * it2 ) . second . fSynced ) | | ! fPartial ) {
pfrom - > PushInventory ( CInv ( MSG_BUDGET_VOTE , ( * it2 ) . second . GetHash ( ) ) ) ;
nInvCount + + ;
}
}
+ + it2 ;
}
}
+ + it1 ;
}
pfrom - > PushMessage ( NetMsgType : : SYNCSTATUSCOUNT , MASTERNODE_SYNC_BUDGET_PROP , nInvCount ) ;
LogPrintf ( " CBudgetManager::Sync - sent %d items \n " , nInvCount ) ;
}
bool CBudgetManager : : UpdateProposal ( CBudgetVote & vote , CNode * pfrom , std : : string & strError )
{
LOCK ( cs ) ;
if ( ! mapProposals . count ( vote . nProposalHash ) ) {
if ( pfrom ) {
// only ask for missing items after our syncing process is complete --
// otherwise we'll think a full sync succeeded when they return a result
if ( ! masternodeSync . IsSynced ( ) ) return false ;
LogPrintf ( " CBudgetManager::UpdateProposal - Unknown proposal %d, asking for source proposal \n " , vote . nProposalHash . ToString ( ) ) ;
mapOrphanMasternodeBudgetVotes [ vote . nProposalHash ] = vote ;
if ( ! askedForSourceProposalOrBudget . count ( vote . nProposalHash ) ) {
pfrom - > PushMessage ( NetMsgType : : MNBUDGETVOTESYNC , vote . nProposalHash ) ;
askedForSourceProposalOrBudget [ vote . nProposalHash ] = GetTime ( ) ;
}
}
strError = " Proposal not found! " ;
return false ;
}
return mapProposals [ vote . nProposalHash ] . AddOrUpdateVote ( vote , strError ) ;
}
CBudgetProposal : : CBudgetProposal ( )
{
strProposalName = " unknown " ;
nBlockStart = 0 ;
nBlockEnd = 0 ;
nAmount = 0 ;
nTime = 0 ;
fValid = true ;
}
CBudgetProposal : : CBudgetProposal ( const CBudgetProposal & other )
{
strProposalName = other . strProposalName ;
strURL = other . strURL ;
nBlockStart = other . nBlockStart ;
nBlockEnd = other . nBlockEnd ;
address = other . address ;
nAmount = other . nAmount ;
nTime = other . nTime ;
nFeeTXHash = other . nFeeTXHash ;
mapVotes = other . mapVotes ;
fValid = true ;
}
CBudgetProposal : : CBudgetProposal ( std : : string strProposalNameIn , std : : string strURLIn , int nPaymentCount , CScript addressIn , CAmount nAmountIn , int nBlockStartIn , uint256 nFeeTXHashIn )
{
strProposalName = strProposalNameIn ;
strURL = strURLIn ;
nBlockStart = nBlockStartIn ;
int nPaymentsStart = nBlockStart - nBlockStart % Params ( ) . GetConsensus ( ) . nBudgetPaymentsCycleBlocks ;
//calculate the end of the cycle for this vote, add half a cycle (vote will be deleted after that block)
nBlockEnd = nPaymentsStart + Params ( ) . GetConsensus ( ) . nBudgetPaymentsCycleBlocks * nPaymentCount ;
address = addressIn ;
nAmount = nAmountIn ;
nFeeTXHash = nFeeTXHashIn ;
}
bool CBudgetProposal : : IsValid ( const CBlockIndex * pindex , std : : string & strError , bool fCheckCollateral )
{
if ( GetNoCount ( ) - GetYesCount ( ) > mnodeman . CountEnabled ( MIN_BUDGET_PEER_PROTO_VERSION ) / 10 ) {
strError = " Active removal " ;
return false ;
}
if ( nBlockStart < 0 ) {
strError = " Invalid Proposal " ;
return false ;
}
if ( ! pindex ) {
strError = " Tip is NULL " ;
return true ;
}
if ( nBlockStart % Params ( ) . GetConsensus ( ) . nBudgetPaymentsCycleBlocks ! = 0 ) {
int nNext = pindex - > nHeight - pindex - > nHeight % Params ( ) . GetConsensus ( ) . nBudgetPaymentsCycleBlocks + Params ( ) . GetConsensus ( ) . nBudgetPaymentsCycleBlocks ;
strError = strprintf ( " Invalid block start - must be a budget cycle block. Next valid block: %d " , nNext ) ;
return false ;
}
if ( nBlockEnd % Params ( ) . GetConsensus ( ) . nBudgetPaymentsCycleBlocks ! = Params ( ) . GetConsensus ( ) . nBudgetPaymentsCycleBlocks / 2 ) {
strError = " Invalid block end " ;
return false ;
}
if ( nBlockEnd < nBlockStart ) {
strError = " Invalid block end - must be greater then block start. " ;
return false ;
}
if ( nAmount < 1 * COIN ) {
strError = " Invalid proposal amount " ;
return false ;
}
if ( strProposalName . size ( ) > 20 ) {
strError = " Invalid proposal name, limit of 20 characters. " ;
return false ;
}
if ( strProposalName ! = SanitizeString ( strProposalName ) ) {
strError = " Invalid proposal name, unsafe characters found. " ;
return false ;
}
if ( strURL . size ( ) > 64 ) {
strError = " Invalid proposal url, limit of 64 characters. " ;
return false ;
}
if ( strURL ! = SanitizeString ( strURL ) ) {
strError = " Invalid proposal url, unsafe characters found. " ;
return false ;
}
if ( address = = CScript ( ) ) {
strError = " Invalid proposal Payment Address " ;
return false ;
}
if ( fCheckCollateral ) {
int nConf = 0 ;
if ( ! IsBudgetCollateralValid ( nFeeTXHash , GetHash ( ) , strError , nTime , nConf ) ) {
return false ;
}
}
/*
TODO : There might be an issue with multisig in the coinbase on mainnet , we will add support for it in a future release .
*/
if ( address . IsPayToScriptHash ( ) ) {
strError = " Multisig is not currently supported. " ;
return false ;
}
// -- If GetAbsoluteYesCount is more than -10% of the network, flag as invalid
if ( GetAbsoluteYesCount ( ) < - ( mnodeman . CountEnabled ( MIN_BUDGET_PEER_PROTO_VERSION ) / 10 ) ) {
strError = " Voted Down " ;
return false ;
}
//can only pay out 10% of the possible coins (min value of coins)
if ( nAmount > budget . GetTotalBudget ( nBlockStart ) ) {
strError = " Payment more than max " ;
return false ;
}
if ( GetBlockEnd ( ) + Params ( ) . GetConsensus ( ) . nBudgetPaymentsWindowBlocks < pindex - > nHeight ) return false ;
return true ;
}
bool CBudgetProposal : : IsEstablished ( ) {
//Proposals must be established to make it into a budget
return ( nTime < GetTime ( ) - Params ( ) . GetConsensus ( ) . nBudgetProposalEstablishingTime ) ;
}
bool CBudgetProposal : : AddOrUpdateVote ( CBudgetVote & vote , std : : string & strError )
{
LOCK ( cs ) ;
uint256 hash = vote . vin . prevout . GetHash ( ) ;
if ( mapVotes . count ( hash ) ) {
if ( mapVotes [ hash ] . nTime > vote . nTime ) {
strError = strprintf ( " new vote older than existing vote - %s " , vote . GetHash ( ) . ToString ( ) ) ;
LogPrint ( " mnbudget " , " CBudgetProposal::AddOrUpdateVote - %s \n " , strError ) ;
return false ;
}
if ( vote . nTime - mapVotes [ hash ] . nTime < BUDGET_VOTE_UPDATE_MIN ) {
strError = strprintf ( " time between votes is too soon - %s - %lli " , vote . GetHash ( ) . ToString ( ) , vote . nTime - mapVotes [ hash ] . nTime ) ;
LogPrint ( " mnbudget " , " CBudgetProposal::AddOrUpdateVote - %s \n " , strError ) ;
return false ;
}
}
mapVotes [ hash ] = vote ;
return true ;
}
// If masternode voted for a proposal, but is now invalid -- remove the vote
void CBudgetProposal : : CleanAndRemove ( bool fSignatureCheck )
{
std : : map < uint256 , CBudgetVote > : : iterator it = mapVotes . begin ( ) ;
while ( it ! = mapVotes . end ( ) ) {
( * it ) . second . fValid = ( * it ) . second . IsValid ( fSignatureCheck ) ;
+ + it ;
}
}
double CBudgetProposal : : GetRatio ( )
{
int yeas = 0 ;
int nays = 0 ;
std : : map < uint256 , CBudgetVote > : : iterator it = mapVotes . begin ( ) ;
while ( it ! = mapVotes . end ( ) ) {
if ( ( * it ) . second . nVote = = VOTE_YES ) yeas + + ;
if ( ( * it ) . second . nVote = = VOTE_NO ) nays + + ;
+ + it ;
}
if ( yeas + nays = = 0 ) return 0.0f ;
return ( ( double ) ( yeas ) / ( double ) ( yeas + nays ) ) ;
}
int CBudgetProposal : : GetAbsoluteYesCount ( )
{
return GetYesCount ( ) - GetNoCount ( ) ;
}
int CBudgetProposal : : GetYesCount ( )
{
int ret = 0 ;
std : : map < uint256 , CBudgetVote > : : iterator it = mapVotes . begin ( ) ;
while ( it ! = mapVotes . end ( ) ) {
if ( ( * it ) . second . nVote = = VOTE_YES & & ( * it ) . second . fValid ) ret + + ;
+ + it ;
}
return ret ;
}
int CBudgetProposal : : GetNoCount ( )
{
int ret = 0 ;
std : : map < uint256 , CBudgetVote > : : iterator it = mapVotes . begin ( ) ;
while ( it ! = mapVotes . end ( ) ) {
if ( ( * it ) . second . nVote = = VOTE_NO & & ( * it ) . second . fValid ) ret + + ;
+ + it ;
}
return ret ;
}
int CBudgetProposal : : GetAbstainCount ( )
{
int ret = 0 ;
std : : map < uint256 , CBudgetVote > : : iterator it = mapVotes . begin ( ) ;
while ( it ! = mapVotes . end ( ) ) {
if ( ( * it ) . second . nVote = = VOTE_ABSTAIN & & ( * it ) . second . fValid ) ret + + ;
+ + it ;
}
return ret ;
}
int CBudgetProposal : : GetBlockStartCycle ( )
{
//end block is half way through the next cycle (so the proposal will be removed much after the payment is sent)
return nBlockStart - nBlockStart % Params ( ) . GetConsensus ( ) . nBudgetPaymentsCycleBlocks ;
}
int CBudgetProposal : : GetBlockCurrentCycle ( const CBlockIndex * pindex )
{
if ( ! pindex ) return - 1 ;
if ( pindex - > nHeight > = GetBlockEndCycle ( ) ) return - 1 ;
return pindex - > nHeight - pindex - > nHeight % Params ( ) . GetConsensus ( ) . nBudgetPaymentsCycleBlocks ;
}
int CBudgetProposal : : GetBlockEndCycle ( )
{
//end block is half way through the next cycle (so the proposal will be removed much after the payment is sent)
return nBlockEnd - Params ( ) . GetConsensus ( ) . nBudgetPaymentsCycleBlocks / 2 ;
}
int CBudgetProposal : : GetTotalPaymentCount ( )
{
return ( GetBlockEndCycle ( ) - GetBlockStartCycle ( ) ) / Params ( ) . GetConsensus ( ) . nBudgetPaymentsCycleBlocks ;
}
int CBudgetProposal : : GetRemainingPaymentCount ( int nBlockHeight )
{
int nPayments = 0 ;
// printf("-> Budget Name : %s\n", strProposalName.c_str());
// printf("------- nBlockStart : %d\n", nBlockStart);
// printf("------- nBlockEnd : %d\n", nBlockEnd);
while ( nBlockHeight + Params ( ) . GetConsensus ( ) . nBudgetPaymentsCycleBlocks < GetBlockEndCycle ( ) )
{
// printf("------- P : %d %d - %d < %d - %d\n", nBlockHeight, nPayments, nBlockHeight + Params().GetConsensus().nBudgetPaymentsCycleBlocks, nBlockEnd, nBlockHeight + Params().GetConsensus().nBudgetPaymentsCycleBlocks < nBlockEnd);
nBlockHeight + = Params ( ) . GetConsensus ( ) . nBudgetPaymentsCycleBlocks ;
nPayments + + ;
}
return nPayments ;
}
void CBudgetProposalBroadcast : : Relay ( )
{
CInv inv ( MSG_BUDGET_PROPOSAL , GetHash ( ) ) ;
RelayInv ( inv , MIN_BUDGET_PEER_PROTO_VERSION ) ;
}
CBudgetVote : : CBudgetVote ( )
{
vin = CTxIn ( ) ;
nProposalHash = uint256 ( ) ;
nVote = VOTE_ABSTAIN ;
nTime = 0 ;
fValid = true ;
fSynced = false ;
}
CBudgetVote : : CBudgetVote ( CTxIn vinIn , uint256 nProposalHashIn , int nVoteIn )
{
vin = vinIn ;
nProposalHash = nProposalHashIn ;
nVote = nVoteIn ;
nTime = GetAdjustedTime ( ) ;
fValid = true ;
fSynced = false ;
}
void CBudgetVote : : Relay ( )
{
CInv inv ( MSG_BUDGET_VOTE , GetHash ( ) ) ;
RelayInv ( inv , MIN_BUDGET_PEER_PROTO_VERSION ) ;
}
bool CBudgetVote : : Sign ( CKey & keyMasternode , CPubKey & pubKeyMasternode )
{
// Choose coins to use
CPubKey pubKeyCollateralAddress ;
CKey keyCollateralAddress ;
std : : string errorMessage ;
std : : string strMessage = vin . prevout . ToStringShort ( ) + nProposalHash . ToString ( ) + boost : : lexical_cast < std : : string > ( nVote ) + boost : : lexical_cast < std : : string > ( nTime ) ;
if ( ! darkSendSigner . SignMessage ( strMessage , errorMessage , vchSig , keyMasternode ) ) {
LogPrintf ( " CBudgetVote::Sign - Error upon calling SignMessage " ) ;
return false ;
}
if ( ! darkSendSigner . VerifyMessage ( pubKeyMasternode , vchSig , strMessage , errorMessage ) ) {
LogPrintf ( " CBudgetVote::Sign - Error upon calling VerifyMessage " ) ;
return false ;
}
return true ;
}
bool CBudgetVote : : IsValid ( bool fSignatureCheck )
{
if ( nTime > GetTime ( ) + ( 60 * 60 ) ) {
LogPrint ( " mnbudget " , " CBudgetVote::IsValid() - vote is too far ahead of current time - %s - nTime %lli - Max Time %lli \n " , GetHash ( ) . ToString ( ) , nTime , GetTime ( ) + ( 60 * 60 ) ) ;
return false ;
}
CMasternode * pmn = mnodeman . Find ( vin ) ;
if ( pmn = = NULL )
{
LogPrint ( " mnbudget " , " CBudgetVote::IsValid() - Unknown Masternode - %s \n " , vin . ToString ( ) ) ;
return false ;
}
if ( ! fSignatureCheck ) return true ;
std : : string errorMessage ;
std : : string strMessage = vin . prevout . ToStringShort ( ) + nProposalHash . ToString ( ) + boost : : lexical_cast < std : : string > ( nVote ) + boost : : lexical_cast < std : : string > ( nTime ) ;
if ( ! darkSendSigner . VerifyMessage ( pmn - > pubkey2 , vchSig , strMessage , errorMessage ) ) {
LogPrintf ( " CBudgetVote::IsValid() - Verify message failed - Error: %s \n " , errorMessage ) ;
return false ;
}
return true ;
}
CFinalizedBudget : : CFinalizedBudget ( )
{
strBudgetName = " " ;
nBlockStart = 0 ;
vecBudgetPayments . clear ( ) ;
mapVotes . clear ( ) ;
nFeeTXHash = uint256 ( ) ;
nTime = 0 ;
fValid = true ;
fAutoChecked = false ;
}
CFinalizedBudget : : CFinalizedBudget ( const CFinalizedBudget & other )
{
strBudgetName = other . strBudgetName ;
nBlockStart = other . nBlockStart ;
vecBudgetPayments = other . vecBudgetPayments ;
mapVotes = other . mapVotes ;
nFeeTXHash = other . nFeeTXHash ;
nTime = other . nTime ;
fValid = true ;
fAutoChecked = false ;
}
bool CFinalizedBudget : : AddOrUpdateVote ( CFinalizedBudgetVote & vote , std : : string & strError )
{
LOCK ( cs ) ;
uint256 hash = vote . vin . prevout . GetHash ( ) ;
if ( mapVotes . count ( hash ) ) {
if ( mapVotes [ hash ] . nTime > vote . nTime ) {
strError = strprintf ( " new vote older than existing vote - %s " , vote . GetHash ( ) . ToString ( ) ) ;
LogPrint ( " mnbudget " , " CFinalizedBudget::AddOrUpdateVote - %s \n " , strError ) ;
return false ;
}
if ( vote . nTime - mapVotes [ hash ] . nTime < BUDGET_VOTE_UPDATE_MIN ) {
strError = strprintf ( " time between votes is too soon - %s - %lli " , vote . GetHash ( ) . ToString ( ) , vote . nTime - mapVotes [ hash ] . nTime ) ;
LogPrint ( " mnbudget " , " CFinalizedBudget::AddOrUpdateVote - %s \n " , strError ) ;
return false ;
}
}
mapVotes [ hash ] = vote ;
return true ;
}
//evaluate if we should vote for this. Masternode only
void CFinalizedBudget : : AutoCheck ( )
{
LOCK ( cs ) ;
CBlockIndex * pindexPrev = chainActive . Tip ( ) ;
if ( ! pindexPrev ) return ;
LogPrintf ( " CFinalizedBudget::AutoCheck - %lli - %d \n " , pindexPrev - > nHeight , fAutoChecked ) ;
if ( ! fMasterNode | | fAutoChecked ) return ;
//do this 1 in 4 blocks -- spread out the voting activity on mainnet
// -- this function is only called every sixth block, so this is really 1 in 24 blocks
if ( Params ( ) . NetworkIDString ( ) = = CBaseChainParams : : MAIN & & rand ( ) % 4 ! = 0 ) {
LogPrintf ( " CFinalizedBudget::AutoCheck - waiting \n " ) ;
return ;
}
fAutoChecked = true ; //we only need to check this once
if ( strBudgetMode = = " auto " ) //only vote for exact matches
{
std : : vector < CBudgetProposal * > vBudgetProposals = budget . GetBudget ( ) ;
for ( unsigned int i = 0 ; i < vecBudgetPayments . size ( ) ; i + + ) {
LogPrintf ( " CFinalizedBudget::AutoCheck - nProp %d %s \n " , i , vecBudgetPayments [ i ] . nProposalHash . ToString ( ) ) ;
LogPrintf ( " CFinalizedBudget::AutoCheck - Payee %d %s \n " , i , ScriptToAsmStr ( vecBudgetPayments [ i ] . payee ) ) ;
LogPrintf ( " CFinalizedBudget::AutoCheck - nAmount %d %lli \n " , i , vecBudgetPayments [ i ] . nAmount ) ;
}
for ( unsigned int i = 0 ; i < vBudgetProposals . size ( ) ; i + + ) {
LogPrintf ( " CFinalizedBudget::AutoCheck - nProp %d %s \n " , i , vBudgetProposals [ i ] - > GetHash ( ) . ToString ( ) ) ;
LogPrintf ( " CFinalizedBudget::AutoCheck - Payee %d %s \n " , i , ScriptToAsmStr ( vBudgetProposals [ i ] - > GetPayee ( ) ) ) ;
LogPrintf ( " CFinalizedBudget::AutoCheck - nAmount %d %lli \n " , i , vBudgetProposals [ i ] - > GetAmount ( ) ) ;
}
if ( vBudgetProposals . size ( ) = = 0 ) {
LogPrintf ( " CFinalizedBudget::AutoCheck - Can't get Budget, aborting \n " ) ;
return ;
}
if ( vBudgetProposals . size ( ) ! = vecBudgetPayments . size ( ) ) {
LogPrintf ( " CFinalizedBudget::AutoCheck - Budget length doesn't match \n " ) ;
return ;
}
for ( unsigned int i = 0 ; i < vecBudgetPayments . size ( ) ; i + + ) {
if ( i > vBudgetProposals . size ( ) - 1 ) {
LogPrintf ( " CFinalizedBudget::AutoCheck - Vector size mismatch, aborting \n " ) ;
return ;
}
if ( vecBudgetPayments [ i ] . nProposalHash ! = vBudgetProposals [ i ] - > GetHash ( ) ) {
LogPrintf ( " CFinalizedBudget::AutoCheck - item #%d doesn't match %s %s \n " , i , vecBudgetPayments [ i ] . nProposalHash . ToString ( ) , vBudgetProposals [ i ] - > GetHash ( ) . ToString ( ) ) ;
return ;
}
// if(vecBudgetPayments[i].payee != vBudgetProposals[i]->GetPayee()){ -- triggered with false positive
if ( vecBudgetPayments [ i ] . payee ! = vBudgetProposals [ i ] - > GetPayee ( ) ) {
LogPrintf ( " CFinalizedBudget::AutoCheck - item #%d payee doesn't match %s %s \n " , i , ScriptToAsmStr ( vecBudgetPayments [ i ] . payee ) , ScriptToAsmStr ( vBudgetProposals [ i ] - > GetPayee ( ) ) ) ;
return ;
}
if ( vecBudgetPayments [ i ] . nAmount ! = vBudgetProposals [ i ] - > GetAmount ( ) ) {
LogPrintf ( " CFinalizedBudget::AutoCheck - item #%d payee doesn't match %lli %lli \n " , i , vecBudgetPayments [ i ] . nAmount , vBudgetProposals [ i ] - > GetAmount ( ) ) ;
return ;
}
}
LogPrintf ( " CFinalizedBudget::AutoCheck - Finalized Budget Matches! Submitting Vote. \n " ) ;
SubmitVote ( ) ;
}
}
// If masternode voted for a proposal, but is now invalid -- remove the vote
void CFinalizedBudget : : CleanAndRemove ( bool fSignatureCheck )
{
std : : map < uint256 , CFinalizedBudgetVote > : : iterator it = mapVotes . begin ( ) ;
while ( it ! = mapVotes . end ( ) ) {
( * it ) . second . fValid = ( * it ) . second . IsValid ( fSignatureCheck ) ;
+ + it ;
}
}
CAmount CFinalizedBudget : : GetTotalPayout ( )
{
CAmount ret = 0 ;
for ( unsigned int i = 0 ; i < vecBudgetPayments . size ( ) ; i + + ) {
ret + = vecBudgetPayments [ i ] . nAmount ;
}
return ret ;
}
std : : string CFinalizedBudget : : GetProposals ( )
{
LOCK ( cs ) ;
std : : string ret = " " ;
BOOST_FOREACH ( CTxBudgetPayment & budgetPayment , vecBudgetPayments ) {
CBudgetProposal * pbudgetProposal = budget . FindProposal ( budgetPayment . nProposalHash ) ;
std : : string token = budgetPayment . nProposalHash . ToString ( ) ;
if ( pbudgetProposal ) token = pbudgetProposal - > GetName ( ) ;
if ( ret = = " " ) { ret = token ; }
else { ret + = " , " + token ; }
}
return ret ;
}
std : : string CFinalizedBudget : : GetStatus ( )
{
std : : string retBadHashes = " " ;
std : : string retBadPayeeOrAmount = " " ;
for ( int nBlockHeight = GetBlockStart ( ) ; nBlockHeight < = GetBlockEnd ( ) ; nBlockHeight + + )
{
CTxBudgetPayment budgetPayment ;
if ( ! GetBudgetPaymentByBlock ( nBlockHeight , budgetPayment ) ) {
LogPrintf ( " CFinalizedBudget::GetStatus - Couldn't find budget payment for block %lld \n " , nBlockHeight ) ;
continue ;
}
CBudgetProposal * pbudgetProposal = budget . FindProposal ( budgetPayment . nProposalHash ) ;
if ( ! pbudgetProposal ) {
if ( retBadHashes = = " " ) {
retBadHashes = " Unknown proposal hash! Check this proposal before voting " + budgetPayment . nProposalHash . ToString ( ) ;
} else {
retBadHashes + = " , " + budgetPayment . nProposalHash . ToString ( ) ;
}
} else {
if ( pbudgetProposal - > GetPayee ( ) ! = budgetPayment . payee | | pbudgetProposal - > GetAmount ( ) ! = budgetPayment . nAmount )
{
if ( retBadPayeeOrAmount = = " " ) {
retBadPayeeOrAmount = " Budget payee/nAmount doesn't match our proposal! " + budgetPayment . nProposalHash . ToString ( ) ;
} else {
retBadPayeeOrAmount + = " , " + budgetPayment . nProposalHash . ToString ( ) ;
}
}
}
}
if ( retBadHashes = = " " & & retBadPayeeOrAmount = = " " ) return " OK " ;
return retBadHashes + retBadPayeeOrAmount ;
}
bool CFinalizedBudget : : IsValid ( const CBlockIndex * pindex , std : : string & strError , bool fCheckCollateral )
{
//must be the correct block for payment to happen (once a month)
if ( nBlockStart % Params ( ) . GetConsensus ( ) . nBudgetPaymentsCycleBlocks ! = 0 ) { strError = " Invalid BlockStart " ; return false ; }
if ( GetBlockEnd ( ) - nBlockStart > Params ( ) . GetConsensus ( ) . nBudgetPaymentsWindowBlocks ) { strError = " Invalid BlockEnd " ; return false ; }
if ( ( int ) vecBudgetPayments . size ( ) > Params ( ) . GetConsensus ( ) . nBudgetPaymentsWindowBlocks ) { strError = " Invalid budget payments count (too many) " ; return false ; }
if ( strBudgetName = = " " ) { strError = " Invalid Budget Name " ; return false ; }
if ( nBlockStart = = 0 ) { strError = " Invalid BlockStart == 0 " ; return false ; }
if ( nFeeTXHash = = uint256 ( ) ) { strError = " Invalid FeeTx == 0 " ; return false ; }
//can only pay out 10% of the possible coins (min value of coins)
if ( GetTotalPayout ( ) > budget . GetTotalBudget ( nBlockStart ) ) { strError = " Invalid Payout (more than max) " ; return false ; }
std : : string strError2 = " " ;
if ( fCheckCollateral ) {
int nConf = 0 ;
if ( ! IsBudgetCollateralValid ( nFeeTXHash , GetHash ( ) , strError2 , nTime , nConf ) ) {
strError = " Invalid Collateral : " + strError2 ;
return false ;
}
}
//TODO: if N cycles old, invalid, invalid
if ( ! pindex ) return true ;
if ( nBlockStart < pindex - > nHeight - Params ( ) . GetConsensus ( ) . nBudgetPaymentsWindowBlocks ) {
strError = " Older than current blockHeight " ;
return false ;
}
return true ;
}
void CFinalizedBudget : : SubmitVote ( )
{
CPubKey pubKeyMasternode ;
CKey keyMasternode ;
std : : string errorMessage ;
if ( ! darkSendSigner . SetKey ( strMasterNodePrivKey , errorMessage , keyMasternode , pubKeyMasternode ) ) {
LogPrintf ( " CFinalizedBudget::SubmitVote - Error upon calling SetKey \n " ) ;
return ;
}
CFinalizedBudgetVote vote ( activeMasternode . vin , GetHash ( ) ) ;
if ( ! vote . Sign ( keyMasternode , pubKeyMasternode ) ) {
LogPrintf ( " CFinalizedBudget::SubmitVote - Failure to sign. " ) ;
return ;
}
std : : string strError = " " ;
if ( budget . UpdateFinalizedBudget ( vote , NULL , strError ) ) {
LogPrintf ( " CFinalizedBudget::SubmitVote - new finalized budget vote - %s \n " , vote . GetHash ( ) . ToString ( ) ) ;
budget . mapSeenFinalizedBudgetVotes . insert ( make_pair ( vote . GetHash ( ) , vote ) ) ;
vote . Relay ( ) ;
} else {
LogPrintf ( " CFinalizedBudget::SubmitVote : Error submitting vote - %s \n " , strError ) ;
}
}
CFinalizedBudgetBroadcast : : CFinalizedBudgetBroadcast ( )
{
strBudgetName = " " ;
nBlockStart = 0 ;
vecBudgetPayments . clear ( ) ;
mapVotes . clear ( ) ;
vchSig . clear ( ) ;
nFeeTXHash = uint256 ( ) ;
}
CFinalizedBudgetBroadcast : : CFinalizedBudgetBroadcast ( const CFinalizedBudget & other )
{
strBudgetName = other . strBudgetName ;
nBlockStart = other . nBlockStart ;
BOOST_FOREACH ( CTxBudgetPayment out , other . vecBudgetPayments ) vecBudgetPayments . push_back ( out ) ;
mapVotes = other . mapVotes ;
nFeeTXHash = other . nFeeTXHash ;
}
CFinalizedBudgetBroadcast : : CFinalizedBudgetBroadcast ( std : : string strBudgetNameIn , int nBlockStartIn , std : : vector < CTxBudgetPayment > vecBudgetPaymentsIn , uint256 nFeeTXHashIn )
{
strBudgetName = strBudgetNameIn ;
nBlockStart = nBlockStartIn ;
BOOST_FOREACH ( CTxBudgetPayment out , vecBudgetPaymentsIn ) vecBudgetPayments . push_back ( out ) ;
mapVotes . clear ( ) ;
nFeeTXHash = nFeeTXHashIn ;
}
void CFinalizedBudgetBroadcast : : Relay ( )
{
CInv inv ( MSG_BUDGET_FINALIZED , GetHash ( ) ) ;
RelayInv ( inv , MIN_BUDGET_PEER_PROTO_VERSION ) ;
}
CFinalizedBudgetVote : : CFinalizedBudgetVote ( )
{
vin = CTxIn ( ) ;
nBudgetHash = uint256 ( ) ;
nTime = 0 ;
vchSig . clear ( ) ;
fValid = true ;
fSynced = false ;
}
CFinalizedBudgetVote : : CFinalizedBudgetVote ( CTxIn vinIn , uint256 nBudgetHashIn )
{
vin = vinIn ;
nBudgetHash = nBudgetHashIn ;
nTime = GetAdjustedTime ( ) ;
vchSig . clear ( ) ;
fValid = true ;
fSynced = false ;
}
void CFinalizedBudgetVote : : Relay ( )
{
CInv inv ( MSG_BUDGET_FINALIZED_VOTE , GetHash ( ) ) ;
RelayInv ( inv , MIN_BUDGET_PEER_PROTO_VERSION ) ;
}
bool CFinalizedBudgetVote : : Sign ( CKey & keyMasternode , CPubKey & pubKeyMasternode )
{
// Choose coins to use
CPubKey pubKeyCollateralAddress ;
CKey keyCollateralAddress ;
std : : string errorMessage ;
std : : string strMessage = vin . prevout . ToStringShort ( ) + nBudgetHash . ToString ( ) + boost : : lexical_cast < std : : string > ( nTime ) ;
if ( ! darkSendSigner . SignMessage ( strMessage , errorMessage , vchSig , keyMasternode ) ) {
LogPrintf ( " CFinalizedBudgetVote::Sign - Error upon calling SignMessage " ) ;
return false ;
}
if ( ! darkSendSigner . VerifyMessage ( pubKeyMasternode , vchSig , strMessage , errorMessage ) ) {
LogPrintf ( " CFinalizedBudgetVote::Sign - Error upon calling VerifyMessage " ) ;
return false ;
}
return true ;
}
bool CFinalizedBudgetVote : : IsValid ( bool fSignatureCheck )
{
if ( nTime > GetTime ( ) + ( 60 * 60 ) ) {
LogPrint ( " mnbudget " , " CFinalizedBudgetVote::IsValid() - vote is too far ahead of current time - %s - nTime %lli - Max Time %lli \n " , GetHash ( ) . ToString ( ) , nTime , GetTime ( ) + ( 60 * 60 ) ) ;
return false ;
}
CMasternode * pmn = mnodeman . Find ( vin ) ;
if ( pmn = = NULL )
{
LogPrint ( " mnbudget " , " CFinalizedBudgetVote::IsValid() - Unknown Masternode \n " ) ;
return false ;
}
if ( ! fSignatureCheck ) return true ;
std : : string errorMessage ;
std : : string strMessage = vin . prevout . ToStringShort ( ) + nBudgetHash . ToString ( ) + boost : : lexical_cast < std : : string > ( nTime ) ;
if ( ! darkSendSigner . VerifyMessage ( pmn - > pubkey2 , vchSig , strMessage , errorMessage ) ) {
LogPrintf ( " CFinalizedBudgetVote::IsValid() - Verify message failed \n " ) ;
return false ;
}
return true ;
}
std : : string CBudgetManager : : ToString ( ) const
{
std : : ostringstream info ;
info < < " Proposals: " < < ( int ) mapProposals . size ( ) < <
" , Seen Budgets: " < < ( int ) mapSeenMasternodeBudgetProposals . size ( ) < <
2016-04-09 22:31:01 +02:00
" , Seen Budget Votes: " < < ( int ) mapSeenMasternodeBudgetVotes . size ( ) ;
2016-04-09 21:57:53 +02:00
return info . str ( ) ;
}
void CBudgetManager : : UpdatedBlockTip ( const CBlockIndex * pindex )
{
pCurrentBlockIndex = pindex ;
LogPrint ( " mnbudget " , " pCurrentBlockIndex->nHeight: %d \n " , pCurrentBlockIndex - > nHeight ) ;
if ( ! fLiteMode & & masternodeSync . RequestedMasternodeAssets > MASTERNODE_SYNC_LIST )
NewBlock ( ) ;
}