Merge branch 'v0.12.0.x'

This commit is contained in:
Evan Duffield 2015-08-29 19:25:38 -07:00
commit afa37a8442
10 changed files with 90 additions and 167 deletions

View File

@ -3,7 +3,7 @@ AC_PREREQ([2.60])
define(_CLIENT_VERSION_MAJOR, 0) define(_CLIENT_VERSION_MAJOR, 0)
define(_CLIENT_VERSION_MINOR, 12) define(_CLIENT_VERSION_MINOR, 12)
define(_CLIENT_VERSION_REVISION, 0) define(_CLIENT_VERSION_REVISION, 0)
define(_CLIENT_VERSION_BUILD, 50) define(_CLIENT_VERSION_BUILD, 51)
define(_CLIENT_VERSION_IS_RELEASE, true) define(_CLIENT_VERSION_IS_RELEASE, true)
define(_COPYRIGHT_YEAR, 2015) define(_COPYRIGHT_YEAR, 2015)
AC_INIT([Dash Core],[_CLIENT_VERSION_MAJOR._CLIENT_VERSION_MINOR._CLIENT_VERSION_REVISION],[info@dashpay.io],[dash]) AC_INIT([Dash Core],[_CLIENT_VERSION_MAJOR._CLIENT_VERSION_MINOR._CLIENT_VERSION_REVISION],[info@dashpay.io],[dash])

View File

@ -5,6 +5,7 @@ EXTRA_LIBRARIES += qt/libbitcoinqt.a
QT_TS = \ QT_TS = \
qt/locale/dash_bg.ts \ qt/locale/dash_bg.ts \
qt/locale/dash_de.ts \ qt/locale/dash_de.ts \
qt/locale/dash_en.ts \
qt/locale/dash_es.ts \ qt/locale/dash_es.ts \
qt/locale/dash_fi.ts \ qt/locale/dash_fi.ts \
qt/locale/dash_fr.ts \ qt/locale/dash_fr.ts \

View File

@ -17,7 +17,7 @@
#define CLIENT_VERSION_MAJOR 0 #define CLIENT_VERSION_MAJOR 0
#define CLIENT_VERSION_MINOR 12 #define CLIENT_VERSION_MINOR 12
#define CLIENT_VERSION_REVISION 0 #define CLIENT_VERSION_REVISION 0
#define CLIENT_VERSION_BUILD 50 #define CLIENT_VERSION_BUILD 51
//! Set to true for release, false for prerelease or test build //! Set to true for release, false for prerelease or test build
#define CLIENT_VERSION_IS_RELEASE true #define CLIENT_VERSION_IS_RELEASE true

View File

@ -169,9 +169,9 @@ void PrepareShutdown()
GenerateBitcoins(false, NULL, 0); GenerateBitcoins(false, NULL, 0);
#endif #endif
StopNode(); StopNode();
//DumpMasternodes(); DumpMasternodes();
//DumpBudgets(); DumpBudgets();
//DumpMasternodePayments(); DumpMasternodePayments();
UnregisterNodeSignals(GetNodeSignals()); UnregisterNodeSignals(GetNodeSignals());
if (fFeeEstimatesInitialized) if (fFeeEstimatesInitialized)
@ -1409,13 +1409,6 @@ bool AppInit2(boost::thread_group& threadGroup)
// ********************************************************* Step 10: setup DarkSend // ********************************************************* Step 10: setup DarkSend
/*
We sync all of this information on boot anyway, as it's kept on the network so there's really no point.
Also, it seems it might be causing some edge cases where clients can get stuck. I think it's better to just
sync from the network instead.
uiInterface.InitMessage(_("Loading masternode cache...")); uiInterface.InitMessage(_("Loading masternode cache..."));
CMasternodeDB mndb; CMasternodeDB mndb;
@ -1431,45 +1424,42 @@ bool AppInit2(boost::thread_group& threadGroup)
LogPrintf("file format is unknown or invalid, please fix it manually\n"); LogPrintf("file format is unknown or invalid, please fix it manually\n");
} }
uiInterface.InitMessage(_("Loading budget cache..."));
// --------- CBudgetDB budgetdb;
// uiInterface.InitMessage(_("Loading budget cache...")); CBudgetDB::ReadResult readResult2 = budgetdb.Read(budget);
// CBudgetDB budgetdb; if (readResult2 == CBudgetDB::FileError)
// CBudgetDB::ReadResult readResult2 = budgetdb.Read(budget); LogPrintf("Missing budget cache - budget.dat, will try to recreate\n");
else if (readResult2 != CBudgetDB::Ok)
{
LogPrintf("Error reading budget.dat: ");
if(readResult2 == 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");
}
// if (readResult2 == CBudgetDB::FileError) //flag our cached items so we send them to our peers
// LogPrintf("Missing budget cache - budget.dat, will try to recreate\n"); budget.ResetSync();
// else if (readResult2 != CBudgetDB::Ok) budget.ClearSeen();
// {
// LogPrintf("Error reading budget.dat: ");
// if(readResult2 == 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");
// }
// //flag our cached items so we send them to our peers
// budget.ResetSync();
// budget.ClearSeen();
// uiInterface.InitMessage(_("Loading masternode payment cache...")); uiInterface.InitMessage(_("Loading masternode payment cache..."));
// CMasternodePaymentDB mnpayments; CMasternodePaymentDB mnpayments;
// CMasternodePaymentDB::ReadResult readResult3 = mnpayments.Read(masternodePayments); CMasternodePaymentDB::ReadResult readResult3 = mnpayments.Read(masternodePayments);
// if (readResult3 == CMasternodePaymentDB::FileError) if (readResult3 == CMasternodePaymentDB::FileError)
// LogPrintf("Missing masternode payment cache - mnpayments.dat, will try to recreate\n"); LogPrintf("Missing masternode payment cache - mnpayments.dat, will try to recreate\n");
// else if (readResult3 != CMasternodePaymentDB::Ok) else if (readResult3 != CMasternodePaymentDB::Ok)
// { {
// LogPrintf("Error reading mnpayments.dat: "); LogPrintf("Error reading mnpayments.dat: ");
// if(readResult3 == CMasternodePaymentDB::IncorrectFormat) if(readResult3 == CMasternodePaymentDB::IncorrectFormat)
// LogPrintf("magic is ok but data has invalid format, will try to recreate\n"); LogPrintf("magic is ok but data has invalid format, will try to recreate\n");
// else else
// LogPrintf("file format is unknown or invalid, please fix it manually\n"); LogPrintf("file format is unknown or invalid, please fix it manually\n");
// } }
*/
fMasterNode = GetBoolArg("-masternode", false); fMasterNode = GetBoolArg("-masternode", false);

View File

@ -1379,16 +1379,6 @@ bool CBudgetProposal::AddOrUpdateVote(CBudgetVote& vote, std::string& strError)
} }
} }
//if we're synced, the vote should have been recent
if(masternodeSync.IsSynced()) {
//up to an hour ago
if(vote.nTime < GetTime() - (60*60)){
strError = strprintf("new vote is too old - %s - nTime %lli - Min Time %lli\n", vote.GetHash().ToString(), vote.nTime, GetTime() - (60*60));
LogPrint("mnbudget", "CBudgetProposal::AddOrUpdateVote - %s\n", strError);
return false;
}
}
if(vote.nTime > GetTime() + (60*60)){ if(vote.nTime > GetTime() + (60*60)){
strError = strprintf("new vote is too far ahead of current time - %s - nTime %lli - Max Time %lli\n", vote.GetHash().ToString(), vote.nTime, GetTime() + (60*60)); strError = strprintf("new vote is too far ahead of current time - %s - nTime %lli - Max Time %lli\n", vote.GetHash().ToString(), vote.nTime, GetTime() + (60*60));
LogPrint("mnbudget", "CBudgetProposal::AddOrUpdateVote - %s\n", strError); LogPrint("mnbudget", "CBudgetProposal::AddOrUpdateVote - %s\n", strError);
@ -1641,16 +1631,6 @@ bool CFinalizedBudget::AddOrUpdateVote(CFinalizedBudgetVote& vote, std::string&
} }
} }
//if we're synced, the vote should have been recent
if(masternodeSync.IsSynced()) {
//up to an hour ago
if(vote.nTime < GetTime() - (60*60)){
strError = strprintf("new vote is too old - %s - nTime %lli - Min Time %lli\n", vote.GetHash().ToString(), vote.nTime, GetTime() - (60*60));
LogPrint("mnbudget", "CFinalizedBudget::AddOrUpdateVote - %s\n", strError);
return false;
}
}
if(vote.nTime > GetTime() + (60*60)){ if(vote.nTime > GetTime() + (60*60)){
strError = strprintf("new vote is too far ahead of current time - %s - nTime %lli - Max Time %lli\n", vote.GetHash().ToString(), vote.nTime, GetTime() + (60*60)); strError = strprintf("new vote is too far ahead of current time - %s - nTime %lli - Max Time %lli\n", vote.GetHash().ToString(), vote.nTime, GetTime() + (60*60));
LogPrint("mnbudget", "CFinalizedBudget::AddOrUpdateVote - %s\n", strError); LogPrint("mnbudget", "CFinalizedBudget::AddOrUpdateVote - %s\n", strError);

View File

@ -382,8 +382,7 @@ void CMasternodePayments::ProcessMessageMasternodePayments(CNode* pfrom, std::st
} }
std::string strError = ""; std::string strError = "";
int nRank = 99999; if(!winner.IsValid(pfrom, strError)){
if(!winner.IsValid(pfrom, strError, nRank)){
if(strError != "") LogPrintf("mnw - invalid message - %s\n", strError); if(strError != "") LogPrintf("mnw - invalid message - %s\n", strError);
return; return;
} }
@ -407,7 +406,7 @@ void CMasternodePayments::ProcessMessageMasternodePayments(CNode* pfrom, std::st
LogPrint("mnpayments", "mnw - winning vote - Addr %s Height %d bestHeight %d - %s\n", address2.ToString().c_str(), winner.nBlockHeight, chainActive.Tip()->nHeight, winner.vinMasternode.prevout.ToStringShort()); LogPrint("mnpayments", "mnw - winning vote - Addr %s Height %d bestHeight %d - %s\n", address2.ToString().c_str(), winner.nBlockHeight, chainActive.Tip()->nHeight, winner.vinMasternode.prevout.ToStringShort());
if(masternodePayments.AddWinningMasternode(winner, nRank)){ if(masternodePayments.AddWinningMasternode(winner)){
winner.Relay(); winner.Relay();
masternodeSync.AddedMasternodeWinner(winner.GetHash()); masternodeSync.AddedMasternodeWinner(winner.GetHash());
} }
@ -472,7 +471,7 @@ bool CMasternodePayments::IsScheduled(CMasternode& mn, int nNotBlockHeight)
return false; return false;
} }
bool CMasternodePayments::AddWinningMasternode(CMasternodePaymentWinner& winnerIn, int nRank) bool CMasternodePayments::AddWinningMasternode(CMasternodePaymentWinner& winnerIn)
{ {
uint256 blockHash = 0; uint256 blockHash = 0;
if(!GetBlockHash(blockHash, winnerIn.nBlockHeight-100)) { if(!GetBlockHash(blockHash, winnerIn.nBlockHeight-100)) {
@ -496,7 +495,7 @@ bool CMasternodePayments::AddWinningMasternode(CMasternodePaymentWinner& winnerI
int n = 1; int n = 1;
if(IsReferenceNode(winnerIn.vinMasternode)) n = 100; if(IsReferenceNode(winnerIn.vinMasternode)) n = 100;
mapMasternodeBlocks[winnerIn.nBlockHeight].AddPayee(winnerIn.payee, n, winnerIn.GetHash(), nRank); mapMasternodeBlocks[winnerIn.nBlockHeight].AddPayee(winnerIn.payee, n);
return true; return true;
} }
@ -626,7 +625,7 @@ bool IsReferenceNode(CTxIn& vin)
return false; return false;
} }
bool CMasternodePaymentWinner::IsValid(CNode* pnode, std::string& strError, int& nRank) bool CMasternodePaymentWinner::IsValid(CNode* pnode, std::string& strError)
{ {
if(IsReferenceNode(vinMasternode)) return true; if(IsReferenceNode(vinMasternode)) return true;
@ -647,15 +646,15 @@ bool CMasternodePaymentWinner::IsValid(CNode* pnode, std::string& strError, int&
return false; return false;
} }
nRank = mnodeman.GetMasternodeRank(vinMasternode, nBlockHeight-100, MIN_MNW_PEER_PROTO_VERSION); int n = mnodeman.GetMasternodeRank(vinMasternode, nBlockHeight-100, MIN_MNW_PEER_PROTO_VERSION);
if(nRank > MNPAYMENTS_SIGNATURES_TOTAL) if(n > MNPAYMENTS_SIGNATURES_TOTAL)
{ {
//It's common to have masternodes mistakenly think they are in the top 10 //It's common to have masternodes mistakenly think they are in the top 10
// We don't want to print all of these messages, or punish them unless they're way off // We don't want to print all of these messages, or punish them unless they're way off
if(nRank > MNPAYMENTS_SIGNATURES_TOTAL*2) if(n > MNPAYMENTS_SIGNATURES_TOTAL*2)
{ {
strError = strprintf("Masternode not in the top %d (%d)", MNPAYMENTS_SIGNATURES_TOTAL, nRank); strError = strprintf("Masternode not in the top %d (%d)", MNPAYMENTS_SIGNATURES_TOTAL, n);
LogPrintf("CMasternodePaymentWinner::IsValid - %s\n", strError); LogPrintf("CMasternodePaymentWinner::IsValid - %s\n", strError);
Misbehaving(pnode->GetId(), 20); Misbehaving(pnode->GetId(), 20);
} }
@ -671,19 +670,18 @@ bool CMasternodePayments::ProcessBlock(int nBlockHeight)
//reference node - hybrid mode //reference node - hybrid mode
int nRank = 9999;
if(!IsReferenceNode(activeMasternode.vin)){ if(!IsReferenceNode(activeMasternode.vin)){
int nRank = mnodeman.GetMasternodeRank(activeMasternode.vin, nBlockHeight-100, MIN_MNW_PEER_PROTO_VERSION); int n = mnodeman.GetMasternodeRank(activeMasternode.vin, nBlockHeight-100, MIN_MNW_PEER_PROTO_VERSION);
if(nRank == -1) if(n == -1)
{ {
LogPrint("mnpayments", "CMasternodePayments::ProcessBlock - Unknown Masternode\n"); LogPrint("mnpayments", "CMasternodePayments::ProcessBlock - Unknown Masternode\n");
return false; return false;
} }
if(nRank > MNPAYMENTS_SIGNATURES_TOTAL) if(n > MNPAYMENTS_SIGNATURES_TOTAL)
{ {
LogPrint("mnpayments", "CMasternodePayments::ProcessBlock - Masternode not in the top %d (%d)\n", MNPAYMENTS_SIGNATURES_TOTAL, nRank); LogPrint("mnpayments", "CMasternodePayments::ProcessBlock - Masternode not in the top %d (%d)\n", MNPAYMENTS_SIGNATURES_TOTAL, n);
return false; return false;
} }
} }
@ -736,7 +734,7 @@ bool CMasternodePayments::ProcessBlock(int nBlockHeight)
{ {
LogPrintf("CMasternodePayments::ProcessBlock() - AddWinningMasternode\n"); LogPrintf("CMasternodePayments::ProcessBlock() - AddWinningMasternode\n");
if(AddWinningMasternode(newWinner, nRank)) if(AddWinningMasternode(newWinner))
{ {
newWinner.Relay(); newWinner.Relay();
nLastBlockHeight = nBlockHeight; nLastBlockHeight = nBlockHeight;
@ -781,34 +779,19 @@ void CMasternodePayments::Sync(CNode* node, int nCountNeeded)
if(chainActive.Tip() == NULL) return; if(chainActive.Tip() == NULL) return;
int nCount = mnodeman.CountEnabled()*1.5; int nCount = (mnodeman.CountEnabled()*2);
if(nCountNeeded > nCount) nCountNeeded = nCount; if(nCountNeeded > nCount) nCountNeeded = nCount;
vector<CInv> vInv; vector<CInv> vInv;
//get 1 winner per block for the previous nCount blocks
vector<uint256> vecHash;
for(int nBlockHeight = chainActive.Tip()->nHeight-nCount; nBlockHeight < chainActive.Tip()->nHeight-5; nBlockHeight++)
{
if(mapMasternodeBlocks[nBlockHeight].GetPayeeInventoryItems(vecHash)){
BOOST_FOREACH(uint256& nHash, vecHash)
{
CInv inv(MSG_MASTERNODE_WINNER, nHash);
vInv.push_back(inv);
}
}
}
//get 10 winners per block for the previous 5 blocks and next 20 (usually will be 10 though)
std::map<uint256, CMasternodePaymentWinner>::iterator it = mapMasternodePayeeVotes.begin(); std::map<uint256, CMasternodePaymentWinner>::iterator it = mapMasternodePayeeVotes.begin();
while(it != mapMasternodePayeeVotes.end()) { while(it != mapMasternodePayeeVotes.end()) {
CMasternodePaymentWinner& winner = (*it).second; CMasternodePaymentWinner winner = (*it).second;
if(winner.nBlockHeight >= chainActive.Tip()->nHeight-5 && winner.nBlockHeight <= chainActive.Tip()->nHeight + 20) { if(winner.nBlockHeight >= chainActive.Tip()->nHeight-nCountNeeded && winner.nBlockHeight <= chainActive.Tip()->nHeight + 20) {
CInv inv(MSG_MASTERNODE_WINNER, winner.GetHash()); CInv inv(MSG_MASTERNODE_WINNER, winner.GetHash());
vInv.push_back(inv); vInv.push_back(inv);
} }
++it; ++it;
} }
node->PushMessage("ssc", MASTERNODE_SYNC_MNW, (int)vInv.size()); node->PushMessage("ssc", MASTERNODE_SYNC_MNW, (int)vInv.size());
if(vInv.size() > 0) node->PushMessage("inv", vInv); if(vInv.size() > 0) node->PushMessage("inv", vInv);
} }

View File

@ -63,21 +63,15 @@ class CMasternodePayee
public: public:
CScript scriptPubKey; CScript scriptPubKey;
int nVotes; int nVotes;
uint256 nInvHash;
int nMasternodeRank;
CMasternodePayee() { CMasternodePayee() {
scriptPubKey = CScript(); scriptPubKey = CScript();
nVotes = 0; nVotes = 0;
nInvHash = 0;
nMasternodeRank = 99999;
} }
CMasternodePayee(CScript payee, int nVotesIn, uint256 nInvHashIn, int nMasternodeRankIn) { CMasternodePayee(CScript payee, int nVotesIn) {
scriptPubKey = payee; scriptPubKey = payee;
nVotes = nVotesIn; nVotes = nVotesIn;
nInvHash = nInvHashIn;
nMasternodeRank = nMasternodeRankIn;
} }
ADD_SERIALIZE_METHODS; ADD_SERIALIZE_METHODS;
@ -86,8 +80,6 @@ public:
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
READWRITE(scriptPubKey); READWRITE(scriptPubKey);
READWRITE(nVotes); READWRITE(nVotes);
READWRITE(nInvHash);
READWRITE(nMasternodeRank);
} }
}; };
@ -107,23 +99,17 @@ public:
vecPayments.clear(); vecPayments.clear();
} }
void AddPayee(CScript payeeIn, int nIncrement, uint256 nInvHashIn, int nMasternodeRankIn){ void AddPayee(CScript payeeIn, int nIncrement){
LOCK(cs_vecPayments); LOCK(cs_vecPayments);
BOOST_FOREACH(CMasternodePayee& payee, vecPayments){ BOOST_FOREACH(CMasternodePayee& payee, vecPayments){
if(payee.scriptPubKey == payeeIn) { if(payee.scriptPubKey == payeeIn) {
payee.nVotes += nIncrement; payee.nVotes += nIncrement;
//keep track of the "best" (highest rank) masternode's inventory item so we can send that one
// when syncing, we will consume much less bandwidth because of this
if(payee.nMasternodeRank > nMasternodeRankIn){
payee.nMasternodeRank = nMasternodeRankIn;
payee.nInvHash = nInvHashIn;
}
return; return;
} }
} }
CMasternodePayee c(payeeIn, nIncrement, nInvHashIn, nMasternodeRankIn); CMasternodePayee c(payeeIn, nIncrement);
vecPayments.push_back(c); vecPayments.push_back(c);
} }
@ -142,30 +128,6 @@ public:
return (nVotes > -1); return (nVotes > -1);
} }
int CountVotes()
{
int nVotes = 0;
BOOST_FOREACH(CMasternodePayee& p, vecPayments)
nVotes += p.nVotes;
return nVotes;
}
bool GetPayeeInventoryItems(vector<uint256>& vecHash)
{
LOCK(cs_vecPayments);
BOOST_FOREACH(CMasternodePayee& p, vecPayments){
//if we're syncing another client from a partial list, send everything.
// otherwise, we'll require 2 votes per item (those are the ones that count on the winners list)
if(p.nVotes >= 2 || CountVotes() <= 5){
vecHash.push_back(p.nInvHash);
}
}
return vecHash.size() >= 1;
}
bool HasPayeeWithVotes(CScript payee, int nVotesReq) bool HasPayeeWithVotes(CScript payee, int nVotesReq)
{ {
LOCK(cs_vecPayments); LOCK(cs_vecPayments);
@ -221,7 +183,7 @@ public:
} }
bool Sign(CKey& keyMasternode, CPubKey& pubKeyMasternode); bool Sign(CKey& keyMasternode, CPubKey& pubKeyMasternode);
bool IsValid(CNode* pnode, std::string& strError, int& nRank); bool IsValid(CNode* pnode, std::string& strError);
bool SignatureValid(); bool SignatureValid();
void Relay(); void Relay();
@ -278,7 +240,7 @@ public:
mapMasternodePayeeVotes.clear(); mapMasternodePayeeVotes.clear();
} }
bool AddWinningMasternode(CMasternodePaymentWinner& winner, int nRank); bool AddWinningMasternode(CMasternodePaymentWinner& winner);
bool ProcessBlock(int nBlockHeight); bool ProcessBlock(int nBlockHeight);
void Sync(CNode* node, int nCountNeeded); void Sync(CNode* node, int nCountNeeded);

View File

@ -348,7 +348,7 @@ void CMasternodeSync::Process()
CBlockIndex* pindexPrev = chainActive.Tip(); CBlockIndex* pindexPrev = chainActive.Tip();
if(pindexPrev == NULL) return; if(pindexPrev == NULL) return;
int nMnCount = mnodeman.CountEnabled(); int nMnCount = mnodeman.CountEnabled()*2;
pnode->PushMessage("mnget", nMnCount); //sync payees pnode->PushMessage("mnget", nMnCount); //sync payees
RequestedMasternodeAttempt++; RequestedMasternodeAttempt++;

View File

@ -271,10 +271,7 @@ int64_t CMasternode::GetLastPaid() {
Search for this payee, with at least 2 votes. This will aid in consensus allowing the network Search for this payee, with at least 2 votes. This will aid in consensus allowing the network
to converge on the same payees quickly, then keep the same schedule. to converge on the same payees quickly, then keep the same schedule.
*/ */
if(masternodePayments.mapMasternodeBlocks[BlockReading->nHeight].HasPayeeWithVotes(mnpayee, 2)){
//if we've synced we'll have 1 vote per winning masternode, those count. Otherwise we'll have 10 votes, then only 2 votes min count
int nMinVotes = masternodePayments.mapMasternodeBlocks[BlockReading->nHeight].CountVotes() >= 6 ? 2 : 1;
if(masternodePayments.mapMasternodeBlocks[BlockReading->nHeight].HasPayeeWithVotes(mnpayee, nMinVotes)){
return BlockReading->nTime + nOffset; return BlockReading->nTime + nOffset;
} }
} }

View File

@ -24,7 +24,7 @@ Value mnbudget(const Array& params, bool fHelp)
strCommand = params[0].get_str(); strCommand = params[0].get_str();
if (fHelp || if (fHelp ||
(strCommand != "vote-many" && strCommand != "prepare" && strCommand != "submit" && strCommand != "vote" && strCommand != "getvotes" && strCommand != "getinfo" && strCommand != "show" && strCommand != "projection" && strCommand != "check")) (strCommand != "vote-many" && strCommand != "prepare" && strCommand != "submit" && strCommand != "vote" && strCommand != "getvotes" && strCommand != "getinfo" && strCommand != "show" && strCommand != "projection" && strCommand != "check" && strCommand != "nextblock"))
throw runtime_error( throw runtime_error(
"mnbudget \"command\"... ( \"passphrase\" )\n" "mnbudget \"command\"... ( \"passphrase\" )\n"
"Vote or show current budgets\n" "Vote or show current budgets\n"
@ -39,8 +39,18 @@ Value mnbudget(const Array& params, bool fHelp)
" show - Show all budgets\n" " show - Show all budgets\n"
" projection - Show the projection of which proposals will be paid the next cycle\n" " projection - Show the projection of which proposals will be paid the next cycle\n"
" check - Scan proposals and remove invalid\n" " check - Scan proposals and remove invalid\n"
" nextblock - Get next superblock for budget system\n"
); );
if(strCommand == "nextblock")
{
CBlockIndex* pindexPrev = chainActive.Tip();
if(!pindexPrev) return "unknown";
int nNext = pindexPrev->nHeight - pindexPrev->nHeight % GetBudgetPaymentCycleBlocks() + GetBudgetPaymentCycleBlocks();
return nNext;
}
if(strCommand == "prepare") if(strCommand == "prepare")
{ {
int nBlockMin = 0; int nBlockMin = 0;