Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 26 additions & 1 deletion src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -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);
Expand All @@ -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);
Expand Down
121 changes: 96 additions & 25 deletions src/masternode-payments.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand All @@ -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();
}
}

Expand All @@ -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;
}
}
Expand All @@ -494,25 +494,25 @@ 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();
}
}

// if we don't have at least MNPAYMENTS_SIGNATURES_REQUIRED signatures on a payee, approve whichever is the longest chain
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 == "") {
Expand All @@ -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());
}
}

Expand Down Expand Up @@ -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;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like the break here will make nTotalVotes innacurate

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep, but it will not be used if fFound is true anyway

}
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;
Expand Down
29 changes: 23 additions & 6 deletions src/masternode-payments.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,20 +40,36 @@ std::string GetRequiredPaymentsString(int nBlockHeight);

class CMasternodePayee
{
public:
private:
CScript scriptPubKey;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't vin (ie. COutPoint) be used here to insure uniqueness ?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, that would be better but we only have CScript payee in CMasternodePaymentWinner and switching from payee to vin would break backward compatibility. This is still quite unique though because this one corresponds to pubKeyCollateralAddress.

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));
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know you didn't change this but this looks weird. Why all the casting ? Shouldn't READWRITE(scriptPubKey) suffice ?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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
Expand Down Expand Up @@ -169,6 +185,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);
Expand Down
6 changes: 4 additions & 2 deletions src/masternode-sync.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
4 changes: 3 additions & 1 deletion src/protocol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion src/protocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down