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:
parent
d93836c0ed
commit
1e2d61ad0d
27
src/main.cpp
27
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<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(mnodeman.mapSeenMasternodeBroadcast.count(inv.hash)){
|
||||
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
|
||||
|
@ -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<std::string>(payee.nVotes);
|
||||
strRequiredPayments += ", " + address2.ToString() + ":" + boost::lexical_cast<std::string>(payee.GetVoteCount());
|
||||
} 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();
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
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;
|
||||
std::map<uint256, CMasternodePaymentWinner>::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<uint256> 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);
|
||||
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::ostringstream info;
|
||||
|
@ -40,20 +40,36 @@ std::string GetRequiredPaymentsString(int nBlockHeight);
|
||||
|
||||
class CMasternodePayee
|
||||
{
|
||||
public:
|
||||
private:
|
||||
CScript scriptPubKey;
|
||||
int nVotes;
|
||||
std::vector<uint256> vecVoteHashes;
|
||||
|
||||
CMasternodePayee() : scriptPubKey(CScript()), nVotes(0) {}
|
||||
CMasternodePayee(CScript payee, int nVotesIn) : scriptPubKey(payee), nVotes(nVotesIn) {}
|
||||
public:
|
||||
CMasternodePayee() :
|
||||
scriptPubKey(),
|
||||
vecVoteHashes()
|
||||
{}
|
||||
|
||||
CMasternodePayee(CScript payee, uint256 hashIn) :
|
||||
scriptPubKey(payee),
|
||||
vecVoteHashes()
|
||||
{
|
||||
vecVoteHashes.push_back(hashIn);
|
||||
}
|
||||
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
|
||||
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
|
||||
@ -169,6 +185,7 @@ public:
|
||||
bool ProcessBlock(int nBlockHeight);
|
||||
|
||||
void Sync(CNode* node, int nCountNeeded);
|
||||
void RequestLowDataPaymentBlocks(CNode* pnode);
|
||||
void CheckAndRemove();
|
||||
|
||||
bool GetBlockPayee(int nBlockHeight, CScript& payee);
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user