2021-12-30 19:36:57 +02:00
// Copyright (c) 2014-2021 The Bitcoin Core developers
2016-02-20 02:57:36 +01:00
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
2017-11-10 13:57:53 +13:00
# include <chain.h>
# include <chainparams.h>
# include <consensus/params.h>
2020-07-03 04:01:23 +10:00
# include <deploymentstatus.h>
2020-04-16 13:11:54 -04:00
# include <test/util/setup_common.h>
# include <validation.h>
# include <versionbits.h>
2016-02-20 02:57:36 +01:00
# include <boost/test/unit_test.hpp>
/* Define a virtual block time, one block per 10 minutes after Nov 14 2014, 0:55:36am */
2018-05-02 17:14:48 +02:00
static int32_t TestTime ( int nHeight ) { return 1415926536 + 600 * nHeight ; }
2016-02-20 02:57:36 +01:00
2020-10-19 20:49:42 +10:00
static const std : : string StateName ( ThresholdState state )
{
switch ( state ) {
case ThresholdState : : DEFINED : return " DEFINED " ;
case ThresholdState : : STARTED : return " STARTED " ;
case ThresholdState : : LOCKED_IN : return " LOCKED_IN " ;
case ThresholdState : : ACTIVE : return " ACTIVE " ;
case ThresholdState : : FAILED : return " FAILED " ;
} // no default case, so the compiler can warn about missing cases
return " " ;
}
2016-02-20 02:57:36 +01:00
static const Consensus : : Params paramsDummy = Consensus : : Params ( ) ;
class TestConditionChecker : public AbstractThresholdConditionChecker
{
private :
mutable ThresholdConditionCache cache ;
public :
2017-06-20 21:58:56 +02:00
int64_t BeginTime ( const Consensus : : Params & params ) const override { return TestTime ( 10000 ) ; }
int64_t EndTime ( const Consensus : : Params & params ) const override { return TestTime ( 20000 ) ; }
int Period ( const Consensus : : Params & params ) const override { return 1000 ; }
int Threshold ( const Consensus : : Params & params ) const override { return 900 ; }
bool Condition ( const CBlockIndex * pindex , const Consensus : : Params & params ) const override { return ( pindex - > nVersion & 0x100 ) ; }
2016-02-20 02:57:36 +01:00
ThresholdState GetStateFor ( const CBlockIndex * pindexPrev ) const { return AbstractThresholdConditionChecker : : GetStateFor ( pindexPrev , paramsDummy , cache ) ; }
2016-05-06 22:08:39 +00:00
int GetStateSinceHeightFor ( const CBlockIndex * pindexPrev ) const { return AbstractThresholdConditionChecker : : GetStateSinceHeightFor ( pindexPrev , paramsDummy , cache ) ; }
2016-02-20 02:57:36 +01:00
} ;
2021-04-07 11:37:47 +10:00
class TestDelayedActivationConditionChecker : public TestConditionChecker
{
public :
int MinActivationHeight ( const Consensus : : Params & params ) const override { return 15000 ; }
} ;
2017-10-17 18:24:46 +10:00
class TestAlwaysActiveConditionChecker : public TestConditionChecker
{
public :
int64_t BeginTime ( const Consensus : : Params & params ) const override { return Consensus : : BIP9Deployment : : ALWAYS_ACTIVE ; }
} ;
2020-10-19 22:59:50 +10:00
class TestNeverActiveConditionChecker : public TestConditionChecker
{
public :
2021-03-27 23:00:14 +10:00
int64_t BeginTime ( const Consensus : : Params & params ) const override { return Consensus : : BIP9Deployment : : NEVER_ACTIVE ; }
2020-10-19 22:59:50 +10:00
} ;
2016-02-20 02:57:36 +01:00
# define CHECKERS 6
class VersionBitsTester
{
// A fake blockchain
std : : vector < CBlockIndex * > vpblock ;
// 6 independent checkers for the same bit.
// The first one performs all checks, the second only 50%, the third only 25%, etc...
// This is to test whether lack of cached information leads to the same results.
TestConditionChecker checker [ CHECKERS ] ;
2021-04-07 11:37:47 +10:00
// Another 6 that assume delayed activation
TestDelayedActivationConditionChecker checker_delayed [ CHECKERS ] ;
2017-10-17 18:24:46 +10:00
// Another 6 that assume always active activation
TestAlwaysActiveConditionChecker checker_always [ CHECKERS ] ;
2020-10-19 22:59:50 +10:00
// Another 6 that assume never active activation
TestNeverActiveConditionChecker checker_never [ CHECKERS ] ;
2016-02-20 02:57:36 +01:00
// Test counter (to identify failures)
2021-04-17 10:27:16 +02:00
int num { 1000 } ;
2016-02-20 02:57:36 +01:00
public :
VersionBitsTester & Reset ( ) {
2021-04-07 11:37:47 +10:00
// Have each group of tests be counted by the 1000s part, starting at 1000
num = num - ( num % 1000 ) + 1000 ;
2016-02-20 02:57:36 +01:00
for ( unsigned int i = 0 ; i < vpblock . size ( ) ; i + + ) {
delete vpblock [ i ] ;
}
for ( unsigned int i = 0 ; i < CHECKERS ; i + + ) {
checker [ i ] = TestConditionChecker ( ) ;
2021-04-07 11:37:47 +10:00
checker_delayed [ i ] = TestDelayedActivationConditionChecker ( ) ;
2017-10-17 18:24:46 +10:00
checker_always [ i ] = TestAlwaysActiveConditionChecker ( ) ;
2020-10-19 22:59:50 +10:00
checker_never [ i ] = TestNeverActiveConditionChecker ( ) ;
2016-02-20 02:57:36 +01:00
}
vpblock . clear ( ) ;
return * this ;
}
~ VersionBitsTester ( ) {
Reset ( ) ;
}
VersionBitsTester & Mine ( unsigned int height , int32_t nTime , int32_t nVersion ) {
while ( vpblock . size ( ) < height ) {
CBlockIndex * pindex = new CBlockIndex ( ) ;
pindex - > nHeight = vpblock . size ( ) ;
2021-03-28 00:07:49 +10:00
pindex - > pprev = Tip ( ) ;
2016-02-20 02:57:36 +01:00
pindex - > nTime = nTime ;
pindex - > nVersion = nVersion ;
pindex - > BuildSkip ( ) ;
vpblock . push_back ( pindex ) ;
}
return * this ;
}
2021-04-07 11:37:47 +10:00
VersionBitsTester & TestStateSinceHeight ( int height )
{
return TestStateSinceHeight ( height , height ) ;
}
VersionBitsTester & TestStateSinceHeight ( int height , int height_delayed )
{
2021-03-28 00:07:49 +10:00
const CBlockIndex * tip = Tip ( ) ;
2016-05-06 22:08:39 +00:00
for ( int i = 0 ; i < CHECKERS ; i + + ) {
2017-06-07 12:03:17 -07:00
if ( InsecureRandBits ( i ) = = 0 ) {
2021-03-28 00:07:49 +10:00
BOOST_CHECK_MESSAGE ( checker [ i ] . GetStateSinceHeightFor ( tip ) = = height , strprintf ( " Test %i for StateSinceHeight " , num ) ) ;
2021-04-07 11:37:47 +10:00
BOOST_CHECK_MESSAGE ( checker_delayed [ i ] . GetStateSinceHeightFor ( tip ) = = height_delayed , strprintf ( " Test %i for StateSinceHeight (delayed) " , num ) ) ;
2021-03-28 00:07:49 +10:00
BOOST_CHECK_MESSAGE ( checker_always [ i ] . GetStateSinceHeightFor ( tip ) = = 0 , strprintf ( " Test %i for StateSinceHeight (always active) " , num ) ) ;
2021-03-27 23:00:14 +10:00
BOOST_CHECK_MESSAGE ( checker_never [ i ] . GetStateSinceHeightFor ( tip ) = = 0 , strprintf ( " Test %i for StateSinceHeight (never active) " , num ) ) ;
2016-05-06 22:08:39 +00:00
}
}
num + + ;
return * this ;
}
2021-04-07 11:37:47 +10:00
VersionBitsTester & TestState ( ThresholdState exp )
{
return TestState ( exp , exp ) ;
}
VersionBitsTester & TestState ( ThresholdState exp , ThresholdState exp_delayed )
{
if ( exp ! = exp_delayed ) {
// only expected differences are that delayed stays in locked_in longer
BOOST_CHECK_EQUAL ( exp , ThresholdState : : ACTIVE ) ;
BOOST_CHECK_EQUAL ( exp_delayed , ThresholdState : : LOCKED_IN ) ;
}
2021-03-28 00:07:49 +10:00
const CBlockIndex * pindex = Tip ( ) ;
2016-02-20 02:57:36 +01:00
for ( int i = 0 ; i < CHECKERS ; i + + ) {
2017-06-07 12:03:17 -07:00
if ( InsecureRandBits ( i ) = = 0 ) {
2020-10-19 20:49:42 +10:00
ThresholdState got = checker [ i ] . GetStateFor ( pindex ) ;
2021-04-07 11:37:47 +10:00
ThresholdState got_delayed = checker_delayed [ i ] . GetStateFor ( pindex ) ;
2020-10-19 20:49:42 +10:00
ThresholdState got_always = checker_always [ i ] . GetStateFor ( pindex ) ;
2020-10-19 22:59:50 +10:00
ThresholdState got_never = checker_never [ i ] . GetStateFor ( pindex ) ;
2020-10-19 20:49:42 +10:00
// nHeight of the next block. If vpblock is empty, the next (ie first)
// block should be the genesis block with nHeight == 0.
int height = pindex = = nullptr ? 0 : pindex - > nHeight + 1 ;
BOOST_CHECK_MESSAGE ( got = = exp , strprintf ( " Test %i for %s height %d (got %s) " , num , StateName ( exp ) , height , StateName ( got ) ) ) ;
2021-04-07 11:37:47 +10:00
BOOST_CHECK_MESSAGE ( got_delayed = = exp_delayed , strprintf ( " Test %i for %s height %d (got %s; delayed case) " , num , StateName ( exp_delayed ) , height , StateName ( got_delayed ) ) ) ;
2020-10-19 20:49:42 +10:00
BOOST_CHECK_MESSAGE ( got_always = = ThresholdState : : ACTIVE , strprintf ( " Test %i for ACTIVE height %d (got %s; always active case) " , num , height , StateName ( got_always ) ) ) ;
2021-03-27 23:00:14 +10:00
BOOST_CHECK_MESSAGE ( got_never = = ThresholdState : : FAILED , strprintf ( " Test %i for FAILED height %d (got %s; never active case) " , num , height , StateName ( got_never ) ) ) ;
2016-02-20 02:57:36 +01:00
}
}
num + + ;
return * this ;
}
2020-10-19 20:49:42 +10:00
VersionBitsTester & TestDefined ( ) { return TestState ( ThresholdState : : DEFINED ) ; }
VersionBitsTester & TestStarted ( ) { return TestState ( ThresholdState : : STARTED ) ; }
VersionBitsTester & TestLockedIn ( ) { return TestState ( ThresholdState : : LOCKED_IN ) ; }
VersionBitsTester & TestActive ( ) { return TestState ( ThresholdState : : ACTIVE ) ; }
VersionBitsTester & TestFailed ( ) { return TestState ( ThresholdState : : FAILED ) ; }
2016-03-09 16:00:53 -05:00
2021-04-07 11:37:47 +10:00
// non-delayed should be active; delayed should still be locked in
VersionBitsTester & TestActiveDelayed ( ) { return TestState ( ThresholdState : : ACTIVE , ThresholdState : : LOCKED_IN ) ; }
2021-03-28 00:07:49 +10:00
CBlockIndex * Tip ( ) { return vpblock . empty ( ) ? nullptr : vpblock . back ( ) ; }
2016-02-20 02:57:36 +01:00
} ;
BOOST_FIXTURE_TEST_SUITE ( versionbits_tests , TestingSetup )
BOOST_AUTO_TEST_CASE ( versionbits_test )
{
for ( int i = 0 ; i < 64 ; i + + ) {
2021-04-07 10:20:46 +10:00
// DEFINED -> STARTED after timeout reached -> FAILED
2016-05-06 22:08:39 +00:00
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 )
2021-04-07 10:20:46 +10:00
. 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 )
2016-02-20 02:57:36 +01:00
// DEFINED -> STARTED -> FAILED
2016-05-06 22:08:39 +00:00
. Reset ( ) . TestDefined ( ) . TestStateSinceHeight ( 0 )
. Mine ( 1 , TestTime ( 1 ) , 0 ) . TestDefined ( ) . TestStateSinceHeight ( 0 )
. Mine ( 1000 , TestTime ( 10000 ) - 1 , 0x100 ) . TestDefined ( ) . TestStateSinceHeight ( 0 ) // One second more and it would be defined
. Mine ( 2000 , TestTime ( 10000 ) , 0x100 ) . TestStarted ( ) . TestStateSinceHeight ( 2000 ) // So that's what happens the next period
. Mine ( 2051 , TestTime ( 10010 ) , 0 ) . TestStarted ( ) . TestStateSinceHeight ( 2000 ) // 51 old blocks
. Mine ( 2950 , TestTime ( 10020 ) , 0x100 ) . TestStarted ( ) . TestStateSinceHeight ( 2000 ) // 899 new blocks
. 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 )
2016-02-20 02:57:36 +01:00
2021-04-07 10:20:46 +10:00
// DEFINED -> STARTED -> LOCKEDIN after timeout reached -> ACTIVE
2016-05-06 22:08:39 +00:00
. 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
2021-04-07 10:20:46 +10:00
. 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 )
2016-02-20 02:57:36 +01:00
2021-04-07 10:20:46 +10:00
// DEFINED -> STARTED -> LOCKEDIN before timeout -> ACTIVE
2016-02-20 02:57:36 +01:00
. Reset ( ) . TestDefined ( )
2016-05-06 22:08:39 +00:00
. 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 ( 2050 , TestTime ( 10010 ) , 0x200 ) . TestStarted ( ) . TestStateSinceHeight ( 2000 ) // 50 old blocks
. Mine ( 2950 , TestTime ( 10020 ) , 0x100 ) . TestStarted ( ) . TestStateSinceHeight ( 2000 ) // 900 new blocks
. Mine ( 2999 , TestTime ( 19999 ) , 0x200 ) . TestStarted ( ) . TestStateSinceHeight ( 2000 ) // 49 old blocks
. Mine ( 3000 , TestTime ( 29999 ) , 0x200 ) . TestLockedIn ( ) . TestStateSinceHeight ( 3000 ) // 1 old block (so 900 out of the past 1000)
. Mine ( 3999 , TestTime ( 30001 ) , 0 ) . TestLockedIn ( ) . TestStateSinceHeight ( 3000 )
2021-04-07 11:37:47 +10:00
. Mine ( 4000 , TestTime ( 30002 ) , 0 ) . TestActiveDelayed ( ) . TestStateSinceHeight ( 4000 , 3000 ) // delayed will not become active until height=15000
. Mine ( 14333 , TestTime ( 30003 ) , 0 ) . TestActiveDelayed ( ) . TestStateSinceHeight ( 4000 , 3000 )
. Mine ( 15000 , TestTime ( 40000 ) , 0 ) . TestActive ( ) . TestStateSinceHeight ( 4000 , 15000 )
. Mine ( 24000 , TestTime ( 40000 ) , 0 ) . TestActive ( ) . TestStateSinceHeight ( 4000 , 15000 )
2016-05-06 22:08:39 +00:00
// DEFINED multiple periods -> STARTED multiple periods -> FAILED
. Reset ( ) . TestDefined ( ) . TestStateSinceHeight ( 0 )
. Mine ( 999 , TestTime ( 999 ) , 0 ) . TestDefined ( ) . TestStateSinceHeight ( 0 )
. Mine ( 1000 , TestTime ( 1000 ) , 0 ) . TestDefined ( ) . TestStateSinceHeight ( 0 )
. Mine ( 2000 , TestTime ( 2000 ) , 0 ) . TestDefined ( ) . TestStateSinceHeight ( 0 )
. Mine ( 3000 , TestTime ( 10000 ) , 0 ) . TestStarted ( ) . TestStateSinceHeight ( 3000 )
. Mine ( 4000 , TestTime ( 10000 ) , 0 ) . TestStarted ( ) . TestStateSinceHeight ( 3000 )
. Mine ( 5000 , TestTime ( 10000 ) , 0 ) . TestStarted ( ) . TestStateSinceHeight ( 3000 )
2021-04-07 10:20:46 +10:00
. Mine ( 5999 , TestTime ( 20000 ) , 0 ) . TestStarted ( ) . TestStateSinceHeight ( 3000 )
2016-05-06 22:08:39 +00:00
. Mine ( 6000 , TestTime ( 20000 ) , 0 ) . TestFailed ( ) . TestStateSinceHeight ( 6000 )
2021-04-07 11:37:47 +10:00
. Mine ( 7000 , TestTime ( 20000 ) , 0x100 ) . TestFailed ( ) . TestStateSinceHeight ( 6000 )
2021-04-07 10:20:46 +10:00
. Mine ( 24000 , TestTime ( 20000 ) , 0x100 ) . TestFailed ( ) . TestStateSinceHeight ( 6000 ) // stay in FAILED no matter how much we signal
2021-04-07 11:37:47 +10:00
;
2016-02-20 02:57:36 +01:00
}
2021-03-28 00:07:49 +10:00
}
2016-03-09 09:48:20 -05:00
2021-03-27 20:17:56 +10:00
/** Check that ComputeBlockVersion will set the appropriate bit correctly */
static void check_computeblockversion ( const Consensus : : Params & params , Consensus : : DeploymentPos dep )
2016-03-09 16:00:53 -05:00
{
2021-06-11 06:59:53 +10:00
// This implicitly uses g_versionbitscache, so clear it every time
g_versionbitscache . Clear ( ) ;
2016-03-09 16:00:53 -05:00
2021-03-27 20:17:56 +10:00
int64_t bit = params . vDeployments [ dep ] . bit ;
int64_t nStartTime = params . vDeployments [ dep ] . nStartTime ;
int64_t nTimeout = params . vDeployments [ dep ] . nTimeout ;
2021-03-06 18:18:49 +10:00
int min_activation_height = params . vDeployments [ dep ] . min_activation_height ;
2016-03-09 16:00:53 -05:00
2021-03-28 03:10:48 +10:00
// should not be any signalling for first block
2021-06-07 14:58:54 +10:00
BOOST_CHECK_EQUAL ( g_versionbitscache . ComputeBlockVersion ( nullptr , params ) , VERSIONBITS_TOP_BITS ) ;
2021-03-28 03:10:48 +10:00
2021-03-27 23:00:14 +10:00
// always/never active deployments shouldn't need to be tested further
2021-04-15 12:50:09 +02:00
if ( nStartTime = = Consensus : : BIP9Deployment : : ALWAYS_ACTIVE | |
nStartTime = = Consensus : : BIP9Deployment : : NEVER_ACTIVE )
{
BOOST_CHECK_EQUAL ( min_activation_height , 0 ) ;
return ;
}
2021-03-28 03:10:48 +10:00
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 ) ;
2021-04-15 12:50:09 +02:00
// Make sure that no deployment tries to set an invalid bit.
2021-03-28 03:10:48 +10:00
BOOST_REQUIRE ( ( ( 1 < < bit ) & VERSIONBITS_TOP_MASK ) = = 0 ) ;
2021-04-07 11:37:47 +10:00
BOOST_REQUIRE ( min_activation_height > = 0 ) ;
2021-04-15 12:50:09 +02:00
// Check min_activation_height is on a retarget boundary
2021-04-17 10:27:16 +02:00
BOOST_REQUIRE_EQUAL ( min_activation_height % params . nMinerConfirmationWindow , 0U ) ;
2016-03-09 16:00:53 -05:00
2020-12-29 11:19:06 +10:00
const uint32_t bitmask { g_versionbitscache . Mask ( params , dep ) } ;
2021-04-15 12:50:09 +02:00
BOOST_CHECK_EQUAL ( bitmask , uint32_t { 1 } < < bit ) ;
2016-03-09 16:00:53 -05:00
// 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
// LOCKED-IN, and then no longer set while ACTIVE.
VersionBitsTester firstChain , secondChain ;
2021-03-28 03:10:48 +10:00
int64_t nTime = nStartTime ;
2016-03-09 16:00:53 -05:00
2021-03-28 00:07:49 +10:00
const CBlockIndex * lastBlock = nullptr ;
2016-03-09 16:00:53 -05:00
2021-03-28 03:10:48 +10:00
// Before MedianTimePast of the chain has crossed nStartTime, the bit
// should not be set.
if ( nTime = = 0 ) {
// since CBlockIndex::nTime is uint32_t we can't represent any
// 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 ( ) ;
2021-06-07 14:58:54 +10:00
BOOST_CHECK_EQUAL ( g_versionbitscache . ComputeBlockVersion ( lastBlock , params ) & ( 1 < < bit ) , 0 ) ;
2021-03-28 03:10:48 +10:00
lastBlock = firstChain . Mine ( params . nMinerConfirmationWindow , nTime , VERSIONBITS_LAST_OLD_BLOCK_VERSION ) . Tip ( ) ;
2021-06-07 14:58:54 +10:00
BOOST_CHECK ( ( g_versionbitscache . ComputeBlockVersion ( lastBlock , params ) & ( 1 < < bit ) ) ! = 0 ) ;
2021-03-28 03:10:48 +10:00
// then we'll keep mining at nStartTime...
} else {
// use a time 1s earlier than start time to check we stay DEFINED
- - nTime ;
// Start generating blocks before nStartTime
lastBlock = firstChain . Mine ( params . nMinerConfirmationWindow , nTime , VERSIONBITS_LAST_OLD_BLOCK_VERSION ) . Tip ( ) ;
2021-06-07 14:58:54 +10:00
BOOST_CHECK_EQUAL ( g_versionbitscache . ComputeBlockVersion ( lastBlock , params ) & ( 1 < < bit ) , 0 ) ;
2021-03-28 03:10:48 +10:00
// 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 ( ) ;
2021-06-07 14:58:54 +10:00
BOOST_CHECK_EQUAL ( g_versionbitscache . ComputeBlockVersion ( lastBlock , params ) & ( 1 < < bit ) , 0 ) ;
2021-03-28 03:10:48 +10:00
}
// 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 ( ) ;
2021-06-07 14:58:54 +10:00
BOOST_CHECK_EQUAL ( g_versionbitscache . ComputeBlockVersion ( lastBlock , params ) & ( 1 < < bit ) , 0 ) ;
2021-03-28 03:10:48 +10:00
}
// Next we will advance to the next period and transition to STARTED,
2016-03-09 16:00:53 -05:00
}
2021-03-27 20:17:56 +10:00
lastBlock = firstChain . Mine ( params . nMinerConfirmationWindow * 3 , nTime , VERSIONBITS_LAST_OLD_BLOCK_VERSION ) . Tip ( ) ;
2016-03-09 16:00:53 -05:00
// so ComputeBlockVersion should now set the bit,
2021-06-07 14:58:54 +10:00
BOOST_CHECK ( ( g_versionbitscache . ComputeBlockVersion ( lastBlock , params ) & ( 1 < < bit ) ) ! = 0 ) ;
2016-03-09 16:00:53 -05:00
// and should also be using the VERSIONBITS_TOP_BITS.
2021-06-07 14:58:54 +10:00
BOOST_CHECK_EQUAL ( g_versionbitscache . ComputeBlockVersion ( lastBlock , params ) & VERSIONBITS_TOP_MASK , VERSIONBITS_TOP_BITS ) ;
2016-03-09 16:00:53 -05:00
// Check that ComputeBlockVersion will set the bit until nTimeout
nTime + = 600 ;
2021-03-27 20:17:56 +10:00
uint32_t blocksToMine = params . nMinerConfirmationWindow * 2 ; // test blocks for up to 2 time periods
uint32_t nHeight = params . nMinerConfirmationWindow * 3 ;
2016-03-09 16:00:53 -05:00
// These blocks are all before nTimeout is reached.
while ( nTime < nTimeout & & blocksToMine > 0 ) {
lastBlock = firstChain . Mine ( nHeight + 1 , nTime , VERSIONBITS_LAST_OLD_BLOCK_VERSION ) . Tip ( ) ;
2021-06-07 14:58:54 +10:00
BOOST_CHECK ( ( g_versionbitscache . ComputeBlockVersion ( lastBlock , params ) & ( 1 < < bit ) ) ! = 0 ) ;
BOOST_CHECK_EQUAL ( g_versionbitscache . ComputeBlockVersion ( lastBlock , params ) & VERSIONBITS_TOP_MASK , VERSIONBITS_TOP_BITS ) ;
2016-03-09 16:00:53 -05:00
blocksToMine - - ;
nTime + = 600 ;
nHeight + = 1 ;
2017-01-14 21:45:32 +01:00
}
2016-03-09 16:00:53 -05:00
2021-03-28 03:10:48 +10:00
if ( nTimeout ! = Consensus : : BIP9Deployment : : NO_TIMEOUT ) {
// can reach any nTimeout other than NO_TIMEOUT due to earlier BOOST_REQUIRE
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 ( ) ;
2021-06-07 14:58:54 +10:00
BOOST_CHECK ( ( g_versionbitscache . ComputeBlockVersion ( lastBlock , params ) & ( 1 < < bit ) ) ! = 0 ) ;
2021-03-28 03:10:48 +10:00
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 ( ) ;
2021-06-07 14:58:54 +10:00
BOOST_CHECK ( ( g_versionbitscache . ComputeBlockVersion ( lastBlock , params ) & ( 1 < < bit ) ) ! = 0 ) ;
2021-03-28 03:10:48 +10:00
nHeight + = 1 ;
}
// The next block should trigger no longer setting the bit.
2016-03-09 16:00:53 -05:00
lastBlock = firstChain . Mine ( nHeight + 1 , nTime , VERSIONBITS_LAST_OLD_BLOCK_VERSION ) . Tip ( ) ;
2021-06-07 14:58:54 +10:00
BOOST_CHECK_EQUAL ( g_versionbitscache . ComputeBlockVersion ( lastBlock , params ) & ( 1 < < bit ) , 0 ) ;
2016-03-09 16:00:53 -05:00
}
// On a new chain:
// verify that the bit will be set after lock-in, and then stop being set
// after activation.
nTime = nStartTime ;
// Mine one period worth of blocks, and check that the bit will be on for the
// next period.
2021-03-27 20:17:56 +10:00
lastBlock = secondChain . Mine ( params . nMinerConfirmationWindow , nTime , VERSIONBITS_LAST_OLD_BLOCK_VERSION ) . Tip ( ) ;
2021-06-07 14:58:54 +10:00
BOOST_CHECK ( ( g_versionbitscache . ComputeBlockVersion ( lastBlock , params ) & ( 1 < < bit ) ) ! = 0 ) ;
2016-03-09 16:00:53 -05:00
// Mine another period worth of blocks, signaling the new bit.
2021-03-27 20:17:56 +10:00
lastBlock = secondChain . Mine ( params . nMinerConfirmationWindow * 2 , nTime , VERSIONBITS_TOP_BITS | ( 1 < < bit ) ) . Tip ( ) ;
2016-03-09 16:00:53 -05:00
// After one period of setting the bit on each block, it should have locked in.
// We keep setting the bit for one more period though, until activation.
2021-06-07 14:58:54 +10:00
BOOST_CHECK ( ( g_versionbitscache . ComputeBlockVersion ( lastBlock , params ) & ( 1 < < bit ) ) ! = 0 ) ;
2016-03-09 16:00:53 -05:00
// Now check that we keep mining the block until the end of this period, and
// then stop at the beginning of the next period.
2021-03-27 20:17:56 +10:00
lastBlock = secondChain . Mine ( ( params . nMinerConfirmationWindow * 3 ) - 1 , nTime , VERSIONBITS_LAST_OLD_BLOCK_VERSION ) . Tip ( ) ;
2021-06-07 14:58:54 +10:00
BOOST_CHECK ( ( g_versionbitscache . ComputeBlockVersion ( lastBlock , params ) & ( 1 < < bit ) ) ! = 0 ) ;
2021-03-27 20:17:56 +10:00
lastBlock = secondChain . Mine ( params . nMinerConfirmationWindow * 3 , nTime , VERSIONBITS_LAST_OLD_BLOCK_VERSION ) . Tip ( ) ;
2021-04-07 11:37:47 +10:00
if ( lastBlock - > nHeight + 1 < min_activation_height ) {
// check signalling continues while min_activation_height is not reached
lastBlock = secondChain . Mine ( min_activation_height - 1 , nTime , VERSIONBITS_LAST_OLD_BLOCK_VERSION ) . Tip ( ) ;
2021-06-07 14:58:54 +10:00
BOOST_CHECK ( ( g_versionbitscache . ComputeBlockVersion ( lastBlock , params ) & ( 1 < < bit ) ) ! = 0 ) ;
2021-04-07 11:37:47 +10:00
// then reach min_activation_height, which was already REQUIRE'd to start a new period
lastBlock = secondChain . Mine ( min_activation_height , nTime , VERSIONBITS_LAST_OLD_BLOCK_VERSION ) . Tip ( ) ;
}
// Check that we don't signal after activation
2021-06-07 14:58:54 +10:00
BOOST_CHECK_EQUAL ( g_versionbitscache . ComputeBlockVersion ( lastBlock , params ) & ( 1 < < bit ) , 0 ) ;
2016-03-09 16:00:53 -05:00
}
2021-03-27 20:17:56 +10:00
BOOST_AUTO_TEST_CASE ( versionbits_computeblockversion )
{
2021-03-28 03:10:48 +10:00
// check that any deployment on any chain can conceivably reach both
// ACTIVE and FAILED states in roughly the way we expect
for ( const auto & chain_name : { CBaseChainParams : : MAIN , CBaseChainParams : : TESTNET , CBaseChainParams : : SIGNET , CBaseChainParams : : REGTEST } ) {
const auto chainParams = CreateChainParams ( * m_node . args , chain_name ) ;
2021-04-15 10:02:32 +02:00
uint32_t chain_all_vbits { 0 } ;
2021-03-28 03:10:48 +10:00
for ( int i = 0 ; i < ( int ) Consensus : : MAX_VERSION_BITS_DEPLOYMENTS ; + + i ) {
2021-04-15 10:02:32 +02:00
const auto dep = static_cast < Consensus : : DeploymentPos > ( i ) ;
// Check that no bits are re-used (within the same chain). This is
// disallowed because the transition to FAILED (on timeout) does
// not take precedence over STARTED/LOCKED_IN. So all softforks on
// the same bit might overlap, even when non-overlapping start-end
// times are picked.
2020-12-29 11:19:06 +10:00
const uint32_t dep_mask { g_versionbitscache . Mask ( chainParams - > GetConsensus ( ) , dep ) } ;
2021-04-15 10:02:32 +02:00
BOOST_CHECK ( ! ( chain_all_vbits & dep_mask ) ) ;
chain_all_vbits | = dep_mask ;
check_computeblockversion ( chainParams - > GetConsensus ( ) , dep ) ;
2021-03-28 03:10:48 +10:00
}
}
2021-04-07 11:37:47 +10:00
2021-03-27 23:00:14 +10:00
{
// Use regtest/testdummy to ensure we always exercise some
// deployment that's not always/never active
ArgsManager args ;
args . ForceSetArg ( " -vbparams " , " testdummy:1199145601:1230767999 " ) ; // January 1, 2008 - December 31, 2008
const auto chainParams = CreateChainParams ( args , CBaseChainParams : : REGTEST ) ;
check_computeblockversion ( chainParams - > GetConsensus ( ) , Consensus : : DEPLOYMENT_TESTDUMMY ) ;
}
2021-04-07 11:37:47 +10:00
{
// Use regtest/testdummy to ensure we always exercise the
// min_activation_height test, even if we're not using that in a
// live deployment
ArgsManager args ;
args . ForceSetArg ( " -vbparams " , " testdummy:1199145601:1230767999:403200 " ) ; // January 1, 2008 - December 31, 2008, min act height 403200
const auto chainParams = CreateChainParams ( args , CBaseChainParams : : REGTEST ) ;
check_computeblockversion ( chainParams - > GetConsensus ( ) , Consensus : : DEPLOYMENT_TESTDUMMY ) ;
}
2021-03-27 20:17:56 +10:00
}
2016-03-09 16:00:53 -05:00
2016-02-20 02:57:36 +01:00
BOOST_AUTO_TEST_SUITE_END ( )