versionbits: Add explicit NEVER_ACTIVE deployments

Previously we used deployments that would timeout prior to Bitcoin's
invention, which allowed the deployment to still be activated in unit
tests. This switches those deployments to be truly never active.
This commit is contained in:
Anthony Towns 2021-03-27 23:00:14 +10:00
parent dd07e6da48
commit 55ac5f568a
6 changed files with 48 additions and 41 deletions

View file

@ -81,14 +81,14 @@ public:
consensus.nRuleChangeActivationThreshold = 1916; // 95% of 2016
consensus.nMinerConfirmationWindow = 2016; // nPowTargetTimespan / nPowTargetSpacing
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 28;
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 1199145601; // January 1, 2008
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = 1230767999; // December 31, 2008
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = Consensus::BIP9Deployment::NEVER_ACTIVE;
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT;
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].min_activation_height = 0; // No activation delay
// Deployment of Taproot (BIPs 340-342)
consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].bit = 2;
consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nStartTime = 1199145601; // January 1, 2008
consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nTimeout = 1230767999; // December 31, 2008
consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nStartTime = Consensus::BIP9Deployment::NEVER_ACTIVE;
consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT;
consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].min_activation_height = 0; // No activation delay
consensus.nMinimumChainWork = uint256S("0x00000000000000000000000000000000000000001533efd8d716a517fe2c5008");
@ -200,14 +200,14 @@ public:
consensus.nRuleChangeActivationThreshold = 1512; // 75% for testchains
consensus.nMinerConfirmationWindow = 2016; // nPowTargetTimespan / nPowTargetSpacing
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 28;
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 1199145601; // January 1, 2008
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = 1230767999; // December 31, 2008
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = Consensus::BIP9Deployment::NEVER_ACTIVE;
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT;
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].min_activation_height = 0; // No activation delay
// Deployment of Taproot (BIPs 340-342)
consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].bit = 2;
consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nStartTime = 1199145601; // January 1, 2008
consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nTimeout = 1230767999; // December 31, 2008
consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nStartTime = Consensus::BIP9Deployment::NEVER_ACTIVE;
consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT;
consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].min_activation_height = 0; // No activation delay
consensus.nMinimumChainWork = uint256S("0x0000000000000000000000000000000000000000000001db6ec4ac88cf2272c6");
@ -337,8 +337,8 @@ public:
consensus.MinBIP9WarningHeight = 0;
consensus.powLimit = uint256S("00000377ae000000000000000000000000000000000000000000000000000000");
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 28;
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 1199145601; // January 1, 2008
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = 1230767999; // December 31, 2008
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = Consensus::BIP9Deployment::NEVER_ACTIVE;
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT;
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].min_activation_height = 0; // No activation delay
// Activation of Taproot (BIPs 340-342)

View file

@ -43,6 +43,11 @@ struct BIP9Deployment {
* process (which takes at least 3 BIP9 intervals). Only tests that specifically test the
* behaviour during activation cannot use this. */
static constexpr int64_t ALWAYS_ACTIVE = -1;
/** Special value for nStartTime indicating that the deployment is never active.
* This is useful for integrating the code changes for a new feature
* prior to deploying it on some or all networks. */
static constexpr int64_t NEVER_ACTIVE = -2;
};
/**

View file

@ -1225,10 +1225,8 @@ static void BuriedForkDescPushBack(UniValue& softforks, const std::string &name,
static void BIP9SoftForkDescPushBack(UniValue& softforks, const std::string &name, const Consensus::Params& consensusParams, Consensus::DeploymentPos id) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
// For BIP9 deployments.
// Deployments (e.g. testdummy) with timeout value before Jan 1, 2009 are hidden.
// A timeout value of 0 guarantees a softfork will never be activated.
// This is used when merging logic to implement a proposed softfork without a specified deployment schedule.
if (consensusParams.vDeployments[id].nTimeout <= 1230768000) return;
// Deployments that are never active are hidden.
if (consensusParams.vDeployments[id].nStartTime == Consensus::BIP9Deployment::NEVER_ACTIVE) return;
UniValue bip9(UniValue::VOBJ);
const ThresholdState thresholdState = VersionBitsState(::ChainActive().Tip(), consensusParams, id, versionbitscache);

View file

@ -163,13 +163,12 @@ FUZZ_TARGET_INIT(versionbits, initialize)
} else {
if (fuzzed_data_provider.ConsumeBool()) {
start_time = Consensus::BIP9Deployment::ALWAYS_ACTIVE;
timeout = Consensus::BIP9Deployment::NO_TIMEOUT;
always_active_test = true;
} else {
start_time = 1199145601; // January 1, 2008
timeout = 1230767999; // December 31, 2008
start_time = Consensus::BIP9Deployment::NEVER_ACTIVE;
never_active_test = true;
}
timeout = fuzzed_data_provider.ConsumeBool() ? Consensus::BIP9Deployment::NO_TIMEOUT : fuzzed_data_provider.ConsumeIntegral<int64_t>();
}
int min_activation = fuzzed_data_provider.ConsumeIntegralInRange<int>(0, period * max_periods);
@ -323,7 +322,7 @@ FUZZ_TARGET_INIT(versionbits, initialize)
assert(exp_state == ThresholdState::ACTIVE || exp_state == ThresholdState::LOCKED_IN);
break;
case ThresholdState::FAILED:
assert(current_block->GetMedianTimePast() >= checker.m_end);
assert(never_active_test || current_block->GetMedianTimePast() >= checker.m_end);
assert(exp_state != ThresholdState::LOCKED_IN && exp_state != ThresholdState::ACTIVE);
break;
default:
@ -335,26 +334,20 @@ FUZZ_TARGET_INIT(versionbits, initialize)
assert(state == ThresholdState::ACTIVE || state == ThresholdState::FAILED);
}
// "always active" has additional restrictions
if (always_active_test) {
// "always active" has additional restrictions
assert(state == ThresholdState::ACTIVE);
assert(exp_state == ThresholdState::ACTIVE);
assert(since == 0);
} else if (never_active_test) {
// "never active" does too
assert(state == ThresholdState::FAILED);
assert(exp_state == ThresholdState::FAILED);
assert(since == 0);
} else {
// except for always active, the initial state is always DEFINED
// for signalled deployments, the initial state is always DEFINED
assert(since > 0 || state == ThresholdState::DEFINED);
assert(exp_since > 0 || exp_state == ThresholdState::DEFINED);
}
// "never active" does too
if (never_active_test) {
assert(state == ThresholdState::FAILED);
assert(since == period);
if (exp_since == 0) {
assert(exp_state == ThresholdState::DEFINED);
} else {
assert(exp_state == ThresholdState::FAILED);
}
}
}
} // namespace

View file

@ -59,8 +59,7 @@ public:
class TestNeverActiveConditionChecker : public TestConditionChecker
{
public:
int64_t BeginTime(const Consensus::Params& params) const override { return 0; }
int64_t EndTime(const Consensus::Params& params) const override { return 1230768000; }
int64_t BeginTime(const Consensus::Params& params) const override { return Consensus::BIP9Deployment::NEVER_ACTIVE; }
};
#define CHECKERS 6
@ -134,10 +133,7 @@ public:
BOOST_CHECK_MESSAGE(checker[i].GetStateSinceHeightFor(tip) == height, strprintf("Test %i for StateSinceHeight", num));
BOOST_CHECK_MESSAGE(checker_delayed[i].GetStateSinceHeightFor(tip) == height_delayed, strprintf("Test %i for StateSinceHeight (delayed)", num));
BOOST_CHECK_MESSAGE(checker_always[i].GetStateSinceHeightFor(tip) == 0, strprintf("Test %i for StateSinceHeight (always active)", num));
// never active may go from DEFINED -> FAILED at the first period
const auto never_height = checker_never[i].GetStateSinceHeightFor(tip);
BOOST_CHECK_MESSAGE(never_height == 0 || never_height == checker_never[i].Period(paramsDummy), strprintf("Test %i for StateSinceHeight (never active)", num));
BOOST_CHECK_MESSAGE(checker_never[i].GetStateSinceHeightFor(tip) == 0, strprintf("Test %i for StateSinceHeight (never active)", num));
}
}
num++;
@ -170,7 +166,7 @@ public:
BOOST_CHECK_MESSAGE(got == exp, strprintf("Test %i for %s height %d (got %s)", num, StateName(exp), height, StateName(got)));
BOOST_CHECK_MESSAGE(got_delayed == exp_delayed, strprintf("Test %i for %s height %d (got %s; delayed case)", num, StateName(exp_delayed), height, StateName(got_delayed)));
BOOST_CHECK_MESSAGE(got_always == ThresholdState::ACTIVE, strprintf("Test %i for ACTIVE height %d (got %s; always active case)", num, height, StateName(got_always)));
BOOST_CHECK_MESSAGE(got_never == ThresholdState::DEFINED|| got_never == ThresholdState::FAILED, strprintf("Test %i for DEFINED/FAILED height %d (got %s; never active case)", num, height, StateName(got_never)));
BOOST_CHECK_MESSAGE(got_never == ThresholdState::FAILED, strprintf("Test %i for FAILED height %d (got %s; never active case)", num, height, StateName(got_never)));
}
}
num++;
@ -270,7 +266,7 @@ BOOST_AUTO_TEST_CASE(versionbits_sanity)
// Check min_activation_height is on a retarget boundary
BOOST_CHECK_EQUAL(mainnetParams.vDeployments[i].min_activation_height % mainnetParams.nMinerConfirmationWindow, 0);
// Check min_activation_height is 0 for ALWAYS_ACTIVE and never active deployments
if (mainnetParams.vDeployments[i].nStartTime == Consensus::BIP9Deployment::ALWAYS_ACTIVE || mainnetParams.vDeployments[i].nTimeout <= 1230768000) {
if (mainnetParams.vDeployments[i].nStartTime == Consensus::BIP9Deployment::ALWAYS_ACTIVE || mainnetParams.vDeployments[i].nStartTime == Consensus::BIP9Deployment::NEVER_ACTIVE) {
BOOST_CHECK_EQUAL(mainnetParams.vDeployments[i].min_activation_height, 0);
}
@ -304,8 +300,9 @@ static void check_computeblockversion(const Consensus::Params& params, Consensus
// should not be any signalling for first block
BOOST_CHECK_EQUAL(ComputeBlockVersion(nullptr, params), VERSIONBITS_TOP_BITS);
// always active deployments shouldn't need to be tested further
// always/never active deployments shouldn't need to be tested further
if (nStartTime == Consensus::BIP9Deployment::ALWAYS_ACTIVE) return;
if (nStartTime == Consensus::BIP9Deployment::NEVER_ACTIVE) return;
BOOST_REQUIRE(nStartTime < nTimeout);
BOOST_REQUIRE(nStartTime >= 0);
@ -447,6 +444,15 @@ BOOST_AUTO_TEST_CASE(versionbits_computeblockversion)
}
}
{
// Use regtest/testdummy to ensure we always exercise some
// deployment that's not always/never active
ArgsManager args;
args.ForceSetArg("-vbparams", "testdummy:1199145601:1230767999"); // January 1, 2008 - December 31, 2008
const auto chainParams = CreateChainParams(args, CBaseChainParams::REGTEST);
check_computeblockversion(chainParams->GetConsensus(), Consensus::DEPLOYMENT_TESTDUMMY);
}
{
// Use regtest/testdummy to ensure we always exercise the
// min_activation_height test, even if we're not using that in a

View file

@ -18,6 +18,11 @@ ThresholdState AbstractThresholdConditionChecker::GetStateFor(const CBlockIndex*
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));
@ -129,7 +134,7 @@ BIP9Stats AbstractThresholdConditionChecker::GetStateStatisticsFor(const CBlockI
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) {
if (start_time == Consensus::BIP9Deployment::ALWAYS_ACTIVE || start_time == Consensus::BIP9Deployment::NEVER_ACTIVE) {
return 0;
}