aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnthony Towns <aj@erisian.com.au>2021-04-07 10:20:46 +1000
committerAndrew Chow <achow101-github@achow101.com>2021-04-15 20:59:17 -0400
commit600357306e2e182a457174862ea2e41c7ba39c64 (patch)
tree693bb010f1d57671469e536456356d3149de8d64
parent3acf0379e0979ea4bdd03976f4987aa6711eb92f (diff)
downloadbitcoin-600357306e2e182a457174862ea2e41c7ba39c64.tar.xz
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
-rw-r--r--src/test/fuzz/versionbits.cpp17
-rw-r--r--src/test/versionbits_tests.cpp34
-rw-r--r--src/versionbits.cpp10
3 files changed, 29 insertions, 32 deletions
diff --git a/src/test/fuzz/versionbits.cpp b/src/test/fuzz/versionbits.cpp
index 5d859c911c..645c0d23c0 100644
--- a/src/test/fuzz/versionbits.cpp
+++ b/src/test/fuzz/versionbits.cpp
@@ -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);
diff --git a/src/test/versionbits_tests.cpp b/src/test/versionbits_tests.cpp
index 0bf5bce27f..774c5670cb 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;
}