git / moonbite-core / src/versionbits.cpp · raw

// Copyright (c) 2016-2019 The Bitcoin Core developers// Distributed under the MIT software license, see the accompanying// file COPYING or http://www.opensource.org/licenses/mit-license.php.#include <versionbits.h>#include <consensus/params.h>ThresholdState AbstractThresholdConditionChecker::GetStateFor(const CBlockIndex* pindexPrev, const Consensus::Params& params, ThresholdConditionCache& cache) const{    int nPeriod = Period(params);    int nThreshold = Threshold(params);    int64_t nTimeStart = BeginTime(params);    int64_t nTimeTimeout = EndTime(params);    int64_t nHeightStart = BeginHeight(params);    int64_t nHeightTimeout = EndHeight(params);    bool fHeightBased = (nTimeStart == 0 && nTimeTimeout == 0) ? true : false;    // Check if this deployment is always active.    if (nTimeStart == Consensus::BIP9Deployment::ALWAYS_ACTIVE) {        return ThresholdState::ACTIVE;    }    // Check if this deployment is never active.    if (nTimeStart == Consensus::BIP9Deployment::NEVER_ACTIVE) {        return ThresholdState::FAILED;    }    // 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 nPeriod - 1.    if (pindexPrev != nullptr) {        pindexPrev = pindexPrev->GetAncestor(pindexPrev->nHeight - ((pindexPrev->nHeight + 1) % nPeriod));    }    // Walk backwards in steps of nPeriod to find a pindexPrev whose information is known    std::vector<const CBlockIndex*> vToCompute;    while (cache.count(pindexPrev) == 0) {        if (pindexPrev == nullptr) {            // The genesis block is by definition defined.            cache[pindexPrev] = ThresholdState::DEFINED;            break;        }        if (fHeightBased ? ((pindexPrev->nHeight + 1) < nHeightStart) : (pindexPrev->GetMedianTimePast() < nTimeStart)) {            // Optimization: don't recompute down further, as we know every earlier block will be before the start time            cache[pindexPrev] = ThresholdState::DEFINED;            break;        }        vToCompute.push_back(pindexPrev);        pindexPrev = pindexPrev->GetAncestor(pindexPrev->nHeight - nPeriod);    }    // At this point, cache[pindexPrev] is known    assert(cache.count(pindexPrev));    ThresholdState state = cache[pindexPrev];    // Now walk forward and compute the state of descendants of pindexPrev    while (!vToCompute.empty()) {        ThresholdState stateNext = state;        pindexPrev = vToCompute.back();        vToCompute.pop_back();        switch (state) {            case ThresholdState::DEFINED: {                if (fHeightBased ? (pindexPrev->nHeight + 1) >= nHeightStart : pindexPrev->GetMedianTimePast() >= nTimeStart) {                    stateNext = ThresholdState::STARTED;                }                break;            }            case ThresholdState::STARTED: {                // We need to count                const CBlockIndex* pindexCount = pindexPrev;                int count = 0;                for (int i = 0; i < nPeriod; i++) {                    if (Condition(pindexCount, params)) {                        count++;                    }                    pindexCount = pindexCount->pprev;                }                if (count >= nThreshold) {                    stateNext = ThresholdState::LOCKED_IN;                } else if (fHeightBased ? ((pindexPrev->nHeight + 1) >= nHeightTimeout) : (pindexPrev->GetMedianTimePast() >= nTimeTimeout)) {                    stateNext = fHeightBased ? ThresholdState::LOCKED_IN : ThresholdState::FAILED;                }                break;            }            case ThresholdState::LOCKED_IN: {                stateNext = ThresholdState::ACTIVE;                break;            }            case ThresholdState::FAILED:            case ThresholdState::ACTIVE: {                // Nothing happens, these are terminal states.                break;            }        }        cache[pindexPrev] = state = stateNext;    }    return state;}BIP9Stats AbstractThresholdConditionChecker::GetStateStatisticsFor(const CBlockIndex* pindex, const Consensus::Params& params) const{    BIP9Stats stats = {};    stats.period = Period(params);    stats.threshold = Threshold(params);    if (pindex == nullptr)        return stats;    // Find beginning of period    const CBlockIndex* pindexEndOfPrevPeriod = pindex->GetAncestor(pindex->nHeight - ((pindex->nHeight + 1) % stats.period));    stats.elapsed = pindex->nHeight - pindexEndOfPrevPeriod->nHeight;    // Count from current block to beginning of period    int count = 0;    const CBlockIndex* currentIndex = pindex;    while (pindexEndOfPrevPeriod->nHeight != currentIndex->nHeight){        if (Condition(currentIndex, params))            count++;        currentIndex = currentIndex->pprev;    }    stats.count = count;    stats.possible = (stats.period - stats.threshold ) >= (stats.elapsed - count);    return stats;}int AbstractThresholdConditionChecker::GetStateSinceHeightFor(const CBlockIndex* pindexPrev, const Consensus::Params& params, ThresholdConditionCache& cache) const{    int64_t start_time = BeginTime(params);    if (start_time == Consensus::BIP9Deployment::ALWAYS_ACTIVE || start_time == Consensus::BIP9Deployment::NEVER_ACTIVE) {        return 0;    }    const ThresholdState initialState = GetStateFor(pindexPrev, params, cache);    // BIP 9 about state DEFINED: "The genesis block is by definition in this state for each deployment."    if (initialState == ThresholdState::DEFINED) {        return 0;    }    const int nPeriod = Period(params);    // 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 nPeriod - 1.    // To ease understanding of the following height calculation, it helps to remember that    // right now pindexPrev points to the block prior to the block that we are computing for, thus:    // if we are computing for the last block of a period, then pindexPrev points to the second to last block of the period, and    // if we are computing for the first block of a period, then pindexPrev points to the last block of the previous period.    // The parent of the genesis block is represented by nullptr.    pindexPrev = pindexPrev->GetAncestor(pindexPrev->nHeight - ((pindexPrev->nHeight + 1) % nPeriod));    const CBlockIndex* previousPeriodParent = pindexPrev->GetAncestor(pindexPrev->nHeight - nPeriod);    while (previousPeriodParent != nullptr && GetStateFor(previousPeriodParent, params, cache) == initialState) {        pindexPrev = previousPeriodParent;        previousPeriodParent = pindexPrev->GetAncestor(pindexPrev->nHeight - nPeriod);    }    // Adjust the result because right now we point to the parent block.    return pindexPrev->nHeight + 1;}namespace{/** * Class to implement versionbits logic. */class VersionBitsConditionChecker : public AbstractThresholdConditionChecker {private:    const Consensus::DeploymentPos id;protected:    int64_t BeginTime(const Consensus::Params& params) const override { return params.vDeployments[id].nStartTime; }    int64_t EndTime(const Consensus::Params& params) const override { return params.vDeployments[id].nTimeout; }    int64_t BeginHeight(const Consensus::Params& params) const override { return params.vDeployments[id].nStartHeight; }    int64_t EndHeight(const Consensus::Params& params) const override { return params.vDeployments[id].nTimeoutHeight; }    int Period(const Consensus::Params& params) const override { return params.nMinerConfirmationWindow; }    int Threshold(const Consensus::Params& params) const override { return params.nRuleChangeActivationThreshold; }    bool Condition(const CBlockIndex* pindex, const Consensus::Params& params) const override    {        return (((pindex->nVersion & VERSIONBITS_TOP_MASK) == VERSIONBITS_TOP_BITS) && (pindex->nVersion & Mask(params)) != 0);    }public:    explicit VersionBitsConditionChecker(Consensus::DeploymentPos id_) : id(id_) {}    uint32_t Mask(const Consensus::Params& params) const { return ((uint32_t)1) << params.vDeployments[id].bit; }};} // namespaceThresholdState VersionBitsState(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::DeploymentPos pos, VersionBitsCache& cache){    return VersionBitsConditionChecker(pos).GetStateFor(pindexPrev, params, cache.caches[pos]);}BIP9Stats VersionBitsStatistics(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::DeploymentPos pos){    return VersionBitsConditionChecker(pos).GetStateStatisticsFor(pindexPrev, params);}int VersionBitsStateSinceHeight(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::DeploymentPos pos, VersionBitsCache& cache){    return VersionBitsConditionChecker(pos).GetStateSinceHeightFor(pindexPrev, params, cache.caches[pos]);}uint32_t VersionBitsMask(const Consensus::Params& params, Consensus::DeploymentPos pos){    return VersionBitsConditionChecker(pos).Mask(params);}void VersionBitsCache::Clear(){    for (unsigned int d = 0; d < Consensus::MAX_VERSION_BITS_DEPLOYMENTS; d++) {        caches[d].clear();    }}