versionbits: Move WarningBits logic from validation to versionbits

This commit is contained in:
Anthony Towns
2025-01-20 12:51:46 +10:00
parent 5da119e5d0
commit 3bd32c2055
4 changed files with 80 additions and 55 deletions

View File

@@ -3,9 +3,12 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <consensus/params.h>
#include <kernel/chainparams.h>
#include <util/check.h>
#include <versionbits.h>
using enum ThresholdState;
ThresholdState AbstractThresholdConditionChecker::GetStateFor(const CBlockIndex* pindexPrev, ThresholdConditionCache& cache) const
{
int nPeriod = Period();
@@ -224,22 +227,28 @@ uint32_t VersionBitsCache::Mask(const Consensus::Params& params, Consensus::Depl
return VersionBitsConditionChecker(params, pos).Mask();
}
int32_t VersionBitsCache::ComputeBlockVersion(const CBlockIndex* pindexPrev, const Consensus::Params& params)
static int32_t ComputeBlockVersion(const CBlockIndex* pindexPrev, const Consensus::Params& params, std::array<ThresholdConditionCache, Consensus::MAX_VERSION_BITS_DEPLOYMENTS>& caches)
{
LOCK(m_mutex);
int32_t nVersion = VERSIONBITS_TOP_BITS;
for (int i = 0; i < (int)Consensus::MAX_VERSION_BITS_DEPLOYMENTS; i++) {
Consensus::DeploymentPos pos = static_cast<Consensus::DeploymentPos>(i);
ThresholdState state = VersionBitsConditionChecker(params, pos).GetStateFor(pindexPrev, m_caches[pos]);
VersionBitsConditionChecker checker(params, pos);
ThresholdState state = checker.GetStateFor(pindexPrev, caches[pos]);
if (state == ThresholdState::LOCKED_IN || state == ThresholdState::STARTED) {
nVersion |= Mask(params, pos);
nVersion |= checker.Mask();
}
}
return nVersion;
}
int32_t VersionBitsCache::ComputeBlockVersion(const CBlockIndex* pindexPrev, const Consensus::Params& params)
{
LOCK(m_mutex);
return ::ComputeBlockVersion(pindexPrev, params, m_caches);
}
void VersionBitsCache::Clear()
{
LOCK(m_mutex);
@@ -247,3 +256,55 @@ void VersionBitsCache::Clear()
m_caches[d].clear();
}
}
namespace {
/**
* Threshold condition checker that triggers when unknown versionbits are seen on the network.
*/
class WarningBitsConditionChecker : public AbstractThresholdConditionChecker
{
private:
const Consensus::Params& m_params;
std::array<ThresholdConditionCache, Consensus::MAX_VERSION_BITS_DEPLOYMENTS>& m_caches;
int m_bit;
int period{2016};
int threshold{1815}; // 90% threshold used in BIP 341
public:
explicit WarningBitsConditionChecker(const CChainParams& chainparams, std::array<ThresholdConditionCache, Consensus::MAX_VERSION_BITS_DEPLOYMENTS>& caches, int bit)
: m_params{chainparams.GetConsensus()}, m_caches{caches}, m_bit(bit)
{
if (chainparams.IsTestChain()) {
period = chainparams.GetConsensus().DifficultyAdjustmentInterval();
threshold = period * 3 / 4; // 75% for test nets per BIP9 suggestion
}
}
int64_t BeginTime() const override { return 0; }
int64_t EndTime() const override { return std::numeric_limits<int64_t>::max(); }
int Period() const override { return period; }
int Threshold() const override { return threshold; }
bool Condition(const CBlockIndex* pindex) const override
{
return pindex->nHeight >= m_params.MinBIP9WarningHeight &&
((pindex->nVersion & VERSIONBITS_TOP_MASK) == VERSIONBITS_TOP_BITS) &&
((pindex->nVersion >> m_bit) & 1) != 0 &&
((::ComputeBlockVersion(pindex->pprev, m_params, m_caches) >> m_bit) & 1) == 0;
}
};
} // anonymous namespace
std::vector<std::pair<int, bool>> VersionBitsCache::CheckUnknownActivations(const CBlockIndex* pindex, const CChainParams& chainparams)
{
LOCK(m_mutex);
std::vector<std::pair<int, bool>> result;
for (int bit = 0; bit < VERSIONBITS_NUM_BITS; ++bit) {
WarningBitsConditionChecker checker(chainparams, m_caches, bit);
ThresholdState state = checker.GetStateFor(pindex, m_warning_caches.at(bit));
if (state == ACTIVE || state == LOCKED_IN) {
result.emplace_back(bit, state == ACTIVE);
}
}
return result;
}