@ -53,6 +53,7 @@ bool fImporting = false;
@@ -53,6 +53,7 @@ bool fImporting = false;
bool fReindex = false ;
bool fTxIndex = false ;
bool fIsBareMultisigStd = true ;
bool fCheckBlockIndex = false ;
unsigned int nCoinCacheSize = 5000 ;
/** Fees smaller than this (in satoshi) are considered zero fee (for relaying and mining) */
@ -74,6 +75,7 @@ void EraseOrphansFor(NodeId peer);
@@ -74,6 +75,7 @@ void EraseOrphansFor(NodeId peer);
* and going backwards .
*/
static bool IsSuperMajority ( int minVersion , const CBlockIndex * pstart , unsigned int nRequired ) ;
static void CheckBlockIndex ( ) ;
/** Constant stuff for coinbase transactions we create: */
CScript COINBASE_FLAGS ;
@ -85,7 +87,7 @@ namespace {
@@ -85,7 +87,7 @@ namespace {
struct CBlockIndexWorkComparator
{
bool operator ( ) ( CBlockIndex * pa , CBlockIndex * pb ) {
bool operator ( ) ( CBlockIndex * pa , CBlockIndex * pb ) const {
// First sort by most total work, ...
if ( pa - > nChainWork > pb - > nChainWork ) return false ;
if ( pa - > nChainWork < pb - > nChainWork ) return true ;
@ -107,8 +109,8 @@ namespace {
@@ -107,8 +109,8 @@ namespace {
CBlockIndex * pindexBestInvalid ;
/**
* The set of all CBlockIndex entries with BLOCK_VALID_TRANSACTIONS or better that are at least
* as good as our current tip . Entries may be failed , though .
* The set of all CBlockIndex entries with BLOCK_VALID_TRANSACTIONS ( for itself and all ancestors ) and
* as good as our current tip or better . Entries may be failed , though .
*/
set < CBlockIndex * , CBlockIndexWorkComparator > setBlockIndexCandidates ;
/** Number of nodes with fSyncStarted. */
@ -2226,6 +2228,7 @@ bool ActivateBestChain(CValidationState &state, CBlock *pblock) {
@@ -2226,6 +2228,7 @@ bool ActivateBestChain(CValidationState &state, CBlock *pblock) {
uiInterface . NotifyBlockTip ( hashNewTip ) ;
}
} while ( pindexMostWork ! = chainActive . Tip ( ) ) ;
CheckBlockIndex ( ) ;
// Write changes periodically to disk, after relay.
if ( ! FlushStateToDisk ( state , FLUSH_STATE_PERIODIC ) ) {
@ -2362,7 +2365,9 @@ bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBl
@@ -2362,7 +2365,9 @@ bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBl
CBlockIndex * pindex = queue . front ( ) ;
queue . pop_front ( ) ;
pindex - > nChainTx = ( pindex - > pprev ? pindex - > pprev - > nChainTx : 0 ) + pindex - > nTx ;
setBlockIndexCandidates . insert ( pindex ) ;
if ( chainActive . Tip ( ) = = NULL | | ! setBlockIndexCandidates . value_comp ( ) ( pindex , chainActive . Tip ( ) ) ) {
setBlockIndexCandidates . insert ( pindex ) ;
}
std : : pair < std : : multimap < CBlockIndex * , CBlockIndex * > : : iterator , std : : multimap < CBlockIndex * , CBlockIndex * > : : iterator > range = mapBlocksUnlinked . equal_range ( pindex ) ;
while ( range . first ! = range . second ) {
std : : multimap < CBlockIndex * , CBlockIndex * > : : iterator it = range . first ;
@ -2725,6 +2730,7 @@ bool ProcessNewBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDis
@@ -2725,6 +2730,7 @@ bool ProcessNewBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDis
if ( pindex & & pfrom ) {
mapBlockSource [ pindex - > GetBlockHash ( ) ] = pfrom - > GetId ( ) ;
}
CheckBlockIndex ( ) ;
if ( ! ret )
return error ( " %s: AcceptBlock FAILED " , __func__ ) ;
}
@ -3213,6 +3219,136 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp)
@@ -3213,6 +3219,136 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp)
return nLoaded > 0 ;
}
void static CheckBlockIndex ( )
{
if ( ! fCheckBlockIndex ) {
return ;
}
LOCK ( cs_main ) ;
// Build forward-pointing map of the entire block tree.
std : : multimap < CBlockIndex * , CBlockIndex * > forward ;
for ( BlockMap : : iterator it = mapBlockIndex . begin ( ) ; it ! = mapBlockIndex . end ( ) ; it + + ) {
forward . insert ( std : : make_pair ( it - > second - > pprev , it - > second ) ) ;
}
assert ( forward . size ( ) = = mapBlockIndex . size ( ) ) ;
std : : pair < std : : multimap < CBlockIndex * , CBlockIndex * > : : iterator , std : : multimap < CBlockIndex * , CBlockIndex * > : : iterator > rangeGenesis = forward . equal_range ( NULL ) ;
CBlockIndex * pindex = rangeGenesis . first - > second ;
rangeGenesis . first + + ;
assert ( rangeGenesis . first = = rangeGenesis . second ) ; // There is only one index entry with parent NULL.
// Iterate over the entire block tree, using depth-first search.
// Along the way, remember whether there are blocks on the path from genesis
// block being explored which are the first to have certain properties.
size_t nNodes = 0 ;
int nHeight = 0 ;
CBlockIndex * pindexFirstInvalid = NULL ; // Oldest ancestor of pindex which is invalid.
CBlockIndex * pindexFirstMissing = NULL ; // Oldest ancestor of pindex which does not have BLOCK_HAVE_DATA.
CBlockIndex * pindexFirstNotTreeValid = NULL ; // Oldest ancestor of pindex which does not have BLOCK_VALID_TREE (regardless of being valid or not).
CBlockIndex * pindexFirstNotChainValid = NULL ; // Oldest ancestor of pindex which does not have BLOCK_VALID_CHAIN (regardless of being valid or not).
CBlockIndex * pindexFirstNotScriptsValid = NULL ; // Oldest ancestor of pindex which does not have BLOCK_VALID_SCRIPTS (regardless of being valid or not).
while ( pindex ! = NULL ) {
nNodes + + ;
if ( pindexFirstInvalid = = NULL & & pindex - > nStatus & BLOCK_FAILED_VALID ) pindexFirstInvalid = pindex ;
if ( pindexFirstMissing = = NULL & & ! ( pindex - > nStatus & BLOCK_HAVE_DATA ) ) pindexFirstMissing = pindex ;
if ( pindex - > pprev ! = NULL & & pindexFirstNotTreeValid = = NULL & & ( pindex - > nStatus & BLOCK_VALID_MASK ) < BLOCK_VALID_TREE ) pindexFirstNotTreeValid = pindex ;
if ( pindex - > pprev ! = NULL & & pindexFirstNotChainValid = = NULL & & ( pindex - > nStatus & BLOCK_VALID_MASK ) < BLOCK_VALID_CHAIN ) pindexFirstNotChainValid = pindex ;
if ( pindex - > pprev ! = NULL & & pindexFirstNotScriptsValid = = NULL & & ( pindex - > nStatus & BLOCK_VALID_MASK ) < BLOCK_VALID_SCRIPTS ) pindexFirstNotScriptsValid = pindex ;
// Begin: actual consistency checks.
if ( pindex - > pprev = = NULL ) {
// Genesis block checks.
assert ( pindex - > GetBlockHash ( ) = = Params ( ) . HashGenesisBlock ( ) ) ; // Genesis block's hash must match.
assert ( pindex = = chainActive . Genesis ( ) ) ; // The current active chain's genesis block must be this block.
}
assert ( ( pindexFirstMissing ! = NULL ) = = ( pindex - > nChainTx = = 0 ) ) ; // nChainTx == 0 is used to signal that all parent block's transaction data is available.
assert ( pindex - > nHeight = = nHeight ) ; // nHeight must be consistent.
assert ( pindex - > pprev = = NULL | | pindex - > nChainWork > = pindex - > pprev - > nChainWork ) ; // For every block except the genesis block, the chainwork must be larger than the parent's.
assert ( nHeight < 2 | | ( pindex - > pskip & & ( pindex - > pskip - > nHeight < nHeight ) ) ) ; // The pskip pointer must point back for all but the first 2 blocks.
assert ( pindexFirstNotTreeValid = = NULL ) ; // All mapBlockIndex entries must at least be TREE valid
if ( ( pindex - > nStatus & BLOCK_VALID_MASK ) > = BLOCK_VALID_TREE ) assert ( pindexFirstNotTreeValid = = NULL ) ; // TREE valid implies all parents are TREE valid
if ( ( pindex - > nStatus & BLOCK_VALID_MASK ) > = BLOCK_VALID_CHAIN ) assert ( pindexFirstNotChainValid = = NULL ) ; // CHAIN valid implies all parents are CHAIN valid
if ( ( pindex - > nStatus & BLOCK_VALID_MASK ) > = BLOCK_VALID_SCRIPTS ) assert ( pindexFirstNotScriptsValid = = NULL ) ; // SCRIPTS valid implies all parents are SCRIPTS valid
if ( pindexFirstInvalid = = NULL ) {
// Checks for not-invalid blocks.
assert ( ( pindex - > nStatus & BLOCK_FAILED_MASK ) = = 0 ) ; // The failed mask cannot be set for blocks without invalid parents.
}
if ( ! CBlockIndexWorkComparator ( ) ( pindex , chainActive . Tip ( ) ) & & pindexFirstMissing = = NULL ) {
if ( pindexFirstInvalid = = NULL ) { // If this block sorts at least as good as the current tip and is valid, it must be in setBlockIndexCandidates.
assert ( setBlockIndexCandidates . count ( pindex ) ) ;
}
} else { // If this block sorts worse than the current tip, it cannot be in setBlockIndexCandidates.
assert ( setBlockIndexCandidates . count ( pindex ) = = 0 ) ;
}
// Check whether this block is in mapBlocksUnlinked.
std : : pair < std : : multimap < CBlockIndex * , CBlockIndex * > : : iterator , std : : multimap < CBlockIndex * , CBlockIndex * > : : iterator > rangeUnlinked = mapBlocksUnlinked . equal_range ( pindex - > pprev ) ;
bool foundInUnlinked = false ;
while ( rangeUnlinked . first ! = rangeUnlinked . second ) {
assert ( rangeUnlinked . first - > first = = pindex - > pprev ) ;
if ( rangeUnlinked . first - > second = = pindex ) {
foundInUnlinked = true ;
break ;
}
rangeUnlinked . first + + ;
}
if ( pindex - > pprev & & pindex - > nStatus & BLOCK_HAVE_DATA & & pindexFirstMissing ! = NULL ) {
if ( pindexFirstInvalid = = NULL ) { // If this block has block data available, some parent doesn't, and has no invalid parents, it must be in mapBlocksUnlinked.
assert ( foundInUnlinked ) ;
}
} else { // If this block does not have block data available, or all parents do, it cannot be in mapBlocksUnlinked.
assert ( ! foundInUnlinked ) ;
}
// assert(pindex->GetBlockHash() == pindex->GetBlockHeader().GetHash()); // Perhaps too slow
// End: actual consistency checks.
// Try descending into the first subnode.
std : : pair < std : : multimap < CBlockIndex * , CBlockIndex * > : : iterator , std : : multimap < CBlockIndex * , CBlockIndex * > : : iterator > range = forward . equal_range ( pindex ) ;
if ( range . first ! = range . second ) {
// A subnode was found.
pindex = range . first - > second ;
nHeight + + ;
continue ;
}
// This is a leaf node.
// Move upwards until we reach a node of which we have not yet visited the last child.
while ( pindex ) {
// We are going to either move to a parent or a sibling of pindex.
// If pindex was the first with a certain property, unset the corresponding variable.
if ( pindex = = pindexFirstInvalid ) pindexFirstInvalid = NULL ;
if ( pindex = = pindexFirstMissing ) pindexFirstMissing = NULL ;
if ( pindex = = pindexFirstNotTreeValid ) pindexFirstNotTreeValid = NULL ;
if ( pindex = = pindexFirstNotChainValid ) pindexFirstNotChainValid = NULL ;
if ( pindex = = pindexFirstNotScriptsValid ) pindexFirstNotScriptsValid = NULL ;
// Find our parent.
CBlockIndex * pindexPar = pindex - > pprev ;
// Find which child we just visited.
std : : pair < std : : multimap < CBlockIndex * , CBlockIndex * > : : iterator , std : : multimap < CBlockIndex * , CBlockIndex * > : : iterator > rangePar = forward . equal_range ( pindexPar ) ;
while ( rangePar . first - > second ! = pindex ) {
assert ( rangePar . first ! = rangePar . second ) ; // Our parent must have at least the node we're coming from as child.
rangePar . first + + ;
}
// Proceed to the next one.
rangePar . first + + ;
if ( rangePar . first ! = rangePar . second ) {
// Move to the sibling.
pindex = rangePar . first - > second ;
break ;
} else {
// Move up further.
pindex = pindexPar ;
nHeight - - ;
continue ;
}
}
}
// Check that we actually traversed the entire map.
assert ( nNodes = = forward . size ( ) ) ;
}
//////////////////////////////////////////////////////////////////////////////
//
// CAlert
@ -3971,6 +4107,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
@@ -3971,6 +4107,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
LogPrint ( " net " , " more getheaders (%d) to end to peer=%d (startheight:%d) \n " , pindexLast - > nHeight , pfrom - > id , pfrom - > nStartingHeight ) ;
pfrom - > PushMessage ( " getheaders " , chainActive . GetLocator ( pindexLast ) , uint256 ( ) ) ;
}
CheckBlockIndex ( ) ;
}
else if ( strCommand = = " block " & & ! fImporting & & ! fReindex ) // Ignore blocks received while importing