Fix masternode score/rank calculations (#1620)

* fix CMasternode::CalculateScore, new mn score algo activation is triggered by DIP0001 lock-in

* unify rank calculation, base it on full mn vector rather than using active mns only

* bump CMasternodeMan::SERIALIZATION_VERSION_STRING

* unify rank calculations even further

* fix (partially revert previous one)
This commit is contained in:
UdjinM6 2017-09-14 16:58:29 +03:00 committed by GitHub
parent ace00175c4
commit d7a8489f31
10 changed files with 152 additions and 114 deletions

View File

@ -101,7 +101,7 @@ void CDarkSendRelay::RelayThroughNode(int nRank)
{
masternode_info_t mnInfo;
if(mnodeman.GetMasternodeByRank(nRank, nBlockHeight, MIN_PRIVATESEND_PEER_PROTO_VERSION, false, mnInfo)){
if(mnodeman.GetMasternodeByRank(nRank, mnInfo, nBlockHeight, MIN_PRIVATESEND_PEER_PROTO_VERSION)) {
//printf("RelayThroughNode %s\n", mnInfo.addr.ToString().c_str());
// TODO: Pass CConnman instance somehow and don't use global variable.
CNode* pnode = g_connman->ConnectNode((CAddress)mnInfo.addr, NULL);

View File

@ -195,22 +195,21 @@ void CInstantSend::Vote(CTxLockCandidate& txLockCandidate)
int nLockInputHeight = nPrevoutHeight + 4;
int n = mnodeman.GetMasternodeRank(activeMasternode.outpoint, nLockInputHeight, MIN_INSTANTSEND_PROTO_VERSION);
if(n == -1) {
int nRank;
if(!mnodeman.GetMasternodeRank(activeMasternode.outpoint, nRank, nLockInputHeight, MIN_INSTANTSEND_PROTO_VERSION)) {
LogPrint("instantsend", "CInstantSend::Vote -- Can't calculate rank for masternode %s\n", activeMasternode.outpoint.ToStringShort());
++itOutpointLock;
continue;
}
int nSignaturesTotal = COutPointLock::SIGNATURES_TOTAL;
if(n > nSignaturesTotal) {
LogPrint("instantsend", "CInstantSend::Vote -- Masternode not in the top %d (%d)\n", nSignaturesTotal, n);
if(nRank > nSignaturesTotal) {
LogPrint("instantsend", "CInstantSend::Vote -- Masternode not in the top %d (%d)\n", nSignaturesTotal, nRank);
++itOutpointLock;
continue;
}
LogPrint("instantsend", "CInstantSend::Vote -- In the top %d (%d)\n", nSignaturesTotal, n);
LogPrint("instantsend", "CInstantSend::Vote -- In the top %d (%d)\n", nSignaturesTotal, nRank);
std::map<COutPoint, std::set<uint256> >::iterator itVoted = mapVotedOutpoints.find(itOutpointLock->first);
@ -1000,19 +999,18 @@ bool CTxLockVote::IsValid(CNode* pnode) const
int nLockInputHeight = coins.nHeight + 4;
int n = mnodeman.GetMasternodeRank(outpointMasternode, nLockInputHeight, MIN_INSTANTSEND_PROTO_VERSION);
if(n == -1) {
int nRank;
if(!mnodeman.GetMasternodeRank(outpointMasternode, nRank, nLockInputHeight, MIN_INSTANTSEND_PROTO_VERSION)) {
//can be caused by past versions trying to vote with an invalid protocol
LogPrint("instantsend", "CTxLockVote::IsValid -- Can't calculate rank for masternode %s\n", outpointMasternode.ToStringShort());
return false;
}
LogPrint("instantsend", "CTxLockVote::IsValid -- Masternode %s, rank=%d\n", outpointMasternode.ToStringShort(), n);
LogPrint("instantsend", "CTxLockVote::IsValid -- Masternode %s, rank=%d\n", outpointMasternode.ToStringShort(), nRank);
int nSignaturesTotal = COutPointLock::SIGNATURES_TOTAL;
if(n > nSignaturesTotal) {
if(nRank > nSignaturesTotal) {
LogPrint("instantsend", "CTxLockVote::IsValid -- Masternode %s is not in the top %d (%d), vote hash=%s\n",
outpointMasternode.ToStringShort(), nSignaturesTotal, n, GetHash().ToString());
outpointMasternode.ToStringShort(), nSignaturesTotal, nRank, GetHash().ToString());
return false;
}

View File

@ -684,9 +684,9 @@ bool CMasternodePaymentVote::IsValid(CNode* pnode, int nValidationHeight, std::s
// Regular clients (miners included) need to verify masternode rank for future block votes only.
if(!fMasterNode && nBlockHeight < nValidationHeight) return true;
int nRank = mnodeman.GetMasternodeRank(vinMasternode.prevout, nBlockHeight - 101, nMinRequiredProtocol, false);
int nRank;
if(nRank == -1) {
if(!mnodeman.GetMasternodeRank(vinMasternode.prevout, nRank, nBlockHeight - 101, nMinRequiredProtocol)) {
LogPrint("mnpayments", "CMasternodePaymentVote::IsValid -- Can't calculate rank for masternode %s\n",
vinMasternode.prevout.ToStringShort());
return false;
@ -700,8 +700,11 @@ bool CMasternodePaymentVote::IsValid(CNode* pnode, int nValidationHeight, std::s
if(nRank > MNPAYMENTS_SIGNATURES_TOTAL*2 && nBlockHeight > nValidationHeight) {
strError = strprintf("Masternode is not in the top %d (%d)", MNPAYMENTS_SIGNATURES_TOTAL*2, nRank);
LogPrintf("CMasternodePaymentVote::IsValid -- Error: %s\n", strError);
// do not ban nodes before DIP0001 is locked in to avoid banning majority of (old) masternodes
if (fDIP0001LockedInAtTip) {
Misbehaving(pnode->GetId(), 20);
}
}
// Still invalid however
return false;
}
@ -720,9 +723,9 @@ bool CMasternodePayments::ProcessBlock(int nBlockHeight)
// if we have not enough data about masternodes.
if(!masternodeSync.IsMasternodeListSynced()) return false;
int nRank = mnodeman.GetMasternodeRank(activeMasternode.outpoint, nBlockHeight - 101, GetMinMasternodePaymentsProto(), false);
int nRank;
if (nRank == -1) {
if (!mnodeman.GetMasternodeRank(activeMasternode.outpoint, nRank, nBlockHeight - 101, GetMinMasternodePaymentsProto())) {
LogPrint("mnpayments", "CMasternodePayments::ProcessBlock -- Unknown Masternode\n");
return false;
}
@ -779,7 +782,8 @@ void CMasternodePaymentVote::Relay()
// do not relay until synced
if (!masternodeSync.IsWinnersListSynced()) return;
CInv inv(MSG_MASTERNODE_PAYMENT_VOTE, GetHash());
g_connman->RelayInv(inv);
// relay votes only strictly to new nodes until DIP0001 is locked in to avoid being banned by majority of (old) masternodes
g_connman->RelayInv(inv, fDIP0001LockedInAtTip ? mnpayments.GetMinMasternodePaymentsProto() : MIN_MASTERNODE_PAYMENT_PROTO_VERSION_2);
}
bool CMasternodePaymentVote::CheckSignature(const CPubKey& pubKeyMasternode, int nValidationHeight, int &nDos)

View File

@ -30,7 +30,7 @@ CMasternode::CMasternode(const CMasternode& other) :
masternode_info_t{other},
lastPing(other.lastPing),
vchSig(other.vchSig),
nCacheCollateralBlock(other.nCacheCollateralBlock),
nCollateralMinConfBlockHash(other.nCollateralMinConfBlockHash),
nBlockLastPaid(other.nBlockLastPaid),
nPoSeBanScore(other.nPoSeBanScore),
nPoSeBanHeight(other.nPoSeBanHeight),
@ -90,6 +90,15 @@ bool CMasternode::UpdateFromNewBroadcast(CMasternodeBroadcast& mnb)
//
arith_uint256 CMasternode::CalculateScore(const uint256& blockHash)
{
if (fDIP0001LockedInAtTip) {
// Deterministically calculate a "score" for a Masternode based on any given (block)hash
CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
ss << vin.prevout << nCollateralMinConfBlockHash << blockHash;
return UintToArith256(ss.GetHash());
}
// TODO: remove calculations below after migration to 12.2
uint256 aux = ArithToUint256(UintToArith256(vin.prevout.hash) + vin.prevout.n);
CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
@ -572,6 +581,8 @@ bool CMasternodeBroadcast::CheckOutpoint(int& nDos)
mnodeman.mapSeenMasternodeBroadcast.erase(GetHash());
return false;
}
// remember the hash of the block where masternode collateral had minimum required confirmations
nCollateralMinConfBlockHash = chainActive[nHeight + Params().GetConsensus().nMasternodeMinimumConfirmations - 1]->GetBlockHash();
}
LogPrint("masternode", "CMasternodeBroadcast::CheckOutpoint -- Masternode UTXO verified\n");

View File

@ -155,7 +155,7 @@ public:
CMasternodePing lastPing{};
std::vector<unsigned char> vchSig{};
int nCacheCollateralBlock{};
uint256 nCollateralMinConfBlockHash{};
int nBlockLastPaid{};
int nPoSeBanScore{};
int nPoSeBanHeight{};
@ -187,7 +187,7 @@ public:
READWRITE(nTimeLastPaid);
READWRITE(nTimeLastWatchdogVote);
READWRITE(nActiveState);
READWRITE(nCacheCollateralBlock);
READWRITE(nCollateralMinConfBlockHash);
READWRITE(nBlockLastPaid);
READWRITE(nProtocolVersion);
READWRITE(nPoSeBanScore);
@ -284,7 +284,7 @@ public:
static_cast<masternode_info_t&>(*this)=from;
lastPing = from.lastPing;
vchSig = from.vchSig;
nCacheCollateralBlock = from.nCacheCollateralBlock;
nCollateralMinConfBlockHash = from.nCollateralMinConfBlockHash;
nBlockLastPaid = from.nBlockLastPaid;
nPoSeBanScore = from.nPoSeBanScore;
nPoSeBanHeight = from.nPoSeBanHeight;

View File

@ -16,7 +16,7 @@
/** Masternode manager */
CMasternodeMan mnodeman;
const std::string CMasternodeMan::SERIALIZATION_VERSION_STRING = "CMasternodeMan-Version-6";
const std::string CMasternodeMan::SERIALIZATION_VERSION_STRING = "CMasternodeMan-Version-7";
struct CompareLastPaidBlock
{
@ -29,8 +29,8 @@ struct CompareLastPaidBlock
struct CompareScoreMN
{
bool operator()(const std::pair<int64_t, CMasternode*>& t1,
const std::pair<int64_t, CMasternode*>& t2) const
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);
}
@ -169,7 +169,7 @@ void CMasternodeMan::CheckAndRemove()
Check();
// Remove spent masternodes, prepare structures and make requests to reasure the state of inactive ones
std::vector<std::pair<int, CMasternode> > vecMasternodeRanks;
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();
@ -199,7 +199,7 @@ void CMasternodeMan::CheckAndRemove()
// calulate only once and only when it's needed
if(vecMasternodeRanks.empty()) {
int nRandomBlockHeight = GetRandInt(nCachedBlockHeight);
vecMasternodeRanks = GetMasternodeRanks(nRandomBlockHeight);
GetMasternodeRanks(vecMasternodeRanks, nRandomBlockHeight);
}
bool fAskedForMnbRecovery = false;
// ask first MNB_RECOVERY_QUORUM_TOTAL masternodes we can connect to and we haven't asked recently
@ -493,7 +493,7 @@ bool CMasternodeMan::GetNextMasternodeInQueueForPayment(int nBlockHeight, bool f
Make a vector with all of the last paid times
*/
int nMnCount = CountEnabled();
int nMnCount = CountMasternodes();
for (auto& mnpair : mapMasternodes) {
if(!mnpair.second.IsValidForPayment()) continue;
@ -593,103 +593,118 @@ masternode_info_t CMasternodeMan::FindRandomNotInVec(const std::vector<COutPoint
return masternode_info_t();
}
int CMasternodeMan::GetMasternodeRank(const COutPoint& outpoint, int nBlockHeight, int nMinProtocol, bool fOnlyActive)
bool CMasternodeMan::GetMasternodeScores(const uint256& nBlockHash, CMasternodeMan::score_pair_vec_t& vecMasternodeScoresRet, int nMinProtocol)
{
std::vector<std::pair<int64_t, CMasternode*> > vecMasternodeScores;
vecMasternodeScoresRet.clear();
if (!masternodeSync.IsMasternodeListSynced())
return false;
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 blockHash = uint256();
if(!GetBlockHash(blockHash, nBlockHeight)) return -1;
LOCK(cs);
// scan for winner
for (auto& mnpair : mapMasternodes) {
if(mnpair.second.nProtocolVersion < nMinProtocol) continue;
if(fOnlyActive) {
if(!mnpair.second.IsEnabled()) continue;
}
else {
if(!mnpair.second.IsValidForPayment()) continue;
}
int64_t nScore = mnpair.second.CalculateScore(blockHash).GetCompact(false);
vecMasternodeScores.push_back(std::make_pair(nScore, &mnpair.second));
}
sort(vecMasternodeScores.rbegin(), vecMasternodeScores.rend(), CompareScoreMN());
int nRank = 0;
BOOST_FOREACH (PAIRTYPE(int64_t, CMasternode*)& scorePair, vecMasternodeScores) {
nRank++;
if(scorePair.second->vin.prevout == outpoint) return nRank;
}
return -1;
}
std::vector<std::pair<int, CMasternode> > CMasternodeMan::GetMasternodeRanks(int nBlockHeight, int nMinProtocol)
{
std::vector<std::pair<int64_t, CMasternode*> > vecMasternodeScores;
std::vector<std::pair<int, CMasternode> > vecMasternodeRanks;
//make sure we know about this block
uint256 blockHash = uint256();
if(!GetBlockHash(blockHash, nBlockHeight)) return vecMasternodeRanks;
LOCK(cs);
// scan for winner
for (auto& mnpair : mapMasternodes) {
if(mnpair.second.nProtocolVersion < nMinProtocol || !mnpair.second.IsEnabled()) continue;
int64_t nScore = mnpair.second.CalculateScore(blockHash).GetCompact(false);
vecMasternodeScores.push_back(std::make_pair(nScore, &mnpair.second));
}
sort(vecMasternodeScores.rbegin(), vecMasternodeScores.rend(), CompareScoreMN());
int nRank = 0;
BOOST_FOREACH (PAIRTYPE(int64_t, CMasternode*)& s, vecMasternodeScores) {
nRank++;
vecMasternodeRanks.push_back(std::make_pair(nRank, *s.second));
}
return vecMasternodeRanks;
}
bool CMasternodeMan::GetMasternodeByRank(int nRank, int nBlockHeight, int nMinProtocol, bool fOnlyActive, masternode_info_t& mnInfoRet)
{
std::vector<std::pair<int64_t, CMasternode*> > vecMasternodeScores;
LOCK(cs);
uint256 blockHash;
if(!GetBlockHash(blockHash, nBlockHeight)) {
LogPrintf("CMasternode::GetMasternodeByRank -- ERROR: GetBlockHash() failed at nBlockHeight %d\n", nBlockHeight);
uint256 nBlockHash = uint256();
if (!GetBlockHash(nBlockHash, nBlockHeight)) {
LogPrintf("CMasternodeMan::%s -- ERROR: GetBlockHash() failed at nBlockHeight %d\n", __func__, nBlockHeight);
return false;
}
// Fill scores
for (auto& mnpair : mapMasternodes) {
LOCK(cs);
if(mnpair.second.nProtocolVersion < nMinProtocol) continue;
if(fOnlyActive && !mnpair.second.IsEnabled()) continue;
score_pair_vec_t vecMasternodeScores;
if (!GetMasternodeScores(nBlockHash, vecMasternodeScores, nMinProtocol))
return false;
int64_t nScore = mnpair.second.CalculateScore(blockHash).GetCompact(false);
vecMasternodeScores.push_back(std::make_pair(nScore, &mnpair.second));
int nRank = 0;
for (auto& scorePair : vecMasternodeScores) {
nRank++;
if(scorePair.second->vin.prevout == outpoint) {
nRankRet = nRank;
return true;
}
}
sort(vecMasternodeScores.rbegin(), vecMasternodeScores.rend(), CompareScoreMN());
return false;
}
int rank = 0;
BOOST_FOREACH (PAIRTYPE(int64_t, CMasternode*)& s, vecMasternodeScores){
rank++;
if(rank == nRank) {
mnInfoRet = *s.second;
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)
{
mnInfoRet = masternode_info_t();
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;
if (vecMasternodeScores.size() < nRankIn)
return false;
int nRank = 0;
for (auto& scorePair : vecMasternodeScores) {
nRank++;
if(nRank == nRankIn) {
mnInfoRet = *scorePair.second;
return true;
}
}
@ -901,7 +916,8 @@ void CMasternodeMan::DoFullVerificationStep()
if(activeMasternode.outpoint == COutPoint()) return;
if(!masternodeSync.IsSynced()) return;
std::vector<std::pair<int, CMasternode> > vecMasternodeRanks = GetMasternodeRanks(nCachedBlockHeight - 1, MIN_POSE_PROTO_VERSION);
rank_pair_vec_t vecMasternodeRanks;
GetMasternodeRanks(vecMasternodeRanks, nCachedBlockHeight - 1, MIN_POSE_PROTO_VERSION);
// Need LOCK2 here to ensure consistent locking order because the SendVerifyRequest call below locks cs_main
// through GetHeight() signal in ConnectNode
@ -1234,9 +1250,9 @@ void CMasternodeMan::ProcessVerifyBroadcast(CNode* pnode, const CMasternodeVerif
return;
}
int nRank = GetMasternodeRank(mnv.vin2.prevout, mnv.nBlockHeight, MIN_POSE_PROTO_VERSION);
int nRank;
if (nRank == -1) {
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;

View File

@ -17,6 +17,10 @@ extern CMasternodeMan mnodeman;
class CMasternodeMan
{
public:
typedef std::pair<arith_uint256, CMasternode*> score_pair_t;
typedef std::vector<score_pair_t> score_pair_vec_t;
typedef std::pair<int, CMasternode> rank_pair_t;
typedef std::vector<rank_pair_t> rank_pair_vec_t;
private:
static const std::string SERIALIZATION_VERSION_STRING;
@ -73,6 +77,8 @@ private:
/// Find an entry
CMasternode* Find(const COutPoint& outpoint);
bool GetMasternodeScores(const uint256& nBlockHash, score_pair_vec_t& vecMasternodeScoresRet, int nMinProtocol = 0);
public:
// Keep track of all broadcasts I've seen
std::map<uint256, std::pair<int64_t, CMasternodeBroadcast> > mapSeenMasternodeBroadcast;
@ -166,9 +172,9 @@ public:
std::map<COutPoint, CMasternode> GetFullMasternodeMap() { return mapMasternodes; }
std::vector<std::pair<int, CMasternode> > GetMasternodeRanks(int nBlockHeight = -1, int nMinProtocol=0);
int GetMasternodeRank(const COutPoint &outpoint, int nBlockHeight, int nMinProtocol=0, bool fOnlyActive=true);
bool GetMasternodeByRank(int nRank, int nBlockHeight, int nMinProtocol, bool fOnlyActive, masternode_info_t& mnInfoRet);
bool GetMasternodeRanks(rank_pair_vec_t& vecMasternodeRanksRet, int nBlockHeight = -1, int nMinProtocol = 0);
bool GetMasternodeRank(const COutPoint &outpoint, int& nRankRet, int nBlockHeight = -1, int nMinProtocol = 0);
bool GetMasternodeByRank(int nRank, masternode_info_t& mnInfoRet, int nBlockHeight = -1, int nMinProtocol = 0);
void ProcessMasternodeConnections();
std::pair<CService, std::set<uint256> > PopScheduledMnbRequestConnection();

View File

@ -504,7 +504,8 @@ UniValue masternodelist(const UniValue& params, bool fHelp)
UniValue obj(UniValue::VOBJ);
if (strMode == "rank") {
std::vector<std::pair<int, CMasternode> > vMasternodeRanks = mnodeman.GetMasternodeRanks();
CMasternodeMan::rank_pair_vec_t vMasternodeRanks;
mnodeman.GetMasternodeRanks(vMasternodeRanks);
BOOST_FOREACH(PAIRTYPE(int, CMasternode)& s, vMasternodeRanks) {
std::string strOutpoint = s.second.vin.prevout.ToStringShort();
if (strFilter !="" && strOutpoint.find(strFilter) == std::string::npos) continue;

View File

@ -1883,7 +1883,7 @@ int32_t ComputeBlockVersion(const CBlockIndex* pindexPrev, const Consensus::Para
const struct BIP9DeploymentInfo& vbinfo = VersionBitsDeploymentInfo[pos];
if (vbinfo.check_mn_protocol && state == THRESHOLD_STARTED && !fAssumeMasternodeIsUpgraded) {
masternode_info_t mnInfo;
bool fFound = mnodeman.GetMasternodeByRank(1, pindexPrev->nHeight, 0, false, mnInfo);
bool fFound = mnodeman.GetMasternodeByRank(1, mnInfo, pindexPrev->nHeight);
if (!fFound || mnInfo.nProtocolVersion < PROTOCOL_VERSION) {
// no masternodes(?) or masternode is not upgraded yet
continue;
@ -2461,7 +2461,8 @@ void static UpdateTip(CBlockIndex *pindexNew) {
}
}
// Update global flag
// Update global flags
fDIP0001LockedInAtTip = (VersionBitsTipState(chainParams.GetConsensus(), Consensus::DEPLOYMENT_DIP0001) == THRESHOLD_LOCKED_IN);
fDIP0001ActiveAtTip = (VersionBitsTipState(chainParams.GetConsensus(), Consensus::DEPLOYMENT_DIP0001) == THRESHOLD_ACTIVE);
}

View File

@ -47,6 +47,7 @@ class CValidationState;
struct LockPoints;
static std::atomic<bool> fDIP0001LockedInAtTip{false};
static std::atomic<bool> fDIP0001ActiveAtTip{false};
/** Default for accepting alerts from the P2P network. */