Reference Node / Stubbed Out Budget System
- Removed of reference node and replaced with decentralized quorums that pick the masternodes who get paid each block. - Made a budgeting system, where masternodes can vote on individual budgets and the data is stored perminently on each clients computer
This commit is contained in:
parent
854a1be027
commit
969826c249
@ -399,7 +399,8 @@ SOURCES += src/activemasternode.cpp \
|
||||
src/rest.cpp \
|
||||
src/rpcblockchain.cpp \
|
||||
src/rpcclient.cpp \
|
||||
src/rpcdarksend.cpp \
|
||||
src/rpcmasternode.cpp \
|
||||
src/rpcmasternode-budget.cpp \
|
||||
src/rpcdump.cpp \
|
||||
src/rpcmining.cpp \
|
||||
src/rpcmisc.cpp \
|
||||
|
@ -109,6 +109,7 @@ BITCOIN_CORE_H = \
|
||||
masternode.h \
|
||||
masternode-payments.h \
|
||||
masternode-pos.h \
|
||||
masternode-budget.h \
|
||||
masternodeman.h \
|
||||
masternodeconfig.h \
|
||||
merkleblock.h \
|
||||
@ -188,7 +189,8 @@ libbitcoin_server_a_SOURCES = \
|
||||
pow.cpp \
|
||||
rest.cpp \
|
||||
rpcblockchain.cpp \
|
||||
rpcdarksend.cpp \
|
||||
rpcmasternode.cpp \
|
||||
rpcmasternode-budget.cpp \
|
||||
rpcmining.cpp \
|
||||
rpcmisc.cpp \
|
||||
rpcnet.cpp \
|
||||
@ -279,6 +281,7 @@ libbitcoin_common_a_SOURCES = \
|
||||
darksend.cpp \
|
||||
darksend-relay.cpp \
|
||||
masternode.cpp \
|
||||
masternode-budget.cpp \
|
||||
masternode-payments.cpp \
|
||||
masternode-pos.cpp \
|
||||
masternodeman.cpp \
|
||||
|
@ -2276,6 +2276,7 @@ void ThreadCheckDarkSendPool()
|
||||
mnodeman.DsegUpdate(pnode);
|
||||
|
||||
pnode->PushMessage("mnget"); //sync payees
|
||||
pnode->PushMessage("mnvs"); //sync masternode votes
|
||||
pnode->PushMessage("getsporks"); //get current network sporks
|
||||
RequestedMasterNodeList++;
|
||||
}
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "ui_interface.h"
|
||||
#include "util.h"
|
||||
#include "activemasternode.h"
|
||||
#include "masternode-budget.h"
|
||||
#include "masternode-payments.h"
|
||||
#include "masternodeman.h"
|
||||
#include "spork.h"
|
||||
@ -164,6 +165,7 @@ void Shutdown()
|
||||
#endif
|
||||
StopNode();
|
||||
DumpMasternodes();
|
||||
DumpBudgets();
|
||||
UnregisterNodeSignals(GetNodeSignals());
|
||||
|
||||
if (fFeeEstimatesInitialized)
|
||||
@ -826,11 +828,9 @@ bool AppInit2(boost::thread_group& threadGroup)
|
||||
threadGroup.create_thread(&ThreadScriptCheck);
|
||||
}
|
||||
|
||||
if (mapArgs.count("-masternodepaymentskey")) // masternode payments priv key
|
||||
if (mapArgs.count("-sporkkey")) // spork priv key
|
||||
{
|
||||
if (!masternodePayments.SetPrivKey(GetArg("-masternodepaymentskey", "")))
|
||||
return InitError(_("Unable to sign masternode payment winner, wrong key?"));
|
||||
if (!sporkManager.SetPrivKey(GetArg("-masternodepaymentskey", "")))
|
||||
if (!sporkManager.SetPrivKey(GetArg("-sporkkey", "")))
|
||||
return InitError(_("Unable to sign spork message, wrong key?"));
|
||||
}
|
||||
|
||||
|
111
src/main.cpp
111
src/main.cpp
@ -16,6 +16,7 @@
|
||||
#include "darksend.h"
|
||||
#include "masternodeman.h"
|
||||
#include "masternode-payments.h"
|
||||
#include "masternode-budget.h"
|
||||
#include "merkleblock.h"
|
||||
#include "net.h"
|
||||
#include "pow.h"
|
||||
@ -1567,10 +1568,6 @@ int64_t GetMasternodePayment(int nHeight, int64_t blockValue)
|
||||
if(nHeight > 158000+((576*30)* 6)) ret += blockValue / 40; // 261680 - 45.0% - 2015-05-01
|
||||
if(nHeight > 158000+((576*30)* 7)) ret += blockValue / 40; // 278960 - 47.5% - 2015-06-01
|
||||
if(nHeight > 158000+((576*30)* 9)) ret += blockValue / 40; // 313520 - 50.0% - 2015-08-03
|
||||
if(nHeight > 158000+((576*30)*11)) ret += blockValue / 40; // 348080 - 52.5% - 2015-10-05
|
||||
if(nHeight > 158000+((576*30)*13)) ret += blockValue / 40; // 382640 - 55.0% - 2015-12-07
|
||||
if(nHeight > 158000+((576*30)*15)) ret += blockValue / 40; // 417200 - 57.5% - 2016-02-08
|
||||
if(nHeight > 158000+((576*30)*17)) ret += blockValue / 40; // 451760 - 60.0% - 2016-04-11
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -2928,72 +2925,17 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo
|
||||
|
||||
// ----------- masternode payments -----------
|
||||
|
||||
bool MasternodePayments = block.nTime > Params().StartMasternodePayments();
|
||||
|
||||
if(!IsSporkActive(SPORK_1_MASTERNODE_PAYMENTS_ENFORCEMENT)){
|
||||
MasternodePayments = false;
|
||||
if(fDebug) LogPrintf("CheckBlock() : Masternode payment enforcement is off\n");
|
||||
}
|
||||
|
||||
if(MasternodePayments)
|
||||
CBlockIndex* pindexPrev = chainActive.Tip();
|
||||
if(pindexPrev != NULL)
|
||||
{
|
||||
LOCK2(cs_main, mempool.cs);
|
||||
|
||||
CBlockIndex *pindex = chainActive.Tip();
|
||||
if(pindex != NULL){
|
||||
if(pindex->GetBlockHash() == block.hashPrevBlock){
|
||||
int64_t masternodePaymentAmount = GetMasternodePayment(pindex->nHeight+1, block.vtx[0].GetValueOut());
|
||||
bool fIsInitialDownload = IsInitialBlockDownload();
|
||||
|
||||
// If we don't already have its previous block, skip masternode payment step
|
||||
if (!fIsInitialDownload && pindex != NULL)
|
||||
{
|
||||
bool foundPaymentAmount = false;
|
||||
bool foundPayee = false;
|
||||
bool foundPaymentAndPayee = false;
|
||||
|
||||
CScript payee;
|
||||
CTxIn vin;
|
||||
if(!masternodePayments.GetBlockPayee(chainActive.Tip()->nHeight+1, payee, vin) || payee == CScript()){
|
||||
foundPayee = true; //doesn't require a specific payee
|
||||
foundPaymentAmount = true;
|
||||
foundPaymentAndPayee = true;
|
||||
LogPrintf("CheckBlock() : Using non-specific masternode payments %d\n", chainActive.Tip()->nHeight+1);
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < block.vtx[0].vout.size(); i++) {
|
||||
if(block.vtx[0].vout[i].nValue == masternodePaymentAmount )
|
||||
foundPaymentAmount = true;
|
||||
if(block.vtx[0].vout[i].scriptPubKey == payee )
|
||||
foundPayee = true;
|
||||
if(block.vtx[0].vout[i].nValue == masternodePaymentAmount && block.vtx[0].vout[i].scriptPubKey == payee)
|
||||
foundPaymentAndPayee = true;
|
||||
}
|
||||
|
||||
|
||||
CTxDestination address1;
|
||||
ExtractDestination(payee, address1);
|
||||
CBitcoinAddress address2(address1);
|
||||
|
||||
if(!foundPaymentAndPayee) {
|
||||
LogPrintf("CheckBlock() : Couldn't find masternode payment(%d|%d) or payee(%d|%s) nHeight %d. \n", foundPaymentAmount, masternodePaymentAmount, foundPayee, address2.ToString().c_str(), chainActive.Tip()->nHeight+1);
|
||||
if(Params().NetworkID() != CBaseChainParams::REGTEST) return state.DoS(100, error("CheckBlock() : Couldn't find masternode payment or payee"));
|
||||
} else {
|
||||
LogPrintf("CheckBlock() : Found payment(%d|%d) or payee(%d|%s) nHeight %d. \n", foundPaymentAmount, masternodePaymentAmount, foundPayee, address2.ToString().c_str(), chainActive.Tip()->nHeight+1);
|
||||
}
|
||||
} else {
|
||||
LogPrintf("CheckBlock() : Is initial download, skipping masternode payment check %d\n", chainActive.Tip()->nHeight+1);
|
||||
}
|
||||
} else {
|
||||
LogPrintf("CheckBlock() : Skipping masternode payment check - nHeight %d Hash %s\n", chainActive.Tip()->nHeight+1, block.GetHash().ToString().c_str());
|
||||
}
|
||||
} else {
|
||||
LogPrintf("CheckBlock() : pindex is null, skipping masternode payment check\n");
|
||||
if(masternodePayments.IsTransactionValid(block.vtx[0], pindexPrev->nHeight+1))
|
||||
{
|
||||
if(Params().NetworkID() != CBaseChainParams::REGTEST)
|
||||
return state.DoS(100, error("CheckBlock() : Couldn't find masternode payment or payee"));
|
||||
}
|
||||
} else {
|
||||
LogPrintf("CheckBlock() : skipping masternode payment checks\n");
|
||||
}
|
||||
|
||||
// -------------------------------------------
|
||||
|
||||
// Check transactions
|
||||
BOOST_FOREACH(const CTransaction& tx, block.vtx)
|
||||
@ -3288,7 +3230,7 @@ bool ProcessNewBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDis
|
||||
|
||||
CScript payee;
|
||||
CTxIn vin;
|
||||
if(masternodePayments.GetBlockPayee(chainActive.Tip()->nHeight, payee, vin)){
|
||||
if(masternodePayments.GetBlockPayee(chainActive.Tip()->nHeight, payee)){
|
||||
//UPDATE MASTERNODE LAST PAID TIME
|
||||
CMasternode* pmn = mnodeman.Find(vin);
|
||||
if(pmn != NULL) pmn->nLastPaid = GetAdjustedTime();
|
||||
@ -3300,6 +3242,7 @@ bool ProcessNewBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDis
|
||||
darkSendPool.NewBlock();
|
||||
masternodePayments.ProcessBlock(GetHeight()+10);
|
||||
mnscan.DoMasternodePOSChecks();
|
||||
//budget.NewBlock();
|
||||
}
|
||||
}
|
||||
|
||||
@ -3985,9 +3928,13 @@ bool static AlreadyHave(const CInv& inv)
|
||||
case MSG_SPORK:
|
||||
return mapSporks.count(inv.hash);
|
||||
case MSG_MASTERNODE_WINNER:
|
||||
return mapSeenMasternodeVotes.count(inv.hash);
|
||||
return true; // mapMasternodePayeeVotes.count(inv.hash);
|
||||
case MSG_MASTERNODE_SCANNING_ERROR:
|
||||
return mapMasternodeScanningErrors.count(inv.hash);
|
||||
case MSG_MASTERNODE_ANNOUNCE:
|
||||
return mapSeenMasternodeBroadcast.count(inv.hash);
|
||||
case MSG_MASTERNODE_PING:
|
||||
return mapSeenMasternodePing.count(inv.hash);
|
||||
}
|
||||
// Don't know what it is, just say we already got one
|
||||
return true;
|
||||
@ -4139,10 +4086,10 @@ void static ProcessGetData(CNode* pfrom)
|
||||
}
|
||||
}
|
||||
if (!pushed && inv.type == MSG_MASTERNODE_WINNER) {
|
||||
if(mapSeenMasternodeVotes.count(inv.hash)){
|
||||
if(mapMasternodePayeeVotes.count(inv.hash)){
|
||||
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
|
||||
ss.reserve(1000);
|
||||
ss << mapSeenMasternodeVotes[inv.hash];
|
||||
ss << mapMasternodePayeeVotes[inv.hash];
|
||||
pfrom->PushMessage("mnw", ss);
|
||||
pushed = true;
|
||||
}
|
||||
@ -4157,6 +4104,26 @@ void static ProcessGetData(CNode* pfrom)
|
||||
}
|
||||
}
|
||||
|
||||
if (!pushed && inv.type == MSG_MASTERNODE_ANNOUNCE) {
|
||||
if(mapSeenMasternodeBroadcast.count(inv.hash)){
|
||||
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
|
||||
ss.reserve(1000);
|
||||
ss << mapSeenMasternodeBroadcast[inv.hash];
|
||||
pfrom->PushMessage("mnb", ss);
|
||||
pushed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!pushed && inv.type == MSG_MASTERNODE_PING) {
|
||||
if(mapSeenMasternodePing.count(inv.hash)){
|
||||
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
|
||||
ss.reserve(1000);
|
||||
ss << mapSeenMasternodePing[inv.hash];
|
||||
pfrom->PushMessage("mnp", ss);
|
||||
pushed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!pushed) {
|
||||
vNotFound.push_back(inv);
|
||||
}
|
||||
@ -5022,7 +4989,9 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
|
||||
//probably one the extensions
|
||||
darkSendPool.ProcessMessageDarksend(pfrom, strCommand, vRecv);
|
||||
mnodeman.ProcessMessage(pfrom, strCommand, vRecv);
|
||||
ProcessMessageMasternodePayments(pfrom, strCommand, vRecv);
|
||||
budget.ProcessMessage(pfrom, strCommand, vRecv);
|
||||
//TODO
|
||||
//ProcessMessageMasternodePayments(pfrom, strCommand, vRecv);
|
||||
ProcessMessageInstantX(pfrom, strCommand, vRecv);
|
||||
ProcessSpork(pfrom, strCommand, vRecv);
|
||||
ProcessMessageMasternodePOS(pfrom, strCommand, vRecv);
|
||||
|
597
src/masternode-budget.cpp
Normal file
597
src/masternode-budget.cpp
Normal file
@ -0,0 +1,597 @@
|
||||
// Copyright (c) 2014-2015 The Dash developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include "masternode-budget.h"
|
||||
#include "masternode.h"
|
||||
#include "darksend.h"
|
||||
#include "masternodeman.h"
|
||||
#include "util.h"
|
||||
#include "addrman.h"
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
CBudgetManager budget;
|
||||
CCriticalSection cs_budget;
|
||||
|
||||
//
|
||||
// CBudgetDB
|
||||
//
|
||||
|
||||
CBudgetDB::CBudgetDB()
|
||||
{
|
||||
pathDB = GetDataDir() / "budget.dat";
|
||||
strMagicMessage = "MasternodeBudget";
|
||||
}
|
||||
|
||||
bool CBudgetDB::Write(const CBudgetManager& budgetToSave)
|
||||
{
|
||||
int64_t nStart = GetTimeMillis();
|
||||
|
||||
// serialize, checksum data up to that point, then append checksum
|
||||
CDataStream ssBudget(SER_DISK, CLIENT_VERSION);
|
||||
ssBudget << strMagicMessage; // masternode cache file specific magic message
|
||||
ssBudget << FLATDATA(Params().MessageStart()); // network specific magic number
|
||||
ssBudget << budgetToSave;
|
||||
uint256 hash = Hash(ssBudget.begin(), ssBudget.end());
|
||||
ssBudget << hash;
|
||||
|
||||
// open output file, and associate with CAutoFile
|
||||
FILE *file = fopen(pathDB.string().c_str(), "wb");
|
||||
CAutoFile fileout(file, SER_DISK, CLIENT_VERSION);
|
||||
if (fileout.IsNull())
|
||||
return error("%s : Failed to open file %s", __func__, pathDB.string());
|
||||
|
||||
// Write and commit header, data
|
||||
try {
|
||||
fileout << ssBudget;
|
||||
}
|
||||
catch (std::exception &e) {
|
||||
return error("%s : Serialize or I/O error - %s", __func__, e.what());
|
||||
}
|
||||
// FileCommit(fileout);
|
||||
fileout.fclose();
|
||||
|
||||
LogPrintf("Written info to mncache.dat %dms\n", GetTimeMillis() - nStart);
|
||||
//LogPrintf(" %s\n", budgetToSave.ToString().c_str());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
CBudgetDB::ReadResult CBudgetDB::Read(CBudgetManager& budgetToLoad)
|
||||
{
|
||||
int64_t nStart = GetTimeMillis();
|
||||
// open input file, and associate with CAutoFile
|
||||
FILE *file = fopen(pathDB.string().c_str(), "rb");
|
||||
CAutoFile filein(file, SER_DISK, CLIENT_VERSION);
|
||||
if (filein.IsNull())
|
||||
{
|
||||
error("%s : Failed to open file %s", __func__, pathDB.string());
|
||||
return FileError;
|
||||
}
|
||||
|
||||
// use file size to size memory buffer
|
||||
int fileSize = boost::filesystem::file_size(pathDB);
|
||||
int dataSize = fileSize - sizeof(uint256);
|
||||
// Don't try to resize to a negative number if file is small
|
||||
if (dataSize < 0)
|
||||
dataSize = 0;
|
||||
vector<unsigned char> vchData;
|
||||
vchData.resize(dataSize);
|
||||
uint256 hashIn;
|
||||
|
||||
// read data and checksum from file
|
||||
try {
|
||||
filein.read((char *)&vchData[0], dataSize);
|
||||
filein >> hashIn;
|
||||
}
|
||||
catch (std::exception &e) {
|
||||
error("%s : Deserialize or I/O error - %s", __func__, e.what());
|
||||
return HashReadError;
|
||||
}
|
||||
filein.fclose();
|
||||
|
||||
CDataStream ssBudget(vchData, SER_DISK, CLIENT_VERSION);
|
||||
|
||||
// verify stored checksum matches input data
|
||||
uint256 hashTmp = Hash(ssBudget.begin(), ssBudget.end());
|
||||
if (hashIn != hashTmp)
|
||||
{
|
||||
error("%s : Checksum mismatch, data corrupted", __func__);
|
||||
return IncorrectHash;
|
||||
}
|
||||
|
||||
|
||||
unsigned char pchMsgTmp[4];
|
||||
std::string strMagicMessageTmp;
|
||||
try {
|
||||
// de-serialize file header (masternode cache file specific magic message) and ..
|
||||
ssBudget >> strMagicMessageTmp;
|
||||
|
||||
// ... verify the message matches predefined one
|
||||
if (strMagicMessage != strMagicMessageTmp)
|
||||
{
|
||||
error("%s : Invalid masternode cache magic message", __func__);
|
||||
return IncorrectMagicMessage;
|
||||
}
|
||||
|
||||
|
||||
// de-serialize file header (network specific magic number) and ..
|
||||
ssBudget >> FLATDATA(pchMsgTmp);
|
||||
|
||||
// ... verify the network matches ours
|
||||
if (memcmp(pchMsgTmp, Params().MessageStart(), sizeof(pchMsgTmp)))
|
||||
{
|
||||
error("%s : Invalid network magic number", __func__);
|
||||
return IncorrectMagicNumber;
|
||||
}
|
||||
|
||||
// de-serialize data into CBudgetManager object
|
||||
ssBudget >> budgetToLoad;
|
||||
}
|
||||
catch (std::exception &e) {
|
||||
budgetToLoad.Clear();
|
||||
error("%s : Deserialize or I/O error - %s", __func__, e.what());
|
||||
return IncorrectFormat;
|
||||
}
|
||||
|
||||
|
||||
budgetToLoad.CheckAndRemove(); // clean out expired
|
||||
LogPrintf("Loaded info from mncache.dat %dms\n", GetTimeMillis() - nStart);
|
||||
LogPrintf(" %s\n", budgetToLoad.ToString());
|
||||
|
||||
return Ok;
|
||||
}
|
||||
|
||||
void DumpBudgets()
|
||||
{
|
||||
int64_t nStart = GetTimeMillis();
|
||||
|
||||
CBudgetDB mndb;
|
||||
CBudgetManager tempbudget;
|
||||
|
||||
LogPrintf("Verifying mncache.dat format...\n");
|
||||
CBudgetDB::ReadResult readResult = mndb.Read(tempbudget);
|
||||
// there was an error and it was not an error on file openning => do not proceed
|
||||
if (readResult == CBudgetDB::FileError)
|
||||
LogPrintf("Missing masternode cache file - mncache.dat, will try to recreate\n");
|
||||
else if (readResult != CBudgetDB::Ok)
|
||||
{
|
||||
LogPrintf("Error reading mncache.dat: ");
|
||||
if(readResult == CBudgetDB::IncorrectFormat)
|
||||
LogPrintf("magic is ok but data has invalid format, will try to recreate\n");
|
||||
else
|
||||
{
|
||||
LogPrintf("file format is unknown or invalid, please fix it manually\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
LogPrintf("Writting info to mncache.dat...\n");
|
||||
mndb.Write(budget);
|
||||
|
||||
LogPrintf("Masternode dump finished %dms\n", GetTimeMillis() - nStart);
|
||||
}
|
||||
|
||||
|
||||
|
||||
CBudgetVote::CBudgetVote()
|
||||
{
|
||||
vin = CTxIn();
|
||||
nVote = VOTE_ABSTAIN;
|
||||
strProposalName = "unknown";
|
||||
nBlockStart = 0;
|
||||
nBlockEnd = 0;
|
||||
nAmount = 0;
|
||||
nTime = 0;
|
||||
}
|
||||
|
||||
CBudgetVote::CBudgetVote(CTxIn vinIn, std::string strProposalNameIn, int nBlockStartIn, int nBlockEndIn, CScript addressIn, CAmount nAmountIn, int nVoteIn)
|
||||
{
|
||||
vin = vinIn;
|
||||
strProposalName = strProposalNameIn;
|
||||
nBlockStart = nBlockStartIn;
|
||||
nBlockEnd = nBlockEndIn;
|
||||
address = addressIn;
|
||||
nAmount = nAmountIn;
|
||||
nVote = nVoteIn;
|
||||
nTime = GetAdjustedTime();
|
||||
}
|
||||
|
||||
bool CBudgetVote::Sign(CKey& keyMasternode, CPubKey& pubKeyMasternode)
|
||||
{
|
||||
// Choose coins to use
|
||||
CPubKey pubKeyCollateralAddress;
|
||||
CKey keyCollateralAddress;
|
||||
|
||||
std::string errorMessage;
|
||||
std::string strMessage = vin.ToString() + boost::lexical_cast<std::string>(nVote) + boost::lexical_cast<std::string>(nTime);
|
||||
|
||||
if(!darkSendSigner.SignMessage(strMessage, errorMessage, vchSig, keyMasternode))
|
||||
return(" Error upon calling SignMessage");
|
||||
|
||||
if(!darkSendSigner.VerifyMessage(pubKeyMasternode, vchSig, strMessage, errorMessage))
|
||||
return(" Error upon calling VerifyMessage");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CBudgetVote::Relay()
|
||||
{
|
||||
CInv inv(MSG_MASTERNODE_VOTE, GetHash());
|
||||
|
||||
vector<CInv> vInv;
|
||||
vInv.push_back(inv);
|
||||
LOCK(cs_vNodes);
|
||||
BOOST_FOREACH(CNode* pnode, vNodes){
|
||||
pnode->PushMessage("inv", vInv);
|
||||
}
|
||||
}
|
||||
|
||||
uint256 GetBudgetProposalHash(std::string strProposalName)
|
||||
{
|
||||
return Hash(strProposalName.begin(), strProposalName.end());
|
||||
}
|
||||
|
||||
|
||||
void CBudgetManager::ProcessMessage(CNode* pfrom, std::string& strCommand, CDataStream& vRecv)
|
||||
{
|
||||
// lite mode is not supported
|
||||
if(IsInitialBlockDownload()) return;
|
||||
|
||||
LOCK(cs_budget);
|
||||
|
||||
if (strCommand == "mnvs") { //Masternode vote sync
|
||||
if(pfrom->HasFulfilledRequest("mnvs")) {
|
||||
LogPrintf("mnvs - peer already asked me for the list\n");
|
||||
Misbehaving(pfrom->GetId(), 20);
|
||||
return;
|
||||
}
|
||||
|
||||
pfrom->FulfilledRequest("mnvs");
|
||||
budget.Sync(pfrom);
|
||||
LogPrintf("mnvs - Sent Masternode votes to %s\n", pfrom->addr.ToString().c_str());
|
||||
}
|
||||
|
||||
if (strCommand == "mvote") { //Masternode Vote
|
||||
CBudgetVote vote;
|
||||
vRecv >> vote;
|
||||
if(!vote.SignatureValid()){
|
||||
LogPrintf("mvote - signature invalid\n");
|
||||
Misbehaving(pfrom->GetId(), 20);
|
||||
return;
|
||||
}
|
||||
|
||||
CMasternode* pmn = mnodeman.Find(vote.vin);
|
||||
if(pmn == NULL) {
|
||||
LogPrintf("mvote - unknown masternode - vin:%s \n", pmn->vin.ToString().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if(pmn->nVotedTimes < 100){
|
||||
budget.AddOrUpdateProposal(vote);
|
||||
vote.Relay();
|
||||
pmn->nVotedTimes++;
|
||||
} else {
|
||||
LogPrintf("mvote - masternode can't vote again - vin:%s \n", pmn->vin.ToString().c_str());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool CBudgetVote::SignatureValid()
|
||||
{
|
||||
std::string errorMessage;
|
||||
std::string strMessage = vin.prevout.ToStringShort() + boost::lexical_cast<std::string>(nVote) + boost::lexical_cast<std::string>(nTime);
|
||||
|
||||
CMasternode* pmn = mnodeman.Find(vin);
|
||||
|
||||
if(pmn == NULL)
|
||||
{
|
||||
LogPrintf("CBudgetVote::SignatureValid() - Unknown Masternode\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
CScript pubkey;
|
||||
pubkey = GetScriptForDestination(pmn->pubkey2.GetID());
|
||||
CTxDestination address1;
|
||||
ExtractDestination(pubkey, address1);
|
||||
CBitcoinAddress address2(address1);
|
||||
|
||||
if(!darkSendSigner.VerifyMessage(pmn->pubkey2, vchSig, strMessage, errorMessage)) {
|
||||
LogPrintf("CBudgetVote::SignatureValid() - Verify message failed\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CBudgetManager::AddOrUpdateProposal(CBudgetVote& vote)
|
||||
{
|
||||
// LOCK(cs);
|
||||
|
||||
// uint256 hash = GetBudgetProposalHash(vote.strProposalName);
|
||||
|
||||
// if(!mapProposals.count(hash)){
|
||||
// CBudgetProposal prop(vote.strProposalName);
|
||||
// mapProposals.insert(make_pair(hash, prop));
|
||||
// return;
|
||||
// }
|
||||
|
||||
// mapProposals[hash].AddOrUpdateVote(vote);
|
||||
}
|
||||
|
||||
void CBudgetProposal::AddOrUpdateVote(CBudgetVote& vote)
|
||||
{
|
||||
// LOCK(cs);
|
||||
|
||||
// uint256 hash = vote.vin.prevout.GetHash();
|
||||
|
||||
// if(!mapProposals.count(hash)){
|
||||
// mapProposals.insert(make_pair(hash, vote));
|
||||
// return;
|
||||
// }
|
||||
|
||||
// vote[hash] = vote;
|
||||
}
|
||||
|
||||
inline 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;
|
||||
|
||||
mnodeman.DecrementVotedTimes();
|
||||
}
|
||||
|
||||
CBudgetProposal *CBudgetManager::Find(const std::string &strProposalName)
|
||||
{
|
||||
// uint256 hash = GetBudgetProposalHash(vote.strProposalName);
|
||||
|
||||
// if(mapProposals.count(hash)){
|
||||
// return &mapProposals[hash];
|
||||
// }
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CBudgetProposal::CBudgetProposal()
|
||||
{
|
||||
strProposalName = "";
|
||||
}
|
||||
|
||||
CBudgetProposal::CBudgetProposal(std::string strProposalNameIn)
|
||||
{
|
||||
strProposalName = strProposalNameIn;
|
||||
}
|
||||
|
||||
std::string CBudgetProposal::GetName()
|
||||
{
|
||||
return strProposalName;
|
||||
}
|
||||
|
||||
int CBudgetProposal::GetBlockStart()
|
||||
{
|
||||
/*std::map<int, int> mapList;
|
||||
|
||||
map<uint256, CBudgetVote>::iterator it;
|
||||
for(it=mapVotes.begin();it<mapVotes.end();it++){
|
||||
if ((*it)->second.mapVotes.nVote != VOTE_YEA) continue;
|
||||
|
||||
if(mapList.count((*it).nBlockStart)){
|
||||
mapList[(*it).nBlockStart]++;
|
||||
} else {
|
||||
mapList[(*it)].insert(make_pair<(*it).nBlockStart, 1>);
|
||||
}
|
||||
}*/
|
||||
|
||||
//sort(mapList.begin(), mapList.end());
|
||||
// return myMap.begin()->second;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CBudgetProposal::GetBlockEnd()
|
||||
{
|
||||
std::map<int, int> mapList;
|
||||
|
||||
// map<uint256, CBudgetVote>::iterator it;
|
||||
// for(it=mapVotes.begin();it<mapVotes.end();it++){
|
||||
// if ((*it)->second.nVote != VOTE_YEA) continue;
|
||||
|
||||
// if(mapList.count((*it).nBlockEnd)){
|
||||
// mapList[(*it).nBlockEnd]++;
|
||||
// } else {
|
||||
// mapList[(*it).nBlockEnd] = 1;
|
||||
// }
|
||||
// }
|
||||
|
||||
// sort(mapList.begin(), mapList.end());
|
||||
// return myMap.begin()->first;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int64_t CBudgetProposal::GetAmount()
|
||||
{
|
||||
std::map<int64_t, int> mapList;
|
||||
|
||||
// map<uint256, CBudgetVote>::iterator it;
|
||||
// for(it=mapVotes.begin();it<mapVotes.end();it++){
|
||||
// if ((*it)->second.nVote != VOTE_YEA) continue;
|
||||
|
||||
// if(mapList.count((*it).nAmount)){
|
||||
// mapList[(*it).nAmount]++;
|
||||
// } else {
|
||||
// mapList[(*it).nAmount] = 1;
|
||||
// }
|
||||
// }
|
||||
|
||||
// sort(mapList.begin(), mapList.end());
|
||||
// return myMap.begin()->first;
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string CBudgetProposal::GetPaymentAddress()
|
||||
{
|
||||
std::map<std::string, int> mapList;
|
||||
|
||||
// map<uint256, CBudgetVote>::iterator it;
|
||||
// for(it=prop->mapVotes.begin();it<prop->mapVotes.end();it++){
|
||||
// if ((*it)->second.nVote != VOTE_YEA) continue;
|
||||
|
||||
// CTxDestination address1;
|
||||
// ExtractDestination((*it)->second.payee, address1);
|
||||
// CBitcoinAddress address2(address1);
|
||||
|
||||
// if(mapList.count(address2){
|
||||
// mapList[address2]++;
|
||||
// } else {
|
||||
// mapList[address2] = 1;
|
||||
// }
|
||||
// }
|
||||
|
||||
// sort(mapList.begin(), mapList.end());
|
||||
// return myMap.begin()->first;
|
||||
return 0;
|
||||
}
|
||||
|
||||
double CBudgetProposal::GetRatio()
|
||||
{
|
||||
int yeas = 0;
|
||||
int nays = 0;
|
||||
|
||||
// map<uint256, CBudgetVote>::iterator it;
|
||||
// for(it=mapVotes.begin();it<mapVotes.end();it++){
|
||||
// if ((*it)->second.prop->mapVotes.nVote != VOTE_YEA) yeas++;
|
||||
// if ((*it)->second.nVote != VOTE_NAY) nays++;
|
||||
// }
|
||||
|
||||
return ((double)yeas / (double)yeas+nays);
|
||||
}
|
||||
|
||||
int CBudgetProposal::GetYeas()
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
// map<uint256, CBudgetVote>::iterator it;
|
||||
// for(it=mapVotes.begin();it<mapVotes.end();it++)
|
||||
// if ((*it)->second.mapVotes.nVote != VOTE_YEA) ret++;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int CBudgetProposal::GetNays()
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
// map<uint256, CBudgetVote>::iterator it;
|
||||
// for(it=mapVotes.begin();it<mapVotes.end();it++)
|
||||
// if ((*it)->second.nVote != VOTE_NAY) ret++;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int CBudgetProposal::GetAbstains()
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
// map<uint256, CBudgetVote>::iterator it;
|
||||
// for(it=mapVotes.begin();it<mapVotes.end();it++)
|
||||
// if ((*it)->second.mapVotes.nVote != VOTE_ABSTAIN) ret++;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool CBudgetManager::IsBudgetPaymentBlock(int nHeight)
|
||||
{
|
||||
if(nHeight > 158000+((576*30)*15)) return (nHeight % 7) == 0 ; // 417200 - 57.5% - 2016-02-08 -- 12.5% of blocks
|
||||
if(nHeight > 158000+((576*30)*13)) return (nHeight % 10) == 0 ; // 382640 - 55.0% - 2015-12-07 -- 10.0% of blocks
|
||||
if(nHeight > 158000+((576*30)*11)) return (nHeight % 13) == 0 ; // 348080 - 52.5% - 2015-10-05 -- 7.5 of blocks
|
||||
if(nHeight > 158000+((576*30)* 9)) return (nHeight % 20) == 0 ; // 313520 - 50.0% - 2015-08-03 -- 5.0% of blocks
|
||||
if(nHeight > 158000+((576*30)* 7)) return (nHeight % 40) == 0 ; // 278960 - 47.5% - 2015-06-01 -- 2.5% of blocks
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void CBudgetManager::FillBlockTx(CMutableTransaction& txNew, int& payments)
|
||||
{
|
||||
/* std::vector<CBudgetProposal*> budget = GetBudget();
|
||||
|
||||
LogPrintf("Masternode Budget payment to");
|
||||
|
||||
BOOST_FOREACH(CBudgetProposal* prop, budget){
|
||||
payments++;
|
||||
txNew.vout.resize(payments);
|
||||
|
||||
txNew.vout[payments-1].scriptPubKey = prop.GetPayee();
|
||||
txNew.vout[payments-1].nValue = prop.GetAmount();
|
||||
|
||||
CTxDestination address1;
|
||||
ExtractDestination(pblock->payee, address1);
|
||||
CBitcoinAddress address2(address1);
|
||||
|
||||
LogPrintf(" (%s|%d)", address2.ToString().c_str(), prop.GetAmount());
|
||||
}
|
||||
LogPrintf("\n");*/
|
||||
}
|
||||
|
||||
int64_t CBudgetManager::GetTotalBudget()
|
||||
{
|
||||
if(chainActive.Tip() == NULL) return 0;
|
||||
|
||||
const CBlockIndex* pindex = chainActive.Tip();
|
||||
return (GetBlockValue(pindex->pprev->nBits, pindex->pprev->nHeight, 0)/100)*15;
|
||||
}
|
||||
|
||||
std::vector<CBudgetProposal*> CBudgetManager::GetBudget()
|
||||
{
|
||||
/* std::map<uint256, int> mapList;
|
||||
|
||||
map<uint256, CBudgetProposal>::iterator it;
|
||||
for(it=prop->mapProposals.begin();it<prop->mapProposals.end();it++){
|
||||
uint256 hash = GetBudgetProposalHash((*it)->second.strProposalName);
|
||||
if(!mapList.count(hash)){
|
||||
mapList[hash] = (*it)->second.GetYeas();
|
||||
}
|
||||
}
|
||||
|
||||
//sort by yeas
|
||||
sort(mapList.begin(), mapList.end());*/
|
||||
|
||||
std::vector<CBudgetProposal*> ret;
|
||||
|
||||
/* int64_t nBudgetAllocated = 0;
|
||||
int64_t nTotalBudget = GetTotalBudget();
|
||||
|
||||
map<uint256, CBudgetProposal>::iterator it;
|
||||
for(it=prop->mapProposals.begin();it<prop->mapProposals.end();it++){
|
||||
if(nTotalBudget == nBudgetAllocated){
|
||||
(*it).SetAllotted(0);
|
||||
} else if((*it).GetAmount() + nBudgetAllocated <= nTotalBudget()) {
|
||||
(*it).SetAllotted((*it).GetAmount());
|
||||
nBudgetAllocated += (*it).GetAmount();
|
||||
} else {
|
||||
//couldn't pay for the entire budget, so it'll be partially paid.
|
||||
(*it).SetAllotted(nTotalBudget - nBudgetAllocated);
|
||||
nBudgetAllocated = nTotalBudget;
|
||||
}
|
||||
|
||||
ret.insert(make_pair((*it).strProposalName, &(*it)))
|
||||
}*/
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void CBudgetManager::Sync(CNode* node)
|
||||
{
|
||||
// map<uint256, CBudgetProposal>::iterator it;
|
||||
// for(it=prop->mapProposals.begin();it<prop->mapProposals.end();it++){
|
||||
// (*it)->second.Sync(node);
|
||||
// }
|
||||
}
|
||||
|
||||
void CBudgetProposal::Sync(CNode* node)
|
||||
{
|
||||
// map<uint256, CBudgetVote>::iterator it;
|
||||
// for(it=mapVotes.begin();it<mapVotes.end();it++){
|
||||
// node->PushMessage("mvote", mapVotes[(*it)->first]);
|
||||
// }
|
||||
}
|
212
src/masternode-budget.h
Normal file
212
src/masternode-budget.h
Normal file
@ -0,0 +1,212 @@
|
||||
|
||||
// Copyright (c) 2014-2015 The Dash developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
#ifndef MASTERNODE_BUDGET_H
|
||||
#define MASTERNODE_BUDGET_H
|
||||
|
||||
#include "main.h"
|
||||
#include "sync.h"
|
||||
#include "net.h"
|
||||
#include "key.h"
|
||||
#include "util.h"
|
||||
#include "base58.h"
|
||||
#include "masternode.h"
|
||||
#include "masternode-pos.h"
|
||||
//#include "timedata.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
class CBudgetManager;
|
||||
class CBudgetProposal;
|
||||
class CBudgetVote;
|
||||
|
||||
#define VOTE_ABSTAIN 0
|
||||
#define VOTE_YES 1
|
||||
#define VOTE_NO 2
|
||||
|
||||
extern CBudgetManager budget;
|
||||
|
||||
void DumpBudgets();
|
||||
|
||||
|
||||
/** Save Budget Manager (budget.dat)
|
||||
*/
|
||||
class CBudgetDB
|
||||
{
|
||||
private:
|
||||
boost::filesystem::path pathDB;
|
||||
std::string strMagicMessage;
|
||||
public:
|
||||
enum ReadResult {
|
||||
Ok,
|
||||
FileError,
|
||||
HashReadError,
|
||||
IncorrectHash,
|
||||
IncorrectMagicMessage,
|
||||
IncorrectMagicNumber,
|
||||
IncorrectFormat
|
||||
};
|
||||
|
||||
CBudgetDB();
|
||||
bool Write(const CBudgetManager &budgetToSave);
|
||||
ReadResult Read(CBudgetManager& budgetToLoad);
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Budget Manager : Contains all proposals for the budget
|
||||
//
|
||||
class CBudgetManager
|
||||
{
|
||||
private:
|
||||
// critical section to protect the inner data structures
|
||||
mutable CCriticalSection cs;
|
||||
|
||||
public:
|
||||
// keep track of the scanning errors I've seen
|
||||
map<uint256, CBudgetProposal> mapProposals;
|
||||
|
||||
CBudgetManager() {
|
||||
mapProposals.clear();
|
||||
}
|
||||
|
||||
void Sync(CNode* node);
|
||||
|
||||
void Calculate();
|
||||
void ProcessMessage(CNode* pfrom, std::string& strCommand, CDataStream& vRecv);
|
||||
CBudgetProposal *Find(const std::string &strProposalName);
|
||||
inline void NewBlock();
|
||||
std::pair<std::string, std::string> GetVotes(std::string strProposalName);
|
||||
uint256 GetBudgetProposalHash(std::string strProposalName);
|
||||
void CleanUp();
|
||||
|
||||
int64_t GetTotalBudget();
|
||||
std::vector<CBudgetProposal*> GetBudget();
|
||||
bool IsBudgetPaymentBlock(int nHeight);
|
||||
void FillBlockTx(CMutableTransaction& txNew, int& payments);
|
||||
void AddOrUpdateProposal(CBudgetVote& vote);
|
||||
|
||||
void Clear(){
|
||||
printf("Not implemented\n");
|
||||
}
|
||||
void CheckAndRemove(){
|
||||
printf("Not implemented\n");
|
||||
//replace cleanup
|
||||
}
|
||||
std::string ToString() {return "not implemented";}
|
||||
|
||||
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
|
||||
READWRITE(mapProposals);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Budget Proposal : Contains the masternode votes for each budget
|
||||
//
|
||||
|
||||
class CBudgetProposal
|
||||
{
|
||||
private:
|
||||
// critical section to protect the inner data structures
|
||||
//mutable CCriticalSection cs;
|
||||
int64_t nAlloted;
|
||||
|
||||
public:
|
||||
std::string strProposalName;
|
||||
|
||||
map<uint256, CBudgetVote> mapVotes;
|
||||
//cache object
|
||||
|
||||
CBudgetProposal();
|
||||
CBudgetProposal(std::string strProposalNameIn);
|
||||
|
||||
void Sync(CNode* node);
|
||||
|
||||
void Calculate();
|
||||
void AddOrUpdateVote(CBudgetVote& vote);
|
||||
bool HasMinimumRequiredSupport();
|
||||
std::pair<std::string, std::string> GetVotes();
|
||||
|
||||
std::string GetName();
|
||||
int GetBlockStart();
|
||||
int GetBlockEnd();
|
||||
std::string GetPaymentAddress();
|
||||
double GetRatio();
|
||||
int GetYeas();
|
||||
int GetNays();
|
||||
int GetAbstains();
|
||||
int64_t GetAmount();
|
||||
|
||||
void SetAlloted(int64_t nAllotedIn) {nAlloted = nAllotedIn;}
|
||||
int64_t GetAlloted() {return nAlloted;}
|
||||
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
|
||||
READWRITE(mapVotes);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// CBudgetVote - Allow a masternode node to vote and broadcast throughout the network
|
||||
//
|
||||
|
||||
class CBudgetVote
|
||||
{
|
||||
public:
|
||||
std::string strProposalName;
|
||||
CTxIn vin;
|
||||
int nBlockStart;
|
||||
int nBlockEnd;
|
||||
int64_t nAmount;
|
||||
int nVote;
|
||||
int64_t nTime;
|
||||
CScript address;
|
||||
std::vector<unsigned char> vchSig;
|
||||
|
||||
CBudgetVote();
|
||||
CBudgetVote(CTxIn vinIn, std::string strProposalNameIn, int nBlockStartIn, int nBlockEndIn, CScript addressIn, CAmount nAmountIn, int nVoteIn);
|
||||
|
||||
bool Sign(CKey& keyCollateralAddress, CPubKey& pubKeyMasternode);
|
||||
bool SignatureValid();
|
||||
void Relay();
|
||||
|
||||
std::string GetVoteString() {
|
||||
std::string ret = "ABSTAIN";
|
||||
if(nVote == VOTE_YES) ret = "YES";
|
||||
if(nVote == VOTE_NO) ret = "NO";
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint256 GetHash(){
|
||||
return Hash(BEGIN(vin), END(vin), BEGIN(nVote), END(nVote), BEGIN(nTime), END(nTime));
|
||||
}
|
||||
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
|
||||
READWRITE(LIMITED_STRING(strProposalName, 20));
|
||||
READWRITE(vin);
|
||||
READWRITE(nBlockStart);
|
||||
READWRITE(nBlockEnd);
|
||||
READWRITE(nAmount);
|
||||
READWRITE(nVote);
|
||||
READWRITE(nTime);
|
||||
READWRITE(address);
|
||||
READWRITE(vchSig);
|
||||
}
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif
|
@ -14,10 +14,10 @@ CCriticalSection cs_masternodepayments;
|
||||
|
||||
/** Object for who's going to get paid on which blocks */
|
||||
CMasternodePayments masternodePayments;
|
||||
// keep track of Masternode votes I've seen
|
||||
map<uint256, CMasternodePaymentWinner> mapSeenMasternodeVotes;
|
||||
map<uint256, CMasternodePaymentWinner> mapMasternodePayeeVotes;
|
||||
map<uint256, CMasternodeBlockPayees> mapMasternodeBlocks;
|
||||
|
||||
void ProcessMessageMasternodePayments(CNode* pfrom, std::string& strCommand, CDataStream& vRecv)
|
||||
void CMasternodePayments::ProcessMessageMasternodePayments(CNode* pfrom, std::string& strCommand, CDataStream& vRecv)
|
||||
{
|
||||
if(IsInitialBlockDownload()) return;
|
||||
|
||||
@ -44,119 +44,65 @@ void ProcessMessageMasternodePayments(CNode* pfrom, std::string& strCommand, CDa
|
||||
|
||||
if(chainActive.Tip() == NULL) return;
|
||||
|
||||
CTxDestination address1;
|
||||
ExtractDestination(winner.payee, address1);
|
||||
CBitcoinAddress address2(address1);
|
||||
|
||||
uint256 hash = winner.GetHash();
|
||||
if(mapSeenMasternodeVotes.count(hash)) {
|
||||
if(fDebug) LogPrintf("mnw - seen vote %s Addr %s Height %d bestHeight %d\n", hash.ToString().c_str(), address2.ToString().c_str(), winner.nBlockHeight, chainActive.Tip()->nHeight);
|
||||
return;
|
||||
if(mapMasternodePayeeVotes.count(winner.GetHash())){
|
||||
if(fDebug) LogPrintf("mnw - Already seen - %s bestHeight %d\n", winner.GetHash().ToString().c_str(), chainActive.Tip()->nHeight);
|
||||
return;
|
||||
}
|
||||
|
||||
if(winner.nBlockHeight < chainActive.Tip()->nHeight - 10 || winner.nBlockHeight > chainActive.Tip()->nHeight+20){
|
||||
LogPrintf("mnw - winner out of range %s Addr %s Height %d bestHeight %d\n", winner.vin.ToString().c_str(), address2.ToString().c_str(), winner.nBlockHeight, chainActive.Tip()->nHeight);
|
||||
LogPrintf("mnw - winner out of range - Height %d bestHeight %d\n", winner.nBlockHeight, chainActive.Tip()->nHeight);
|
||||
return;
|
||||
}
|
||||
|
||||
if(winner.vin.nSequence != std::numeric_limits<unsigned int>::max()){
|
||||
LogPrintf("mnw - invalid nSequence\n");
|
||||
Misbehaving(pfrom->GetId(), 100);
|
||||
if(!winner.IsValid()){
|
||||
LogPrintf("mnw - invalid message\n");
|
||||
return;
|
||||
}
|
||||
|
||||
LogPrintf("mnw - winning vote - Vin %s Addr %s Height %d bestHeight %d\n", winner.vin.ToString().c_str(), address2.ToString().c_str(), winner.nBlockHeight, chainActive.Tip()->nHeight);
|
||||
|
||||
if(!masternodePayments.CheckSignature(winner)){
|
||||
if(!winner.SignatureValid()){
|
||||
LogPrintf("mnw - invalid signature\n");
|
||||
Misbehaving(pfrom->GetId(), 100);
|
||||
return;
|
||||
}
|
||||
|
||||
mapSeenMasternodeVotes.insert(make_pair(hash, winner));
|
||||
CTxDestination address1;
|
||||
ExtractDestination(winner.payee.scriptPubKey, address1);
|
||||
CBitcoinAddress address2(address1);
|
||||
|
||||
if(fDebug) LogPrintf("mnw - winning vote - Addr %s Height %d bestHeight %d\n", address2.ToString().c_str(), winner.nBlockHeight, chainActive.Tip()->nHeight);
|
||||
|
||||
if(masternodePayments.AddWinningMasternode(winner)){
|
||||
masternodePayments.Relay(winner);
|
||||
winner.Relay();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool CMasternodePayments::CheckSignature(CMasternodePaymentWinner& winner)
|
||||
bool CMasternodePaymentWinner::Sign(CKey& keyMasternode, CPubKey& pubKeyMasternode)
|
||||
{
|
||||
//note: need to investigate why this is failing
|
||||
std::string strMessage = winner.vin.ToString().c_str() + boost::lexical_cast<std::string>(winner.nBlockHeight) + winner.payee.ToString();
|
||||
CPubKey pubkey(ParseHex(Params().MasternodePaymentPubKey()));
|
||||
std::string errorMessage;
|
||||
std::string strMasterNodeSignMessage;
|
||||
|
||||
std::string errorMessage = "";
|
||||
if(!darkSendSigner.VerifyMessage(pubkey, winner.vchSig, strMessage, errorMessage)){
|
||||
std::string strMessage = vinMasternode.prevout.ToStringShort() +
|
||||
boost::lexical_cast<std::string>(nBlockHeight) +
|
||||
payee.ToString();
|
||||
|
||||
if(!darkSendSigner.SignMessage(strMessage, errorMessage, vchSig, keyMasternode)) {
|
||||
LogPrintf("CMasternodePing::Sign() - Error: %s\n", errorMessage.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!darkSendSigner.VerifyMessage(pubKeyMasternode, vchSig, strMessage, errorMessage)) {
|
||||
LogPrintf("CMasternodePing::Sign() - Error: %s\n", errorMessage.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMasternodePayments::Sign(CMasternodePaymentWinner& winner)
|
||||
bool CMasternodePayments::GetBlockPayee(int nBlockHeight, CScript& payee)
|
||||
{
|
||||
std::string strMessage = winner.vin.ToString().c_str() + boost::lexical_cast<std::string>(winner.nBlockHeight) + winner.payee.ToString();
|
||||
|
||||
CKey key2;
|
||||
CPubKey pubkey2;
|
||||
std::string errorMessage = "";
|
||||
|
||||
if(!darkSendSigner.SetKey(strMasterPrivKey, errorMessage, key2, pubkey2))
|
||||
{
|
||||
LogPrintf("CMasternodePayments::Sign - ERROR: Invalid Masternodeprivkey: '%s'\n", errorMessage.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!darkSendSigner.SignMessage(strMessage, errorMessage, winner.vchSig, key2)) {
|
||||
LogPrintf("CMasternodePayments::Sign - Sign message failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!darkSendSigner.VerifyMessage(pubkey2, winner.vchSig, strMessage, errorMessage)) {
|
||||
LogPrintf("CMasternodePayments::Sign - Verify message failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint64_t CMasternodePayments::CalculateScore(uint256 blockHash, CTxIn& vin)
|
||||
{
|
||||
uint256 n1 = blockHash;
|
||||
uint256 n2 = HashX11(BEGIN(n1), END(n1));
|
||||
uint256 n3 = HashX11(BEGIN(vin.prevout.hash), END(vin.prevout.hash));
|
||||
uint256 n4 = n3 > n2 ? (n3 - n2) : (n2 - n3);
|
||||
|
||||
//printf(" -- CMasternodePayments CalculateScore() n2 = %d \n", n2.Get64());
|
||||
//printf(" -- CMasternodePayments CalculateScore() n3 = %d \n", n3.Get64());
|
||||
//printf(" -- CMasternodePayments CalculateScore() n4 = %d \n", n4.Get64());
|
||||
|
||||
return n4.Get64();
|
||||
}
|
||||
|
||||
bool CMasternodePayments::GetBlockPayee(int nBlockHeight, CScript& payee, CTxIn& vin)
|
||||
{
|
||||
BOOST_FOREACH(CMasternodePaymentWinner& winner, vWinning){
|
||||
if(winner.nBlockHeight == nBlockHeight) {
|
||||
payee = winner.payee;
|
||||
vin = winner.vin;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CMasternodePayments::GetWinningMasternode(int nBlockHeight, CTxIn& vinOut)
|
||||
{
|
||||
BOOST_FOREACH(CMasternodePaymentWinner& winner, vWinning){
|
||||
if(winner.nBlockHeight == nBlockHeight) {
|
||||
vinOut = winner.vin;
|
||||
return true;
|
||||
}
|
||||
if(!mapMasternodeBlocks.count(nBlockHeight)){
|
||||
return mapMasternodeBlocks[nBlockHeight].GetPayee(payee);
|
||||
}
|
||||
|
||||
return false;
|
||||
@ -169,34 +115,87 @@ bool CMasternodePayments::AddWinningMasternode(CMasternodePaymentWinner& winnerI
|
||||
return false;
|
||||
}
|
||||
|
||||
winnerIn.score = CalculateScore(blockHash, winnerIn.vin);
|
||||
if(mapMasternodePayeeVotes.count(winnerIn.GetHash())){
|
||||
return false;
|
||||
}
|
||||
|
||||
bool foundBlock = false;
|
||||
BOOST_FOREACH(CMasternodePaymentWinner& winner, vWinning){
|
||||
if(winner.nBlockHeight == winnerIn.nBlockHeight) {
|
||||
foundBlock = true;
|
||||
if(winner.score < winnerIn.score){
|
||||
winner.score = winnerIn.score;
|
||||
winner.vin = winnerIn.vin;
|
||||
winner.payee = winnerIn.payee;
|
||||
winner.vchSig = winnerIn.vchSig;
|
||||
mapMasternodePayeeVotes[winnerIn.GetHash()] = winnerIn;
|
||||
|
||||
mapSeenMasternodeVotes.insert(make_pair(winnerIn.GetHash(), winnerIn));
|
||||
if(!mapMasternodeBlocks.count(winnerIn.nBlockHeight)){
|
||||
CMasternodeBlockPayees blockPayees;
|
||||
mapMasternodeBlocks[winnerIn.nBlockHeight] = blockPayees;
|
||||
}
|
||||
|
||||
return true;
|
||||
int n = 1;
|
||||
if(IsReferenceNode(winnerIn.vinMasternode)) n = 100;
|
||||
mapMasternodeBlocks[winnerIn.nBlockHeight].AddPayee(winnerIn.payee.scriptPubKey, winnerIn.payee.nValue, n);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMasternodeBlockPayees::IsTransactionValid(const CTransaction& txNew)
|
||||
{
|
||||
/* BOOST_FOREACH(CMasternodePayee& payee, vecPayees)
|
||||
{
|
||||
bool found = false;
|
||||
BOOST_FOREACH(CTxOut& out, txNew.vout)
|
||||
{
|
||||
if(payee.scriptPubKey == out.scriptPubKey && payee.nValue == out.nValue)
|
||||
found = true;
|
||||
}
|
||||
|
||||
if(payee.nVotes >= MNPAYMENTS_SIGNATURES_REQUIRED && !found){
|
||||
|
||||
CTxDestination address1;
|
||||
ExtractDestination(payee.scriptPubKey, address1);
|
||||
CBitcoinAddress address2(address1);
|
||||
|
||||
LogPrintf("CMasternodePayments::IsTransactionValid - Missing required payment - %s:%d\n", address2.ToString().c_str, payee.nValue);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string CMasternodeBlockPayees::GetRequiredPaymentsString()
|
||||
{
|
||||
std::string ret = "Unknown";
|
||||
|
||||
/* BOOST_FOREACH(CMasternodePayee& payee, vecPayees)
|
||||
{
|
||||
if(payee.nVotes >= MNPAYMENTS_SIGNATURES_REQUIRED){
|
||||
CTxDestination address1;
|
||||
ExtractDestination(payee.scriptPubKey, address1);
|
||||
CBitcoinAddress address2(address1);
|
||||
|
||||
if(ret != "Unknown"){
|
||||
ret += sprintf(", %s:%d", address2.ToString(), payee.nValue);
|
||||
} else {
|
||||
ret = sprintf("%s:%d", address2.ToString(), payee.nValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
return ret;
|
||||
}
|
||||
|
||||
// if it's not in the vector
|
||||
if(!foundBlock){
|
||||
vWinning.push_back(winnerIn);
|
||||
mapSeenMasternodeVotes.insert(make_pair(winnerIn.GetHash(), winnerIn));
|
||||
|
||||
return true;
|
||||
std::string CMasternodePayments::GetRequiredPaymentsString(int nBlockHeight)
|
||||
{
|
||||
if(mapMasternodeBlocks.count(nBlockHeight)){
|
||||
return mapMasternodeBlocks[nBlockHeight].GetRequiredPaymentsString();
|
||||
}
|
||||
|
||||
return false;
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
bool CMasternodePayments::IsTransactionValid(const CTransaction& txNew, int nBlockHeight)
|
||||
{
|
||||
if(mapMasternodeBlocks.count(nBlockHeight)){
|
||||
return mapMasternodeBlocks[nBlockHeight].IsTransactionValid(txNew);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CMasternodePayments::CleanPaymentList()
|
||||
@ -207,119 +206,193 @@ void CMasternodePayments::CleanPaymentList()
|
||||
|
||||
int nLimit = std::max(((int)mnodeman.size())*2, 1000);
|
||||
|
||||
vector<CMasternodePaymentWinner>::iterator it;
|
||||
/* vector<CMasternodePaymentWinner>::iterator it;
|
||||
for(it=vWinning.begin();it<vWinning.end();it++){
|
||||
if(chainActive.Tip()->nHeight - (*it).nBlockHeight > nLimit){
|
||||
if(fDebug) LogPrintf("CMasternodePayments::CleanPaymentList - Removing old Masternode payment - block %d\n", (*it).nBlockHeight);
|
||||
vWinning.erase(it);
|
||||
break;
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
bool IsReferenceNode(CTxIn& vin)
|
||||
{
|
||||
//reference node - hybrid mode
|
||||
if(vin.prevout.ToStringShort() == "099c01bea63abd1692f60806bb646fa1d288e2d049281225f17e499024084e28-0") return true; // mainnet
|
||||
if(vin.prevout.ToStringShort() == "testnet-0") return true; // testnet
|
||||
if(vin.prevout.ToStringShort() == "regtest-0") return true; // regtest
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CMasternodePaymentWinner::IsValid()
|
||||
{
|
||||
if(IsReferenceNode(vinMasternode)) return true;
|
||||
|
||||
int n = mnodeman.GetMasternodeRank(vinMasternode, nBlockHeight, MIN_MNPAYMENTS_PROTO_VERSION);
|
||||
|
||||
if(n == -1)
|
||||
{
|
||||
if(fDebug) LogPrintf("CMasternodePaymentWinner::IsValid - Unknown Masternode\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(n > MNPAYMENTS_SIGNATURES_TOTAL)
|
||||
{
|
||||
if(fDebug) LogPrintf("CMasternodePaymentWinner::IsValid - Masternode not in the top %d (%d)\n", MNPAYMENTS_SIGNATURES_TOTAL, n);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMasternodePayments::ProcessBlock(int nBlockHeight)
|
||||
{
|
||||
LOCK(cs_masternodepayments);
|
||||
|
||||
if(nBlockHeight <= nLastBlockHeight) return false;
|
||||
if(!enabled) return false;
|
||||
CMasternodePaymentWinner newWinner;
|
||||
int nMinimumAge = mnodeman.CountEnabled();
|
||||
CScript payeeSource;
|
||||
|
||||
uint256 hash;
|
||||
if(!GetBlockHash(hash, nBlockHeight-10)) return false;
|
||||
unsigned int nHash;
|
||||
memcpy(&nHash, &hash, 2);
|
||||
if(!fMasterNode) return false;
|
||||
|
||||
LogPrintf(" ProcessBlock Start nHeight %d. \n", nBlockHeight);
|
||||
//reference node - hybrid mode
|
||||
|
||||
std::vector<CTxIn> vecLastPayments;
|
||||
BOOST_REVERSE_FOREACH(CMasternodePaymentWinner& winner, vWinning)
|
||||
{
|
||||
//if we already have the same vin - we have one full payment cycle, break
|
||||
if(vecLastPayments.size() > (unsigned int)nMinimumAge) break;
|
||||
vecLastPayments.push_back(winner.vin);
|
||||
}
|
||||
if(!IsReferenceNode(activeMasternode.vin)){
|
||||
int n = mnodeman.GetMasternodeRank(activeMasternode.vin, nBlockHeight, MIN_MNPAYMENTS_PROTO_VERSION);
|
||||
|
||||
// pay to the oldest MN that still had no payment but its input is old enough and it was active long enough
|
||||
CMasternode *pmn = mnodeman.FindOldestNotInVec(vecLastPayments, nMinimumAge);
|
||||
if(pmn != NULL)
|
||||
{
|
||||
LogPrintf(" Found by FindOldestNotInVec \n");
|
||||
|
||||
newWinner.score = 0;
|
||||
newWinner.nBlockHeight = nBlockHeight;
|
||||
newWinner.vin = pmn->vin;
|
||||
|
||||
if(pmn->donationPercentage > 0 && (nHash % 100) <= (unsigned int)pmn->donationPercentage) {
|
||||
newWinner.payee = pmn->donationAddress;
|
||||
} else {
|
||||
newWinner.payee = GetScriptForDestination(pmn->pubkey.GetID());
|
||||
if(n == -1)
|
||||
{
|
||||
if(fDebug) LogPrintf("CMasternodePayments::ProcessBlock - Unknown Masternode\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
payeeSource = GetScriptForDestination(pmn->pubkey.GetID());
|
||||
if(n > MNPAYMENTS_SIGNATURES_TOTAL)
|
||||
{
|
||||
if(fDebug) LogPrintf("CMasternodePayments::ProcessBlock - Masternode not in the top %d (%d)\n", MNPAYMENTS_SIGNATURES_TOTAL, n);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//if we can't find new MN to get paid, pick first active MN counting back from the end of vecLastPayments list
|
||||
if(newWinner.nBlockHeight == 0 && nMinimumAge > 0)
|
||||
{
|
||||
LogPrintf(" Find by reverse \n");
|
||||
|
||||
BOOST_REVERSE_FOREACH(CTxIn& vinLP, vecLastPayments)
|
||||
{
|
||||
CMasternode* pmn = mnodeman.Find(vinLP);
|
||||
if(pmn != NULL)
|
||||
{
|
||||
pmn->Check();
|
||||
if(!pmn->IsEnabled()) continue;
|
||||
|
||||
newWinner.score = 0;
|
||||
newWinner.nBlockHeight = nBlockHeight;
|
||||
newWinner.vin = pmn->vin;
|
||||
|
||||
if(pmn->donationPercentage > 0 && (nHash % 100) <= (unsigned int)pmn->donationPercentage) {
|
||||
newWinner.payee = pmn->donationAddress;
|
||||
} else {
|
||||
newWinner.payee = GetScriptForDestination(pmn->pubkey.GetID());
|
||||
}
|
||||
|
||||
payeeSource = GetScriptForDestination(pmn->pubkey.GetID());
|
||||
|
||||
break; // we found active MN
|
||||
if(nBlockHeight <= nLastBlockHeight) return false;
|
||||
|
||||
/* if(budget.IsBudgetPaymentBlock(nBlockHeight)){
|
||||
//is budget payment block
|
||||
std::vector<CBudgetProposal*> budget = budget.GetBudget();
|
||||
BOOST_FOREACH(CBudgetProposal* prop, budget){
|
||||
if(prop.GetAllocated() > 0){
|
||||
newWinner.AddPayee(prop.GetPayee(), prop.GetAllocated());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
CMasternodePaymentWinner newWinner(activeMasternode.vin);
|
||||
int nMinimumAge = mnodeman.CountEnabled();
|
||||
CScript payeeSource;
|
||||
|
||||
CBlockIndex* pindexPrev = chainActive.Tip();
|
||||
if(pindexPrev == NULL) return false;
|
||||
CAmount blockValue = GetBlockValue(pindexPrev->nBits, pindexPrev->nHeight, 0);
|
||||
CAmount masternodePayment = GetMasternodePayment(pindexPrev->nHeight+1, blockValue);
|
||||
|
||||
uint256 hash;
|
||||
if(!GetBlockHash(hash, nBlockHeight-10)) return false;
|
||||
unsigned int nHash;
|
||||
memcpy(&nHash, &hash, 2);
|
||||
|
||||
LogPrintf(" ProcessBlock Start nHeight %d. \n", nBlockHeight);
|
||||
|
||||
std::vector<CTxIn> vecLastPayments;
|
||||
BOOST_REVERSE_FOREACH(CMasternodePaymentWinner& winner, vWinning)
|
||||
{
|
||||
//if we already have the same vin - we have one full payment cycle, break
|
||||
if(vecLastPayments.size() > (unsigned int)nMinimumAge) break;
|
||||
vecLastPayments.push_back(winner.vin);
|
||||
}
|
||||
|
||||
// pay to the oldest MN that still had no payment but its input is old enough and it was active long enough
|
||||
CMasternode *pmn = mnodeman.FindOldestNotInVec(vecLastPayments, nMinimumAge);
|
||||
if(pmn != NULL)
|
||||
{
|
||||
LogPrintf(" Found by FindOldestNotInVec \n");
|
||||
|
||||
newWinner.nBlockHeight = nBlockHeight;
|
||||
|
||||
CScript payee;
|
||||
if(pmn->donationPercentage > 0 && (nHash % 100) <= (unsigned int)pmn->donationPercentage) {
|
||||
payee = pmn->donationAddress;
|
||||
} else {
|
||||
payee = GetScriptForDestination(pmn->pubkey.GetID());
|
||||
}
|
||||
newWinner.AddPayee(payee, masternodePayment);
|
||||
}
|
||||
|
||||
//if we can't find new MN to get paid, pick first active MN counting back from the end of vecLastPayments list
|
||||
if(newWinner.nBlockHeight == 0 && nMinimumAge > 0)
|
||||
{
|
||||
LogPrintf(" Find by reverse \n");
|
||||
|
||||
BOOST_REVERSE_FOREACH(CTxIn& vinLP, vecLastPayments)
|
||||
{
|
||||
CMasternode* pmn = mnodeman.Find(vinLP);
|
||||
if(pmn != NULL)
|
||||
{
|
||||
pmn->Check();
|
||||
if(!pmn->IsEnabled()) continue;
|
||||
if(pmn->SecondsSincePayment() < 60*60*24) continue;
|
||||
|
||||
newWinner.nBlockHeight = nBlockHeight;
|
||||
|
||||
CScript payee;
|
||||
if(pmn->donationPercentage > 0 && (nHash % 100) <= (unsigned int)pmn->donationPercentage) {
|
||||
payee = pmn->donationAddress;
|
||||
} else {
|
||||
payee = GetScriptForDestination(pmn->pubkey.GetID());
|
||||
}
|
||||
newWinner.AddPayee(payee, masternodePayment);
|
||||
|
||||
break; // we found active MN
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(newWinner.nBlockHeight == 0) return false;
|
||||
|
||||
CTxDestination address1;
|
||||
ExtractDestination(newWinner.payee, address1);
|
||||
CBitcoinAddress address2(address1);
|
||||
|
||||
CTxDestination address3;
|
||||
ExtractDestination(payeeSource, address3);
|
||||
CBitcoinAddress address4(address3);
|
||||
|
||||
LogPrintf("Winner payee %s nHeight %d vin source %s. \n", address2.ToString().c_str(), newWinner.nBlockHeight, address4.ToString().c_str());
|
||||
}
|
||||
|
||||
if(newWinner.nBlockHeight == 0) return false;
|
||||
std::string errorMessage;
|
||||
CPubKey pubKeyMasternode;
|
||||
CKey keyMasternode;
|
||||
|
||||
CTxDestination address1;
|
||||
ExtractDestination(newWinner.payee, address1);
|
||||
CBitcoinAddress address2(address1);
|
||||
if(!darkSendSigner.SetKey(strMasterNodePrivKey, errorMessage, keyMasternode, pubKeyMasternode))
|
||||
{
|
||||
LogPrintf("CMasternodePayments::ProcessBlock() - Error upon calling SetKey: %s\n", errorMessage.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
CTxDestination address3;
|
||||
ExtractDestination(payeeSource, address3);
|
||||
CBitcoinAddress address4(address3);
|
||||
|
||||
LogPrintf("Winner payee %s nHeight %d vin source %s. \n", address2.ToString().c_str(), newWinner.nBlockHeight, address4.ToString().c_str());
|
||||
|
||||
if(Sign(newWinner))
|
||||
if(Sign(keyMasternode, pubKeyMasternode))
|
||||
{
|
||||
if(AddWinningMasternode(newWinner))
|
||||
{
|
||||
Relay(newWinner);
|
||||
newWinner.Relay();
|
||||
nLastBlockHeight = nBlockHeight;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void CMasternodePayments::Relay(CMasternodePaymentWinner& winner)
|
||||
void CMasternodePaymentWinner::Relay()
|
||||
{
|
||||
CInv inv(MSG_MASTERNODE_WINNER, winner.GetHash());
|
||||
CInv inv(MSG_MASTERNODE_WINNER, GetHash());
|
||||
|
||||
vector<CInv> vInv;
|
||||
vInv.push_back(inv);
|
||||
@ -329,30 +402,34 @@ void CMasternodePayments::Relay(CMasternodePaymentWinner& winner)
|
||||
}
|
||||
}
|
||||
|
||||
bool CMasternodePaymentWinner::SignatureValid()
|
||||
{
|
||||
|
||||
CMasternode* pmn = mnodeman.Find(vinMasternode);
|
||||
|
||||
if(pmn != NULL)
|
||||
{
|
||||
std::string strMessage = vinMasternode.prevout.ToStringShort() +
|
||||
boost::lexical_cast<std::string>(nBlockHeight) +
|
||||
payee.ToString();
|
||||
|
||||
|
||||
std::string errorMessage = "";
|
||||
if(!darkSendSigner.VerifyMessage(pmn->pubkey2, vchSig, strMessage, errorMessage)){
|
||||
return error("CMasternodePaymentWinner::SignatureValid() - Got bad Masternode address signature %s \n", vinMasternode.ToString().c_str());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void CMasternodePayments::Sync(CNode* node)
|
||||
{
|
||||
LOCK(cs_masternodepayments);
|
||||
|
||||
/*
|
||||
BOOST_FOREACH(CMasternodePaymentWinner& winner, vWinning)
|
||||
if(winner.nBlockHeight >= chainActive.Tip()->nHeight-10 && winner.nBlockHeight <= chainActive.Tip()->nHeight + 20)
|
||||
node->PushMessage("mnw", winner);
|
||||
}
|
||||
|
||||
|
||||
bool CMasternodePayments::SetPrivKey(std::string strPrivKey)
|
||||
{
|
||||
CMasternodePaymentWinner winner;
|
||||
|
||||
// Test signing successful, proceed
|
||||
strMasterPrivKey = strPrivKey;
|
||||
|
||||
Sign(winner);
|
||||
|
||||
if(CheckSignature(winner)){
|
||||
LogPrintf("CMasternodePayments::SetPrivKey - Successfully initialized as Masternode payments master\n");
|
||||
enabled = true;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
node->PushMessage("mnw", winner);*/
|
||||
}
|
@ -6,59 +6,147 @@
|
||||
#ifndef MASTERNODE_PAYMENTS_H
|
||||
#define MASTERNODE_PAYMENTS_H
|
||||
|
||||
#include "sync.h"
|
||||
#include "net.h"
|
||||
//#include "sync.h"
|
||||
//#include "net.h"
|
||||
#include "key.h"
|
||||
#include "util.h"
|
||||
#include "base58.h"
|
||||
//#include "util.h"
|
||||
//#include "base58.h"
|
||||
#include "main.h"
|
||||
#include "masternode.h"
|
||||
#include "masternode-pos.h"
|
||||
#include "timedata.h"
|
||||
//#include "masternode-pos.h"
|
||||
//#include "timedata.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
class CMasternodePayments;
|
||||
class CMasternodePaymentWinner;
|
||||
class CMasternodeBlockPayees;
|
||||
|
||||
extern CMasternodePayments masternodePayments;
|
||||
extern map<uint256, CMasternodePaymentWinner> mapSeenMasternodeVotes;
|
||||
extern std::map<uint256, CMasternodePaymentWinner> mapMasternodePayeeVotes;
|
||||
extern std::map<uint256, CMasternodeBlockPayees> mapMasternodeBlocks;
|
||||
|
||||
static const int MIN_MNPAYMENTS_PROTO_VERSION = 70066;
|
||||
#define MNPAYMENTS_SIGNATURES_REQUIRED 11
|
||||
#define MNPAYMENTS_SIGNATURES_TOTAL 20
|
||||
|
||||
void ProcessMessageMasternodePayments(CNode* pfrom, std::string& strCommand, CDataStream& vRecv);
|
||||
bool IsReferenceNode(CTxIn& vin);
|
||||
|
||||
class CMasternodePayee : public CTxOut
|
||||
{
|
||||
public:
|
||||
int nVotes;
|
||||
|
||||
// for storing the winning payments
|
||||
class CMasternodePaymentWinner
|
||||
CMasternodePayee() {
|
||||
scriptPubKey = CScript();
|
||||
nValue = 0;
|
||||
nVotes = 0;
|
||||
}
|
||||
|
||||
CMasternodePayee(CAmount nValue, CScript payee) {
|
||||
scriptPubKey = payee;
|
||||
nValue = nValue;
|
||||
nVotes = 0;
|
||||
}
|
||||
};
|
||||
|
||||
// Keep track of votes for payees from masternodes
|
||||
class CMasternodeBlockPayees
|
||||
{
|
||||
public:
|
||||
int nBlockHeight;
|
||||
CTxIn vin;
|
||||
CScript payee;
|
||||
std::vector<unsigned char> vchSig;
|
||||
uint64_t score;
|
||||
std::vector<CMasternodePayee> vecPayments;
|
||||
|
||||
CMasternodePaymentWinner() {
|
||||
CMasternodeBlockPayees(){
|
||||
nBlockHeight = 0;
|
||||
score = 0;
|
||||
vin = CTxIn();
|
||||
payee = CScript();
|
||||
vecPayments.clear();
|
||||
}
|
||||
CMasternodeBlockPayees(int nBlockHeightIn) {
|
||||
nBlockHeight = nBlockHeightIn;
|
||||
vecPayments.clear();
|
||||
}
|
||||
|
||||
uint256 GetHash(){
|
||||
uint256 n2 = HashX11(BEGIN(nBlockHeight), END(nBlockHeight));
|
||||
uint256 n3 = vin.prevout.hash > n2 ? (vin.prevout.hash - n2) : (n2 - vin.prevout.hash);
|
||||
void AddPayee(CScript payeeIn, int64_t nAmount, int nIncrement){
|
||||
BOOST_FOREACH(CMasternodePayee& payee, vecPayments){
|
||||
if(payee.scriptPubKey == payeeIn && payee.nValue == nAmount) {
|
||||
payee.nVotes += nIncrement;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
return n3;
|
||||
CMasternodePayee c((CAmount)nAmount, payeeIn);
|
||||
vecPayments.push_back(c);
|
||||
}
|
||||
|
||||
bool GetPayee(CScript& payee)
|
||||
{
|
||||
int nVotes = -1;
|
||||
BOOST_FOREACH(CMasternodePayee& p, vecPayments){
|
||||
if(p.nVotes > nVotes){
|
||||
payee = p.scriptPubKey;
|
||||
nVotes = p.nVotes;
|
||||
}
|
||||
}
|
||||
|
||||
return nVotes > -1;
|
||||
}
|
||||
|
||||
bool IsTransactionValid(const CTransaction& txNew);
|
||||
std::string GetRequiredPaymentsString();
|
||||
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
|
||||
READWRITE(nBlockHeight);
|
||||
READWRITE(vecPayments);
|
||||
}
|
||||
};
|
||||
|
||||
// for storing the winning payments
|
||||
class CMasternodePaymentWinner
|
||||
{
|
||||
public:
|
||||
CTxIn vinMasternode;
|
||||
|
||||
int nBlockHeight;
|
||||
CTxOut payee;
|
||||
std::vector<unsigned char> vchSig;
|
||||
|
||||
CMasternodePaymentWinner() {
|
||||
nBlockHeight = 0;
|
||||
vinMasternode = CTxIn();
|
||||
payee = CTxOut();
|
||||
}
|
||||
|
||||
CMasternodePaymentWinner(CTxIn vinIn) {
|
||||
nBlockHeight = 0;
|
||||
vinMasternode = vinIn;
|
||||
payee = CTxOut();
|
||||
}
|
||||
|
||||
uint256 GetHash(){
|
||||
return Hash(BEGIN(payee), END(payee));
|
||||
}
|
||||
|
||||
bool Sign(CKey& keyMasternode, CPubKey& pubKeyMasternode);
|
||||
bool IsValid();
|
||||
bool SignatureValid();
|
||||
void Relay();
|
||||
|
||||
void AddPayee(CScript payeeIn, int64_t nAmount){
|
||||
payee.scriptPubKey = payeeIn;
|
||||
payee.nValue = nAmount;
|
||||
}
|
||||
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
|
||||
READWRITE(vinMasternode);
|
||||
READWRITE(nBlockHeight);
|
||||
READWRITE(payee);
|
||||
READWRITE(vin);
|
||||
READWRITE(score);
|
||||
READWRITE(vchSig);
|
||||
}
|
||||
};
|
||||
@ -71,37 +159,29 @@ public:
|
||||
class CMasternodePayments
|
||||
{
|
||||
private:
|
||||
std::vector<CMasternodePaymentWinner> vWinning;
|
||||
int nSyncedFromPeer;
|
||||
std::string strMasterPrivKey;
|
||||
bool enabled;
|
||||
int nLastBlockHeight;
|
||||
|
||||
public:
|
||||
|
||||
CMasternodePayments() {
|
||||
enabled = false;
|
||||
nSyncedFromPeer = 0;
|
||||
nLastBlockHeight = 0;
|
||||
}
|
||||
|
||||
bool SetPrivKey(std::string strPrivKey);
|
||||
bool CheckSignature(CMasternodePaymentWinner& winner);
|
||||
bool Sign(CMasternodePaymentWinner& winner);
|
||||
|
||||
// Deterministically calculate a given "score" for a masternode depending on how close it's hash is
|
||||
// to the blockHeight. The further away they are the better, the furthest will win the election
|
||||
// and get paid this block
|
||||
//
|
||||
|
||||
uint64_t CalculateScore(uint256 blockHash, CTxIn& vin);
|
||||
bool GetWinningMasternode(int nBlockHeight, CTxIn& vinOut);
|
||||
bool AddWinningMasternode(CMasternodePaymentWinner& winner);
|
||||
bool ProcessBlock(int nBlockHeight);
|
||||
void Relay(CMasternodePaymentWinner& winner);
|
||||
|
||||
void Sync(CNode* node);
|
||||
void CleanPaymentList();
|
||||
int LastPayment(CMasternode& mn);
|
||||
|
||||
bool GetBlockPayee(int nBlockHeight, CScript& payee, CTxIn& vin);
|
||||
bool GetBlockPayee(int nBlockHeight, CScript& payee);
|
||||
bool IsTransactionValid(const CTransaction& txNew, int nBlockHeight);
|
||||
|
||||
void ProcessMessageMasternodePayments(CNode* pfrom, std::string& strCommand, CDataStream& vRecv);
|
||||
std::string GetRequiredPaymentsString(int nBlockHeight);
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
@ -15,7 +15,6 @@ map<uint256, int> mapSeenMasternodeScanningErrors;
|
||||
// cache block hashes as we calculate them
|
||||
std::map<int64_t, uint256> mapCacheBlockHashes;
|
||||
|
||||
|
||||
struct CompareValueOnly
|
||||
{
|
||||
bool operator()(const pair<int64_t, CTxIn>& t1,
|
||||
@ -83,10 +82,9 @@ CMasternode::CMasternode()
|
||||
nLastDsq = 0;
|
||||
donationAddress = CScript();
|
||||
donationPercentage = 0;
|
||||
nVote = 0;
|
||||
lastVote = 0;
|
||||
nScanningErrorCount = 0;
|
||||
nLastScanningErrorBlockHeight = 0;
|
||||
nVotedTimes = 0;
|
||||
|
||||
//mark last paid as current for new entries
|
||||
nLastPaid = GetAdjustedTime();
|
||||
@ -112,11 +110,10 @@ CMasternode::CMasternode(const CMasternode& other)
|
||||
nLastDsq = other.nLastDsq;
|
||||
donationAddress = other.donationAddress;
|
||||
donationPercentage = other.donationPercentage;
|
||||
nVote = other.nVote;
|
||||
lastVote = other.lastVote;
|
||||
nScanningErrorCount = other.nScanningErrorCount;
|
||||
nLastScanningErrorBlockHeight = other.nLastScanningErrorBlockHeight;
|
||||
nLastPaid = other.nLastPaid;
|
||||
nVotedTimes = other.nVotedTimes;
|
||||
}
|
||||
|
||||
CMasternode::CMasternode(CService newAddr, CTxIn newVin, CPubKey newPubkey, std::vector<unsigned char> newSig, int64_t newSigTime, CPubKey newPubkey2, int protocolVersionIn, CScript newDonationAddress, int newDonationPercentage)
|
||||
@ -139,11 +136,10 @@ CMasternode::CMasternode(CService newAddr, CTxIn newVin, CPubKey newPubkey, std:
|
||||
nLastDsq = 0;
|
||||
donationAddress = newDonationAddress;
|
||||
donationPercentage = newDonationPercentage;
|
||||
nVote = 0;
|
||||
lastVote = 0;
|
||||
nScanningErrorCount = 0;
|
||||
nLastScanningErrorBlockHeight = 0;
|
||||
nLastPaid = GetAdjustedTime();
|
||||
nVotedTimes = 0;
|
||||
}
|
||||
|
||||
CMasternode::CMasternode(const CMasternodeBroadcast& mnb)
|
||||
@ -166,11 +162,10 @@ CMasternode::CMasternode(const CMasternodeBroadcast& mnb)
|
||||
nLastDsq = 0;
|
||||
donationAddress = mnb.donationAddress;
|
||||
donationPercentage = mnb.donationPercentage;
|
||||
nVote = 0;
|
||||
lastVote = 0;
|
||||
nScanningErrorCount = 0;
|
||||
nLastScanningErrorBlockHeight = 0;
|
||||
nLastPaid = mnb.nLastPaid;
|
||||
nVotedTimes = 0;
|
||||
}
|
||||
|
||||
//
|
||||
@ -272,8 +267,6 @@ CMasternodeBroadcast::CMasternodeBroadcast()
|
||||
nLastDsq = 0;
|
||||
donationAddress = CScript();
|
||||
donationPercentage = 0;
|
||||
nVote = 0;
|
||||
lastVote = 0;
|
||||
nScanningErrorCount = 0;
|
||||
nLastScanningErrorBlockHeight = 0;
|
||||
|
||||
@ -300,8 +293,6 @@ CMasternodeBroadcast::CMasternodeBroadcast(CService newAddr, CTxIn newVin, CPubK
|
||||
nLastDsq = 0;
|
||||
donationAddress = newDonationAddress;
|
||||
donationPercentage = newDonationPercentage;
|
||||
nVote = 0;
|
||||
lastVote = 0;
|
||||
nScanningErrorCount = 0;
|
||||
nLastScanningErrorBlockHeight = 0;
|
||||
nLastPaid = GetAdjustedTime();
|
||||
@ -326,8 +317,6 @@ CMasternodeBroadcast::CMasternodeBroadcast(const CMasternode& other)
|
||||
nLastDsq = other.nLastDsq;
|
||||
donationAddress = other.donationAddress;
|
||||
donationPercentage = other.donationPercentage;
|
||||
nVote = other.nVote;
|
||||
lastVote = other.lastVote;
|
||||
nScanningErrorCount = other.nScanningErrorCount;
|
||||
nLastScanningErrorBlockHeight = other.nLastScanningErrorBlockHeight;
|
||||
nLastPaid = other.nLastPaid;
|
||||
@ -481,9 +470,14 @@ bool CMasternodeBroadcast::CheckInputsAndAdd(int& nDoS, bool fRequested)
|
||||
|
||||
void CMasternodeBroadcast::Relay(bool fRequested)
|
||||
{
|
||||
CInv inv(MSG_MASTERNODE_ANNOUNCE, GetHash());
|
||||
|
||||
vector<CInv> vInv;
|
||||
vInv.push_back(inv);
|
||||
LOCK(cs_vNodes);
|
||||
BOOST_FOREACH(CNode* pnode, vNodes)
|
||||
pnode->PushMessage("mnb", (*this), fRequested);
|
||||
BOOST_FOREACH(CNode* pnode, vNodes){
|
||||
pnode->PushMessage("inv", vInv);
|
||||
}
|
||||
}
|
||||
|
||||
bool CMasternodeBroadcast::Sign(CKey& keyCollateralAddress)
|
||||
@ -591,9 +585,12 @@ bool CMasternodePing::CheckAndUpdate(int& nDos)
|
||||
|
||||
void CMasternodePing::Relay()
|
||||
{
|
||||
//const CTxIn vin, const std::vector<unsigned char> vchSig, const int64_t nNow, const bool stop
|
||||
CInv inv(MSG_MASTERNODE_PING, GetHash());
|
||||
|
||||
vector<CInv> vInv;
|
||||
vInv.push_back(inv);
|
||||
LOCK(cs_vNodes);
|
||||
BOOST_FOREACH(CNode* pnode, vNodes)
|
||||
pnode->PushMessage("mnp", (*this));
|
||||
BOOST_FOREACH(CNode* pnode, vNodes){
|
||||
pnode->PushMessage("inv", vInv);
|
||||
}
|
||||
}
|
@ -77,11 +77,10 @@ public:
|
||||
int64_t nLastDsq; //the dsq count from the last dsq broadcast of this node
|
||||
CScript donationAddress;
|
||||
int donationPercentage;
|
||||
int nVote;
|
||||
int64_t lastVote;
|
||||
int nScanningErrorCount;
|
||||
int nLastScanningErrorBlockHeight;
|
||||
int64_t nLastPaid;
|
||||
int nVotedTimes;
|
||||
|
||||
CMasternode();
|
||||
CMasternode(const CMasternode& other);
|
||||
@ -113,11 +112,10 @@ public:
|
||||
swap(first.nLastDsq, second.nLastDsq);
|
||||
swap(first.donationAddress, second.donationAddress);
|
||||
swap(first.donationPercentage, second.donationPercentage);
|
||||
swap(first.nVote, second.nVote);
|
||||
swap(first.lastVote, second.lastVote);
|
||||
swap(first.nScanningErrorCount, second.nScanningErrorCount);
|
||||
swap(first.nLastScanningErrorBlockHeight, second.nLastScanningErrorBlockHeight);
|
||||
swap(first.nLastPaid, second.nLastPaid);
|
||||
swap(first.nVotedTimes, second.nVotedTimes);
|
||||
}
|
||||
|
||||
CMasternode& operator=(CMasternode from)
|
||||
@ -160,10 +158,9 @@ public:
|
||||
READWRITE(unitTest);
|
||||
READWRITE(allowFreeTx);
|
||||
READWRITE(nLastDsq);
|
||||
READWRITE(nVote);
|
||||
READWRITE(lastVote);
|
||||
READWRITE(nScanningErrorCount);
|
||||
READWRITE(nLastScanningErrorBlockHeight);
|
||||
READWRITE(nVotedTimes);
|
||||
}
|
||||
|
||||
int64_t SecondsSincePayment()
|
||||
@ -282,9 +279,14 @@ public:
|
||||
READWRITE(protocolVersion);
|
||||
READWRITE(donationAddress);
|
||||
READWRITE(donationPercentage);
|
||||
READWRITE(nLastPaid);
|
||||
}
|
||||
|
||||
uint256 GetHash(){
|
||||
return Hash(
|
||||
BEGIN(sigTime), END(sigTime),
|
||||
BEGIN(pubkey), END(pubkey)
|
||||
);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@ -316,7 +318,10 @@ public:
|
||||
|
||||
bool CheckAndUpdate(int& nDos);
|
||||
bool Sign(CKey& keyMasternode, CPubKey& pubKeyMasternode);
|
||||
void Relay();
|
||||
void Relay();
|
||||
|
||||
uint256 GetHash(){
|
||||
return Hash(BEGIN(vin), END(vin), BEGIN(sigTime), END(sigTime));
|
||||
}
|
||||
};
|
||||
#endif
|
@ -16,6 +16,12 @@ CCriticalSection cs_process_message;
|
||||
/** Masternode manager */
|
||||
CMasternodeMan mnodeman;
|
||||
|
||||
// Keep track of all broadcasts I've seen
|
||||
map<uint256, CMasternodeBroadcast> mapSeenMasternodeBroadcast;
|
||||
|
||||
// Keep track of all pings I've seen
|
||||
map<uint256, CMasternodePing> mapSeenMasternodePing;
|
||||
|
||||
struct CompareValueOnly
|
||||
{
|
||||
bool operator()(const pair<int64_t, CTxIn>& t1,
|
||||
@ -385,6 +391,12 @@ CMasternode *CMasternodeMan::FindRandom()
|
||||
return &vMasternodes[GetRandInt(vMasternodes.size())];
|
||||
}
|
||||
|
||||
void CMasternodeMan::DecrementVotedTimes()
|
||||
{
|
||||
BOOST_FOREACH(CMasternode& mn, vMasternodes)
|
||||
if(--mn.nVotedTimes < 0) mn.nVotedTimes = 0;
|
||||
}
|
||||
|
||||
CMasternode* CMasternodeMan::GetCurrentMasterNode(int mod, int64_t nBlockHeight, int minProtocol)
|
||||
{
|
||||
unsigned int score = 0;
|
||||
@ -550,6 +562,9 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData
|
||||
bool fRequested; //specifically requested?
|
||||
vRecv >> mnb >> fRequested;
|
||||
|
||||
if(mapSeenMasternodeBroadcast.count(mnb.GetHash())) return; //seen
|
||||
mapSeenMasternodeBroadcast[mnb.GetHash()] = mnb;
|
||||
|
||||
int nDoS = 0;
|
||||
if(!mnb.CheckAndUpdate(nDoS, fRequested)){
|
||||
|
||||
@ -589,7 +604,8 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData
|
||||
CMasternodePing mnp;
|
||||
vRecv >> mnp;
|
||||
|
||||
if(fDebug) LogPrintf("mnping - Received: vin: %s sigTime: %lld\n", mnp.vin.ToString().c_str(), mnp.sigTime);
|
||||
if(mapSeenMasternodePing.count(mnp.GetHash())) return; //seen
|
||||
mapSeenMasternodePing[mnp.GetHash()] = mnp;
|
||||
|
||||
int nDoS = 0;
|
||||
if(!mnp.CheckAndUpdate(nDoS))
|
||||
@ -617,40 +633,6 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData
|
||||
int64_t askAgain = GetTime() + MASTERNODE_MIN_MNP_SECONDS;
|
||||
mWeAskedForMasternodeListEntry[mnp.vin.prevout] = askAgain;
|
||||
|
||||
} else if (strCommand == "mvote") { //Masternode Vote
|
||||
|
||||
CTxIn vin;
|
||||
vector<unsigned char> vchSig;
|
||||
int nVote;
|
||||
vRecv >> vin >> vchSig >> nVote;
|
||||
|
||||
// see if we have this Masternode
|
||||
CMasternode* pmn = this->Find(vin);
|
||||
if(pmn != NULL)
|
||||
{
|
||||
if((GetAdjustedTime() - pmn->lastVote) > (60*60))
|
||||
{
|
||||
std::string strMessage = vin.ToString() + boost::lexical_cast<std::string>(nVote);
|
||||
|
||||
std::string errorMessage = "";
|
||||
if(!darkSendSigner.VerifyMessage(pmn->pubkey2, vchSig, strMessage, errorMessage))
|
||||
{
|
||||
LogPrintf("mvote - Got bad Masternode address signature %s \n", vin.ToString().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
pmn->nVote = nVote;
|
||||
pmn->lastVote = GetAdjustedTime();
|
||||
|
||||
//send to all peers
|
||||
LOCK(cs_vNodes);
|
||||
BOOST_FOREACH(CNode* pnode, vNodes)
|
||||
pnode->PushMessage("mvote", vin, vchSig, nVote);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
} else if (strCommand == "dseg") { //Get Masternode list or specific entry
|
||||
|
||||
CTxIn vin;
|
||||
|
@ -20,6 +20,12 @@ using namespace std;
|
||||
|
||||
class CMasternodeMan;
|
||||
|
||||
// Keep track of all broadcasts I've seen
|
||||
extern map<uint256, CMasternodeBroadcast> mapSeenMasternodeBroadcast;
|
||||
|
||||
// Keep track of all pings I've seen
|
||||
extern map<uint256, CMasternodePing> mapSeenMasternodePing;
|
||||
|
||||
extern CMasternodeMan mnodeman;
|
||||
void DumpMasternodes();
|
||||
|
||||
@ -108,6 +114,9 @@ public:
|
||||
/// Find a random entry
|
||||
CMasternode* FindRandom();
|
||||
|
||||
/// Decrement all masternode nVotedTimes, called 1/6 blocks (allowing for 100 votes each day)
|
||||
void DecrementVotedTimes();
|
||||
|
||||
/// Get the current winner for this block
|
||||
CMasternode* GetCurrentMasterNode(int mod=1, int64_t nBlockHeight=0, int minProtocol=0);
|
||||
|
||||
|
@ -141,9 +141,8 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
|
||||
|
||||
if(bMasterNodePayment) {
|
||||
bool hasPayment = true;
|
||||
CTxIn vin;
|
||||
//spork
|
||||
if(!masternodePayments.GetBlockPayee(pindexPrev->nHeight+1, pblock->payee, vin)){
|
||||
if(!masternodePayments.GetBlockPayee(pindexPrev->nHeight+1, pblock->payee)){
|
||||
//no masternode detected
|
||||
CMasternode* winningNode = mnodeman.GetCurrentMasterNode(1);
|
||||
if(winningNode){
|
||||
|
@ -108,6 +108,7 @@ public:
|
||||
CBlockHeader::SetNull();
|
||||
vtx.clear();
|
||||
vMerkleTree.clear();
|
||||
payee = CScript();
|
||||
}
|
||||
|
||||
CBlockHeader GetBlockHeader() const
|
||||
|
@ -23,6 +23,11 @@ static const char* ppszTypeName[] =
|
||||
"tx lock vote",
|
||||
"spork",
|
||||
"masternode winner",
|
||||
"masternode scan",
|
||||
"masternode vote",
|
||||
"masternode quorum",
|
||||
"masternode announce",
|
||||
"masternode ping",
|
||||
"unknown",
|
||||
"unknown",
|
||||
"unknown",
|
||||
|
@ -151,7 +151,11 @@ enum {
|
||||
MSG_TXLOCK_VOTE,
|
||||
MSG_SPORK,
|
||||
MSG_MASTERNODE_WINNER,
|
||||
MSG_MASTERNODE_SCANNING_ERROR
|
||||
MSG_MASTERNODE_SCANNING_ERROR,
|
||||
MSG_MASTERNODE_VOTE,
|
||||
MSG_MASTERNODE_QUORUM,
|
||||
MSG_MASTERNODE_ANNOUNCE,
|
||||
MSG_MASTERNODE_PING
|
||||
};
|
||||
|
||||
#endif // BITCOIN_PROTOCOL_H
|
||||
|
237
src/rpcmasternode-budget.cpp
Normal file
237
src/rpcmasternode-budget.cpp
Normal file
@ -0,0 +1,237 @@
|
||||
// Copyright (c) 2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2012 The Bitcoin developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include "main.h"
|
||||
#include "db.h"
|
||||
#include "init.h"
|
||||
#include "activemasternode.h"
|
||||
#include "masternodeman.h"
|
||||
#include "masternode-payments.h"
|
||||
#include "masternode-budget.h"
|
||||
#include "masternodeconfig.h"
|
||||
#include "rpcserver.h"
|
||||
#include "utilmoneystr.h"
|
||||
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <fstream>
|
||||
using namespace json_spirit;
|
||||
using namespace std;
|
||||
|
||||
Value mnbudget(const Array& params, bool fHelp)
|
||||
{
|
||||
string strCommand;
|
||||
if (params.size() >= 1)
|
||||
strCommand = params[0].get_str();
|
||||
|
||||
if (fHelp ||
|
||||
(strCommand != "vote-many" && strCommand != "vote" && strCommand != "getvotes" && strCommand != "getinfo"))
|
||||
throw runtime_error(
|
||||
"mnbudget \"command\"... ( \"passphrase\" )\n"
|
||||
"Vote or show current budgets\n"
|
||||
"\nAvailable commands:\n"
|
||||
" vote-many - Vote on a Dash initiative\n"
|
||||
" vote - Vote on a Dash initiative\n"
|
||||
" getvotes - Show current masternode budgets\n"
|
||||
" getinfo - Show current masternode budgets\n"
|
||||
);
|
||||
|
||||
if(strCommand == "vote-many")
|
||||
{
|
||||
/* std::vector<CMasternodeConfig::CMasternodeEntry> mnEntries;
|
||||
mnEntries = masternodeConfig.getEntries();
|
||||
|
||||
if (params.size() != 5)
|
||||
throw runtime_error("Correct usage of vote-many is 'mnbudget vote-many PROPOSAL-NAME BLOCKSTART BLOCKEND XADDRESS AMOUNT YEA|NAY'");
|
||||
|
||||
std::string strProposalName = params[1].get_str();
|
||||
if(strProposalName.size() > 20)
|
||||
return "Invalid proposal name, limit of 20 characters.";
|
||||
|
||||
int nBlockStart = params[2].get_int();
|
||||
int nBlockEnd = params[3].get_int();
|
||||
CBitcoinAddress address(params[4].get_str());
|
||||
if (!address.IsValid())
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Dash address");
|
||||
|
||||
CAmount nAmount = AmountFromValue(params[5]);
|
||||
std::string strVote = params[6].get_str().c_str();
|
||||
|
||||
if(strVote != "yes" && strVote != "no") return "You can only vote 'yes' or 'no'";
|
||||
int nVote = VOTE_ABSTAIN;
|
||||
if(strVote == "yes") nVote = VOTE_YES;
|
||||
if(strVote == "no") nVote = VOTE_NO;
|
||||
|
||||
int success = 0;
|
||||
int failed = 0;
|
||||
|
||||
Object resultObj;
|
||||
|
||||
BOOST_FOREACH(CMasternodeConfig::CMasternodeEntry mne, masternodeConfig.getEntries()) {
|
||||
std::string errorMessage;
|
||||
std::vector<unsigned char> vchMasterNodeSignature;
|
||||
std::string strMasterNodeSignMessage;
|
||||
|
||||
CPubKey pubKeyCollateralAddress;
|
||||
CKey keyCollateralAddress;
|
||||
CPubKey pubKeyMasternode;
|
||||
CKey keyMasternode;
|
||||
|
||||
if(!darkSendSigner.SetKey(mne.getPrivKey(), errorMessage, keyMasternode, pubKeyMasternode)){
|
||||
printf(" Error upon calling SetKey for %s\n", mne.getAlias().c_str());
|
||||
failed++;
|
||||
continue;
|
||||
}
|
||||
|
||||
CMasternode* pmn = mnodeman.Find(pubKeyMasternode);
|
||||
if(pmn == NULL)
|
||||
{
|
||||
printf("Can't find masternode by pubkey for %s\n", mne.getAlias().c_str());
|
||||
failed++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(!darkSendSigner.SetKey(strMasterNodePrivKey, errorMessage, keyMasternode, pubKeyMasternode))
|
||||
return(" Error upon calling SetKey");
|
||||
|
||||
CBudgetVote vote(pmn->vin, strProposalName, nBlockStart, nBlockEnd, address, nAmount, nVote);
|
||||
if(!vote.Sign(keyMasternode, pubKeyMasternode)){
|
||||
return "Failure to sign.";
|
||||
}
|
||||
|
||||
success++;
|
||||
vote.Relay();
|
||||
}
|
||||
|
||||
return("Voted successfully " + boost::lexical_cast<std::string>(success) + " time(s) and failed " + boost::lexical_cast<std::string>(failed) + " time(s).");*/
|
||||
}
|
||||
|
||||
if(strCommand == "vote")
|
||||
{
|
||||
/* std::vector<CMasternodeConfig::CMasternodeEntry> mnEntries;
|
||||
mnEntries = masternodeConfig.getEntries();
|
||||
|
||||
if (params.size() != 5)
|
||||
throw runtime_error("Correct usage of vote-many is 'mnbudget vote PROPOSAL-NAME BLOCKSTART BLOCKEND XADDRESS AMOUNT YEA|NAY'");
|
||||
|
||||
std::string strProposalName = params[1].get_str();
|
||||
|
||||
if(strProposalName.size() > 20)
|
||||
return "Invalid proposal name, limit of 20 characters.";
|
||||
|
||||
int nBlockStart = params[2].get_int();
|
||||
int nBlockEnd = params[3].get_int();
|
||||
CBitcoinAddress address(params[4].get_str());
|
||||
if (!address.IsValid())
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Dash address");
|
||||
|
||||
CAmount nAmount = AmountFromValue(params[5]);
|
||||
std::string strVote = params[6].get_str().c_str();
|
||||
|
||||
if(strVote != "yes" && strVote != "no") return "You can only vote 'yes' or 'no'";
|
||||
int nVote = VOTE_ABSTAIN;
|
||||
if(strVote == "yes") nVote = VOTE_YES;
|
||||
if(strVote == "no") nVote = VOTE_NO;
|
||||
|
||||
CPubKey pubKeyMasternode;
|
||||
CKey keyMasternode;
|
||||
std::string errorMessage;
|
||||
|
||||
if(!darkSendSigner.SetKey(strMasterNodePrivKey, errorMessage, keyMasternode, pubKeyMasternode))
|
||||
return(" Error upon calling SetKey");
|
||||
|
||||
CBudgetVote vote(activeMasternode.vin, strProposalName, nBlockStart, nBlockEnd, address, nAmount, nVote);
|
||||
if(!vote.Sign(keyMasternode, pubKeyMasternode)){
|
||||
return "Failure to sign.";
|
||||
}
|
||||
|
||||
vote.Relay();*/
|
||||
|
||||
}
|
||||
|
||||
if(strCommand == "show")
|
||||
{
|
||||
std::string strProposalName = params[1].get_str();
|
||||
|
||||
CBudgetProposal* prop = budget.Find(strProposalName);
|
||||
|
||||
if(prop == NULL) return "Unknown proposal name";
|
||||
|
||||
Object resultObj;
|
||||
int64_t nTotalAlloted = 0;
|
||||
|
||||
std::vector<CBudgetProposal*> winningProps = budget.GetBudget();
|
||||
BOOST_FOREACH(CBudgetProposal* prop, winningProps)
|
||||
{
|
||||
nTotalAlloted += prop->GetAlloted();
|
||||
|
||||
Object bObj;
|
||||
bObj.push_back(Pair("Name", prop->GetName().c_str()));
|
||||
bObj.push_back(Pair("BlockStart", (int64_t)prop->GetBlockStart()));
|
||||
bObj.push_back(Pair("BlockEnd", (int64_t)prop->GetBlockEnd()));
|
||||
bObj.push_back(Pair("PaymentAddress", prop->GetPaymentAddress()));
|
||||
bObj.push_back(Pair("Ratio", prop->GetRatio()));
|
||||
bObj.push_back(Pair("Yeas", (int64_t)prop->GetYeas()));
|
||||
bObj.push_back(Pair("Nays", (int64_t)prop->GetNays()));
|
||||
bObj.push_back(Pair("Abstains", (int64_t)prop->GetAbstains()));
|
||||
bObj.push_back(Pair("Alloted", (int64_t)prop->GetAlloted()));
|
||||
bObj.push_back(Pair("TotalBudgetAlloted", nTotalAlloted));
|
||||
resultObj.push_back(Pair("masternode", bObj));
|
||||
}
|
||||
|
||||
return resultObj;
|
||||
}
|
||||
|
||||
if(strCommand == "getinfo")
|
||||
{
|
||||
if (params.size() != 2)
|
||||
throw runtime_error("Correct usage of getinfo is 'mnbudget getinfo profilename'");
|
||||
|
||||
std::string strProposalName = params[1].get_str();
|
||||
|
||||
CBudgetProposal* prop = budget.Find(strProposalName);
|
||||
|
||||
if(prop == NULL) return "Unknown proposal name";
|
||||
|
||||
Object obj;
|
||||
obj.push_back(Pair("Name", prop->GetName().c_str()));
|
||||
obj.push_back(Pair("BlockStart", (int64_t)prop->GetBlockStart()));
|
||||
obj.push_back(Pair("BlockEnd", (int64_t)prop->GetBlockEnd()));
|
||||
obj.push_back(Pair("PaymentAddress", prop->GetPaymentAddress()));
|
||||
obj.push_back(Pair("Ratio", prop->GetRatio()));
|
||||
obj.push_back(Pair("Yeas", (int64_t)prop->GetYeas()));
|
||||
obj.push_back(Pair("Nays", (int64_t)prop->GetNays()));
|
||||
obj.push_back(Pair("Abstains", (int64_t)prop->GetAbstains()));
|
||||
obj.push_back(Pair("Alloted", (int64_t)prop->GetAlloted()));
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
if(strCommand == "getvotes")
|
||||
{
|
||||
|
||||
if (params.size() != 2)
|
||||
throw runtime_error("Correct usage of getvotes is 'mnbudget getinfo profilename'");
|
||||
|
||||
std::string strProposalName = params[1].get_str();
|
||||
|
||||
CBudgetProposal* prop = budget.Find(strProposalName);
|
||||
|
||||
if(prop == NULL) return "Unknown proposal name";
|
||||
|
||||
Object obj;
|
||||
|
||||
int c = 0;
|
||||
|
||||
/* map<uint256, CBudgetVote>::iterator it = prop->mapVotes.begin();
|
||||
for(it != prop->mapVotes.end()){
|
||||
obj.push_back(Pair((*it).second.nProposalName.c_str(), (*it).second.GetVoteString().c_str()));
|
||||
}*/
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
return Value::null;
|
||||
}
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "activemasternode.h"
|
||||
#include "masternodeman.h"
|
||||
#include "masternode-payments.h"
|
||||
#include "masternode-budget.h"
|
||||
#include "masternodeconfig.h"
|
||||
#include "rpcserver.h"
|
||||
#include "utilmoneystr.h"
|
||||
@ -126,8 +127,10 @@ Value masternode(const Array& params, bool fHelp)
|
||||
strCommand = params[0].get_str();
|
||||
|
||||
if (fHelp ||
|
||||
(strCommand != "start" && strCommand != "start-alias" && strCommand != "start-many" && strCommand != "stop" && strCommand != "stop-alias" && strCommand != "stop-many" && strCommand != "list" && strCommand != "list-conf" && strCommand != "count" && strCommand != "enforce"
|
||||
&& strCommand != "debug" && strCommand != "current" && strCommand != "winners" && strCommand != "genkey" && strCommand != "connect" && strCommand != "outputs" && strCommand != "vote-many" && strCommand != "vote"))
|
||||
(strCommand != "start" && strCommand != "start-alias" && strCommand != "start-many" && strCommand != "stop" && strCommand != "stop-alias" &&
|
||||
strCommand != "stop-many" && strCommand != "list" && strCommand != "list-conf" && strCommand != "count" && strCommand != "enforce" &&
|
||||
strCommand != "debug" && strCommand != "current" && strCommand != "winners" && strCommand != "genkey" && strCommand != "connect" &&
|
||||
strCommand != "outputs"))
|
||||
throw runtime_error(
|
||||
"masternode \"command\"... ( \"passphrase\" )\n"
|
||||
"Set of commands to execute masternode related actions\n"
|
||||
@ -147,8 +150,6 @@ Value masternode(const Array& params, bool fHelp)
|
||||
" list - Print list of all known masternodes (see masternodelist for more info)\n"
|
||||
" list-conf - Print masternode.conf in JSON format\n"
|
||||
" winners - Print list of masternode winners\n"
|
||||
" vote-many - Vote on a Dash initiative\n"
|
||||
" vote - Vote on a Dash initiative\n"
|
||||
);
|
||||
|
||||
if (strCommand == "list")
|
||||
@ -158,6 +159,11 @@ Value masternode(const Array& params, bool fHelp)
|
||||
return masternodelist(newParams, fHelp);
|
||||
}
|
||||
|
||||
if (strCommand == "budget")
|
||||
{
|
||||
return "Show budgets";
|
||||
}
|
||||
|
||||
if (strCommand == "count")
|
||||
{
|
||||
if (params.size() > 2){
|
||||
@ -387,28 +393,10 @@ Value masternode(const Array& params, bool fHelp)
|
||||
if (strCommand == "winners")
|
||||
{
|
||||
Object obj;
|
||||
std::string strMode = "addr";
|
||||
|
||||
if (params.size() >= 1) strMode = params[0].get_str();
|
||||
|
||||
for(int nHeight = chainActive.Tip()->nHeight-10; nHeight < chainActive.Tip()->nHeight+20; nHeight++)
|
||||
{
|
||||
CScript payee;
|
||||
CTxIn vin;
|
||||
if(masternodePayments.GetBlockPayee(nHeight, payee, vin)){
|
||||
CTxDestination address1;
|
||||
ExtractDestination(payee, address1);
|
||||
CBitcoinAddress address2(address1);
|
||||
|
||||
if(strMode == "addr")
|
||||
obj.push_back(Pair(boost::lexical_cast<std::string>(nHeight), address2.ToString().c_str()));
|
||||
|
||||
if(strMode == "vin")
|
||||
obj.push_back(Pair(boost::lexical_cast<std::string>(nHeight), vin.ToString().c_str()));
|
||||
|
||||
} else {
|
||||
obj.push_back(Pair(boost::lexical_cast<std::string>(nHeight), ""));
|
||||
}
|
||||
obj.push_back(Pair(boost::lexical_cast<std::string>(nHeight), masternodePayments.GetRequiredPaymentsString(nHeight).c_str()));
|
||||
}
|
||||
|
||||
return obj;
|
||||
@ -473,115 +461,6 @@ Value masternode(const Array& params, bool fHelp)
|
||||
|
||||
}
|
||||
|
||||
if(strCommand == "vote-many")
|
||||
{
|
||||
std::vector<CMasternodeConfig::CMasternodeEntry> mnEntries;
|
||||
mnEntries = masternodeConfig.getEntries();
|
||||
|
||||
if (params.size() != 2)
|
||||
throw runtime_error("You can only vote 'yea' or 'nay'");
|
||||
|
||||
std::string vote = params[1].get_str().c_str();
|
||||
if(vote != "yea" && vote != "nay") return "You can only vote 'yea' or 'nay'";
|
||||
int nVote = 0;
|
||||
if(vote == "yea") nVote = 1;
|
||||
if(vote == "nay") nVote = -1;
|
||||
|
||||
|
||||
int success = 0;
|
||||
int failed = 0;
|
||||
|
||||
Object resultObj;
|
||||
|
||||
BOOST_FOREACH(CMasternodeConfig::CMasternodeEntry mne, masternodeConfig.getEntries()) {
|
||||
std::string errorMessage;
|
||||
std::vector<unsigned char> vchMasterNodeSignature;
|
||||
std::string strMasterNodeSignMessage;
|
||||
|
||||
CPubKey pubKeyCollateralAddress;
|
||||
CKey keyCollateralAddress;
|
||||
CPubKey pubKeyMasternode;
|
||||
CKey keyMasternode;
|
||||
|
||||
if(!darkSendSigner.SetKey(mne.getPrivKey(), errorMessage, keyMasternode, pubKeyMasternode)){
|
||||
printf(" Error upon calling SetKey for %s\n", mne.getAlias().c_str());
|
||||
failed++;
|
||||
continue;
|
||||
}
|
||||
|
||||
CMasternode* pmn = mnodeman.Find(pubKeyMasternode);
|
||||
if(pmn == NULL)
|
||||
{
|
||||
printf("Can't find masternode by pubkey for %s\n", mne.getAlias().c_str());
|
||||
failed++;
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string strMessage = pmn->vin.ToString() + boost::lexical_cast<std::string>(nVote);
|
||||
|
||||
if(!darkSendSigner.SignMessage(strMessage, errorMessage, vchMasterNodeSignature, keyMasternode)){
|
||||
printf(" Error upon calling SignMessage for %s\n", mne.getAlias().c_str());
|
||||
failed++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(!darkSendSigner.VerifyMessage(pubKeyMasternode, vchMasterNodeSignature, strMessage, errorMessage)){
|
||||
printf(" Error upon calling VerifyMessage for %s\n", mne.getAlias().c_str());
|
||||
failed++;
|
||||
continue;
|
||||
}
|
||||
|
||||
success++;
|
||||
|
||||
//send to all peers
|
||||
LOCK(cs_vNodes);
|
||||
BOOST_FOREACH(CNode* pnode, vNodes)
|
||||
pnode->PushMessage("mvote", pmn->vin, vchMasterNodeSignature, nVote);
|
||||
}
|
||||
|
||||
return("Voted successfully " + boost::lexical_cast<std::string>(success) + " time(s) and failed " + boost::lexical_cast<std::string>(failed) + " time(s).");
|
||||
}
|
||||
|
||||
if(strCommand == "vote")
|
||||
{
|
||||
std::vector<CMasternodeConfig::CMasternodeEntry> mnEntries;
|
||||
mnEntries = masternodeConfig.getEntries();
|
||||
|
||||
if (params.size() != 2)
|
||||
throw runtime_error("You can only vote 'yea' or 'nay'");
|
||||
|
||||
std::string vote = params[1].get_str().c_str();
|
||||
if(vote != "yea" && vote != "nay") return "You can only vote 'yea' or 'nay'";
|
||||
int nVote = 0;
|
||||
if(vote == "yea") nVote = 1;
|
||||
if(vote == "nay") nVote = -1;
|
||||
|
||||
// Choose coins to use
|
||||
CPubKey pubKeyCollateralAddress;
|
||||
CKey keyCollateralAddress;
|
||||
CPubKey pubKeyMasternode;
|
||||
CKey keyMasternode;
|
||||
|
||||
std::string errorMessage;
|
||||
std::vector<unsigned char> vchMasterNodeSignature;
|
||||
std::string strMessage = activeMasternode.vin.ToString() + boost::lexical_cast<std::string>(nVote);
|
||||
|
||||
if(!darkSendSigner.SetKey(strMasterNodePrivKey, errorMessage, keyMasternode, pubKeyMasternode))
|
||||
return(" Error upon calling SetKey");
|
||||
|
||||
if(!darkSendSigner.SignMessage(strMessage, errorMessage, vchMasterNodeSignature, keyMasternode))
|
||||
return(" Error upon calling SignMessage");
|
||||
|
||||
if(!darkSendSigner.VerifyMessage(pubKeyMasternode, vchMasterNodeSignature, strMessage, errorMessage))
|
||||
return(" Error upon calling VerifyMessage");
|
||||
|
||||
//send to all peers
|
||||
LOCK(cs_vNodes);
|
||||
BOOST_FOREACH(CNode* pnode, vNodes)
|
||||
pnode->PushMessage("mvote", activeMasternode.vin, vchMasterNodeSignature, nVote);
|
||||
|
||||
}
|
||||
|
||||
return Value::null;
|
||||
}
|
||||
|
||||
@ -618,8 +497,6 @@ Value masternodelist(const Array& params, bool fHelp)
|
||||
" status - Print masternode status: ENABLED / EXPIRED / VIN_SPENT / REMOVE / POS_ERROR\n"
|
||||
" (can be additionally filtered, partial match)\n"
|
||||
" addr - Print ip address associated with a masternode (can be additionally filtered, partial match)\n"
|
||||
" votes - Print all masternode votes for a Dash initiative (can be additionally filtered,\n"
|
||||
" partial match)\n"
|
||||
" lastpaid - The last time a node was paid on the network\n"
|
||||
);
|
||||
}
|
||||
@ -708,18 +585,6 @@ Value masternodelist(const Array& params, bool fHelp)
|
||||
if(strFilter !="" && mn.vin.prevout.hash.ToString().find(strFilter) == string::npos &&
|
||||
strVin.find(strFilter) == string::npos) continue;
|
||||
obj.push_back(Pair(strVin, mn.addr.ToString().c_str()));
|
||||
} else if(strMode == "votes"){
|
||||
std::string strStatus = "ABSTAIN";
|
||||
|
||||
//voting lasts 7 days, ignore the last vote if it was older than that
|
||||
if((GetAdjustedTime() - mn.lastVote) < (60*60*8))
|
||||
{
|
||||
if(mn.nVote == -1) strStatus = "NAY";
|
||||
if(mn.nVote == 1) strStatus = "YEA";
|
||||
}
|
||||
|
||||
if(strFilter !="" && (strVin.find(strFilter) == string::npos && strStatus.find(strFilter) == string::npos)) continue;
|
||||
obj.push_back(Pair(strVin, strStatus.c_str()));
|
||||
} else if(strMode == "lastpaid"){
|
||||
if(strFilter !="" && mn.vin.prevout.hash.ToString().find(strFilter) == string::npos &&
|
||||
strVin.find(strFilter) == string::npos) continue;
|
@ -311,6 +311,7 @@ static const CRPCCommand vRPCCommands[] =
|
||||
/* Dash features */
|
||||
{ "dash", "spork", &spork, true, false, false },
|
||||
{ "dash", "masternode", &masternode, true, false, true },
|
||||
{ "dash", "mnbudget", &mnbudget, true, false, false },
|
||||
{ "dash", "masternodelist", &masternodelist, true, false, false },
|
||||
#ifdef ENABLE_WALLET
|
||||
{ "dash", "darksend", &darksend, false, false, true },
|
||||
|
@ -230,6 +230,7 @@ extern json_spirit::Value darksend(const json_spirit::Array& params, bool fHelp)
|
||||
extern json_spirit::Value spork(const json_spirit::Array& params, bool fHelp);
|
||||
extern json_spirit::Value masternode(const json_spirit::Array& params, bool fHelp);
|
||||
extern json_spirit::Value masternodelist(const json_spirit::Array& params, bool fHelp);
|
||||
extern json_spirit::Value mnbudget(const json_spirit::Array& params, bool fHelp);
|
||||
|
||||
// in rest.cpp
|
||||
extern bool HTTPReq_REST(AcceptedConnection *conn,
|
||||
|
Loading…
Reference in New Issue
Block a user