tests: test ComputeBlockVersion for all deployments

This generalises the ComputeBlockVersion test so that it can apply to
any activation parameters we might set, and checks all the parameters
set for each deployment on each chain, to simultaneously ensure that the
deployments we have configured work sensibly, and that the test code
does not suffer bitrot in the event that all interesting deployments
are buried.
This commit is contained in:
Anthony Towns committed 2021-04-12 10:47:42 +10:00
1 parent 63879f0a47
commit 5932744450
1 file changed
+71 -35
+71 -35
View File
@@ -252,38 +252,61 @@ static void check_computeblockversion(const Consensus::Params& params, Consensus
int64_t nStartTime = params.vDeployments[dep].nStartTime; int64_t nStartTime = params.vDeployments[dep].nStartTime;
int64_t nTimeout = params.vDeployments[dep].nTimeout; int64_t nTimeout = params.vDeployments[dep].nTimeout;
assert(nStartTime < nTimeout); // 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
if (nStartTime == Consensus::BIP9Deployment::ALWAYS_ACTIVE) return;
BOOST_REQUIRE(nStartTime < nTimeout);
BOOST_REQUIRE(nStartTime >= 0);
BOOST_REQUIRE(nTimeout <= std::numeric_limits<uint32_t>::max() || nTimeout == Consensus::BIP9Deployment::NO_TIMEOUT);
BOOST_REQUIRE(0 <= bit && bit < 32);
BOOST_REQUIRE(((1 << bit) & VERSIONBITS_TOP_MASK) == 0);
// In the first chain, test that the bit is set by CBV until it has failed. // In the first chain, test that the bit is set by CBV until it has failed.
// In the second chain, test the bit is set by CBV while STARTED and // In the second chain, test the bit is set by CBV while STARTED and
// LOCKED-IN, and then no longer set while ACTIVE. // LOCKED-IN, and then no longer set while ACTIVE.
VersionBitsTester firstChain, secondChain; VersionBitsTester firstChain, secondChain;
// Start generating blocks before nStartTime int64_t nTime = nStartTime;
int64_t nTime = nStartTime - 1;
CBlockIndex *lastBlock = nullptr;
// Before MedianTimePast of the chain has crossed nStartTime, the bit // Before MedianTimePast of the chain has crossed nStartTime, the bit
// should not be set. // should not be set.
CBlockIndex *lastBlock = nullptr; if (nTime == 0) {
lastBlock = firstChain.Mine(params.nMinerConfirmationWindow, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip(); // since CBlockIndex::nTime is uint32_t we can't represent any
BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, params) & (1<<bit), 0); // earlier time, so will transition from DEFINED to STARTED at the
// end of the first period by mining blocks at nTime == 0
lastBlock = firstChain.Mine(params.nMinerConfirmationWindow - 1, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, params) & (1<<bit), 0);
lastBlock = firstChain.Mine(params.nMinerConfirmationWindow, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
BOOST_CHECK((ComputeBlockVersion(lastBlock, params) & (1<<bit)) != 0);
// then we'll keep mining at nStartTime...
} else {
// use a time 1s earlier than start time to check we stay DEFINED
--nTime;
// Mine more blocks (4 less than the adjustment period) at the old time, and check that CBV isn't setting the bit yet. // Start generating blocks before nStartTime
for (uint32_t i = 1; i < params.nMinerConfirmationWindow - 4; i++) { lastBlock = firstChain.Mine(params.nMinerConfirmationWindow, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
lastBlock = firstChain.Mine(params.nMinerConfirmationWindow + i, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
// This works because VERSIONBITS_LAST_OLD_BLOCK_VERSION happens
// to be 4, and the bit we're testing happens to be bit 28.
BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, params) & (1<<bit), 0);
}
// Now mine 5 more blocks at the start time -- MTP should not have passed yet, so
// CBV should still not yet set the bit.
nTime = nStartTime;
for (uint32_t i = params.nMinerConfirmationWindow - 4; i <= params.nMinerConfirmationWindow; i++) {
lastBlock = firstChain.Mine(params.nMinerConfirmationWindow + i, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, params) & (1<<bit), 0); BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, params) & (1<<bit), 0);
// Mine more blocks (4 less than the adjustment period) at the old time, and check that CBV isn't setting the bit yet.
for (uint32_t i = 1; i < params.nMinerConfirmationWindow - 4; i++) {
lastBlock = firstChain.Mine(params.nMinerConfirmationWindow + i, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, params) & (1<<bit), 0);
}
// Now mine 5 more blocks at the start time -- MTP should not have passed yet, so
// CBV should still not yet set the bit.
nTime = nStartTime;
for (uint32_t i = params.nMinerConfirmationWindow - 4; i <= params.nMinerConfirmationWindow; i++) {
lastBlock = firstChain.Mine(params.nMinerConfirmationWindow + i, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, params) & (1<<bit), 0);
}
// Next we will advance to the next period and transition to STARTED,
} }
// Advance to the next period and transition to STARTED,
lastBlock = firstChain.Mine(params.nMinerConfirmationWindow * 3, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip(); lastBlock = firstChain.Mine(params.nMinerConfirmationWindow * 3, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
// so ComputeBlockVersion should now set the bit, // so ComputeBlockVersion should now set the bit,
BOOST_CHECK((ComputeBlockVersion(lastBlock, params) & (1<<bit)) != 0); BOOST_CHECK((ComputeBlockVersion(lastBlock, params) & (1<<bit)) != 0);
@@ -304,17 +327,29 @@ static void check_computeblockversion(const Consensus::Params& params, Consensus
nHeight += 1; nHeight += 1;
} }
nTime = nTimeout; if (nTimeout != Consensus::BIP9Deployment::NO_TIMEOUT) {
// FAILED is only triggered at the end of a period, so CBV should be setting // can reach any nTimeout other than NO_TIMEOUT due to earlier BOOST_REQUIRE
// the bit until the period transition.
for (uint32_t i = 0; i < params.nMinerConfirmationWindow - 1; i++) { nTime = nTimeout;
// finish the last period before we start timing out
while (nHeight % params.nMinerConfirmationWindow != 0) {
lastBlock = firstChain.Mine(nHeight+1, nTime - 1, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
BOOST_CHECK((ComputeBlockVersion(lastBlock, params) & (1<<bit)) != 0);
nHeight += 1;
}
// FAILED is only triggered at the end of a period, so CBV should be setting
// the bit until the period transition.
for (uint32_t i = 0; i < params.nMinerConfirmationWindow - 1; i++) {
lastBlock = firstChain.Mine(nHeight+1, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
BOOST_CHECK((ComputeBlockVersion(lastBlock, params) & (1<<bit)) != 0);
nHeight += 1;
}
// The next block should trigger no longer setting the bit.
lastBlock = firstChain.Mine(nHeight+1, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip(); lastBlock = firstChain.Mine(nHeight+1, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
BOOST_CHECK((ComputeBlockVersion(lastBlock, params) & (1<<bit)) != 0); BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, params) & (1<<bit), 0);
nHeight += 1;
} }
// The next block should trigger no longer setting the bit.
lastBlock = firstChain.Mine(nHeight+1, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, params) & (1<<bit), 0);
// On a new chain: // On a new chain:
// verify that the bit will be set after lock-in, and then stop being set // verify that the bit will be set after lock-in, and then stop being set
@@ -338,17 +373,18 @@ static void check_computeblockversion(const Consensus::Params& params, Consensus
BOOST_CHECK((ComputeBlockVersion(lastBlock, params) & (1 << bit)) != 0); BOOST_CHECK((ComputeBlockVersion(lastBlock, params) & (1 << bit)) != 0);
lastBlock = secondChain.Mine(params.nMinerConfirmationWindow * 3, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip(); lastBlock = secondChain.Mine(params.nMinerConfirmationWindow * 3, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, params) & (1<<bit), 0); BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, params) & (1<<bit), 0);
// Finally, verify that after a soft fork has activated, CBV no longer uses
// VERSIONBITS_LAST_OLD_BLOCK_VERSION.
//BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, mainnetParams) & VERSIONBITS_TOP_MASK, VERSIONBITS_TOP_BITS);
} }
BOOST_AUTO_TEST_CASE(versionbits_computeblockversion) BOOST_AUTO_TEST_CASE(versionbits_computeblockversion)
{ {
// Use the TESTDUMMY deployment for testing purposes. // check that any deployment on any chain can conceivably reach both
const auto chainParams = CreateChainParams(*m_node.args, CBaseChainParams::MAIN); // ACTIVE and FAILED states in roughly the way we expect
check_computeblockversion(chainParams->GetConsensus(), Consensus::DEPLOYMENT_TESTDUMMY); for (const auto& chain_name : {CBaseChainParams::MAIN, CBaseChainParams::TESTNET, CBaseChainParams::SIGNET, CBaseChainParams::REGTEST}) {
const auto chainParams = CreateChainParams(*m_node.args, chain_name);
for (int i = 0; i < (int)Consensus::MAX_VERSION_BITS_DEPLOYMENTS; ++i) {
check_computeblockversion(chainParams->GetConsensus(), static_cast<Consensus::DeploymentPos>(i));
}
}
} }
BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END()