mirror of
https://github.com/dashpay/dash.git
synced 2024-12-26 12:32:48 +01:00
Drop watchdogs, replace them with sentinel pings (#1949)
* Drop watchdogs, replace them with sentinel pings * Address review comments * revert `()`
This commit is contained in:
parent
ef9a9f2d67
commit
89380b4c92
@ -98,7 +98,7 @@ bool CActiveMasternode::SendMasternodePing(CConnman& connman)
|
||||
CMasternodePing mnp(outpoint);
|
||||
mnp.nSentinelVersion = nSentinelVersion;
|
||||
mnp.fSentinelIsCurrent =
|
||||
(abs(GetAdjustedTime() - nSentinelPingTime) < MASTERNODE_WATCHDOG_MAX_SECONDS);
|
||||
(abs(GetAdjustedTime() - nSentinelPingTime) < MASTERNODE_SENTINEL_PING_MAX_SECONDS);
|
||||
if(!mnp.Sign(keyMasternode, pubKeyMasternode)) {
|
||||
LogPrintf("CActiveMasternode::SendMasternodePing -- ERROR: Couldn't sign Masternode Ping\n");
|
||||
return false;
|
||||
|
@ -447,9 +447,11 @@ bool CGovernanceObject::IsValidLocally(std::string& strError, bool& fMissingMast
|
||||
}
|
||||
|
||||
switch(nObjectType) {
|
||||
case GOVERNANCE_OBJECT_WATCHDOG:
|
||||
// watchdogs are deprecated
|
||||
return false;
|
||||
case GOVERNANCE_OBJECT_PROPOSAL:
|
||||
case GOVERNANCE_OBJECT_TRIGGER:
|
||||
case GOVERNANCE_OBJECT_WATCHDOG:
|
||||
if (vchData.size() > MAX_GOVERNANCE_OBJECT_DATA_SIZE) {
|
||||
strError = strprintf("Invalid object size %d", vchData.size());
|
||||
return false;
|
||||
@ -465,7 +467,7 @@ bool CGovernanceObject::IsValidLocally(std::string& strError, bool& fMissingMast
|
||||
// CHECK COLLATERAL IF REQUIRED (HIGH CPU USAGE)
|
||||
|
||||
if(fCheckCollateral) {
|
||||
if((nObjectType == GOVERNANCE_OBJECT_TRIGGER) || (nObjectType == GOVERNANCE_OBJECT_WATCHDOG)) {
|
||||
if(nObjectType == GOVERNANCE_OBJECT_TRIGGER) {
|
||||
std::string strOutpoint = masternodeOutpoint.ToStringShort();
|
||||
masternode_info_t infoMn;
|
||||
if(!mnodeman.GetMasternodeInfo(masternodeOutpoint, infoMn)) {
|
||||
|
@ -42,7 +42,6 @@ static const int64_t GOVERNANCE_MIN_RELAY_FEE_CONFIRMATIONS = 1;
|
||||
static const int64_t GOVERNANCE_UPDATE_MIN = 60*60;
|
||||
static const int64_t GOVERNANCE_DELETION_DELAY = 10*60;
|
||||
static const int64_t GOVERNANCE_ORPHAN_EXPIRATION_TIME = 10*60;
|
||||
static const int64_t GOVERNANCE_WATCHDOG_EXPIRATION_TIME = 2*60*60;
|
||||
|
||||
// FOR SEEN MAP ARRAYS - GOVERNANCE OBJECTS AND VOTES
|
||||
static const int SEEN_OBJECT_IS_VALID = 0;
|
||||
|
@ -29,9 +29,6 @@ CGovernanceManager::CGovernanceManager()
|
||||
mapObjects(),
|
||||
mapErasedGovernanceObjects(),
|
||||
mapMasternodeOrphanObjects(),
|
||||
mapWatchdogObjects(),
|
||||
nHashWatchdogCurrent(),
|
||||
nTimeWatchdogCurrent(0),
|
||||
cmapVoteToObject(MAX_CACHE_SIZE),
|
||||
cmapInvalidVotes(MAX_CACHE_SIZE),
|
||||
cmmapOrphanVotes(MAX_CACHE_SIZE),
|
||||
@ -321,26 +318,6 @@ void CGovernanceManager::AddGovernanceObject(CGovernanceObject& govobj, CConnman
|
||||
|
||||
LogPrint("gobject", "CGovernanceManager::AddGovernanceObject -- Adding object: hash = %s, type = %d\n", nHash.ToString(), govobj.GetObjectType());
|
||||
|
||||
if(govobj.nObjectType == GOVERNANCE_OBJECT_WATCHDOG) {
|
||||
// If it's a watchdog, make sure it fits required time bounds
|
||||
if((govobj.GetCreationTime() < GetAdjustedTime() - GOVERNANCE_WATCHDOG_EXPIRATION_TIME ||
|
||||
govobj.GetCreationTime() > GetAdjustedTime() + GOVERNANCE_WATCHDOG_EXPIRATION_TIME)
|
||||
) {
|
||||
// drop it
|
||||
LogPrint("gobject", "CGovernanceManager::AddGovernanceObject -- CreationTime is out of bounds: hash = %s\n", nHash.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
if(!UpdateCurrentWatchdog(govobj)) {
|
||||
// Allow wd's which are not current to be reprocessed
|
||||
if(pfrom && (nHashWatchdogCurrent != uint256())) {
|
||||
pfrom->PushInventory(CInv(MSG_GOVERNANCE_OBJECT, nHashWatchdogCurrent));
|
||||
}
|
||||
LogPrint("gobject", "CGovernanceManager::AddGovernanceObject -- Watchdog not better than current: hash = %s\n", nHash.ToString());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// INSERT INTO OUR GOVERNANCE OBJECT MEMORY
|
||||
mapObjects.insert(std::make_pair(nHash, govobj));
|
||||
|
||||
@ -351,18 +328,10 @@ void CGovernanceManager::AddGovernanceObject(CGovernanceObject& govobj, CConnman
|
||||
<< ", nObjectType = " << govobj.nObjectType
|
||||
<< std::endl; );
|
||||
|
||||
switch(govobj.nObjectType) {
|
||||
case GOVERNANCE_OBJECT_TRIGGER:
|
||||
if (govobj.nObjectType == GOVERNANCE_OBJECT_TRIGGER) {
|
||||
DBG( std::cout << "CGovernanceManager::AddGovernanceObject Before AddNewTrigger" << std::endl; );
|
||||
triggerman.AddNewTrigger(nHash);
|
||||
DBG( std::cout << "CGovernanceManager::AddGovernanceObject After AddNewTrigger" << std::endl; );
|
||||
break;
|
||||
case GOVERNANCE_OBJECT_WATCHDOG:
|
||||
mapWatchdogObjects[nHash] = govobj.GetCreationTime() + GOVERNANCE_WATCHDOG_EXPIRATION_TIME;
|
||||
LogPrint("gobject", "CGovernanceManager::AddGovernanceObject -- Added watchdog to map: hash = %s\n", nHash.ToString());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
LogPrintf("AddGovernanceObject -- %s new, received form %s\n", strHash, pfrom? pfrom->GetAddrName() : "NULL");
|
||||
@ -381,40 +350,6 @@ void CGovernanceManager::AddGovernanceObject(CGovernanceObject& govobj, CConnman
|
||||
DBG( std::cout << "CGovernanceManager::AddGovernanceObject END" << std::endl; );
|
||||
}
|
||||
|
||||
bool CGovernanceManager::UpdateCurrentWatchdog(CGovernanceObject& watchdogNew)
|
||||
{
|
||||
bool fAccept = false;
|
||||
|
||||
arith_uint256 nHashNew = UintToArith256(watchdogNew.GetHash());
|
||||
arith_uint256 nHashCurrent = UintToArith256(nHashWatchdogCurrent);
|
||||
|
||||
int64_t nExpirationDelay = GOVERNANCE_WATCHDOG_EXPIRATION_TIME / 2;
|
||||
int64_t nNow = GetAdjustedTime();
|
||||
|
||||
if(nHashWatchdogCurrent == uint256() || // no known current OR
|
||||
((nNow - watchdogNew.GetCreationTime() < nExpirationDelay) && // (new one is NOT expired AND
|
||||
((nNow - nTimeWatchdogCurrent > nExpirationDelay) || (nHashNew > nHashCurrent)))// (current is expired OR
|
||||
// its hash is lower))
|
||||
) {
|
||||
LOCK(cs);
|
||||
object_m_it it = mapObjects.find(nHashWatchdogCurrent);
|
||||
if(it != mapObjects.end()) {
|
||||
LogPrint("gobject", "CGovernanceManager::UpdateCurrentWatchdog -- Expiring previous current watchdog, hash = %s\n", nHashWatchdogCurrent.ToString());
|
||||
it->second.fExpired = true;
|
||||
if(it->second.nDeletionTime == 0) {
|
||||
it->second.nDeletionTime = nNow;
|
||||
}
|
||||
}
|
||||
nHashWatchdogCurrent = watchdogNew.GetHash();
|
||||
nTimeWatchdogCurrent = watchdogNew.GetCreationTime();
|
||||
fAccept = true;
|
||||
LogPrint("gobject", "CGovernanceManager::UpdateCurrentWatchdog -- Current watchdog updated to: hash = %s\n",
|
||||
ArithToUint256(nHashNew).ToString());
|
||||
}
|
||||
|
||||
return fAccept;
|
||||
}
|
||||
|
||||
void CGovernanceManager::UpdateCachesAndClean()
|
||||
{
|
||||
LogPrint("gobject", "CGovernanceManager::UpdateCachesAndClean\n");
|
||||
@ -423,34 +358,6 @@ void CGovernanceManager::UpdateCachesAndClean()
|
||||
|
||||
LOCK2(cs_main, cs);
|
||||
|
||||
// Flag expired watchdogs for removal
|
||||
int64_t nNow = GetAdjustedTime();
|
||||
LogPrint("gobject", "CGovernanceManager::UpdateCachesAndClean -- Number watchdogs in map: %d, current time = %d\n", mapWatchdogObjects.size(), nNow);
|
||||
if(mapWatchdogObjects.size() > 1) {
|
||||
hash_time_m_it it = mapWatchdogObjects.begin();
|
||||
while(it != mapWatchdogObjects.end()) {
|
||||
LogPrint("gobject", "CGovernanceManager::UpdateCachesAndClean -- Checking watchdog: %s, expiration time = %d\n", it->first.ToString(), it->second);
|
||||
if(it->second < nNow) {
|
||||
LogPrint("gobject", "CGovernanceManager::UpdateCachesAndClean -- Attempting to expire watchdog: %s, expiration time = %d\n", it->first.ToString(), it->second);
|
||||
object_m_it it2 = mapObjects.find(it->first);
|
||||
if(it2 != mapObjects.end()) {
|
||||
LogPrint("gobject", "CGovernanceManager::UpdateCachesAndClean -- Expiring watchdog: %s, expiration time = %d\n", it->first.ToString(), it->second);
|
||||
it2->second.fExpired = true;
|
||||
if(it2->second.nDeletionTime == 0) {
|
||||
it2->second.nDeletionTime = nNow;
|
||||
}
|
||||
}
|
||||
if(it->first == nHashWatchdogCurrent) {
|
||||
nHashWatchdogCurrent = uint256();
|
||||
}
|
||||
mapWatchdogObjects.erase(it++);
|
||||
}
|
||||
else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < vecDirtyHashes.size(); ++i) {
|
||||
object_m_it it = mapObjects.find(vecDirtyHashes[i]);
|
||||
if(it == mapObjects.end()) {
|
||||
@ -469,6 +376,8 @@ void CGovernanceManager::UpdateCachesAndClean()
|
||||
// Clean up any expired or invalid triggers
|
||||
triggerman.CleanAndRemove();
|
||||
|
||||
int64_t nNow = GetAdjustedTime();
|
||||
|
||||
while(it != mapObjects.end())
|
||||
{
|
||||
CGovernanceObject* pObj = &((*it).second);
|
||||
@ -490,13 +399,9 @@ void CGovernanceManager::UpdateCachesAndClean()
|
||||
pObj->UpdateSentinelVariables();
|
||||
}
|
||||
|
||||
if(pObj->IsSetCachedDelete() && (nHash == nHashWatchdogCurrent)) {
|
||||
nHashWatchdogCurrent = uint256();
|
||||
}
|
||||
|
||||
// IF DELETE=TRUE, THEN CLEAN THE MESS UP!
|
||||
|
||||
int64_t nTimeSinceDeletion = GetAdjustedTime() - pObj->GetDeletionTime();
|
||||
int64_t nTimeSinceDeletion = nNow - pObj->GetDeletionTime();
|
||||
|
||||
LogPrint("gobject", "CGovernanceManager::UpdateCachesAndClean -- Checking object for deletion: %s, deletion time = %d, time since deletion = %d, delete flag = %d, expired flag = %d\n",
|
||||
strHash, pObj->GetDeletionTime(), nTimeSinceDeletion, pObj->IsSetCachedDelete(), pObj->IsSetExpired());
|
||||
@ -520,14 +425,14 @@ void CGovernanceManager::UpdateCachesAndClean()
|
||||
}
|
||||
}
|
||||
|
||||
int64_t nSuperblockCycleSeconds = Params().GetConsensus().nSuperblockCycle * Params().GetConsensus().nPowTargetSpacing;
|
||||
int64_t nTimeExpired = pObj->GetCreationTime() + 2 * nSuperblockCycleSeconds + GOVERNANCE_DELETION_DELAY;
|
||||
int64_t nTimeExpired{0};
|
||||
|
||||
if(pObj->GetObjectType() == GOVERNANCE_OBJECT_WATCHDOG) {
|
||||
mapWatchdogObjects.erase(nHash);
|
||||
} else if(pObj->GetObjectType() != GOVERNANCE_OBJECT_TRIGGER) {
|
||||
if(pObj->GetObjectType() == GOVERNANCE_OBJECT_PROPOSAL) {
|
||||
// keep hashes of deleted proposals forever
|
||||
nTimeExpired = std::numeric_limits<int64_t>::max();
|
||||
} else {
|
||||
int64_t nSuperblockCycleSeconds = Params().GetConsensus().nSuperblockCycle * Params().GetConsensus().nPowTargetSpacing;
|
||||
nTimeExpired = pObj->GetCreationTime() + 2 * nSuperblockCycleSeconds + GOVERNANCE_DELETION_DELAY;
|
||||
}
|
||||
|
||||
mapErasedGovernanceObjects.insert(std::make_pair(nHash, nTimeExpired));
|
||||
@ -824,8 +729,7 @@ void CGovernanceManager::SyncAll(CNode* pnode, CConnman& connman)
|
||||
|
||||
void CGovernanceManager::MasternodeRateUpdate(const CGovernanceObject& govobj)
|
||||
{
|
||||
int nObjectType = govobj.GetObjectType();
|
||||
if((nObjectType != GOVERNANCE_OBJECT_TRIGGER) && (nObjectType != GOVERNANCE_OBJECT_WATCHDOG))
|
||||
if(govobj.GetObjectType() != GOVERNANCE_OBJECT_TRIGGER)
|
||||
return;
|
||||
|
||||
const COutPoint& masternodeOutpoint = govobj.GetMasternodeOutpoint();
|
||||
@ -835,10 +739,7 @@ void CGovernanceManager::MasternodeRateUpdate(const CGovernanceObject& govobj)
|
||||
it = mapLastMasternodeObject.insert(txout_m_t::value_type(masternodeOutpoint, last_object_rec(true))).first;
|
||||
|
||||
int64_t nTimestamp = govobj.GetCreationTime();
|
||||
if (GOVERNANCE_OBJECT_TRIGGER == nObjectType)
|
||||
it->second.triggerBuffer.AddTimestamp(nTimestamp);
|
||||
else if (GOVERNANCE_OBJECT_WATCHDOG == nObjectType)
|
||||
it->second.watchdogBuffer.AddTimestamp(nTimestamp);
|
||||
it->second.triggerBuffer.AddTimestamp(nTimestamp);
|
||||
|
||||
if (nTimestamp > GetTime() + MAX_TIME_FUTURE_DEVIATION - RELIABLE_PROPAGATION_TIME) {
|
||||
// schedule additional relay for the object
|
||||
@ -868,8 +769,7 @@ bool CGovernanceManager::MasternodeRateCheck(const CGovernanceObject& govobj, bo
|
||||
return true;
|
||||
}
|
||||
|
||||
int nObjectType = govobj.GetObjectType();
|
||||
if((nObjectType != GOVERNANCE_OBJECT_TRIGGER) && (nObjectType != GOVERNANCE_OBJECT_WATCHDOG)) {
|
||||
if(govobj.GetObjectType() != GOVERNANCE_OBJECT_TRIGGER) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -901,38 +801,26 @@ bool CGovernanceManager::MasternodeRateCheck(const CGovernanceObject& govobj, bo
|
||||
return true;
|
||||
}
|
||||
|
||||
double dMaxRate = 1.1 / nSuperblockCycleSeconds;
|
||||
double dRate = 0.0;
|
||||
CRateCheckBuffer buffer;
|
||||
switch(nObjectType) {
|
||||
case GOVERNANCE_OBJECT_TRIGGER:
|
||||
// Allow 1 trigger per mn per cycle, with a small fudge factor
|
||||
buffer = it->second.triggerBuffer;
|
||||
dMaxRate = 2 * 1.1 / double(nSuperblockCycleSeconds);
|
||||
break;
|
||||
case GOVERNANCE_OBJECT_WATCHDOG:
|
||||
buffer = it->second.watchdogBuffer;
|
||||
dMaxRate = 2 * 1.1 / 3600.;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
// Allow 1 trigger per mn per cycle, with a small fudge factor
|
||||
double dMaxRate = 2 * 1.1 / double(nSuperblockCycleSeconds);
|
||||
|
||||
// Temporary copy to check rate after new timestamp is added
|
||||
CRateCheckBuffer buffer = it->second.triggerBuffer;
|
||||
|
||||
buffer.AddTimestamp(nTimestamp);
|
||||
dRate = buffer.GetRate();
|
||||
double dRate = buffer.GetRate();
|
||||
|
||||
bool fRateOK = ( dRate < dMaxRate );
|
||||
|
||||
if(!fRateOK)
|
||||
{
|
||||
LogPrintf("CGovernanceManager::MasternodeRateCheck -- Rate too high: object hash = %s, masternode = %s, object timestamp = %d, rate = %f, max rate = %f\n",
|
||||
strHash, masternodeOutpoint.ToStringShort(), nTimestamp, dRate, dMaxRate);
|
||||
|
||||
if (fUpdateFailStatus)
|
||||
it->second.fStatusOK = false;
|
||||
if(dRate < dMaxRate) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return fRateOK;
|
||||
LogPrintf("CGovernanceManager::MasternodeRateCheck -- Rate too high: object hash = %s, masternode = %s, object timestamp = %d, rate = %f, max rate = %f\n",
|
||||
strHash, masternodeOutpoint.ToStringShort(), nTimestamp, dRate, dMaxRate);
|
||||
|
||||
if (fUpdateFailStatus)
|
||||
it->second.fStatusOK = false;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CGovernanceManager::ProcessVote(CNode* pfrom, const CGovernanceVote& vote, CGovernanceException& exception, CConnman& connman)
|
||||
@ -985,10 +873,6 @@ bool CGovernanceManager::ProcessVote(CNode* pfrom, const CGovernanceVote& vote,
|
||||
}
|
||||
|
||||
bool fOk = govobj.ProcessVote(pfrom, vote, exception, connman) && cmapVoteToObject.Insert(nHashVote, &govobj);
|
||||
if(fOk && govobj.GetObjectType() == GOVERNANCE_OBJECT_WATCHDOG) {
|
||||
mnodeman.UpdateWatchdogVoteTime(vote.GetMasternodeOutpoint());
|
||||
LogPrint("gobject", "CGovernanceObject::ProcessVote -- GOVERNANCE_OBJECT_WATCHDOG vote %s for %s\n", nHashVote.ToString(), nHashGovobj.ToString());
|
||||
}
|
||||
LEAVE_CRITICAL_SECTION(cs);
|
||||
return fOk;
|
||||
}
|
||||
@ -1051,8 +935,7 @@ void CGovernanceManager::CheckPostponedObjects(CConnman& connman)
|
||||
const uint256& nHash = it->first;
|
||||
CGovernanceObject& govobj = it->second;
|
||||
|
||||
assert(govobj.GetObjectType() != GOVERNANCE_OBJECT_WATCHDOG &&
|
||||
govobj.GetObjectType() != GOVERNANCE_OBJECT_TRIGGER);
|
||||
assert(govobj.GetObjectType() != GOVERNANCE_OBJECT_TRIGGER);
|
||||
|
||||
std::string strError;
|
||||
bool fMissingConfirmations;
|
||||
@ -1074,7 +957,7 @@ void CGovernanceManager::CheckPostponedObjects(CConnman& connman)
|
||||
}
|
||||
|
||||
|
||||
// Perform additional relays for triggers/watchdogs
|
||||
// Perform additional relays for triggers
|
||||
int64_t nNow = GetAdjustedTime();
|
||||
int64_t nSuperblockCycleSeconds = Params().GetConsensus().nSuperblockCycle * Params().GetConsensus().nPowTargetSpacing;
|
||||
|
||||
@ -1323,7 +1206,6 @@ std::string CGovernanceManager::ToString() const
|
||||
|
||||
int nProposalCount = 0;
|
||||
int nTriggerCount = 0;
|
||||
int nWatchdogCount = 0;
|
||||
int nOtherCount = 0;
|
||||
|
||||
object_m_cit it = mapObjects.begin();
|
||||
@ -1336,9 +1218,6 @@ std::string CGovernanceManager::ToString() const
|
||||
case GOVERNANCE_OBJECT_TRIGGER:
|
||||
nTriggerCount++;
|
||||
break;
|
||||
case GOVERNANCE_OBJECT_WATCHDOG:
|
||||
nWatchdogCount++;
|
||||
break;
|
||||
default:
|
||||
nOtherCount++;
|
||||
break;
|
||||
@ -1346,9 +1225,9 @@ std::string CGovernanceManager::ToString() const
|
||||
++it;
|
||||
}
|
||||
|
||||
return strprintf("Governance Objects: %d (Proposals: %d, Triggers: %d, Watchdogs: %d/%d, Other: %d; Erased: %d), Votes: %d",
|
||||
return strprintf("Governance Objects: %d (Proposals: %d, Triggers: %d, Other: %d; Erased: %d), Votes: %d",
|
||||
(int)mapObjects.size(),
|
||||
nProposalCount, nTriggerCount, nWatchdogCount, mapWatchdogObjects.size(), nOtherCount, (int)mapErasedGovernanceObjects.size(),
|
||||
nProposalCount, nTriggerCount, nOtherCount, (int)mapErasedGovernanceObjects.size(),
|
||||
(int)cmapVoteToObject.GetSize());
|
||||
}
|
||||
|
||||
|
@ -152,7 +152,6 @@ public: // Types
|
||||
struct last_object_rec {
|
||||
last_object_rec(bool fStatusOKIn = true)
|
||||
: triggerBuffer(),
|
||||
watchdogBuffer(),
|
||||
fStatusOK(fStatusOKIn)
|
||||
{}
|
||||
|
||||
@ -162,12 +161,10 @@ public: // Types
|
||||
inline void SerializationOp(Stream& s, Operation ser_action)
|
||||
{
|
||||
READWRITE(triggerBuffer);
|
||||
READWRITE(watchdogBuffer);
|
||||
READWRITE(fStatusOK);
|
||||
}
|
||||
|
||||
CRateCheckBuffer triggerBuffer;
|
||||
CRateCheckBuffer watchdogBuffer;
|
||||
bool fStatusOK;
|
||||
};
|
||||
|
||||
@ -245,12 +242,6 @@ private:
|
||||
object_m_t mapPostponedObjects;
|
||||
hash_s_t setAdditionalRelayObjects;
|
||||
|
||||
hash_time_m_t mapWatchdogObjects;
|
||||
|
||||
uint256 nHashWatchdogCurrent;
|
||||
|
||||
int64_t nTimeWatchdogCurrent;
|
||||
|
||||
object_ref_cm_t cmapVoteToObject;
|
||||
|
||||
vote_cm_t cmapInvalidVotes;
|
||||
@ -328,9 +319,6 @@ public:
|
||||
LogPrint("gobject", "Governance object manager was cleared\n");
|
||||
mapObjects.clear();
|
||||
mapErasedGovernanceObjects.clear();
|
||||
mapWatchdogObjects.clear();
|
||||
nHashWatchdogCurrent = uint256();
|
||||
nTimeWatchdogCurrent = 0;
|
||||
cmapVoteToObject.Clear();
|
||||
cmapInvalidVotes.Clear();
|
||||
cmmapOrphanVotes.Clear();
|
||||
@ -357,9 +345,6 @@ public:
|
||||
READWRITE(cmapInvalidVotes);
|
||||
READWRITE(cmmapOrphanVotes);
|
||||
READWRITE(mapObjects);
|
||||
READWRITE(mapWatchdogObjects);
|
||||
READWRITE(nHashWatchdogCurrent);
|
||||
READWRITE(nTimeWatchdogCurrent);
|
||||
READWRITE(mapLastMasternodeObject);
|
||||
if(ser_action.ForRead() && (strVersion != SERIALIZATION_VERSION_STRING)) {
|
||||
Clear();
|
||||
@ -453,8 +438,6 @@ private:
|
||||
|
||||
void AddCachedTriggers();
|
||||
|
||||
bool UpdateCurrentWatchdog(CGovernanceObject& watchdogNew);
|
||||
|
||||
void RequestOrphanObjects(CConnman& connman);
|
||||
|
||||
void CleanOrphanObjects();
|
||||
|
@ -46,8 +46,7 @@ CMasternode::CMasternode(const CMasternode& other) :
|
||||
|
||||
CMasternode::CMasternode(const CMasternodeBroadcast& mnb) :
|
||||
masternode_info_t{ mnb.nActiveState, mnb.nProtocolVersion, mnb.sigTime,
|
||||
mnb.outpoint, mnb.addr, mnb.pubKeyCollateralAddress, mnb.pubKeyMasternode,
|
||||
mnb.sigTime /*nTimeLastWatchdogVote*/},
|
||||
mnb.outpoint, mnb.addr, mnb.pubKeyCollateralAddress, mnb.pubKeyMasternode},
|
||||
lastPing(mnb.lastPing),
|
||||
vchSig(mnb.vchSig),
|
||||
fAllowMixingTx(true)
|
||||
@ -194,7 +193,7 @@ void CMasternode::Check(bool fForce)
|
||||
|
||||
if(fWaitForPing && !fOurMasternode) {
|
||||
// ...but if it was already expired before the initial check - return right away
|
||||
if(IsExpired() || IsWatchdogExpired() || IsNewStartRequired()) {
|
||||
if(IsExpired() || IsSentinelPingExpired() || IsNewStartRequired()) {
|
||||
LogPrint("masternode", "CMasternode::Check -- Masternode %s is in %s state, waiting for ping\n", outpoint.ToStringShort(), GetStateString());
|
||||
return;
|
||||
}
|
||||
@ -211,14 +210,14 @@ void CMasternode::Check(bool fForce)
|
||||
return;
|
||||
}
|
||||
|
||||
bool fWatchdogActive = masternodeSync.IsSynced() && mnodeman.IsWatchdogActive();
|
||||
bool fWatchdogExpired = (fWatchdogActive && ((GetAdjustedTime() - nTimeLastWatchdogVote) > MASTERNODE_WATCHDOG_MAX_SECONDS));
|
||||
bool fSentinelPingActive = masternodeSync.IsSynced() && mnodeman.IsSentinelPingActive();
|
||||
bool fSentinelPingExpired = fSentinelPingActive && (!lastPing.fSentinelIsCurrent || !IsPingedWithin(MASTERNODE_SENTINEL_PING_MAX_SECONDS));
|
||||
|
||||
LogPrint("masternode", "CMasternode::Check -- outpoint=%s, nTimeLastWatchdogVote=%d, GetAdjustedTime()=%d, fWatchdogExpired=%d\n",
|
||||
outpoint.ToStringShort(), nTimeLastWatchdogVote, GetAdjustedTime(), fWatchdogExpired);
|
||||
LogPrint("masternode", "CMasternode::Check -- outpoint=%s, GetAdjustedTime()=%d, fSentinelPingExpired=%d\n",
|
||||
outpoint.ToStringShort(), GetAdjustedTime(), fSentinelPingExpired);
|
||||
|
||||
if(fWatchdogExpired) {
|
||||
nActiveState = MASTERNODE_WATCHDOG_EXPIRED;
|
||||
if(fSentinelPingExpired) {
|
||||
nActiveState = MASTERNODE_SENTINEL_PING_EXPIRED;
|
||||
if(nActiveStatePrev != nActiveState) {
|
||||
LogPrint("masternode", "CMasternode::Check -- Masternode %s is in %s state now\n", outpoint.ToStringShort(), GetStateString());
|
||||
}
|
||||
@ -281,7 +280,7 @@ std::string CMasternode::StateToString(int nStateIn)
|
||||
case MASTERNODE_EXPIRED: return "EXPIRED";
|
||||
case MASTERNODE_OUTPOINT_SPENT: return "OUTPOINT_SPENT";
|
||||
case MASTERNODE_UPDATE_REQUIRED: return "UPDATE_REQUIRED";
|
||||
case MASTERNODE_WATCHDOG_EXPIRED: return "WATCHDOG_EXPIRED";
|
||||
case MASTERNODE_SENTINEL_PING_EXPIRED: return "SENTINEL_PING_EXPIRED";
|
||||
case MASTERNODE_NEW_START_REQUIRED: return "NEW_START_REQUIRED";
|
||||
case MASTERNODE_POSE_BAN: return "POSE_BAN";
|
||||
default: return "UNKNOWN";
|
||||
@ -890,8 +889,8 @@ bool CMasternodePing::CheckAndUpdate(CMasternode* pmn, bool fFromNewBroadcast, i
|
||||
|
||||
// force update, ignoring cache
|
||||
pmn->Check(true);
|
||||
// relay ping for nodes in ENABLED/EXPIRED/WATCHDOG_EXPIRED state only, skip everyone else
|
||||
if (!pmn->IsEnabled() && !pmn->IsExpired() && !pmn->IsWatchdogExpired()) return false;
|
||||
// relay ping for nodes in ENABLED/EXPIRED/SENTINEL_PING_EXPIRED state only, skip everyone else
|
||||
if (!pmn->IsEnabled() && !pmn->IsExpired() && !pmn->IsSentinelPingExpired()) return false;
|
||||
|
||||
LogPrint("masternode", "CMasternodePing::CheckAndUpdate -- Masternode ping acceepted and relayed, masternode=%s\n", masternodeOutpoint.ToStringShort());
|
||||
Relay(connman);
|
||||
@ -929,12 +928,6 @@ void CMasternode::RemoveGovernanceObject(uint256 nGovernanceObjectHash)
|
||||
mapGovernanceObjectsVotedOn.erase(it);
|
||||
}
|
||||
|
||||
void CMasternode::UpdateWatchdogVoteTime(uint64_t nVoteTime)
|
||||
{
|
||||
LOCK(cs);
|
||||
nTimeLastWatchdogVote = (nVoteTime == 0) ? GetAdjustedTime() : nVoteTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* FLAG GOVERNANCE ITEMS AS DIRTY
|
||||
*
|
||||
|
@ -17,7 +17,7 @@ static const int MASTERNODE_CHECK_SECONDS = 5;
|
||||
static const int MASTERNODE_MIN_MNB_SECONDS = 5 * 60;
|
||||
static const int MASTERNODE_MIN_MNP_SECONDS = 10 * 60;
|
||||
static const int MASTERNODE_EXPIRATION_SECONDS = 65 * 60;
|
||||
static const int MASTERNODE_WATCHDOG_MAX_SECONDS = 120 * 60;
|
||||
static const int MASTERNODE_SENTINEL_PING_MAX_SECONDS = 120 * 60;
|
||||
static const int MASTERNODE_NEW_START_REQUIRED_SECONDS = 180 * 60;
|
||||
|
||||
static const int MASTERNODE_POSE_BAN_MAX_SCORE = 5;
|
||||
@ -129,12 +129,10 @@ struct masternode_info_t
|
||||
|
||||
masternode_info_t(int activeState, int protoVer, int64_t sTime,
|
||||
COutPoint const& outpnt, CService const& addr,
|
||||
CPubKey const& pkCollAddr, CPubKey const& pkMN,
|
||||
int64_t tWatchdogV = 0) :
|
||||
CPubKey const& pkCollAddr, CPubKey const& pkMN) :
|
||||
nActiveState{activeState}, nProtocolVersion{protoVer}, sigTime{sTime},
|
||||
outpoint{outpnt}, addr{addr},
|
||||
pubKeyCollateralAddress{pkCollAddr}, pubKeyMasternode{pkMN},
|
||||
nTimeLastWatchdogVote{tWatchdogV} {}
|
||||
pubKeyCollateralAddress{pkCollAddr}, pubKeyMasternode{pkMN} {}
|
||||
|
||||
int nActiveState = 0;
|
||||
int nProtocolVersion = 0;
|
||||
@ -144,7 +142,6 @@ struct masternode_info_t
|
||||
CService addr{};
|
||||
CPubKey pubKeyCollateralAddress{};
|
||||
CPubKey pubKeyMasternode{};
|
||||
int64_t nTimeLastWatchdogVote = 0;
|
||||
|
||||
int64_t nLastDsq = 0; //the dsq count from the last dsq broadcast of this node
|
||||
int64_t nTimeLastChecked = 0;
|
||||
@ -170,7 +167,7 @@ public:
|
||||
MASTERNODE_EXPIRED,
|
||||
MASTERNODE_OUTPOINT_SPENT,
|
||||
MASTERNODE_UPDATE_REQUIRED,
|
||||
MASTERNODE_WATCHDOG_EXPIRED,
|
||||
MASTERNODE_SENTINEL_PING_EXPIRED,
|
||||
MASTERNODE_NEW_START_REQUIRED,
|
||||
MASTERNODE_POSE_BAN
|
||||
};
|
||||
@ -230,7 +227,6 @@ public:
|
||||
READWRITE(nLastDsq);
|
||||
READWRITE(nTimeLastChecked);
|
||||
READWRITE(nTimeLastPaid);
|
||||
READWRITE(nTimeLastWatchdogVote);
|
||||
READWRITE(nActiveState);
|
||||
READWRITE(nCollateralMinConfBlockHash);
|
||||
READWRITE(nBlockLastPaid);
|
||||
@ -271,7 +267,7 @@ public:
|
||||
bool IsExpired() const { return nActiveState == MASTERNODE_EXPIRED; }
|
||||
bool IsOutpointSpent() const { return nActiveState == MASTERNODE_OUTPOINT_SPENT; }
|
||||
bool IsUpdateRequired() const { return nActiveState == MASTERNODE_UPDATE_REQUIRED; }
|
||||
bool IsWatchdogExpired() const { return nActiveState == MASTERNODE_WATCHDOG_EXPIRED; }
|
||||
bool IsSentinelPingExpired() const { return nActiveState == MASTERNODE_SENTINEL_PING_EXPIRED; }
|
||||
bool IsNewStartRequired() const { return nActiveState == MASTERNODE_NEW_START_REQUIRED; }
|
||||
|
||||
static bool IsValidStateForAutoStart(int nActiveStateIn)
|
||||
@ -279,7 +275,7 @@ public:
|
||||
return nActiveStateIn == MASTERNODE_ENABLED ||
|
||||
nActiveStateIn == MASTERNODE_PRE_ENABLED ||
|
||||
nActiveStateIn == MASTERNODE_EXPIRED ||
|
||||
nActiveStateIn == MASTERNODE_WATCHDOG_EXPIRED;
|
||||
nActiveStateIn == MASTERNODE_SENTINEL_PING_EXPIRED;
|
||||
}
|
||||
|
||||
bool IsValidForPayment() const
|
||||
@ -288,7 +284,7 @@ public:
|
||||
return true;
|
||||
}
|
||||
if(!sporkManager.IsSporkActive(SPORK_14_REQUIRE_SENTINEL_FLAG) &&
|
||||
(nActiveState == MASTERNODE_WATCHDOG_EXPIRED)) {
|
||||
(nActiveState == MASTERNODE_SENTINEL_PING_EXPIRED)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -319,8 +315,6 @@ public:
|
||||
|
||||
void RemoveGovernanceObject(uint256 nGovernanceObjectHash);
|
||||
|
||||
void UpdateWatchdogVoteTime(uint64_t nVoteTime = 0);
|
||||
|
||||
CMasternode& operator=(CMasternode const& from)
|
||||
{
|
||||
static_cast<masternode_info_t&>(*this)=from;
|
||||
|
@ -63,7 +63,7 @@ CMasternodeMan::CMasternodeMan():
|
||||
fMasternodesAdded(false),
|
||||
fMasternodesRemoved(false),
|
||||
vecDirtyGovernanceObjectHashes(),
|
||||
nLastWatchdogVoteTime(0),
|
||||
nLastSentinelPingTime(0),
|
||||
mapSeenMasternodeBroadcast(),
|
||||
mapSeenMasternodePing(),
|
||||
nDsqCount(0)
|
||||
@ -157,7 +157,7 @@ void CMasternodeMan::Check()
|
||||
{
|
||||
LOCK(cs);
|
||||
|
||||
LogPrint("masternode", "CMasternodeMan::Check -- nLastWatchdogVoteTime=%d, IsWatchdogActive()=%d\n", nLastWatchdogVoteTime, IsWatchdogActive());
|
||||
LogPrint("masternode", "CMasternodeMan::Check -- nLastSentinelPingTime=%d, IsSentinelPingActive()=%d\n", nLastSentinelPingTime, IsSentinelPingActive());
|
||||
|
||||
for (auto& mnpair : mapMasternodes) {
|
||||
// NOTE: internally it checks only every MASTERNODE_CHECK_SECONDS seconds
|
||||
@ -359,7 +359,7 @@ void CMasternodeMan::Clear()
|
||||
mapSeenMasternodeBroadcast.clear();
|
||||
mapSeenMasternodePing.clear();
|
||||
nDsqCount = 0;
|
||||
nLastWatchdogVoteTime = 0;
|
||||
nLastSentinelPingTime = 0;
|
||||
}
|
||||
|
||||
int CMasternodeMan::CountMasternodes(int nProtocolVersion)
|
||||
@ -846,11 +846,8 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, const std::string& strCommand,
|
||||
// see if we have this Masternode
|
||||
CMasternode* pmn = Find(mnp.masternodeOutpoint);
|
||||
|
||||
// if masternode uses sentinel ping instead of watchdog
|
||||
// we shoud update nTimeLastWatchdogVote here if sentinel
|
||||
// ping flag is actual
|
||||
if(pmn && mnp.fSentinelIsCurrent)
|
||||
UpdateWatchdogVoteTime(mnp.masternodeOutpoint, mnp.sigTime);
|
||||
UpdateLastSentinelPingTime();
|
||||
|
||||
// too late, new MNANNOUNCE is required
|
||||
if(pmn && pmn->IsNewStartRequired()) return;
|
||||
@ -1609,22 +1606,17 @@ void CMasternodeMan::UpdateLastPaid(const CBlockIndex* pindex)
|
||||
IsFirstRun = false;
|
||||
}
|
||||
|
||||
void CMasternodeMan::UpdateWatchdogVoteTime(const COutPoint& outpoint, uint64_t nVoteTime)
|
||||
void CMasternodeMan::UpdateLastSentinelPingTime()
|
||||
{
|
||||
LOCK(cs);
|
||||
CMasternode* pmn = Find(outpoint);
|
||||
if(!pmn) {
|
||||
return;
|
||||
}
|
||||
pmn->UpdateWatchdogVoteTime(nVoteTime);
|
||||
nLastWatchdogVoteTime = GetTime();
|
||||
nLastSentinelPingTime = GetTime();
|
||||
}
|
||||
|
||||
bool CMasternodeMan::IsWatchdogActive()
|
||||
bool CMasternodeMan::IsSentinelPingActive()
|
||||
{
|
||||
LOCK(cs);
|
||||
// Check if any masternodes have voted recently, otherwise return false
|
||||
return (GetTime() - nLastWatchdogVoteTime) <= MASTERNODE_WATCHDOG_MAX_SECONDS;
|
||||
return (GetTime() - nLastSentinelPingTime) <= MASTERNODE_SENTINEL_PING_MAX_SECONDS;
|
||||
}
|
||||
|
||||
bool CMasternodeMan::AddGovernanceVote(const COutPoint& outpoint, uint256 nGovernanceObjectHash)
|
||||
@ -1672,11 +1664,8 @@ void CMasternodeMan::SetMasternodeLastPing(const COutPoint& outpoint, const CMas
|
||||
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) {
|
||||
UpdateWatchdogVoteTime(mnp.masternodeOutpoint, mnp.sigTime);
|
||||
UpdateLastSentinelPingTime();
|
||||
}
|
||||
mapSeenMasternodePing.insert(std::make_pair(mnp.GetHash(), mnp));
|
||||
|
||||
|
@ -73,7 +73,7 @@ private:
|
||||
|
||||
std::vector<uint256> vecDirtyGovernanceObjectHashes;
|
||||
|
||||
int64_t nLastWatchdogVoteTime;
|
||||
int64_t nLastSentinelPingTime;
|
||||
|
||||
friend class CMasternodeSync;
|
||||
/// Find an entry
|
||||
@ -117,7 +117,7 @@ public:
|
||||
READWRITE(mWeAskedForMasternodeListEntry);
|
||||
READWRITE(mMnbRecoveryRequests);
|
||||
READWRITE(mMnbRecoveryGoodReplies);
|
||||
READWRITE(nLastWatchdogVoteTime);
|
||||
READWRITE(nLastSentinelPingTime);
|
||||
READWRITE(nDsqCount);
|
||||
|
||||
READWRITE(mapSeenMasternodeBroadcast);
|
||||
@ -223,8 +223,8 @@ public:
|
||||
return vecTmp;;
|
||||
}
|
||||
|
||||
bool IsWatchdogActive();
|
||||
void UpdateWatchdogVoteTime(const COutPoint& outpoint, uint64_t nVoteTime = 0);
|
||||
bool IsSentinelPingActive();
|
||||
void UpdateLastSentinelPingTime();
|
||||
bool AddGovernanceVote(const COutPoint& outpoint, uint256 nGovernanceObjectHash);
|
||||
void RemoveGovernanceObject(uint256 nGovernanceObjectHash);
|
||||
|
||||
|
@ -157,9 +157,12 @@ UniValue gobject(const JSONRPCRequest& request)
|
||||
}
|
||||
}
|
||||
|
||||
if((govobj.GetObjectType() == GOVERNANCE_OBJECT_TRIGGER) ||
|
||||
(govobj.GetObjectType() == GOVERNANCE_OBJECT_WATCHDOG)) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Trigger and watchdog objects need not be prepared (however only masternodes can create them)");
|
||||
if(govobj.GetObjectType() == GOVERNANCE_OBJECT_TRIGGER) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Trigger objects need not be prepared (however only masternodes can create them)");
|
||||
}
|
||||
|
||||
if(govobj.GetObjectType() == GOVERNANCE_OBJECT_WATCHDOG) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Watchdogs are deprecated");
|
||||
}
|
||||
|
||||
{
|
||||
@ -247,9 +250,12 @@ UniValue gobject(const JSONRPCRequest& request)
|
||||
}
|
||||
}
|
||||
|
||||
if(govobj.GetObjectType() == GOVERNANCE_OBJECT_WATCHDOG) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Watchdogs are deprecated");
|
||||
}
|
||||
|
||||
// Attempt to sign triggers if we are a MN
|
||||
if((govobj.GetObjectType() == GOVERNANCE_OBJECT_TRIGGER) ||
|
||||
(govobj.GetObjectType() == GOVERNANCE_OBJECT_WATCHDOG)) {
|
||||
if(govobj.GetObjectType() == GOVERNANCE_OBJECT_TRIGGER) {
|
||||
if(fMnFound) {
|
||||
govobj.SetMasternodeOutpoint(activeMasternode.outpoint);
|
||||
govobj.Sign(activeMasternode.keyMasternode, activeMasternode.pubKeyMasternode);
|
||||
@ -622,8 +628,8 @@ UniValue gobject(const JSONRPCRequest& request)
|
||||
|
||||
std::string strType = "all";
|
||||
if (request.params.size() == 3) strType = request.params[2].get_str();
|
||||
if (strType != "proposals" && strType != "triggers" && strType != "watchdogs" && strType != "all")
|
||||
return "Invalid type, should be 'proposals', 'triggers', 'watchdogs' or 'all'";
|
||||
if (strType != "proposals" && strType != "triggers" && strType != "all")
|
||||
return "Invalid type, should be 'proposals', 'triggers' or 'all'";
|
||||
|
||||
// GET STARTING TIME TO QUERY SYSTEM WITH
|
||||
|
||||
@ -652,7 +658,6 @@ UniValue gobject(const JSONRPCRequest& request)
|
||||
|
||||
if(strType == "proposals" && pGovObj->GetObjectType() != GOVERNANCE_OBJECT_PROPOSAL) continue;
|
||||
if(strType == "triggers" && pGovObj->GetObjectType() != GOVERNANCE_OBJECT_TRIGGER) continue;
|
||||
if(strType == "watchdogs" && pGovObj->GetObjectType() != GOVERNANCE_OBJECT_WATCHDOG) continue;
|
||||
|
||||
UniValue bObj(UniValue::VOBJ);
|
||||
bObj.push_back(Pair("DataHex", pGovObj->GetDataAsHexString()));
|
||||
@ -915,7 +920,8 @@ UniValue getgovernanceinfo(const JSONRPCRequest& request)
|
||||
"\nResult:\n"
|
||||
"{\n"
|
||||
" \"governanceminquorum\": xxxxx, (numeric) the absolute minimum number of votes needed to trigger a governance action\n"
|
||||
" \"masternodewatchdogmaxseconds\": xxxxx, (numeric) sentinel watchdog expiration time in seconds\n"
|
||||
" \"masternodewatchdogmaxseconds\": xxxxx, (numeric) sentinel watchdog expiration time in seconds (DEPRECATED)\n"
|
||||
" \"sentinelpingmaxseconds\": xxxxx, (numeric) sentinel ping expiration time in seconds\n"
|
||||
" \"proposalfee\": xxx.xx, (numeric) the collateral transaction fee which must be paid to create a proposal in " + CURRENCY_UNIT + "\n"
|
||||
" \"superblockcycle\": xxxxx, (numeric) the number of blocks between superblocks\n"
|
||||
" \"lastsuperblock\": xxxxx, (numeric) the block number of the last superblock\n"
|
||||
@ -937,7 +943,8 @@ UniValue getgovernanceinfo(const JSONRPCRequest& request)
|
||||
|
||||
UniValue obj(UniValue::VOBJ);
|
||||
obj.push_back(Pair("governanceminquorum", Params().GetConsensus().nGovernanceMinQuorum));
|
||||
obj.push_back(Pair("masternodewatchdogmaxseconds", MASTERNODE_WATCHDOG_MAX_SECONDS));
|
||||
obj.push_back(Pair("masternodewatchdogmaxseconds", MASTERNODE_SENTINEL_PING_MAX_SECONDS));
|
||||
obj.push_back(Pair("sentinelpingmaxseconds", MASTERNODE_SENTINEL_PING_MAX_SECONDS));
|
||||
obj.push_back(Pair("proposalfee", ValueFromAmount(GOVERNANCE_PROPOSAL_FEE_TX)));
|
||||
obj.push_back(Pair("superblockcycle", Params().GetConsensus().nSuperblockCycle));
|
||||
obj.push_back(Pair("lastsuperblock", nLastSuperblock));
|
||||
|
@ -501,7 +501,7 @@ UniValue masternodelist(const JSONRPCRequest& request)
|
||||
" protocol - Print protocol of a masternode (can be additionally filtered, exact match)\n"
|
||||
" pubkey - Print the masternode (not collateral) public key\n"
|
||||
" rank - Print rank of a masternode based on current block\n"
|
||||
" status - Print masternode status: PRE_ENABLED / ENABLED / EXPIRED / WATCHDOG_EXPIRED / NEW_START_REQUIRED /\n"
|
||||
" status - Print masternode status: PRE_ENABLED / ENABLED / EXPIRED / SENTINEL_PING_EXPIRED / NEW_START_REQUIRED /\n"
|
||||
" UPDATE_REQUIRED / POSE_BAN / OUTPOINT_SPENT (can be additionally filtered, partial match)\n"
|
||||
);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user