From 8187228be13d80b3f673d7a922cb947a205f7094 Mon Sep 17 00:00:00 2001 From: Evan Duffield Date: Sat, 25 Jul 2015 09:29:29 -0700 Subject: [PATCH] Fixed budget syncing issues / forking issues / syncing issues - Budgets now store the seen objects locally so they're not overwritten when saving/loading to check validity of budget.dat - Added safer sync "failure" mode, that will retry an hour later if the sync fails for some reason. This will stop the client from thinking it has budget data and rejecting blocks when they're valid. - protocol bump - version bump --- configure.ac | 2 +- src/activemasternode.cpp | 2 +- src/clientversion.h | 2 +- src/instantx.h | 8 ++++++-- src/main.cpp | 38 +++++++++++++++++++++++------------ src/masternode-budget.cpp | 39 ++++++++++++++++++++++++++---------- src/masternode-budget.h | 17 +++++++++++----- src/masternode-sync.cpp | 18 ++++++++++++++++- src/masternode-sync.h | 4 +++- src/rpcmasternode-budget.cpp | 10 ++++----- src/version.h | 10 ++++----- 11 files changed, 104 insertions(+), 46 deletions(-) diff --git a/configure.ac b/configure.ac index 24cae2ce2d..69cdb53e04 100644 --- a/configure.ac +++ b/configure.ac @@ -3,7 +3,7 @@ AC_PREREQ([2.60]) define(_CLIENT_VERSION_MAJOR, 0) define(_CLIENT_VERSION_MINOR, 12) define(_CLIENT_VERSION_REVISION, 0) -define(_CLIENT_VERSION_BUILD, 28) +define(_CLIENT_VERSION_BUILD, 29) define(_CLIENT_VERSION_IS_RELEASE, true) define(_COPYRIGHT_YEAR, 2015) AC_INIT([Dash Core],[_CLIENT_VERSION_MAJOR._CLIENT_VERSION_MINOR._CLIENT_VERSION_REVISION],[info@dashpay.io],[dash]) diff --git a/src/activemasternode.cpp b/src/activemasternode.cpp index fa4c56e5dc..ff6552feb5 100644 --- a/src/activemasternode.cpp +++ b/src/activemasternode.cpp @@ -17,7 +17,7 @@ void CActiveMasternode::ManageStatus() if (fDebug) LogPrintf("CActiveMasternode::ManageStatus() - Begin\n"); //need correct blocks to send ping - if(!masternodeSync.IsSynced()) { + if(Params().NetworkID() != CBaseChainParams::REGTEST && !masternodeSync.IsSynced()) { status = ACTIVE_MASTERNODE_SYNC_IN_PROCESS; LogPrintf("CActiveMasternode::ManageStatus() - %s\n", GetStatus()); return; diff --git a/src/clientversion.h b/src/clientversion.h index d652249655..f0138c8187 100644 --- a/src/clientversion.h +++ b/src/clientversion.h @@ -17,7 +17,7 @@ #define CLIENT_VERSION_MAJOR 0 #define CLIENT_VERSION_MINOR 12 #define CLIENT_VERSION_REVISION 0 -#define CLIENT_VERSION_BUILD 28 +#define CLIENT_VERSION_BUILD 29 //! Set to true for release, false for prerelease or test build #define CLIENT_VERSION_IS_RELEASE true diff --git a/src/instantx.h b/src/instantx.h index 2b44e069cc..e89328812a 100644 --- a/src/instantx.h +++ b/src/instantx.h @@ -15,7 +15,11 @@ /* At 15 signatures, 1/2 of the masternode network can be owned by one party without comprimising the security of InstantX - (1000/2150.0)**15 = 1.031e-05 + (1000/2150.0)**10 = 0.00047382219560689856 + (1000/2900.0)**10 = 2.3769498616783657e-05 + + ### getting 5 of 10 signatures w/ 1000 nodes of 2900 + (1000/2900.0)**5 = 0.004875397277841433 */ #define INSTANTX_SIGNATURES_REQUIRED 5 #define INSTANTX_SIGNATURES_TOTAL 10 @@ -27,7 +31,7 @@ class CConsensusVote; class CTransaction; class CTransactionLock; -static const int MIN_INSTANTX_PROTO_VERSION = 70096; +static const int MIN_INSTANTX_PROTO_VERSION = 70097; extern map mapTxLockReq; extern map mapTxLockReqRejected; diff --git a/src/main.cpp b/src/main.cpp index 5c907f6ca0..26ba00e0bb 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3266,6 +3266,17 @@ bool ProcessNewBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDis darkSendPool.NewBlock(); masternodePayments.ProcessBlock(GetHeight()+10); budget.NewBlock(); + + //allow clients to ask for syncing again if they need it + if(GetHeight() % 100 == 0) { + LOCK(cs_vNodes); + BOOST_FOREACH(CNode* pnode, vNodes) { + pnode->ClearFulfilledRequest("getspork"); + pnode->ClearFulfilledRequest("mnsync"); + pnode->ClearFulfilledRequest("mnwsync"); + pnode->ClearFulfilledRequest("busync"); + } + } } } @@ -3970,25 +3981,25 @@ bool static AlreadyHave(const CInv& inv) } return false; case MSG_BUDGET_VOTE: - if(mapSeenMasternodeBudgetVotes.count(inv.hash)) { + if(budget.mapSeenMasternodeBudgetVotes.count(inv.hash)) { masternodeSync.AddedBudgetItem(); return true; } return false; case MSG_BUDGET_PROPOSAL: - if(mapSeenMasternodeBudgetProposals.count(inv.hash)) { + if(budget.mapSeenMasternodeBudgetProposals.count(inv.hash)) { masternodeSync.AddedBudgetItem(); return true; } return false; case MSG_BUDGET_FINALIZED_VOTE: - if(mapSeenFinalizedBudgetVotes.count(inv.hash)) { + if(budget.mapSeenFinalizedBudgetVotes.count(inv.hash)) { masternodeSync.AddedBudgetItem(); return true; } return false; case MSG_BUDGET_FINALIZED: - if(mapSeenFinalizedBudgets.count(inv.hash)) { + if(budget.mapSeenFinalizedBudgets.count(inv.hash)) { masternodeSync.AddedBudgetItem(); return true; } @@ -4161,40 +4172,40 @@ void static ProcessGetData(CNode* pfrom) } } if (!pushed && inv.type == MSG_BUDGET_VOTE) { - if(mapSeenMasternodeBudgetVotes.count(inv.hash)){ + if(budget.mapSeenMasternodeBudgetVotes.count(inv.hash)){ CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); ss.reserve(1000); - ss << mapSeenMasternodeBudgetVotes[inv.hash]; + ss << budget.mapSeenMasternodeBudgetVotes[inv.hash]; pfrom->PushMessage("mvote", ss); pushed = true; } } if (!pushed && inv.type == MSG_BUDGET_PROPOSAL) { - if(mapSeenMasternodeBudgetProposals.count(inv.hash)){ + if(budget.mapSeenMasternodeBudgetProposals.count(inv.hash)){ CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); ss.reserve(1000); - ss << mapSeenMasternodeBudgetProposals[inv.hash]; + ss << budget.mapSeenMasternodeBudgetProposals[inv.hash]; pfrom->PushMessage("mprop", ss); pushed = true; } } if (!pushed && inv.type == MSG_BUDGET_FINALIZED_VOTE) { - if(mapSeenFinalizedBudgetVotes.count(inv.hash)){ + if(budget.mapSeenFinalizedBudgetVotes.count(inv.hash)){ CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); ss.reserve(1000); - ss << mapSeenFinalizedBudgetVotes[inv.hash]; + ss << budget.mapSeenFinalizedBudgetVotes[inv.hash]; pfrom->PushMessage("fbvote", ss); pushed = true; } } if (!pushed && inv.type == MSG_BUDGET_FINALIZED) { - if(mapSeenFinalizedBudgets.count(inv.hash)){ + if(budget.mapSeenFinalizedBudgets.count(inv.hash)){ CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); ss.reserve(1000); - ss << mapSeenFinalizedBudgets[inv.hash]; + ss << budget.mapSeenFinalizedBudgets[inv.hash]; pfrom->PushMessage("fbs", ss); pushed = true; } @@ -4818,7 +4829,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, if (state.IsInvalid(nDoS)) { if (nDoS > 0) Misbehaving(pfrom->GetId(), nDoS); - return error("invalid header received"); + std::string strError = "invalid header received " + header.GetHash().ToString(); + return error(strError.c_str()); } } } diff --git a/src/masternode-budget.cpp b/src/masternode-budget.cpp index dd9a6737c9..08fcf3265b 100644 --- a/src/masternode-budget.cpp +++ b/src/masternode-budget.cpp @@ -18,13 +18,6 @@ CBudgetManager budget; CCriticalSection cs_budget; -std::map mapSeenMasternodeBudgetProposals; -std::map mapSeenMasternodeBudgetVotes; -std::map mapOrphanMasternodeBudgetVotes; -std::map mapSeenFinalizedBudgets; -std::map mapSeenFinalizedBudgetVotes; -std::map mapOrphanFinalizedBudgetVotes; - std::map askedForSourceProposalOrBudget; int nSubmittedFinalBudget; @@ -514,6 +507,19 @@ bool CBudgetManager::IsBudgetPaymentBlock(int nBlockHeight){ return false; } +bool CBudgetManager::HasNextFinalizedBudget() +{ + CBlockIndex* pindexPrev = chainActive.Tip(); + if(!pindexPrev) return false; + + int nBlockStart = pindexPrev->nHeight - pindexPrev->nHeight % GetBudgetPaymentCycleBlocks() + GetBudgetPaymentCycleBlocks(); + if(nBlockStart - pindexPrev->nHeight > 576*2) return false; //we wouldn't have the budget yet + + if(budget.IsBudgetPaymentBlock(nBlockStart)) return true; + + return false; +} + bool CBudgetManager::IsTransactionValid(const CTransaction& txNew, int nBlockHeight) { int nHighestCount = 0; @@ -771,7 +777,6 @@ void CBudgetManager::ProcessMessage(CNode* pfrom, std::string& strCommand, CData uint256 nProp; vRecv >> nProp; - if(Params().NetworkID() == CBaseChainParams::MAIN){ if(pfrom->HasFulfilledRequest("mnvs")) { LogPrintf("mnvs - peer already asked me for the list\n"); @@ -810,6 +815,8 @@ void CBudgetManager::ProcessMessage(CNode* pfrom, std::string& strCommand, CData budgetProposalBroadcast.Relay(); masternodeSync.AddedBudgetItem(); + LogPrintf("mprop - new budget - %s\n", budgetProposalBroadcast.GetHash().ToString()); + //We might have active votes for this proposal that are valid now CheckOrphanVotes(); } @@ -843,6 +850,8 @@ void CBudgetManager::ProcessMessage(CNode* pfrom, std::string& strCommand, CData vote.Relay(); if(!masternodeSync.IsSynced()) pmn->nVotedTimes++; masternodeSync.AddedBudgetItem(); + + LogPrintf("mvote - new budget vote - %s\n", vote.GetHash().ToString()); } else { LogPrintf("mvote - masternode can't vote again - vin: %s\n", pmn->vin.ToString()); return; @@ -871,6 +880,8 @@ void CBudgetManager::ProcessMessage(CNode* pfrom, std::string& strCommand, CData return; } + LogPrintf("fbs - new finalized budget - %s\n", finalizedBudgetBroadcast.GetHash().ToString()); + CFinalizedBudget finalizedBudget(finalizedBudgetBroadcast); AddFinalizedBudget(finalizedBudget); finalizedBudgetBroadcast.Relay(); @@ -908,6 +919,9 @@ void CBudgetManager::ProcessMessage(CNode* pfrom, std::string& strCommand, CData vote.Relay(); if(!masternodeSync.IsSynced()) pmn->nVotedTimes++; masternodeSync.AddedBudgetItem(); + + if(fDebug) LogPrintf("fbs - new finalized budget vote - %s\n", vote.GetHash().ToString()); + } else { LogPrintf("fbvote - masternode can't vote again - vin: %s\n", pmn->vin.ToString()); return; @@ -953,7 +967,6 @@ void CBudgetManager::Sync(CNode* pfrom, uint256 nProp) ++it1; } - std::map::iterator it3 = mapSeenFinalizedBudgets.begin(); while(it3 != mapSeenFinalizedBudgets.end()){ CFinalizedBudget* pfinalizedBudget = FindFinalizedBudget((*it3).first); @@ -1576,7 +1589,7 @@ void CFinalizedBudget::SubmitVote() return; } - mapSeenFinalizedBudgetVotes.insert(make_pair(vote.GetHash(), vote)); + budget.mapSeenFinalizedBudgetVotes.insert(make_pair(vote.GetHash(), vote)); vote.Relay(); budget.UpdateFinalizedBudget(vote, NULL); } @@ -1690,7 +1703,11 @@ std::string CBudgetManager::ToString() const std::ostringstream info; info << "Proposals: " << (int)mapProposals.size() << - ", Budgets: " << (int)mapFinalizedBudgets.size(); + ", Budgets: " << (int)mapFinalizedBudgets.size() << + ", Seen Budgets: " << (int)mapSeenMasternodeBudgetProposals.size() << + ", Seen Budget Votes: " << (int)mapSeenMasternodeBudgetVotes.size() << + ", Seen Final Budgets: " << (int)mapSeenFinalizedBudgets.size() << + ", Seen Final Budget Votes: " << (int)mapSeenFinalizedBudgetVotes.size(); return info.str(); } diff --git a/src/masternode-budget.h b/src/masternode-budget.h index 2801631aa0..1080e640c5 100644 --- a/src/masternode-budget.h +++ b/src/masternode-budget.h @@ -33,11 +33,6 @@ class CTxBudgetPayment; static const CAmount BUDGET_FEE_TX = (0.5*COIN); static const int64_t BUDGET_FEE_CONFIRMATIONS = 6; -extern std::map mapSeenMasternodeBudgetProposals; -extern std::map mapSeenMasternodeBudgetVotes; -extern std::map mapSeenFinalizedBudgets; -extern std::map mapSeenFinalizedBudgetVotes; - extern CBudgetManager budget; void DumpBudgets(); @@ -88,6 +83,13 @@ public: map mapProposals; map mapFinalizedBudgets; + std::map mapSeenMasternodeBudgetProposals; + std::map mapSeenMasternodeBudgetVotes; + std::map mapOrphanMasternodeBudgetVotes; + std::map mapSeenFinalizedBudgets; + std::map mapSeenFinalizedBudgetVotes; + std::map mapOrphanFinalizedBudgetVotes; + CBudgetManager() { mapProposals.clear(); mapFinalizedBudgets.clear(); @@ -114,6 +116,7 @@ public: void AddProposal(CBudgetProposal& budgetProposal); void AddFinalizedBudget(CFinalizedBudget& finalizedBudget); void SubmitFinalBudget(); + bool HasNextFinalizedBudget(); bool UpdateProposal(CBudgetVote& vote, CNode* pfrom); bool UpdateFinalizedBudget(CFinalizedBudgetVote& vote, CNode* pfrom); @@ -131,6 +134,8 @@ public: mapSeenMasternodeBudgetVotes.clear(); mapSeenFinalizedBudgets.clear(); mapSeenFinalizedBudgetVotes.clear(); + mapOrphanMasternodeBudgetVotes.clear(); + mapOrphanFinalizedBudgetVotes.clear(); } void CheckAndRemove(); std::string ToString() const; @@ -144,6 +149,8 @@ public: READWRITE(mapSeenMasternodeBudgetVotes); READWRITE(mapSeenFinalizedBudgets); READWRITE(mapSeenFinalizedBudgetVotes); + READWRITE(mapOrphanMasternodeBudgetVotes); + READWRITE(mapOrphanFinalizedBudgetVotes); READWRITE(mapProposals); READWRITE(mapFinalizedBudgets); diff --git a/src/masternode-sync.cpp b/src/masternode-sync.cpp index 167ee3d223..3f9244156f 100644 --- a/src/masternode-sync.cpp +++ b/src/masternode-sync.cpp @@ -5,6 +5,7 @@ #include "main.h" #include "masternode-sync.h" #include "masternode-payments.h" +#include "masternode-budget.h" #include "masternode.h" #include "masternodeman.h" #include "util.h" @@ -47,6 +48,7 @@ void CMasternodeSync::GetNextAsset() switch(RequestedMasternodeAssets) { case(MASTERNODE_SYNC_INITIAL): + case(MASTERNODE_SYNC_FAILED): lastMasternodeList = 0; lastMasternodeWinner = 0; lastBudgetItem = 0; @@ -97,6 +99,13 @@ void CMasternodeSync::Process() return; } + //try syncing again in an hour + if(RequestedMasternodeAssets == MASTERNODE_SYNC_FAILED && lastFailure + (60*60) < GetTime()) { + GetNextAsset(); + } else if (RequestedMasternodeAssets == MASTERNODE_SYNC_FAILED) { + return; + } + if(fDebug) LogPrintf("CMasternodeSync::Process() - tick %d RequestedMasternodeAssets %d\n", tick, RequestedMasternodeAssets); if(RequestedMasternodeAssets == MASTERNODE_SYNC_INITIAL) GetNextAsset(); @@ -185,7 +194,14 @@ void CMasternodeSync::Process() if(RequestedMasternodeAssets == MASTERNODE_SYNC_BUDGET){ if(lastBudgetItem > 0 && lastBudgetItem < GetTime() - MASTERNODE_SYNC_TIMEOUT){ //hasn't received a new item in the last five seconds, so we'll move to the - GetNextAsset(); + if(budget.HasNextFinalizedBudget()) { + GetNextAsset(); + } else { //we've failed to sync, this state will reject the next budget block + LogPrintf("CMasternodeSync::Process - ERROR - Sync has failed, will retry later\n"); + RequestedMasternodeAssets = MASTERNODE_SYNC_FAILED; + RequestedMasternodeAttempt = 0; + lastFailure = GetTime(); + } return; } diff --git a/src/masternode-sync.h b/src/masternode-sync.h index 677f4abb7c..0326a14d48 100644 --- a/src/masternode-sync.h +++ b/src/masternode-sync.h @@ -10,9 +10,10 @@ #define MASTERNODE_SYNC_LIST 2 #define MASTERNODE_SYNC_MNW 3 #define MASTERNODE_SYNC_BUDGET 4 +#define MASTERNODE_SYNC_FAILED 998 #define MASTERNODE_SYNC_FINISHED 999 -#define MASTERNODE_SYNC_TIMEOUT 5 +#define MASTERNODE_SYNC_TIMEOUT 15 class CMasternodeSync; extern CMasternodeSync masternodeSync; @@ -27,6 +28,7 @@ public: int64_t lastMasternodeList; int64_t lastMasternodeWinner; int64_t lastBudgetItem; + int64_t lastFailure; // Count peers we've requested the list from int RequestedMasternodeAssets; diff --git a/src/rpcmasternode-budget.cpp b/src/rpcmasternode-budget.cpp index c2749bdaec..6d2505d175 100644 --- a/src/rpcmasternode-budget.cpp +++ b/src/rpcmasternode-budget.cpp @@ -180,7 +180,7 @@ Value mnbudget(const Array& params, bool fHelp) return "Proposal is not valid - " + budgetProposalBroadcast.GetHash().ToString() + " - " + strError; } - mapSeenMasternodeBudgetProposals.insert(make_pair(budgetProposalBroadcast.GetHash(), budgetProposalBroadcast)); + budget.mapSeenMasternodeBudgetProposals.insert(make_pair(budgetProposalBroadcast.GetHash(), budgetProposalBroadcast)); budgetProposalBroadcast.Relay(); budget.AddProposal(budgetProposalBroadcast); @@ -248,7 +248,7 @@ Value mnbudget(const Array& params, bool fHelp) continue; } - mapSeenMasternodeBudgetVotes.insert(make_pair(vote.GetHash(), vote)); + budget.mapSeenMasternodeBudgetVotes.insert(make_pair(vote.GetHash(), vote)); vote.Relay(); budget.UpdateProposal(vote, NULL); @@ -292,7 +292,7 @@ Value mnbudget(const Array& params, bool fHelp) return "Failure to sign."; } - mapSeenMasternodeBudgetVotes.insert(make_pair(vote.GetHash(), vote)); + budget.mapSeenMasternodeBudgetVotes.insert(make_pair(vote.GetHash(), vote)); vote.Relay(); budget.UpdateProposal(vote, NULL); @@ -538,7 +538,7 @@ Value mnfinalbudget(const Array& params, bool fHelp) continue; } - mapSeenFinalizedBudgetVotes.insert(make_pair(vote.GetHash(), vote)); + budget.mapSeenFinalizedBudgetVotes.insert(make_pair(vote.GetHash(), vote)); vote.Relay(); budget.UpdateFinalizedBudget(vote, NULL); @@ -577,7 +577,7 @@ Value mnfinalbudget(const Array& params, bool fHelp) return "Failure to sign."; } - mapSeenFinalizedBudgetVotes.insert(make_pair(vote.GetHash(), vote)); + budget.mapSeenFinalizedBudgetVotes.insert(make_pair(vote.GetHash(), vote)); vote.Relay(); budget.UpdateFinalizedBudget(vote, NULL); diff --git a/src/version.h b/src/version.h index 2c5b5c3a72..788c2d62f6 100644 --- a/src/version.h +++ b/src/version.h @@ -10,7 +10,7 @@ * network protocol versioning */ -static const int PROTOCOL_VERSION = 70096; +static const int PROTOCOL_VERSION = 70097; //! initial proto version, to be increased after version/verack negotiation static const int INIT_PROTO_VERSION = 209; @@ -22,19 +22,19 @@ static const int GETHEADERS_VERSION = 70077; static const int MIN_PEER_PROTO_VERSION = 70066; //! minimum peer version accepted by DarksendPool -static const int MIN_POOL_PEER_PROTO_VERSION = 70096; +static const int MIN_POOL_PEER_PROTO_VERSION = 70097; //! minimum peer version for masternode budgets -static const int MIN_BUDGET_PEER_PROTO_VERSION = 70096; +static const int MIN_BUDGET_PEER_PROTO_VERSION = 70097; //! minimum peer version for masternode winner broadcasts -static const int MIN_MNW_PEER_PROTO_VERSION = 70096; +static const int MIN_MNW_PEER_PROTO_VERSION = 70097; //! minimum peer version that can receive masternode payments // V1 - Last protocol version before update // V2 - Newest protocol version static const int MIN_MASTERNODE_PAYMENT_PROTO_VERSION_1 = 70066; -static const int MIN_MASTERNODE_PAYMENT_PROTO_VERSION_2 = 70096; +static const int MIN_MASTERNODE_PAYMENT_PROTO_VERSION_2 = 70097; //! nTime field added to CAddress, starting with this version; //! if possible, avoid requesting addresses nodes older than this