mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-03-12 18:44:59 +01:00
versionbits: Move WarningBits logic from validation to versionbits
This commit is contained in:
parent
5da119e5d0
commit
3bd32c2055
4 changed files with 80 additions and 55 deletions
|
@ -2364,44 +2364,6 @@ DisconnectResult Chainstate::DisconnectBlock(const CBlock& block, const CBlockIn
|
|||
return fClean ? DISCONNECT_OK : DISCONNECT_UNCLEAN;
|
||||
}
|
||||
|
||||
/**
|
||||
* Threshold condition checker that triggers when unknown versionbits are seen on the network.
|
||||
*/
|
||||
class WarningBitsConditionChecker : public AbstractThresholdConditionChecker
|
||||
{
|
||||
private:
|
||||
const ChainstateManager& m_chainman;
|
||||
int m_bit;
|
||||
|
||||
public:
|
||||
explicit WarningBitsConditionChecker(const ChainstateManager& chainman, int bit) : m_chainman{chainman}, m_bit(bit) {}
|
||||
|
||||
int64_t BeginTime() const override { return 0; }
|
||||
int64_t EndTime() const override { return std::numeric_limits<int64_t>::max(); }
|
||||
int Period() const override {
|
||||
if (m_chainman.GetParams().IsTestChain()) {
|
||||
return m_chainman.GetConsensus().DifficultyAdjustmentInterval();
|
||||
} else {
|
||||
return 2016;
|
||||
}
|
||||
}
|
||||
int Threshold() const override {
|
||||
if (m_chainman.GetParams().IsTestChain()) {
|
||||
return m_chainman.GetConsensus().DifficultyAdjustmentInterval() * 3 / 4; // 75% for test nets per BIP9 suggestion
|
||||
} else {
|
||||
return 1815; // 90% threshold used in BIP 341
|
||||
}
|
||||
}
|
||||
|
||||
bool Condition(const CBlockIndex* pindex) const override
|
||||
{
|
||||
return pindex->nHeight >= m_chainman.GetConsensus().MinBIP9WarningHeight &&
|
||||
((pindex->nVersion & VERSIONBITS_TOP_MASK) == VERSIONBITS_TOP_BITS) &&
|
||||
((pindex->nVersion >> m_bit) & 1) != 0 &&
|
||||
((m_chainman.m_versionbitscache.ComputeBlockVersion(pindex->pprev, m_chainman.GetConsensus()) >> m_bit) & 1) == 0;
|
||||
}
|
||||
};
|
||||
|
||||
static unsigned int GetBlockScriptFlags(const CBlockIndex& block_index, const ChainstateManager& chainman)
|
||||
{
|
||||
const Consensus::Params& consensusparams = chainman.GetConsensus();
|
||||
|
@ -3038,17 +3000,13 @@ void Chainstate::UpdateTip(const CBlockIndex* pindexNew)
|
|||
|
||||
std::vector<bilingual_str> warning_messages;
|
||||
if (!m_chainman.IsInitialBlockDownload()) {
|
||||
const CBlockIndex* pindex = pindexNew;
|
||||
for (int bit = 0; bit < VERSIONBITS_NUM_BITS; bit++) {
|
||||
WarningBitsConditionChecker checker(m_chainman, bit);
|
||||
ThresholdState state = checker.GetStateFor(pindex, m_chainman.m_warningcache.at(bit));
|
||||
if (state == ThresholdState::ACTIVE || state == ThresholdState::LOCKED_IN) {
|
||||
const bilingual_str warning = strprintf(_("Unknown new rules activated (versionbit %i)"), bit);
|
||||
if (state == ThresholdState::ACTIVE) {
|
||||
m_chainman.GetNotifications().warningSet(kernel::Warning::UNKNOWN_NEW_RULES_ACTIVATED, warning);
|
||||
} else {
|
||||
warning_messages.push_back(warning);
|
||||
}
|
||||
auto bits = m_chainman.m_versionbitscache.CheckUnknownActivations(pindexNew, m_chainman.GetParams());
|
||||
for (auto [bit, active] : bits) {
|
||||
const bilingual_str warning = strprintf(_("Unknown new rules activated (versionbit %i)"), bit);
|
||||
if (active) {
|
||||
m_chainman.GetNotifications().warningSet(kernel::Warning::UNKNOWN_NEW_RULES_ACTIVATED, warning);
|
||||
} else {
|
||||
warning_messages.push_back(warning);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -935,8 +935,6 @@ private:
|
|||
/** Most recent headers presync progress update, for rate-limiting. */
|
||||
std::chrono::time_point<std::chrono::steady_clock> m_last_presync_update GUARDED_BY(::cs_main) {};
|
||||
|
||||
std::array<ThresholdConditionCache, VERSIONBITS_NUM_BITS> m_warningcache GUARDED_BY(::cs_main);
|
||||
|
||||
//! Return true if a chainstate is considered usable.
|
||||
//!
|
||||
//! This is false when a background validation chainstate has completed its
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
#include <array>
|
||||
#include <map>
|
||||
|
||||
class CChainParams;
|
||||
|
||||
/** What block version to use for new blocks (pre versionbits) */
|
||||
static const int32_t VERSIONBITS_LAST_OLD_BLOCK_VERSION = 4;
|
||||
/** What bits to set in version for versionbits blocks */
|
||||
|
@ -82,6 +84,7 @@ class VersionBitsCache
|
|||
{
|
||||
private:
|
||||
Mutex m_mutex;
|
||||
std::array<ThresholdConditionCache,VERSIONBITS_NUM_BITS> m_warning_caches GUARDED_BY(m_mutex);
|
||||
std::array<ThresholdConditionCache,Consensus::MAX_VERSION_BITS_DEPLOYMENTS> m_caches GUARDED_BY(m_mutex);
|
||||
|
||||
public:
|
||||
|
@ -102,6 +105,11 @@ public:
|
|||
*/
|
||||
int32_t ComputeBlockVersion(const CBlockIndex* pindexPrev, const Consensus::Params& params) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex);
|
||||
|
||||
/** Check for unknown activations
|
||||
* Returns a vector containing the bit number used for signalling and a bool
|
||||
* indicating the deployment is likely to be ACTIVE, rather than merely LOCKED_IN. */
|
||||
std::vector<std::pair<int,bool>> CheckUnknownActivations(const CBlockIndex* pindex, const CChainParams& chainparams) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex);
|
||||
|
||||
void Clear() EXCLUSIVE_LOCKS_REQUIRED(!m_mutex);
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue