@ -28,10 +28,45 @@ bool fHavePruned = false;
bool fPruneMode = false ;
uint64_t nPruneTarget = 0 ;
bool CBlockIndexWorkComparator : : operator ( ) ( const CBlockIndex * pa , const CBlockIndex * pb ) const
{
// First sort by most total work, ...
if ( pa - > nChainWork > pb - > nChainWork ) return false ;
if ( pa - > nChainWork < pb - > nChainWork ) return true ;
// ... then by earliest time received, ...
if ( pa - > nSequenceId < pb - > nSequenceId ) return false ;
if ( pa - > nSequenceId > pb - > nSequenceId ) return true ;
// Use pointer address as tie breaker (should only happen with blocks
// loaded from disk, as those all have id 0).
if ( pa < pb ) return false ;
if ( pa > pb ) return true ;
// Identical blocks.
return false ;
}
bool CBlockIndexHeightOnlyComparator : : operator ( ) ( const CBlockIndex * pa , const CBlockIndex * pb ) const
{
return pa - > nHeight < pb - > nHeight ;
}
static FILE * OpenUndoFile ( const FlatFilePos & pos , bool fReadOnly = false ) ;
static FlatFileSeq BlockFileSeq ( ) ;
static FlatFileSeq UndoFileSeq ( ) ;
std : : vector < CBlockIndex * > BlockManager : : GetAllBlockIndices ( )
{
AssertLockHeld ( cs_main ) ;
std : : vector < CBlockIndex * > rv ;
rv . reserve ( m_block_index . size ( ) ) ;
for ( auto & [ _ , block_index ] : m_block_index ) {
rv . push_back ( & block_index ) ;
}
return rv ;
}
CBlockIndex * BlockManager : : LookupBlockIndex ( const uint256 & hash )
{
AssertLockHeld ( cs_main ) ;
@ -203,8 +238,7 @@ CBlockIndex* BlockManager::InsertBlockIndex(const uint256& hash)
return nullptr ;
}
// Return existing or create new
auto [ mi , inserted ] = m_block_index . try_emplace ( hash ) ;
const auto [ mi , inserted ] { m_block_index . try_emplace ( hash ) } ;
CBlockIndex * pindex = & ( * mi ) . second ;
if ( inserted ) {
pindex - > phashBlock = & ( ( * mi ) . first ) ;
@ -212,46 +246,19 @@ CBlockIndex* BlockManager::InsertBlockIndex(const uint256& hash)
return pindex ;
}
bool BlockManager : : LoadBlockIndex (
const Consensus : : Params & consensus_params ,
ChainstateManager & chainman )
bool BlockManager : : LoadBlockIndex ( const Consensus : : Params & consensus_params )
{
if ( ! m_block_tree_db - > LoadBlockIndexGuts ( consensus_params , [ this ] ( const uint256 & hash ) EXCLUSIVE_LOCKS_REQUIRED ( cs_main ) { return this - > InsertBlockIndex ( hash ) ; } ) ) {
return false ;
}
// Calculate nChainWork
std : : vector < std : : pair < int , CBlockIndex * > > vSortedByHeight ;
vSortedByHeight . reserve ( m_block_index . size ( ) ) ;
for ( auto & [ _ , block_index ] : m_block_index ) {
CBlockIndex * pindex = & block_index ;
vSortedByHeight . push_back ( std : : make_pair ( pindex - > nHeight , pindex ) ) ;
}
sort ( vSortedByHeight . begin ( ) , vSortedByHeight . end ( ) ) ;
// Find start of assumed-valid region.
int first_assumed_valid_height = std : : numeric_limits < int > : : max ( ) ;
for ( const auto & [ height , block ] : vSortedByHeight ) {
if ( block - > IsAssumedValid ( ) ) {
auto chainstates = chainman . GetAll ( ) ;
// If we encounter an assumed-valid block index entry, ensure that we have
// one chainstate that tolerates assumed-valid entries and another that does
// not (i.e. the background validation chainstate), since assumed-valid
// entries should always be pending validation by a fully-validated chainstate.
auto any_chain = [ & ] ( auto fnc ) { return std : : any_of ( chainstates . cbegin ( ) , chainstates . cend ( ) , fnc ) ; } ;
assert ( any_chain ( [ ] ( auto chainstate ) { return chainstate - > reliesOnAssumedValid ( ) ; } ) ) ;
assert ( any_chain ( [ ] ( auto chainstate ) { return ! chainstate - > reliesOnAssumedValid ( ) ; } ) ) ;
first_assumed_valid_height = height ;
break ;
}
}
std : : vector < CBlockIndex * > vSortedByHeight { GetAllBlockIndices ( ) } ;
std : : sort ( vSortedByHeight . begin ( ) , vSortedByHeight . end ( ) ,
CBlockIndexHeightOnlyComparator ( ) ) ;
for ( const std : : pair < int , CBlockIndex * > & item : vSortedByHeight ) {
for ( CBlockIndex * pindex : vSortedByHeight ) {
if ( ShutdownRequested ( ) ) return false ;
CBlockIndex * pindex = item . second ;
pindex - > nChainWork = ( pindex - > pprev ? pindex - > pprev - > nChainWork : 0 ) + GetBlockProof ( * pindex ) ;
pindex - > nTimeMax = ( pindex - > pprev ? std : : max ( pindex - > pprev - > nTimeMax , pindex - > nTime ) : pindex - > nTime ) ;
@ -275,43 +282,6 @@ bool BlockManager::LoadBlockIndex(
pindex - > nStatus | = BLOCK_FAILED_CHILD ;
m_dirty_blockindex . insert ( pindex ) ;
}
if ( pindex - > IsAssumedValid ( ) | |
( pindex - > IsValid ( BLOCK_VALID_TRANSACTIONS ) & &
( pindex - > HaveTxsDownloaded ( ) | | pindex - > pprev = = nullptr ) ) ) {
// Fill each chainstate's block candidate set. Only add assumed-valid
// blocks to the tip candidate set if the chainstate is allowed to rely on
// assumed-valid blocks.
//
// If all setBlockIndexCandidates contained the assumed-valid blocks, the
// background chainstate's ActivateBestChain() call would add assumed-valid
// blocks to the chain (based on how FindMostWorkChain() works). Obviously
// we don't want this since the purpose of the background validation chain
// is to validate assued-valid blocks.
//
// Note: This is considering all blocks whose height is greater or equal to
// the first assumed-valid block to be assumed-valid blocks, and excluding
// them from the background chainstate's setBlockIndexCandidates set. This
// does mean that some blocks which are not technically assumed-valid
// (later blocks on a fork beginning before the first assumed-valid block)
// might not get added to the background chainstate, but this is ok,
// because they will still be attached to the active chainstate if they
// actually contain more work.
//
// Instead of this height-based approach, an earlier attempt was made at
// detecting "holistically" whether the block index under consideration
// relied on an assumed-valid ancestor, but this proved to be too slow to
// be practical.
for ( CChainState * chainstate : chainman . GetAll ( ) ) {
if ( chainstate - > reliesOnAssumedValid ( ) | |
pindex - > nHeight < first_assumed_valid_height ) {
chainstate - > setBlockIndexCandidates . insert ( pindex ) ;
}
}
}
if ( pindex - > nStatus & BLOCK_FAILED_MASK & & ( ! chainman . m_best_invalid | | pindex - > nChainWork > chainman . m_best_invalid - > nChainWork ) ) {
chainman . m_best_invalid = pindex ;
}
if ( pindex - > pprev ) {
pindex - > BuildSkip ( ) ;
}
@ -355,9 +325,9 @@ bool BlockManager::WriteBlockIndexDB()
return true ;
}
bool BlockManager : : LoadBlockIndexDB ( ChainstateManager & chainman )
bool BlockManager : : LoadBlockIndexDB ( )
{
if ( ! LoadBlockIndex ( : : Params ( ) . GetConsensus ( ) , chainman )) {
if ( ! LoadBlockIndex ( : : Params ( ) . GetConsensus ( ) )) {
return false ;
}
@ -382,9 +352,8 @@ bool BlockManager::LoadBlockIndexDB(ChainstateManager& chainman)
LogPrintf ( " Checking all blk files are present... \n " ) ;
std : : set < int > setBlkDataFiles ;
for ( const auto & [ _ , block_index ] : m_block_index ) {
const CBlockIndex * pindex = & block_index ;
if ( pindex - > nStatus & BLOCK_HAVE_DATA ) {
setBlkDataFiles . insert ( pindex - > nFile ) ;
if ( block_index . nStatus & BLOCK_HAVE_DATA ) {
setBlkDataFiles . insert ( block_index . nFile ) ;
}
}
for ( std : : set < int > : : iterator it = setBlkDataFiles . begin ( ) ; it ! = setBlkDataFiles . end ( ) ; it + + ) {
@ -408,13 +377,13 @@ bool BlockManager::LoadBlockIndexDB(ChainstateManager& chainman)
return true ;
}
CBlockIndex * BlockManager : : GetLastCheckpoint ( const CCheckpointData & data )
const CBlockIndex * BlockManager : : GetLastCheckpoint ( const CCheckpointData & data )
{
const MapCheckpoints & checkpoints = data . mapCheckpoints ;
for ( const MapCheckpoints : : value_type & i : reverse_iterate ( checkpoints ) ) {
const uint256 & hash = i . second ;
CBlockIndex * pindex = LookupBlockIndex ( hash ) ;
const CBlockIndex * pindex = LookupBlockIndex ( hash ) ;
if ( pindex ) {
return pindex ;
}