diff --git a/src/test/fuzz/versionbits.cpp b/src/test/fuzz/versionbits.cpp index 4177323233..9186821836 100644 --- a/src/test/fuzz/versionbits.cpp +++ b/src/test/fuzz/versionbits.cpp @@ -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(0, period * (max_periods - 3)); - int end_block = fuzzed_data_provider.ConsumeIntegralInRange(start_block, period * (max_periods - 3)); + int end_block = fuzzed_data_provider.ConsumeIntegralInRange(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); diff --git a/src/test/versionbits_tests.cpp b/src/test/versionbits_tests.cpp index 80072eff9c..05838ec19a 100644 --- a/src/test/versionbits_tests.cpp +++ b/src/test/versionbits_tests.cpp @@ -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 ; } } diff --git a/src/versionbits.cpp b/src/versionbits.cpp index df666c963f..df2ec4e056 100644 --- a/src/versionbits.cpp +++ b/src/versionbits.cpp @@ -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; }