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
25
src/main.cpp
25
src/main.cpp
@ -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);
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user