From d0cac9921b99f8e363503df38b71fe54abf7b463 Mon Sep 17 00:00:00 2001 From: UdjinM6 Date: Fri, 16 Sep 2016 21:23:42 +0300 Subject: [PATCH 1/3] store vote hashes in CMasternodePayee and use them in CMasternodePayments::Sync --- src/masternode-payments.cpp | 50 ++++++++++++++++++++----------------- src/masternode-payments.h | 32 +++++++++++++++++++++--- 2 files changed, 55 insertions(+), 27 deletions(-) diff --git a/src/masternode-payments.cpp b/src/masternode-payments.cpp index b9b394fd40ba..1ee7f0dd1663 100644 --- a/src/masternode-payments.cpp +++ b/src/masternode-payments.cpp @@ -439,12 +439,12 @@ void CMasternodeBlockPayees::AddPayee(CMasternodePaymentWinner winner) LOCK(cs_vecPayees); BOOST_FOREACH(CMasternodePayee& payee, vecPayees) { - if (payee.scriptPubKey == winner.payee) { - payee.nVotes++; + if (payee.GetPayee() == winner.payee) { + payee.AddVoteHash(winner.GetHash()); return; } } - CMasternodePayee payeeNew(winner.payee, 1); + CMasternodePayee payeeNew(winner.payee, winner.GetHash()); vecPayees.push_back(payeeNew); } @@ -459,9 +459,9 @@ bool CMasternodeBlockPayees::GetPayee(CScript& payeeRet) int nVotes = -1; BOOST_FOREACH(CMasternodePayee& payee, vecPayees) { - if (payee.nVotes > nVotes) { - payeeRet = payee.scriptPubKey; - nVotes = payee.nVotes; + if (payee.GetVoteCount() > nVotes) { + payeeRet = payee.GetPayee(); + nVotes = payee.GetVoteCount(); } } @@ -473,7 +473,7 @@ bool CMasternodeBlockPayees::HasPayeeWithVotes(CScript payeeIn, int nVotesReq) LOCK(cs_vecPayees); BOOST_FOREACH(CMasternodePayee& payee, vecPayees) { - if (payee.nVotes >= nVotesReq && payee.scriptPubKey == payeeIn) { + if (payee.GetVoteCount() >= nVotesReq && payee.GetPayee() == payeeIn) { return true; } } @@ -494,8 +494,8 @@ bool CMasternodeBlockPayees::IsTransactionValid(const CTransaction& txNew) //require at least MNPAYMENTS_SIGNATURES_REQUIRED signatures BOOST_FOREACH(CMasternodePayee& payee, vecPayees) { - if (payee.nVotes >= nMaxSignatures) { - nMaxSignatures = payee.nVotes; + if (payee.GetVoteCount() >= nMaxSignatures) { + nMaxSignatures = payee.GetVoteCount(); } } @@ -503,16 +503,16 @@ bool CMasternodeBlockPayees::IsTransactionValid(const CTransaction& txNew) if(nMaxSignatures < MNPAYMENTS_SIGNATURES_REQUIRED) return true; BOOST_FOREACH(CMasternodePayee& payee, vecPayees) { - if (payee.nVotes >= MNPAYMENTS_SIGNATURES_REQUIRED) { + if (payee.GetVoteCount() >= MNPAYMENTS_SIGNATURES_REQUIRED) { BOOST_FOREACH(CTxOut txout, txNew.vout) { - if (payee.scriptPubKey == txout.scriptPubKey && nMasternodePayment == txout.nValue) { + if (payee.GetPayee() == txout.scriptPubKey && nMasternodePayment == txout.nValue) { LogPrint("mnpayments", "CMasternodeBlockPayees::IsTransactionValid -- Found required payment\n"); return true; } } CTxDestination address1; - ExtractDestination(payee.scriptPubKey, address1); + ExtractDestination(payee.GetPayee(), address1); CBitcoinAddress address2(address1); if(strPayeesPossible == "") { @@ -536,13 +536,13 @@ std::string CMasternodeBlockPayees::GetRequiredPaymentsString() BOOST_FOREACH(CMasternodePayee& payee, vecPayees) { CTxDestination address1; - ExtractDestination(payee.scriptPubKey, address1); + ExtractDestination(payee.GetPayee(), address1); CBitcoinAddress address2(address1); if (strRequiredPayments != "Unknown") { - strRequiredPayments += ", " + address2.ToString() + ":" + boost::lexical_cast(payee.nVotes); + strRequiredPayments += ", " + address2.ToString() + ":" + boost::lexical_cast(payee.GetVoteCount()); } else { - strRequiredPayments = address2.ToString() + ":" + boost::lexical_cast(payee.nVotes); + strRequiredPayments = address2.ToString() + ":" + boost::lexical_cast(payee.GetVoteCount()); } } @@ -743,9 +743,10 @@ std::string CMasternodePaymentWinner::ToString() const return info.str(); } +// Send all votes up to nCountNeeded blocks (but not more than GetStorageLimit) void CMasternodePayments::Sync(CNode* pnode, int nCountNeeded) { - LOCK(cs_mapMasternodePayeeVotes); + LOCK(cs_mapMasternodeBlocks); if(!pCurrentBlockIndex) return; @@ -753,14 +754,17 @@ void CMasternodePayments::Sync(CNode* pnode, int nCountNeeded) if(nCountNeeded > nLimit) nCountNeeded = nLimit; int nInvCount = 0; - std::map::iterator it = mapMasternodePayeeVotes.begin(); - while(it != mapMasternodePayeeVotes.end()) { - CMasternodePaymentWinner winner = (*it).second; - if(winner.nBlockHeight >= pCurrentBlockIndex->nHeight - nCountNeeded && winner.nBlockHeight <= pCurrentBlockIndex->nHeight + 20) { - pnode->PushInventory(CInv(MSG_MASTERNODE_WINNER, winner.GetHash())); - nInvCount++; + + for(int h = pCurrentBlockIndex->nHeight - nCountNeeded; h < pCurrentBlockIndex->nHeight + 20; h++) { + if(mapMasternodeBlocks.count(h)) { + BOOST_FOREACH(CMasternodePayee& payee, mapMasternodeBlocks[h].vecPayees) { + std::vector vecVoteHashes = payee.GetVoteHashes(); + BOOST_FOREACH(uint256& hash, vecVoteHashes) { + pnode->PushInventory(CInv(MSG_MASTERNODE_WINNER, hash)); + nInvCount++; + } + } } - ++it; } LogPrintf("CMasternodePayments::Sync -- Sent %d winners to peer %d\n", nInvCount, pnode->id); diff --git a/src/masternode-payments.h b/src/masternode-payments.h index 816c7e23d127..fbcde15a167a 100644 --- a/src/masternode-payments.h +++ b/src/masternode-payments.h @@ -40,12 +40,25 @@ std::string GetRequiredPaymentsString(int nBlockHeight); class CMasternodePayee { -public: +private: CScript scriptPubKey; int nVotes; + std::vector vecVoteHashes; + +public: + CMasternodePayee() : + scriptPubKey(), + nVotes(0), + vecVoteHashes() + {} - CMasternodePayee() : scriptPubKey(CScript()), nVotes(0) {} - CMasternodePayee(CScript payee, int nVotesIn) : scriptPubKey(payee), nVotes(nVotesIn) {} + CMasternodePayee(CScript payee, uint256 hashIn) : + scriptPubKey(payee), + nVotes(1), + vecVoteHashes(hashIn) + { + vecVoteHashes.push_back(hashIn); + } ADD_SERIALIZE_METHODS; @@ -53,7 +66,18 @@ class CMasternodePayee inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { READWRITE(*(CScriptBase*)(&scriptPubKey)); READWRITE(nVotes); - } + READWRITE(vecVoteHashes); + } + + CScript GetPayee() { return scriptPubKey; } + int GetVoteCount() { return nVotes; } + + void AddVoteHash(uint256 hashIn) + { + vecVoteHashes.push_back(hashIn); + nVotes++; + } + std::vector GetVoteHashes() { return vecVoteHashes; } }; // Keep track of votes for payees from masternodes From a0d36761866edf60bbfe070d4677a22bb8656511 Mon Sep 17 00:00:00 2001 From: UdjinM6 Date: Fri, 16 Sep 2016 21:46:47 +0300 Subject: [PATCH 2/3] Request low data payment blocks in batches directly from some node instead of/after preliminary Sync. --- src/main.cpp | 27 +++++++++++++- src/masternode-payments.cpp | 71 +++++++++++++++++++++++++++++++++++-- src/masternode-payments.h | 3 +- src/masternode-sync.cpp | 6 ++-- src/protocol.cpp | 4 ++- src/protocol.h | 2 +- 6 files changed, 105 insertions(+), 8 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index f0fa50081d99..e368c61fc41d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4939,6 +4939,12 @@ bool static AlreadyHave(const CInv& inv) EXCLUSIVE_LOCKS_REQUIRED(cs_main) case MSG_MASTERNODE_WINNER: return mnpayments.mapMasternodePayeeVotes.count(inv.hash); + case MSG_MASTERNODE_WINNER_BLOCK: + { + BlockMap::iterator mi = mapBlockIndex.find(inv.hash); + return mi != mapBlockIndex.end() && mnpayments.mapMasternodeBlocks.find(mi->second->nHeight) != mnpayments.mapMasternodeBlocks.end(); + } + case MSG_MASTERNODE_ANNOUNCE: return mnodeman.mapSeenMasternodeBroadcast.count(inv.hash); @@ -5105,7 +5111,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam pushed = true; } } - + if (!pushed && inv.type == MSG_MASTERNODE_WINNER) { if(mnpayments.mapMasternodePayeeVotes.count(inv.hash)) { CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); @@ -5116,6 +5122,25 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam } } + if (!pushed && inv.type == MSG_MASTERNODE_WINNER_BLOCK) { + BlockMap::iterator mi = mapBlockIndex.find(inv.hash); + LOCK(cs_mapMasternodeBlocks); + if (mi != mapBlockIndex.end() && mnpayments.mapMasternodeBlocks.count(mi->second->nHeight)) { + BOOST_FOREACH(CMasternodePayee& payee, mnpayments.mapMasternodeBlocks[mi->second->nHeight].vecPayees) { + std::vector vecVoteHashes = payee.GetVoteHashes(); + BOOST_FOREACH(uint256& hash, vecVoteHashes) { + if(mnpayments.mapMasternodePayeeVotes.count(hash)) { + CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); + ss.reserve(1000); + ss << mnpayments.mapMasternodePayeeVotes[hash]; + pfrom->PushMessage(NetMsgType::MNWINNER, ss); + } + } + } + pushed = true; + } + } + if (!pushed && inv.type == MSG_MASTERNODE_ANNOUNCE) { if(mnodeman.mapSeenMasternodeBroadcast.count(inv.hash)){ CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); diff --git a/src/masternode-payments.cpp b/src/masternode-payments.cpp index 1ee7f0dd1663..36802209fae9 100644 --- a/src/masternode-payments.cpp +++ b/src/masternode-payments.cpp @@ -750,8 +750,14 @@ void CMasternodePayments::Sync(CNode* pnode, int nCountNeeded) if(!pCurrentBlockIndex) return; - int nLimit = GetStorageLimit(); - if(nCountNeeded > nLimit) nCountNeeded = nLimit; + if(pnode->nVersion < 70201) { + // Old nodes can only sync via heavy method + int nLimit = GetStorageLimit(); + if(nCountNeeded > nLimit) nCountNeeded = nLimit; + } else { + // New nodes request missing payment blocks themselves, push only future winners to them + nCountNeeded = 0; + } int nInvCount = 0; @@ -771,6 +777,67 @@ void CMasternodePayments::Sync(CNode* pnode, int nCountNeeded) pnode->PushMessage(NetMsgType::SYNCSTATUSCOUNT, MASTERNODE_SYNC_MNW, nInvCount); } +// Request low data payment blocks in batches directly from some node instead of/after preliminary Sync. +void CMasternodePayments::RequestLowDataPaymentBlocks(CNode* pnode) +{ + // Old nodes can't process this + if(pnode->nVersion < 70201) return; + + LOCK(cs_mapMasternodeBlocks); + + std::vector vToFetch; + std::map::iterator it = mapMasternodeBlocks.begin(); + + while(it != mapMasternodeBlocks.end()) { + int nTotalVotes = 0; + bool fFound = false; + BOOST_FOREACH(CMasternodePayee& payee, it->second.vecPayees) { + if(payee.GetVoteCount() >= MNPAYMENTS_SIGNATURES_REQUIRED) { + fFound = true; + break; + } + nTotalVotes += payee.GetVoteCount(); + } + // A clear winner (MNPAYMENTS_SIGNATURES_REQUIRED+ votes) was found + // or no clear winner was found but there are at least avg number of votes + if(fFound || nTotalVotes >= (MNPAYMENTS_SIGNATURES_TOTAL + MNPAYMENTS_SIGNATURES_REQUIRED)/2) { + // so just move to the next block + ++it; + continue; + } + // DEBUG + DBG ( + // Let's see why this failed + BOOST_FOREACH(CMasternodePayee& payee, it->second.vecPayees) { + CTxDestination address1; + ExtractDestination(payee.scriptPubKey, address1); + CBitcoinAddress address2(address1); + printf("payee %s votes %d\n", address2.ToString().c_str(), payee.GetVoteCount()); + } + printf("block %d votes total %d\n", it->first, nTotalVotes); + ) + // END DEBUG + // Low data block found, let's try to sync it + uint256 hash; + if(GetBlockHash(hash, it->first)) { + vToFetch.push_back(CInv(MSG_MASTERNODE_WINNER_BLOCK, hash)); + } + // We should not violate GETDATA rules + if(vToFetch.size() == MAX_INV_SZ) { + LogPrintf("CMasternodePayments::SyncLowDataPaymentBlocks -- asking peer %d for %d blocks\n", pnode->id, MAX_INV_SZ); + pnode->PushMessage(NetMsgType::GETDATA, vToFetch); + // Start filling new batch + vToFetch.clear(); + } + ++it; + } + // Ask for the rest of it + if(!vToFetch.empty()) { + LogPrintf("CMasternodePayments::SyncLowDataPaymentBlocks -- asking peer %d for %d blocks\n", pnode->id, vToFetch.size()); + pnode->PushMessage(NetMsgType::GETDATA, vToFetch); + } +} + std::string CMasternodePayments::ToString() const { std::ostringstream info; diff --git a/src/masternode-payments.h b/src/masternode-payments.h index fbcde15a167a..9d1f7a9ee10d 100644 --- a/src/masternode-payments.h +++ b/src/masternode-payments.h @@ -55,7 +55,7 @@ class CMasternodePayee CMasternodePayee(CScript payee, uint256 hashIn) : scriptPubKey(payee), nVotes(1), - vecVoteHashes(hashIn) + vecVoteHashes() { vecVoteHashes.push_back(hashIn); } @@ -193,6 +193,7 @@ class CMasternodePayments bool ProcessBlock(int nBlockHeight); void Sync(CNode* node, int nCountNeeded); + void RequestLowDataPaymentBlocks(CNode* pnode); void CheckAndRemove(); bool GetBlockPayee(int nBlockHeight, CScript& payee); diff --git a/src/masternode-sync.cpp b/src/masternode-sync.cpp index a6cad7851fb3..2364ebf1229d 100644 --- a/src/masternode-sync.cpp +++ b/src/masternode-sync.cpp @@ -309,8 +309,10 @@ void CMasternodeSync::ProcessTick() if(pnode->nVersion < mnpayments.GetMinMasternodePaymentsProto()) continue; nRequestedMasternodeAttempt++; - pnode->PushMessage(NetMsgType::MNWINNERSSYNC, mnpayments.GetStorageLimit()); //sync payees - + // ask node for all winners it has (new nodes will only return future winners) + pnode->PushMessage(NetMsgType::MNWINNERSSYNC, mnpayments.GetStorageLimit()); + // ask node for missing pieces only (old nodes will not be asked) + mnpayments.RequestLowDataPaymentBlocks(pnode); return; //this will cause each peer to get one request each six seconds for the various assets we need } diff --git a/src/protocol.cpp b/src/protocol.cpp index 2f9579b2d039..5981dc2f5038 100644 --- a/src/protocol.cpp +++ b/src/protocol.cpp @@ -41,6 +41,7 @@ const char *TXLOCKVOTE="txlvote"; const char *SPORK="spork"; const char *GETSPORKS="getsporks"; const char *MNWINNER="mnw"; +const char *MNWINNERBLOCK="mnwb"; const char *MNWINNERSSYNC="mnget"; const char *MNSCANERROR="mn scan error"; // not implemented const char *MNBUDGETSYNC="mnvs"; // depreciated since 12.1 @@ -78,7 +79,7 @@ static const char* ppszTypeName[] = NetMsgType::TXLOCKVOTE, NetMsgType::SPORK, NetMsgType::MNWINNER, - NetMsgType::MNSCANERROR, // not implemented + NetMsgType::MNWINNERBLOCK, // reusing, was MNSCANERROR previousely, was NOT used in 12.0, we need this for inv NetMsgType::MNBUDGETVOTE, // depreciated since 12.1 NetMsgType::MNBUDGETPROPOSAL, // depreciated since 12.1 NetMsgType::MNBUDGETFINAL, // depreciated since 12.1 @@ -124,6 +125,7 @@ const static std::string allNetMessageTypes[] = { NetMsgType::SPORK, NetMsgType::GETSPORKS, NetMsgType::MNWINNER, + // NetMsgType::MNWINNERBLOCK, // there is no message for this, only inventory NetMsgType::MNWINNERSSYNC, NetMsgType::MNANNOUNCE, NetMsgType::MNPING, diff --git a/src/protocol.h b/src/protocol.h index 137ef6c073df..e2107aebcf00 100644 --- a/src/protocol.h +++ b/src/protocol.h @@ -346,7 +346,7 @@ enum { MSG_TXLOCK_VOTE, MSG_SPORK, MSG_MASTERNODE_WINNER, - MSG_MASTERNODE_SCANNING_ERROR, // not implemented + MSG_MASTERNODE_WINNER_BLOCK, // reusing, was MSG_MASTERNODE_SCANNING_ERROR previousely, was NOT used in 12.0 MSG_BUDGET_VOTE, // depreciated since 12.1 MSG_BUDGET_PROPOSAL, // depreciated since 12.1 MSG_BUDGET_FINALIZED, // depreciated since 12.1 From 8cfe32f158363e71e923f4a5b24ae7a5e3656152 Mon Sep 17 00:00:00 2001 From: UdjinM6 Date: Sun, 18 Sep 2016 22:09:24 +0300 Subject: [PATCH 3/3] remove nVotes --- src/masternode-payments.h | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/masternode-payments.h b/src/masternode-payments.h index 9d1f7a9ee10d..7f91f4ed2127 100644 --- a/src/masternode-payments.h +++ b/src/masternode-payments.h @@ -42,19 +42,16 @@ class CMasternodePayee { private: CScript scriptPubKey; - int nVotes; std::vector vecVoteHashes; public: CMasternodePayee() : scriptPubKey(), - nVotes(0), vecVoteHashes() {} CMasternodePayee(CScript payee, uint256 hashIn) : scriptPubKey(payee), - nVotes(1), vecVoteHashes() { vecVoteHashes.push_back(hashIn); @@ -65,19 +62,14 @@ class CMasternodePayee template inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { READWRITE(*(CScriptBase*)(&scriptPubKey)); - READWRITE(nVotes); READWRITE(vecVoteHashes); } CScript GetPayee() { return scriptPubKey; } - int GetVoteCount() { return nVotes; } - void AddVoteHash(uint256 hashIn) - { - vecVoteHashes.push_back(hashIn); - nVotes++; - } + void AddVoteHash(uint256 hashIn) { vecVoteHashes.push_back(hashIn); } std::vector GetVoteHashes() { return vecVoteHashes; } + int GetVoteCount() { return vecVoteHashes.size(); } }; // Keep track of votes for payees from masternodes