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"
|
|
|
|
|
2016-04-10 08:31:32 +02:00
|
|
|
#include "flat-database.h"
|
2016-04-09 22:55:52 +02:00
|
|
|
#include "governance.h"
|
2016-04-14 00:41:40 +02:00
|
|
|
#include "governance-vote.h"
|
2016-04-09 21:57:53 +02:00
|
|
|
#include "masternode.h"
|
2016-04-15 04:54:11 +02:00
|
|
|
#include "governance.h"
|
2016-04-09 21:57:53 +02:00
|
|
|
#include "darksend.h"
|
|
|
|
#include "masternodeman.h"
|
|
|
|
#include "masternode-sync.h"
|
|
|
|
#include "util.h"
|
|
|
|
#include "addrman.h"
|
|
|
|
#include <boost/lexical_cast.hpp>
|
|
|
|
|
2016-04-14 20:53:46 +02:00
|
|
|
class CNode;
|
|
|
|
|
2016-04-10 16:46:19 +02:00
|
|
|
CGovernanceManager governance;
|
2016-04-09 21:57:53 +02:00
|
|
|
CCriticalSection cs_budget;
|
|
|
|
|
|
|
|
std::map<uint256, int64_t> askedForSourceProposalOrBudget;
|
2016-04-16 19:19:17 +02:00
|
|
|
std::vector<CGovernanceObject> vecImmatureBudgetProposals;
|
2016-04-09 21:57:53 +02:00
|
|
|
|
|
|
|
int nSubmittedFinalBudget;
|
|
|
|
|
2016-04-10 02:43:15 +02:00
|
|
|
bool IsCollateralValid(uint256 nTxCollateralHash, uint256 nExpectedHash, std::string& strError, int64_t& nTime, int& nConf, CAmount minFee)
|
2016-04-09 21:57:53 +02:00
|
|
|
{
|
|
|
|
CTransaction txCollateral;
|
|
|
|
uint256 nBlockHash;
|
|
|
|
if(!GetTransaction(nTxCollateralHash, txCollateral, Params().GetConsensus(), nBlockHash, true)){
|
|
|
|
strError = strprintf("Can't find collateral tx %s", txCollateral.ToString());
|
2016-04-16 19:19:17 +02:00
|
|
|
LogPrintf ("CGovernanceObject::IsCollateralValid - %s\n", strError);
|
2016-04-09 21:57:53 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-05-13 18:03:01 +02:00
|
|
|
if(txCollateral.vout.size() < 1) {
|
|
|
|
strError = strprintf("tx vout size less than 1 | %d", txCollateral.vout.size());
|
|
|
|
LogPrintf ("CGovernanceObject::IsCollateralValid - %s\n", strError);
|
|
|
|
return false;
|
|
|
|
}
|
2016-04-09 21:57:53 +02:00
|
|
|
|
|
|
|
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());
|
2016-04-16 19:19:17 +02:00
|
|
|
LogPrintf ("CGovernanceObject::IsCollateralValid - %s\n", strError);
|
2016-04-09 21:57:53 +02:00
|
|
|
return false;
|
|
|
|
}
|
2016-04-10 02:43:15 +02:00
|
|
|
if(o.scriptPubKey == findScript && o.nValue >= minFee) foundOpReturn = true;
|
2016-04-09 21:57:53 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
if(!foundOpReturn){
|
|
|
|
strError = strprintf("Couldn't find opReturn %s in %s", nExpectedHash.ToString(), txCollateral.ToString());
|
2016-04-16 19:19:17 +02:00
|
|
|
LogPrintf ("CGovernanceObject::IsCollateralValid - %s\n", strError);
|
2016-04-09 21:57:53 +02:00
|
|
|
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){
|
2016-05-13 18:03:01 +02:00
|
|
|
strError = "valid";
|
2016-04-09 21:57:53 +02:00
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
strError = strprintf("Collateral requires at least %d confirmations - %d confirmations", BUDGET_FEE_CONFIRMATIONS, conf);
|
2016-04-16 19:19:17 +02:00
|
|
|
LogPrintf ("CGovernanceObject::IsCollateralValid - %s - %d confirmations\n", strError, conf);
|
2016-04-09 21:57:53 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-09 22:55:52 +02:00
|
|
|
void CGovernanceManager::CheckOrphanVotes()
|
2016-04-09 21:57:53 +02:00
|
|
|
{
|
|
|
|
LOCK(cs);
|
|
|
|
|
|
|
|
std::string strError = "";
|
|
|
|
std::map<uint256, CBudgetVote>::iterator it1 = mapOrphanMasternodeBudgetVotes.begin();
|
|
|
|
while(it1 != mapOrphanMasternodeBudgetVotes.end()){
|
2016-04-09 22:55:52 +02:00
|
|
|
if(UpdateProposal(((*it1).second), NULL, strError)){
|
|
|
|
LogPrintf("CGovernanceManager::CheckOrphanVotes - Proposal/Budget is known, activating and removing orphan vote\n");
|
2016-04-09 21:57:53 +02:00
|
|
|
mapOrphanMasternodeBudgetVotes.erase(it1++);
|
|
|
|
} else {
|
|
|
|
++it1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-16 19:19:17 +02:00
|
|
|
bool CGovernanceManager::AddProposal(CGovernanceObject& budgetProposal)
|
2016-04-09 21:57:53 +02:00
|
|
|
{
|
|
|
|
LOCK(cs);
|
|
|
|
std::string strError = "";
|
|
|
|
if(!budgetProposal.IsValid(pCurrentBlockIndex, strError)) {
|
2016-05-13 18:03:01 +02:00
|
|
|
LogPrintf("CGovernanceManager::AddProposal - invalid governance object - %s\n", strError);
|
2016-04-09 21:57:53 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-05-13 18:03:01 +02:00
|
|
|
if(mapObjects.count(budgetProposal.GetHash())) {
|
|
|
|
LogPrintf("CGovernanceManager::AddProposal - already have governance object - %s\n", strError);
|
2016-04-09 21:57:53 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-05-13 18:03:01 +02:00
|
|
|
mapObjects.insert(make_pair(budgetProposal.GetHash(), budgetProposal));
|
2016-04-09 21:57:53 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-04-09 22:55:52 +02:00
|
|
|
void CGovernanceManager::CheckAndRemove()
|
2016-04-09 21:57:53 +02:00
|
|
|
{
|
2016-04-09 22:55:52 +02:00
|
|
|
LogPrintf("CGovernanceManager::CheckAndRemove \n");
|
2016-04-09 21:57:53 +02:00
|
|
|
|
2016-05-13 18:03:01 +02:00
|
|
|
// 12.1 -- disabled -- use "delete" voting mechanism
|
|
|
|
|
|
|
|
// if(!pCurrentBlockIndex) return;
|
2016-04-09 21:57:53 +02:00
|
|
|
|
2016-05-13 18:03:01 +02:00
|
|
|
// std::string strError = "";
|
2016-04-09 22:55:52 +02:00
|
|
|
|
2016-05-13 18:03:01 +02:00
|
|
|
// std::map<uint256, CGovernanceObject>::iterator it2 = mapObjects.begin();
|
|
|
|
// while(it2 != mapObjects.end())
|
|
|
|
// {
|
|
|
|
// CGovernanceObject* pbudgetProposal = &((*it2).second);
|
|
|
|
// pbudgetProposal->fValid = pbudgetProposal->IsValid(pCurrentBlockIndex, strError);
|
|
|
|
// ++it2;
|
|
|
|
// }
|
2016-04-09 21:57:53 +02:00
|
|
|
}
|
|
|
|
|
2016-04-16 19:19:17 +02:00
|
|
|
CGovernanceObject *CGovernanceManager::FindProposal(const std::string &strName)
|
2016-04-09 21:57:53 +02:00
|
|
|
{
|
|
|
|
//find the prop with the highest yes count
|
|
|
|
|
|
|
|
int nYesCount = -99999;
|
2016-04-16 19:19:17 +02:00
|
|
|
CGovernanceObject* pbudgetProposal = NULL;
|
2016-04-09 21:57:53 +02:00
|
|
|
|
2016-05-13 18:03:01 +02:00
|
|
|
std::map<uint256, CGovernanceObject>::iterator it = mapObjects.begin();
|
|
|
|
while(it != mapObjects.end()){
|
2016-04-26 06:08:36 +02:00
|
|
|
if((*it).second.strName == strName && (*it).second.GetYesCount(VOTE_ACTION_FUNDING) > nYesCount){
|
2016-04-09 21:57:53 +02:00
|
|
|
pbudgetProposal = &((*it).second);
|
2016-04-26 06:08:36 +02:00
|
|
|
nYesCount = pbudgetProposal->GetYesCount(VOTE_ACTION_FUNDING);
|
2016-04-09 21:57:53 +02:00
|
|
|
}
|
|
|
|
++it;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(nYesCount == -99999) return NULL;
|
|
|
|
|
|
|
|
return pbudgetProposal;
|
|
|
|
}
|
|
|
|
|
2016-04-16 19:19:17 +02:00
|
|
|
CGovernanceObject *CGovernanceManager::FindProposal(uint256 nHash)
|
2016-04-09 21:57:53 +02:00
|
|
|
{
|
|
|
|
LOCK(cs);
|
|
|
|
|
2016-05-13 18:03:01 +02:00
|
|
|
if(mapObjects.count(nHash))
|
|
|
|
return &mapObjects[nHash];
|
2016-04-09 21:57:53 +02:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2016-04-26 06:08:36 +02:00
|
|
|
std::vector<CGovernanceObject*> CGovernanceManager::GetAllProposals(int64_t nMoreThanTime)
|
2016-04-09 21:57:53 +02:00
|
|
|
{
|
|
|
|
LOCK(cs);
|
|
|
|
|
2016-04-16 19:19:17 +02:00
|
|
|
std::vector<CGovernanceObject*> vBudgetProposalRet;
|
2016-04-09 21:57:53 +02:00
|
|
|
|
2016-05-13 18:03:01 +02:00
|
|
|
std::map<uint256, CGovernanceObject>::iterator it = mapObjects.begin();
|
|
|
|
while(it != mapObjects.end())
|
2016-04-09 21:57:53 +02:00
|
|
|
{
|
2016-05-13 18:03:01 +02:00
|
|
|
// if((*it).second.nTime < nMoreThanTime) {
|
|
|
|
// ++it;
|
|
|
|
// continue;
|
|
|
|
// }
|
|
|
|
// (*it).second.CleanAndRemove(false);
|
2016-04-09 21:57:53 +02:00
|
|
|
|
2016-04-16 19:19:17 +02:00
|
|
|
CGovernanceObject* pbudgetProposal = &((*it).second);
|
2016-04-09 21:57:53 +02:00
|
|
|
vBudgetProposalRet.push_back(pbudgetProposal);
|
|
|
|
|
|
|
|
++it;
|
|
|
|
}
|
|
|
|
|
|
|
|
return vBudgetProposalRet;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Sort by votes, if there's a tie sort by their feeHash TX
|
|
|
|
//
|
|
|
|
struct sortProposalsByVotes {
|
2016-04-16 19:19:17 +02:00
|
|
|
bool operator()(const std::pair<CGovernanceObject*, int> &left, const std::pair<CGovernanceObject*, int> &right) {
|
2016-04-09 21:57:53 +02:00
|
|
|
if( left.second != right.second)
|
|
|
|
return (left.second > right.second);
|
|
|
|
return (UintToArith256(left.first->nFeeTXHash) > UintToArith256(right.first->nFeeTXHash));
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2016-04-09 22:55:52 +02:00
|
|
|
void CGovernanceManager::NewBlock()
|
2016-04-09 21:57:53 +02:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
|
2016-04-14 00:41:40 +02:00
|
|
|
// description: incremental sync with our peers
|
|
|
|
// note: incremental syncing seems excessive, well just have clients ask for specific objects and their votes
|
|
|
|
// note: 12.1 - remove
|
|
|
|
// if(masternodeSync.IsSynced()){
|
|
|
|
// /*
|
|
|
|
// Needs comment below:
|
|
|
|
|
|
|
|
// - Why are we doing a partial sync with our peers on new blocks?
|
|
|
|
// - Why only partial? Why not partial when we recieve the request directly?
|
|
|
|
// - Can we simplify this somehow?
|
|
|
|
// - Why are we marking everything synced? Was this to correct a bug?
|
|
|
|
// */
|
|
|
|
|
|
|
|
// LogPrintf("CGovernanceManager::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());
|
|
|
|
|
|
|
|
// MarkSynced();
|
|
|
|
// }
|
2016-04-09 21:57:53 +02:00
|
|
|
|
|
|
|
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++);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-13 18:03:01 +02:00
|
|
|
std::map<uint256, CGovernanceObject>::iterator it2 = mapObjects.begin();
|
|
|
|
while(it2 != mapObjects.end()){
|
2016-04-09 21:57:53 +02:00
|
|
|
(*it2).second.CleanAndRemove(false);
|
|
|
|
++it2;
|
|
|
|
}
|
|
|
|
|
2016-04-16 19:19:17 +02:00
|
|
|
std::vector<CGovernanceObject>::iterator it4 = vecImmatureBudgetProposals.begin();
|
2016-04-09 21:57:53 +02:00
|
|
|
while(it4 != vecImmatureBudgetProposals.end())
|
|
|
|
{
|
|
|
|
std::string strError = "";
|
|
|
|
int nConf = 0;
|
2016-04-10 02:43:15 +02:00
|
|
|
if(!IsCollateralValid((*it4).nFeeTXHash, (*it4).GetHash(), strError, (*it4).nTime, nConf, GOVERNANCE_FEE_TX)){
|
2016-04-09 21:57:53 +02:00
|
|
|
++it4;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2016-04-15 04:14:27 +02:00
|
|
|
// 12.1 -- fix below
|
|
|
|
// if(!(*it4).IsValid(pCurrentBlockIndex, strError)) {
|
|
|
|
// LogPrintf("mprop (immature) - invalid budget proposal - %s\n", strError);
|
|
|
|
// it4 = vecImmatureBudgetProposals.erase(it4);
|
|
|
|
// continue;
|
|
|
|
// }
|
|
|
|
|
2016-04-16 19:19:17 +02:00
|
|
|
// CGovernanceObject budgetProposal((*it4));
|
2016-04-15 04:14:27 +02:00
|
|
|
// if(AddProposal(budgetProposal)) {(*it4).Relay();}
|
|
|
|
|
|
|
|
// LogPrintf("mprop (immature) - new budget - %s\n", (*it4).GetHash().ToString());
|
|
|
|
// it4 = vecImmatureBudgetProposals.erase(it4);
|
2016-04-09 21:57:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2016-04-09 22:55:52 +02:00
|
|
|
void CGovernanceManager::ProcessMessage(CNode* pfrom, std::string& strCommand, CDataStream& vRecv)
|
2016-04-09 21:57:53 +02:00
|
|
|
{
|
|
|
|
// lite mode is not supported
|
|
|
|
if(fLiteMode) return;
|
|
|
|
if(!masternodeSync.IsBlockchainSynced()) return;
|
|
|
|
|
|
|
|
LOCK(cs_budget);
|
|
|
|
|
2016-05-05 19:30:28 +02:00
|
|
|
if (strCommand == NetMsgType::MNGOVERNANCEVOTESYNC) { //Masternode vote sync
|
2016-04-09 21:57:53 +02:00
|
|
|
uint256 nProp;
|
|
|
|
vRecv >> nProp;
|
|
|
|
|
|
|
|
if(Params().NetworkIDString() == CBaseChainParams::MAIN){
|
|
|
|
if(nProp == uint256()) {
|
2016-05-05 19:30:28 +02:00
|
|
|
if(pfrom->HasFulfilledRequest(NetMsgType::MNGOVERNANCEVOTESYNC)) {
|
2016-04-09 21:57:53 +02:00
|
|
|
LogPrintf("mnvs - peer already asked me for the list\n");
|
|
|
|
Misbehaving(pfrom->GetId(), 20);
|
|
|
|
return;
|
|
|
|
}
|
2016-05-05 19:30:28 +02:00
|
|
|
pfrom->FulfilledRequest(NetMsgType::MNGOVERNANCEVOTESYNC);
|
2016-04-09 21:57:53 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-14 00:41:40 +02:00
|
|
|
// ask for a specific proposal and it's votes
|
2016-04-09 21:57:53 +02:00
|
|
|
Sync(pfrom, nProp);
|
|
|
|
LogPrintf("mnvs - Sent Masternode votes to %s\n", pfrom->addr.ToString());
|
|
|
|
}
|
|
|
|
|
2016-05-05 19:30:28 +02:00
|
|
|
if (strCommand == NetMsgType::MNGOVERNANCEPROPOSAL) { //Masternode Proposal
|
2016-04-16 19:19:17 +02:00
|
|
|
CGovernanceObject budgetProposalBroadcast;
|
2016-04-09 21:57:53 +02:00
|
|
|
vRecv >> budgetProposalBroadcast;
|
|
|
|
|
|
|
|
if(mapSeenMasternodeBudgetProposals.count(budgetProposalBroadcast.GetHash())){
|
2016-05-13 18:03:01 +02:00
|
|
|
// TODO - print error code? what if it's GOVOBJ_ERROR_IMMATURE?
|
2016-04-09 21:57:53 +02:00
|
|
|
masternodeSync.AddedBudgetItem(budgetProposalBroadcast.GetHash());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string strError = "";
|
|
|
|
int nConf = 0;
|
2016-04-10 02:43:15 +02:00
|
|
|
if(!IsCollateralValid(budgetProposalBroadcast.nFeeTXHash, budgetProposalBroadcast.GetHash(), strError, budgetProposalBroadcast.nTime, nConf, GOVERNANCE_FEE_TX)){
|
2016-04-09 21:57:53 +02:00
|
|
|
LogPrintf("Proposal FeeTX is not valid - %s - %s\n", budgetProposalBroadcast.nFeeTXHash.ToString(), strError);
|
2016-05-07 00:36:11 +02:00
|
|
|
//todo 12.1
|
|
|
|
//if(nConf >= 1) vecImmatureBudgetProposals.push_back(budgetProposalBroadcast);
|
2016-04-09 21:57:53 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!budgetProposalBroadcast.IsValid(pCurrentBlockIndex, strError)) {
|
2016-05-13 18:03:01 +02:00
|
|
|
mapSeenMasternodeBudgetProposals.insert(make_pair(budgetProposalBroadcast.GetHash(), SEEN_OBJECT_ERROR_INVALID));
|
2016-04-09 21:57:53 +02:00
|
|
|
LogPrintf("mprop - invalid budget proposal - %s\n", strError);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-04-26 06:08:36 +02:00
|
|
|
if(AddProposal(budgetProposalBroadcast))
|
|
|
|
{
|
|
|
|
budgetProposalBroadcast.Relay();
|
|
|
|
}
|
2016-05-13 18:03:01 +02:00
|
|
|
mapSeenMasternodeBudgetProposals.insert(make_pair(budgetProposalBroadcast.GetHash(), SEEN_OBJECT_IS_VALID));
|
2016-04-09 21:57:53 +02:00
|
|
|
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-05-05 19:30:28 +02:00
|
|
|
if (strCommand == NetMsgType::MNGOVERNANCEVOTE) { //Masternode Vote
|
2016-04-09 21:57:53 +02:00
|
|
|
CBudgetVote vote;
|
|
|
|
vRecv >> vote;
|
|
|
|
vote.fValid = true;
|
|
|
|
|
|
|
|
if(mapSeenMasternodeBudgetVotes.count(vote.GetHash())){
|
|
|
|
masternodeSync.AddedBudgetItem(vote.GetHash());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-04-14 22:01:15 +02:00
|
|
|
CMasternode* pmn = mnodeman.Find(vote.vinMasternode);
|
2016-04-09 21:57:53 +02:00
|
|
|
if(pmn == NULL) {
|
2016-04-19 18:51:15 +02:00
|
|
|
LogPrint("mngovernance", "mvote - unknown masternode - vin: %s\n", vote.vinMasternode.ToString());
|
2016-04-14 22:01:15 +02:00
|
|
|
mnodeman.AskForMN(pfrom, vote.vinMasternode);
|
2016-04-09 21:57:53 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-05-13 18:03:01 +02:00
|
|
|
mapSeenMasternodeBudgetVotes.insert(make_pair(vote.GetHash(), SEEN_OBJECT_IS_VALID));
|
2016-04-09 21:57:53 +02:00
|
|
|
if(!vote.IsValid(true)){
|
|
|
|
LogPrintf("mvote - signature invalid\n");
|
|
|
|
if(masternodeSync.IsSynced()) Misbehaving(pfrom->GetId(), 20);
|
|
|
|
// it could just be a non-synced masternode
|
2016-04-14 22:01:15 +02:00
|
|
|
mnodeman.AskForMN(pfrom, vote.vinMasternode);
|
2016-04-09 21:57:53 +02:00
|
|
|
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());
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
//todo - 12.1 - terrible name - maybe DoesObjectExist?
|
2016-04-09 22:55:52 +02:00
|
|
|
bool CGovernanceManager::PropExists(uint256 nHash)
|
2016-04-09 21:57:53 +02:00
|
|
|
{
|
2016-05-13 18:03:01 +02:00
|
|
|
if(mapObjects.count(nHash)) return true;
|
2016-04-09 21:57:53 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-04-14 00:41:40 +02:00
|
|
|
// description: incremental sync with our peers
|
|
|
|
// note: incremental syncing seems excessive, well just have clients ask for specific objects and their votes
|
|
|
|
// note: 12.1 - remove
|
|
|
|
// void CGovernanceManager::ResetSync()
|
|
|
|
// {
|
|
|
|
// LOCK(cs);
|
2016-04-09 21:57:53 +02:00
|
|
|
|
2016-04-14 20:07:59 +02:00
|
|
|
// std::map<uint256, std::map<uint256, CBudgetVote> >::iterator it1 = mapVotes.begin();
|
2016-04-14 00:41:40 +02:00
|
|
|
// while(it1 != mapVotes.end()){
|
|
|
|
// (*it1).second.second.fSynced = false;
|
|
|
|
// ++it1;
|
|
|
|
// }
|
|
|
|
// }
|
2016-04-09 21:57:53 +02:00
|
|
|
|
2016-04-14 00:41:40 +02:00
|
|
|
// description: incremental sync with our peers
|
|
|
|
// note: incremental syncing seems excessive, well just have clients ask for specific objects and their votes
|
|
|
|
// note: 12.1 - remove
|
|
|
|
// void CGovernanceManager::MarkSynced()
|
|
|
|
// {
|
|
|
|
// LOCK(cs);
|
2016-04-09 21:57:53 +02:00
|
|
|
|
2016-04-14 00:41:40 +02:00
|
|
|
// /*
|
|
|
|
// Mark that we've sent all valid items
|
|
|
|
// */
|
2016-04-09 21:57:53 +02:00
|
|
|
|
2016-04-14 00:41:40 +02:00
|
|
|
// // this could screw up syncing, so let's log it
|
|
|
|
// LogPrintf("CGovernanceManager::MarkSynced\n");
|
2016-04-09 21:57:53 +02:00
|
|
|
|
2016-04-14 20:07:59 +02:00
|
|
|
// std::map<uint256, std::map<uint256, CBudgetVote> >::iterator it1 = mapVotes.begin();
|
2016-04-14 00:41:40 +02:00
|
|
|
// while(it1 != mapVotes.end()){
|
|
|
|
// if((*it1).second.second.fValid)
|
|
|
|
// (*it1).second.second.fSynced = true;
|
|
|
|
// ++it1;
|
|
|
|
// }
|
|
|
|
// }
|
2016-04-09 21:57:53 +02:00
|
|
|
|
|
|
|
|
2016-04-14 00:41:40 +02:00
|
|
|
void CGovernanceManager::Sync(CNode* pfrom, uint256 nProp)
|
2016-04-09 21:57:53 +02:00
|
|
|
{
|
|
|
|
LOCK(cs);
|
|
|
|
|
|
|
|
/*
|
2016-04-14 00:41:40 +02:00
|
|
|
note 12.1 - fix comments below
|
|
|
|
|
2016-04-09 21:57:53 +02:00
|
|
|
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;
|
|
|
|
|
2016-04-14 00:41:40 +02:00
|
|
|
// sync gov objects
|
2016-05-13 18:03:01 +02:00
|
|
|
std::map<uint256, int>::iterator it1 = mapSeenMasternodeBudgetProposals.begin();
|
2016-04-09 21:57:53 +02:00
|
|
|
while(it1 != mapSeenMasternodeBudgetProposals.end()){
|
2016-04-16 19:19:17 +02:00
|
|
|
CGovernanceObject* pbudgetProposal = FindProposal((*it1).first);
|
2016-05-13 18:03:01 +02:00
|
|
|
if(pbudgetProposal && pbudgetProposal->fCachedValid && ((nProp == uint256() || ((*it1).first == nProp)))){
|
2016-04-09 21:57:53 +02:00
|
|
|
// Push the inventory budget proposal message over to the other client
|
2016-05-13 18:03:01 +02:00
|
|
|
pfrom->PushInventory(CInv(MSG_BUDGET_PROPOSAL, (*it1).first));
|
2016-04-09 21:57:53 +02:00
|
|
|
nInvCount++;
|
|
|
|
}
|
|
|
|
++it1;
|
|
|
|
}
|
|
|
|
|
2016-04-14 00:41:40 +02:00
|
|
|
// sync votes
|
2016-05-13 18:03:01 +02:00
|
|
|
std::map<uint256, CBudgetVote>::iterator it2 = mapVotes.begin();
|
2016-04-14 20:53:46 +02:00
|
|
|
while(it2 != mapVotes.end()){
|
2016-05-13 18:03:01 +02:00
|
|
|
pfrom->PushInventory(CInv(MSG_BUDGET_VOTE, (*it2).first));
|
|
|
|
nInvCount++;
|
2016-04-14 20:53:46 +02:00
|
|
|
++it2;
|
2016-04-14 00:41:40 +02:00
|
|
|
}
|
|
|
|
|
2016-04-09 21:57:53 +02:00
|
|
|
pfrom->PushMessage(NetMsgType::SYNCSTATUSCOUNT, MASTERNODE_SYNC_BUDGET_PROP, nInvCount);
|
|
|
|
|
2016-04-09 22:55:52 +02:00
|
|
|
LogPrintf("CGovernanceManager::Sync - sent %d items\n", nInvCount);
|
2016-04-09 21:57:53 +02:00
|
|
|
}
|
|
|
|
|
2016-04-09 22:55:52 +02:00
|
|
|
bool CGovernanceManager::UpdateProposal(CBudgetVote& vote, CNode* pfrom, std::string& strError)
|
2016-04-09 21:57:53 +02:00
|
|
|
{
|
|
|
|
LOCK(cs);
|
|
|
|
|
2016-05-13 18:03:01 +02:00
|
|
|
if(!mapObjects.count(vote.nParentHash)){
|
2016-04-09 21:57:53 +02:00
|
|
|
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;
|
|
|
|
|
2016-04-14 22:01:15 +02:00
|
|
|
LogPrintf("CGovernanceManager::UpdateProposal - Unknown proposal %d, asking for source proposal\n", vote.nParentHash.ToString());
|
|
|
|
mapOrphanMasternodeBudgetVotes[vote.nParentHash] = vote;
|
2016-04-09 21:57:53 +02:00
|
|
|
|
2016-04-14 22:01:15 +02:00
|
|
|
if(!askedForSourceProposalOrBudget.count(vote.nParentHash)){
|
2016-05-05 19:30:28 +02:00
|
|
|
pfrom->PushMessage(NetMsgType::MNGOVERNANCEVOTESYNC, vote.nParentHash);
|
2016-04-14 22:01:15 +02:00
|
|
|
askedForSourceProposalOrBudget[vote.nParentHash] = GetTime();
|
2016-04-09 21:57:53 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
strError = "Proposal not found!";
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-04-14 03:52:26 +02:00
|
|
|
return AddOrUpdateVote(vote, strError);
|
2016-04-09 21:57:53 +02:00
|
|
|
}
|
|
|
|
|
2016-04-14 03:52:26 +02:00
|
|
|
bool CGovernanceManager::AddOrUpdateVote(CBudgetVote& vote, std::string& strError)
|
2016-04-14 00:41:40 +02:00
|
|
|
{
|
|
|
|
LOCK(cs);
|
|
|
|
|
2016-05-13 18:03:01 +02:00
|
|
|
// uint256 hash = vote.vinMasternode.prevout.GetHash();
|
|
|
|
// uint256 hash2 = vote.nParentHash;
|
2016-04-14 03:52:26 +02:00
|
|
|
|
2016-05-13 18:03:01 +02:00
|
|
|
// if(mapVotes[hash2].count(hash))
|
|
|
|
// {
|
|
|
|
// if(mapVotes[hash2][hash].nTime > vote.nTime){
|
|
|
|
// strError = strprintf("new vote older than existing vote - %s", vote.GetHash().ToString());
|
|
|
|
// LogPrint("mngovernance", "CGovernanceObject::AddOrUpdateVote - %s\n", strError);
|
|
|
|
// return false;
|
|
|
|
// }
|
|
|
|
// if(vote.nTime - mapVotes[hash2][hash].nTime < BUDGET_VOTE_UPDATE_MIN){
|
|
|
|
// strError = strprintf("time between votes is too soon - %s - %lli", vote.GetHash().ToString(), vote.nTime - mapVotes[hash2][hash].nTime);
|
|
|
|
// LogPrint("mngovernance", "CGovernanceObject::AddOrUpdateVote - %s\n", strError);
|
|
|
|
// return false;
|
|
|
|
// }
|
|
|
|
// }
|
2016-04-14 00:41:40 +02:00
|
|
|
|
2016-05-13 18:03:01 +02:00
|
|
|
// mapVotes[hash2][hash] = vote;
|
2016-04-14 00:41:40 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-04-16 19:19:17 +02:00
|
|
|
CGovernanceObject::CGovernanceObject()
|
2016-04-09 21:57:53 +02:00
|
|
|
{
|
2016-04-15 18:39:33 +02:00
|
|
|
strName = "unknown";
|
2016-04-09 21:57:53 +02:00
|
|
|
nTime = 0;
|
2016-04-26 06:08:36 +02:00
|
|
|
|
2016-04-26 13:42:34 +02:00
|
|
|
nHashParent = uint256(); //parent object, 0 is root
|
2016-04-26 06:08:36 +02:00
|
|
|
nRevision = 0; //object revision in the system
|
2016-04-26 13:42:34 +02:00
|
|
|
nFeeTXHash = uint256(); //fee-tx
|
2016-04-26 06:08:36 +02:00
|
|
|
|
|
|
|
// caching
|
2016-05-13 18:03:01 +02:00
|
|
|
fCachedFunding = false;
|
|
|
|
fCachedValid = false;
|
|
|
|
fCachedDelete = false;
|
|
|
|
fCachedClearRegisters = false;
|
|
|
|
fCachedEndorsed = false;
|
|
|
|
fCachedReleaseBounty1 = false;
|
|
|
|
fCachedReleaseBounty2 = false;
|
|
|
|
fCachedReleaseBounty3 = false;
|
|
|
|
|
2016-04-26 13:42:34 +02:00
|
|
|
nHash = uint256();
|
2016-04-09 21:57:53 +02:00
|
|
|
}
|
|
|
|
|
2016-04-26 06:08:36 +02:00
|
|
|
CGovernanceObject::CGovernanceObject(uint256 nHashParentIn, int nRevisionIn, std::string strNameIn, int64_t nTime, uint256 nFeeTXHashIn)
|
2016-04-09 21:57:53 +02:00
|
|
|
{
|
2016-04-26 06:08:36 +02:00
|
|
|
strName = "unknown";
|
|
|
|
nTime = 0;
|
|
|
|
|
|
|
|
nHashParent = nHashParentIn; //parent object, 0 is root
|
2016-04-26 13:44:48 +02:00
|
|
|
// nPriority = nPriorityIn;
|
2016-04-26 06:08:36 +02:00
|
|
|
nRevision = nRevisionIn; //object revision in the system
|
|
|
|
nFeeTXHash = nFeeTXHashIn; //fee-tx
|
2016-04-26 13:44:48 +02:00
|
|
|
// nTypeVersion = nTypeVersionIn;
|
2016-04-09 21:57:53 +02:00
|
|
|
}
|
|
|
|
|
2016-04-26 13:42:34 +02:00
|
|
|
CGovernanceObject::CGovernanceObject(const CGovernanceObject& other)
|
|
|
|
{
|
|
|
|
strName = other.strName;
|
|
|
|
nTime = other.nTime;
|
|
|
|
|
|
|
|
nHashParent = other.nHashParent; //parent object, 0 is root
|
|
|
|
// nPriority = other.nPriorityIn;
|
|
|
|
nRevision = other.nRevision; //object revision in the system
|
|
|
|
nFeeTXHash = other.nFeeTXHash; //fee-tx
|
|
|
|
// nTypeVersion = other.nTypeVersion;
|
|
|
|
//??
|
2016-05-13 18:03:01 +02:00
|
|
|
strData = other.strData;
|
2016-04-26 13:42:34 +02:00
|
|
|
}
|
|
|
|
|
2016-04-16 19:19:17 +02:00
|
|
|
bool CGovernanceObject::IsValid(const CBlockIndex* pindex, std::string& strError, bool fCheckCollateral)
|
2016-04-09 21:57:53 +02:00
|
|
|
{
|
2016-04-26 06:08:36 +02:00
|
|
|
if(GetNoCount(VOTE_ACTION_VALID) - GetYesCount(VOTE_ACTION_VALID) > mnodeman.CountEnabled(MIN_BUDGET_PEER_PROTO_VERSION)/10){
|
|
|
|
strError = "Automated removal";
|
2016-04-09 21:57:53 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-04-26 13:44:48 +02:00
|
|
|
// if(nEndTime < GetTime()) {
|
|
|
|
// strError = "Expired Proposal";
|
|
|
|
// return false;
|
|
|
|
// }
|
2016-04-09 21:57:53 +02:00
|
|
|
|
|
|
|
if(!pindex) {
|
|
|
|
strError = "Tip is NULL";
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-04-26 13:44:48 +02:00
|
|
|
// if(nAmount < 10000) {
|
|
|
|
// strError = "Invalid proposal amount (minimum 10000)";
|
|
|
|
// return false;
|
|
|
|
// }
|
2016-04-09 21:57:53 +02:00
|
|
|
|
2016-04-15 18:39:33 +02:00
|
|
|
if(strName.size() > 20) {
|
2016-04-09 21:57:53 +02:00
|
|
|
strError = "Invalid proposal name, limit of 20 characters.";
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-04-15 18:39:33 +02:00
|
|
|
if(strName != SanitizeString(strName)) {
|
2016-04-09 21:57:53 +02:00
|
|
|
strError = "Invalid proposal name, unsafe characters found.";
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-04-26 13:44:48 +02:00
|
|
|
// if(address == CScript()) {
|
|
|
|
// strError = "Invalid proposal Payment Address";
|
|
|
|
// return false;
|
|
|
|
// }
|
2016-04-09 21:57:53 +02:00
|
|
|
|
2016-04-14 03:52:26 +02:00
|
|
|
// 12.1 - add valid predicates
|
|
|
|
// this can be handled by configuration
|
|
|
|
// found = false
|
2016-04-15 18:39:33 +02:00
|
|
|
// if strName[:10] = "proposal="; found = true;
|
|
|
|
// if strName[:10] = "contract="; found = true;
|
|
|
|
// if strName[:10] = "project="; found = true;
|
|
|
|
// if strName[:10] = "employee="; found = true;
|
|
|
|
// if strName[:10] = "project-milestone="; found = true;
|
|
|
|
// if strName[:10] = "project-report="; found = true;
|
2016-04-14 00:41:40 +02:00
|
|
|
|
2016-04-14 03:52:26 +02:00
|
|
|
// if not found: return false
|
2016-04-14 00:41:40 +02:00
|
|
|
|
2016-04-14 03:52:26 +02:00
|
|
|
// automatically expire
|
|
|
|
// if(GetTime() > nExpirationTime) return false;
|
2016-04-14 00:41:40 +02:00
|
|
|
|
2016-04-09 21:57:53 +02:00
|
|
|
if(fCheckCollateral){
|
|
|
|
int nConf = 0;
|
2016-04-10 02:43:15 +02:00
|
|
|
if(!IsCollateralValid(nFeeTXHash, GetHash(), strError, nTime, nConf, GOVERNANCE_FEE_TX)){
|
2016-05-13 18:03:01 +02:00
|
|
|
// strError set in IsCollateralValid
|
2016-04-09 21:57:53 +02:00
|
|
|
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.
|
|
|
|
*/
|
2016-04-26 13:44:48 +02:00
|
|
|
// if(address.IsPayToScriptHash()) {
|
|
|
|
// strError = "Multisig is not currently supported.";
|
|
|
|
// return false;
|
|
|
|
// }
|
2016-04-09 21:57:53 +02:00
|
|
|
|
2016-04-14 23:28:33 +02:00
|
|
|
// 12.1 move to pybrain
|
|
|
|
// //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;
|
|
|
|
// }
|
2016-04-09 21:57:53 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-04-16 19:19:17 +02:00
|
|
|
bool CGovernanceObject::NetworkWillPay()
|
2016-04-14 20:07:59 +02:00
|
|
|
{
|
|
|
|
/**
|
|
|
|
* vote nVoteType 1 to 10
|
|
|
|
* --------------------------
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* // note: if the vote is not passing and we're before the starttime, it's invalid
|
|
|
|
* // note: plain english version - if funding votes nocount > funding votes yescount and GetTime() < nStartTime: return false
|
|
|
|
* if votecount(VOTE_TYPE_FUNDING, "no") > votecount(VOTE_TYPE_FUNDING, "yes") && GetTime() < nStartTime: return false
|
|
|
|
*/
|
|
|
|
|
2016-04-14 22:01:15 +02:00
|
|
|
std::string strError = "";
|
|
|
|
|
|
|
|
// -- If GetAbsoluteYesCount is more than -10% of the network, flag as invalid
|
2016-04-26 13:44:48 +02:00
|
|
|
// if(GetAbsoluteYesCount() < -(mnodeman.CountEnabled(MIN_BUDGET_PEER_PROTO_VERSION)/10)) {
|
|
|
|
// strError = "Voted Down";
|
|
|
|
// return false;
|
|
|
|
// }
|
2016-04-14 22:01:15 +02:00
|
|
|
|
|
|
|
return true;
|
2016-04-14 20:07:59 +02:00
|
|
|
}
|
|
|
|
|
2016-04-26 13:42:34 +02:00
|
|
|
void CGovernanceObject::CleanAndRemove(bool fSignatureCheck) {
|
|
|
|
// TODO: do smth here
|
|
|
|
}
|
|
|
|
|
2016-04-14 22:01:15 +02:00
|
|
|
void CGovernanceManager::CleanAndRemove(bool fSignatureCheck)
|
2016-04-09 21:57:53 +02:00
|
|
|
{
|
2016-04-14 22:01:15 +02:00
|
|
|
/*
|
|
|
|
*
|
|
|
|
* Loop through each item and delete the items that have become invalid
|
|
|
|
*
|
|
|
|
*/
|
2016-04-09 21:57:53 +02:00
|
|
|
|
2016-05-13 18:03:01 +02:00
|
|
|
std::map<uint256, CBudgetVote>::iterator it2 = mapVotes.begin();
|
2016-04-14 22:01:15 +02:00
|
|
|
while(it2 != mapVotes.end()){
|
2016-05-13 18:03:01 +02:00
|
|
|
if(!(*it2).second.IsValid(fSignatureCheck))
|
2016-04-14 22:01:15 +02:00
|
|
|
{
|
2016-05-13 18:03:01 +02:00
|
|
|
// 12.1 - log to specialized handle (govobj?)
|
|
|
|
LogPrintf("CGovernanceManager::CleanAndRemove - Proposal/Budget is known, activating and removing orphan vote\n");
|
|
|
|
mapVotes.erase(it2++);
|
|
|
|
} else {
|
|
|
|
++it2;
|
2016-04-14 22:01:15 +02:00
|
|
|
}
|
2016-04-09 21:57:53 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-26 06:08:36 +02:00
|
|
|
/**
|
|
|
|
* Get specific vote counts for each outcome (funding, validity, etc)
|
|
|
|
*/
|
|
|
|
|
|
|
|
int CGovernanceObject::GetAbsoluteYesCount(int nVoteOutcomeIn)
|
2016-04-09 21:57:53 +02:00
|
|
|
{
|
2016-05-13 18:03:01 +02:00
|
|
|
return governance.CountMatchingAbsoluteVotes(nVoteOutcomeIn, VOTE_OUTCOME_YES) - governance.CountMatchingAbsoluteVotes(nVoteOutcomeIn, VOTE_OUTCOME_NO);
|
2016-04-09 21:57:53 +02:00
|
|
|
}
|
|
|
|
|
2016-04-26 06:08:36 +02:00
|
|
|
int CGovernanceObject::GetYesCount(int nVoteOutcomeIn)
|
2016-04-09 21:57:53 +02:00
|
|
|
{
|
2016-05-13 18:03:01 +02:00
|
|
|
return governance.CountMatchingAbsoluteVotes(nVoteOutcomeIn, VOTE_OUTCOME_YES);
|
2016-04-09 21:57:53 +02:00
|
|
|
}
|
|
|
|
|
2016-04-26 06:08:36 +02:00
|
|
|
int CGovernanceObject::GetNoCount(int nVoteOutcomeIn)
|
2016-04-09 21:57:53 +02:00
|
|
|
{
|
2016-05-13 18:03:01 +02:00
|
|
|
return governance.CountMatchingAbsoluteVotes(nVoteOutcomeIn, VOTE_OUTCOME_NO);
|
2016-04-09 21:57:53 +02:00
|
|
|
}
|
|
|
|
|
2016-04-26 06:08:36 +02:00
|
|
|
int CGovernanceObject::GetAbstainCount(int nVoteOutcomeIn)
|
2016-04-09 21:57:53 +02:00
|
|
|
{
|
2016-05-13 18:03:01 +02:00
|
|
|
return governance.CountMatchingAbsoluteVotes(nVoteOutcomeIn, VOTE_OUTCOME_ABSTAIN);
|
2016-04-09 21:57:53 +02:00
|
|
|
}
|
|
|
|
|
2016-04-16 19:19:17 +02:00
|
|
|
void CGovernanceObject::Relay()
|
2016-04-09 21:57:53 +02:00
|
|
|
{
|
|
|
|
CInv inv(MSG_BUDGET_PROPOSAL, GetHash());
|
|
|
|
RelayInv(inv, MIN_BUDGET_PEER_PROTO_VERSION);
|
|
|
|
}
|
|
|
|
|
2016-04-09 22:55:52 +02:00
|
|
|
std::string CGovernanceManager::ToString() const
|
2016-04-09 21:57:53 +02:00
|
|
|
{
|
|
|
|
std::ostringstream info;
|
|
|
|
|
2016-05-13 18:03:01 +02:00
|
|
|
info << "Proposals: " << (int)mapObjects.size() <<
|
2016-04-09 21:57:53 +02:00
|
|
|
", 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();
|
|
|
|
}
|
|
|
|
|
2016-04-09 22:55:52 +02:00
|
|
|
void CGovernanceManager::UpdatedBlockTip(const CBlockIndex *pindex)
|
2016-04-09 21:57:53 +02:00
|
|
|
{
|
|
|
|
pCurrentBlockIndex = pindex;
|
2016-04-19 18:51:15 +02:00
|
|
|
LogPrint("mngovernance", "pCurrentBlockIndex->nHeight: %d\n", pCurrentBlockIndex->nHeight);
|
2016-04-09 21:57:53 +02:00
|
|
|
|
|
|
|
if(!fLiteMode && masternodeSync.RequestedMasternodeAssets > MASTERNODE_SYNC_LIST)
|
|
|
|
NewBlock();
|
|
|
|
}
|
2016-04-14 20:07:59 +02:00
|
|
|
|
2016-05-13 18:03:01 +02:00
|
|
|
int CGovernanceManager::CountMatchingAbsoluteVotes(int nVoteActionIn, int nVoteOutcomeIn)
|
2016-04-14 22:01:15 +02:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
*
|
|
|
|
* Count matching votes and return
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2016-05-13 18:03:01 +02:00
|
|
|
int nCount = 0;
|
2016-04-14 22:01:15 +02:00
|
|
|
|
2016-05-13 18:03:01 +02:00
|
|
|
std::map<uint256, CBudgetVote>::iterator it2 = mapVotes.begin();
|
2016-04-14 22:01:15 +02:00
|
|
|
while(it2 != mapVotes.end()){
|
2016-05-13 18:03:01 +02:00
|
|
|
if(!(*it2).second.IsValid(true) && (*it2).second.nVoteAction == nVoteActionIn)
|
2016-04-14 22:01:15 +02:00
|
|
|
{
|
2016-05-13 18:03:01 +02:00
|
|
|
nCount += ((*it2).second.nVoteOutcome == nVoteOutcomeIn ? 1 : 0);
|
|
|
|
} else {
|
|
|
|
++it2;
|
2016-04-14 22:01:15 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-13 18:03:01 +02:00
|
|
|
return nCount;
|
|
|
|
}
|