neobytes/src/governance.cpp

779 lines
25 KiB
C++
Raw Normal View History

// 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"
#include "masternode.h"
2016-04-09 22:55:52 +02:00
#include "masternode-budget.h"
#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;
CCriticalSection cs_budget;
std::map<uint256, int64_t> askedForSourceProposalOrBudget;
2016-04-14 20:53:46 +02:00
std::vector<CBudgetProposal> vecImmatureBudgetProposals;
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)
{
CTransaction txCollateral;
uint256 nBlockHash;
if(!GetTransaction(nTxCollateralHash, txCollateral, Params().GetConsensus(), nBlockHash, true)){
strError = strprintf("Can't find collateral tx %s", txCollateral.ToString());
2016-04-14 20:53:46 +02:00
LogPrintf ("CBudgetProposal::IsCollateralValid - %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());
2016-04-14 20:53:46 +02:00
LogPrintf ("CBudgetProposal::IsCollateralValid - %s\n", strError);
return false;
}
2016-04-10 02:43:15 +02:00
if(o.scriptPubKey == findScript && o.nValue >= minFee) foundOpReturn = true;
}
if(!foundOpReturn){
strError = strprintf("Couldn't find opReturn %s in %s", nExpectedHash.ToString(), txCollateral.ToString());
2016-04-14 20:53:46 +02:00
LogPrintf ("CBudgetProposal::IsCollateralValid - %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);
2016-04-14 20:53:46 +02:00
LogPrintf ("CBudgetProposal::IsCollateralValid - %s - %d confirmations\n", strError, conf);
return false;
}
}
2016-04-09 22:55:52 +02:00
void CGovernanceManager::CheckOrphanVotes()
{
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");
mapOrphanMasternodeBudgetVotes.erase(it1++);
} else {
++it1;
}
}
}
2016-04-09 22:55:52 +02:00
bool CGovernanceManager::AddProposal(CBudgetProposal& budgetProposal)
{
LOCK(cs);
std::string strError = "";
if(!budgetProposal.IsValid(pCurrentBlockIndex, strError)) {
2016-04-09 22:55:52 +02:00
LogPrintf("CGovernanceManager::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;
}
2016-04-09 22:55:52 +02:00
void CGovernanceManager::CheckAndRemove()
{
2016-04-09 22:55:52 +02:00
LogPrintf("CGovernanceManager::CheckAndRemove \n");
if(!pCurrentBlockIndex) return;
2016-04-09 22:55:52 +02:00
std::string strError = "";
std::map<uint256, CBudgetProposal>::iterator it2 = mapProposals.begin();
while(it2 != mapProposals.end())
{
CBudgetProposal* pbudgetProposal = &((*it2).second);
pbudgetProposal->fValid = pbudgetProposal->IsValid(pCurrentBlockIndex, strError);
++it2;
}
}
2016-04-09 22:55:52 +02:00
CBudgetProposal *CGovernanceManager::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;
}
2016-04-09 22:55:52 +02:00
CBudgetProposal *CGovernanceManager::FindProposal(uint256 nHash)
{
LOCK(cs);
if(mapProposals.count(nHash))
return &mapProposals[nHash];
return NULL;
}
2016-04-09 22:55:52 +02:00
std::vector<CBudgetProposal*> CGovernanceManager::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));
}
};
2016-04-09 22:55:52 +02:00
void CGovernanceManager::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;
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();
// }
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;
}
2016-04-14 20:53:46 +02:00
std::vector<CBudgetProposal>::iterator it4 = vecImmatureBudgetProposals.begin();
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)){
++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);
}
}
2016-04-09 22:55:52 +02:00
void CGovernanceManager::ProcessMessage(CNode* pfrom, std::string& strCommand, CDataStream& vRecv)
{
// lite mode is not supported
if(fLiteMode) return;
if(!masternodeSync.IsBlockchainSynced()) return;
LOCK(cs_budget);
// todo - 12.1 - change to MNGOVERNANCEVOTESYNC
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);
}
}
2016-04-14 00:41:40 +02:00
// ask for a specific proposal and it's votes
Sync(pfrom, nProp);
LogPrintf("mnvs - Sent Masternode votes to %s\n", pfrom->addr.ToString());
}
// todo - 12.1 - change to MNGOVERNANCEPROPOSAL
if (strCommand == NetMsgType::MNBUDGETPROPOSAL) { //Masternode Proposal
2016-04-14 20:53:46 +02:00
CBudgetProposal budgetProposalBroadcast;
vRecv >> budgetProposalBroadcast;
if(mapSeenMasternodeBudgetProposals.count(budgetProposalBroadcast.GetHash())){
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)){
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();
}
// todo - 12.1 - change to MNGOVERNANCEVOTE
if (strCommand == NetMsgType::MNBUDGETVOTE) { //Masternode Vote
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);
if(pmn == NULL) {
2016-04-14 22:01:15 +02:00
LogPrint("mnbudget", "mvote - unknown masternode - vin: %s\n", vote.vinMasternode.ToString());
mnodeman.AskForMN(pfrom, vote.vinMasternode);
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
2016-04-14 22:01:15 +02:00
mnodeman.AskForMN(pfrom, vote.vinMasternode);
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)
{
if(mapProposals.count(nHash)) return true;
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-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-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-14 00:41:40 +02:00
// /*
// Mark that we've sent all valid items
// */
2016-04-14 00:41:40 +02:00
// // this could screw up syncing, so let's log it
// LogPrintf("CGovernanceManager::MarkSynced\n");
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-14 00:41:40 +02:00
void CGovernanceManager::Sync(CNode* pfrom, uint256 nProp)
{
LOCK(cs);
/*
2016-04-14 00:41:40 +02:00
note 12.1 - fix comments below
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-04-14 20:53:46 +02:00
std::map<uint256, CBudgetProposal>::iterator it1 = mapSeenMasternodeBudgetProposals.begin();
while(it1 != mapSeenMasternodeBudgetProposals.end()){
CBudgetProposal* pbudgetProposal = FindProposal((*it1).first);
2016-04-14 00:41:40 +02:00
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++;
}
++it1;
}
2016-04-14 00:41:40 +02:00
// sync votes
2016-04-14 20:53:46 +02:00
std::map<uint256, std::map<uint256, CBudgetVote> >::iterator it2 = mapVotes.begin();
while(it2 != mapVotes.end()){
std::map<uint256, CBudgetVote>::iterator it3 = mapVotes[(*it2).first].begin();
if((*it3).second.fValid && ((nProp == uint256() || ((*it2).first == nProp))))
2016-04-14 22:01:15 +02:00
{
pfrom->PushInventory(CInv(MSG_BUDGET_VOTE, (*it3).second.GetHash()));
nInvCount++;
}
2016-04-14 20:53:46 +02:00
++it2;
2016-04-14 00:41:40 +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 22:55:52 +02:00
bool CGovernanceManager::UpdateProposal(CBudgetVote& vote, CNode* pfrom, std::string& strError)
{
LOCK(cs);
2016-04-14 22:01:15 +02:00
if(!mapProposals.count(vote.nParentHash)){
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-14 22:01:15 +02:00
if(!askedForSourceProposalOrBudget.count(vote.nParentHash)){
pfrom->PushMessage(NetMsgType::MNBUDGETVOTESYNC, vote.nParentHash);
askedForSourceProposalOrBudget[vote.nParentHash] = GetTime();
}
}
strError = "Proposal not found!";
return false;
}
2016-04-14 03:52:26 +02:00
return AddOrUpdateVote(vote, strError);
}
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-04-14 22:01:15 +02:00
uint256 hash = vote.vinMasternode.prevout.GetHash();
uint256 hash2 = vote.nParentHash;
2016-04-14 03:52:26 +02:00
2016-04-14 22:01:15 +02:00
if(mapVotes[hash2].count(hash)){
if(mapVotes[hash2][hash].nTime > vote.nTime){
2016-04-14 00:41:40 +02:00
strError = strprintf("new vote older than existing vote - %s", vote.GetHash().ToString());
LogPrint("mnbudget", "CBudgetProposal::AddOrUpdateVote - %s\n", strError);
return false;
}
2016-04-14 22:01:15 +02:00
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);
2016-04-14 00:41:40 +02:00
LogPrint("mnbudget", "CBudgetProposal::AddOrUpdateVote - %s\n", strError);
return false;
}
}
2016-04-14 22:01:15 +02:00
mapVotes[hash2][hash] = vote;
2016-04-14 00:41:40 +02:00
return true;
}
CBudgetProposal::CBudgetProposal()
{
strProposalName = "unknown";
2016-04-14 23:28:33 +02:00
nStartTime = 0;
nEndTime = 0;
nAmount = 0;
nTime = 0;
fValid = true;
}
CBudgetProposal::CBudgetProposal(const CBudgetProposal& other)
{
strProposalName = other.strProposalName;
strURL = other.strURL;
2016-04-14 23:28:33 +02:00
nStartTime = other.nStartTime;
nEndTime = other.nEndTime;
address = other.address;
nAmount = other.nAmount;
nTime = other.nTime;
nFeeTXHash = other.nFeeTXHash;
fValid = true;
}
2016-04-14 23:28:33 +02:00
CBudgetProposal::CBudgetProposal(std::string strProposalNameIn, std::string strURLIn, int nPaymentCount, CScript addressIn, CAmount nAmountIn, int64_t nStartTimeIn, int64_t nEndTimeIn, uint256 nFeeTXHashIn)
{
strProposalName = strProposalNameIn;
strURL = strURLIn;
2016-04-14 23:28:33 +02:00
nStartTime = nStartTimeIn;
nEndTime = nEndTimeIn;
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;
}
2016-04-14 23:28:33 +02:00
if(nEndTime < GetTime()) {
strError = "Expired Proposal";
return false;
}
if(!pindex) {
strError = "Tip is NULL";
return true;
}
2016-04-14 23:28:33 +02:00
if(nAmount < 10000) {
strError = "Invalid proposal amount (minimum 10000)";
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;
}
2016-04-14 23:28:33 +02:00
if(strURL.size() > 100) {
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;
}
2016-04-14 03:52:26 +02:00
// 12.1 - add valid predicates
// this can be handled by configuration
// found = false
// if strProposalName[:10] = "proposal="; found = true;
// if strProposalName[:10] = "contract="; found = true;
// if strProposalName[:10] = "project="; found = true;
// if strProposalName[:10] = "employee="; found = true;
// if strProposalName[:10] = "project-milestone="; found = true;
// if strProposalName[: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
if(fCheckCollateral){
int nConf = 0;
2016-04-10 02:43:15 +02:00
if(!IsCollateralValid(nFeeTXHash, GetHash(), strError, nTime, nConf, GOVERNANCE_FEE_TX)){
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;
}
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;
// }
return true;
}
2016-04-14 20:07:59 +02:00
bool CBudgetProposal::NetworkWillPay()
{
/**
* 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
if(GetAbsoluteYesCount() < -(mnodeman.CountEnabled(MIN_BUDGET_PEER_PROTO_VERSION)/10)) {
strError = "Voted Down";
return false;
}
return true;
2016-04-14 20:07:59 +02:00
}
bool CBudgetProposal::IsEstablished() {
//Proposals must be established to make it into a budget
return (nTime < GetTime() - Params().GetConsensus().nBudgetProposalEstablishingTime);
}
2016-04-14 22:01:15 +02:00
void CGovernanceManager::CleanAndRemove(bool fSignatureCheck)
{
2016-04-14 22:01:15 +02:00
/*
*
* Loop through each item and delete the items that have become invalid
*
*/
2016-04-14 22:01:15 +02:00
std::map<uint256, std::map<uint256, CBudgetVote> >::iterator it2 = mapVotes.begin();
while(it2 != mapVotes.end()){
std::map<uint256, CBudgetVote>::iterator it3 = mapVotes[(*it2).first].begin();
while(it3 != mapVotes[(*it2).first].end())
{
if(!(*it3).second.IsValid(fSignatureCheck))
{
// 12.1 - log to specialized handle (govobj?)
LogPrintf("CGovernanceManager::CleanAndRemove - Proposal/Budget is known, activating and removing orphan vote\n");
mapVotes[(*it2).first].erase(it3++);
} else {
++it3;
}
}
++it2;
}
}
int CBudgetProposal::GetAbsoluteYesCount()
{
2016-04-14 23:28:33 +02:00
return governance.CountMatchingVotes(VOTE_TYPE_FUND, VOTE_OUTCOME_YES) - governance.CountMatchingVotes(VOTE_TYPE_FUND, VOTE_OUTCOME_NO);
}
int CBudgetProposal::GetYesCount()
{
2016-04-14 22:01:15 +02:00
return governance.CountMatchingVotes(VOTE_TYPE_FUND, VOTE_OUTCOME_YES);
}
int CBudgetProposal::GetNoCount()
{
2016-04-14 22:01:15 +02:00
return governance.CountMatchingVotes(VOTE_TYPE_FUND, VOTE_OUTCOME_NO);
}
int CBudgetProposal::GetAbstainCount()
{
2016-04-14 22:01:15 +02:00
return governance.CountMatchingVotes(VOTE_TYPE_FUND, VOTE_OUTCOME_ABSTAIN);
}
2016-04-14 20:53:46 +02:00
void CBudgetProposal::Relay()
{
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
{
std::ostringstream info;
info << "Proposals: " << (int)mapProposals.size() <<
", Seen Budgets: " << (int)mapSeenMasternodeBudgetProposals.size() <<
", Seen Budget Votes: " << (int)mapSeenMasternodeBudgetVotes.size();
return info.str();
}
2016-04-09 22:55:52 +02:00
void CGovernanceManager::UpdatedBlockTip(const CBlockIndex *pindex)
{
pCurrentBlockIndex = pindex;
LogPrint("mnbudget", "pCurrentBlockIndex->nHeight: %d\n", pCurrentBlockIndex->nHeight);
if(!fLiteMode && masternodeSync.RequestedMasternodeAssets > MASTERNODE_SYNC_LIST)
NewBlock();
}
2016-04-14 20:07:59 +02:00
2016-04-14 23:28:33 +02:00
int CGovernanceManager::CountMatchingVotes(int nVoteTypeIn, int nVoteOutcomeIn)
2016-04-14 22:01:15 +02:00
{
/*
*
* Count matching votes and return
*
*/
int nMatching = 0;
std::map<uint256, std::map<uint256, CBudgetVote> >::iterator it2 = mapVotes.begin();
while(it2 != mapVotes.end()){
std::map<uint256, CBudgetVote>::iterator it3 = mapVotes[(*it2).first].begin();
while(it3 != mapVotes[(*it2).first].end())
{
2016-04-14 23:28:33 +02:00
if(!(*it3).second.IsValid(true))
2016-04-14 22:01:15 +02:00
{
if((*it3).second.nVoteType == nVoteTypeIn &&
(*it3).second.nVoteOutcome == nVoteOutcomeIn)
nMatching++;
} else {
++it3;
}
}
++it2;
}
return nMatching;
}