Changeset View
Changeset View
Standalone View
Standalone View
src/versionbits.cpp
Show All 30 Lines | ThresholdState AbstractThresholdConditionChecker::GetStateFor( | ||||
} | } | ||||
// Walk backwards in steps of nPeriod to find a pindexPrev whose information | // Walk backwards in steps of nPeriod to find a pindexPrev whose information | ||||
// is known | // is known | ||||
std::vector<const CBlockIndex *> vToCompute; | std::vector<const CBlockIndex *> vToCompute; | ||||
while (cache.count(pindexPrev) == 0) { | while (cache.count(pindexPrev) == 0) { | ||||
if (pindexPrev == nullptr) { | if (pindexPrev == nullptr) { | ||||
// The genesis block is by definition defined. | // The genesis block is by definition defined. | ||||
cache[pindexPrev] = THRESHOLD_DEFINED; | cache[pindexPrev] = ThresholdState::DEFINED; | ||||
break; | break; | ||||
} | } | ||||
if (pindexPrev->GetMedianTimePast() < nTimeStart) { | if (pindexPrev->GetMedianTimePast() < nTimeStart) { | ||||
// Optimization: don't recompute down further, as we know every | // Optimization: don't recompute down further, as we know every | ||||
// earlier block will be before the start time | // earlier block will be before the start time | ||||
cache[pindexPrev] = THRESHOLD_DEFINED; | cache[pindexPrev] = ThresholdState::DEFINED; | ||||
break; | break; | ||||
} | } | ||||
vToCompute.push_back(pindexPrev); | vToCompute.push_back(pindexPrev); | ||||
pindexPrev = pindexPrev->GetAncestor(pindexPrev->nHeight - nPeriod); | pindexPrev = pindexPrev->GetAncestor(pindexPrev->nHeight - nPeriod); | ||||
} | } | ||||
// At this point, cache[pindexPrev] is known | // At this point, cache[pindexPrev] is known | ||||
assert(cache.count(pindexPrev)); | assert(cache.count(pindexPrev)); | ||||
ThresholdState state = cache[pindexPrev]; | ThresholdState state = cache[pindexPrev]; | ||||
// Now walk forward and compute the state of descendants of pindexPrev | // Now walk forward and compute the state of descendants of pindexPrev | ||||
while (!vToCompute.empty()) { | while (!vToCompute.empty()) { | ||||
ThresholdState stateNext = state; | ThresholdState stateNext = state; | ||||
pindexPrev = vToCompute.back(); | pindexPrev = vToCompute.back(); | ||||
vToCompute.pop_back(); | vToCompute.pop_back(); | ||||
switch (state) { | switch (state) { | ||||
case THRESHOLD_DEFINED: { | case ThresholdState::DEFINED: { | ||||
if (pindexPrev->GetMedianTimePast() >= nTimeTimeout) { | if (pindexPrev->GetMedianTimePast() >= nTimeTimeout) { | ||||
stateNext = THRESHOLD_FAILED; | stateNext = ThresholdState::FAILED; | ||||
} else if (pindexPrev->GetMedianTimePast() >= nTimeStart) { | } else if (pindexPrev->GetMedianTimePast() >= nTimeStart) { | ||||
stateNext = THRESHOLD_STARTED; | stateNext = ThresholdState::STARTED; | ||||
} | } | ||||
break; | break; | ||||
} | } | ||||
case THRESHOLD_STARTED: { | case ThresholdState::STARTED: { | ||||
if (pindexPrev->GetMedianTimePast() >= nTimeTimeout) { | if (pindexPrev->GetMedianTimePast() >= nTimeTimeout) { | ||||
stateNext = THRESHOLD_FAILED; | stateNext = ThresholdState::FAILED; | ||||
break; | break; | ||||
} | } | ||||
// We need to count | // We need to count | ||||
const CBlockIndex *pindexCount = pindexPrev; | const CBlockIndex *pindexCount = pindexPrev; | ||||
int count = 0; | int count = 0; | ||||
for (int i = 0; i < nPeriod; i++) { | for (int i = 0; i < nPeriod; i++) { | ||||
if (Condition(pindexCount, params)) { | if (Condition(pindexCount, params)) { | ||||
count++; | count++; | ||||
} | } | ||||
pindexCount = pindexCount->pprev; | pindexCount = pindexCount->pprev; | ||||
} | } | ||||
if (count >= nThreshold) { | if (count >= nThreshold) { | ||||
stateNext = THRESHOLD_LOCKED_IN; | stateNext = ThresholdState::LOCKED_IN; | ||||
} | } | ||||
break; | break; | ||||
} | } | ||||
case THRESHOLD_LOCKED_IN: { | case ThresholdState::LOCKED_IN: { | ||||
// Always progresses into ACTIVE. | // Always progresses into ACTIVE. | ||||
stateNext = THRESHOLD_ACTIVE; | stateNext = ThresholdState::ACTIVE; | ||||
break; | break; | ||||
} | } | ||||
case THRESHOLD_FAILED: | case ThresholdState::FAILED: | ||||
case THRESHOLD_ACTIVE: { | case ThresholdState::ACTIVE: { | ||||
// Nothing happens, these are terminal states. | // Nothing happens, these are terminal states. | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
cache[pindexPrev] = state = stateNext; | cache[pindexPrev] = state = stateNext; | ||||
} | } | ||||
return state; | return state; | ||||
} | } | ||||
int AbstractThresholdConditionChecker::GetStateSinceHeightFor( | int AbstractThresholdConditionChecker::GetStateSinceHeightFor( | ||||
const CBlockIndex *pindexPrev, const Consensus::Params ¶ms, | const CBlockIndex *pindexPrev, const Consensus::Params ¶ms, | ||||
ThresholdConditionCache &cache) const { | ThresholdConditionCache &cache) const { | ||||
const ThresholdState initialState = GetStateFor(pindexPrev, params, cache); | const ThresholdState initialState = GetStateFor(pindexPrev, params, cache); | ||||
// BIP 9 about state DEFINED: "The genesis block is by definition in this | // BIP 9 about state DEFINED: "The genesis block is by definition in this | ||||
// state for each deployment." | // state for each deployment." | ||||
if (initialState == THRESHOLD_DEFINED) { | if (initialState == ThresholdState::DEFINED) { | ||||
return 0; | return 0; | ||||
} | } | ||||
const int nPeriod = Period(params); | const int nPeriod = Period(params); | ||||
// A block's state is always the same as that of the first of its period, so | // A block's state is always the same as that of the first of its period, so | ||||
// it is computed based on a pindexPrev whose height equals a multiple of | // it is computed based on a pindexPrev whose height equals a multiple of | ||||
// nPeriod - 1. To ease understanding of the following height calculation, | // nPeriod - 1. To ease understanding of the following height calculation, | ||||
▲ Show 20 Lines • Show All 87 Lines • Show Last 20 Lines |