2016-02-15 05:13:27 +01:00
// Copyright (c) 2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
2020-03-19 23:46:56 +01:00
# include <versionbits.h>
# include <consensus/params.h>
2023-11-10 15:31:12 +01:00
# include <limits>
2017-04-11 12:53:54 +02:00
2023-08-03 22:35:17 +02:00
static int calculateStartHeight ( const CBlockIndex * pindexPrev , ThresholdState state , const int nPeriod , const ThresholdConditionCache & cache ) {
int nStartHeight { std : : numeric_limits < int > : : max ( ) } ;
// we are interested only in state STARTED
// For state DEFINED: it is not started yet, nothing to do
// For states LOCKED_IN, FAILED, ACTIVE: it is too late, nothing to do
while ( state = = ThresholdState : : STARTED ) {
nStartHeight = std : : min ( pindexPrev - > nHeight + 1 , nStartHeight ) ;
// we can walk back here because the only way for STARTED state to exist
// in cache already is to be calculated in previous runs via "walk forward"
// loop below starting from DEFINED state.
pindexPrev = pindexPrev - > GetAncestor ( pindexPrev - > nHeight - nPeriod ) ;
auto cache_it = cache . find ( pindexPrev ) ;
assert ( cache_it ! = cache . end ( ) ) ;
state = cache_it - > second ;
}
return nStartHeight ;
}
2016-02-15 05:13:27 +01:00
ThresholdState AbstractThresholdConditionChecker : : GetStateFor ( const CBlockIndex * pindexPrev , const Consensus : : Params & params , ThresholdConditionCache & cache ) const
{
int nPeriod = Period ( params ) ;
int64_t nTimeStart = BeginTime ( params ) ;
2023-11-10 15:31:12 +01:00
int masternodeStartHeight = SignalHeight ( pindexPrev , params ) ;
2016-02-15 05:13:27 +01:00
int64_t nTimeTimeout = EndTime ( params ) ;
2023-08-26 23:45:22 +02:00
// Check if this deployment is always active.
if ( nTimeStart = = Consensus : : BIP9Deployment : : ALWAYS_ACTIVE ) {
return ThresholdState : : ACTIVE ;
}
2016-02-15 05:13:27 +01:00
// A block's state is always the same as that of the first of its period, so it is computed based on a pindexPrev whose height equals a multiple of nPeriod - 1.
2019-08-06 05:08:33 +02:00
if ( pindexPrev ! = nullptr ) {
2016-02-15 05:13:27 +01:00
pindexPrev = pindexPrev - > GetAncestor ( pindexPrev - > nHeight - ( ( pindexPrev - > nHeight + 1 ) % nPeriod ) ) ;
}
// Walk backwards in steps of nPeriod to find a pindexPrev whose information is known
std : : vector < const CBlockIndex * > vToCompute ;
while ( cache . count ( pindexPrev ) = = 0 ) {
2019-08-06 05:08:33 +02:00
if ( pindexPrev = = nullptr ) {
2016-02-15 05:13:27 +01:00
// The genesis block is by definition defined.
2020-06-09 05:44:04 +02:00
cache [ pindexPrev ] = ThresholdState : : DEFINED ;
2016-02-15 05:13:27 +01:00
break ;
}
2023-08-03 22:35:17 +02:00
if ( pindexPrev - > GetMedianTimePast ( ) < nTimeStart | | pindexPrev - > nHeight < masternodeStartHeight ) {
2016-04-02 07:14:55 +02:00
// Optimization: don't recompute down further, as we know every earlier block will be before the start time
2020-06-09 05:44:04 +02:00
cache [ pindexPrev ] = ThresholdState : : DEFINED ;
2016-02-15 05:13:27 +01:00
break ;
}
vToCompute . push_back ( pindexPrev ) ;
pindexPrev = pindexPrev - > GetAncestor ( pindexPrev - > nHeight - nPeriod ) ;
}
// At this point, cache[pindexPrev] is known
assert ( cache . count ( pindexPrev ) ) ;
ThresholdState state = cache [ pindexPrev ] ;
2023-08-03 22:35:17 +02:00
int nStartHeight = calculateStartHeight ( pindexPrev , state , nPeriod , cache ) ;
2020-09-12 16:33:12 +02:00
2016-02-15 05:13:27 +01:00
// Now walk forward and compute the state of descendants of pindexPrev
while ( ! vToCompute . empty ( ) ) {
ThresholdState stateNext = state ;
pindexPrev = vToCompute . back ( ) ;
vToCompute . pop_back ( ) ;
switch ( state ) {
2020-06-09 05:44:04 +02:00
case ThresholdState : : DEFINED : {
2016-02-15 05:13:27 +01:00
if ( pindexPrev - > GetMedianTimePast ( ) > = nTimeTimeout ) {
2020-06-09 05:44:04 +02:00
stateNext = ThresholdState : : FAILED ;
2023-08-03 22:35:17 +02:00
} else if ( pindexPrev - > GetMedianTimePast ( ) > = nTimeStart & & pindexPrev - > nHeight > = masternodeStartHeight ) {
2020-06-09 05:44:04 +02:00
stateNext = ThresholdState : : STARTED ;
2020-09-12 16:33:12 +02:00
nStartHeight = pindexPrev - > nHeight + 1 ;
2016-02-15 05:13:27 +01:00
}
break ;
}
2020-06-09 05:44:04 +02:00
case ThresholdState : : STARTED : {
2016-02-15 05:13:27 +01:00
if ( pindexPrev - > GetMedianTimePast ( ) > = nTimeTimeout ) {
2020-06-09 05:44:04 +02:00
stateNext = ThresholdState : : FAILED ;
2016-02-15 05:13:27 +01:00
break ;
}
// We need to count
const CBlockIndex * pindexCount = pindexPrev ;
int count = 0 ;
for ( int i = 0 ; i < nPeriod ; i + + ) {
if ( Condition ( pindexCount , params ) ) {
count + + ;
}
pindexCount = pindexCount - > pprev ;
}
2020-09-12 16:33:12 +02:00
assert ( nStartHeight > 0 & & nStartHeight < std : : numeric_limits < int > : : max ( ) ) ;
int nAttempt = ( pindexCount - > nHeight + 1 - nStartHeight ) / nPeriod ;
if ( count > = Threshold ( params , nAttempt ) ) {
2020-06-09 05:44:04 +02:00
stateNext = ThresholdState : : LOCKED_IN ;
2016-02-15 05:13:27 +01:00
}
break ;
}
2020-06-09 05:44:04 +02:00
case ThresholdState : : LOCKED_IN : {
2016-02-15 05:13:27 +01:00
// Always progresses into ACTIVE.
2020-06-09 05:44:04 +02:00
stateNext = ThresholdState : : ACTIVE ;
2016-02-15 05:13:27 +01:00
break ;
}
2020-06-09 05:44:04 +02:00
case ThresholdState : : FAILED :
case ThresholdState : : ACTIVE : {
2016-02-15 05:13:27 +01:00
// Nothing happens, these are terminal states.
break ;
}
}
cache [ pindexPrev ] = state = stateNext ;
}
return state ;
}
2020-09-12 16:33:12 +02:00
BIP9Stats AbstractThresholdConditionChecker : : GetStateStatisticsFor ( const CBlockIndex * pindex , const Consensus : : Params & params , ThresholdConditionCache & cache ) const
2017-05-23 19:07:29 +02:00
{
2017-08-16 02:45:09 +02:00
BIP9Stats stats = { } ;
2017-05-23 19:07:29 +02:00
stats . period = Period ( params ) ;
2020-09-12 16:33:12 +02:00
stats . threshold = Threshold ( params , 0 ) ;
2017-05-23 19:07:29 +02:00
2019-08-06 05:08:33 +02:00
if ( pindex = = nullptr )
2017-05-23 19:07:29 +02:00
return stats ;
// Find beginning of period
const CBlockIndex * pindexEndOfPrevPeriod = pindex - > GetAncestor ( pindex - > nHeight - ( ( pindex - > nHeight + 1 ) % stats . period ) ) ;
stats . elapsed = pindex - > nHeight - pindexEndOfPrevPeriod - > nHeight ;
2020-09-12 16:33:12 +02:00
// Re-calculate current threshold
int nAttempt { 0 } ;
const ThresholdState state = GetStateFor ( pindexEndOfPrevPeriod , params , cache ) ;
if ( state = = ThresholdState : : STARTED ) {
int nStartHeight = GetStateSinceHeightFor ( pindexEndOfPrevPeriod , params , cache ) ;
nAttempt = ( pindexEndOfPrevPeriod - > nHeight + 1 - nStartHeight ) / stats . period ;
}
stats . threshold = Threshold ( params , nAttempt ) ;
2017-05-23 19:07:29 +02:00
// Count from current block to beginning of period
int count = 0 ;
const CBlockIndex * currentIndex = pindex ;
while ( pindexEndOfPrevPeriod - > nHeight ! = currentIndex - > nHeight ) {
if ( Condition ( currentIndex , params ) )
count + + ;
currentIndex = currentIndex - > pprev ;
}
stats . count = count ;
stats . possible = ( stats . period - stats . threshold ) > = ( stats . elapsed - count ) ;
return stats ;
}
2016-10-19 16:36:21 +02:00
int AbstractThresholdConditionChecker : : GetStateSinceHeightFor ( const CBlockIndex * pindexPrev , const Consensus : : Params & params , ThresholdConditionCache & cache ) const
{
2023-08-26 23:45:22 +02:00
int64_t start_time = BeginTime ( params ) ;
if ( start_time = = Consensus : : BIP9Deployment : : ALWAYS_ACTIVE ) {
return 0 ;
}
2016-10-19 16:36:21 +02:00
const ThresholdState initialState = GetStateFor ( pindexPrev , params , cache ) ;
// BIP 9 about state DEFINED: "The genesis block is by definition in this state for each deployment."
2020-06-09 05:44:04 +02:00
if ( initialState = = ThresholdState : : DEFINED ) {
2016-10-19 16:36:21 +02:00
return 0 ;
}
const int nPeriod = Period ( params ) ;
// A block's state is always the same as that of the first of its period, so it is computed based on a pindexPrev whose height equals a multiple of nPeriod - 1.
// To ease understanding of the following height calculation, it helps to remember that
// right now pindexPrev points to the block prior to the block that we are computing for, thus:
// if we are computing for the last block of a period, then pindexPrev points to the second to last block of the period, and
// if we are computing for the first block of a period, then pindexPrev points to the last block of the previous period.
2019-08-06 05:08:33 +02:00
// The parent of the genesis block is represented by nullptr.
2016-10-19 16:36:21 +02:00
pindexPrev = pindexPrev - > GetAncestor ( pindexPrev - > nHeight - ( ( pindexPrev - > nHeight + 1 ) % nPeriod ) ) ;
const CBlockIndex * previousPeriodParent = pindexPrev - > GetAncestor ( pindexPrev - > nHeight - nPeriod ) ;
2019-08-06 05:08:33 +02:00
while ( previousPeriodParent ! = nullptr & & GetStateFor ( previousPeriodParent , params , cache ) = = initialState ) {
2016-10-19 16:36:21 +02:00
pindexPrev = previousPeriodParent ;
previousPeriodParent = pindexPrev - > GetAncestor ( pindexPrev - > nHeight - nPeriod ) ;
}
// Adjust the result because right now we point to the parent block.
return pindexPrev - > nHeight + 1 ;
}
2016-02-15 05:13:27 +01:00
namespace
{
/**
* Class to implement versionbits logic .
*/
class VersionBitsConditionChecker : public AbstractThresholdConditionChecker {
private :
const Consensus : : DeploymentPos id ;
protected :
2018-02-15 08:29:15 +01:00
int64_t BeginTime ( const Consensus : : Params & params ) const override { return params . vDeployments [ id ] . nStartTime ; }
2023-11-10 15:31:12 +01:00
int SignalHeight ( const CBlockIndex * const pindexPrev , const Consensus : : Params & params ) const override {
2023-08-03 22:35:17 +02:00
const auto & deployment = params . vDeployments [ id ] ;
2023-11-10 15:31:12 +01:00
if ( ! deployment . useEHF ) {
2023-08-03 22:35:17 +02:00
return 0 ;
}
2023-11-10 15:31:12 +01:00
// ehfManager should be initialized before first usage of VersionBitsConditionChecker
refactor: re-order headers and forward declarations to improve compile time (#5693)
## Issue being fixed or feature implemented
Some headers include other heavy headers, such as `logging.h`,
`tinyformat.h`, `iostream`. These headers are heavy and increase
compilation time on scale of whole project drastically because can be
used in many other headers.
## What was done?
Moved many heavy includes from headers to cpp files to optimize
compilation time.
In some places added forward declarations if it is reasonable.
As side effect removed 2 circular dependencies:
```
"llmq/debug -> llmq/dkgsessionhandler -> llmq/debug"
"llmq/debug -> llmq/dkgsessionhandler -> llmq/dkgsession -> llmq/debug"
```
## How Has This Been Tested?
Run build 2 times before refactoring and after refactoring: `make clean
&& sleep 10s; time make -j18`
Before refactoring:
```
real 5m37,826s
user 77m12,075s
sys 6m20,547s
real 5m32,626s
user 76m51,143s
sys 6m24,511s
```
After refactoring:
```
real 5m18,509s
user 73m32,133s
sys 6m21,590s
real 5m14,466s
user 73m20,942s
sys 6m17,868s
```
~5% of improvement for compilation time. That's not huge, but that's
worth to get merged
There're several more refactorings TODO but better to do them later by
backports:
- bitcoin/bitcoin#27636
- bitcoin/bitcoin#26286
- bitcoin/bitcoin#27238
- and maybe this one: bitcoin/bitcoin#28200
## Breaking Changes
N/A
## Checklist:
- [x] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have added or updated relevant unit/integration/functional/e2e
tests
- [ ] I have made corresponding changes to the documentation
- [x] I have assigned this pull request to a milestone
2023-11-17 17:04:18 +01:00
const auto ehfManagerPtr = AbstractEHFManager : : getInstance ( ) ;
2023-11-10 15:31:12 +01:00
const auto signals = ehfManagerPtr - > GetSignalsStage ( pindexPrev ) ;
const auto it = signals . find ( deployment . bit ) ;
if ( it = = signals . end ( ) ) {
return std : : numeric_limits < int > : : max ( ) ;
}
return it - > second ;
2023-08-03 22:35:17 +02:00
}
2018-02-15 08:29:15 +01:00
int64_t EndTime ( const Consensus : : Params & params ) const override { return params . vDeployments [ id ] . nTimeout ; }
int Period ( const Consensus : : Params & params ) const override { return params . vDeployments [ id ] . nWindowSize ? params . vDeployments [ id ] . nWindowSize : params . nMinerConfirmationWindow ; }
2020-09-12 16:33:12 +02:00
int Threshold ( const Consensus : : Params & params , int nAttempt ) const override
{
if ( params . vDeployments [ id ] . nThresholdStart = = 0 ) {
return params . nRuleChangeActivationThreshold ;
}
if ( params . vDeployments [ id ] . nThresholdMin = = 0 | | params . vDeployments [ id ] . nFalloffCoeff = = 0 ) {
return params . vDeployments [ id ] . nThresholdStart ;
}
int64_t nThresholdCalc = params . vDeployments [ id ] . nThresholdStart - nAttempt * nAttempt * Period ( params ) / 100 / params . vDeployments [ id ] . nFalloffCoeff ;
return std : : max ( params . vDeployments [ id ] . nThresholdMin , nThresholdCalc ) ;
}
2016-02-15 05:13:27 +01:00
2018-02-15 08:29:15 +01:00
bool Condition ( const CBlockIndex * pindex , const Consensus : : Params & params ) const override
2016-02-15 05:13:27 +01:00
{
return ( ( ( pindex - > nVersion & VERSIONBITS_TOP_MASK ) = = VERSIONBITS_TOP_BITS ) & & ( pindex - > nVersion & Mask ( params ) ) ! = 0 ) ;
}
public :
2017-08-17 22:59:56 +02:00
explicit VersionBitsConditionChecker ( Consensus : : DeploymentPos id_ ) : id ( id_ ) { }
2016-02-15 05:13:27 +01:00
uint32_t Mask ( const Consensus : : Params & params ) const { return ( ( uint32_t ) 1 ) < < params . vDeployments [ id ] . bit ; }
} ;
2017-06-26 13:37:42 +02:00
} // namespace
2016-02-15 05:13:27 +01:00
ThresholdState VersionBitsState ( const CBlockIndex * pindexPrev , const Consensus : : Params & params , Consensus : : DeploymentPos pos , VersionBitsCache & cache )
{
return VersionBitsConditionChecker ( pos ) . GetStateFor ( pindexPrev , params , cache . caches [ pos ] ) ;
}
2020-09-12 16:33:12 +02:00
BIP9Stats VersionBitsStatistics ( const CBlockIndex * pindexPrev , const Consensus : : Params & params , Consensus : : DeploymentPos pos , VersionBitsCache & cache )
2017-05-23 19:07:29 +02:00
{
2020-09-12 16:33:12 +02:00
return VersionBitsConditionChecker ( pos ) . GetStateStatisticsFor ( pindexPrev , params , cache . caches [ pos ] ) ;
2017-05-23 19:07:29 +02:00
}
2016-10-19 16:36:21 +02:00
int VersionBitsStateSinceHeight ( const CBlockIndex * pindexPrev , const Consensus : : Params & params , Consensus : : DeploymentPos pos , VersionBitsCache & cache )
{
return VersionBitsConditionChecker ( pos ) . GetStateSinceHeightFor ( pindexPrev , params , cache . caches [ pos ] ) ;
}
2016-02-15 05:13:27 +01:00
uint32_t VersionBitsMask ( const Consensus : : Params & params , Consensus : : DeploymentPos pos )
{
return VersionBitsConditionChecker ( pos ) . Mask ( params ) ;
}
void VersionBitsCache : : Clear ( )
{
for ( unsigned int d = 0 ; d < Consensus : : MAX_VERSION_BITS_DEPLOYMENTS ; d + + ) {
caches [ d ] . clear ( ) ;
}
}
2023-11-10 15:31:12 +01:00
AbstractEHFManager * AbstractEHFManager : : globalInstance { nullptr } ;