diff --git a/src/Makefile.am b/src/Makefile.am index 45bccbcc5..dfd7bb85b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -106,6 +106,7 @@ BITCOIN_CORE_H = \ consensus/validation.h \ core_io.h \ darksend.h \ + dsnotificationinterface.h \ darksend-relay.h \ core_memusage.h \ hash.h \ @@ -249,6 +250,7 @@ libbitcoin_wallet_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libbitcoin_wallet_a_SOURCES = \ activemasternode.cpp \ darksend.cpp \ + dsnotificationinterface.cpp \ darksend-relay.cpp \ instantx.cpp \ masternode.cpp \ diff --git a/src/darksend.cpp b/src/darksend.cpp index 395c0b8db..eb96db78d 100644 --- a/src/darksend.cpp +++ b/src/darksend.cpp @@ -450,7 +450,7 @@ std::string CDarksendPool::GetStatus() showingDarkSendMessage += 10; std::string suffix = ""; - if(chainActive.Tip()->nHeight - cachedLastSuccess < minBlockSpacing || !masternodeSync.IsBlockchainSynced()) { + if((pCurrentBlockIndex && pCurrentBlockIndex->nHeight - cachedLastSuccess < minBlockSpacing) || !masternodeSync.IsBlockchainSynced()) { return strAutoDenomResult; } switch(state) { @@ -570,10 +570,10 @@ void CDarksendPool::CheckFinalTransaction() CWalletTx txNew = CWalletTx(pwalletMain, finalTransaction); - LOCK2(cs_main, pwalletMain->cs_wallet); - { - LogPrint("darksend", "Transaction 2: %s\n", txNew.ToString()); + LogPrint("darksend", "Transaction 2: %s\n", txNew.ToString()); + { + LOCK(cs_main); // See if the transaction is valid if (!txNew.AcceptToMemoryPool(false, true)) { @@ -585,58 +585,57 @@ void CDarksendPool::CheckFinalTransaction() RelayCompletedTransaction(sessionID, true, ERR_INVALID_TX); return; } - - LogPrintf("CDarksendPool::Check() -- IS MASTER -- TRANSMITTING DARKSEND\n"); - - // sign a message - - int64_t sigTime = GetAdjustedTime(); - std::string strMessage = txNew.GetHash().ToString() + boost::lexical_cast(sigTime); - std::string strError = ""; - std::vector vchSig; - CKey key2; - CPubKey pubkey2; - - if(!darkSendSigner.SetKey(strMasterNodePrivKey, strError, key2, pubkey2)) - { - LogPrintf("CDarksendPool::Check() - ERROR: Invalid Masternodeprivkey: '%s'\n", strError); - return; - } - - if(!darkSendSigner.SignMessage(strMessage, strError, vchSig, key2)) { - LogPrintf("CDarksendPool::Check() - Sign message failed\n"); - return; - } - - if(!darkSendSigner.VerifyMessage(pubkey2, vchSig, strMessage, strError)) { - LogPrintf("CDarksendPool::Check() - Verify message failed\n"); - return; - } - - if(!mapDarksendBroadcastTxes.count(txNew.GetHash())){ - CDarksendBroadcastTx dstx; - dstx.tx = txNew; - dstx.vin = activeMasternode.vin; - dstx.vchSig = vchSig; - dstx.sigTime = sigTime; - - mapDarksendBroadcastTxes.insert(make_pair(txNew.GetHash(), dstx)); - } - - CInv inv(MSG_DSTX, txNew.GetHash()); - RelayInv(inv); - - // Tell the clients it was successful - RelayCompletedTransaction(sessionID, false, MSG_SUCCESS); - - // Randomly charge clients - ChargeRandomFees(); - - // Reset - LogPrint("darksend", "CDarksendPool::Check() -- COMPLETED -- RESETTING\n"); - SetNull(); - RelayStatus(sessionID, GetState(), GetEntriesCount(), MASTERNODE_RESET); } + LogPrintf("CDarksendPool::Check() -- IS MASTER -- TRANSMITTING DARKSEND\n"); + + // sign a message + + int64_t sigTime = GetAdjustedTime(); + std::string strMessage = txNew.GetHash().ToString() + boost::lexical_cast(sigTime); + std::string strError = ""; + std::vector vchSig; + CKey key2; + CPubKey pubkey2; + + if(!darkSendSigner.SetKey(strMasterNodePrivKey, strError, key2, pubkey2)) + { + LogPrintf("CDarksendPool::Check() - ERROR: Invalid Masternodeprivkey: '%s'\n", strError); + return; + } + + if(!darkSendSigner.SignMessage(strMessage, strError, vchSig, key2)) { + LogPrintf("CDarksendPool::Check() - Sign message failed\n"); + return; + } + + if(!darkSendSigner.VerifyMessage(pubkey2, vchSig, strMessage, strError)) { + LogPrintf("CDarksendPool::Check() - Verify message failed\n"); + return; + } + + if(!mapDarksendBroadcastTxes.count(txNew.GetHash())){ + CDarksendBroadcastTx dstx; + dstx.tx = txNew; + dstx.vin = activeMasternode.vin; + dstx.vchSig = vchSig; + dstx.sigTime = sigTime; + + mapDarksendBroadcastTxes.insert(make_pair(txNew.GetHash(), dstx)); + } + + CInv inv(MSG_DSTX, txNew.GetHash()); + RelayInv(inv); + + // Tell the clients it was successful + RelayCompletedTransaction(sessionID, false, MSG_SUCCESS); + + // Randomly charge clients + ChargeRandomFees(); + + // Reset + LogPrint("darksend", "CDarksendPool::Check() -- COMPLETED -- RESETTING\n"); + SetNull(); + RelayStatus(sessionID, GetState(), GetEntriesCount(), MASTERNODE_RESET); } // @@ -1342,7 +1341,7 @@ void CDarksendPool::CompletedTransaction(bool error, int errorID) SetNull(); // To avoid race conditions, we'll only let DS run once per block - cachedLastSuccess = chainActive.Tip()->nHeight; + cachedLastSuccess = pCurrentBlockIndex->nHeight; } lastMessage = GetMessageByID(errorID); } @@ -1361,6 +1360,9 @@ bool CDarksendPool::DoAutomaticDenominating(bool fDryRun) { if(!fEnableDarksend) return false; if(fMasterNode) return false; + + if(!pCurrentBlockIndex) return false; + if(state == POOL_STATUS_ERROR || state == POOL_STATUS_SUCCESS) return false; if(GetEntriesCount() > 0) { strAutoDenomResult = _("Mixing in progress..."); @@ -1383,7 +1385,7 @@ bool CDarksendPool::DoAutomaticDenominating(bool fDryRun) return false; } - if(!fDarksendMultiSession && chainActive.Tip()->nHeight - cachedLastSuccess < minBlockSpacing) { + if(!fDarksendMultiSession && pCurrentBlockIndex->nHeight - cachedLastSuccess < minBlockSpacing) { LogPrintf("CDarksendPool::DoAutomaticDenominating - Last successful Darksend action was too recent\n"); strAutoDenomResult = _("Last successful Darksend action was too recent."); return false; @@ -1704,7 +1706,7 @@ bool CDarksendPool::MakeCollateralAmounts() return false; } - cachedLastSuccess = chainActive.Tip()->nHeight; + cachedLastSuccess = pCurrentBlockIndex->nHeight; return true; } @@ -1795,7 +1797,7 @@ bool CDarksendPool::CreateDenominated(CAmount nTotalValue) // use the same cachedLastSuccess as for DS mixinx to prevent race if(pwalletMain->CommitTransaction(wtx, reservekeyChange)) - cachedLastSuccess = chainActive.Tip()->nHeight; + cachedLastSuccess = pCurrentBlockIndex->nHeight; else LogPrintf("CreateDenominated: CommitTransaction failed!\n"); @@ -2198,6 +2200,15 @@ void CDarksendPool::RelayCompletedTransaction(const int sessionID, const bool er pnode->PushMessage(NetMsgType::DSSTATUSUPDATE, sessionID, error, errorID); } +void CDarksendPool::UpdatedBlockTip(const CBlockIndex *pindex) +{ + pCurrentBlockIndex = pindex; + LogPrint("darksend", "pCurrentBlockIndex->nHeight: %d\n", pCurrentBlockIndex->nHeight); + + if(!fLiteMode && masternodeSync.RequestedMasternodeAssets > MASTERNODE_SYNC_LIST) + NewBlock(); +} + //TODO: Rename/move to core void ThreadCheckDarkSendPool() { diff --git a/src/darksend.h b/src/darksend.h index b38d52f42..028e2d413 100644 --- a/src/darksend.h +++ b/src/darksend.h @@ -289,6 +289,9 @@ private: int64_t lastNewBlock; + // Keep track of current block index + const CBlockIndex *pCurrentBlockIndex; + std::vector darkSendDenominationsSkipped; //debugging data @@ -535,6 +538,8 @@ public: void RelayIn(const std::vector& vin, const CAmount& nAmount, const CTransaction& txCollateral, const std::vector& vout); void RelayStatus(const int sessionID, const int newState, const int newEntriesCount, const int newAccepted, const int errorID=MSG_NOERR); void RelayCompletedTransaction(const int sessionID, const bool error, const int errorID); + + void UpdatedBlockTip(const CBlockIndex *pindex); }; void ThreadCheckDarkSendPool(); diff --git a/src/dsnotificationinterface.cpp b/src/dsnotificationinterface.cpp new file mode 100644 index 000000000..7fc227feb --- /dev/null +++ b/src/dsnotificationinterface.cpp @@ -0,0 +1,25 @@ +// Copyright (c) 2015 The Dash Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "dsnotificationinterface.h" +#include "darksend.h" +#include "masternode-budget.h" +#include "masternode-payments.h" +#include "masternode-sync.h" + +CDSNotificationInterface::CDSNotificationInterface() +{ +} + +CDSNotificationInterface::~CDSNotificationInterface() +{ +} + +void CDSNotificationInterface::UpdatedBlockTip(const CBlockIndex *pindex) +{ + darkSendPool.UpdatedBlockTip(pindex); + mnpayments.UpdatedBlockTip(pindex); + budget.UpdatedBlockTip(pindex); + masternodeSync.UpdatedBlockTip(pindex); +} diff --git a/src/dsnotificationinterface.h b/src/dsnotificationinterface.h new file mode 100644 index 000000000..abc0d501b --- /dev/null +++ b/src/dsnotificationinterface.h @@ -0,0 +1,24 @@ +// Copyright (c) 2015 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_DSNOTIFICATIONINTERFACE_H +#define BITCOIN_DSNOTIFICATIONINTERFACE_H + +#include "validationinterface.h" + +class CDSNotificationInterface : public CValidationInterface +{ +public: + // virtual CDSNotificationInterface(); + CDSNotificationInterface(); + virtual ~CDSNotificationInterface(); + +protected: + // CValidationInterface + void UpdatedBlockTip(const CBlockIndex *pindex); + +private: +}; + +#endif // BITCOIN_DSNOTIFICATIONINTERFACE_H diff --git a/src/init.cpp b/src/init.cpp index 6b8ea4c9b..f5225746e 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -70,6 +70,8 @@ #include "zmq/zmqnotificationinterface.h" #endif +#include "dsnotificationinterface.h" + using namespace std; #ifdef ENABLE_WALLET @@ -87,6 +89,8 @@ static const bool DEFAULT_STOPAFTERBLOCKIMPORT = false; static CZMQNotificationInterface* pzmqNotificationInterface = NULL; #endif +static CDSNotificationInterface* pdsNotificationInterface = NULL; + #ifdef WIN32 // Win32 LevelDB doesn't use filedescriptors, and the ones used for // accessing block files don't count towards the fd_set size limit @@ -254,6 +258,12 @@ void PrepareShutdown() } #endif + if (pdsNotificationInterface) { + UnregisterValidationInterface(pdsNotificationInterface); + delete pdsNotificationInterface; + pdsNotificationInterface = NULL; + } + #ifndef WIN32 try { boost::filesystem::remove(GetPidFile()); @@ -1428,6 +1438,10 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) RegisterValidationInterface(pzmqNotificationInterface); } #endif + + pdsNotificationInterface = new CDSNotificationInterface(); + RegisterValidationInterface(pdsNotificationInterface); + if (mapArgs.count("-maxuploadtarget")) { CNode::SetMaxOutboundTarget(GetArg("-maxuploadtarget", DEFAULT_MAX_UPLOAD_TARGET)*1024*1024); } @@ -1938,6 +1952,10 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) darkSendPool.InitDenominations(); darkSendPool.InitCollateralAddress(); + // force UpdatedBlockTip to initialize pCurrentBlockIndex for DS, MN payments and budgets + GetMainSignals().UpdatedBlockTip(chainActive.Tip()); + + // start dash-darksend thread threadGroup.create_thread(boost::bind(&ThreadCheckDarkSendPool)); // ********************************************************* Step 11: start node diff --git a/src/instantx.cpp b/src/instantx.cpp index 6e9907dc6..5286cbeb6 100644 --- a/src/instantx.cpp +++ b/src/instantx.cpp @@ -235,7 +235,13 @@ int64_t CreateNewLock(CTransaction tx) This prevents attackers from using transaction mallibility to predict which masternodes they'll use. */ - int nBlockHeight = (chainActive.Tip()->nHeight - nTxAge)+4; + int nBlockHeight = 0; + { + LOCK(cs_main); + CBlockIndex* tip = chainActive.Tip(); + if(tip) nBlockHeight = tip->nHeight - nTxAge + 4; + else return 0; + } if (!mapTxLocks.count(tx.GetHash())){ LogPrintf("CreateNewLock - New Transaction Lock %s !\n", tx.GetHash().ToString().c_str()); @@ -434,8 +440,6 @@ int64_t GetAverageVoteTime() void CleanTransactionLocksList() { - if(chainActive.Tip() == NULL) return; - std::map::iterator it = mapTxLocks.begin(); while(it != mapTxLocks.end()) { @@ -460,7 +464,6 @@ void CleanTransactionLocksList() it++; } } - } uint256 CConsensusVote::GetHash() const diff --git a/src/main.cpp b/src/main.cpp index 42089ec7e..1755860dd 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3527,14 +3527,6 @@ bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, c if (!ActivateBestChain(state, chainparams, pblock)) return error("%s: ActivateBestChain failed", __func__); - if(!fLiteMode){ - if (masternodeSync.RequestedMasternodeAssets > MASTERNODE_SYNC_LIST) { - darkSendPool.NewBlock(); - mnpayments.ProcessBlock(GetHeight()+10); - budget.NewBlock(); - } - } - LogPrintf("%s : ACCEPTED\n", __func__); return true; } diff --git a/src/masternode-budget.cpp b/src/masternode-budget.cpp index 7c7cf15c9..aaa86df85 100644 --- a/src/masternode-budget.cpp +++ b/src/masternode-budget.cpp @@ -57,6 +57,7 @@ bool IsBudgetCollateralValid(uint256 nTxCollateralHash, uint256 nExpectedHash, s return false; } + LOCK(cs_main); int conf = GetIXConfirmations(nTxCollateralHash); if (nBlockHash != uint256()) { BlockMap::iterator mi = mapBlockIndex.find(nBlockHash); @@ -109,12 +110,11 @@ void CBudgetManager::CheckOrphanVotes() void CBudgetManager::SubmitFinalBudget() { - CBlockIndex* pindexPrev = chainActive.Tip(); - if(!pindexPrev) return; + if(!pCurrentBlockIndex) return; - int nBlockStart = pindexPrev->nHeight - pindexPrev->nHeight % Params().GetConsensus().nBudgetPaymentsCycleBlocks + Params().GetConsensus().nBudgetPaymentsCycleBlocks; + int nBlockStart = pCurrentBlockIndex->nHeight - pCurrentBlockIndex->nHeight % Params().GetConsensus().nBudgetPaymentsCycleBlocks + Params().GetConsensus().nBudgetPaymentsCycleBlocks; if(nSubmittedFinalBudget >= nBlockStart) return; - if(nBlockStart - pindexPrev->nHeight > 576*2) return; //submit final budget 2 days before payment + if(nBlockStart - pCurrentBlockIndex->nHeight > 576*2) return; //submit final budget 2 days before payment std::vector vBudgetProposals = budget.GetBudget(); std::string strBudgetName = "main"; @@ -136,7 +136,7 @@ void CBudgetManager::SubmitFinalBudget() CFinalizedBudgetBroadcast tempBudget(strBudgetName, nBlockStart, vecTxBudgetPayments, uint256()); if(mapSeenFinalizedBudgets.count(tempBudget.GetHash())) { LogPrintf("CBudgetManager::SubmitFinalBudget - Budget already exists - %s\n", tempBudget.GetHash().ToString()); - nSubmittedFinalBudget = pindexPrev->nHeight; + nSubmittedFinalBudget = pCurrentBlockIndex->nHeight; return; //already exists } @@ -177,7 +177,7 @@ void CBudgetManager::SubmitFinalBudget() CFinalizedBudgetBroadcast finalizedBudgetBroadcast(strBudgetName, nBlockStart, vecTxBudgetPayments, tx.GetHash()); std::string strError = ""; - if(!finalizedBudgetBroadcast.IsValid(strError)){ + if(!finalizedBudgetBroadcast.IsValid(pCurrentBlockIndex, strError)){ LogPrintf("CBudgetManager::SubmitFinalBudget - Invalid finalized budget - %s \n", strError); return; } @@ -355,7 +355,7 @@ void DumpBudgets() bool CBudgetManager::AddFinalizedBudget(CFinalizedBudget& finalizedBudget) { std::string strError = ""; - if(!finalizedBudget.IsValid(strError)) return false; + if(!finalizedBudget.IsValid(pCurrentBlockIndex, strError)) return false; if(mapFinalizedBudgets.count(finalizedBudget.GetHash())) { return false; @@ -369,7 +369,7 @@ bool CBudgetManager::AddProposal(CBudgetProposal& budgetProposal) { LOCK(cs); std::string strError = ""; - if(!budgetProposal.IsValid(strError)) { + if(!budgetProposal.IsValid(pCurrentBlockIndex, strError)) { LogPrintf("CBudgetManager::AddProposal - invalid budget proposal - %s\n", strError); return false; } @@ -386,9 +386,7 @@ void CBudgetManager::CheckAndRemove() { LogPrintf("CBudgetManager::CheckAndRemove \n"); - CBlockIndex* pindexPrev = chainActive.Tip(); - if(!pindexPrev) return; - + if(!pCurrentBlockIndex) return; std::string strError = ""; std::map::iterator it = mapFinalizedBudgets.begin(); @@ -396,13 +394,13 @@ void CBudgetManager::CheckAndRemove() { CFinalizedBudget* pfinalizedBudget = &((*it).second); - pfinalizedBudget->fValid = pfinalizedBudget->IsValid(strError); + pfinalizedBudget->fValid = pfinalizedBudget->IsValid(pCurrentBlockIndex, strError); if(pfinalizedBudget->fValid) { pfinalizedBudget->AutoCheck(); ++it; // if it's too old, remove it - } else if(pfinalizedBudget->nBlockStart != 0 && pfinalizedBudget->nBlockStart < pindexPrev->nHeight - Params().GetConsensus().nBudgetPaymentsCycleBlocks) { + } else if(pfinalizedBudget->nBlockStart != 0 && pfinalizedBudget->nBlockStart < pCurrentBlockIndex->nHeight - Params().GetConsensus().nBudgetPaymentsCycleBlocks) { mapFinalizedBudgets.erase(it++); LogPrintf("CBudgetManager::CheckAndRemove - removing budget %s\n", pfinalizedBudget->GetHash().ToString()); } @@ -412,7 +410,7 @@ void CBudgetManager::CheckAndRemove() while(it2 != mapProposals.end()) { CBudgetProposal* pbudgetProposal = &((*it2).second); - pbudgetProposal->fValid = pbudgetProposal->IsValid(strError); + pbudgetProposal->fValid = pbudgetProposal->IsValid(pCurrentBlockIndex, strError); ++it2; } } @@ -421,8 +419,7 @@ void CBudgetManager::FillBlockPayee(CMutableTransaction& txNew, CAmount nFees) { LOCK(cs); - CBlockIndex* pindexPrev = chainActive.Tip(); - if(!pindexPrev) return; + if(!pCurrentBlockIndex) return; int nHighestCount = 0; CScript payee; @@ -435,19 +432,17 @@ void CBudgetManager::FillBlockPayee(CMutableTransaction& txNew, CAmount nFees) { CFinalizedBudget* pfinalizedBudget = &((*it).second); if(pfinalizedBudget->GetVoteCount() > nHighestCount && - pindexPrev->nHeight + 1 >= pfinalizedBudget->GetBlockStart() && - pindexPrev->nHeight + 1 <= pfinalizedBudget->GetBlockEnd() && - pfinalizedBudget->GetPayeeAndAmount(pindexPrev->nHeight + 1, payee, nAmount)){ + pCurrentBlockIndex->nHeight + 1 >= pfinalizedBudget->GetBlockStart() && + pCurrentBlockIndex->nHeight + 1 <= pfinalizedBudget->GetBlockEnd() && + pfinalizedBudget->GetPayeeAndAmount(pCurrentBlockIndex->nHeight + 1, payee, nAmount)){ nHighestCount = pfinalizedBudget->GetVoteCount(); } ++it; } - CAmount blockValue = nFees + GetBlockSubsidy(pindexPrev->nBits, pindexPrev->nHeight, Params().GetConsensus()); - //miners get the full amount on these blocks - txNew.vout[0].nValue = blockValue; + txNew.vout[0].nValue = nFees + GetBlockSubsidy(pCurrentBlockIndex->nBits, pCurrentBlockIndex->nHeight, Params().GetConsensus()); if(nHighestCount > 0){ txNew.vout.resize(2); @@ -531,13 +526,12 @@ bool CBudgetManager::IsBudgetPaymentBlock(int nBlockHeight) bool CBudgetManager::HasNextFinalizedBudget() { - CBlockIndex* pindexPrev = chainActive.Tip(); - if(!pindexPrev) return false; + if(!pCurrentBlockIndex) return false; if(masternodeSync.IsBudgetFinEmpty()) return true; - int nBlockStart = pindexPrev->nHeight - pindexPrev->nHeight % Params().GetConsensus().nBudgetPaymentsCycleBlocks + Params().GetConsensus().nBudgetPaymentsCycleBlocks; - if(nBlockStart - pindexPrev->nHeight > 576*2) return true; //we wouldn't have the budget yet + int nBlockStart = pCurrentBlockIndex->nHeight - pCurrentBlockIndex->nHeight % Params().GetConsensus().nBudgetPaymentsCycleBlocks + Params().GetConsensus().nBudgetPaymentsCycleBlocks; + if(nBlockStart - pCurrentBlockIndex->nHeight > 576*2) return true; //we wouldn't have the budget yet if(budget.IsBudgetPaymentBlock(nBlockStart)) return true; @@ -649,10 +643,9 @@ std::vector CBudgetManager::GetBudget() std::vector vBudgetProposalsRet; CAmount nBudgetAllocated = 0; - CBlockIndex* pindexPrev = chainActive.Tip(); - if(pindexPrev == NULL) return vBudgetProposalsRet; + if(!pCurrentBlockIndex) return vBudgetProposalsRet; - int nBlockStart = pindexPrev->nHeight - pindexPrev->nHeight % Params().GetConsensus().nBudgetPaymentsCycleBlocks + Params().GetConsensus().nBudgetPaymentsCycleBlocks; + int nBlockStart = pCurrentBlockIndex->nHeight - pCurrentBlockIndex->nHeight % Params().GetConsensus().nBudgetPaymentsCycleBlocks + Params().GetConsensus().nBudgetPaymentsCycleBlocks; int nBlockEnd = nBlockStart + Params().GetConsensus().nBudgetPaymentsWindowBlocks; CAmount nTotalBudget = GetTotalBudget(nBlockStart); @@ -765,7 +758,7 @@ std::string CBudgetManager::GetRequiredPaymentsString(int nBlockHeight) CAmount CBudgetManager::GetTotalBudget(int nHeight) { - if(chainActive.Tip() == NULL) return 0; + if(!pCurrentBlockIndex) return 0; //get min block value and calculate from that CAmount nSubsidy = 5 * COIN; @@ -793,6 +786,8 @@ void CBudgetManager::NewBlock() TRY_LOCK(cs, fBudgetNewBlock); if(!fBudgetNewBlock) return; + if(!pCurrentBlockIndex) return; + if (masternodeSync.RequestedMasternodeAssets <= MASTERNODE_SYNC_BUDGET) return; if (strBudgetMode == "suggest") { //suggest the budget we see @@ -800,12 +795,12 @@ 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; + if(pCurrentBlockIndex->nHeight % 6 != 0) return; // incremental sync with our peers if(masternodeSync.IsSynced()){ LogPrintf("CBudgetManager::NewBlock - incremental sync started\n"); - if(chainActive.Height() % 600 == rand() % 600) { + if(pCurrentBlockIndex->nHeight % 600 == rand() % 600) { ClearSeen(); ResetSync(); } @@ -814,10 +809,9 @@ void CBudgetManager::NewBlock() BOOST_FOREACH(CNode* pnode, vNodes) if(pnode->nVersion >= MIN_BUDGET_PEER_PROTO_VERSION) Sync(pnode, uint256(), true); - + MarkSynced(); } - CheckAndRemove(); @@ -854,7 +848,7 @@ void CBudgetManager::NewBlock() continue; } - if(!(*it4).IsValid(strError)) { + if(!(*it4).IsValid(pCurrentBlockIndex, strError)) { LogPrintf("mprop (immature) - invalid budget proposal - %s\n", strError); it4 = vecImmatureBudgetProposals.erase(it4); continue; @@ -877,7 +871,7 @@ void CBudgetManager::NewBlock() continue; } - if(!(*it5).IsValid(strError)) { + if(!(*it5).IsValid(pCurrentBlockIndex, strError)) { LogPrintf("fbs (immature) - invalid finalized budget - %s\n", strError); it5 = vecImmatureFinalizedBudgets.erase(it5); continue; @@ -939,7 +933,7 @@ void CBudgetManager::ProcessMessage(CNode* pfrom, std::string& strCommand, CData mapSeenMasternodeBudgetProposals.insert(make_pair(budgetProposalBroadcast.GetHash(), budgetProposalBroadcast)); - if(!budgetProposalBroadcast.IsValid(strError)) { + if(!budgetProposalBroadcast.IsValid(pCurrentBlockIndex, strError)) { LogPrintf("mprop - invalid budget proposal - %s\n", strError); return; } @@ -980,7 +974,7 @@ void CBudgetManager::ProcessMessage(CNode* pfrom, std::string& strCommand, CData mnodeman.AskForMN(pfrom, vote.vin); return; } - + std::string strError = ""; if(UpdateProposal(vote, pfrom, strError)) { vote.Relay(); @@ -1010,7 +1004,7 @@ void CBudgetManager::ProcessMessage(CNode* pfrom, std::string& strCommand, CData mapSeenFinalizedBudgets.insert(make_pair(finalizedBudgetBroadcast.GetHash(), finalizedBudgetBroadcast)); - if(!finalizedBudgetBroadcast.IsValid(strError)) { + if(!finalizedBudgetBroadcast.IsValid(pCurrentBlockIndex, strError)) { LogPrintf("fbs - invalid finalized budget - %s\n", strError); return; } @@ -1320,7 +1314,7 @@ CBudgetProposal::CBudgetProposal(std::string strProposalNameIn, std::string strU nFeeTXHash = nFeeTXHashIn; } -bool CBudgetProposal::IsValid(std::string& strError, bool fCheckCollateral) +bool CBudgetProposal::IsValid(const CBlockIndex* pindex, std::string& strError, bool fCheckCollateral) { if(GetNoCount() - GetYesCount() > mnodeman.CountEnabled(MIN_BUDGET_PEER_PROTO_VERSION)/10){ strError = "Active removal"; @@ -1332,11 +1326,13 @@ bool CBudgetProposal::IsValid(std::string& strError, bool fCheckCollateral) return false; } - CBlockIndex* pindexPrev = chainActive.Tip(); - if(pindexPrev == NULL) {strError = "Tip is NULL"; return true;} + if(!pindex) { + strError = "Tip is NULL"; + return true; + } if(nBlockStart % Params().GetConsensus().nBudgetPaymentsCycleBlocks != 0){ - int nNext = pindexPrev->nHeight - pindexPrev->nHeight % Params().GetConsensus().nBudgetPaymentsCycleBlocks + Params().GetConsensus().nBudgetPaymentsCycleBlocks; + int nNext = pindex->nHeight - pindex->nHeight % Params().GetConsensus().nBudgetPaymentsCycleBlocks + Params().GetConsensus().nBudgetPaymentsCycleBlocks; strError = strprintf("Invalid block start - must be a budget cycle block. Next valid block: %d", nNext); return false; } @@ -1408,7 +1404,7 @@ bool CBudgetProposal::IsValid(std::string& strError, bool fCheckCollateral) return false; } - if(GetBlockEnd() + Params().GetConsensus().nBudgetPaymentsWindowBlocks < pindexPrev->nHeight) return false; + if(GetBlockEnd() + Params().GetConsensus().nBudgetPaymentsWindowBlocks < pindex->nHeight) return false; return true; @@ -1528,14 +1524,13 @@ int CBudgetProposal::GetBlockStartCycle() return nBlockStart - nBlockStart % Params().GetConsensus().nBudgetPaymentsCycleBlocks; } -int CBudgetProposal::GetBlockCurrentCycle() +int CBudgetProposal::GetBlockCurrentCycle(const CBlockIndex* pindex) { - CBlockIndex* pindexPrev = chainActive.Tip(); - if(pindexPrev == NULL) return -1; + if(!pindex) return -1; - if(pindexPrev->nHeight >= GetBlockEndCycle()) return -1; + if(pindex->nHeight >= GetBlockEndCycle()) return -1; - return pindexPrev->nHeight - pindexPrev->nHeight % Params().GetConsensus().nBudgetPaymentsCycleBlocks; + return pindex->nHeight - pindex->nHeight % Params().GetConsensus().nBudgetPaymentsCycleBlocks; } int CBudgetProposal::GetBlockEndCycle() @@ -1850,7 +1845,7 @@ std::string CFinalizedBudget::GetStatus() return retBadHashes + retBadPayeeOrAmount; } -bool CFinalizedBudget::IsValid(std::string& strError, bool fCheckCollateral) +bool CFinalizedBudget::IsValid(const CBlockIndex* pindex, std::string& strError, bool fCheckCollateral) { //must be the correct block for payment to happen (once a month) if(nBlockStart % Params().GetConsensus().nBudgetPaymentsCycleBlocks != 0) {strError = "Invalid BlockStart"; return false;} @@ -1867,16 +1862,19 @@ bool CFinalizedBudget::IsValid(std::string& strError, bool fCheckCollateral) if(fCheckCollateral){ int nConf = 0; if(!IsBudgetCollateralValid(nFeeTXHash, GetHash(), strError2, nTime, nConf)){ - {strError = "Invalid Collateral : " + strError2; return false;} + strError = "Invalid Collateral : " + strError2; + return false; } } //TODO: if N cycles old, invalid, invalid - CBlockIndex* pindexPrev = chainActive.Tip(); - if(pindexPrev == NULL) return true; + if(!pindex) return true; - if(nBlockStart < pindexPrev->nHeight - Params().GetConsensus().nBudgetPaymentsWindowBlocks) {strError = "Older than current blockHeight"; return false;} + if(nBlockStart < pindex->nHeight - Params().GetConsensus().nBudgetPaymentsWindowBlocks) { + strError = "Older than current blockHeight"; + return false; + } return true; } @@ -2059,4 +2057,11 @@ std::string CBudgetManager::ToString() const return info.str(); } +void CBudgetManager::UpdatedBlockTip(const CBlockIndex *pindex) +{ + pCurrentBlockIndex = pindex; + LogPrint("mnbudget", "pCurrentBlockIndex->nHeight: %d\n", pCurrentBlockIndex->nHeight); + if(!fLiteMode && masternodeSync.RequestedMasternodeAssets > MASTERNODE_SYNC_LIST) + NewBlock(); +} diff --git a/src/masternode-budget.h b/src/masternode-budget.h index eb2e1bcc1..1a6b4334b 100644 --- a/src/masternode-budget.h +++ b/src/masternode-budget.h @@ -78,6 +78,8 @@ private: //hold txes until they mature enough to use map mapCollateral; + // Keep track of current block index + const CBlockIndex *pCurrentBlockIndex; public: // critical section to protect the inner data structures @@ -179,6 +181,8 @@ public: READWRITE(mapProposals); READWRITE(mapFinalizedBudgets); } + + void UpdatedBlockTip(const CBlockIndex *pindex); }; @@ -235,7 +239,7 @@ public: double GetScore(); bool HasMinimumRequiredSupport(); - bool IsValid(std::string& strError, bool fCheckCollateral=true); + bool IsValid(const CBlockIndex* pindex, std::string& strError, bool fCheckCollateral=true); std::string GetName() {return strBudgetName; } std::string GetProposals(); @@ -427,7 +431,7 @@ public: bool HasMinimumRequiredSupport(); std::pair GetVotes(); - bool IsValid(std::string& strError, bool fCheckCollateral=true); + bool IsValid(const CBlockIndex* pindex, std::string& strError, bool fCheckCollateral=true); bool IsEstablished(); std::string GetName() {return strProposalName; } @@ -438,7 +442,7 @@ public: int GetTotalPaymentCount(); int GetRemainingPaymentCount(); int GetBlockStartCycle(); - int GetBlockCurrentCycle(); + int GetBlockCurrentCycle(const CBlockIndex* pindex); int GetBlockEndCycle(); double GetRatio(); int GetAbsoluteYesCount(); diff --git a/src/masternode-payments.cpp b/src/masternode-payments.cpp index de8c1daa7..fbd63ad99 100644 --- a/src/masternode-payments.cpp +++ b/src/masternode-payments.cpp @@ -183,19 +183,21 @@ void DumpMasternodePayments() } bool IsBlockValueValid(const CBlock& block, CAmount nExpectedValue){ - CBlockIndex* pindexPrev = chainActive.Tip(); - if(pindexPrev == NULL) return true; - int nHeight = 0; - if(pindexPrev->GetBlockHash() == block.hashPrevBlock) - { - nHeight = pindexPrev->nHeight+1; - } else { //out of order - BlockMap::iterator mi = mapBlockIndex.find(block.hashPrevBlock); - if (mi != mapBlockIndex.end() && (*mi).second) - nHeight = (*mi).second->nHeight+1; - } + { + LOCK(cs_main); + if(!chainActive.Tip()) return true; + + if(chainActive.Tip()->GetBlockHash() == block.hashPrevBlock) + { + nHeight = chainActive.Tip()->nHeight+1; + } else { //out of order + BlockMap::iterator mi = mapBlockIndex.find(block.hashPrevBlock); + if (mi != mapBlockIndex.end() && (*mi).second) + nHeight = (*mi).second->nHeight+1; + } + } if(nHeight == 0){ LogPrintf("IsBlockValueValid() : WARNING: Couldn't find previous block"); } @@ -269,10 +271,9 @@ bool IsBlockPayeeValid(const CTransaction& txNew, int nBlockHeight) void FillBlockPayee(CMutableTransaction& txNew, CAmount nFees) { - CBlockIndex* pindexPrev = chainActive.Tip(); - if(!pindexPrev) return; + if(!chainActive.Tip()) return; - if(IsSporkActive(SPORK_13_ENABLE_SUPERBLOCKS) && budget.IsBudgetPaymentBlock(pindexPrev->nHeight+1)){ + if(IsSporkActive(SPORK_13_ENABLE_SUPERBLOCKS) && budget.IsBudgetPaymentBlock(chainActive.Tip()->nHeight+1)){ budget.FillBlockPayee(txNew, nFees); } else { mnpayments.FillBlockPayee(txNew, nFees); @@ -290,14 +291,13 @@ std::string GetRequiredPaymentsString(int nBlockHeight) void CMasternodePayments::FillBlockPayee(CMutableTransaction& txNew, CAmount nFees) { - CBlockIndex* pindexPrev = chainActive.Tip(); - if(!pindexPrev) return; + if(!pCurrentBlockIndex) return; bool hasPayment = true; CScript payee; //spork - if(!mnpayments.GetBlockPayee(pindexPrev->nHeight+1, payee)){ + if(!mnpayments.GetBlockPayee(pCurrentBlockIndex->nHeight+1, payee)){ //no masternode detected CMasternode* winningNode = mnodeman.GetCurrentMasterNode(); if(winningNode){ @@ -308,8 +308,8 @@ void CMasternodePayments::FillBlockPayee(CMutableTransaction& txNew, CAmount nFe } } - CAmount blockValue = nFees + GetBlockSubsidy(pindexPrev->nBits, pindexPrev->nHeight, Params().GetConsensus()); - CAmount masternodePayment = GetMasternodePayment(pindexPrev->nHeight+1, blockValue); + CAmount blockValue = nFees + GetBlockSubsidy(pCurrentBlockIndex->nBits, pCurrentBlockIndex->nHeight, Params().GetConsensus()); + CAmount masternodePayment = GetMasternodePayment(pCurrentBlockIndex->nHeight+1, blockValue); txNew.vout[0].nValue = blockValue; @@ -367,17 +367,17 @@ void CMasternodePayments::ProcessMessageMasternodePayments(CNode* pfrom, std::st if(pfrom->nVersion < MIN_MNW_PEER_PROTO_VERSION) return; - if(chainActive.Tip() == NULL) return; + if(!pCurrentBlockIndex) return; if(mnpayments.mapMasternodePayeeVotes.count(winner.GetHash())){ - LogPrint("mnpayments", "mnw - Already seen - %s bestHeight %d\n", winner.GetHash().ToString().c_str(), chainActive.Tip()->nHeight); + LogPrint("mnpayments", "mnw - Already seen - %s bestHeight %d\n", winner.GetHash().ToString().c_str(), pCurrentBlockIndex->nHeight); masternodeSync.AddedMasternodeWinner(winner.GetHash()); return; } - int nFirstBlock = chainActive.Tip()->nHeight - (mnodeman.CountEnabled()*1.25); - if(winner.nBlockHeight < nFirstBlock || winner.nBlockHeight > chainActive.Tip()->nHeight+20){ - LogPrint("mnpayments", "mnw - winner out of range - FirstBlock %d Height %d bestHeight %d\n", nFirstBlock, winner.nBlockHeight, chainActive.Tip()->nHeight); + int nFirstBlock = pCurrentBlockIndex->nHeight - (mnodeman.CountEnabled()*1.25); + if(winner.nBlockHeight < nFirstBlock || winner.nBlockHeight > pCurrentBlockIndex->nHeight+20){ + LogPrint("mnpayments", "mnw - winner out of range - FirstBlock %d Height %d bestHeight %d\n", nFirstBlock, winner.nBlockHeight, pCurrentBlockIndex->nHeight); return; } @@ -404,7 +404,7 @@ void CMasternodePayments::ProcessMessageMasternodePayments(CNode* pfrom, std::st ExtractDestination(winner.payee, address1); CBitcoinAddress address2(address1); - 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, pCurrentBlockIndex->nHeight, winner.vinMasternode.prevout.ToStringShort()); if(mnpayments.AddWinningMasternode(winner)){ winner.Relay(); @@ -450,14 +450,13 @@ bool CMasternodePayments::IsScheduled(CMasternode& mn, int nNotBlockHeight) { LOCK(cs_mapMasternodeBlocks); - CBlockIndex* pindexPrev = chainActive.Tip(); - if(pindexPrev == NULL) return false; + if(!pCurrentBlockIndex) return false; CScript mnpayee; mnpayee = GetScriptForDestination(mn.pubkey.GetID()); CScript payee; - for(int64_t h = pindexPrev->nHeight; h <= pindexPrev->nHeight+8; h++){ + for(int64_t h = pCurrentBlockIndex->nHeight; h <= pCurrentBlockIndex->nHeight + 8; h++){ if(h == nNotBlockHeight) continue; if(mapMasternodeBlocks.count(h)){ if(mapMasternodeBlocks[h].GetPayee(payee)){ @@ -593,18 +592,18 @@ bool CMasternodePayments::IsTransactionValid(const CTransaction& txNew, int nBlo void CMasternodePayments::CleanPaymentList() { + if(!pCurrentBlockIndex) return; + LOCK2(cs_mapMasternodePayeeVotes, cs_mapMasternodeBlocks); - if(chainActive.Tip() == NULL) return; - - //keep up to five cycles for historical sake - int nLimit = std::max(int(mnodeman.size()*1.25), 1000); + // keep a bit more for historical sake but at least 4000 + int nLimit = std::max(int(mnodeman.size()*1.25), 4000); std::map::iterator it = mapMasternodePayeeVotes.begin(); while(it != mapMasternodePayeeVotes.end()) { CMasternodePaymentWinner winner = (*it).second; - if(chainActive.Tip()->nHeight - winner.nBlockHeight > nLimit){ + if(pCurrentBlockIndex->nHeight - winner.nBlockHeight > nLimit){ LogPrint("mnpayments", "CMasternodePayments::CleanPaymentList - Removing old Masternode payment - block %d\n", winner.nBlockHeight); masternodeSync.mapSeenSyncMNW.erase((*it).first); mapMasternodePayeeVotes.erase(it++); @@ -777,7 +776,7 @@ void CMasternodePayments::Sync(CNode* node, int nCountNeeded) { LOCK(cs_mapMasternodePayeeVotes); - if(chainActive.Tip() == NULL) return; + if(!pCurrentBlockIndex) return; int nCount = (mnodeman.CountEnabled()*1.25); if(nCountNeeded > nCount) nCountNeeded = nCount; @@ -786,7 +785,7 @@ void CMasternodePayments::Sync(CNode* node, int nCountNeeded) std::map::iterator it = mapMasternodePayeeVotes.begin(); while(it != mapMasternodePayeeVotes.end()) { CMasternodePaymentWinner winner = (*it).second; - if(winner.nBlockHeight >= chainActive.Tip()->nHeight-nCountNeeded && winner.nBlockHeight <= chainActive.Tip()->nHeight + 20) { + if(winner.nBlockHeight >= pCurrentBlockIndex->nHeight - nCountNeeded && winner.nBlockHeight <= pCurrentBlockIndex->nHeight + 20) { node->PushInventory(CInv(MSG_MASTERNODE_WINNER, winner.GetHash())); nInvCount++; } @@ -842,3 +841,12 @@ int CMasternodePayments::GetNewestBlock() return nNewestBlock; } + +void CMasternodePayments::UpdatedBlockTip(const CBlockIndex *pindex) +{ + pCurrentBlockIndex = pindex; + LogPrint("mnpayments", "pCurrentBlockIndex->nHeight: %d\n", pCurrentBlockIndex->nHeight); + + if(!fLiteMode && masternodeSync.RequestedMasternodeAssets > MASTERNODE_SYNC_LIST) + ProcessBlock(pindex->nHeight+10); +} diff --git a/src/masternode-payments.h b/src/masternode-payments.h index c63974625..ae9b44388 100644 --- a/src/masternode-payments.h +++ b/src/masternode-payments.h @@ -226,6 +226,8 @@ class CMasternodePayments private: int nSyncedFromPeer; int nLastBlockHeight; + // Keep track of current block index + const CBlockIndex *pCurrentBlockIndex; public: std::map mapMasternodePayeeVotes; @@ -293,6 +295,8 @@ public: READWRITE(mapMasternodePayeeVotes); READWRITE(mapMasternodeBlocks); } + + void UpdatedBlockTip(const CBlockIndex *pindex); }; diff --git a/src/masternode-sync.cpp b/src/masternode-sync.cpp index a07a6571a..701111ee3 100644 --- a/src/masternode-sync.cpp +++ b/src/masternode-sync.cpp @@ -42,15 +42,8 @@ bool CMasternodeSync::IsBlockchainSynced() if (fImporting || fReindex) return false; - TRY_LOCK(cs_main, lockMain); - if(!lockMain) return false; - - CBlockIndex* pindex = chainActive.Tip(); - if(pindex == NULL) return false; - - - if(pindex->nTime + 60*60 < GetTime()) - return false; + if(!pCurrentBlockIndex) return false; + if(pCurrentBlockIndex->nTime + 60*60 < GetTime()) return false; fBlockchainSynced = true; @@ -227,8 +220,10 @@ void CMasternodeSync::Process() static int tick = 0; if(tick++ % 6 != 0) return; + if(!pCurrentBlockIndex) return; + //the actual count of masternodes we have currently - int nMnCount = mnodeman.CountEnabled(); + int nMnCount = mnodeman.CountEnabled(); // RESET SYNCING INCASE OF FAILURE { @@ -319,8 +314,8 @@ void CMasternodeSync::Process() // shall we move onto the next asset? - //printf("Masternode count %d est %d\n", nMnCount, mnodeman.GetEstimatedMasternodes(chainActive.Height())) ; - if(nMnCount > mnodeman.GetEstimatedMasternodes(chainActive.Height())*0.9) + //printf("Masternode count %d est %d\n", nMnCount, mnodeman.GetEstimatedMasternodes(pCurrentBlockIndex->nHeight)); + if(nMnCount > mnodeman.GetEstimatedMasternodes(pCurrentBlockIndex->nHeight)*0.9) { GetNextAsset(); //printf("synced masternode list successfully\n"); @@ -378,9 +373,6 @@ void CMasternodeSync::Process() if(pnode->HasFulfilledRequest("mnwsync")) continue; pnode->FulfilledRequest("mnwsync"); - CBlockIndex* pindexPrev = chainActive.Tip(); - if(pindexPrev == NULL) return; - int nMnCount = mnodeman.CountEnabled(); pnode->PushMessage(NetMsgType::MNWINNERSSYNC, nMnCount); //sync payees RequestedMasternodeAttempt++; @@ -435,3 +427,8 @@ void CMasternodeSync::Process() } } } + +void CMasternodeSync::UpdatedBlockTip(const CBlockIndex *pindex) +{ + pCurrentBlockIndex = pindex; +} diff --git a/src/masternode-sync.h b/src/masternode-sync.h index 3005ab6b4..647d0cc1c 100644 --- a/src/masternode-sync.h +++ b/src/masternode-sync.h @@ -55,6 +55,9 @@ public: // Time when current masternode asset sync started int64_t nAssetSyncStarted; + // Keep track of current block index + const CBlockIndex *pCurrentBlockIndex; + CMasternodeSync(); void AddedMasternodeList(uint256 hash); @@ -71,6 +74,8 @@ public: bool IsSynced(); bool IsBlockchainSynced(); void ClearFulfilledRequest(); + + void UpdatedBlockTip(const CBlockIndex *pindex); }; #endif diff --git a/src/masternode.cpp b/src/masternode.cpp index d1d76cd66..93349d660 100644 --- a/src/masternode.cpp +++ b/src/masternode.cpp @@ -21,6 +21,7 @@ std::map mapCacheBlockHashes; //Get the last hash that matches the modulus given. Processed in reverse order bool GetBlockHash(uint256& hash, int nBlockHeight) { + LOCK(cs_main); if (chainActive.Tip() == NULL) return false; if(nBlockHeight == 0) @@ -151,7 +152,10 @@ bool CMasternode::UpdateFromNewBroadcast(CMasternodeBroadcast& mnb) // uint256 CMasternode::CalculateScore(int mod, int64_t nBlockHeight) { - if(chainActive.Tip() == NULL) return uint256(); + { + LOCK(cs_main); + if(chainActive.Tip() == NULL) return uint256(); + } uint256 hash = uint256(); uint256 aux = ArithToUint256(UintToArith256(vin.prevout.hash) + vin.prevout.n); @@ -241,8 +245,13 @@ int64_t CMasternode::SecondsSincePayment() { } int64_t CMasternode::GetLastPaid() { - CBlockIndex* pindexPrev = chainActive.Tip(); - if(pindexPrev == NULL) return false; + CBlockIndex *pindexPrev = NULL; + { + LOCK(cs_main); + pindexPrev = chainActive.Tip(); + if(!pindexPrev) return 0; + } + CScript mnpayee; mnpayee = GetScriptForDestination(pubkey.GetID()); @@ -255,9 +264,7 @@ int64_t CMasternode::GetLastPaid() { // use a deterministic offset to break a tie -- 2.5 minutes int64_t nOffset = UintToArith256(hash).GetCompact(false) % 150; - if (chainActive.Tip() == NULL) return false; - - const CBlockIndex *BlockReading = chainActive.Tip(); + const CBlockIndex *BlockReading = pindexPrev; int nMnCount = mnodeman.CountEnabled()*1.25; int n = 0; @@ -473,19 +480,21 @@ bool CMasternodeBroadcast::CheckInputsAndAdd(int& nDoS) uint256 hashBlock = uint256(); CTransaction tx2; GetTransaction(vin.prevout.hash, tx2, Params().GetConsensus(), hashBlock, true); - BlockMap::iterator mi = mapBlockIndex.find(hashBlock); - if (mi != mapBlockIndex.end() && (*mi).second) { - CBlockIndex* pMNIndex = (*mi).second; // block for 1000 DASH tx -> 1 confirmation - CBlockIndex* pConfIndex = chainActive[pMNIndex->nHeight + MASTERNODE_MIN_CONFIRMATIONS - 1]; // block where tx got MASTERNODE_MIN_CONFIRMATIONS - if(pConfIndex->GetBlockTime() > sigTime) + LOCK(cs_main); + BlockMap::iterator mi = mapBlockIndex.find(hashBlock); + if (mi != mapBlockIndex.end() && (*mi).second) { - LogPrintf("mnb - Bad sigTime %d for Masternode %20s %105s (%i conf block is at %d)\n", - sigTime, addr.ToString(), vin.ToString(), MASTERNODE_MIN_CONFIRMATIONS, pConfIndex->GetBlockTime()); - return false; + CBlockIndex* pMNIndex = (*mi).second; // block for 1000 DASH tx -> 1 confirmation + CBlockIndex* pConfIndex = chainActive[pMNIndex->nHeight + MASTERNODE_MIN_CONFIRMATIONS - 1]; // block where tx got MASTERNODE_MIN_CONFIRMATIONS + if(pConfIndex->GetBlockTime() > sigTime) + { + LogPrintf("mnb - Bad sigTime %d for Masternode %20s %105s (%i conf block is at %d)\n", + sigTime, addr.ToString(), vin.ToString(), MASTERNODE_MIN_CONFIRMATIONS, pConfIndex->GetBlockTime()); + return false; + } } } - LogPrintf("mnb - Got NEW Masternode entry - %s - %s - %s - %lli \n", GetHash().ToString(), addr.ToString(), vin.ToString(), sigTime); CMasternode mn(*this); mnodeman.Add(mn); @@ -543,8 +552,17 @@ CMasternodePing::CMasternodePing() CMasternodePing::CMasternodePing(CTxIn& newVin) { + int nHeight; + { + LOCK(cs_main); + CBlockIndex* pindexPrev = chainActive.Tip(); + if(!pindexPrev) return; + + nHeight = pindexPrev->nHeight; + } + vin = newVin; - blockHash = chainActive[chainActive.Height() - 12]->GetBlockHash(); + blockHash = chainActive[nHeight - 12]->GetBlockHash(); sigTime = GetAdjustedTime(); vchSig = std::vector(); } @@ -608,25 +626,27 @@ bool CMasternodePing::CheckAndUpdate(int& nDos, bool fRequireEnabled) return false; } - BlockMap::iterator mi = mapBlockIndex.find(blockHash); - if (mi != mapBlockIndex.end() && (*mi).second) { - if((*mi).second->nHeight < chainActive.Height() - 24) + LOCK(cs_main); + BlockMap::iterator mi = mapBlockIndex.find(blockHash); + if (mi != mapBlockIndex.end() && (*mi).second) { - LogPrintf("CMasternodePing::CheckAndUpdate - Masternode %s block hash %s is too old\n", vin.ToString(), blockHash.ToString()); - // Do nothing here (no Masternode update, no mnping relay) - // Let this node to be visible but fail to accept mnping + if((*mi).second->nHeight < chainActive.Height() - 24) + { + LogPrintf("CMasternodePing::CheckAndUpdate - Masternode %s block hash %s is too old\n", vin.ToString(), blockHash.ToString()); + // Do nothing here (no Masternode update, no mnping relay) + // Let this node to be visible but fail to accept mnping + + return false; + } + } else { + if (fDebug) LogPrintf("CMasternodePing::CheckAndUpdate - Masternode %s block hash %s is unknown\n", vin.ToString(), blockHash.ToString()); + // maybe we stuck so we shouldn't ban this node, just fail to accept it + // TODO: or should we also request this block? return false; } - } else { - if (fDebug) LogPrintf("CMasternodePing::CheckAndUpdate - Masternode %s block hash %s is unknown\n", vin.ToString(), blockHash.ToString()); - // maybe we stuck so we shouldn't ban this node, just fail to accept it - // TODO: or should we also request this block? - - return false; } - pmn->lastPing = *this; //mnodeman.mapSeenMasternodeBroadcast.lastPing is probably outdated, so we'll update it diff --git a/src/masternode.h b/src/masternode.h index 183faf875..d438baec6 100644 --- a/src/masternode.h +++ b/src/masternode.h @@ -251,6 +251,7 @@ public: int GetMasternodeInputAge() { + LOCK(cs_main); if(chainActive.Tip() == NULL) return 0; if(cacheInputAge == 0){ @@ -258,7 +259,7 @@ public: cacheInputAgeBlock = chainActive.Tip()->nHeight; } - return cacheInputAge+(chainActive.Tip()->nHeight-cacheInputAgeBlock); + return cacheInputAge + (chainActive.Tip()->nHeight - cacheInputAgeBlock); } std::string Status() { diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp index 78fd819b3..6162a08f3 100644 --- a/src/qt/overviewpage.cpp +++ b/src/qt/overviewpage.cpp @@ -351,9 +351,6 @@ void OverviewPage::updateDarksendProgress() double nAverageAnonymizedRounds; { - TRY_LOCK(cs_main, lockMain); - if(!lockMain) return; - nDenominatedConfirmedBalance = pwalletMain->GetDenominatedBalance(); nDenominatedUnconfirmedBalance = pwalletMain->GetDenominatedBalance(true); nAnonymizableBalance = pwalletMain->GetAnonymizableBalance(); @@ -434,12 +431,10 @@ void OverviewPage::updateDarksendProgress() void OverviewPage::darkSendStatus() { - if (!chainActive.Tip()) return; if(!masternodeSync.IsBlockchainSynced() || ShutdownRequested()) return; static int64_t nLastDSProgressBlockTime = 0; - - int nBestHeight = chainActive.Tip()->nHeight; + int nBestHeight = clientModel->getNumBlocks(); // we we're processing more then 1 block per second, we'll just leave if(((nBestHeight - darkSendPool.cachedNumBlocks) / (GetTimeMillis() - nLastDSProgressBlockTime + 1) > 1)) return; diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index 422e59aff..ff59a95d4 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -583,9 +583,6 @@ void SendCoinsDialog::setBalance(const CAmount& balance, const CAmount& unconfir void SendCoinsDialog::updateDisplayUnit() { - TRY_LOCK(cs_main, lockMain); - if(!lockMain) return; - setBalance(model->getBalance(), model->getUnconfirmedBalance(), model->getImmatureBalance(), model->getAnonymizedBalance(), model->getWatchBalance(), model->getWatchUnconfirmedBalance(), model->getWatchImmatureBalance()); CoinControlDialog::coinControl->useDarkSend = ui->checkUseDarksend->isChecked(); diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 88679e541..9896ee566 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -146,9 +146,6 @@ void WalletModel::pollBalanceChanged() void WalletModel::checkBalanceChanged() { - TRY_LOCK(cs_main, lockMain); - if(!lockMain) return; - CAmount newBalance = getBalance(); CAmount newUnconfirmedBalance = getUnconfirmedBalance(); CAmount newImmatureBalance = getImmatureBalance(); diff --git a/src/rpcmasternode-budget.cpp b/src/rpcmasternode-budget.cpp index 5685969fb..e3de83dfa 100644 --- a/src/rpcmasternode-budget.cpp +++ b/src/rpcmasternode-budget.cpp @@ -53,19 +53,21 @@ UniValue mnbudget(const UniValue& params, bool fHelp) if(strCommand == "nextblock") { - CBlockIndex* pindexPrev = chainActive.Tip(); - if(!pindexPrev) return "unknown"; + LOCK(cs_main); + CBlockIndex* pindex = chainActive.Tip(); + if(!pindex) return "unknown"; - int nNext = pindexPrev->nHeight - pindexPrev->nHeight % Params().GetConsensus().nBudgetPaymentsCycleBlocks + Params().GetConsensus().nBudgetPaymentsCycleBlocks; + int nNext = pindex->nHeight - pindex->nHeight % Params().GetConsensus().nBudgetPaymentsCycleBlocks + Params().GetConsensus().nBudgetPaymentsCycleBlocks; return nNext; } if(strCommand == "nextsuperblocksize") { - CBlockIndex* pindexPrev = chainActive.Tip(); - if(!pindexPrev) return "unknown"; + LOCK(cs_main); + CBlockIndex* pindex = chainActive.Tip(); + if(!pindex) return "unknown"; - int nHeight = pindexPrev->nHeight - pindexPrev->nHeight % Params().GetConsensus().nBudgetPaymentsCycleBlocks + Params().GetConsensus().nBudgetPaymentsCycleBlocks; + int nHeight = pindex->nHeight - pindex->nHeight % Params().GetConsensus().nBudgetPaymentsCycleBlocks + Params().GetConsensus().nBudgetPaymentsCycleBlocks; CAmount nTotal = budget.GetTotalBudget(nHeight); return nTotal; @@ -77,7 +79,8 @@ UniValue mnbudget(const UniValue& params, bool fHelp) throw runtime_error("Correct usage is 'mnbudget prepare '"); int nBlockMin = 0; - CBlockIndex* pindexPrev = chainActive.Tip(); + LOCK(cs_main); + CBlockIndex* pindex = chainActive.Tip(); std::vector mnEntries; mnEntries = masternodeConfig.getEntries(); @@ -88,7 +91,7 @@ UniValue mnbudget(const UniValue& params, bool fHelp) int nBlockStart = params[4].get_int(); //set block min - if(pindexPrev != NULL) nBlockMin = pindexPrev->nHeight; + if(pindex != NULL) nBlockMin = pindex->nHeight; if(nBlockStart < nBlockMin) return "Invalid block start, must be more than current height."; @@ -107,7 +110,7 @@ UniValue mnbudget(const UniValue& params, bool fHelp) CBudgetProposalBroadcast budgetProposalBroadcast(strProposalName, strURL, nPaymentCount, scriptPubKey, nAmount, nBlockStart, uint256()); std::string strError = ""; - if(!budgetProposalBroadcast.IsValid(strError, false)) + if(!budgetProposalBroadcast.IsValid(pindex, strError, false)) return "Proposal is not valid - " + budgetProposalBroadcast.GetHash().ToString() + " - " + strError; bool useIX = false; //true; @@ -140,7 +143,8 @@ UniValue mnbudget(const UniValue& params, bool fHelp) } int nBlockMin = 0; - CBlockIndex* pindexPrev = chainActive.Tip(); + LOCK(cs_main); + CBlockIndex* pindex = chainActive.Tip(); std::vector mnEntries; mnEntries = masternodeConfig.getEntries(); @@ -151,7 +155,7 @@ UniValue mnbudget(const UniValue& params, bool fHelp) int nBlockStart = params[4].get_int(); //set block min - if(pindexPrev != NULL) nBlockMin = pindexPrev->nHeight; + if(pindex != NULL) nBlockMin = pindex->nHeight; if(nBlockStart < nBlockMin) return "Invalid payment count, must be more than current height."; @@ -170,7 +174,7 @@ UniValue mnbudget(const UniValue& params, bool fHelp) std::string strError = ""; - if(!budgetProposalBroadcast.IsValid(strError)){ + if(!budgetProposalBroadcast.IsValid(pindex, strError)){ return "Proposal is not valid - " + budgetProposalBroadcast.GetHash().ToString() + " - " + strError; } @@ -404,6 +408,12 @@ UniValue mnbudget(const UniValue& params, bool fHelp) if(strCommand == "projection") { + CBlockIndex* pindex; + { + LOCK(cs_main); + pindex = chainActive.Tip(); + } + UniValue resultObj(UniValue::VOBJ); CAmount nTotalAllotted = 0; @@ -434,7 +444,7 @@ UniValue mnbudget(const UniValue& params, bool fHelp) bObj.push_back(Pair("Alloted", ValueFromAmount(pbudgetProposal->GetAllotted()))); std::string strError = ""; - bObj.push_back(Pair("IsValid", pbudgetProposal->IsValid(strError))); + bObj.push_back(Pair("IsValid", pbudgetProposal->IsValid(pindex, strError))); bObj.push_back(Pair("IsValidReason", strError.c_str())); bObj.push_back(Pair("fValid", pbudgetProposal->fValid)); @@ -453,6 +463,12 @@ UniValue mnbudget(const UniValue& params, bool fHelp) std::string strShow = "valid"; if (params.size() == 2) strShow = params[1].get_str(); + CBlockIndex* pindex; + { + LOCK(cs_main); + pindex = chainActive.Tip(); + } + UniValue resultObj(UniValue::VOBJ); int64_t nTotalAllotted = 0; @@ -488,7 +504,7 @@ UniValue mnbudget(const UniValue& params, bool fHelp) bObj.push_back(Pair("IsEstablished", pbudgetProposal->IsEstablished())); std::string strError = ""; - bObj.push_back(Pair("IsValid", pbudgetProposal->IsValid(strError))); + bObj.push_back(Pair("IsValid", pbudgetProposal->IsValid(pindex, strError))); bObj.push_back(Pair("IsValidReason", strError.c_str())); bObj.push_back(Pair("fValid", pbudgetProposal->fValid)); @@ -544,6 +560,7 @@ UniValue mnbudget(const UniValue& params, bool fHelp) ExtractDestination(pbudgetProposal->GetPayee(), address1); CBitcoinAddress address2(address1); + LOCK(cs_main); UniValue obj(UniValue::VOBJ); obj.push_back(Pair("Name", pbudgetProposal->GetName())); obj.push_back(Pair("Hash", pbudgetProposal->GetHash().ToString())); @@ -565,7 +582,7 @@ UniValue mnbudget(const UniValue& params, bool fHelp) obj.push_back(Pair("IsEstablished", pbudgetProposal->IsEstablished())); std::string strError = ""; - obj.push_back(Pair("IsValid", pbudgetProposal->IsValid(strError))); + obj.push_back(Pair("IsValid", pbudgetProposal->IsValid(chainActive.Tip(), strError))); obj.push_back(Pair("fValid", pbudgetProposal->fValid)); return obj; @@ -803,6 +820,7 @@ UniValue mnfinalbudget(const UniValue& params, bool fHelp) UniValue resultObj(UniValue::VOBJ); std::vector winningFbs = budget.GetFinalizedBudgets(); + LOCK(cs_main); BOOST_FOREACH(CFinalizedBudget* finalizedBudget, winningFbs) { UniValue bObj(UniValue::VOBJ); @@ -815,7 +833,7 @@ UniValue mnfinalbudget(const UniValue& params, bool fHelp) bObj.push_back(Pair("Status", finalizedBudget->GetStatus())); std::string strError = ""; - bObj.push_back(Pair("IsValid", finalizedBudget->IsValid(strError))); + bObj.push_back(Pair("IsValid", finalizedBudget->IsValid(chainActive.Tip(), strError))); bObj.push_back(Pair("IsValidReason", strError.c_str())); resultObj.push_back(Pair(finalizedBudget->GetName(), bObj)); @@ -887,11 +905,11 @@ UniValue mnfinalbudget(const UniValue& params, bool fHelp) return "Invalid finalized proposal"; } + LOCK(cs_main); + CBlockIndex* pindex = chainActive.Tip(); + if(!pindex) return "invalid chaintip"; - CBlockIndex* pindexPrev = chainActive.Tip(); - if(!pindexPrev) return "invalid chaintip"; - - int nBlockStart = pindexPrev->nHeight - pindexPrev->nHeight % Params().GetConsensus().nBudgetPaymentsCycleBlocks + Params().GetConsensus().nBudgetPaymentsCycleBlocks; + int nBlockStart = pindex->nHeight - pindex->nHeight % Params().GetConsensus().nBudgetPaymentsCycleBlocks + Params().GetConsensus().nBudgetPaymentsCycleBlocks; CFinalizedBudgetBroadcast tempBudget("main", nBlockStart, vecTxBudgetPayments, uint256()); // if(mapSeenFinalizedBudgets.count(tempBudget.GetHash())) { @@ -945,10 +963,11 @@ UniValue mnfinalbudget(const UniValue& params, bool fHelp) return "Invalid finalized proposal"; } - CBlockIndex* pindexPrev = chainActive.Tip(); - if(!pindexPrev) return "invalid chaintip"; + LOCK(cs_main); + CBlockIndex* pindex = chainActive.Tip(); + if(!pindex) return "invalid chaintip"; - int nBlockStart = pindexPrev->nHeight - pindexPrev->nHeight % Params().GetConsensus().nBudgetPaymentsCycleBlocks + Params().GetConsensus().nBudgetPaymentsCycleBlocks; + int nBlockStart = pindex->nHeight - pindex->nHeight % Params().GetConsensus().nBudgetPaymentsCycleBlocks + Params().GetConsensus().nBudgetPaymentsCycleBlocks; // CTxIn in(COutPoint(nColHash, 0)); // int conf = GetInputAgeIX(nColHash, in); @@ -965,7 +984,7 @@ UniValue mnfinalbudget(const UniValue& params, bool fHelp) CFinalizedBudgetBroadcast finalizedBudgetBroadcast("main", nBlockStart, vecTxBudgetPayments, nColHash); std::string strError = ""; - if(!finalizedBudgetBroadcast.IsValid(strError)){ + if(!finalizedBudgetBroadcast.IsValid(pindex, strError)){ printf("CBudgetManager::SubmitFinalBudget - Invalid finalized budget - %s \n", strError.c_str()); return "invalid finalized budget"; } diff --git a/src/rpcmasternode.cpp b/src/rpcmasternode.cpp index 1cbfef9f3..c9e147fdd 100644 --- a/src/rpcmasternode.cpp +++ b/src/rpcmasternode.cpp @@ -155,8 +155,11 @@ UniValue masternode(const UniValue& params, bool fHelp) { int nCount = 0; - if(chainActive.Tip()) - mnodeman.GetNextMasternodeInQueueForPayment(chainActive.Tip()->nHeight, true, nCount); + { + LOCK(cs_main); + if(chainActive.Tip()) + mnodeman.GetNextMasternodeInQueueForPayment(chainActive.Tip()->nHeight, true, nCount); + } if(params[1].get_str() == "ds") return mnodeman.CountEnabled(MIN_POOL_PEER_PROTO_VERSION); if(params[1].get_str() == "enabled") return mnodeman.CountEnabled(); @@ -172,7 +175,10 @@ UniValue masternode(const UniValue& params, bool fHelp) if (strCommand == "current") { - CMasternode* winner = mnodeman.GetCurrentMasterNode(1); + LOCK(cs_main); + CMasternode* winner = NULL; + if(chainActive.Tip()) + winner = mnodeman.GetCurrentMasterNode(1); if(winner) { UniValue obj(UniValue::VOBJ); @@ -425,6 +431,15 @@ UniValue masternode(const UniValue& params, bool fHelp) if (strCommand == "winners") { + int nHeight; + { + LOCK(cs_main); + CBlockIndex* pindex = chainActive.Tip(); + if(!pindex) return NullUniValue; + + nHeight = pindex->nHeight; + } + int nLast = 10; if (params.size() >= 2){ @@ -433,9 +448,9 @@ UniValue masternode(const UniValue& params, bool fHelp) UniValue obj(UniValue::VOBJ); - for(int nHeight = chainActive.Tip()->nHeight-nLast; nHeight < chainActive.Tip()->nHeight+20; nHeight++) + for(int i = nHeight - nLast; i < nHeight + 20; i++) { - obj.push_back(Pair(strprintf("%d", nHeight), GetRequiredPaymentsString(nHeight))); + obj.push_back(Pair(strprintf("%d", i), GetRequiredPaymentsString(i))); } return obj; @@ -447,6 +462,15 @@ UniValue masternode(const UniValue& params, bool fHelp) if (strCommand == "calcscore") { + int nHeight; + { + LOCK(cs_main); + CBlockIndex* pindex = chainActive.Tip(); + if(!pindex) return NullUniValue; + + nHeight = pindex->nHeight; + } + int nLast = 10; if (params.size() >= 2){ @@ -455,18 +479,18 @@ UniValue masternode(const UniValue& params, bool fHelp) UniValue obj(UniValue::VOBJ); std::vector vMasternodes = mnodeman.GetFullMasternodeVector(); - for(int nHeight = chainActive.Tip()->nHeight-nLast; nHeight < chainActive.Tip()->nHeight+20; nHeight++){ + for(int i = nHeight - nLast; i < nHeight + 20; i++){ arith_uint256 nHigh = 0; CMasternode *pBestMasternode = NULL; BOOST_FOREACH(CMasternode& mn, vMasternodes) { - arith_uint256 n = UintToArith256(mn.CalculateScore(1, nHeight-100)); + arith_uint256 n = UintToArith256(mn.CalculateScore(1, i - 100)); if(n > nHigh){ nHigh = n; pBestMasternode = &mn; } } if(pBestMasternode) - obj.push_back(Pair(strprintf("%d", nHeight), pBestMasternode->vin.prevout.ToStringShort().c_str())); + obj.push_back(Pair(strprintf("%d", i), pBestMasternode->vin.prevout.ToStringShort().c_str())); } return obj; diff --git a/src/spork.cpp b/src/spork.cpp index a1ff43b8e..51d291cbc 100644 --- a/src/spork.cpp +++ b/src/spork.cpp @@ -39,6 +39,7 @@ void ProcessSpork(CNode* pfrom, std::string& strCommand, CDataStream& vRecv) CSporkMessage spork; vRecv >> spork; + LOCK(cs_main); if(chainActive.Tip() == NULL) return; uint256 hash = spork.GetHash(); diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp index d9aba92de..a4fd060e6 100644 --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -8,6 +8,7 @@ #include "consensus/merkle.h" #include "consensus/validation.h" #include "main.h" +#include "masternode-payments.h" #include "miner.h" #include "pubkey.h" #include "script/standard.h" @@ -74,6 +75,9 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) LOCK(cs_main); fCheckpointsEnabled = false; + // force UpdatedBlockTip to initialize pCurrentBlockIndex + mnpayments.UpdatedBlockTip(chainActive.Tip()); + // Simple block creation, nothing special yet: BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey));