Commit 4a1a7992 authored by Evan Duffield's avatar Evan Duffield
Browse files

Finalized Budget Voting and Payment

- Added strBudgetMode with modes of "auto", "output-vin" and "suggest". Auto votes for what the masternode sees as the most popular proposals, output-vin is a delegation mode to another party and "suggest" sends a message to the network, suggesting the most popular proposals
parent 8247d6de
Showing with 186 additions and 10 deletions
+186 -10
......@@ -408,6 +408,7 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += " -masternodeprivkey=<n> " + _("Set the masternode private key") + "\n";
strUsage += " -masternodeaddr=<n> " + _("Set external address:port to get to this masternode (example: address:port)") + "\n";
strUsage += " -masternodeminprotocol=<n> " + strprintf(_("Ignore masternodes less than version (example: 70050; default: %u)"), MIN_POOL_PEER_PROTO_VERSION) + "\n";
strUsage += " -budgetvotemode=<mode> " + _("Change automatic finalized budget voting behavior. mode=auto: Vote for only exact finalized budget match to my generated budget. (string, default: auto)") + "\n";
strUsage += "\n" + _("Darksend options:") + "\n";
strUsage += " -enabledarksend=<n> " + strprintf(_("Enable use of automated darksend for funds stored in this wallet (0-1, default: %u)"), 0) + "\n";
......@@ -1443,6 +1444,9 @@ bool AppInit2(boost::thread_group& threadGroup)
}
}
//get the mode of budget voting for this masternode
strBudgetMode = GetArg("-budgetvotemode", "auto");
strMasterNodePrivKey = GetArg("-masternodeprivkey", "");
if(!strMasterNodePrivKey.empty()){
std::string errorMessage;
......@@ -1498,6 +1502,7 @@ bool AppInit2(boost::thread_group& threadGroup)
LogPrintf("nInstantXDepth %d\n", nInstantXDepth);
LogPrintf("Darksend rounds %d\n", nDarksendRounds);
LogPrintf("Anonymize Dash Amount %d\n", nAnonymizeDarkcoinAmount);
LogPrintf("Budget Mode %s\n", strBudgetMode.c_str());
/* Denominations
......
......@@ -18,6 +18,7 @@ std::map<uint256, CBudgetProposalBroadcast> mapSeenMasternodeBudgetProposals;
std::map<uint256, CBudgetVote> mapSeenMasternodeBudgetVotes;
std::map<uint256, CFinalizedBudgetBroadcast> mapSeenFinalizedBudgets;
std::map<uint256, CFinalizedBudgetVote> mapSeenFinalizedBudgetVotes;
int nSubmittedFinalBudget;
int GetBudgetPaymentCycleBlocks(){
if(Params().NetworkID() == CBaseChainParams::MAIN) return 16616; //(60*24*30)/2.6
......@@ -292,6 +293,8 @@ bool CBudgetProposal::IsValid()
CBlockIndex* pindexPrev = chainActive.Tip();
if(pindexPrev == NULL) return false;
//TODO: if < 20 votes and 2+ weeks old, invalid
if(pindexPrev->nHeight - nBlockStart < 0) return false;
if(pindexPrev->nHeight > nBlockEnd) return false;
......@@ -622,10 +625,15 @@ void CBudgetProposal::AddOrUpdateVote(CBudgetVote& vote)
void CBudgetManager::NewBlock()
{
//this function should be called 1/6 blocks, allowing up to 100 votes per day on all proposals
if(chainActive.Height() % 6 != 0) return;
budget.CheckAndRemove();
mnodeman.DecrementVotedTimes();
if (strBudgetMode == "suggest") { //suggest the budget we see
SubmitFinalBudget();
}
//this function should be called 1/6 blocks, allowing up to 100 votes per day on all proposals
if(chainActive.Height() % 6 != 0) return;
mnodeman.DecrementVotedTimes();
}
double CBudgetProposal::GetRatio()
......@@ -1043,6 +1051,8 @@ bool CFinalizedBudget::IsValid()
if(GetBlockEnd() - nBlockStart > 100) return false;
if(vecProposals.size() > 100) return false;
//TODO: if N cycles old, invalid, invalid
return true;
}
......@@ -1249,4 +1259,157 @@ std::string CBudgetManager::GetRequiredPaymentsString(int64_t nBlockHeight)
}
return ret;
}
\ No newline at end of file
}
void CBudgetManager::CheckAndRemove()
{
std::map<uint256, CFinalizedBudget>::iterator it = mapFinalizedBudgets.begin();
while(it != mapFinalizedBudgets.end())
{
CFinalizedBudget* prop = &((*it).second);
if(!prop->IsValid()){
mapFinalizedBudgets.erase(it);
} else {
prop->AutoCheck();
it++;
}
}
std::map<uint256, CBudgetProposal>::iterator it2 = mapProposals.begin();
while(it2 != mapProposals.end())
{
CBudgetProposal* prop = &((*it2).second);
if(!prop->IsValid()){
mapProposals.erase(it2);
} else {
it2++;
}
}
}
//evaluate if we should vote for this. Masternode only
void CFinalizedBudget::AutoCheck()
{
if(!fMasterNode || fAutoChecked) return;
if(Params().NetworkID() == CBaseChainParams::MAIN){
if(rand() % 100 > 5) return; //do this 1 in 20 blocks -- spread out the voting activity on mainnet
}
fAutoChecked = true; //we only need to check this once
if(strBudgetMode == "auto") //only vote for exact matches
{
std::vector<CBudgetProposal*> props1 = budget.GetBudget();
for(unsigned int i = 0; i < vecProposals.size(); i++){
if(i > props1.size()-1) {
LogPrintf("CFinalizedBudget::AutoCheck - Vector size mismatch, aborting\n");
return;
}
if(vecProposals[i].nProposalHash != props1[i]->GetHash()){
LogPrintf("CFinalizedBudget::AutoCheck - item #%d doesn't match %s %s\n", i, vecProposals[i].nProposalHash.ToString().c_str(), props1[i]->GetHash().ToString().c_str());
return;
}
if(vecProposals[i].payee != props1[i]->GetPayee()){
LogPrintf("CFinalizedBudget::AutoCheck - item #%d payee doesn't match %s %s\n", i, vecProposals[i].payee.ToString().c_str(), props1[i]->GetPayee().ToString().c_str());
return;
}
if(vecProposals[i].nAmount != props1[i]->GetAmount()){
LogPrintf("CFinalizedBudget::AutoCheck - item #%d payee doesn't match %s %s\n", i, vecProposals[i].payee.ToString().c_str(), props1[i]->GetPayee().ToString().c_str());
return;
}
LogPrintf("CFinalizedBudget::AutoCheck - Finalized Budget Matches! Submitting Vote.\n");
SubmitVote();
}
}
// Feature : Masternodes can delegate finalized budgets to a 3rd party simply by adding this option to the configuration
else if (strBudgetMode == vin.prevout.ToStringShort())
{
SubmitVote();
}
}
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;
}
mapSeenFinalizedBudgetVotes.insert(make_pair(vote.GetHash(), vote));
vote.Relay();
budget.UpdateFinalizedBudget(vote);
}
void SubmitFinalBudget()
{
CBlockIndex* pindexPrev = chainActive.Tip();
if(!pindexPrev) return;
int nBlockStart = pindexPrev->nHeight-(pindexPrev->nHeight % GetBudgetPaymentCycleBlocks())+GetBudgetPaymentCycleBlocks();
if(nSubmittedFinalBudget >= nBlockStart) return;
if(nBlockStart - pindexPrev->nHeight > 100) return;
std::vector<CBudgetProposal*> props1 = budget.GetBudget();
std::string strBudgetName = "main";
std::vector<CTxBudgetPayment> vecPayments;
for(unsigned int i = 0; i < props1.size(); i++){
CTxBudgetPayment out;
out.nProposalHash = props1[i]->GetHash();
out.payee = props1[i]->GetPayee();
out.nAmount = props1[i]->GetAmount();
vecPayments.push_back(out);
}
if(vecPayments.size() < 1) return;
nSubmittedFinalBudget = nBlockStart;
CPubKey pubKeyMasternode;
CKey keyMasternode;
std::string errorMessage;
if(!darkSendSigner.SetKey(strMasterNodePrivKey, errorMessage, keyMasternode, pubKeyMasternode)){
LogPrintf("SubmitFinalBudget - Error upon calling SetKey");
}
//create the proposal incase we're the first to make it
CFinalizedBudgetBroadcast prop(activeMasternode.vin, strBudgetName, nBlockStart, vecPayments);
if(!prop.Sign(keyMasternode, pubKeyMasternode)){
LogPrintf("SubmitFinalBudget - Failure to sign.");
}
if(!prop.IsValid()){
LogPrintf("SubmitFinalBudget - Invalid prop (are all the hashes correct?)");
}
mapSeenFinalizedBudgets.insert(make_pair(prop.GetHash(), prop));
prop.Relay();
budget.AddFinalizedBudget(prop);
CFinalizedBudgetVote vote(activeMasternode.vin, prop.GetHash());
if(!vote.Sign(keyMasternode, pubKeyMasternode)){
LogPrintf("SubmitFinalBudget - Failure to sign.");
}
mapSeenFinalizedBudgetVotes.insert(make_pair(vote.GetHash(), vote));
vote.Relay();
budget.UpdateFinalizedBudget(vote);
}
......@@ -42,6 +42,7 @@ void GetMasternodeBudgetEscrow(CScript& payee);
//Amount of blocks in a months period of time (using 2.6 minutes per)
int GetBudgetPaymentCycleBlocks();
void SubmitFinalBudget();
/** Save Budget Manager (budget.dat)
*/
......@@ -113,12 +114,11 @@ public:
void FillBlockPayee(CMutableTransaction& txNew, int64_t nFees);
void Clear(){
printf("Not implemented\n");
}
void CheckAndRemove(){
printf("Not implemented\n");
//replace cleanup
LogPrintf("Budget object cleared\n");
mapProposals.clear();
mapFinalizedBudgets.clear();
}
void CheckAndRemove();
std::string ToString() {return "not implemented";}
......@@ -171,10 +171,11 @@ 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:
CTxIn vin;
std::string strBudgetName;
CTxIn vin;
int nBlockStart;
std::vector<CTxBudgetPayment> vecProposals;
map<uint256, CFinalizedBudgetVote> mapVotes;
......@@ -216,6 +217,11 @@ public:
return true;
}
//check to see if we should vote on this
void AutoCheck();
//vote on this finalized budget as a masternode
void SubmitVote();
//checks the hashes to make sure we know about them
string GetStatus();
......
......@@ -118,6 +118,7 @@ bool fSucessfullyLoaded = false;
bool fEnableDarksend = false;
/** All denominations used by darksend */
std::vector<int64_t> darkSendDenominations;
string strBudgetMode = "";
map<string, string> mapArgs;
map<string, vector<string> > mapMultiArgs;
......
......@@ -43,6 +43,7 @@ extern int nMasternodeMinProtocol;
extern int keysLoaded;
extern bool fSucessfullyLoaded;
extern std::vector<int64_t> darkSendDenominations;
extern std::string strBudgetMode;
extern std::map<std::string, std::string> mapArgs;
extern std::map<std::string, std::vector<std::string> > mapMultiArgs;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment