versionbits: simplify state transitions
This removes the DEFINED->FAILED transition and changes the STARTED->FAILED transition to only occur if signalling didn't pass the threshold. This ensures that it is always possible for activation to occur, no matter what settings are chosen, or the speed at which blocks are found. Github-Pull: #21377 Rebased-From: f054f6bcd2c2ce5fea84cf8681013f85a444e7ea
This commit is contained in:
parent
3acf0379e0
commit
600357306e
|
@ -144,19 +144,14 @@ void test_one_input(const std::vector<uint8_t>& buffer)
|
|||
// pick the timestamp to switch based on a block
|
||||
// note states will change *after* these blocks because mediantime lags
|
||||
int start_block = fuzzed_data_provider.ConsumeIntegralInRange<int>(0, period * (max_periods - 3));
|
||||
int end_block = fuzzed_data_provider.ConsumeIntegralInRange<int>(start_block, period * (max_periods - 3));
|
||||
int end_block = fuzzed_data_provider.ConsumeIntegralInRange<int>(0, period * (max_periods - 3));
|
||||
|
||||
start_time = block_start_time + start_block * interval;
|
||||
timeout = block_start_time + end_block * interval;
|
||||
|
||||
assert(start_time <= timeout);
|
||||
|
||||
// allow for times to not exactly match a block
|
||||
if (fuzzed_data_provider.ConsumeBool()) start_time += interval / 2;
|
||||
if (fuzzed_data_provider.ConsumeBool()) timeout += interval / 2;
|
||||
|
||||
// this may make timeout too early; if so, don't run the test
|
||||
if (start_time > timeout) return;
|
||||
} else {
|
||||
if (fuzzed_data_provider.ConsumeBool()) {
|
||||
start_time = Consensus::BIP9Deployment::ALWAYS_ACTIVE;
|
||||
|
@ -292,13 +287,12 @@ void test_one_input(const std::vector<uint8_t>& buffer)
|
|||
assert(since == 0);
|
||||
assert(exp_state == ThresholdState::DEFINED);
|
||||
assert(current_block->GetMedianTimePast() < checker.m_begin);
|
||||
assert(current_block->GetMedianTimePast() < checker.m_end);
|
||||
break;
|
||||
case ThresholdState::STARTED:
|
||||
assert(current_block->GetMedianTimePast() >= checker.m_begin);
|
||||
assert(current_block->GetMedianTimePast() < checker.m_end);
|
||||
if (exp_state == ThresholdState::STARTED) {
|
||||
assert(blocks_sig < threshold);
|
||||
assert(current_block->GetMedianTimePast() < checker.m_end);
|
||||
} else {
|
||||
assert(exp_state == ThresholdState::DEFINED);
|
||||
}
|
||||
|
@ -308,7 +302,6 @@ void test_one_input(const std::vector<uint8_t>& buffer)
|
|||
assert(current_block->nHeight + 1 < min_activation);
|
||||
} else {
|
||||
assert(exp_state == ThresholdState::STARTED);
|
||||
assert(current_block->GetMedianTimePast() < checker.m_end);
|
||||
assert(blocks_sig >= threshold);
|
||||
}
|
||||
break;
|
||||
|
@ -318,7 +311,11 @@ void test_one_input(const std::vector<uint8_t>& buffer)
|
|||
break;
|
||||
case ThresholdState::FAILED:
|
||||
assert(never_active_test || current_block->GetMedianTimePast() >= checker.m_end);
|
||||
assert(exp_state != ThresholdState::LOCKED_IN && exp_state != ThresholdState::ACTIVE);
|
||||
if (exp_state == ThresholdState::STARTED) {
|
||||
assert(blocks_sig < threshold);
|
||||
} else {
|
||||
assert(exp_state == ThresholdState::FAILED);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
|
|
|
@ -190,18 +190,20 @@ BOOST_FIXTURE_TEST_SUITE(versionbits_tests, TestingSetup)
|
|||
BOOST_AUTO_TEST_CASE(versionbits_test)
|
||||
{
|
||||
for (int i = 0; i < 64; i++) {
|
||||
// DEFINED -> FAILED
|
||||
// DEFINED -> STARTED after timeout reached -> FAILED
|
||||
VersionBitsTester().TestDefined().TestStateSinceHeight(0)
|
||||
.Mine(1, TestTime(1), 0x100).TestDefined().TestStateSinceHeight(0)
|
||||
.Mine(11, TestTime(11), 0x100).TestDefined().TestStateSinceHeight(0)
|
||||
.Mine(989, TestTime(989), 0x100).TestDefined().TestStateSinceHeight(0)
|
||||
.Mine(999, TestTime(20000), 0x100).TestDefined().TestStateSinceHeight(0)
|
||||
.Mine(1000, TestTime(20000), 0x100).TestFailed().TestStateSinceHeight(1000)
|
||||
.Mine(1999, TestTime(30001), 0x100).TestFailed().TestStateSinceHeight(1000)
|
||||
.Mine(2000, TestTime(30002), 0x100).TestFailed().TestStateSinceHeight(1000)
|
||||
.Mine(2001, TestTime(30003), 0x100).TestFailed().TestStateSinceHeight(1000)
|
||||
.Mine(2999, TestTime(30004), 0x100).TestFailed().TestStateSinceHeight(1000)
|
||||
.Mine(3000, TestTime(30005), 0x100).TestFailed().TestStateSinceHeight(1000)
|
||||
.Mine(999, TestTime(20000), 0x100).TestDefined().TestStateSinceHeight(0) // Timeout and start time reached simultaneously
|
||||
.Mine(1000, TestTime(20000), 0).TestStarted().TestStateSinceHeight(1000) // Hit started, stop signalling
|
||||
.Mine(1999, TestTime(30001), 0).TestStarted().TestStateSinceHeight(1000)
|
||||
.Mine(2000, TestTime(30002), 0x100).TestFailed().TestStateSinceHeight(2000) // Hit failed, start signalling again
|
||||
.Mine(2001, TestTime(30003), 0x100).TestFailed().TestStateSinceHeight(2000)
|
||||
.Mine(2999, TestTime(30004), 0x100).TestFailed().TestStateSinceHeight(2000)
|
||||
.Mine(3000, TestTime(30005), 0x100).TestFailed().TestStateSinceHeight(2000)
|
||||
.Mine(4000, TestTime(30006), 0x100).TestFailed().TestStateSinceHeight(2000)
|
||||
|
||||
// DEFINED -> STARTED -> FAILED
|
||||
.Reset().TestDefined().TestStateSinceHeight(0)
|
||||
.Mine(1, TestTime(1), 0).TestDefined().TestStateSinceHeight(0)
|
||||
|
@ -212,19 +214,19 @@ BOOST_AUTO_TEST_CASE(versionbits_test)
|
|||
.Mine(3000, TestTime(20000), 0).TestFailed().TestStateSinceHeight(3000) // 50 old blocks (so 899 out of the past 1000)
|
||||
.Mine(4000, TestTime(20010), 0x100).TestFailed().TestStateSinceHeight(3000)
|
||||
|
||||
// DEFINED -> STARTED -> FAILED while threshold reached
|
||||
// DEFINED -> STARTED -> LOCKEDIN after timeout reached -> ACTIVE
|
||||
.Reset().TestDefined().TestStateSinceHeight(0)
|
||||
.Mine(1, TestTime(1), 0).TestDefined().TestStateSinceHeight(0)
|
||||
.Mine(1000, TestTime(10000) - 1, 0x101).TestDefined().TestStateSinceHeight(0) // One second more and it would be defined
|
||||
.Mine(2000, TestTime(10000), 0x101).TestStarted().TestStateSinceHeight(2000) // So that's what happens the next period
|
||||
.Mine(2999, TestTime(30000), 0x100).TestStarted().TestStateSinceHeight(2000) // 999 new blocks
|
||||
.Mine(3000, TestTime(30000), 0x100).TestFailed().TestStateSinceHeight(3000) // 1 new block (so 1000 out of the past 1000 are new)
|
||||
.Mine(3999, TestTime(30001), 0).TestFailed().TestStateSinceHeight(3000)
|
||||
.Mine(4000, TestTime(30002), 0).TestFailed().TestStateSinceHeight(3000)
|
||||
.Mine(14333, TestTime(30003), 0).TestFailed().TestStateSinceHeight(3000)
|
||||
.Mine(24000, TestTime(40000), 0).TestFailed().TestStateSinceHeight(3000)
|
||||
.Mine(3000, TestTime(30000), 0x100).TestLockedIn().TestStateSinceHeight(3000) // 1 new block (so 1000 out of the past 1000 are new)
|
||||
.Mine(3999, TestTime(30001), 0).TestLockedIn().TestStateSinceHeight(3000)
|
||||
.Mine(4000, TestTime(30002), 0).TestActiveDelayed().TestStateSinceHeight(4000, 3000)
|
||||
.Mine(14333, TestTime(30003), 0).TestActiveDelayed().TestStateSinceHeight(4000, 3000)
|
||||
.Mine(24000, TestTime(40000), 0).TestActive().TestStateSinceHeight(4000, 15000)
|
||||
|
||||
// DEFINED -> STARTED -> LOCKEDIN at the last minute -> ACTIVE
|
||||
// DEFINED -> STARTED -> LOCKEDIN before timeout -> ACTIVE
|
||||
.Reset().TestDefined()
|
||||
.Mine(1, TestTime(1), 0).TestDefined().TestStateSinceHeight(0)
|
||||
.Mine(1000, TestTime(10000) - 1, 0x101).TestDefined().TestStateSinceHeight(0) // One second more and it would be defined
|
||||
|
@ -247,8 +249,10 @@ BOOST_AUTO_TEST_CASE(versionbits_test)
|
|||
.Mine(3000, TestTime(10000), 0).TestStarted().TestStateSinceHeight(3000)
|
||||
.Mine(4000, TestTime(10000), 0).TestStarted().TestStateSinceHeight(3000)
|
||||
.Mine(5000, TestTime(10000), 0).TestStarted().TestStateSinceHeight(3000)
|
||||
.Mine(5999, TestTime(20000), 0).TestStarted().TestStateSinceHeight(3000)
|
||||
.Mine(6000, TestTime(20000), 0).TestFailed().TestStateSinceHeight(6000)
|
||||
.Mine(7000, TestTime(20000), 0x100).TestFailed().TestStateSinceHeight(6000)
|
||||
.Mine(24000, TestTime(20000), 0x100).TestFailed().TestStateSinceHeight(6000) // stay in FAILED no matter how much we signal
|
||||
;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -57,18 +57,12 @@ ThresholdState AbstractThresholdConditionChecker::GetStateFor(const CBlockIndex*
|
|||
|
||||
switch (state) {
|
||||
case ThresholdState::DEFINED: {
|
||||
if (pindexPrev->GetMedianTimePast() >= nTimeTimeout) {
|
||||
stateNext = ThresholdState::FAILED;
|
||||
} else if (pindexPrev->GetMedianTimePast() >= nTimeStart) {
|
||||
if (pindexPrev->GetMedianTimePast() >= nTimeStart) {
|
||||
stateNext = ThresholdState::STARTED;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ThresholdState::STARTED: {
|
||||
if (pindexPrev->GetMedianTimePast() >= nTimeTimeout) {
|
||||
stateNext = ThresholdState::FAILED;
|
||||
break;
|
||||
}
|
||||
// We need to count
|
||||
const CBlockIndex* pindexCount = pindexPrev;
|
||||
int count = 0;
|
||||
|
@ -80,6 +74,8 @@ ThresholdState AbstractThresholdConditionChecker::GetStateFor(const CBlockIndex*
|
|||
}
|
||||
if (count >= nThreshold) {
|
||||
stateNext = ThresholdState::LOCKED_IN;
|
||||
} else if (pindexPrev->GetMedianTimePast() >= nTimeTimeout) {
|
||||
stateNext = ThresholdState::FAILED;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue