mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-02-08 10:31:50 -05:00
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.
This commit is contained in:
parent
55ac5f568a
commit
f054f6bcd2
3 changed files with 29 additions and 32 deletions
|
@ -147,19 +147,14 @@ FUZZ_TARGET_INIT(versionbits, initialize)
|
|||
// 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;
|
||||
|
@ -297,13 +292,12 @@ FUZZ_TARGET_INIT(versionbits, initialize)
|
|||
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);
|
||||
}
|
||||
|
@ -313,7 +307,6 @@ FUZZ_TARGET_INIT(versionbits, initialize)
|
|||
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;
|
||||
|
@ -323,7 +316,11 @@ FUZZ_TARGET_INIT(versionbits, initialize)
|
|||
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…
Add table
Reference in a new issue