Implement a way to sync only needed winners (#1028)

* store vote hashes in CMasternodePayee and use them in CMasternodePayments::Sync

* Request low data payment blocks in batches directly from some node instead of/after preliminary Sync.

* remove nVotes
This commit is contained in:
UdjinM6 2016-09-19 02:23:52 +04:00 committed by GitHub
parent d93836c0ed
commit 1e2d61ad0d
6 changed files with 153 additions and 36 deletions

View File

@ -4939,6 +4939,12 @@ bool static AlreadyHave(const CInv& inv) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
case MSG_MASTERNODE_WINNER: case MSG_MASTERNODE_WINNER:
return mnpayments.mapMasternodePayeeVotes.count(inv.hash); 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: case MSG_MASTERNODE_ANNOUNCE:
return mnodeman.mapSeenMasternodeBroadcast.count(inv.hash); return mnodeman.mapSeenMasternodeBroadcast.count(inv.hash);
@ -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<uint256> 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 (!pushed && inv.type == MSG_MASTERNODE_ANNOUNCE) {
if(mnodeman.mapSeenMasternodeBroadcast.count(inv.hash)){ if(mnodeman.mapSeenMasternodeBroadcast.count(inv.hash)){
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);

View File

@ -439,12 +439,12 @@ void CMasternodeBlockPayees::AddPayee(CMasternodePaymentWinner winner)
LOCK(cs_vecPayees); LOCK(cs_vecPayees);
BOOST_FOREACH(CMasternodePayee& payee, vecPayees) { BOOST_FOREACH(CMasternodePayee& payee, vecPayees) {
if (payee.scriptPubKey == winner.payee) { if (payee.GetPayee() == winner.payee) {
payee.nVotes++; payee.AddVoteHash(winner.GetHash());
return; return;
} }
} }
CMasternodePayee payeeNew(winner.payee, 1); CMasternodePayee payeeNew(winner.payee, winner.GetHash());
vecPayees.push_back(payeeNew); vecPayees.push_back(payeeNew);
} }
@ -459,9 +459,9 @@ bool CMasternodeBlockPayees::GetPayee(CScript& payeeRet)
int nVotes = -1; int nVotes = -1;
BOOST_FOREACH(CMasternodePayee& payee, vecPayees) { BOOST_FOREACH(CMasternodePayee& payee, vecPayees) {
if (payee.nVotes > nVotes) { if (payee.GetVoteCount() > nVotes) {
payeeRet = payee.scriptPubKey; payeeRet = payee.GetPayee();
nVotes = payee.nVotes; nVotes = payee.GetVoteCount();
} }
} }
@ -473,7 +473,7 @@ bool CMasternodeBlockPayees::HasPayeeWithVotes(CScript payeeIn, int nVotesReq)
LOCK(cs_vecPayees); LOCK(cs_vecPayees);
BOOST_FOREACH(CMasternodePayee& payee, vecPayees) { BOOST_FOREACH(CMasternodePayee& payee, vecPayees) {
if (payee.nVotes >= nVotesReq && payee.scriptPubKey == payeeIn) { if (payee.GetVoteCount() >= nVotesReq && payee.GetPayee() == payeeIn) {
return true; return true;
} }
} }
@ -494,8 +494,8 @@ bool CMasternodeBlockPayees::IsTransactionValid(const CTransaction& txNew)
//require at least MNPAYMENTS_SIGNATURES_REQUIRED signatures //require at least MNPAYMENTS_SIGNATURES_REQUIRED signatures
BOOST_FOREACH(CMasternodePayee& payee, vecPayees) { BOOST_FOREACH(CMasternodePayee& payee, vecPayees) {
if (payee.nVotes >= nMaxSignatures) { if (payee.GetVoteCount() >= nMaxSignatures) {
nMaxSignatures = payee.nVotes; nMaxSignatures = payee.GetVoteCount();
} }
} }
@ -503,16 +503,16 @@ bool CMasternodeBlockPayees::IsTransactionValid(const CTransaction& txNew)
if(nMaxSignatures < MNPAYMENTS_SIGNATURES_REQUIRED) return true; if(nMaxSignatures < MNPAYMENTS_SIGNATURES_REQUIRED) return true;
BOOST_FOREACH(CMasternodePayee& payee, vecPayees) { BOOST_FOREACH(CMasternodePayee& payee, vecPayees) {
if (payee.nVotes >= MNPAYMENTS_SIGNATURES_REQUIRED) { if (payee.GetVoteCount() >= MNPAYMENTS_SIGNATURES_REQUIRED) {
BOOST_FOREACH(CTxOut txout, txNew.vout) { 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"); LogPrint("mnpayments", "CMasternodeBlockPayees::IsTransactionValid -- Found required payment\n");
return true; return true;
} }
} }
CTxDestination address1; CTxDestination address1;
ExtractDestination(payee.scriptPubKey, address1); ExtractDestination(payee.GetPayee(), address1);
CBitcoinAddress address2(address1); CBitcoinAddress address2(address1);
if(strPayeesPossible == "") { if(strPayeesPossible == "") {
@ -536,13 +536,13 @@ std::string CMasternodeBlockPayees::GetRequiredPaymentsString()
BOOST_FOREACH(CMasternodePayee& payee, vecPayees) BOOST_FOREACH(CMasternodePayee& payee, vecPayees)
{ {
CTxDestination address1; CTxDestination address1;
ExtractDestination(payee.scriptPubKey, address1); ExtractDestination(payee.GetPayee(), address1);
CBitcoinAddress address2(address1); CBitcoinAddress address2(address1);
if (strRequiredPayments != "Unknown") { if (strRequiredPayments != "Unknown") {
strRequiredPayments += ", " + address2.ToString() + ":" + boost::lexical_cast<std::string>(payee.nVotes); strRequiredPayments += ", " + address2.ToString() + ":" + boost::lexical_cast<std::string>(payee.GetVoteCount());
} else { } else {
strRequiredPayments = address2.ToString() + ":" + boost::lexical_cast<std::string>(payee.nVotes); strRequiredPayments = address2.ToString() + ":" + boost::lexical_cast<std::string>(payee.GetVoteCount());
} }
} }
@ -743,30 +743,101 @@ std::string CMasternodePaymentWinner::ToString() const
return info.str(); return info.str();
} }
// Send all votes up to nCountNeeded blocks (but not more than GetStorageLimit)
void CMasternodePayments::Sync(CNode* pnode, int nCountNeeded) void CMasternodePayments::Sync(CNode* pnode, int nCountNeeded)
{ {
LOCK(cs_mapMasternodePayeeVotes); LOCK(cs_mapMasternodeBlocks);
if(!pCurrentBlockIndex) return; if(!pCurrentBlockIndex) return;
if(pnode->nVersion < 70201) {
// Old nodes can only sync via heavy method
int nLimit = GetStorageLimit(); int nLimit = GetStorageLimit();
if(nCountNeeded > nLimit) nCountNeeded = nLimit; if(nCountNeeded > nLimit) nCountNeeded = nLimit;
} else {
// New nodes request missing payment blocks themselves, push only future winners to them
nCountNeeded = 0;
}
int nInvCount = 0; int nInvCount = 0;
std::map<uint256, CMasternodePaymentWinner>::iterator it = mapMasternodePayeeVotes.begin();
while(it != mapMasternodePayeeVotes.end()) { for(int h = pCurrentBlockIndex->nHeight - nCountNeeded; h < pCurrentBlockIndex->nHeight + 20; h++) {
CMasternodePaymentWinner winner = (*it).second; if(mapMasternodeBlocks.count(h)) {
if(winner.nBlockHeight >= pCurrentBlockIndex->nHeight - nCountNeeded && winner.nBlockHeight <= pCurrentBlockIndex->nHeight + 20) { BOOST_FOREACH(CMasternodePayee& payee, mapMasternodeBlocks[h].vecPayees) {
pnode->PushInventory(CInv(MSG_MASTERNODE_WINNER, winner.GetHash())); std::vector<uint256> vecVoteHashes = payee.GetVoteHashes();
BOOST_FOREACH(uint256& hash, vecVoteHashes) {
pnode->PushInventory(CInv(MSG_MASTERNODE_WINNER, hash));
nInvCount++; nInvCount++;
} }
++it; }
}
} }
LogPrintf("CMasternodePayments::Sync -- Sent %d winners to peer %d\n", nInvCount, pnode->id); LogPrintf("CMasternodePayments::Sync -- Sent %d winners to peer %d\n", nInvCount, pnode->id);
pnode->PushMessage(NetMsgType::SYNCSTATUSCOUNT, MASTERNODE_SYNC_MNW, nInvCount); 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<CInv> vToFetch;
std::map<int, CMasternodeBlockPayees>::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::string CMasternodePayments::ToString() const
{ {
std::ostringstream info; std::ostringstream info;

View File

@ -40,20 +40,36 @@ std::string GetRequiredPaymentsString(int nBlockHeight);
class CMasternodePayee class CMasternodePayee
{ {
public: private:
CScript scriptPubKey; CScript scriptPubKey;
int nVotes; std::vector<uint256> vecVoteHashes;
CMasternodePayee() : scriptPubKey(CScript()), nVotes(0) {} public:
CMasternodePayee(CScript payee, int nVotesIn) : scriptPubKey(payee), nVotes(nVotesIn) {} CMasternodePayee() :
scriptPubKey(),
vecVoteHashes()
{}
CMasternodePayee(CScript payee, uint256 hashIn) :
scriptPubKey(payee),
vecVoteHashes()
{
vecVoteHashes.push_back(hashIn);
}
ADD_SERIALIZE_METHODS; ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation> template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
READWRITE(*(CScriptBase*)(&scriptPubKey)); READWRITE(*(CScriptBase*)(&scriptPubKey));
READWRITE(nVotes); READWRITE(vecVoteHashes);
} }
CScript GetPayee() { return scriptPubKey; }
void AddVoteHash(uint256 hashIn) { vecVoteHashes.push_back(hashIn); }
std::vector<uint256> GetVoteHashes() { return vecVoteHashes; }
int GetVoteCount() { return vecVoteHashes.size(); }
}; };
// Keep track of votes for payees from masternodes // Keep track of votes for payees from masternodes
@ -169,6 +185,7 @@ public:
bool ProcessBlock(int nBlockHeight); bool ProcessBlock(int nBlockHeight);
void Sync(CNode* node, int nCountNeeded); void Sync(CNode* node, int nCountNeeded);
void RequestLowDataPaymentBlocks(CNode* pnode);
void CheckAndRemove(); void CheckAndRemove();
bool GetBlockPayee(int nBlockHeight, CScript& payee); bool GetBlockPayee(int nBlockHeight, CScript& payee);

View File

@ -309,8 +309,10 @@ void CMasternodeSync::ProcessTick()
if(pnode->nVersion < mnpayments.GetMinMasternodePaymentsProto()) continue; if(pnode->nVersion < mnpayments.GetMinMasternodePaymentsProto()) continue;
nRequestedMasternodeAttempt++; 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 return; //this will cause each peer to get one request each six seconds for the various assets we need
} }

View File

@ -41,6 +41,7 @@ const char *TXLOCKVOTE="txlvote";
const char *SPORK="spork"; const char *SPORK="spork";
const char *GETSPORKS="getsporks"; const char *GETSPORKS="getsporks";
const char *MNWINNER="mnw"; const char *MNWINNER="mnw";
const char *MNWINNERBLOCK="mnwb";
const char *MNWINNERSSYNC="mnget"; const char *MNWINNERSSYNC="mnget";
const char *MNSCANERROR="mn scan error"; // not implemented const char *MNSCANERROR="mn scan error"; // not implemented
const char *MNBUDGETSYNC="mnvs"; // depreciated since 12.1 const char *MNBUDGETSYNC="mnvs"; // depreciated since 12.1
@ -78,7 +79,7 @@ static const char* ppszTypeName[] =
NetMsgType::TXLOCKVOTE, NetMsgType::TXLOCKVOTE,
NetMsgType::SPORK, NetMsgType::SPORK,
NetMsgType::MNWINNER, 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::MNBUDGETVOTE, // depreciated since 12.1
NetMsgType::MNBUDGETPROPOSAL, // depreciated since 12.1 NetMsgType::MNBUDGETPROPOSAL, // depreciated since 12.1
NetMsgType::MNBUDGETFINAL, // depreciated since 12.1 NetMsgType::MNBUDGETFINAL, // depreciated since 12.1
@ -124,6 +125,7 @@ const static std::string allNetMessageTypes[] = {
NetMsgType::SPORK, NetMsgType::SPORK,
NetMsgType::GETSPORKS, NetMsgType::GETSPORKS,
NetMsgType::MNWINNER, NetMsgType::MNWINNER,
// NetMsgType::MNWINNERBLOCK, // there is no message for this, only inventory
NetMsgType::MNWINNERSSYNC, NetMsgType::MNWINNERSSYNC,
NetMsgType::MNANNOUNCE, NetMsgType::MNANNOUNCE,
NetMsgType::MNPING, NetMsgType::MNPING,

View File

@ -346,7 +346,7 @@ enum {
MSG_TXLOCK_VOTE, MSG_TXLOCK_VOTE,
MSG_SPORK, MSG_SPORK,
MSG_MASTERNODE_WINNER, 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_VOTE, // depreciated since 12.1
MSG_BUDGET_PROPOSAL, // depreciated since 12.1 MSG_BUDGET_PROPOSAL, // depreciated since 12.1
MSG_BUDGET_FINALIZED, // depreciated since 12.1 MSG_BUDGET_FINALIZED, // depreciated since 12.1