From 138511f87985d8dfef2666c987f14c7b6db37b16 Mon Sep 17 00:00:00 2001 From: Evan Duffield Date: Sat, 9 Apr 2016 13:55:52 -0700 Subject: [PATCH] splitting progress pt . --- src/governance.cpp | 600 +++----------------------------------- src/governance.h | 6 +- src/masternode-budget.cpp | 393 ++++++++++++++++++++++++- src/masternode-budget.h | 188 +++++++++++- 4 files changed, 614 insertions(+), 573 deletions(-) diff --git a/src/governance.cpp b/src/governance.cpp index 1079d9d93..ce16fe625 100644 --- a/src/governance.cpp +++ b/src/governance.cpp @@ -7,8 +7,9 @@ #include "main.h" #include "init.h" -#include "masternode-budget.h" +#include "governance.h" #include "masternode.h" +#include "masternode-budget.h" #include "darksend.h" #include "masternodeman.h" #include "masternode-sync.h" @@ -17,7 +18,7 @@ #include #include -CBudgetManager budget; +CGovernanceManager governator; CCriticalSection cs_budget; std::map askedForSourceProposalOrBudget; @@ -82,7 +83,7 @@ bool IsBudgetCollateralValid(uint256 nTxCollateralHash, uint256 nExpectedHash, s } } -void CBudgetManager::CheckOrphanVotes() +void CGovernanceManager::CheckOrphanVotes() { LOCK(cs); @@ -90,8 +91,8 @@ void CBudgetManager::CheckOrphanVotes() std::string strError = ""; std::map::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"); + if(UpdateProposal(((*it1).second), NULL, strError)){ + LogPrintf("CGovernanceManager::CheckOrphanVotes - Proposal/Budget is known, activating and removing orphan vote\n"); mapOrphanMasternodeBudgetVotes.erase(it1++); } else { ++it1; @@ -109,7 +110,7 @@ CBudgetDB::CBudgetDB() strMagicMessage = "MasternodeBudget"; } -bool CBudgetDB::Write(const CBudgetManager& objToSave) +bool CBudgetDB::Write(const CGovernanceManager& objToSave) { LOCK(objToSave.cs); @@ -144,7 +145,7 @@ bool CBudgetDB::Write(const CBudgetManager& objToSave) return true; } -CBudgetDB::ReadResult CBudgetDB::Read(CBudgetManager& objToLoad, bool fDryRun) +CBudgetDB::ReadResult CBudgetDB::Read(CGovernanceManager& objToLoad, bool fDryRun) { //LOCK(objToLoad.cs); @@ -214,7 +215,7 @@ CBudgetDB::ReadResult CBudgetDB::Read(CBudgetManager& objToLoad, bool fDryRun) return IncorrectMagicNumber; } - // de-serialize data into CBudgetManager object + // de-serialize data into CGovernanceManager object ssObj >> objToLoad; } catch (std::exception &e) { @@ -238,11 +239,11 @@ void DumpBudgets() { int64_t nStart = GetTimeMillis(); - CBudgetDB budgetdb; - CBudgetManager tempBudget; + CBudgetDB govdb; + CGovernanceManager tempBudget; LogPrintf("Verifying budget.dat format...\n"); - CBudgetDB::ReadResult readResult = budgetdb.Read(tempBudget, true); + CBudgetDB::ReadResult readResult = govdb.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"); @@ -258,17 +259,17 @@ void DumpBudgets() } } LogPrintf("Writting info to budget.dat...\n"); - budgetdb.Write(budget); + govdb.Write(governator); LogPrintf("Budget dump finished %dms\n", GetTimeMillis() - nStart); } -bool CBudgetManager::AddProposal(CBudgetProposal& budgetProposal) +bool CGovernanceManager::AddProposal(CBudgetProposal& budgetProposal) { LOCK(cs); std::string strError = ""; if(!budgetProposal.IsValid(pCurrentBlockIndex, strError)) { - LogPrintf("CBudgetManager::AddProposal - invalid budget proposal - %s\n", strError); + LogPrintf("CGovernanceManager::AddProposal - invalid budget proposal - %s\n", strError); return false; } @@ -280,12 +281,14 @@ bool CBudgetManager::AddProposal(CBudgetProposal& budgetProposal) return true; } -void CBudgetManager::CheckAndRemove() +void CGovernanceManager::CheckAndRemove() { - LogPrintf("CBudgetManager::CheckAndRemove \n"); + LogPrintf("CGovernanceManager::CheckAndRemove \n"); if(!pCurrentBlockIndex) return; + std::string strError = ""; + std::map::iterator it2 = mapProposals.begin(); while(it2 != mapProposals.end()) { @@ -295,7 +298,7 @@ void CBudgetManager::CheckAndRemove() } } -CBudgetProposal *CBudgetManager::FindProposal(const std::string &strProposalName) +CBudgetProposal *CGovernanceManager::FindProposal(const std::string &strProposalName) { //find the prop with the highest yes count @@ -316,7 +319,7 @@ CBudgetProposal *CBudgetManager::FindProposal(const std::string &strProposalName return pbudgetProposal; } -CBudgetProposal *CBudgetManager::FindProposal(uint256 nHash) +CBudgetProposal *CGovernanceManager::FindProposal(uint256 nHash) { LOCK(cs); @@ -326,56 +329,7 @@ CBudgetProposal *CBudgetManager::FindProposal(uint256 nHash) return NULL; } -bool CBudgetManager::IsTransactionValid(const CTransaction& txNew, int nBlockHeight) -{ - LOCK(cs); - - int nHighestCount = 0; - std::vector ret; - - // ------- Grab The Highest Count - - std::map::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 CBudgetManager::GetAllProposals() +std::vector CGovernanceManager::GetAllProposals() { LOCK(cs); @@ -406,84 +360,7 @@ struct sortProposalsByVotes { } }; -//Need to review this function -std::vector CBudgetManager::GetBudget() -{ - LOCK(cs); - - // ------- Sort budgets by Yes Count - - std::vector > vBudgetPorposalsSort; - - std::map::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 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 >::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 &left, const std::pair &right) { - return left.second > right.second; - } -}; - -void CBudgetManager::NewBlock() +void CGovernanceManager::NewBlock() { TRY_LOCK(cs, fBudgetNewBlock); if(!fBudgetNewBlock) return; @@ -498,7 +375,7 @@ void CBudgetManager::NewBlock() // incremental sync with our peers if(masternodeSync.IsSynced()){ - LogPrintf("CBudgetManager::NewBlock - incremental sync started\n"); + LogPrintf("CGovernanceManager::NewBlock - incremental sync started\n"); if(pCurrentBlockIndex->nHeight % 600 == rand() % 600) { ClearSeen(); ResetSync(); @@ -556,7 +433,7 @@ void CBudgetManager::NewBlock() } -void CBudgetManager::ProcessMessage(CNode* pfrom, std::string& strCommand, CDataStream& vRecv) +void CGovernanceManager::ProcessMessage(CNode* pfrom, std::string& strCommand, CDataStream& vRecv) { // lite mode is not supported if(fLiteMode) return; @@ -656,52 +533,17 @@ void CBudgetManager::ProcessMessage(CNode* pfrom, std::string& strCommand, CData 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) +bool CGovernanceManager::PropExists(uint256 nHash) { if(mapProposals.count(nHash)) return true; return false; } //mark that a full sync is needed -void CBudgetManager::ResetSync() +void CGovernanceManager::ResetSync() { LOCK(cs); @@ -722,7 +564,7 @@ void CBudgetManager::ResetSync() } } -void CBudgetManager::MarkSynced() +void CGovernanceManager::MarkSynced() { LOCK(cs); @@ -748,7 +590,7 @@ void CBudgetManager::MarkSynced() } -void CBudgetManager::Sync(CNode* pfrom, uint256 nProp, bool fPartial) +void CGovernanceManager::Sync(CNode* pfrom, uint256 nProp, bool fPartial) { LOCK(cs); @@ -792,10 +634,10 @@ void CBudgetManager::Sync(CNode* pfrom, uint256 nProp, bool fPartial) pfrom->PushMessage(NetMsgType::SYNCSTATUSCOUNT, MASTERNODE_SYNC_BUDGET_PROP, nInvCount); - LogPrintf("CBudgetManager::Sync - sent %d items\n", nInvCount); + LogPrintf("CGovernanceManager::Sync - sent %d items\n", nInvCount); } -bool CBudgetManager::UpdateProposal(CBudgetVote& vote, CNode* pfrom, std::string& strError) +bool CGovernanceManager::UpdateProposal(CBudgetVote& vote, CNode* pfrom, std::string& strError) { LOCK(cs); @@ -805,7 +647,7 @@ bool CBudgetManager::UpdateProposal(CBudgetVote& vote, CNode* pfrom, std::string // 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()); + LogPrintf("CGovernanceManager::UpdateProposal - Unknown proposal %d, asking for source proposal\n", vote.nProposalHash.ToString()); mapOrphanMasternodeBudgetVotes[vote.nProposalHash] = vote; if(!askedForSourceProposalOrBudget.count(vote.nProposalHash)){ @@ -947,6 +789,7 @@ bool CBudgetProposal::IsValid(const CBlockIndex* pindex, std::string& strError, return false; } + // todo 12.1 - setup a hard limit via spork or something? Maybe up to 1/4 of the total budget? //can only pay out 10% of the possible coins (min value of coins) if(nAmount > budget.GetTotalBudget(nBlockStart)) { strError = "Payment more than max"; @@ -1185,380 +1028,7 @@ bool CBudgetVote::IsValid(bool fSignatureCheck) 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 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::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 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(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(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::string CGovernanceManager::ToString() const { std::ostringstream info; @@ -1569,7 +1039,7 @@ std::string CBudgetManager::ToString() const return info.str(); } -void CBudgetManager::UpdatedBlockTip(const CBlockIndex *pindex) +void CGovernanceManager::UpdatedBlockTip(const CBlockIndex *pindex) { pCurrentBlockIndex = pindex; LogPrint("mnbudget", "pCurrentBlockIndex->nHeight: %d\n", pCurrentBlockIndex->nHeight); diff --git a/src/governance.h b/src/governance.h index c0822306c..2a464d783 100644 --- a/src/governance.h +++ b/src/governance.h @@ -34,11 +34,8 @@ static const int64_t BUDGET_FEE_CONFIRMATIONS = 6; static const int64_t BUDGET_VOTE_UPDATE_MIN = 60*60; extern std::vector vecImmatureBudgetProposals; -extern std::vector vecImmatureFinalizedBudgets; -//# ---- -// todo - 12.1 - change budget to govman -extern CGovernanceManager budget; +extern CGovernanceManager governator; void DumpBudgets(); //Check the collateral transaction for the budget proposal/finalized budget @@ -70,6 +67,7 @@ public: ReadResult Read(CGovernanceManager& objToLoad, bool fDryRun = false); }; +//# ---- // // Governance Manager : Contains all proposals for the budget diff --git a/src/masternode-budget.cpp b/src/masternode-budget.cpp index 3fc9b972d..0f52961b2 100644 --- a/src/masternode-budget.cpp +++ b/src/masternode-budget.cpp @@ -1,6 +1,12 @@ #include "src/masternode-budget.h" +struct sortFinalizedBudgetsByVotes { + bool operator()(const std::pair &left, const std::pair &right) { + return left.second > right.second; + } +}; + void CBudgetManager::MarkSynced() { LOCK(cs); @@ -437,7 +443,7 @@ void CBudgetManager::SubmitFinalBudget() LOCK(cs); mapSeenFinalizedBudgets.insert(make_pair(finalizedBudgetBroadcast.GetHash(), finalizedBudgetBroadcast)); finalizedBudgetBroadcast.Relay(); - budget.AddFinalizedBudget(finalizedBudgetBroadcast); + AddFinalizedBudget(finalizedBudgetBroadcast); } bool CBudgetManager::HasNextFinalizedBudget() @@ -449,7 +455,7 @@ bool CBudgetManager::HasNextFinalizedBudget() int nBlockStart = pCurrentBlockIndex->nHeight - pCurrentBlockIndex->nHeight % Params().GetConsensus().nBudgetPaymentsCycleBlocks + Params().GetConsensus().nBudgetPaymentsCycleBlocks; if(nBlockStart - pCurrentBlockIndex->nHeight > 576*2) return true; //we wouldn't have the budget yet - if(budget.IsBudgetPaymentBlock(nBlockStart)) return true; + if(IsBudgetPaymentBlock(nBlockStart)) return true; LogPrintf("CBudgetManager::HasNextFinalizedBudget() - Client is missing budget - %lli\n", nBlockStart); @@ -616,7 +622,7 @@ void CBudgetManager::CheckOrphanVotes() std::map::iterator it2 = mapOrphanFinalizedBudgetVotes.begin(); while(it2 != mapOrphanFinalizedBudgetVotes.end()){ - if(budget.UpdateFinalizedBudget(((*it2).second),NULL, strError)){ + if(UpdateFinalizedBudget(((*it2).second),NULL, strError)){ LogPrintf("CBudgetManager::CheckOrphanVotes - Proposal/Budget is known, activating and removing orphan vote\n"); mapOrphanFinalizedBudgetVotes.erase(it2++); } else { @@ -674,3 +680,384 @@ void CBudgetManager::UpdatedBlockTip(const CBlockIndex *pindex) NewBlock(); } +/* + * Class : CFinalizedBudget + * -------------------- + * Holds a proposed finalized budget + * +*/ + +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 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::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 = 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 = 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() > 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(UpdateFinalizedBudget(vote, NULL, strError)){ + LogPrintf("CFinalizedBudget::SubmitVote - new finalized budget vote - %s\n", vote.GetHash().ToString()); + + 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 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(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(nTime); + + if(!darkSendSigner.VerifyMessage(pmn->pubkey2, vchSig, strMessage, errorMessage)) { + LogPrintf("CFinalizedBudgetVote::IsValid() - Verify message failed\n"); + return false; + } + + return true; +} + diff --git a/src/masternode-budget.h b/src/masternode-budget.h index 2b63bc240..c08a66d04 100644 --- a/src/masternode-budget.h +++ b/src/masternode-budget.h @@ -181,4 +181,190 @@ public: READWRITE(nAmount); READWRITE(nProposalHash); } -}; \ No newline at end of file +}; + + +// +// Finalized Budget : Contains the suggested proposals to pay on a given block +// + +class CFinalizedBudget +{ + +private: + // critical section to protect the inner data structures + mutable CCriticalSection cs; + bool fAutoChecked; //If it matches what we see, we'll auto vote for it (masternode only) + +public: + bool fValid; + std::string strBudgetName; + int nBlockStart; + std::vector vecBudgetPayments; + map mapVotes; + uint256 nFeeTXHash; + int64_t nTime; + + CFinalizedBudget(); + CFinalizedBudget(const CFinalizedBudget& other); + + void CleanAndRemove(bool fSignatureCheck); + bool AddOrUpdateVote(CFinalizedBudgetVote& vote, std::string& strError); + double GetScore(); + bool HasMinimumRequiredSupport(); + + bool IsValid(std::string& strError, bool fCheckCollateral=true); + + std::string GetName() {return strBudgetName; } + std::string GetProposals(); + int GetBlockStart() {return nBlockStart;} + int GetBlockEnd() {return nBlockStart + (int)(vecBudgetPayments.size() - 1);} + int GetVoteCount() {return (int)mapVotes.size();} + bool IsTransactionValid(const CTransaction& txNew, int nBlockHeight); + bool GetBudgetPaymentByBlock(int64_t nBlockHeight, CTxBudgetPayment& payment) + { + LOCK(cs); + + int i = nBlockHeight - GetBlockStart(); + if(i < 0) return false; + if(i > (int)vecBudgetPayments.size() - 1) return false; + payment = vecBudgetPayments[i]; + return true; + } + bool GetPayeeAndAmount(int64_t nBlockHeight, CScript& payee, CAmount& nAmount) + { + LOCK(cs); + + int i = nBlockHeight - GetBlockStart(); + if(i < 0) return false; + if(i > (int)vecBudgetPayments.size() - 1) return false; + payee = vecBudgetPayments[i].payee; + nAmount = vecBudgetPayments[i].nAmount; + return true; + } + + //check to see if we should vote on this + void AutoCheck(); + //total dash paid out by this budget + CAmount GetTotalPayout(); + //vote on this finalized budget as a masternode + void SubmitVote(); + + //checks the hashes to make sure we know about them + string GetStatus(); + + uint256 GetHash(){ + CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION); + ss << strBudgetName; + ss << nBlockStart; + ss << vecBudgetPayments; + + uint256 h1 = ss.GetHash(); + return h1; + } + + ADD_SERIALIZE_METHODS; + + //for saving to the serialized db + template + inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + READWRITE(LIMITED_STRING(strBudgetName, 20)); + READWRITE(nFeeTXHash); + READWRITE(nTime); + READWRITE(nBlockStart); + READWRITE(vecBudgetPayments); + READWRITE(fAutoChecked); + + READWRITE(mapVotes); + } +}; + +// FinalizedBudget are cast then sent to peers with this object, which leaves the votes out +class CFinalizedBudgetBroadcast : public CFinalizedBudget +{ +private: + std::vector vchSig; + +public: + CFinalizedBudgetBroadcast(); + CFinalizedBudgetBroadcast(const CFinalizedBudget& other); + CFinalizedBudgetBroadcast(std::string strBudgetNameIn, int nBlockStartIn, std::vector vecBudgetPaymentsIn, uint256 nFeeTXHashIn); + + void swap(CFinalizedBudgetBroadcast& first, CFinalizedBudgetBroadcast& second) // nothrow + { + // enable ADL (not necessary in our case, but good practice) + using std::swap; + + // by swapping the members of two classes, + // the two classes are effectively swapped + swap(first.strBudgetName, second.strBudgetName); + swap(first.nBlockStart, second.nBlockStart); + first.mapVotes.swap(second.mapVotes); + first.vecBudgetPayments.swap(second.vecBudgetPayments); + swap(first.nFeeTXHash, second.nFeeTXHash); + swap(first.nTime, second.nTime); + } + + CFinalizedBudgetBroadcast& operator=(CFinalizedBudgetBroadcast from) + { + swap(*this, from); + return *this; + } + + void Relay(); + + ADD_SERIALIZE_METHODS; + + //for propagating messages + template + inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + //for syncing with other clients + READWRITE(LIMITED_STRING(strBudgetName, 20)); + READWRITE(nBlockStart); + READWRITE(vecBudgetPayments); + READWRITE(nFeeTXHash); + } +}; + +// +// CFinalizedBudgetVote - Allow a masternode node to vote and broadcast throughout the network +// + +class CFinalizedBudgetVote +{ +public: + bool fValid; //if the vote is currently valid / counted + bool fSynced; //if we've sent this to our peers + CTxIn vin; + uint256 nBudgetHash; + int64_t nTime; + std::vector vchSig; + + CFinalizedBudgetVote(); + CFinalizedBudgetVote(CTxIn vinIn, uint256 nBudgetHashIn); + + bool Sign(CKey& keyMasternode, CPubKey& pubKeyMasternode); + bool SignatureValid(bool fSignatureCheck); + void Relay(); + + uint256 GetHash(){ + CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION); + ss << vin; + ss << nBudgetHash; + ss << nTime; + return ss.GetHash(); + } + + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + READWRITE(vin); + READWRITE(nBudgetHash); + READWRITE(nTime); + READWRITE(vchSig); + } + +}; + +#endif \ No newline at end of file