neobytes/src/masternodeman.cpp

1586 lines
62 KiB
C++
Raw Normal View History

2016-12-20 14:26:45 +01:00
// Copyright (c) 2014-2017 The Dash Core developers
2015-02-24 15:02:22 +01:00
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "activemasternode.h"
#include "addrman.h"
#include "governance.h"
#include "masternode-payments.h"
#include "masternode-sync.h"
#include "masternodeman.h"
#include "messagesigner.h"
2016-10-20 23:11:30 +02:00
#include "netfulfilledman.h"
#include "privatesend-client.h"
#include "util.h"
/** Masternode manager */
CMasternodeMan mnodeman;
const std::string CMasternodeMan::SERIALIZATION_VERSION_STRING = "CMasternodeMan-Version-7";
2016-10-20 23:11:30 +02:00
struct CompareLastPaidBlock
{
bool operator()(const std::pair<int, CMasternode*>& t1,
const std::pair<int, CMasternode*>& t2) const
{
return (t1.first != t2.first) ? (t1.first < t2.first) : (t1.second->vin < t2.second->vin);
}
};
struct CompareScoreMN
{
bool operator()(const std::pair<arith_uint256, CMasternode*>& t1,
const std::pair<arith_uint256, CMasternode*>& t2) const
{
return (t1.first != t2.first) ? (t1.first < t2.first) : (t1.second->vin < t2.second->vin);
}
};
2016-10-20 23:11:30 +02:00
struct CompareByAddr
2016-10-20 23:11:30 +02:00
{
bool operator()(const CMasternode* t1,
const CMasternode* t2) const
{
return t1->addr < t2->addr;
}
};
CMasternodeMan::CMasternodeMan()
: cs(),
mapMasternodes(),
mAskedUsForMasternodeList(),
mWeAskedForMasternodeList(),
mWeAskedForMasternodeListEntry(),
mWeAskedForVerification(),
mMnbRecoveryRequests(),
mMnbRecoveryGoodReplies(),
listScheduledMnbRequestConnections(),
fMasternodesAdded(false),
fMasternodesRemoved(false),
vecDirtyGovernanceObjectHashes(),
nLastWatchdogVoteTime(0),
mapSeenMasternodeBroadcast(),
mapSeenMasternodePing(),
nDsqCount(0)
{}
bool CMasternodeMan::Add(CMasternode &mn)
{
LOCK(cs);
if (Has(mn.vin.prevout)) return false;
2017-08-25 14:57:19 +02:00
LogPrint("masternode", "CMasternodeMan::Add -- Adding new Masternode: addr=%s, %i now\n", mn.addr.ToString(), size() + 1);
mapMasternodes[mn.vin.prevout] = mn;
2017-08-25 14:57:19 +02:00
fMasternodesAdded = true;
return true;
}
void CMasternodeMan::AskForMN(CNode* pnode, const COutPoint& outpoint)
2015-08-07 05:07:40 +02:00
{
if(!pnode) return;
LOCK(cs);
2015-08-07 05:07:40 +02:00
std::map<COutPoint, std::map<CNetAddr, int64_t> >::iterator it1 = mWeAskedForMasternodeListEntry.find(outpoint);
if (it1 != mWeAskedForMasternodeListEntry.end()) {
std::map<CNetAddr, int64_t>::iterator it2 = it1->second.find(pnode->addr);
if (it2 != it1->second.end()) {
if (GetTime() < it2->second) {
// we've asked recently, should not repeat too often or we could get banned
return;
}
// we asked this node for this outpoint but it's ok to ask again already
LogPrintf("CMasternodeMan::AskForMN -- Asking same peer %s for missing masternode entry again: %s\n", pnode->addr.ToString(), outpoint.ToStringShort());
} else {
// we already asked for this outpoint but not this node
LogPrintf("CMasternodeMan::AskForMN -- Asking new peer %s for missing masternode entry: %s\n", pnode->addr.ToString(), outpoint.ToStringShort());
}
} else {
// we never asked any node for this outpoint
LogPrintf("CMasternodeMan::AskForMN -- Asking peer %s for missing masternode entry for the first time: %s\n", pnode->addr.ToString(), outpoint.ToStringShort());
}
mWeAskedForMasternodeListEntry[outpoint][pnode->addr] = GetTime() + DSEG_UPDATE_SECONDS;
2015-08-07 05:07:40 +02:00
g_connman->PushMessage(pnode, NetMsgType::DSEG, CTxIn(outpoint));
}
bool CMasternodeMan::AllowMixing(const COutPoint &outpoint)
{
LOCK(cs);
CMasternode* pmn = Find(outpoint);
if (!pmn) {
return false;
}
nDsqCount++;
pmn->nLastDsq = nDsqCount;
pmn->fAllowMixingTx = true;
return true;
}
bool CMasternodeMan::DisallowMixing(const COutPoint &outpoint)
{
LOCK(cs);
CMasternode* pmn = Find(outpoint);
if (!pmn) {
return false;
}
pmn->fAllowMixingTx = false;
return true;
2015-08-07 05:07:40 +02:00
}
bool CMasternodeMan::PoSeBan(const COutPoint &outpoint)
{
LOCK(cs);
CMasternode* pmn = Find(outpoint);
if (!pmn) {
return false;
}
pmn->PoSeBan();
return true;
}
void CMasternodeMan::Check()
{
LOCK(cs);
LogPrint("masternode", "CMasternodeMan::Check -- nLastWatchdogVoteTime=%d, IsWatchdogActive()=%d\n", nLastWatchdogVoteTime, IsWatchdogActive());
V0.12.1.x sentinel watchdog pr (#1079) Squashed: * Replaced unsafe mnodeman.Find function with Get in governance-vote.cpp * Reject unparsable governance objects * Implemented sentinel watchdog objects (separated out from locking changes) * Added WATCHDOG support to rpcgovernance.cpp * Implemented WATCHDOG_EXPIRED state for masternodes * Added serialization of watchdog timestamps * Masternode fixes - Added version check to CMasternodeMan deserialization - Added several missing locking calls in CMasternodeMan * Fixed missing member initialization in CMasternode constructor and added more logging * Added MASTERNODE_WATCHDOG_MAX_SECONDS to governanceinfo * Added masternodewatchdogmaxseconds info to getgovernanceinfo help * Make masternodes remain in WATCHDOG_EXPIRED state unless removed or collateral expires * Allow watchdog object creation by WATCHDOG_EXPIRED MN * Fixed MN validation logic for governance object creation * Count total masternodes instead of enabled masternodes in masternode-sync * Transition out of WATCHDOG_EXPIRED state if the watchdog is inactive * Fixed IsWatchdogExpired bug * Fixed rate check for watchdog objects and no longer check MN state when validating governance objects * Applied PR #1061 patch * Ported locking changes from other branch * Require only 1 block between new watchdog objects * Accept pings for WATCHDOG_EXPIRED masternodes * Lock CmasternodeMan::cs in CmasternodeMan::ProcessMessage * Several governance changes - Fixed uninitialized value in CGovernancePayment class - Return an error on submission if any superblock payment cannot be parsed - Added logging more statements * Explicitly initialize all governance object members * Fix deadlock * Fixed non-threadsafe access to masternode in activemasternode.cpp * Revert added wallet lock * Changed CActiveMasternode so that watchdog expired nodes can still send pings * Modified CActiveMasternode to run pinger regardless of state when MN is in list * Added voter and time information to getvotes command * Improved CActiveMasternode state management * Implemented GetInfo functions for more efficient thread-safe access to masternode information * Added CActiveMasternode debug logging messages * Fixed initial type setting and error message for incorrect protocol version * Changes based on code review comments * Set active state for local mode
2016-10-17 20:54:28 +02:00
for (auto& mnpair : mapMasternodes) {
mnpair.second.Check();
2015-06-24 18:41:03 +02:00
}
}
void CMasternodeMan::CheckAndRemove()
{
if(!masternodeSync.IsMasternodeListSynced()) return;
LogPrintf("CMasternodeMan::CheckAndRemove\n");
{
// Need LOCK2 here to ensure consistent locking order because code below locks cs_main
// in CheckMnbAndUpdateMasternodeList()
LOCK2(cs_main, cs);
Check();
2015-07-30 15:44:18 +02:00
// Remove spent masternodes, prepare structures and make requests to reasure the state of inactive ones
rank_pair_vec_t vecMasternodeRanks;
// ask for up to MNB_RECOVERY_MAX_ASK_ENTRIES masternode entries at a time
int nAskForMnbRecovery = MNB_RECOVERY_MAX_ASK_ENTRIES;
std::map<COutPoint, CMasternode>::iterator it = mapMasternodes.begin();
while (it != mapMasternodes.end()) {
CMasternodeBroadcast mnb = CMasternodeBroadcast(it->second);
uint256 hash = mnb.GetHash();
// If collateral was spent ...
if (it->second.IsOutpointSpent()) {
LogPrint("masternode", "CMasternodeMan::CheckAndRemove -- Removing Masternode: %s addr=%s %i now\n", it->second.GetStateString(), it->second.addr.ToString(), size() - 1);
// erase all of the broadcasts we've seen from this txin, ...
mapSeenMasternodeBroadcast.erase(hash);
mWeAskedForMasternodeListEntry.erase(it->first);
// and finally remove it from the list
it->second.FlagGovernanceItemsAsDirty();
mapMasternodes.erase(it++);
fMasternodesRemoved = true;
} else {
bool fAsk = (nAskForMnbRecovery > 0) &&
masternodeSync.IsSynced() &&
it->second.IsNewStartRequired() &&
!IsMnbRecoveryRequested(hash);
if(fAsk) {
// this mn is in a non-recoverable state and we haven't asked other nodes yet
std::set<CNetAddr> setRequested;
// calulate only once and only when it's needed
if(vecMasternodeRanks.empty()) {
int nRandomBlockHeight = GetRandInt(nCachedBlockHeight);
GetMasternodeRanks(vecMasternodeRanks, nRandomBlockHeight);
}
bool fAskedForMnbRecovery = false;
// ask first MNB_RECOVERY_QUORUM_TOTAL masternodes we can connect to and we haven't asked recently
for(int i = 0; setRequested.size() < MNB_RECOVERY_QUORUM_TOTAL && i < (int)vecMasternodeRanks.size(); i++) {
// avoid banning
if(mWeAskedForMasternodeListEntry.count(it->first) && mWeAskedForMasternodeListEntry[it->first].count(vecMasternodeRanks[i].second.addr)) continue;
// didn't ask recently, ok to ask now
CService addr = vecMasternodeRanks[i].second.addr;
setRequested.insert(addr);
listScheduledMnbRequestConnections.push_back(std::make_pair(addr, hash));
fAskedForMnbRecovery = true;
}
if(fAskedForMnbRecovery) {
LogPrint("masternode", "CMasternodeMan::CheckAndRemove -- Recovery initiated, masternode=%s\n", it->first.ToStringShort());
nAskForMnbRecovery--;
}
// wait for mnb recovery replies for MNB_RECOVERY_WAIT_SECONDS seconds
mMnbRecoveryRequests[hash] = std::make_pair(GetTime() + MNB_RECOVERY_WAIT_SECONDS, setRequested);
}
++it;
}
}
// proces replies for MASTERNODE_NEW_START_REQUIRED masternodes
LogPrint("masternode", "CMasternodeMan::CheckAndRemove -- mMnbRecoveryGoodReplies size=%d\n", (int)mMnbRecoveryGoodReplies.size());
std::map<uint256, std::vector<CMasternodeBroadcast> >::iterator itMnbReplies = mMnbRecoveryGoodReplies.begin();
while(itMnbReplies != mMnbRecoveryGoodReplies.end()){
if(mMnbRecoveryRequests[itMnbReplies->first].first < GetTime()) {
// all nodes we asked should have replied now
if(itMnbReplies->second.size() >= MNB_RECOVERY_QUORUM_REQUIRED) {
// majority of nodes we asked agrees that this mn doesn't require new mnb, reprocess one of new mnbs
LogPrint("masternode", "CMasternodeMan::CheckAndRemove -- reprocessing mnb, masternode=%s\n", itMnbReplies->second[0].vin.prevout.ToStringShort());
// mapSeenMasternodeBroadcast.erase(itMnbReplies->first);
int nDos;
itMnbReplies->second[0].fRecovery = true;
CheckMnbAndUpdateMasternodeList(NULL, itMnbReplies->second[0], nDos);
}
LogPrint("masternode", "CMasternodeMan::CheckAndRemove -- removing mnb recovery reply, masternode=%s, size=%d\n", itMnbReplies->second[0].vin.prevout.ToStringShort(), (int)itMnbReplies->second.size());
mMnbRecoveryGoodReplies.erase(itMnbReplies++);
} else {
++itMnbReplies;
}
}
}
{
// no need for cm_main below
LOCK(cs);
std::map<uint256, std::pair< int64_t, std::set<CNetAddr> > >::iterator itMnbRequest = mMnbRecoveryRequests.begin();
while(itMnbRequest != mMnbRecoveryRequests.end()){
// Allow this mnb to be re-verified again after MNB_RECOVERY_RETRY_SECONDS seconds
// if mn is still in MASTERNODE_NEW_START_REQUIRED state.
if(GetTime() - itMnbRequest->second.first > MNB_RECOVERY_RETRY_SECONDS) {
mMnbRecoveryRequests.erase(itMnbRequest++);
} else {
++itMnbRequest;
}
}
// check who's asked for the Masternode list
std::map<CNetAddr, int64_t>::iterator it1 = mAskedUsForMasternodeList.begin();
while(it1 != mAskedUsForMasternodeList.end()){
if((*it1).second < GetTime()) {
mAskedUsForMasternodeList.erase(it1++);
} else {
++it1;
}
}
// check who we asked for the Masternode list
it1 = mWeAskedForMasternodeList.begin();
while(it1 != mWeAskedForMasternodeList.end()){
if((*it1).second < GetTime()){
mWeAskedForMasternodeList.erase(it1++);
} else {
++it1;
}
}
// check which Masternodes we've asked for
std::map<COutPoint, std::map<CNetAddr, int64_t> >::iterator it2 = mWeAskedForMasternodeListEntry.begin();
while(it2 != mWeAskedForMasternodeListEntry.end()){
std::map<CNetAddr, int64_t>::iterator it3 = it2->second.begin();
while(it3 != it2->second.end()){
if(it3->second < GetTime()){
it2->second.erase(it3++);
} else {
++it3;
}
}
if(it2->second.empty()) {
mWeAskedForMasternodeListEntry.erase(it2++);
} else {
++it2;
}
}
2015-08-29 05:25:55 +02:00
std::map<CNetAddr, CMasternodeVerification>::iterator it3 = mWeAskedForVerification.begin();
while(it3 != mWeAskedForVerification.end()){
if(it3->second.nBlockHeight < nCachedBlockHeight - MAX_POSE_BLOCKS) {
mWeAskedForVerification.erase(it3++);
} else {
++it3;
}
}
// NOTE: do not expire mapSeenMasternodeBroadcast entries here, clean them on mnb updates!
// remove expired mapSeenMasternodePing
std::map<uint256, CMasternodePing>::iterator it4 = mapSeenMasternodePing.begin();
while(it4 != mapSeenMasternodePing.end()){
if((*it4).second.IsExpired()) {
LogPrint("masternode", "CMasternodeMan::CheckAndRemove -- Removing expired Masternode ping: hash=%s\n", (*it4).second.GetHash().ToString());
mapSeenMasternodePing.erase(it4++);
} else {
++it4;
}
}
// remove expired mapSeenMasternodeVerification
std::map<uint256, CMasternodeVerification>::iterator itv2 = mapSeenMasternodeVerification.begin();
while(itv2 != mapSeenMasternodeVerification.end()){
if((*itv2).second.nBlockHeight < nCachedBlockHeight - MAX_POSE_BLOCKS){
LogPrint("masternode", "CMasternodeMan::CheckAndRemove -- Removing expired Masternode verification: hash=%s\n", (*itv2).first.ToString());
mapSeenMasternodeVerification.erase(itv2++);
} else {
++itv2;
}
}
LogPrintf("CMasternodeMan::CheckAndRemove -- %s\n", ToString());
2016-10-20 23:11:30 +02:00
}
if(fMasternodesRemoved) {
NotifyMasternodeUpdates();
}
}
2015-03-01 01:04:17 +01:00
void CMasternodeMan::Clear()
{
LOCK(cs);
mapMasternodes.clear();
2015-03-01 01:04:17 +01:00
mAskedUsForMasternodeList.clear();
mWeAskedForMasternodeList.clear();
mWeAskedForMasternodeListEntry.clear();
mapSeenMasternodeBroadcast.clear();
mapSeenMasternodePing.clear();
2015-03-06 18:25:48 +01:00
nDsqCount = 0;
V0.12.1.x sentinel watchdog pr (#1079) Squashed: * Replaced unsafe mnodeman.Find function with Get in governance-vote.cpp * Reject unparsable governance objects * Implemented sentinel watchdog objects (separated out from locking changes) * Added WATCHDOG support to rpcgovernance.cpp * Implemented WATCHDOG_EXPIRED state for masternodes * Added serialization of watchdog timestamps * Masternode fixes - Added version check to CMasternodeMan deserialization - Added several missing locking calls in CMasternodeMan * Fixed missing member initialization in CMasternode constructor and added more logging * Added MASTERNODE_WATCHDOG_MAX_SECONDS to governanceinfo * Added masternodewatchdogmaxseconds info to getgovernanceinfo help * Make masternodes remain in WATCHDOG_EXPIRED state unless removed or collateral expires * Allow watchdog object creation by WATCHDOG_EXPIRED MN * Fixed MN validation logic for governance object creation * Count total masternodes instead of enabled masternodes in masternode-sync * Transition out of WATCHDOG_EXPIRED state if the watchdog is inactive * Fixed IsWatchdogExpired bug * Fixed rate check for watchdog objects and no longer check MN state when validating governance objects * Applied PR #1061 patch * Ported locking changes from other branch * Require only 1 block between new watchdog objects * Accept pings for WATCHDOG_EXPIRED masternodes * Lock CmasternodeMan::cs in CmasternodeMan::ProcessMessage * Several governance changes - Fixed uninitialized value in CGovernancePayment class - Return an error on submission if any superblock payment cannot be parsed - Added logging more statements * Explicitly initialize all governance object members * Fix deadlock * Fixed non-threadsafe access to masternode in activemasternode.cpp * Revert added wallet lock * Changed CActiveMasternode so that watchdog expired nodes can still send pings * Modified CActiveMasternode to run pinger regardless of state when MN is in list * Added voter and time information to getvotes command * Improved CActiveMasternode state management * Implemented GetInfo functions for more efficient thread-safe access to masternode information * Added CActiveMasternode debug logging messages * Fixed initial type setting and error message for incorrect protocol version * Changes based on code review comments * Set active state for local mode
2016-10-17 20:54:28 +02:00
nLastWatchdogVoteTime = 0;
}
int CMasternodeMan::CountMasternodes(int nProtocolVersion)
V0.12.1.x sentinel watchdog pr (#1079) Squashed: * Replaced unsafe mnodeman.Find function with Get in governance-vote.cpp * Reject unparsable governance objects * Implemented sentinel watchdog objects (separated out from locking changes) * Added WATCHDOG support to rpcgovernance.cpp * Implemented WATCHDOG_EXPIRED state for masternodes * Added serialization of watchdog timestamps * Masternode fixes - Added version check to CMasternodeMan deserialization - Added several missing locking calls in CMasternodeMan * Fixed missing member initialization in CMasternode constructor and added more logging * Added MASTERNODE_WATCHDOG_MAX_SECONDS to governanceinfo * Added masternodewatchdogmaxseconds info to getgovernanceinfo help * Make masternodes remain in WATCHDOG_EXPIRED state unless removed or collateral expires * Allow watchdog object creation by WATCHDOG_EXPIRED MN * Fixed MN validation logic for governance object creation * Count total masternodes instead of enabled masternodes in masternode-sync * Transition out of WATCHDOG_EXPIRED state if the watchdog is inactive * Fixed IsWatchdogExpired bug * Fixed rate check for watchdog objects and no longer check MN state when validating governance objects * Applied PR #1061 patch * Ported locking changes from other branch * Require only 1 block between new watchdog objects * Accept pings for WATCHDOG_EXPIRED masternodes * Lock CmasternodeMan::cs in CmasternodeMan::ProcessMessage * Several governance changes - Fixed uninitialized value in CGovernancePayment class - Return an error on submission if any superblock payment cannot be parsed - Added logging more statements * Explicitly initialize all governance object members * Fix deadlock * Fixed non-threadsafe access to masternode in activemasternode.cpp * Revert added wallet lock * Changed CActiveMasternode so that watchdog expired nodes can still send pings * Modified CActiveMasternode to run pinger regardless of state when MN is in list * Added voter and time information to getvotes command * Improved CActiveMasternode state management * Implemented GetInfo functions for more efficient thread-safe access to masternode information * Added CActiveMasternode debug logging messages * Fixed initial type setting and error message for incorrect protocol version * Changes based on code review comments * Set active state for local mode
2016-10-17 20:54:28 +02:00
{
LOCK(cs);
int nCount = 0;
nProtocolVersion = nProtocolVersion == -1 ? mnpayments.GetMinMasternodePaymentsProto() : nProtocolVersion;
V0.12.1.x sentinel watchdog pr (#1079) Squashed: * Replaced unsafe mnodeman.Find function with Get in governance-vote.cpp * Reject unparsable governance objects * Implemented sentinel watchdog objects (separated out from locking changes) * Added WATCHDOG support to rpcgovernance.cpp * Implemented WATCHDOG_EXPIRED state for masternodes * Added serialization of watchdog timestamps * Masternode fixes - Added version check to CMasternodeMan deserialization - Added several missing locking calls in CMasternodeMan * Fixed missing member initialization in CMasternode constructor and added more logging * Added MASTERNODE_WATCHDOG_MAX_SECONDS to governanceinfo * Added masternodewatchdogmaxseconds info to getgovernanceinfo help * Make masternodes remain in WATCHDOG_EXPIRED state unless removed or collateral expires * Allow watchdog object creation by WATCHDOG_EXPIRED MN * Fixed MN validation logic for governance object creation * Count total masternodes instead of enabled masternodes in masternode-sync * Transition out of WATCHDOG_EXPIRED state if the watchdog is inactive * Fixed IsWatchdogExpired bug * Fixed rate check for watchdog objects and no longer check MN state when validating governance objects * Applied PR #1061 patch * Ported locking changes from other branch * Require only 1 block between new watchdog objects * Accept pings for WATCHDOG_EXPIRED masternodes * Lock CmasternodeMan::cs in CmasternodeMan::ProcessMessage * Several governance changes - Fixed uninitialized value in CGovernancePayment class - Return an error on submission if any superblock payment cannot be parsed - Added logging more statements * Explicitly initialize all governance object members * Fix deadlock * Fixed non-threadsafe access to masternode in activemasternode.cpp * Revert added wallet lock * Changed CActiveMasternode so that watchdog expired nodes can still send pings * Modified CActiveMasternode to run pinger regardless of state when MN is in list * Added voter and time information to getvotes command * Improved CActiveMasternode state management * Implemented GetInfo functions for more efficient thread-safe access to masternode information * Added CActiveMasternode debug logging messages * Fixed initial type setting and error message for incorrect protocol version * Changes based on code review comments * Set active state for local mode
2016-10-17 20:54:28 +02:00
for (auto& mnpair : mapMasternodes) {
if(mnpair.second.nProtocolVersion < nProtocolVersion) continue;
nCount++;
V0.12.1.x sentinel watchdog pr (#1079) Squashed: * Replaced unsafe mnodeman.Find function with Get in governance-vote.cpp * Reject unparsable governance objects * Implemented sentinel watchdog objects (separated out from locking changes) * Added WATCHDOG support to rpcgovernance.cpp * Implemented WATCHDOG_EXPIRED state for masternodes * Added serialization of watchdog timestamps * Masternode fixes - Added version check to CMasternodeMan deserialization - Added several missing locking calls in CMasternodeMan * Fixed missing member initialization in CMasternode constructor and added more logging * Added MASTERNODE_WATCHDOG_MAX_SECONDS to governanceinfo * Added masternodewatchdogmaxseconds info to getgovernanceinfo help * Make masternodes remain in WATCHDOG_EXPIRED state unless removed or collateral expires * Allow watchdog object creation by WATCHDOG_EXPIRED MN * Fixed MN validation logic for governance object creation * Count total masternodes instead of enabled masternodes in masternode-sync * Transition out of WATCHDOG_EXPIRED state if the watchdog is inactive * Fixed IsWatchdogExpired bug * Fixed rate check for watchdog objects and no longer check MN state when validating governance objects * Applied PR #1061 patch * Ported locking changes from other branch * Require only 1 block between new watchdog objects * Accept pings for WATCHDOG_EXPIRED masternodes * Lock CmasternodeMan::cs in CmasternodeMan::ProcessMessage * Several governance changes - Fixed uninitialized value in CGovernancePayment class - Return an error on submission if any superblock payment cannot be parsed - Added logging more statements * Explicitly initialize all governance object members * Fix deadlock * Fixed non-threadsafe access to masternode in activemasternode.cpp * Revert added wallet lock * Changed CActiveMasternode so that watchdog expired nodes can still send pings * Modified CActiveMasternode to run pinger regardless of state when MN is in list * Added voter and time information to getvotes command * Improved CActiveMasternode state management * Implemented GetInfo functions for more efficient thread-safe access to masternode information * Added CActiveMasternode debug logging messages * Fixed initial type setting and error message for incorrect protocol version * Changes based on code review comments * Set active state for local mode
2016-10-17 20:54:28 +02:00
}
return nCount;
2015-03-01 01:04:17 +01:00
}
int CMasternodeMan::CountEnabled(int nProtocolVersion)
{
V0.12.1.x sentinel watchdog pr (#1079) Squashed: * Replaced unsafe mnodeman.Find function with Get in governance-vote.cpp * Reject unparsable governance objects * Implemented sentinel watchdog objects (separated out from locking changes) * Added WATCHDOG support to rpcgovernance.cpp * Implemented WATCHDOG_EXPIRED state for masternodes * Added serialization of watchdog timestamps * Masternode fixes - Added version check to CMasternodeMan deserialization - Added several missing locking calls in CMasternodeMan * Fixed missing member initialization in CMasternode constructor and added more logging * Added MASTERNODE_WATCHDOG_MAX_SECONDS to governanceinfo * Added masternodewatchdogmaxseconds info to getgovernanceinfo help * Make masternodes remain in WATCHDOG_EXPIRED state unless removed or collateral expires * Allow watchdog object creation by WATCHDOG_EXPIRED MN * Fixed MN validation logic for governance object creation * Count total masternodes instead of enabled masternodes in masternode-sync * Transition out of WATCHDOG_EXPIRED state if the watchdog is inactive * Fixed IsWatchdogExpired bug * Fixed rate check for watchdog objects and no longer check MN state when validating governance objects * Applied PR #1061 patch * Ported locking changes from other branch * Require only 1 block between new watchdog objects * Accept pings for WATCHDOG_EXPIRED masternodes * Lock CmasternodeMan::cs in CmasternodeMan::ProcessMessage * Several governance changes - Fixed uninitialized value in CGovernancePayment class - Return an error on submission if any superblock payment cannot be parsed - Added logging more statements * Explicitly initialize all governance object members * Fix deadlock * Fixed non-threadsafe access to masternode in activemasternode.cpp * Revert added wallet lock * Changed CActiveMasternode so that watchdog expired nodes can still send pings * Modified CActiveMasternode to run pinger regardless of state when MN is in list * Added voter and time information to getvotes command * Improved CActiveMasternode state management * Implemented GetInfo functions for more efficient thread-safe access to masternode information * Added CActiveMasternode debug logging messages * Fixed initial type setting and error message for incorrect protocol version * Changes based on code review comments * Set active state for local mode
2016-10-17 20:54:28 +02:00
LOCK(cs);
int nCount = 0;
nProtocolVersion = nProtocolVersion == -1 ? mnpayments.GetMinMasternodePaymentsProto() : nProtocolVersion;
for (auto& mnpair : mapMasternodes) {
if(mnpair.second.nProtocolVersion < nProtocolVersion || !mnpair.second.IsEnabled()) continue;
nCount++;
}
return nCount;
}
/* Only IPv4 masternodes are allowed in 12.1, saving this for later
int CMasternodeMan::CountByIP(int nNetworkType)
{
V0.12.1.x sentinel watchdog pr (#1079) Squashed: * Replaced unsafe mnodeman.Find function with Get in governance-vote.cpp * Reject unparsable governance objects * Implemented sentinel watchdog objects (separated out from locking changes) * Added WATCHDOG support to rpcgovernance.cpp * Implemented WATCHDOG_EXPIRED state for masternodes * Added serialization of watchdog timestamps * Masternode fixes - Added version check to CMasternodeMan deserialization - Added several missing locking calls in CMasternodeMan * Fixed missing member initialization in CMasternode constructor and added more logging * Added MASTERNODE_WATCHDOG_MAX_SECONDS to governanceinfo * Added masternodewatchdogmaxseconds info to getgovernanceinfo help * Make masternodes remain in WATCHDOG_EXPIRED state unless removed or collateral expires * Allow watchdog object creation by WATCHDOG_EXPIRED MN * Fixed MN validation logic for governance object creation * Count total masternodes instead of enabled masternodes in masternode-sync * Transition out of WATCHDOG_EXPIRED state if the watchdog is inactive * Fixed IsWatchdogExpired bug * Fixed rate check for watchdog objects and no longer check MN state when validating governance objects * Applied PR #1061 patch * Ported locking changes from other branch * Require only 1 block between new watchdog objects * Accept pings for WATCHDOG_EXPIRED masternodes * Lock CmasternodeMan::cs in CmasternodeMan::ProcessMessage * Several governance changes - Fixed uninitialized value in CGovernancePayment class - Return an error on submission if any superblock payment cannot be parsed - Added logging more statements * Explicitly initialize all governance object members * Fix deadlock * Fixed non-threadsafe access to masternode in activemasternode.cpp * Revert added wallet lock * Changed CActiveMasternode so that watchdog expired nodes can still send pings * Modified CActiveMasternode to run pinger regardless of state when MN is in list * Added voter and time information to getvotes command * Improved CActiveMasternode state management * Implemented GetInfo functions for more efficient thread-safe access to masternode information * Added CActiveMasternode debug logging messages * Fixed initial type setting and error message for incorrect protocol version * Changes based on code review comments * Set active state for local mode
2016-10-17 20:54:28 +02:00
LOCK(cs);
int nNodeCount = 0;
for (auto& mnpair : mapMasternodes)
if ((nNetworkType == NET_IPV4 && mnpair.second.addr.IsIPv4()) ||
(nNetworkType == NET_TOR && mnpair.second.addr.IsTor()) ||
(nNetworkType == NET_IPV6 && mnpair.second.addr.IsIPv6())) {
nNodeCount++;
}
return nNodeCount;
}
*/
void CMasternodeMan::DsegUpdate(CNode* pnode)
{
LOCK(cs);
if(Params().NetworkIDString() == CBaseChainParams::MAIN) {
if(!(pnode->addr.IsRFC1918() || pnode->addr.IsLocal())) {
std::map<CNetAddr, int64_t>::iterator it = mWeAskedForMasternodeList.find(pnode->addr);
if(it != mWeAskedForMasternodeList.end() && GetTime() < (*it).second) {
LogPrintf("CMasternodeMan::DsegUpdate -- we already asked %s for the list; skipping...\n", pnode->addr.ToString());
return;
2015-07-02 17:07:30 +02:00
}
}
}
Backport Bitcoin PR#8708: net: have CConnman handle message sending (#1553) * serialization: teach serializers variadics Also add a variadic CDataStream ctor for ease-of-use. * connman is in charge of pushing messages The changes here are dense and subtle, but hopefully all is more explicit than before. - CConnman is now in charge of sending data rather than the nodes themselves. This is necessary because many decisions need to be made with all nodes in mind, and a model that requires the nodes calling up to their manager quickly turns to spaghetti. - The per-node-serializer (ssSend) has been replaced with a (quasi-)const send-version. Since the send version for serialization can only change once per connection, we now explicitly tag messages with INIT_PROTO_VERSION if they are sent before the handshake. With this done, there's no need to lock for access to nSendVersion. Also, a new stream is used for each message, so there's no need to lock during the serialization process. - This takes care of accounting for optimistic sends, so the nOptimisticBytesWritten hack can be removed. - -dropmessagestest and -fuzzmessagestest have not been preserved, as I suspect they haven't been used in years. * net: switch all callers to connman for pushing messages Drop all of the old stuff. * drop the optimistic write counter hack This is now handled properly in realtime. * net: remove now-unused ssSend and Fuzz * net: construct CNodeStates in place * net: handle version push in InitializeNode
2017-07-27 16:28:05 +02:00
g_connman->PushMessage(pnode, NetMsgType::DSEG, CTxIn());
2016-10-20 23:11:30 +02:00
int64_t askAgain = GetTime() + DSEG_UPDATE_SECONDS;
mWeAskedForMasternodeList[pnode->addr] = askAgain;
LogPrint("masternode", "CMasternodeMan::DsegUpdate -- asked %s for the list\n", pnode->addr.ToString());
}
CMasternode* CMasternodeMan::Find(const COutPoint &outpoint)
{
LOCK(cs);
auto it = mapMasternodes.find(outpoint);
return it == mapMasternodes.end() ? NULL : &(it->second);
}
bool CMasternodeMan::Get(const COutPoint& outpoint, CMasternode& masternodeRet)
{
// Theses mutexes are recursive so double locking by the same thread is safe.
LOCK(cs);
auto it = mapMasternodes.find(outpoint);
if (it == mapMasternodes.end()) {
return false;
}
masternodeRet = it->second;
return true;
}
bool CMasternodeMan::GetMasternodeInfo(const COutPoint& outpoint, masternode_info_t& mnInfoRet)
{
LOCK(cs);
auto it = mapMasternodes.find(outpoint);
if (it == mapMasternodes.end()) {
return false;
}
mnInfoRet = it->second.GetInfo();
return true;
}
bool CMasternodeMan::GetMasternodeInfo(const CPubKey& pubKeyMasternode, masternode_info_t& mnInfoRet)
V0.12.1.x sentinel watchdog pr (#1079) Squashed: * Replaced unsafe mnodeman.Find function with Get in governance-vote.cpp * Reject unparsable governance objects * Implemented sentinel watchdog objects (separated out from locking changes) * Added WATCHDOG support to rpcgovernance.cpp * Implemented WATCHDOG_EXPIRED state for masternodes * Added serialization of watchdog timestamps * Masternode fixes - Added version check to CMasternodeMan deserialization - Added several missing locking calls in CMasternodeMan * Fixed missing member initialization in CMasternode constructor and added more logging * Added MASTERNODE_WATCHDOG_MAX_SECONDS to governanceinfo * Added masternodewatchdogmaxseconds info to getgovernanceinfo help * Make masternodes remain in WATCHDOG_EXPIRED state unless removed or collateral expires * Allow watchdog object creation by WATCHDOG_EXPIRED MN * Fixed MN validation logic for governance object creation * Count total masternodes instead of enabled masternodes in masternode-sync * Transition out of WATCHDOG_EXPIRED state if the watchdog is inactive * Fixed IsWatchdogExpired bug * Fixed rate check for watchdog objects and no longer check MN state when validating governance objects * Applied PR #1061 patch * Ported locking changes from other branch * Require only 1 block between new watchdog objects * Accept pings for WATCHDOG_EXPIRED masternodes * Lock CmasternodeMan::cs in CmasternodeMan::ProcessMessage * Several governance changes - Fixed uninitialized value in CGovernancePayment class - Return an error on submission if any superblock payment cannot be parsed - Added logging more statements * Explicitly initialize all governance object members * Fix deadlock * Fixed non-threadsafe access to masternode in activemasternode.cpp * Revert added wallet lock * Changed CActiveMasternode so that watchdog expired nodes can still send pings * Modified CActiveMasternode to run pinger regardless of state when MN is in list * Added voter and time information to getvotes command * Improved CActiveMasternode state management * Implemented GetInfo functions for more efficient thread-safe access to masternode information * Added CActiveMasternode debug logging messages * Fixed initial type setting and error message for incorrect protocol version * Changes based on code review comments * Set active state for local mode
2016-10-17 20:54:28 +02:00
{
LOCK(cs);
for (auto& mnpair : mapMasternodes) {
if (mnpair.second.pubKeyMasternode == pubKeyMasternode) {
mnInfoRet = mnpair.second.GetInfo();
return true;
}
V0.12.1.x sentinel watchdog pr (#1079) Squashed: * Replaced unsafe mnodeman.Find function with Get in governance-vote.cpp * Reject unparsable governance objects * Implemented sentinel watchdog objects (separated out from locking changes) * Added WATCHDOG support to rpcgovernance.cpp * Implemented WATCHDOG_EXPIRED state for masternodes * Added serialization of watchdog timestamps * Masternode fixes - Added version check to CMasternodeMan deserialization - Added several missing locking calls in CMasternodeMan * Fixed missing member initialization in CMasternode constructor and added more logging * Added MASTERNODE_WATCHDOG_MAX_SECONDS to governanceinfo * Added masternodewatchdogmaxseconds info to getgovernanceinfo help * Make masternodes remain in WATCHDOG_EXPIRED state unless removed or collateral expires * Allow watchdog object creation by WATCHDOG_EXPIRED MN * Fixed MN validation logic for governance object creation * Count total masternodes instead of enabled masternodes in masternode-sync * Transition out of WATCHDOG_EXPIRED state if the watchdog is inactive * Fixed IsWatchdogExpired bug * Fixed rate check for watchdog objects and no longer check MN state when validating governance objects * Applied PR #1061 patch * Ported locking changes from other branch * Require only 1 block between new watchdog objects * Accept pings for WATCHDOG_EXPIRED masternodes * Lock CmasternodeMan::cs in CmasternodeMan::ProcessMessage * Several governance changes - Fixed uninitialized value in CGovernancePayment class - Return an error on submission if any superblock payment cannot be parsed - Added logging more statements * Explicitly initialize all governance object members * Fix deadlock * Fixed non-threadsafe access to masternode in activemasternode.cpp * Revert added wallet lock * Changed CActiveMasternode so that watchdog expired nodes can still send pings * Modified CActiveMasternode to run pinger regardless of state when MN is in list * Added voter and time information to getvotes command * Improved CActiveMasternode state management * Implemented GetInfo functions for more efficient thread-safe access to masternode information * Added CActiveMasternode debug logging messages * Fixed initial type setting and error message for incorrect protocol version * Changes based on code review comments * Set active state for local mode
2016-10-17 20:54:28 +02:00
}
return false;
V0.12.1.x sentinel watchdog pr (#1079) Squashed: * Replaced unsafe mnodeman.Find function with Get in governance-vote.cpp * Reject unparsable governance objects * Implemented sentinel watchdog objects (separated out from locking changes) * Added WATCHDOG support to rpcgovernance.cpp * Implemented WATCHDOG_EXPIRED state for masternodes * Added serialization of watchdog timestamps * Masternode fixes - Added version check to CMasternodeMan deserialization - Added several missing locking calls in CMasternodeMan * Fixed missing member initialization in CMasternode constructor and added more logging * Added MASTERNODE_WATCHDOG_MAX_SECONDS to governanceinfo * Added masternodewatchdogmaxseconds info to getgovernanceinfo help * Make masternodes remain in WATCHDOG_EXPIRED state unless removed or collateral expires * Allow watchdog object creation by WATCHDOG_EXPIRED MN * Fixed MN validation logic for governance object creation * Count total masternodes instead of enabled masternodes in masternode-sync * Transition out of WATCHDOG_EXPIRED state if the watchdog is inactive * Fixed IsWatchdogExpired bug * Fixed rate check for watchdog objects and no longer check MN state when validating governance objects * Applied PR #1061 patch * Ported locking changes from other branch * Require only 1 block between new watchdog objects * Accept pings for WATCHDOG_EXPIRED masternodes * Lock CmasternodeMan::cs in CmasternodeMan::ProcessMessage * Several governance changes - Fixed uninitialized value in CGovernancePayment class - Return an error on submission if any superblock payment cannot be parsed - Added logging more statements * Explicitly initialize all governance object members * Fix deadlock * Fixed non-threadsafe access to masternode in activemasternode.cpp * Revert added wallet lock * Changed CActiveMasternode so that watchdog expired nodes can still send pings * Modified CActiveMasternode to run pinger regardless of state when MN is in list * Added voter and time information to getvotes command * Improved CActiveMasternode state management * Implemented GetInfo functions for more efficient thread-safe access to masternode information * Added CActiveMasternode debug logging messages * Fixed initial type setting and error message for incorrect protocol version * Changes based on code review comments * Set active state for local mode
2016-10-17 20:54:28 +02:00
}
bool CMasternodeMan::Has(const COutPoint& outpoint)
V0.12.1.x sentinel watchdog pr (#1079) Squashed: * Replaced unsafe mnodeman.Find function with Get in governance-vote.cpp * Reject unparsable governance objects * Implemented sentinel watchdog objects (separated out from locking changes) * Added WATCHDOG support to rpcgovernance.cpp * Implemented WATCHDOG_EXPIRED state for masternodes * Added serialization of watchdog timestamps * Masternode fixes - Added version check to CMasternodeMan deserialization - Added several missing locking calls in CMasternodeMan * Fixed missing member initialization in CMasternode constructor and added more logging * Added MASTERNODE_WATCHDOG_MAX_SECONDS to governanceinfo * Added masternodewatchdogmaxseconds info to getgovernanceinfo help * Make masternodes remain in WATCHDOG_EXPIRED state unless removed or collateral expires * Allow watchdog object creation by WATCHDOG_EXPIRED MN * Fixed MN validation logic for governance object creation * Count total masternodes instead of enabled masternodes in masternode-sync * Transition out of WATCHDOG_EXPIRED state if the watchdog is inactive * Fixed IsWatchdogExpired bug * Fixed rate check for watchdog objects and no longer check MN state when validating governance objects * Applied PR #1061 patch * Ported locking changes from other branch * Require only 1 block between new watchdog objects * Accept pings for WATCHDOG_EXPIRED masternodes * Lock CmasternodeMan::cs in CmasternodeMan::ProcessMessage * Several governance changes - Fixed uninitialized value in CGovernancePayment class - Return an error on submission if any superblock payment cannot be parsed - Added logging more statements * Explicitly initialize all governance object members * Fix deadlock * Fixed non-threadsafe access to masternode in activemasternode.cpp * Revert added wallet lock * Changed CActiveMasternode so that watchdog expired nodes can still send pings * Modified CActiveMasternode to run pinger regardless of state when MN is in list * Added voter and time information to getvotes command * Improved CActiveMasternode state management * Implemented GetInfo functions for more efficient thread-safe access to masternode information * Added CActiveMasternode debug logging messages * Fixed initial type setting and error message for incorrect protocol version * Changes based on code review comments * Set active state for local mode
2016-10-17 20:54:28 +02:00
{
LOCK(cs);
return mapMasternodes.find(outpoint) != mapMasternodes.end();
V0.12.1.x sentinel watchdog pr (#1079) Squashed: * Replaced unsafe mnodeman.Find function with Get in governance-vote.cpp * Reject unparsable governance objects * Implemented sentinel watchdog objects (separated out from locking changes) * Added WATCHDOG support to rpcgovernance.cpp * Implemented WATCHDOG_EXPIRED state for masternodes * Added serialization of watchdog timestamps * Masternode fixes - Added version check to CMasternodeMan deserialization - Added several missing locking calls in CMasternodeMan * Fixed missing member initialization in CMasternode constructor and added more logging * Added MASTERNODE_WATCHDOG_MAX_SECONDS to governanceinfo * Added masternodewatchdogmaxseconds info to getgovernanceinfo help * Make masternodes remain in WATCHDOG_EXPIRED state unless removed or collateral expires * Allow watchdog object creation by WATCHDOG_EXPIRED MN * Fixed MN validation logic for governance object creation * Count total masternodes instead of enabled masternodes in masternode-sync * Transition out of WATCHDOG_EXPIRED state if the watchdog is inactive * Fixed IsWatchdogExpired bug * Fixed rate check for watchdog objects and no longer check MN state when validating governance objects * Applied PR #1061 patch * Ported locking changes from other branch * Require only 1 block between new watchdog objects * Accept pings for WATCHDOG_EXPIRED masternodes * Lock CmasternodeMan::cs in CmasternodeMan::ProcessMessage * Several governance changes - Fixed uninitialized value in CGovernancePayment class - Return an error on submission if any superblock payment cannot be parsed - Added logging more statements * Explicitly initialize all governance object members * Fix deadlock * Fixed non-threadsafe access to masternode in activemasternode.cpp * Revert added wallet lock * Changed CActiveMasternode so that watchdog expired nodes can still send pings * Modified CActiveMasternode to run pinger regardless of state when MN is in list * Added voter and time information to getvotes command * Improved CActiveMasternode state management * Implemented GetInfo functions for more efficient thread-safe access to masternode information * Added CActiveMasternode debug logging messages * Fixed initial type setting and error message for incorrect protocol version * Changes based on code review comments * Set active state for local mode
2016-10-17 20:54:28 +02:00
}
//
// Deterministically select the oldest/best masternode to pay on the network
//
bool CMasternodeMan::GetNextMasternodeInQueueForPayment(bool fFilterSigTime, int& nCountRet, masternode_info_t& mnInfoRet)
{
return GetNextMasternodeInQueueForPayment(nCachedBlockHeight, fFilterSigTime, nCountRet, mnInfoRet);
}
bool CMasternodeMan::GetNextMasternodeInQueueForPayment(int nBlockHeight, bool fFilterSigTime, int& nCountRet, masternode_info_t& mnInfoRet)
{
mnInfoRet = masternode_info_t();
nCountRet = 0;
if (!masternodeSync.IsWinnersListSynced()) {
// without winner list we can't reliably find the next winner anyway
return false;
}
// Need LOCK2 here to ensure consistent locking order because the GetBlockHash call below locks cs_main
LOCK2(cs_main,cs);
std::vector<std::pair<int, CMasternode*> > vecMasternodeLastPaid;
/*
Make a vector with all of the last paid times
*/
int nMnCount = CountMasternodes();
for (auto& mnpair : mapMasternodes) {
if(!mnpair.second.IsValidForPayment()) continue;
2017-07-03 15:14:07 +02:00
//check protocol version
if(mnpair.second.nProtocolVersion < mnpayments.GetMinMasternodePaymentsProto()) continue;
//it's in the list (up to 8 entries ahead of current block to allow propagation) -- so let's skip it
if(mnpayments.IsScheduled(mnpair.second, nBlockHeight)) continue;
//it's too new, wait for a cycle
if(fFilterSigTime && mnpair.second.sigTime + (nMnCount*2.6*60) > GetAdjustedTime()) continue;
//make sure it has at least as many confirmations as there are masternodes
if(GetUTXOConfirmations(mnpair.first) < nMnCount) continue;
vecMasternodeLastPaid.push_back(std::make_pair(mnpair.second.GetLastPaidBlock(), &mnpair.second));
}
nCountRet = (int)vecMasternodeLastPaid.size();
//when the network is in the process of upgrading, don't penalize nodes that recently restarted
if(fFilterSigTime && nCountRet < nMnCount/3)
return GetNextMasternodeInQueueForPayment(nBlockHeight, false, nCountRet, mnInfoRet);
// Sort them low to high
sort(vecMasternodeLastPaid.begin(), vecMasternodeLastPaid.end(), CompareLastPaidBlock());
uint256 blockHash;
if(!GetBlockHash(blockHash, nBlockHeight - 101)) {
LogPrintf("CMasternode::GetNextMasternodeInQueueForPayment -- ERROR: GetBlockHash() failed at nBlockHeight %d\n", nBlockHeight - 101);
return false;
}
// Look at 1/10 of the oldest nodes (by last payment), calculate their scores and pay the best one
// -- This doesn't look at who is being paid in the +8-10 blocks, allowing for double payments very rarely
// -- 1/100 payments should be a double payment on mainnet - (1/(3000/10))*2
// -- (chance per block * chances before IsScheduled will fire)
int nTenthNetwork = nMnCount/10;
int nCountTenth = 0;
arith_uint256 nHighest = 0;
CMasternode *pBestMasternode = NULL;
BOOST_FOREACH (PAIRTYPE(int, CMasternode*)& s, vecMasternodeLastPaid){
arith_uint256 nScore = s.second->CalculateScore(blockHash);
if(nScore > nHighest){
nHighest = nScore;
pBestMasternode = s.second;
}
nCountTenth++;
if(nCountTenth >= nTenthNetwork) break;
}
if (pBestMasternode) {
mnInfoRet = pBestMasternode->GetInfo();
}
return mnInfoRet.fInfoValid;
}
masternode_info_t CMasternodeMan::FindRandomNotInVec(const std::vector<COutPoint> &vecToExclude, int nProtocolVersion)
{
LOCK(cs);
nProtocolVersion = nProtocolVersion == -1 ? mnpayments.GetMinMasternodePaymentsProto() : nProtocolVersion;
int nCountEnabled = CountEnabled(nProtocolVersion);
int nCountNotExcluded = nCountEnabled - vecToExclude.size();
LogPrintf("CMasternodeMan::FindRandomNotInVec -- %d enabled masternodes, %d masternodes to choose from\n", nCountEnabled, nCountNotExcluded);
if(nCountNotExcluded < 1) return masternode_info_t();
// fill a vector of pointers
std::vector<CMasternode*> vpMasternodesShuffled;
for (auto& mnpair : mapMasternodes) {
vpMasternodesShuffled.push_back(&mnpair.second);
}
InsecureRand insecureRand;
// shuffle pointers
std::random_shuffle(vpMasternodesShuffled.begin(), vpMasternodesShuffled.end(), insecureRand);
bool fExclude;
// loop through
BOOST_FOREACH(CMasternode* pmn, vpMasternodesShuffled) {
if(pmn->nProtocolVersion < nProtocolVersion || !pmn->IsEnabled()) continue;
fExclude = false;
BOOST_FOREACH(const COutPoint &outpointToExclude, vecToExclude) {
if(pmn->vin.prevout == outpointToExclude) {
fExclude = true;
break;
}
}
if(fExclude) continue;
// found the one not in vecToExclude
LogPrint("masternode", "CMasternodeMan::FindRandomNotInVec -- found, masternode=%s\n", pmn->vin.prevout.ToStringShort());
return pmn->GetInfo();
}
LogPrint("masternode", "CMasternodeMan::FindRandomNotInVec -- failed\n");
return masternode_info_t();
}
bool CMasternodeMan::GetMasternodeScores(const uint256& nBlockHash, CMasternodeMan::score_pair_vec_t& vecMasternodeScoresRet, int nMinProtocol)
{
vecMasternodeScoresRet.clear();
if (!masternodeSync.IsMasternodeListSynced())
return false;
2015-03-23 13:59:22 +01:00
AssertLockHeld(cs);
if (mapMasternodes.empty())
return false;
// calculate scores
for (auto& mnpair : mapMasternodes) {
if (mnpair.second.nProtocolVersion >= nMinProtocol) {
vecMasternodeScoresRet.push_back(std::make_pair(mnpair.second.CalculateScore(nBlockHash), &mnpair.second));
}
}
sort(vecMasternodeScoresRet.rbegin(), vecMasternodeScoresRet.rend(), CompareScoreMN());
return !vecMasternodeScoresRet.empty();
}
bool CMasternodeMan::GetMasternodeRank(const COutPoint& outpoint, int& nRankRet, int nBlockHeight, int nMinProtocol)
{
nRankRet = -1;
if (!masternodeSync.IsMasternodeListSynced())
return false;
// make sure we know about this block
uint256 nBlockHash = uint256();
if (!GetBlockHash(nBlockHash, nBlockHeight)) {
LogPrintf("CMasternodeMan::%s -- ERROR: GetBlockHash() failed at nBlockHeight %d\n", __func__, nBlockHeight);
return false;
}
LOCK(cs);
score_pair_vec_t vecMasternodeScores;
if (!GetMasternodeScores(nBlockHash, vecMasternodeScores, nMinProtocol))
return false;
int nRank = 0;
for (auto& scorePair : vecMasternodeScores) {
nRank++;
if(scorePair.second->vin.prevout == outpoint) {
nRankRet = nRank;
return true;
}
}
return false;
}
bool CMasternodeMan::GetMasternodeRanks(CMasternodeMan::rank_pair_vec_t& vecMasternodeRanksRet, int nBlockHeight, int nMinProtocol)
{
vecMasternodeRanksRet.clear();
if (!masternodeSync.IsMasternodeListSynced())
return false;
// make sure we know about this block
uint256 nBlockHash = uint256();
if (!GetBlockHash(nBlockHash, nBlockHeight)) {
LogPrintf("CMasternodeMan::%s -- ERROR: GetBlockHash() failed at nBlockHeight %d\n", __func__, nBlockHeight);
return false;
}
LOCK(cs);
score_pair_vec_t vecMasternodeScores;
if (!GetMasternodeScores(nBlockHash, vecMasternodeScores, nMinProtocol))
return false;
int nRank = 0;
for (auto& scorePair : vecMasternodeScores) {
nRank++;
vecMasternodeRanksRet.push_back(std::make_pair(nRank, *scorePair.second));
}
return true;
}
bool CMasternodeMan::GetMasternodeByRank(int nRankIn, masternode_info_t& mnInfoRet, int nBlockHeight, int nMinProtocol)
2015-03-02 00:09:33 +01:00
{
mnInfoRet = masternode_info_t();
2015-03-02 00:09:33 +01:00
if (!masternodeSync.IsMasternodeListSynced())
return false;
// make sure we know about this block
uint256 nBlockHash = uint256();
if (!GetBlockHash(nBlockHash, nBlockHeight)) {
LogPrintf("CMasternodeMan::%s -- ERROR: GetBlockHash() failed at nBlockHeight %d\n", __func__, nBlockHeight);
return false;
}
LOCK(cs);
2015-03-02 00:09:33 +01:00
score_pair_vec_t vecMasternodeScores;
if (!GetMasternodeScores(nBlockHash, vecMasternodeScores, nMinProtocol))
return false;
2015-03-02 00:09:33 +01:00
if (vecMasternodeScores.size() < nRankIn)
return false;
2015-03-02 00:09:33 +01:00
int nRank = 0;
for (auto& scorePair : vecMasternodeScores) {
nRank++;
if(nRank == nRankIn) {
mnInfoRet = *scorePair.second;
return true;
2015-03-02 00:09:33 +01:00
}
}
return false;
2015-03-02 00:09:33 +01:00
}
void CMasternodeMan::ProcessMasternodeConnections()
{
//we don't care about this for regtest
if(Params().NetworkIDString() == CBaseChainParams::REGTEST) return;
Backport Bitcoin PR#9609: net: fix remaining net assertions (#1575) + Dashify * Dont deserialize nVersion into CNode, should fix #9212 * net: deserialize the entire version message locally This avoids having some vars set if the version negotiation fails. Also copy it all into CNode at the same site. nVersion and fSuccessfullyConnected are set last, as they are the gates for the other vars. Make them atomic for that reason. * net: don't run callbacks on nodes that haven't completed the version handshake Since ForEach* are can be used to send messages to all nodes, the caller may end up sending a message before the version handshake is complete. To limit this, filter out these nodes. While we're at it, may as well filter out disconnected nodes as well. Delete unused methods rather than updating them. * net: Disallow sending messages until the version handshake is complete This is a change in behavior, though it's much more sane now than before. * net: log an error rather than asserting if send version is misused Also cleaned up the comments and moved from the header to the .cpp so that logging headers aren't needed from net.h * Implement conditions for ForEachNode() and ForNode() methods of CConnman. A change making ForEachNode() and ForNode() methods ignore nodes that have not completed initial handshake have been backported from Bitcoin. Unfortunately, some Dash-specific code needs to iterate over all nodes. This change introduces additional condition argument to these methods. This argument is a functional object that should return true for nodes that should be taken into account, not ignored. Two functional objects are provided in CConnman namespace: * FullyConnectedOnly returns true for nodes that have handshake completed, * AllNodes returns true for all nodes. Overloads for ForEachNode() and ForNode() methods without condition argument are left for compatibility with non-Dash-specific code. They use FullyConnectedOnly functional object for condition. Signed-off-by: Oleg Girko <ol@infoserver.lv> * Iterate over all nodes in Dash-specific code using AllNodes condition. Use AllNodes functional object as newly introduced condition argument for ForEachNode() and ForNode() methods of CConnman to iterate over all nodes where needed in Dash-specific code. Signed-off-by: Oleg Girko <ol@infoserver.lv>
2017-08-17 20:37:22 +02:00
g_connman->ForEachNode(CConnman::AllNodes, [](CNode* pnode) {
if(pnode->fMasternode) {
if(privateSendClient.infoMixingMasternode.fInfoValid && pnode->addr == privateSendClient.infoMixingMasternode.addr)
return;
LogPrintf("Closing Masternode connection: peer=%d, addr=%s\n", pnode->id, pnode->addr.ToString());
pnode->fDisconnect = true;
2015-03-02 00:09:33 +01:00
}
Backport Bitcoin PR#8085: p2p: Begin encapsulation (#1537) * net: move CBanDB and CAddrDB out of net.h/cpp This will eventually solve a circular dependency * net: Create CConnman to encapsulate p2p connections * net: Move socket binding into CConnman * net: move OpenNetworkConnection into CConnman * net: move ban and addrman functions into CConnman * net: Add oneshot functions to CConnman * net: move added node functions to CConnman * net: Add most functions needed for vNodes to CConnman * net: handle nodesignals in CConnman * net: Pass CConnection to wallet rather than using the global * net: Add rpc error for missing/disabled p2p functionality * net: Pass CConnman around as needed * gui: add NodeID to the peer table * net: create generic functor accessors and move vNodes to CConnman * net: move whitelist functions into CConnman * net: move nLastNodeId to CConnman * net: move nLocalHostNonce to CConnman This behavior seems to have been quite racy and broken. Move nLocalHostNonce into CNode, and check received nonces against all non-fully-connected nodes. If there's a match, assume we've connected to ourself. * net: move messageHandlerCondition to CConnman * net: move send/recv statistics to CConnman * net: move SendBufferSize/ReceiveFloodSize to CConnman * net: move nLocalServices/nRelevantServices to CConnman These are in-turn passed to CNode at connection time. This allows us to offer different services to different peers (or test the effects of doing so). * net: move semOutbound and semMasternodeOutbound to CConnman * net: SocketSendData returns written size * net: move max/max-outbound to CConnman * net: Pass best block known height into CConnman CConnman then passes the current best height into CNode at creation time. This way CConnman/CNode have no dependency on main for height, and the signals only move in one direction. This also helps to prevent identity leakage a tiny bit. Before this change, an attacker could theoretically make 2 connections on different interfaces. They would connect fully on one, and only establish the initial connection on the other. Once they receive a new block, they would relay it to your first connection, and immediately commence the version handshake on the second. Since the new block height is reflected immediately, they could attempt to learn whether the two connections were correlated. This is, of course, incredibly unlikely to work due to the small timings involved and receipt from other senders. But it doesn't hurt to lock-in nBestHeight at the time of connection, rather than letting the remote choose the time. * net: pass CClientUIInterface into CConnman * net: Drop StartNode/StopNode and use CConnman directly * net: Introduce CConnection::Options to avoid passing so many params * net: add nSendBufferMaxSize/nReceiveFloodSize to CConnection::Options * net: move vNodesDisconnected into CConnman * Made the ForEachNode* functions in src/net.cpp more pragmatic and self documenting * Convert ForEachNode* functions to take a templated function argument rather than a std::function to eliminate std::function overhead * net: move MAX_FEELER_CONNECTIONS into connman
2017-07-21 11:35:19 +02:00
});
2015-03-02 00:09:33 +01:00
}
std::pair<CService, std::set<uint256> > CMasternodeMan::PopScheduledMnbRequestConnection()
{
LOCK(cs);
if(listScheduledMnbRequestConnections.empty()) {
return std::make_pair(CService(), std::set<uint256>());
}
std::set<uint256> setResult;
listScheduledMnbRequestConnections.sort();
std::pair<CService, uint256> pairFront = listScheduledMnbRequestConnections.front();
// squash hashes from requests with the same CService as the first one into setResult
std::list< std::pair<CService, uint256> >::iterator it = listScheduledMnbRequestConnections.begin();
while(it != listScheduledMnbRequestConnections.end()) {
if(pairFront.first == it->first) {
setResult.insert(it->second);
it = listScheduledMnbRequestConnections.erase(it);
} else {
// since list is sorted now, we can be sure that there is no more hashes left
// to ask for from this addr
break;
}
}
return std::make_pair(pairFront.first, setResult);
}
void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CDataStream& vRecv)
{
if(fLiteMode) return; // disable all Dash specific functionality
if(!masternodeSync.IsBlockchainSynced()) return;
if (strCommand == NetMsgType::MNANNOUNCE) { //Masternode Broadcast
CMasternodeBroadcast mnb;
vRecv >> mnb;
pfrom->setAskFor.erase(mnb.GetHash());
LogPrint("masternode", "MNANNOUNCE -- Masternode announce, masternode=%s\n", mnb.vin.prevout.ToStringShort());
int nDos = 0;
if (CheckMnbAndUpdateMasternodeList(pfrom, mnb, nDos)) {
// use announced Masternode as a peer
Backport Bitcoin PR#8085: p2p: Begin encapsulation (#1537) * net: move CBanDB and CAddrDB out of net.h/cpp This will eventually solve a circular dependency * net: Create CConnman to encapsulate p2p connections * net: Move socket binding into CConnman * net: move OpenNetworkConnection into CConnman * net: move ban and addrman functions into CConnman * net: Add oneshot functions to CConnman * net: move added node functions to CConnman * net: Add most functions needed for vNodes to CConnman * net: handle nodesignals in CConnman * net: Pass CConnection to wallet rather than using the global * net: Add rpc error for missing/disabled p2p functionality * net: Pass CConnman around as needed * gui: add NodeID to the peer table * net: create generic functor accessors and move vNodes to CConnman * net: move whitelist functions into CConnman * net: move nLastNodeId to CConnman * net: move nLocalHostNonce to CConnman This behavior seems to have been quite racy and broken. Move nLocalHostNonce into CNode, and check received nonces against all non-fully-connected nodes. If there's a match, assume we've connected to ourself. * net: move messageHandlerCondition to CConnman * net: move send/recv statistics to CConnman * net: move SendBufferSize/ReceiveFloodSize to CConnman * net: move nLocalServices/nRelevantServices to CConnman These are in-turn passed to CNode at connection time. This allows us to offer different services to different peers (or test the effects of doing so). * net: move semOutbound and semMasternodeOutbound to CConnman * net: SocketSendData returns written size * net: move max/max-outbound to CConnman * net: Pass best block known height into CConnman CConnman then passes the current best height into CNode at creation time. This way CConnman/CNode have no dependency on main for height, and the signals only move in one direction. This also helps to prevent identity leakage a tiny bit. Before this change, an attacker could theoretically make 2 connections on different interfaces. They would connect fully on one, and only establish the initial connection on the other. Once they receive a new block, they would relay it to your first connection, and immediately commence the version handshake on the second. Since the new block height is reflected immediately, they could attempt to learn whether the two connections were correlated. This is, of course, incredibly unlikely to work due to the small timings involved and receipt from other senders. But it doesn't hurt to lock-in nBestHeight at the time of connection, rather than letting the remote choose the time. * net: pass CClientUIInterface into CConnman * net: Drop StartNode/StopNode and use CConnman directly * net: Introduce CConnection::Options to avoid passing so many params * net: add nSendBufferMaxSize/nReceiveFloodSize to CConnection::Options * net: move vNodesDisconnected into CConnman * Made the ForEachNode* functions in src/net.cpp more pragmatic and self documenting * Convert ForEachNode* functions to take a templated function argument rather than a std::function to eliminate std::function overhead * net: move MAX_FEELER_CONNECTIONS into connman
2017-07-21 11:35:19 +02:00
g_connman->AddNewAddress(CAddress(mnb.addr, NODE_NETWORK), pfrom->addr, 2*60*60);
} else if(nDos > 0) {
Misbehaving(pfrom->GetId(), nDos);
}
if(fMasternodesAdded) {
NotifyMasternodeUpdates();
}
} else if (strCommand == NetMsgType::MNPING) { //Masternode Ping
CMasternodePing mnp;
vRecv >> mnp;
uint256 nHash = mnp.GetHash();
pfrom->setAskFor.erase(nHash);
LogPrint("masternode", "MNPING -- Masternode ping, masternode=%s\n", mnp.vin.prevout.ToStringShort());
// Need LOCK2 here to ensure consistent locking order because the CheckAndUpdate call below locks cs_main
LOCK2(cs_main, cs);
2016-10-30 20:40:30 +01:00
if(mapSeenMasternodePing.count(nHash)) return; //seen
mapSeenMasternodePing.insert(std::make_pair(nHash, mnp));
LogPrint("masternode", "MNPING -- Masternode ping, masternode=%s new\n", mnp.vin.prevout.ToStringShort());
// see if we have this Masternode
CMasternode* pmn = Find(mnp.vin.prevout);
// if masternode uses sentinel ping instead of watchdog
// we shoud update nTimeLastWatchdogVote here if sentinel
// ping flag is actual
if(pmn && mnp.fSentinelIsCurrent)
pmn->UpdateWatchdogVoteTime(mnp.sigTime);
// too late, new MNANNOUNCE is required
if(pmn && pmn->IsNewStartRequired()) return;
int nDos = 0;
2016-12-26 07:44:48 +01:00
if(mnp.CheckAndUpdate(pmn, false, nDos)) return;
if(nDos > 0) {
2015-08-07 05:07:40 +02:00
// if anything significant failed, mark that node
Misbehaving(pfrom->GetId(), nDos);
} else if(pmn != NULL) {
// nothing significant failed, mn is a known one too
return;
}
2015-08-07 05:07:40 +02:00
// something significant is broken or mn is unknown,
// we might have to ask for a masternode entry once
AskForMN(pfrom, mnp.vin.prevout);
} else if (strCommand == NetMsgType::DSEG) { //Get Masternode list or specific entry
// Ignore such requests until we are fully synced.
// We could start processing this after masternode list is synced
// but this is a heavy one so it's better to finish sync first.
if (!masternodeSync.IsSynced()) return;
CTxIn vin;
vRecv >> vin;
LogPrint("masternode", "DSEG -- Masternode list, masternode=%s\n", vin.prevout.ToStringShort());
2016-10-30 20:40:30 +01:00
LOCK(cs);
if(vin == CTxIn()) { //only should ask for this once
//local network
2015-07-02 17:07:30 +02:00
bool isLocal = (pfrom->addr.IsRFC1918() || pfrom->addr.IsLocal());
if(!isLocal && Params().NetworkIDString() == CBaseChainParams::MAIN) {
2017-07-03 15:14:07 +02:00
std::map<CNetAddr, int64_t>::iterator it = mAskedUsForMasternodeList.find(pfrom->addr);
if (it != mAskedUsForMasternodeList.end() && it->second > GetTime()) {
Misbehaving(pfrom->GetId(), 34);
LogPrintf("DSEG -- peer already asked me for the list, peer=%d\n", pfrom->id);
return;
}
2016-10-20 23:11:30 +02:00
int64_t askAgain = GetTime() + DSEG_UPDATE_SECONDS;
mAskedUsForMasternodeList[pfrom->addr] = askAgain;
}
} //else, asking for a specific node which is ok
int nInvCount = 0;
for (auto& mnpair : mapMasternodes) {
if (vin != CTxIn() && vin != mnpair.second.vin) continue; // asked for specific vin but we are not there yet
if (mnpair.second.addr.IsRFC1918() || mnpair.second.addr.IsLocal()) continue; // do not send local network masternode
if (mnpair.second.IsUpdateRequired()) continue; // do not send outdated masternodes
LogPrint("masternode", "DSEG -- Sending Masternode entry: masternode=%s addr=%s\n", mnpair.first.ToStringShort(), mnpair.second.addr.ToString());
CMasternodeBroadcast mnb = CMasternodeBroadcast(mnpair.second);
uint256 hash = mnb.GetHash();
pfrom->PushInventory(CInv(MSG_MASTERNODE_ANNOUNCE, hash));
pfrom->PushInventory(CInv(MSG_MASTERNODE_PING, mnpair.second.lastPing.GetHash()));
nInvCount++;
if (!mapSeenMasternodeBroadcast.count(hash)) {
mapSeenMasternodeBroadcast.insert(std::make_pair(hash, std::make_pair(GetTime(), mnb)));
}
if (vin.prevout == mnpair.first) {
LogPrintf("DSEG -- Sent 1 Masternode inv to peer %d\n", pfrom->id);
return;
}
}
2015-07-29 06:16:11 +02:00
if(vin == CTxIn()) {
Backport Bitcoin PR#8708: net: have CConnman handle message sending (#1553) * serialization: teach serializers variadics Also add a variadic CDataStream ctor for ease-of-use. * connman is in charge of pushing messages The changes here are dense and subtle, but hopefully all is more explicit than before. - CConnman is now in charge of sending data rather than the nodes themselves. This is necessary because many decisions need to be made with all nodes in mind, and a model that requires the nodes calling up to their manager quickly turns to spaghetti. - The per-node-serializer (ssSend) has been replaced with a (quasi-)const send-version. Since the send version for serialization can only change once per connection, we now explicitly tag messages with INIT_PROTO_VERSION if they are sent before the handshake. With this done, there's no need to lock for access to nSendVersion. Also, a new stream is used for each message, so there's no need to lock during the serialization process. - This takes care of accounting for optimistic sends, so the nOptimisticBytesWritten hack can be removed. - -dropmessagestest and -fuzzmessagestest have not been preserved, as I suspect they haven't been used in years. * net: switch all callers to connman for pushing messages Drop all of the old stuff. * drop the optimistic write counter hack This is now handled properly in realtime. * net: remove now-unused ssSend and Fuzz * net: construct CNodeStates in place * net: handle version push in InitializeNode
2017-07-27 16:28:05 +02:00
g_connman->PushMessage(pfrom, NetMsgType::SYNCSTATUSCOUNT, MASTERNODE_SYNC_LIST, nInvCount);
LogPrintf("DSEG -- Sent %d Masternode invs to peer %d\n", nInvCount, pfrom->id);
return;
}
// smth weird happen - someone asked us for vin we have no idea about?
LogPrint("masternode", "DSEG -- No invs sent to peer %d\n", pfrom->id);
2016-10-20 23:11:30 +02:00
} else if (strCommand == NetMsgType::MNVERIFY) { // Masternode Verify
// Need LOCK2 here to ensure consistent locking order because the all functions below call GetBlockHash which locks cs_main
LOCK2(cs_main, cs);
2016-10-20 23:11:30 +02:00
CMasternodeVerification mnv;
vRecv >> mnv;
if(mnv.vchSig1.empty()) {
// CASE 1: someone asked me to verify myself /IP we are using/
SendVerifyReply(pfrom, mnv);
} else if (mnv.vchSig2.empty()) {
// CASE 2: we _probably_ got verification we requested from some masternode
ProcessVerifyReply(pfrom, mnv);
} else {
// CASE 3: we _probably_ got verification broadcast signed by some masternode which verified another one
ProcessVerifyBroadcast(pfrom, mnv);
}
}
}
// Verification of masternodes via unique direct requests.
2016-10-20 23:11:30 +02:00
void CMasternodeMan::DoFullVerificationStep()
{
if(activeMasternode.outpoint == COutPoint()) return;
if(!masternodeSync.IsSynced()) return;
2016-10-20 23:11:30 +02:00
rank_pair_vec_t vecMasternodeRanks;
GetMasternodeRanks(vecMasternodeRanks, nCachedBlockHeight - 1, MIN_POSE_PROTO_VERSION);
2016-10-20 23:11:30 +02:00
// Need LOCK2 here to ensure consistent locking order because the SendVerifyRequest call below locks cs_main
// through GetHeight() signal in ConnectNode
LOCK2(cs_main, cs);
2016-10-20 23:11:30 +02:00
int nCount = 0;
int nMyRank = -1;
int nRanksTotal = (int)vecMasternodeRanks.size();
// send verify requests only if we are in top MAX_POSE_RANK
std::vector<std::pair<int, CMasternode> >::iterator it = vecMasternodeRanks.begin();
while(it != vecMasternodeRanks.end()) {
if(it->first > MAX_POSE_RANK) {
LogPrint("masternode", "CMasternodeMan::DoFullVerificationStep -- Must be in top %d to send verify request\n",
(int)MAX_POSE_RANK);
return;
}
if(it->second.vin.prevout == activeMasternode.outpoint) {
2016-10-20 23:11:30 +02:00
nMyRank = it->first;
LogPrint("masternode", "CMasternodeMan::DoFullVerificationStep -- Found self at rank %d/%d, verifying up to %d masternodes\n",
nMyRank, nRanksTotal, (int)MAX_POSE_CONNECTIONS);
2016-10-20 23:11:30 +02:00
break;
}
++it;
}
// edge case: list is too short and this masternode is not enabled
if(nMyRank == -1) return;
// send verify requests to up to MAX_POSE_CONNECTIONS masternodes
// starting from MAX_POSE_RANK + nMyRank and using MAX_POSE_CONNECTIONS as a step
int nOffset = MAX_POSE_RANK + nMyRank - 1;
2016-10-20 23:11:30 +02:00
if(nOffset >= (int)vecMasternodeRanks.size()) return;
std::vector<CMasternode*> vSortedByAddr;
for (auto& mnpair : mapMasternodes) {
vSortedByAddr.push_back(&mnpair.second);
2016-10-20 23:11:30 +02:00
}
sort(vSortedByAddr.begin(), vSortedByAddr.end(), CompareByAddr());
it = vecMasternodeRanks.begin() + nOffset;
while(it != vecMasternodeRanks.end()) {
if(it->second.IsPoSeVerified() || it->second.IsPoSeBanned()) {
LogPrint("masternode", "CMasternodeMan::DoFullVerificationStep -- Already %s%s%s masternode %s address %s, skipping...\n",
it->second.IsPoSeVerified() ? "verified" : "",
it->second.IsPoSeVerified() && it->second.IsPoSeBanned() ? " and " : "",
it->second.IsPoSeBanned() ? "banned" : "",
it->second.vin.prevout.ToStringShort(), it->second.addr.ToString());
nOffset += MAX_POSE_CONNECTIONS;
if(nOffset >= (int)vecMasternodeRanks.size()) break;
it += MAX_POSE_CONNECTIONS;
2016-10-20 23:11:30 +02:00
continue;
}
LogPrint("masternode", "CMasternodeMan::DoFullVerificationStep -- Verifying masternode %s rank %d/%d address %s\n",
it->second.vin.prevout.ToStringShort(), it->first, nRanksTotal, it->second.addr.ToString());
if(SendVerifyRequest(CAddress(it->second.addr, NODE_NETWORK), vSortedByAddr)) {
2016-10-20 23:11:30 +02:00
nCount++;
if(nCount >= MAX_POSE_CONNECTIONS) break;
2016-10-20 23:11:30 +02:00
}
nOffset += MAX_POSE_CONNECTIONS;
if(nOffset >= (int)vecMasternodeRanks.size()) break;
it += MAX_POSE_CONNECTIONS;
2016-10-20 23:11:30 +02:00
}
LogPrint("masternode", "CMasternodeMan::DoFullVerificationStep -- Sent verification requests to %d masternodes\n", nCount);
}
// This function tries to find masternodes with the same addr,
// find a verified one and ban all the other. If there are many nodes
// with the same addr but none of them is verified yet, then none of them are banned.
// It could take many times to run this before most of the duplicate nodes are banned.
2016-10-20 23:11:30 +02:00
void CMasternodeMan::CheckSameAddr()
{
if(!masternodeSync.IsSynced() || mapMasternodes.empty()) return;
2016-10-20 23:11:30 +02:00
std::vector<CMasternode*> vBan;
std::vector<CMasternode*> vSortedByAddr;
{
LOCK(cs);
CMasternode* pprevMasternode = NULL;
CMasternode* pverifiedMasternode = NULL;
for (auto& mnpair : mapMasternodes) {
vSortedByAddr.push_back(&mnpair.second);
2016-10-20 23:11:30 +02:00
}
sort(vSortedByAddr.begin(), vSortedByAddr.end(), CompareByAddr());
BOOST_FOREACH(CMasternode* pmn, vSortedByAddr) {
// check only (pre)enabled masternodes
if(!pmn->IsEnabled() && !pmn->IsPreEnabled()) continue;
// initial step
if(!pprevMasternode) {
pprevMasternode = pmn;
pverifiedMasternode = pmn->IsPoSeVerified() ? pmn : NULL;
continue;
}
// second+ step
if(pmn->addr == pprevMasternode->addr) {
if(pverifiedMasternode) {
// another masternode with the same ip is verified, ban this one
vBan.push_back(pmn);
} else if(pmn->IsPoSeVerified()) {
// this masternode with the same ip is verified, ban previous one
vBan.push_back(pprevMasternode);
// and keep a reference to be able to ban following masternodes with the same ip
pverifiedMasternode = pmn;
}
} else {
pverifiedMasternode = pmn->IsPoSeVerified() ? pmn : NULL;
}
pprevMasternode = pmn;
}
}
// ban duplicates
BOOST_FOREACH(CMasternode* pmn, vBan) {
LogPrintf("CMasternodeMan::CheckSameAddr -- increasing PoSe ban score for masternode %s\n", pmn->vin.prevout.ToStringShort());
pmn->IncreasePoSeBanScore();
2016-10-20 23:11:30 +02:00
}
}
bool CMasternodeMan::SendVerifyRequest(const CAddress& addr, const std::vector<CMasternode*>& vSortedByAddr)
{
if(netfulfilledman.HasFulfilledRequest(addr, strprintf("%s", NetMsgType::MNVERIFY)+"-request")) {
// we already asked for verification, not a good idea to do this too often, skip it
LogPrint("masternode", "CMasternodeMan::SendVerifyRequest -- too many requests, skipping... addr=%s\n", addr.ToString());
return false;
}
Backport Bitcoin PR#8085: p2p: Begin encapsulation (#1537) * net: move CBanDB and CAddrDB out of net.h/cpp This will eventually solve a circular dependency * net: Create CConnman to encapsulate p2p connections * net: Move socket binding into CConnman * net: move OpenNetworkConnection into CConnman * net: move ban and addrman functions into CConnman * net: Add oneshot functions to CConnman * net: move added node functions to CConnman * net: Add most functions needed for vNodes to CConnman * net: handle nodesignals in CConnman * net: Pass CConnection to wallet rather than using the global * net: Add rpc error for missing/disabled p2p functionality * net: Pass CConnman around as needed * gui: add NodeID to the peer table * net: create generic functor accessors and move vNodes to CConnman * net: move whitelist functions into CConnman * net: move nLastNodeId to CConnman * net: move nLocalHostNonce to CConnman This behavior seems to have been quite racy and broken. Move nLocalHostNonce into CNode, and check received nonces against all non-fully-connected nodes. If there's a match, assume we've connected to ourself. * net: move messageHandlerCondition to CConnman * net: move send/recv statistics to CConnman * net: move SendBufferSize/ReceiveFloodSize to CConnman * net: move nLocalServices/nRelevantServices to CConnman These are in-turn passed to CNode at connection time. This allows us to offer different services to different peers (or test the effects of doing so). * net: move semOutbound and semMasternodeOutbound to CConnman * net: SocketSendData returns written size * net: move max/max-outbound to CConnman * net: Pass best block known height into CConnman CConnman then passes the current best height into CNode at creation time. This way CConnman/CNode have no dependency on main for height, and the signals only move in one direction. This also helps to prevent identity leakage a tiny bit. Before this change, an attacker could theoretically make 2 connections on different interfaces. They would connect fully on one, and only establish the initial connection on the other. Once they receive a new block, they would relay it to your first connection, and immediately commence the version handshake on the second. Since the new block height is reflected immediately, they could attempt to learn whether the two connections were correlated. This is, of course, incredibly unlikely to work due to the small timings involved and receipt from other senders. But it doesn't hurt to lock-in nBestHeight at the time of connection, rather than letting the remote choose the time. * net: pass CClientUIInterface into CConnman * net: Drop StartNode/StopNode and use CConnman directly * net: Introduce CConnection::Options to avoid passing so many params * net: add nSendBufferMaxSize/nReceiveFloodSize to CConnection::Options * net: move vNodesDisconnected into CConnman * Made the ForEachNode* functions in src/net.cpp more pragmatic and self documenting * Convert ForEachNode* functions to take a templated function argument rather than a std::function to eliminate std::function overhead * net: move MAX_FEELER_CONNECTIONS into connman
2017-07-21 11:35:19 +02:00
// TODO: Pass CConnman instance somehow and don't use global variable.
CNode* pnode = g_connman->ConnectNode(addr, NULL, true);
if(pnode == NULL) {
LogPrintf("CMasternodeMan::SendVerifyRequest -- can't connect to node to verify it, addr=%s\n", addr.ToString());
2016-10-20 23:11:30 +02:00
return false;
}
netfulfilledman.AddFulfilledRequest(addr, strprintf("%s", NetMsgType::MNVERIFY)+"-request");
// use random nonce, store it and require node to reply with correct one later
CMasternodeVerification mnv(addr, GetRandInt(999999), nCachedBlockHeight - 1);
mWeAskedForVerification[addr] = mnv;
LogPrintf("CMasternodeMan::SendVerifyRequest -- verifying node using nonce %d addr=%s\n", mnv.nonce, addr.ToString());
Backport Bitcoin PR#8708: net: have CConnman handle message sending (#1553) * serialization: teach serializers variadics Also add a variadic CDataStream ctor for ease-of-use. * connman is in charge of pushing messages The changes here are dense and subtle, but hopefully all is more explicit than before. - CConnman is now in charge of sending data rather than the nodes themselves. This is necessary because many decisions need to be made with all nodes in mind, and a model that requires the nodes calling up to their manager quickly turns to spaghetti. - The per-node-serializer (ssSend) has been replaced with a (quasi-)const send-version. Since the send version for serialization can only change once per connection, we now explicitly tag messages with INIT_PROTO_VERSION if they are sent before the handshake. With this done, there's no need to lock for access to nSendVersion. Also, a new stream is used for each message, so there's no need to lock during the serialization process. - This takes care of accounting for optimistic sends, so the nOptimisticBytesWritten hack can be removed. - -dropmessagestest and -fuzzmessagestest have not been preserved, as I suspect they haven't been used in years. * net: switch all callers to connman for pushing messages Drop all of the old stuff. * drop the optimistic write counter hack This is now handled properly in realtime. * net: remove now-unused ssSend and Fuzz * net: construct CNodeStates in place * net: handle version push in InitializeNode
2017-07-27 16:28:05 +02:00
g_connman->PushMessage(pnode, NetMsgType::MNVERIFY, mnv);
return true;
2016-10-20 23:11:30 +02:00
}
void CMasternodeMan::SendVerifyReply(CNode* pnode, CMasternodeVerification& mnv)
{
// only masternodes can sign this, why would someone ask regular node?
if(!fMasterNode) {
// do not ban, malicious node might be using my IP
// and trying to confuse the node which tries to verify it
return;
}
if(netfulfilledman.HasFulfilledRequest(pnode->addr, strprintf("%s", NetMsgType::MNVERIFY)+"-reply")) {
// peer should not ask us that often
LogPrintf("MasternodeMan::SendVerifyReply -- ERROR: peer already asked me recently, peer=%d\n", pnode->id);
Misbehaving(pnode->id, 20);
return;
}
uint256 blockHash;
if(!GetBlockHash(blockHash, mnv.nBlockHeight)) {
LogPrintf("MasternodeMan::SendVerifyReply -- can't get block hash for unknown block height %d, peer=%d\n", mnv.nBlockHeight, pnode->id);
return;
}
std::string strMessage = strprintf("%s%d%s", activeMasternode.service.ToString(false), mnv.nonce, blockHash.ToString());
if(!CMessageSigner::SignMessage(strMessage, mnv.vchSig1, activeMasternode.keyMasternode)) {
2016-10-20 23:11:30 +02:00
LogPrintf("MasternodeMan::SendVerifyReply -- SignMessage() failed\n");
return;
}
std::string strError;
if(!CMessageSigner::VerifyMessage(activeMasternode.pubKeyMasternode, mnv.vchSig1, strMessage, strError)) {
2016-10-20 23:11:30 +02:00
LogPrintf("MasternodeMan::SendVerifyReply -- VerifyMessage() failed, error: %s\n", strError);
return;
}
Backport Bitcoin PR#8708: net: have CConnman handle message sending (#1553) * serialization: teach serializers variadics Also add a variadic CDataStream ctor for ease-of-use. * connman is in charge of pushing messages The changes here are dense and subtle, but hopefully all is more explicit than before. - CConnman is now in charge of sending data rather than the nodes themselves. This is necessary because many decisions need to be made with all nodes in mind, and a model that requires the nodes calling up to their manager quickly turns to spaghetti. - The per-node-serializer (ssSend) has been replaced with a (quasi-)const send-version. Since the send version for serialization can only change once per connection, we now explicitly tag messages with INIT_PROTO_VERSION if they are sent before the handshake. With this done, there's no need to lock for access to nSendVersion. Also, a new stream is used for each message, so there's no need to lock during the serialization process. - This takes care of accounting for optimistic sends, so the nOptimisticBytesWritten hack can be removed. - -dropmessagestest and -fuzzmessagestest have not been preserved, as I suspect they haven't been used in years. * net: switch all callers to connman for pushing messages Drop all of the old stuff. * drop the optimistic write counter hack This is now handled properly in realtime. * net: remove now-unused ssSend and Fuzz * net: construct CNodeStates in place * net: handle version push in InitializeNode
2017-07-27 16:28:05 +02:00
g_connman->PushMessage(pnode, NetMsgType::MNVERIFY, mnv);
2016-10-20 23:11:30 +02:00
netfulfilledman.AddFulfilledRequest(pnode->addr, strprintf("%s", NetMsgType::MNVERIFY)+"-reply");
}
void CMasternodeMan::ProcessVerifyReply(CNode* pnode, CMasternodeVerification& mnv)
{
std::string strError;
// did we even ask for it? if that's the case we should have matching fulfilled request
if(!netfulfilledman.HasFulfilledRequest(pnode->addr, strprintf("%s", NetMsgType::MNVERIFY)+"-request")) {
LogPrintf("CMasternodeMan::ProcessVerifyReply -- ERROR: we didn't ask for verification of %s, peer=%d\n", pnode->addr.ToString(), pnode->id);
Misbehaving(pnode->id, 20);
return;
}
// Received nonce for a known address must match the one we sent
if(mWeAskedForVerification[pnode->addr].nonce != mnv.nonce) {
LogPrintf("CMasternodeMan::ProcessVerifyReply -- ERROR: wrong nounce: requested=%d, received=%d, peer=%d\n",
mWeAskedForVerification[pnode->addr].nonce, mnv.nonce, pnode->id);
Misbehaving(pnode->id, 20);
return;
}
// Received nBlockHeight for a known address must match the one we sent
if(mWeAskedForVerification[pnode->addr].nBlockHeight != mnv.nBlockHeight) {
LogPrintf("CMasternodeMan::ProcessVerifyReply -- ERROR: wrong nBlockHeight: requested=%d, received=%d, peer=%d\n",
mWeAskedForVerification[pnode->addr].nBlockHeight, mnv.nBlockHeight, pnode->id);
Misbehaving(pnode->id, 20);
return;
}
uint256 blockHash;
if(!GetBlockHash(blockHash, mnv.nBlockHeight)) {
// this shouldn't happen...
LogPrintf("MasternodeMan::ProcessVerifyReply -- can't get block hash for unknown block height %d, peer=%d\n", mnv.nBlockHeight, pnode->id);
return;
}
// we already verified this address, why node is spamming?
if(netfulfilledman.HasFulfilledRequest(pnode->addr, strprintf("%s", NetMsgType::MNVERIFY)+"-done")) {
LogPrintf("CMasternodeMan::ProcessVerifyReply -- ERROR: already verified %s recently\n", pnode->addr.ToString());
Misbehaving(pnode->id, 20);
return;
}
{
LOCK(cs);
CMasternode* prealMasternode = NULL;
std::vector<CMasternode*> vpMasternodesToBan;
std::string strMessage1 = strprintf("%s%d%s", pnode->addr.ToString(false), mnv.nonce, blockHash.ToString());
for (auto& mnpair : mapMasternodes) {
if(CAddress(mnpair.second.addr, NODE_NETWORK) == pnode->addr) {
if(CMessageSigner::VerifyMessage(mnpair.second.pubKeyMasternode, mnv.vchSig1, strMessage1, strError)) {
2016-10-20 23:11:30 +02:00
// found it!
prealMasternode = &mnpair.second;
if(!mnpair.second.IsPoSeVerified()) {
mnpair.second.DecreasePoSeBanScore();
2016-10-20 23:11:30 +02:00
}
netfulfilledman.AddFulfilledRequest(pnode->addr, strprintf("%s", NetMsgType::MNVERIFY)+"-done");
// we can only broadcast it if we are an activated masternode
if(activeMasternode.outpoint == COutPoint()) continue;
2016-10-20 23:11:30 +02:00
// update ...
mnv.addr = mnpair.second.addr;
mnv.vin1 = mnpair.second.vin;
mnv.vin2 = CTxIn(activeMasternode.outpoint);
2016-10-20 23:11:30 +02:00
std::string strMessage2 = strprintf("%s%d%s%s%s", mnv.addr.ToString(false), mnv.nonce, blockHash.ToString(),
mnv.vin1.prevout.ToStringShort(), mnv.vin2.prevout.ToStringShort());
// ... and sign it
if(!CMessageSigner::SignMessage(strMessage2, mnv.vchSig2, activeMasternode.keyMasternode)) {
2016-10-20 23:11:30 +02:00
LogPrintf("MasternodeMan::ProcessVerifyReply -- SignMessage() failed\n");
return;
}
std::string strError;
if(!CMessageSigner::VerifyMessage(activeMasternode.pubKeyMasternode, mnv.vchSig2, strMessage2, strError)) {
2016-10-20 23:11:30 +02:00
LogPrintf("MasternodeMan::ProcessVerifyReply -- VerifyMessage() failed, error: %s\n", strError);
return;
}
mWeAskedForVerification[pnode->addr] = mnv;
mnv.Relay();
} else {
vpMasternodesToBan.push_back(&mnpair.second);
2016-10-20 23:11:30 +02:00
}
}
}
// no real masternode found?...
if(!prealMasternode) {
// this should never be the case normally,
// only if someone is trying to game the system in some way or smth like that
LogPrintf("CMasternodeMan::ProcessVerifyReply -- ERROR: no real masternode found for addr %s\n", pnode->addr.ToString());
Misbehaving(pnode->id, 20);
return;
}
LogPrintf("CMasternodeMan::ProcessVerifyReply -- verified real masternode %s for addr %s\n",
prealMasternode->vin.prevout.ToStringShort(), pnode->addr.ToString());
// increase ban score for everyone else
BOOST_FOREACH(CMasternode* pmn, vpMasternodesToBan) {
pmn->IncreasePoSeBanScore();
2016-10-20 23:11:30 +02:00
LogPrint("masternode", "CMasternodeMan::ProcessVerifyBroadcast -- increased PoSe ban score for %s addr %s, new score %d\n",
prealMasternode->vin.prevout.ToStringShort(), pnode->addr.ToString(), pmn->nPoSeBanScore);
}
LogPrintf("CMasternodeMan::ProcessVerifyBroadcast -- PoSe score increased for %d fake masternodes, addr %s\n",
2016-10-20 23:11:30 +02:00
(int)vpMasternodesToBan.size(), pnode->addr.ToString());
}
}
void CMasternodeMan::ProcessVerifyBroadcast(CNode* pnode, const CMasternodeVerification& mnv)
{
std::string strError;
if(mapSeenMasternodeVerification.find(mnv.GetHash()) != mapSeenMasternodeVerification.end()) {
// we already have one
return;
}
mapSeenMasternodeVerification[mnv.GetHash()] = mnv;
// we don't care about history
if(mnv.nBlockHeight < nCachedBlockHeight - MAX_POSE_BLOCKS) {
LogPrint("masternode", "CMasternodeMan::ProcessVerifyBroadcast -- Outdated: current block %d, verification block %d, peer=%d\n",
nCachedBlockHeight, mnv.nBlockHeight, pnode->id);
2016-10-20 23:11:30 +02:00
return;
}
if(mnv.vin1.prevout == mnv.vin2.prevout) {
LogPrint("masternode", "CMasternodeMan::ProcessVerifyBroadcast -- ERROR: same vins %s, peer=%d\n",
2016-10-20 23:11:30 +02:00
mnv.vin1.prevout.ToStringShort(), pnode->id);
// that was NOT a good idea to cheat and verify itself,
// ban the node we received such message from
Misbehaving(pnode->id, 100);
return;
}
uint256 blockHash;
if(!GetBlockHash(blockHash, mnv.nBlockHeight)) {
// this shouldn't happen...
LogPrintf("CMasternodeMan::ProcessVerifyBroadcast -- Can't get block hash for unknown block height %d, peer=%d\n", mnv.nBlockHeight, pnode->id);
2016-10-20 23:11:30 +02:00
return;
}
int nRank;
if (!GetMasternodeRank(mnv.vin2.prevout, nRank, mnv.nBlockHeight, MIN_POSE_PROTO_VERSION)) {
LogPrint("masternode", "CMasternodeMan::ProcessVerifyBroadcast -- Can't calculate rank for masternode %s\n",
mnv.vin2.prevout.ToStringShort());
return;
}
if(nRank > MAX_POSE_RANK) {
LogPrint("masternode", "CMasternodeMan::ProcessVerifyBroadcast -- Masternode %s is not in top %d, current rank %d, peer=%d\n",
mnv.vin2.prevout.ToStringShort(), (int)MAX_POSE_RANK, nRank, pnode->id);
2016-10-20 23:11:30 +02:00
return;
}
{
LOCK(cs);
std::string strMessage1 = strprintf("%s%d%s", mnv.addr.ToString(false), mnv.nonce, blockHash.ToString());
std::string strMessage2 = strprintf("%s%d%s%s%s", mnv.addr.ToString(false), mnv.nonce, blockHash.ToString(),
mnv.vin1.prevout.ToStringShort(), mnv.vin2.prevout.ToStringShort());
CMasternode* pmn1 = Find(mnv.vin1.prevout);
2016-10-20 23:11:30 +02:00
if(!pmn1) {
LogPrintf("CMasternodeMan::ProcessVerifyBroadcast -- can't find masternode1 %s\n", mnv.vin1.prevout.ToStringShort());
return;
}
CMasternode* pmn2 = Find(mnv.vin2.prevout);
2016-10-20 23:11:30 +02:00
if(!pmn2) {
LogPrintf("CMasternodeMan::ProcessVerifyBroadcast -- can't find masternode2 %s\n", mnv.vin2.prevout.ToStringShort());
return;
}
if(pmn1->addr != mnv.addr) {
LogPrintf("CMasternodeMan::ProcessVerifyBroadcast -- addr %s do not match %s\n", mnv.addr.ToString(), pnode->addr.ToString());
return;
}
if(CMessageSigner::VerifyMessage(pmn1->pubKeyMasternode, mnv.vchSig1, strMessage1, strError)) {
LogPrintf("CMasternodeMan::ProcessVerifyBroadcast -- VerifyMessage() for masternode1 failed, error: %s\n", strError);
2016-10-20 23:11:30 +02:00
return;
}
if(CMessageSigner::VerifyMessage(pmn2->pubKeyMasternode, mnv.vchSig2, strMessage2, strError)) {
LogPrintf("CMasternodeMan::ProcessVerifyBroadcast -- VerifyMessage() for masternode2 failed, error: %s\n", strError);
2016-10-20 23:11:30 +02:00
return;
}
if(!pmn1->IsPoSeVerified()) {
pmn1->DecreasePoSeBanScore();
2016-10-20 23:11:30 +02:00
}
mnv.Relay();
LogPrintf("CMasternodeMan::ProcessVerifyBroadcast -- verified masternode %s for addr %s\n",
pmn1->vin.prevout.ToStringShort(), pnode->addr.ToString());
// increase ban score for everyone else with the same addr
int nCount = 0;
for (auto& mnpair : mapMasternodes) {
if(mnpair.second.addr != mnv.addr || mnpair.first == mnv.vin1.prevout) continue;
mnpair.second.IncreasePoSeBanScore();
2016-10-20 23:11:30 +02:00
nCount++;
LogPrint("masternode", "CMasternodeMan::ProcessVerifyBroadcast -- increased PoSe ban score for %s addr %s, new score %d\n",
mnpair.first.ToStringShort(), mnpair.second.addr.ToString(), mnpair.second.nPoSeBanScore);
2016-10-20 23:11:30 +02:00
}
LogPrintf("CMasternodeMan::ProcessVerifyBroadcast -- PoSe score incresed for %d fake masternodes, addr %s\n",
nCount, pnode->addr.ToString());
}
}
std::string CMasternodeMan::ToString() const
{
std::ostringstream info;
info << "Masternodes: " << (int)mapMasternodes.size() <<
2015-03-05 09:10:15 +01:00
", peers who asked us for Masternode list: " << (int)mAskedUsForMasternodeList.size() <<
", peers we asked for Masternode list: " << (int)mWeAskedForMasternodeList.size() <<
2015-03-06 18:25:48 +01:00
", entries in Masternode list we asked for: " << (int)mWeAskedForMasternodeListEntry.size() <<
", nDsqCount: " << (int)nDsqCount;
return info.str();
}
void CMasternodeMan::UpdateMasternodeList(CMasternodeBroadcast mnb)
{
LOCK2(cs_main, cs);
mapSeenMasternodePing.insert(std::make_pair(mnb.lastPing.GetHash(), mnb.lastPing));
mapSeenMasternodeBroadcast.insert(std::make_pair(mnb.GetHash(), std::make_pair(GetTime(), mnb)));
LogPrintf("CMasternodeMan::UpdateMasternodeList -- masternode=%s addr=%s\n", mnb.vin.prevout.ToStringShort(), mnb.addr.ToString());
CMasternode* pmn = Find(mnb.vin.prevout);
if(pmn == NULL) {
if(Add(mnb)) {
masternodeSync.BumpAssetLastTime("CMasternodeMan::UpdateMasternodeList - new");
}
} else {
CMasternodeBroadcast mnbOld = mapSeenMasternodeBroadcast[CMasternodeBroadcast(*pmn).GetHash()].second;
if(pmn->UpdateFromNewBroadcast(mnb)) {
masternodeSync.BumpAssetLastTime("CMasternodeMan::UpdateMasternodeList - seen");
mapSeenMasternodeBroadcast.erase(mnbOld.GetHash());
}
}
}
bool CMasternodeMan::CheckMnbAndUpdateMasternodeList(CNode* pfrom, CMasternodeBroadcast mnb, int& nDos)
2016-10-20 23:11:30 +02:00
{
// Need to lock cs_main here to ensure consistent locking order because the SimpleCheck call below locks cs_main
LOCK(cs_main);
2016-10-20 23:11:30 +02:00
{
LOCK(cs);
nDos = 0;
LogPrint("masternode", "CMasternodeMan::CheckMnbAndUpdateMasternodeList -- masternode=%s\n", mnb.vin.prevout.ToStringShort());
uint256 hash = mnb.GetHash();
if(mapSeenMasternodeBroadcast.count(hash) && !mnb.fRecovery) { //seen
LogPrint("masternode", "CMasternodeMan::CheckMnbAndUpdateMasternodeList -- masternode=%s seen\n", mnb.vin.prevout.ToStringShort());
// less then 2 pings left before this MN goes into non-recoverable state, bump sync timeout
if(GetTime() - mapSeenMasternodeBroadcast[hash].first > MASTERNODE_NEW_START_REQUIRED_SECONDS - MASTERNODE_MIN_MNP_SECONDS * 2) {
LogPrint("masternode", "CMasternodeMan::CheckMnbAndUpdateMasternodeList -- masternode=%s seen update\n", mnb.vin.prevout.ToStringShort());
mapSeenMasternodeBroadcast[hash].first = GetTime();
masternodeSync.BumpAssetLastTime("CMasternodeMan::CheckMnbAndUpdateMasternodeList - seen");
}
// did we ask this node for it?
if(pfrom && IsMnbRecoveryRequested(hash) && GetTime() < mMnbRecoveryRequests[hash].first) {
LogPrint("masternode", "CMasternodeMan::CheckMnbAndUpdateMasternodeList -- mnb=%s seen request\n", hash.ToString());
if(mMnbRecoveryRequests[hash].second.count(pfrom->addr)) {
LogPrint("masternode", "CMasternodeMan::CheckMnbAndUpdateMasternodeList -- mnb=%s seen request, addr=%s\n", hash.ToString(), pfrom->addr.ToString());
// do not allow node to send same mnb multiple times in recovery mode
mMnbRecoveryRequests[hash].second.erase(pfrom->addr);
// does it have newer lastPing?
if(mnb.lastPing.sigTime > mapSeenMasternodeBroadcast[hash].second.lastPing.sigTime) {
// simulate Check
CMasternode mnTemp = CMasternode(mnb);
mnTemp.Check();
LogPrint("masternode", "CMasternodeMan::CheckMnbAndUpdateMasternodeList -- mnb=%s seen request, addr=%s, better lastPing: %d min ago, projected mn state: %s\n", hash.ToString(), pfrom->addr.ToString(), (GetAdjustedTime() - mnb.lastPing.sigTime)/60, mnTemp.GetStateString());
if(mnTemp.IsValidStateForAutoStart(mnTemp.nActiveState)) {
// this node thinks it's a good one
LogPrint("masternode", "CMasternodeMan::CheckMnbAndUpdateMasternodeList -- masternode=%s seen good\n", mnb.vin.prevout.ToStringShort());
mMnbRecoveryGoodReplies[hash].push_back(mnb);
}
}
}
}
return true;
}
mapSeenMasternodeBroadcast.insert(std::make_pair(hash, std::make_pair(GetTime(), mnb)));
LogPrint("masternode", "CMasternodeMan::CheckMnbAndUpdateMasternodeList -- masternode=%s new\n", mnb.vin.prevout.ToStringShort());
if(!mnb.SimpleCheck(nDos)) {
LogPrint("masternode", "CMasternodeMan::CheckMnbAndUpdateMasternodeList -- SimpleCheck() failed, masternode=%s\n", mnb.vin.prevout.ToStringShort());
2016-10-20 23:11:30 +02:00
return false;
}
// search Masternode list
CMasternode* pmn = Find(mnb.vin.prevout);
if(pmn) {
CMasternodeBroadcast mnbOld = mapSeenMasternodeBroadcast[CMasternodeBroadcast(*pmn).GetHash()].second;
if(!mnb.Update(pmn, nDos)) {
LogPrint("masternode", "CMasternodeMan::CheckMnbAndUpdateMasternodeList -- Update() failed, masternode=%s\n", mnb.vin.prevout.ToStringShort());
return false;
}
if(hash != mnbOld.GetHash()) {
mapSeenMasternodeBroadcast.erase(mnbOld.GetHash());
}
return true;
}
}
if(mnb.CheckOutpoint(nDos)) {
Add(mnb);
masternodeSync.BumpAssetLastTime("CMasternodeMan::CheckMnbAndUpdateMasternodeList - new");
// if it matches our Masternode privkey...
if(fMasterNode && mnb.pubKeyMasternode == activeMasternode.pubKeyMasternode) {
mnb.nPoSeBanScore = -MASTERNODE_POSE_BAN_MAX_SCORE;
if(mnb.nProtocolVersion == PROTOCOL_VERSION) {
// ... and PROTOCOL_VERSION, then we've been remotely activated ...
LogPrintf("CMasternodeMan::CheckMnbAndUpdateMasternodeList -- Got NEW Masternode entry: masternode=%s sigTime=%lld addr=%s\n",
mnb.vin.prevout.ToStringShort(), mnb.sigTime, mnb.addr.ToString());
activeMasternode.ManageState();
} else {
// ... otherwise we need to reactivate our node, do not add it to the list and do not relay
// but also do not ban the node we get this message from
LogPrintf("CMasternodeMan::CheckMnbAndUpdateMasternodeList -- wrong PROTOCOL_VERSION, re-activate your MN: message nProtocolVersion=%d PROTOCOL_VERSION=%d\n", mnb.nProtocolVersion, PROTOCOL_VERSION);
return false;
2016-10-20 23:11:30 +02:00
}
}
mnb.Relay();
} else {
LogPrintf("CMasternodeMan::CheckMnbAndUpdateMasternodeList -- Rejected Masternode entry: %s addr=%s\n", mnb.vin.prevout.ToStringShort(), mnb.addr.ToString());
return false;
}
return true;
}
void CMasternodeMan::UpdateLastPaid(const CBlockIndex* pindex)
2016-10-20 23:11:30 +02:00
{
V0.12.1.x sentinel watchdog pr (#1079) Squashed: * Replaced unsafe mnodeman.Find function with Get in governance-vote.cpp * Reject unparsable governance objects * Implemented sentinel watchdog objects (separated out from locking changes) * Added WATCHDOG support to rpcgovernance.cpp * Implemented WATCHDOG_EXPIRED state for masternodes * Added serialization of watchdog timestamps * Masternode fixes - Added version check to CMasternodeMan deserialization - Added several missing locking calls in CMasternodeMan * Fixed missing member initialization in CMasternode constructor and added more logging * Added MASTERNODE_WATCHDOG_MAX_SECONDS to governanceinfo * Added masternodewatchdogmaxseconds info to getgovernanceinfo help * Make masternodes remain in WATCHDOG_EXPIRED state unless removed or collateral expires * Allow watchdog object creation by WATCHDOG_EXPIRED MN * Fixed MN validation logic for governance object creation * Count total masternodes instead of enabled masternodes in masternode-sync * Transition out of WATCHDOG_EXPIRED state if the watchdog is inactive * Fixed IsWatchdogExpired bug * Fixed rate check for watchdog objects and no longer check MN state when validating governance objects * Applied PR #1061 patch * Ported locking changes from other branch * Require only 1 block between new watchdog objects * Accept pings for WATCHDOG_EXPIRED masternodes * Lock CmasternodeMan::cs in CmasternodeMan::ProcessMessage * Several governance changes - Fixed uninitialized value in CGovernancePayment class - Return an error on submission if any superblock payment cannot be parsed - Added logging more statements * Explicitly initialize all governance object members * Fix deadlock * Fixed non-threadsafe access to masternode in activemasternode.cpp * Revert added wallet lock * Changed CActiveMasternode so that watchdog expired nodes can still send pings * Modified CActiveMasternode to run pinger regardless of state when MN is in list * Added voter and time information to getvotes command * Improved CActiveMasternode state management * Implemented GetInfo functions for more efficient thread-safe access to masternode information * Added CActiveMasternode debug logging messages * Fixed initial type setting and error message for incorrect protocol version * Changes based on code review comments * Set active state for local mode
2016-10-17 20:54:28 +02:00
LOCK(cs);
2016-10-20 23:11:30 +02:00
if(fLiteMode || !masternodeSync.IsWinnersListSynced() || mapMasternodes.empty()) return;
static bool IsFirstRun = true;
// Do full scan on first run or if we are not a masternode
// (MNs should update this info on every block, so limited scan should be enough for them)
2016-10-20 23:11:30 +02:00
int nMaxBlocksToScanBack = (IsFirstRun || !fMasterNode) ? mnpayments.GetStorageLimit() : LAST_PAID_SCAN_BLOCKS;
// LogPrint("mnpayments", "CMasternodeMan::UpdateLastPaid -- nHeight=%d, nMaxBlocksToScanBack=%d, IsFirstRun=%s\n",
// nCachedBlockHeight, nMaxBlocksToScanBack, IsFirstRun ? "true" : "false");
for (auto& mnpair: mapMasternodes) {
mnpair.second.UpdateLastPaid(pindex, nMaxBlocksToScanBack);
}
IsFirstRun = false;
}
V0.12.1.x sentinel watchdog pr (#1079) Squashed: * Replaced unsafe mnodeman.Find function with Get in governance-vote.cpp * Reject unparsable governance objects * Implemented sentinel watchdog objects (separated out from locking changes) * Added WATCHDOG support to rpcgovernance.cpp * Implemented WATCHDOG_EXPIRED state for masternodes * Added serialization of watchdog timestamps * Masternode fixes - Added version check to CMasternodeMan deserialization - Added several missing locking calls in CMasternodeMan * Fixed missing member initialization in CMasternode constructor and added more logging * Added MASTERNODE_WATCHDOG_MAX_SECONDS to governanceinfo * Added masternodewatchdogmaxseconds info to getgovernanceinfo help * Make masternodes remain in WATCHDOG_EXPIRED state unless removed or collateral expires * Allow watchdog object creation by WATCHDOG_EXPIRED MN * Fixed MN validation logic for governance object creation * Count total masternodes instead of enabled masternodes in masternode-sync * Transition out of WATCHDOG_EXPIRED state if the watchdog is inactive * Fixed IsWatchdogExpired bug * Fixed rate check for watchdog objects and no longer check MN state when validating governance objects * Applied PR #1061 patch * Ported locking changes from other branch * Require only 1 block between new watchdog objects * Accept pings for WATCHDOG_EXPIRED masternodes * Lock CmasternodeMan::cs in CmasternodeMan::ProcessMessage * Several governance changes - Fixed uninitialized value in CGovernancePayment class - Return an error on submission if any superblock payment cannot be parsed - Added logging more statements * Explicitly initialize all governance object members * Fix deadlock * Fixed non-threadsafe access to masternode in activemasternode.cpp * Revert added wallet lock * Changed CActiveMasternode so that watchdog expired nodes can still send pings * Modified CActiveMasternode to run pinger regardless of state when MN is in list * Added voter and time information to getvotes command * Improved CActiveMasternode state management * Implemented GetInfo functions for more efficient thread-safe access to masternode information * Added CActiveMasternode debug logging messages * Fixed initial type setting and error message for incorrect protocol version * Changes based on code review comments * Set active state for local mode
2016-10-17 20:54:28 +02:00
void CMasternodeMan::UpdateWatchdogVoteTime(const COutPoint& outpoint)
V0.12.1.x sentinel watchdog pr (#1079) Squashed: * Replaced unsafe mnodeman.Find function with Get in governance-vote.cpp * Reject unparsable governance objects * Implemented sentinel watchdog objects (separated out from locking changes) * Added WATCHDOG support to rpcgovernance.cpp * Implemented WATCHDOG_EXPIRED state for masternodes * Added serialization of watchdog timestamps * Masternode fixes - Added version check to CMasternodeMan deserialization - Added several missing locking calls in CMasternodeMan * Fixed missing member initialization in CMasternode constructor and added more logging * Added MASTERNODE_WATCHDOG_MAX_SECONDS to governanceinfo * Added masternodewatchdogmaxseconds info to getgovernanceinfo help * Make masternodes remain in WATCHDOG_EXPIRED state unless removed or collateral expires * Allow watchdog object creation by WATCHDOG_EXPIRED MN * Fixed MN validation logic for governance object creation * Count total masternodes instead of enabled masternodes in masternode-sync * Transition out of WATCHDOG_EXPIRED state if the watchdog is inactive * Fixed IsWatchdogExpired bug * Fixed rate check for watchdog objects and no longer check MN state when validating governance objects * Applied PR #1061 patch * Ported locking changes from other branch * Require only 1 block between new watchdog objects * Accept pings for WATCHDOG_EXPIRED masternodes * Lock CmasternodeMan::cs in CmasternodeMan::ProcessMessage * Several governance changes - Fixed uninitialized value in CGovernancePayment class - Return an error on submission if any superblock payment cannot be parsed - Added logging more statements * Explicitly initialize all governance object members * Fix deadlock * Fixed non-threadsafe access to masternode in activemasternode.cpp * Revert added wallet lock * Changed CActiveMasternode so that watchdog expired nodes can still send pings * Modified CActiveMasternode to run pinger regardless of state when MN is in list * Added voter and time information to getvotes command * Improved CActiveMasternode state management * Implemented GetInfo functions for more efficient thread-safe access to masternode information * Added CActiveMasternode debug logging messages * Fixed initial type setting and error message for incorrect protocol version * Changes based on code review comments * Set active state for local mode
2016-10-17 20:54:28 +02:00
{
LOCK(cs);
CMasternode* pmn = Find(outpoint);
if(!pmn) {
V0.12.1.x sentinel watchdog pr (#1079) Squashed: * Replaced unsafe mnodeman.Find function with Get in governance-vote.cpp * Reject unparsable governance objects * Implemented sentinel watchdog objects (separated out from locking changes) * Added WATCHDOG support to rpcgovernance.cpp * Implemented WATCHDOG_EXPIRED state for masternodes * Added serialization of watchdog timestamps * Masternode fixes - Added version check to CMasternodeMan deserialization - Added several missing locking calls in CMasternodeMan * Fixed missing member initialization in CMasternode constructor and added more logging * Added MASTERNODE_WATCHDOG_MAX_SECONDS to governanceinfo * Added masternodewatchdogmaxseconds info to getgovernanceinfo help * Make masternodes remain in WATCHDOG_EXPIRED state unless removed or collateral expires * Allow watchdog object creation by WATCHDOG_EXPIRED MN * Fixed MN validation logic for governance object creation * Count total masternodes instead of enabled masternodes in masternode-sync * Transition out of WATCHDOG_EXPIRED state if the watchdog is inactive * Fixed IsWatchdogExpired bug * Fixed rate check for watchdog objects and no longer check MN state when validating governance objects * Applied PR #1061 patch * Ported locking changes from other branch * Require only 1 block between new watchdog objects * Accept pings for WATCHDOG_EXPIRED masternodes * Lock CmasternodeMan::cs in CmasternodeMan::ProcessMessage * Several governance changes - Fixed uninitialized value in CGovernancePayment class - Return an error on submission if any superblock payment cannot be parsed - Added logging more statements * Explicitly initialize all governance object members * Fix deadlock * Fixed non-threadsafe access to masternode in activemasternode.cpp * Revert added wallet lock * Changed CActiveMasternode so that watchdog expired nodes can still send pings * Modified CActiveMasternode to run pinger regardless of state when MN is in list * Added voter and time information to getvotes command * Improved CActiveMasternode state management * Implemented GetInfo functions for more efficient thread-safe access to masternode information * Added CActiveMasternode debug logging messages * Fixed initial type setting and error message for incorrect protocol version * Changes based on code review comments * Set active state for local mode
2016-10-17 20:54:28 +02:00
return;
}
pmn->UpdateWatchdogVoteTime();
V0.12.1.x sentinel watchdog pr (#1079) Squashed: * Replaced unsafe mnodeman.Find function with Get in governance-vote.cpp * Reject unparsable governance objects * Implemented sentinel watchdog objects (separated out from locking changes) * Added WATCHDOG support to rpcgovernance.cpp * Implemented WATCHDOG_EXPIRED state for masternodes * Added serialization of watchdog timestamps * Masternode fixes - Added version check to CMasternodeMan deserialization - Added several missing locking calls in CMasternodeMan * Fixed missing member initialization in CMasternode constructor and added more logging * Added MASTERNODE_WATCHDOG_MAX_SECONDS to governanceinfo * Added masternodewatchdogmaxseconds info to getgovernanceinfo help * Make masternodes remain in WATCHDOG_EXPIRED state unless removed or collateral expires * Allow watchdog object creation by WATCHDOG_EXPIRED MN * Fixed MN validation logic for governance object creation * Count total masternodes instead of enabled masternodes in masternode-sync * Transition out of WATCHDOG_EXPIRED state if the watchdog is inactive * Fixed IsWatchdogExpired bug * Fixed rate check for watchdog objects and no longer check MN state when validating governance objects * Applied PR #1061 patch * Ported locking changes from other branch * Require only 1 block between new watchdog objects * Accept pings for WATCHDOG_EXPIRED masternodes * Lock CmasternodeMan::cs in CmasternodeMan::ProcessMessage * Several governance changes - Fixed uninitialized value in CGovernancePayment class - Return an error on submission if any superblock payment cannot be parsed - Added logging more statements * Explicitly initialize all governance object members * Fix deadlock * Fixed non-threadsafe access to masternode in activemasternode.cpp * Revert added wallet lock * Changed CActiveMasternode so that watchdog expired nodes can still send pings * Modified CActiveMasternode to run pinger regardless of state when MN is in list * Added voter and time information to getvotes command * Improved CActiveMasternode state management * Implemented GetInfo functions for more efficient thread-safe access to masternode information * Added CActiveMasternode debug logging messages * Fixed initial type setting and error message for incorrect protocol version * Changes based on code review comments * Set active state for local mode
2016-10-17 20:54:28 +02:00
nLastWatchdogVoteTime = GetTime();
}
bool CMasternodeMan::IsWatchdogActive()
{
LOCK(cs);
// Check if any masternodes have voted recently, otherwise return false
return (GetTime() - nLastWatchdogVoteTime) <= MASTERNODE_WATCHDOG_MAX_SECONDS;
}
bool CMasternodeMan::AddGovernanceVote(const COutPoint& outpoint, uint256 nGovernanceObjectHash)
V0.12.1.x sentinel watchdog pr (#1079) Squashed: * Replaced unsafe mnodeman.Find function with Get in governance-vote.cpp * Reject unparsable governance objects * Implemented sentinel watchdog objects (separated out from locking changes) * Added WATCHDOG support to rpcgovernance.cpp * Implemented WATCHDOG_EXPIRED state for masternodes * Added serialization of watchdog timestamps * Masternode fixes - Added version check to CMasternodeMan deserialization - Added several missing locking calls in CMasternodeMan * Fixed missing member initialization in CMasternode constructor and added more logging * Added MASTERNODE_WATCHDOG_MAX_SECONDS to governanceinfo * Added masternodewatchdogmaxseconds info to getgovernanceinfo help * Make masternodes remain in WATCHDOG_EXPIRED state unless removed or collateral expires * Allow watchdog object creation by WATCHDOG_EXPIRED MN * Fixed MN validation logic for governance object creation * Count total masternodes instead of enabled masternodes in masternode-sync * Transition out of WATCHDOG_EXPIRED state if the watchdog is inactive * Fixed IsWatchdogExpired bug * Fixed rate check for watchdog objects and no longer check MN state when validating governance objects * Applied PR #1061 patch * Ported locking changes from other branch * Require only 1 block between new watchdog objects * Accept pings for WATCHDOG_EXPIRED masternodes * Lock CmasternodeMan::cs in CmasternodeMan::ProcessMessage * Several governance changes - Fixed uninitialized value in CGovernancePayment class - Return an error on submission if any superblock payment cannot be parsed - Added logging more statements * Explicitly initialize all governance object members * Fix deadlock * Fixed non-threadsafe access to masternode in activemasternode.cpp * Revert added wallet lock * Changed CActiveMasternode so that watchdog expired nodes can still send pings * Modified CActiveMasternode to run pinger regardless of state when MN is in list * Added voter and time information to getvotes command * Improved CActiveMasternode state management * Implemented GetInfo functions for more efficient thread-safe access to masternode information * Added CActiveMasternode debug logging messages * Fixed initial type setting and error message for incorrect protocol version * Changes based on code review comments * Set active state for local mode
2016-10-17 20:54:28 +02:00
{
LOCK(cs);
CMasternode* pmn = Find(outpoint);
if(!pmn) {
return false;
V0.12.1.x sentinel watchdog pr (#1079) Squashed: * Replaced unsafe mnodeman.Find function with Get in governance-vote.cpp * Reject unparsable governance objects * Implemented sentinel watchdog objects (separated out from locking changes) * Added WATCHDOG support to rpcgovernance.cpp * Implemented WATCHDOG_EXPIRED state for masternodes * Added serialization of watchdog timestamps * Masternode fixes - Added version check to CMasternodeMan deserialization - Added several missing locking calls in CMasternodeMan * Fixed missing member initialization in CMasternode constructor and added more logging * Added MASTERNODE_WATCHDOG_MAX_SECONDS to governanceinfo * Added masternodewatchdogmaxseconds info to getgovernanceinfo help * Make masternodes remain in WATCHDOG_EXPIRED state unless removed or collateral expires * Allow watchdog object creation by WATCHDOG_EXPIRED MN * Fixed MN validation logic for governance object creation * Count total masternodes instead of enabled masternodes in masternode-sync * Transition out of WATCHDOG_EXPIRED state if the watchdog is inactive * Fixed IsWatchdogExpired bug * Fixed rate check for watchdog objects and no longer check MN state when validating governance objects * Applied PR #1061 patch * Ported locking changes from other branch * Require only 1 block between new watchdog objects * Accept pings for WATCHDOG_EXPIRED masternodes * Lock CmasternodeMan::cs in CmasternodeMan::ProcessMessage * Several governance changes - Fixed uninitialized value in CGovernancePayment class - Return an error on submission if any superblock payment cannot be parsed - Added logging more statements * Explicitly initialize all governance object members * Fix deadlock * Fixed non-threadsafe access to masternode in activemasternode.cpp * Revert added wallet lock * Changed CActiveMasternode so that watchdog expired nodes can still send pings * Modified CActiveMasternode to run pinger regardless of state when MN is in list * Added voter and time information to getvotes command * Improved CActiveMasternode state management * Implemented GetInfo functions for more efficient thread-safe access to masternode information * Added CActiveMasternode debug logging messages * Fixed initial type setting and error message for incorrect protocol version * Changes based on code review comments * Set active state for local mode
2016-10-17 20:54:28 +02:00
}
pmn->AddGovernanceVote(nGovernanceObjectHash);
return true;
V0.12.1.x sentinel watchdog pr (#1079) Squashed: * Replaced unsafe mnodeman.Find function with Get in governance-vote.cpp * Reject unparsable governance objects * Implemented sentinel watchdog objects (separated out from locking changes) * Added WATCHDOG support to rpcgovernance.cpp * Implemented WATCHDOG_EXPIRED state for masternodes * Added serialization of watchdog timestamps * Masternode fixes - Added version check to CMasternodeMan deserialization - Added several missing locking calls in CMasternodeMan * Fixed missing member initialization in CMasternode constructor and added more logging * Added MASTERNODE_WATCHDOG_MAX_SECONDS to governanceinfo * Added masternodewatchdogmaxseconds info to getgovernanceinfo help * Make masternodes remain in WATCHDOG_EXPIRED state unless removed or collateral expires * Allow watchdog object creation by WATCHDOG_EXPIRED MN * Fixed MN validation logic for governance object creation * Count total masternodes instead of enabled masternodes in masternode-sync * Transition out of WATCHDOG_EXPIRED state if the watchdog is inactive * Fixed IsWatchdogExpired bug * Fixed rate check for watchdog objects and no longer check MN state when validating governance objects * Applied PR #1061 patch * Ported locking changes from other branch * Require only 1 block between new watchdog objects * Accept pings for WATCHDOG_EXPIRED masternodes * Lock CmasternodeMan::cs in CmasternodeMan::ProcessMessage * Several governance changes - Fixed uninitialized value in CGovernancePayment class - Return an error on submission if any superblock payment cannot be parsed - Added logging more statements * Explicitly initialize all governance object members * Fix deadlock * Fixed non-threadsafe access to masternode in activemasternode.cpp * Revert added wallet lock * Changed CActiveMasternode so that watchdog expired nodes can still send pings * Modified CActiveMasternode to run pinger regardless of state when MN is in list * Added voter and time information to getvotes command * Improved CActiveMasternode state management * Implemented GetInfo functions for more efficient thread-safe access to masternode information * Added CActiveMasternode debug logging messages * Fixed initial type setting and error message for incorrect protocol version * Changes based on code review comments * Set active state for local mode
2016-10-17 20:54:28 +02:00
}
void CMasternodeMan::RemoveGovernanceObject(uint256 nGovernanceObjectHash)
{
LOCK(cs);
for(auto& mnpair : mapMasternodes) {
mnpair.second.RemoveGovernanceObject(nGovernanceObjectHash);
V0.12.1.x sentinel watchdog pr (#1079) Squashed: * Replaced unsafe mnodeman.Find function with Get in governance-vote.cpp * Reject unparsable governance objects * Implemented sentinel watchdog objects (separated out from locking changes) * Added WATCHDOG support to rpcgovernance.cpp * Implemented WATCHDOG_EXPIRED state for masternodes * Added serialization of watchdog timestamps * Masternode fixes - Added version check to CMasternodeMan deserialization - Added several missing locking calls in CMasternodeMan * Fixed missing member initialization in CMasternode constructor and added more logging * Added MASTERNODE_WATCHDOG_MAX_SECONDS to governanceinfo * Added masternodewatchdogmaxseconds info to getgovernanceinfo help * Make masternodes remain in WATCHDOG_EXPIRED state unless removed or collateral expires * Allow watchdog object creation by WATCHDOG_EXPIRED MN * Fixed MN validation logic for governance object creation * Count total masternodes instead of enabled masternodes in masternode-sync * Transition out of WATCHDOG_EXPIRED state if the watchdog is inactive * Fixed IsWatchdogExpired bug * Fixed rate check for watchdog objects and no longer check MN state when validating governance objects * Applied PR #1061 patch * Ported locking changes from other branch * Require only 1 block between new watchdog objects * Accept pings for WATCHDOG_EXPIRED masternodes * Lock CmasternodeMan::cs in CmasternodeMan::ProcessMessage * Several governance changes - Fixed uninitialized value in CGovernancePayment class - Return an error on submission if any superblock payment cannot be parsed - Added logging more statements * Explicitly initialize all governance object members * Fix deadlock * Fixed non-threadsafe access to masternode in activemasternode.cpp * Revert added wallet lock * Changed CActiveMasternode so that watchdog expired nodes can still send pings * Modified CActiveMasternode to run pinger regardless of state when MN is in list * Added voter and time information to getvotes command * Improved CActiveMasternode state management * Implemented GetInfo functions for more efficient thread-safe access to masternode information * Added CActiveMasternode debug logging messages * Fixed initial type setting and error message for incorrect protocol version * Changes based on code review comments * Set active state for local mode
2016-10-17 20:54:28 +02:00
}
}
void CMasternodeMan::CheckMasternode(const CPubKey& pubKeyMasternode, bool fForce)
{
LOCK(cs);
for (auto& mnpair : mapMasternodes) {
if (mnpair.second.pubKeyMasternode == pubKeyMasternode) {
mnpair.second.Check(fForce);
return;
}
V0.12.1.x sentinel watchdog pr (#1079) Squashed: * Replaced unsafe mnodeman.Find function with Get in governance-vote.cpp * Reject unparsable governance objects * Implemented sentinel watchdog objects (separated out from locking changes) * Added WATCHDOG support to rpcgovernance.cpp * Implemented WATCHDOG_EXPIRED state for masternodes * Added serialization of watchdog timestamps * Masternode fixes - Added version check to CMasternodeMan deserialization - Added several missing locking calls in CMasternodeMan * Fixed missing member initialization in CMasternode constructor and added more logging * Added MASTERNODE_WATCHDOG_MAX_SECONDS to governanceinfo * Added masternodewatchdogmaxseconds info to getgovernanceinfo help * Make masternodes remain in WATCHDOG_EXPIRED state unless removed or collateral expires * Allow watchdog object creation by WATCHDOG_EXPIRED MN * Fixed MN validation logic for governance object creation * Count total masternodes instead of enabled masternodes in masternode-sync * Transition out of WATCHDOG_EXPIRED state if the watchdog is inactive * Fixed IsWatchdogExpired bug * Fixed rate check for watchdog objects and no longer check MN state when validating governance objects * Applied PR #1061 patch * Ported locking changes from other branch * Require only 1 block between new watchdog objects * Accept pings for WATCHDOG_EXPIRED masternodes * Lock CmasternodeMan::cs in CmasternodeMan::ProcessMessage * Several governance changes - Fixed uninitialized value in CGovernancePayment class - Return an error on submission if any superblock payment cannot be parsed - Added logging more statements * Explicitly initialize all governance object members * Fix deadlock * Fixed non-threadsafe access to masternode in activemasternode.cpp * Revert added wallet lock * Changed CActiveMasternode so that watchdog expired nodes can still send pings * Modified CActiveMasternode to run pinger regardless of state when MN is in list * Added voter and time information to getvotes command * Improved CActiveMasternode state management * Implemented GetInfo functions for more efficient thread-safe access to masternode information * Added CActiveMasternode debug logging messages * Fixed initial type setting and error message for incorrect protocol version * Changes based on code review comments * Set active state for local mode
2016-10-17 20:54:28 +02:00
}
}
bool CMasternodeMan::IsMasternodePingedWithin(const COutPoint& outpoint, int nSeconds, int64_t nTimeToCheckAt)
V0.12.1.x sentinel watchdog pr (#1079) Squashed: * Replaced unsafe mnodeman.Find function with Get in governance-vote.cpp * Reject unparsable governance objects * Implemented sentinel watchdog objects (separated out from locking changes) * Added WATCHDOG support to rpcgovernance.cpp * Implemented WATCHDOG_EXPIRED state for masternodes * Added serialization of watchdog timestamps * Masternode fixes - Added version check to CMasternodeMan deserialization - Added several missing locking calls in CMasternodeMan * Fixed missing member initialization in CMasternode constructor and added more logging * Added MASTERNODE_WATCHDOG_MAX_SECONDS to governanceinfo * Added masternodewatchdogmaxseconds info to getgovernanceinfo help * Make masternodes remain in WATCHDOG_EXPIRED state unless removed or collateral expires * Allow watchdog object creation by WATCHDOG_EXPIRED MN * Fixed MN validation logic for governance object creation * Count total masternodes instead of enabled masternodes in masternode-sync * Transition out of WATCHDOG_EXPIRED state if the watchdog is inactive * Fixed IsWatchdogExpired bug * Fixed rate check for watchdog objects and no longer check MN state when validating governance objects * Applied PR #1061 patch * Ported locking changes from other branch * Require only 1 block between new watchdog objects * Accept pings for WATCHDOG_EXPIRED masternodes * Lock CmasternodeMan::cs in CmasternodeMan::ProcessMessage * Several governance changes - Fixed uninitialized value in CGovernancePayment class - Return an error on submission if any superblock payment cannot be parsed - Added logging more statements * Explicitly initialize all governance object members * Fix deadlock * Fixed non-threadsafe access to masternode in activemasternode.cpp * Revert added wallet lock * Changed CActiveMasternode so that watchdog expired nodes can still send pings * Modified CActiveMasternode to run pinger regardless of state when MN is in list * Added voter and time information to getvotes command * Improved CActiveMasternode state management * Implemented GetInfo functions for more efficient thread-safe access to masternode information * Added CActiveMasternode debug logging messages * Fixed initial type setting and error message for incorrect protocol version * Changes based on code review comments * Set active state for local mode
2016-10-17 20:54:28 +02:00
{
LOCK(cs);
CMasternode* pmn = Find(outpoint);
return pmn ? pmn->IsPingedWithin(nSeconds, nTimeToCheckAt) : false;
V0.12.1.x sentinel watchdog pr (#1079) Squashed: * Replaced unsafe mnodeman.Find function with Get in governance-vote.cpp * Reject unparsable governance objects * Implemented sentinel watchdog objects (separated out from locking changes) * Added WATCHDOG support to rpcgovernance.cpp * Implemented WATCHDOG_EXPIRED state for masternodes * Added serialization of watchdog timestamps * Masternode fixes - Added version check to CMasternodeMan deserialization - Added several missing locking calls in CMasternodeMan * Fixed missing member initialization in CMasternode constructor and added more logging * Added MASTERNODE_WATCHDOG_MAX_SECONDS to governanceinfo * Added masternodewatchdogmaxseconds info to getgovernanceinfo help * Make masternodes remain in WATCHDOG_EXPIRED state unless removed or collateral expires * Allow watchdog object creation by WATCHDOG_EXPIRED MN * Fixed MN validation logic for governance object creation * Count total masternodes instead of enabled masternodes in masternode-sync * Transition out of WATCHDOG_EXPIRED state if the watchdog is inactive * Fixed IsWatchdogExpired bug * Fixed rate check for watchdog objects and no longer check MN state when validating governance objects * Applied PR #1061 patch * Ported locking changes from other branch * Require only 1 block between new watchdog objects * Accept pings for WATCHDOG_EXPIRED masternodes * Lock CmasternodeMan::cs in CmasternodeMan::ProcessMessage * Several governance changes - Fixed uninitialized value in CGovernancePayment class - Return an error on submission if any superblock payment cannot be parsed - Added logging more statements * Explicitly initialize all governance object members * Fix deadlock * Fixed non-threadsafe access to masternode in activemasternode.cpp * Revert added wallet lock * Changed CActiveMasternode so that watchdog expired nodes can still send pings * Modified CActiveMasternode to run pinger regardless of state when MN is in list * Added voter and time information to getvotes command * Improved CActiveMasternode state management * Implemented GetInfo functions for more efficient thread-safe access to masternode information * Added CActiveMasternode debug logging messages * Fixed initial type setting and error message for incorrect protocol version * Changes based on code review comments * Set active state for local mode
2016-10-17 20:54:28 +02:00
}
void CMasternodeMan::SetMasternodeLastPing(const COutPoint& outpoint, const CMasternodePing& mnp)
V0.12.1.x sentinel watchdog pr (#1079) Squashed: * Replaced unsafe mnodeman.Find function with Get in governance-vote.cpp * Reject unparsable governance objects * Implemented sentinel watchdog objects (separated out from locking changes) * Added WATCHDOG support to rpcgovernance.cpp * Implemented WATCHDOG_EXPIRED state for masternodes * Added serialization of watchdog timestamps * Masternode fixes - Added version check to CMasternodeMan deserialization - Added several missing locking calls in CMasternodeMan * Fixed missing member initialization in CMasternode constructor and added more logging * Added MASTERNODE_WATCHDOG_MAX_SECONDS to governanceinfo * Added masternodewatchdogmaxseconds info to getgovernanceinfo help * Make masternodes remain in WATCHDOG_EXPIRED state unless removed or collateral expires * Allow watchdog object creation by WATCHDOG_EXPIRED MN * Fixed MN validation logic for governance object creation * Count total masternodes instead of enabled masternodes in masternode-sync * Transition out of WATCHDOG_EXPIRED state if the watchdog is inactive * Fixed IsWatchdogExpired bug * Fixed rate check for watchdog objects and no longer check MN state when validating governance objects * Applied PR #1061 patch * Ported locking changes from other branch * Require only 1 block between new watchdog objects * Accept pings for WATCHDOG_EXPIRED masternodes * Lock CmasternodeMan::cs in CmasternodeMan::ProcessMessage * Several governance changes - Fixed uninitialized value in CGovernancePayment class - Return an error on submission if any superblock payment cannot be parsed - Added logging more statements * Explicitly initialize all governance object members * Fix deadlock * Fixed non-threadsafe access to masternode in activemasternode.cpp * Revert added wallet lock * Changed CActiveMasternode so that watchdog expired nodes can still send pings * Modified CActiveMasternode to run pinger regardless of state when MN is in list * Added voter and time information to getvotes command * Improved CActiveMasternode state management * Implemented GetInfo functions for more efficient thread-safe access to masternode information * Added CActiveMasternode debug logging messages * Fixed initial type setting and error message for incorrect protocol version * Changes based on code review comments * Set active state for local mode
2016-10-17 20:54:28 +02:00
{
LOCK(cs);
CMasternode* pmn = Find(outpoint);
if(!pmn) {
V0.12.1.x sentinel watchdog pr (#1079) Squashed: * Replaced unsafe mnodeman.Find function with Get in governance-vote.cpp * Reject unparsable governance objects * Implemented sentinel watchdog objects (separated out from locking changes) * Added WATCHDOG support to rpcgovernance.cpp * Implemented WATCHDOG_EXPIRED state for masternodes * Added serialization of watchdog timestamps * Masternode fixes - Added version check to CMasternodeMan deserialization - Added several missing locking calls in CMasternodeMan * Fixed missing member initialization in CMasternode constructor and added more logging * Added MASTERNODE_WATCHDOG_MAX_SECONDS to governanceinfo * Added masternodewatchdogmaxseconds info to getgovernanceinfo help * Make masternodes remain in WATCHDOG_EXPIRED state unless removed or collateral expires * Allow watchdog object creation by WATCHDOG_EXPIRED MN * Fixed MN validation logic for governance object creation * Count total masternodes instead of enabled masternodes in masternode-sync * Transition out of WATCHDOG_EXPIRED state if the watchdog is inactive * Fixed IsWatchdogExpired bug * Fixed rate check for watchdog objects and no longer check MN state when validating governance objects * Applied PR #1061 patch * Ported locking changes from other branch * Require only 1 block between new watchdog objects * Accept pings for WATCHDOG_EXPIRED masternodes * Lock CmasternodeMan::cs in CmasternodeMan::ProcessMessage * Several governance changes - Fixed uninitialized value in CGovernancePayment class - Return an error on submission if any superblock payment cannot be parsed - Added logging more statements * Explicitly initialize all governance object members * Fix deadlock * Fixed non-threadsafe access to masternode in activemasternode.cpp * Revert added wallet lock * Changed CActiveMasternode so that watchdog expired nodes can still send pings * Modified CActiveMasternode to run pinger regardless of state when MN is in list * Added voter and time information to getvotes command * Improved CActiveMasternode state management * Implemented GetInfo functions for more efficient thread-safe access to masternode information * Added CActiveMasternode debug logging messages * Fixed initial type setting and error message for incorrect protocol version * Changes based on code review comments * Set active state for local mode
2016-10-17 20:54:28 +02:00
return;
}
pmn->lastPing = mnp;
// if masternode uses sentinel ping instead of watchdog
// we shoud update nTimeLastWatchdogVote here if sentinel
// ping flag is actual
if(mnp.fSentinelIsCurrent) {
pmn->UpdateWatchdogVoteTime(mnp.sigTime);
}
V0.12.1.x sentinel watchdog pr (#1079) Squashed: * Replaced unsafe mnodeman.Find function with Get in governance-vote.cpp * Reject unparsable governance objects * Implemented sentinel watchdog objects (separated out from locking changes) * Added WATCHDOG support to rpcgovernance.cpp * Implemented WATCHDOG_EXPIRED state for masternodes * Added serialization of watchdog timestamps * Masternode fixes - Added version check to CMasternodeMan deserialization - Added several missing locking calls in CMasternodeMan * Fixed missing member initialization in CMasternode constructor and added more logging * Added MASTERNODE_WATCHDOG_MAX_SECONDS to governanceinfo * Added masternodewatchdogmaxseconds info to getgovernanceinfo help * Make masternodes remain in WATCHDOG_EXPIRED state unless removed or collateral expires * Allow watchdog object creation by WATCHDOG_EXPIRED MN * Fixed MN validation logic for governance object creation * Count total masternodes instead of enabled masternodes in masternode-sync * Transition out of WATCHDOG_EXPIRED state if the watchdog is inactive * Fixed IsWatchdogExpired bug * Fixed rate check for watchdog objects and no longer check MN state when validating governance objects * Applied PR #1061 patch * Ported locking changes from other branch * Require only 1 block between new watchdog objects * Accept pings for WATCHDOG_EXPIRED masternodes * Lock CmasternodeMan::cs in CmasternodeMan::ProcessMessage * Several governance changes - Fixed uninitialized value in CGovernancePayment class - Return an error on submission if any superblock payment cannot be parsed - Added logging more statements * Explicitly initialize all governance object members * Fix deadlock * Fixed non-threadsafe access to masternode in activemasternode.cpp * Revert added wallet lock * Changed CActiveMasternode so that watchdog expired nodes can still send pings * Modified CActiveMasternode to run pinger regardless of state when MN is in list * Added voter and time information to getvotes command * Improved CActiveMasternode state management * Implemented GetInfo functions for more efficient thread-safe access to masternode information * Added CActiveMasternode debug logging messages * Fixed initial type setting and error message for incorrect protocol version * Changes based on code review comments * Set active state for local mode
2016-10-17 20:54:28 +02:00
mapSeenMasternodePing.insert(std::make_pair(mnp.GetHash(), mnp));
CMasternodeBroadcast mnb(*pmn);
V0.12.1.x sentinel watchdog pr (#1079) Squashed: * Replaced unsafe mnodeman.Find function with Get in governance-vote.cpp * Reject unparsable governance objects * Implemented sentinel watchdog objects (separated out from locking changes) * Added WATCHDOG support to rpcgovernance.cpp * Implemented WATCHDOG_EXPIRED state for masternodes * Added serialization of watchdog timestamps * Masternode fixes - Added version check to CMasternodeMan deserialization - Added several missing locking calls in CMasternodeMan * Fixed missing member initialization in CMasternode constructor and added more logging * Added MASTERNODE_WATCHDOG_MAX_SECONDS to governanceinfo * Added masternodewatchdogmaxseconds info to getgovernanceinfo help * Make masternodes remain in WATCHDOG_EXPIRED state unless removed or collateral expires * Allow watchdog object creation by WATCHDOG_EXPIRED MN * Fixed MN validation logic for governance object creation * Count total masternodes instead of enabled masternodes in masternode-sync * Transition out of WATCHDOG_EXPIRED state if the watchdog is inactive * Fixed IsWatchdogExpired bug * Fixed rate check for watchdog objects and no longer check MN state when validating governance objects * Applied PR #1061 patch * Ported locking changes from other branch * Require only 1 block between new watchdog objects * Accept pings for WATCHDOG_EXPIRED masternodes * Lock CmasternodeMan::cs in CmasternodeMan::ProcessMessage * Several governance changes - Fixed uninitialized value in CGovernancePayment class - Return an error on submission if any superblock payment cannot be parsed - Added logging more statements * Explicitly initialize all governance object members * Fix deadlock * Fixed non-threadsafe access to masternode in activemasternode.cpp * Revert added wallet lock * Changed CActiveMasternode so that watchdog expired nodes can still send pings * Modified CActiveMasternode to run pinger regardless of state when MN is in list * Added voter and time information to getvotes command * Improved CActiveMasternode state management * Implemented GetInfo functions for more efficient thread-safe access to masternode information * Added CActiveMasternode debug logging messages * Fixed initial type setting and error message for incorrect protocol version * Changes based on code review comments * Set active state for local mode
2016-10-17 20:54:28 +02:00
uint256 hash = mnb.GetHash();
if(mapSeenMasternodeBroadcast.count(hash)) {
mapSeenMasternodeBroadcast[hash].second.lastPing = mnp;
V0.12.1.x sentinel watchdog pr (#1079) Squashed: * Replaced unsafe mnodeman.Find function with Get in governance-vote.cpp * Reject unparsable governance objects * Implemented sentinel watchdog objects (separated out from locking changes) * Added WATCHDOG support to rpcgovernance.cpp * Implemented WATCHDOG_EXPIRED state for masternodes * Added serialization of watchdog timestamps * Masternode fixes - Added version check to CMasternodeMan deserialization - Added several missing locking calls in CMasternodeMan * Fixed missing member initialization in CMasternode constructor and added more logging * Added MASTERNODE_WATCHDOG_MAX_SECONDS to governanceinfo * Added masternodewatchdogmaxseconds info to getgovernanceinfo help * Make masternodes remain in WATCHDOG_EXPIRED state unless removed or collateral expires * Allow watchdog object creation by WATCHDOG_EXPIRED MN * Fixed MN validation logic for governance object creation * Count total masternodes instead of enabled masternodes in masternode-sync * Transition out of WATCHDOG_EXPIRED state if the watchdog is inactive * Fixed IsWatchdogExpired bug * Fixed rate check for watchdog objects and no longer check MN state when validating governance objects * Applied PR #1061 patch * Ported locking changes from other branch * Require only 1 block between new watchdog objects * Accept pings for WATCHDOG_EXPIRED masternodes * Lock CmasternodeMan::cs in CmasternodeMan::ProcessMessage * Several governance changes - Fixed uninitialized value in CGovernancePayment class - Return an error on submission if any superblock payment cannot be parsed - Added logging more statements * Explicitly initialize all governance object members * Fix deadlock * Fixed non-threadsafe access to masternode in activemasternode.cpp * Revert added wallet lock * Changed CActiveMasternode so that watchdog expired nodes can still send pings * Modified CActiveMasternode to run pinger regardless of state when MN is in list * Added voter and time information to getvotes command * Improved CActiveMasternode state management * Implemented GetInfo functions for more efficient thread-safe access to masternode information * Added CActiveMasternode debug logging messages * Fixed initial type setting and error message for incorrect protocol version * Changes based on code review comments * Set active state for local mode
2016-10-17 20:54:28 +02:00
}
}
2016-10-20 23:11:30 +02:00
void CMasternodeMan::UpdatedBlockTip(const CBlockIndex *pindex)
{
nCachedBlockHeight = pindex->nHeight;
LogPrint("masternode", "CMasternodeMan::UpdatedBlockTip -- nCachedBlockHeight=%d\n", nCachedBlockHeight);
2016-10-20 23:11:30 +02:00
CheckSameAddr();
if(fMasterNode) {
// normal wallet does not need to update this every block, doing update on rpc call should be enough
UpdateLastPaid(pindex);
2016-10-20 23:11:30 +02:00
}
}
void CMasternodeMan::NotifyMasternodeUpdates()
{
// Avoid double locking
bool fMasternodesAddedLocal = false;
bool fMasternodesRemovedLocal = false;
{
LOCK(cs);
fMasternodesAddedLocal = fMasternodesAdded;
fMasternodesRemovedLocal = fMasternodesRemoved;
}
if(fMasternodesAddedLocal) {
governance.CheckMasternodeOrphanObjects();
governance.CheckMasternodeOrphanVotes();
}
if(fMasternodesRemovedLocal) {
governance.UpdateCachesAndClean();
}
LOCK(cs);
fMasternodesAdded = false;
fMasternodesRemoved = false;
}