added vote types and outcomes

This commit is contained in:
Evan Duffield 2016-04-14 13:01:15 -07:00
parent b5476ca60a
commit 8f0f5343ce
3 changed files with 126 additions and 165 deletions

View File

@ -19,9 +19,18 @@ using namespace std;
class CBudgetVote;
#define VOTE_ABSTAIN 0
#define VOTE_YES 1
#define VOTE_NO 2
#define VOTE_OUTCOME_NONE 0
#define VOTE_OUTCOME_YES 1
#define VOTE_OUTCOME_NO 2
#define VOTE_OUTCOME_ABSTAIN 3
// INTENTION OF MASTERNODES REGARDING ITEM
#define VOTE_TYPE_FUND 0
#define VOTE_TYPE_END 1
#define VOTE_TYPE_VALID 2
#define VOTE_TYPE_MILESTONE1 3
#define VOTE_TYPE_MILESTONE2 4
#define VOTE_TYPE_ENDORSED 5
//
// CBudgetVote - Allow a masternode node to vote and broadcast throughout the network
@ -33,50 +42,35 @@ class CBudgetVote
public:
bool fValid; //if the vote is currently valid / counted
bool fSynced; //if we've sent this to our peers
int nVoteType; //fund, end, invalid, reports
/*
fund=1 = shall we fund this?
url=2= is the url correct?
amount=3 is the amount correct?
expiration is the expiration correct?
address is the address correct?
parent=4 to 10 is variable x correct?
reports=5= Are all reports up to date?
spam=6= Is this spam?
name=7= Is the name correct?
certifications:
business=7 Has it been certified by the business committee? (if exists)
technical=8 Has it been certified by the technical committee?
scientific=9 etc
*/
CTxIn vin;
uint256 nProposalHash;
int nVote;
int nVoteType; // see VOTE_OUTCOMES above
CTxIn vinMasternode;
uint256 nParentHash;
int nVoteOutcome;
int64_t nTime;
std::vector<unsigned char> vchSig;
CBudgetVote();
CBudgetVote(CTxIn vin, uint256 nProposalHash, int nVoteIn);
CBudgetVote(CTxIn vinMasternode, uint256 nParentHash, int nVoteTypeIn, int nVoteOutcomeIn);
bool Sign(CKey& keyMasternode, CPubKey& pubKeyMasternode);
bool IsValid(bool fSignatureCheck);
void Relay();
std::string GetVoteString() {
std::string ret = "ABSTAIN";
if(nVote == VOTE_YES) ret = "YES";
if(nVote == VOTE_NO) ret = "NO";
std::string ret = "ERROR";
if(nVoteOutcome == VOTE_OUTCOME_NONE) ret = "NONE";
else if(nVoteOutcome == VOTE_OUTCOME_ABSTAIN) ret = "ABSTAIN";
else if(nVoteOutcome == VOTE_OUTCOME_YES) ret = "YES";
else if(nVoteOutcome == VOTE_OUTCOME_NO) ret = "NO";
return ret;
}
uint256 GetHash(){
CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
ss << vin;
ss << nProposalHash;
ss << nVote;
ss << vinMasternode;
ss << nParentHash;
ss << nVoteType;
ss << nVoteOutcome;
ss << nTime;
return ss.GetHash();
}
@ -85,9 +79,10 @@ public:
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
READWRITE(vin);
READWRITE(nProposalHash);
READWRITE(nVote);
READWRITE(vinMasternode);
READWRITE(nParentHash);
READWRITE(nVoteOutcome);
READWRITE(nVoteType);
READWRITE(nTime);
READWRITE(vchSig);
}

View File

@ -356,10 +356,10 @@ void CGovernanceManager::ProcessMessage(CNode* pfrom, std::string& strCommand, C
return;
}
CMasternode* pmn = mnodeman.Find(vote.vin);
CMasternode* pmn = mnodeman.Find(vote.vinMasternode);
if(pmn == NULL) {
LogPrint("mnbudget", "mvote - unknown masternode - vin: %s\n", vote.vin.ToString());
mnodeman.AskForMN(pfrom, vote.vin);
LogPrint("mnbudget", "mvote - unknown masternode - vin: %s\n", vote.vinMasternode.ToString());
mnodeman.AskForMN(pfrom, vote.vinMasternode);
return;
}
@ -369,7 +369,7 @@ void CGovernanceManager::ProcessMessage(CNode* pfrom, std::string& strCommand, C
LogPrintf("mvote - signature invalid\n");
if(masternodeSync.IsSynced()) Misbehaving(pfrom->GetId(), 20);
// it could just be a non-synced masternode
mnodeman.AskForMN(pfrom, vote.vin);
mnodeman.AskForMN(pfrom, vote.vinMasternode);
return;
}
@ -463,9 +463,10 @@ void CGovernanceManager::Sync(CNode* pfrom, uint256 nProp)
while(it2 != mapVotes.end()){
std::map<uint256, CBudgetVote>::iterator it3 = mapVotes[(*it2).first].begin();
if((*it3).second.fValid && ((nProp == uint256() || ((*it2).first == nProp))))
pfrom->PushInventory(CInv(MSG_BUDGET_VOTE, (*it3).second.GetHash()));
nInvCount++;
}
{
pfrom->PushInventory(CInv(MSG_BUDGET_VOTE, (*it3).second.GetHash()));
nInvCount++;
}
++it2;
}
@ -478,18 +479,18 @@ bool CGovernanceManager::UpdateProposal(CBudgetVote& vote, CNode* pfrom, std::st
{
LOCK(cs);
if(!mapProposals.count(vote.nProposalHash)){
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;
LogPrintf("CGovernanceManager::UpdateProposal - Unknown proposal %d, asking for source proposal\n", vote.nProposalHash.ToString());
mapOrphanMasternodeBudgetVotes[vote.nProposalHash] = vote;
LogPrintf("CGovernanceManager::UpdateProposal - Unknown proposal %d, asking for source proposal\n", vote.nParentHash.ToString());
mapOrphanMasternodeBudgetVotes[vote.nParentHash] = vote;
if(!askedForSourceProposalOrBudget.count(vote.nProposalHash)){
pfrom->PushMessage(NetMsgType::MNBUDGETVOTESYNC, vote.nProposalHash);
askedForSourceProposalOrBudget[vote.nProposalHash] = GetTime();
if(!askedForSourceProposalOrBudget.count(vote.nParentHash)){
pfrom->PushMessage(NetMsgType::MNBUDGETVOTESYNC, vote.nParentHash);
askedForSourceProposalOrBudget[vote.nParentHash] = GetTime();
}
}
@ -505,26 +506,23 @@ bool CGovernanceManager::AddOrUpdateVote(CBudgetVote& vote, std::string& strErro
{
LOCK(cs);
uint256 hash = vote.vin.prevout.GetHash();
uint256 hash = vote.vinMasternode.prevout.GetHash();
uint256 hash2 = vote.nParentHash;
// todo - need to rewrite
// check for first vote, create structure
// clear out votes if the budgets are invalid
if(mapVotes.count(hash)){
if(mapVotes[hash].nTime > vote.nTime){
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("mnbudget", "CBudgetProposal::AddOrUpdateVote - %s\n", strError);
return false;
}
if(vote.nTime - mapVotes[hash].nTime < BUDGET_VOTE_UPDATE_MIN){
strError = strprintf("time between votes is too soon - %s - %lli", vote.GetHash().ToString(), vote.nTime - mapVotes[hash].nTime);
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("mnbudget", "CBudgetProposal::AddOrUpdateVote - %s\n", strError);
return false;
}
}
mapVotes[hash] = vote;
mapVotes[hash2][hash] = vote;
return true;
}
@ -548,7 +546,6 @@ CBudgetProposal::CBudgetProposal(const CBudgetProposal& other)
nAmount = other.nAmount;
nTime = other.nTime;
nFeeTXHash = other.nFeeTXHash;
mapVotes = other.mapVotes;
fValid = true;
}
@ -662,12 +659,6 @@ bool CBudgetProposal::IsValid(const CBlockIndex* pindex, std::string& strError,
return false;
}
// -- If GetAbsoluteYesCount is more than -10% of the network, flag as invalid
if(GetAbsoluteYesCount() < -(mnodeman.CountEnabled(MIN_BUDGET_PEER_PROTO_VERSION)/10)) {
strError = "Voted Down";
return false;
}
// 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)) {
@ -696,6 +687,15 @@ bool CBudgetProposal::NetworkWillPay()
* if votecount(VOTE_TYPE_FUNDING, "no") > votecount(VOTE_TYPE_FUNDING, "yes") && GetTime() < nStartTime: return false
*/
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;
}
bool CBudgetProposal::IsEstablished() {
@ -703,77 +703,50 @@ bool CBudgetProposal::IsEstablished() {
return (nTime < GetTime() - Params().GetConsensus().nBudgetProposalEstablishingTime);
}
// If masternode voted for a proposal, but is now invalid -- remove the vote
void CBudgetProposal::CleanAndRemove(bool fSignatureCheck)
void CGovernanceManager::CleanAndRemove(bool fSignatureCheck)
{
std::map<uint256, CBudgetVote>::iterator it = mapVotes.begin();
/*
*
* Loop through each item and delete the items that have become invalid
*
*/
while(it != mapVotes.end()) {
(*it).second.fValid = (*it).second.IsValid(fSignatureCheck);
++it;
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;
}
}
double CBudgetProposal::GetRatio()
{
int yeas = 0;
int nays = 0;
std::map<uint256, CBudgetVote>::iterator it = mapVotes.begin();
while(it != mapVotes.end()) {
if ((*it).second.nVote == VOTE_YES) yeas++;
if ((*it).second.nVote == VOTE_NO) nays++;
++it;
}
if(yeas+nays == 0) return 0.0f;
return ((double)(yeas) / (double)(yeas+nays));
}
int CBudgetProposal::GetAbsoluteYesCount()
{
return GetYesCount() - GetNoCount();
return governance.CountMatchingVotes(VOTE_TYPE_FUND, VOTE_OUTCOME_YES) - governance.governance.CountMatchingVotes(VOTE_TYPE_FUND, VOTE_OUTCOME_NO);
}
int CBudgetProposal::GetYesCount()
{
int ret = 0;
std::map<uint256, CBudgetVote>::iterator it = mapVotes.begin();
while(it != mapVotes.end()){
if ((*it).second.nVote == VOTE_YES && (*it).second.fValid) ret++;
++it;
}
return ret;
return governance.CountMatchingVotes(VOTE_TYPE_FUND, VOTE_OUTCOME_YES);
}
int CBudgetProposal::GetNoCount()
{
int ret = 0;
std::map<uint256, CBudgetVote>::iterator it = mapVotes.begin();
while(it != mapVotes.end()){
if ((*it).second.nVote == VOTE_NO && (*it).second.fValid) ret++;
++it;
}
return ret;
return governance.CountMatchingVotes(VOTE_TYPE_FUND, VOTE_OUTCOME_NO);
}
int CBudgetProposal::GetAbstainCount()
{
int ret = 0;
std::map<uint256, CBudgetVote>::iterator it = mapVotes.begin();
while(it != mapVotes.end()){
if ((*it).second.nVote == VOTE_ABSTAIN && (*it).second.fValid) ret++;
++it;
}
return ret;
return governance.CountMatchingVotes(VOTE_TYPE_FUND, VOTE_OUTCOME_ABSTAIN);
}
int CBudgetProposal::GetBlockStartCycle()
@ -792,33 +765,6 @@ int CBudgetProposal::GetBlockCurrentCycle(const CBlockIndex* pindex)
return pindex->nHeight - pindex->nHeight % Params().GetConsensus().nBudgetPaymentsCycleBlocks;
}
int CBudgetProposal::GetBlockEndCycle()
{
//end block is half way through the next cycle (so the proposal will be removed much after the payment is sent)
return nBlockEnd - Params().GetConsensus().nBudgetPaymentsCycleBlocks/2;
}
int CBudgetProposal::GetTotalPaymentCount()
{
return (GetBlockEndCycle() - GetBlockStartCycle()) / Params().GetConsensus().nBudgetPaymentsCycleBlocks;
}
int CBudgetProposal::GetRemainingPaymentCount(int nBlockHeight)
{
int nPayments = 0;
// printf("-> Budget Name : %s\n", strProposalName.c_str());
// printf("------- nBlockStart : %d\n", nBlockStart);
// printf("------- nBlockEnd : %d\n", nBlockEnd);
while(nBlockHeight + Params().GetConsensus().nBudgetPaymentsCycleBlocks < GetBlockEndCycle())
{
// printf("------- P : %d %d - %d < %d - %d\n", nBlockHeight, nPayments, nBlockHeight + Params().GetConsensus().nBudgetPaymentsCycleBlocks, nBlockEnd, nBlockHeight + Params().GetConsensus().nBudgetPaymentsCycleBlocks < nBlockEnd);
nBlockHeight += Params().GetConsensus().nBudgetPaymentsCycleBlocks;
nPayments++;
}
return nPayments;
}
void CBudgetProposal::Relay()
{
CInv inv(MSG_BUDGET_PROPOSAL, GetHash());
@ -885,11 +831,6 @@ std::vector<CBudgetProposal*> CBudgetManager::GetBudget()
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);
@ -919,3 +860,32 @@ std::vector<CBudgetProposal*> CBudgetManager::GetBudget()
return vBudgetProposalsRet;
}
int CBudgetManager::CountMatchingVotes(int nVoteTypeIn, int nVoteOutcomeIn)
{
/*
*
* 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())
{
if(!(*it3).second.IsValid(fSignatureCheck))
{
if((*it3).second.nVoteType == nVoteTypeIn &&
(*it3).second.nVoteOutcome == nVoteOutcomeIn)
nMatching++;
} else {
++it3;
}
}
++it2;
}
return nMatching;
}

View File

@ -103,6 +103,8 @@ public:
bool AddOrUpdateVote(CBudgetVote& vote, std::string& strError);
bool PropExists(uint256 nHash);
std::string GetRequiredPaymentsString(int nBlockHeight);
void CleanAndRemove(bool fSignatureCheck);
int CountMatchingVotes(int nVoteTypeIn, int nVoteOutcomeIn);
void CheckOrphanVotes();
void Clear(){
@ -184,8 +186,8 @@ public:
This allows the proposal website to stay 100% decentralized
*/
std::string strURL;
int nBlockStart; //int nStartTime;
int nBlockEnd; //int nExpirationTime;
int nStartTime;
int nEndTime;
CAmount nAmount; // 12.1 - remove
// int nPriority; //budget is sorted by this integer before funding votecount
// GovernanceObjectPayloadType payloadType;
@ -205,25 +207,19 @@ public:
bool IsValid(const CBlockIndex* pindex, std::string& strError, bool fCheckCollateral=true);
bool IsEstablished();
bool NetworkWillPay();
std::string GetName() {return strProposalName; }
std::string GetURL() {return strURL; }
int GetBlockStart() {return nBlockStart;}
int GetBlockEnd() {return nBlockEnd;}
int GetStartTime() {return nStartTime;}
int GetEndTime() {return nEndTime;}
CScript GetPayee() {return address;}
int GetTotalPaymentCount();
int GetRemainingPaymentCount(int nBlockHeight);
int GetBlockStartCycle();
int GetBlockCurrentCycle(const CBlockIndex* pindex);
int GetBlockEndCycle();
double GetRatio();
int IsActive() {return GetTime() > nStartTime && GetTime() < nEndTime;}
int GetAbsoluteYesCount();
int GetYesCount();
int GetNoCount();
int GetAbstainCount();
CAmount GetAmount() {return nAmount;}
void SetAllotted(CAmount nAllotedIn) {nAlloted = nAllotedIn;}
CAmount GetAllotted() {return nAlloted;}
void CleanAndRemove(bool fSignatureCheck);
@ -231,8 +227,8 @@ public:
CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
ss << strProposalName;
ss << strURL;
ss << nBlockStart;
ss << nBlockEnd;
ss << nStartTime;
ss << nEndTime;
ss << nAmount;
ss << *(CScriptBase*)(&address);
uint256 h1 = ss.GetHash();
@ -249,8 +245,8 @@ public:
READWRITE(LIMITED_STRING(strProposalName, 20));
READWRITE(LIMITED_STRING(strURL, 64));
READWRITE(nTime);
READWRITE(nBlockStart);
READWRITE(nBlockEnd);
READWRITE(nStartTime);
READWRITE(nEndTime);
READWRITE(nAmount);
READWRITE(*(CScriptBase*)(&address));