@ -40,7 +40,6 @@ CTxMemPool mempool;
map < uint256 , CBlockIndex * > mapBlockIndex ;
map < uint256 , CBlockIndex * > mapBlockIndex ;
CChain chainActive ;
CChain chainActive ;
CChain chainMostWork ;
int64_t nTimeBestReceived = 0 ;
int64_t nTimeBestReceived = 0 ;
int nScriptCheckThreads = 0 ;
int nScriptCheckThreads = 0 ;
bool fImporting = false ;
bool fImporting = false ;
@ -398,6 +397,12 @@ CBlockIndex *CChain::FindFork(const CBlockLocator &locator) const {
return Genesis ( ) ;
return Genesis ( ) ;
}
}
CBlockIndex * CChain : : FindFork ( CBlockIndex * pindex ) const {
while ( pindex & & ! Contains ( pindex ) )
pindex = pindex - > pprev ;
return pindex ;
}
CCoinsViewCache * pcoinsTip = NULL ;
CCoinsViewCache * pcoinsTip = NULL ;
CBlockTreeDB * pblocktree = NULL ;
CBlockTreeDB * pblocktree = NULL ;
@ -1890,6 +1895,11 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C
for ( unsigned int i = 0 ; i < block . vtx . size ( ) ; i + + )
for ( unsigned int i = 0 ; i < block . vtx . size ( ) ; i + + )
g_signals . SyncTransaction ( block . GetTxHash ( i ) , block . vtx [ i ] , & block ) ;
g_signals . SyncTransaction ( block . GetTxHash ( i ) , block . vtx [ i ] , & block ) ;
// Watch for changes to the previous coinbase transaction.
static uint256 hashPrevBestCoinBase ;
g_signals . UpdatedTransaction ( hashPrevBestCoinBase ) ;
hashPrevBestCoinBase = block . GetTxHash ( 0 ) ;
return true ;
return true ;
}
}
@ -2035,23 +2045,17 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew) {
return true ;
return true ;
}
}
// Make chainMostWork correspond to the chain with the most work in it, that isn't
// Return the tip of the chain with the most work in it, that isn't
// known to be invalid (it's however far from certain to be valid).
// known to be invalid (it's however far from certain to be valid).
void static FindMostWorkChain ( ) {
static CBlockIndex * FindMostWorkChain ( ) {
do {
CBlockIndex * pindexNew = NULL ;
CBlockIndex * pindexNew = NULL ;
// In case the current best is invalid, do not consider it.
while ( chainMostWork . Tip ( ) & & ( chainMostWork . Tip ( ) - > nStatus & BLOCK_FAILED_MASK ) ) {
setBlockIndexValid . erase ( chainMostWork . Tip ( ) ) ;
chainMostWork . SetTip ( chainMostWork . Tip ( ) - > pprev ) ;
}
do {
// Find the best candidate header.
// Find the best candidate header.
{
{
std : : set < CBlockIndex * , CBlockIndexWorkComparator > : : reverse_iterator it = setBlockIndexValid . rbegin ( ) ;
std : : set < CBlockIndex * , CBlockIndexWorkComparator > : : reverse_iterator it = setBlockIndexValid . rbegin ( ) ;
if ( it = = setBlockIndexValid . rend ( ) )
if ( it = = setBlockIndexValid . rend ( ) )
return ;
return NULL ;
pindexNew = * it ;
pindexNew = * it ;
}
}
@ -2075,70 +2079,111 @@ void static FindMostWorkChain() {
}
}
pindexTest = pindexTest - > pprev ;
pindexTest = pindexTest - > pprev ;
}
}
if ( fInvalidAncestor )
if ( ! fInvalidAncestor )
continue ;
return pindexNew ;
break ;
} while ( true ) ;
} while ( true ) ;
// Check whether it's actually an improvement.
if ( chainMostWork . Tip ( ) & & ! CBlockIndexWorkComparator ( ) ( chainMostWork . Tip ( ) , pindexNew ) )
return ;
// We have a new best.
chainMostWork . SetTip ( pindexNew ) ;
}
}
// Try to activate to the most-work chain (thereby connecting it).
// Try to make some progress towards making pindexMostWork the active block.
bool ActivateBestChain ( CValidationState & state ) {
static bool ActivateBestChainStep ( CValidationState & state , CBlockIndex * pindexMostWork ) {
LOCK ( cs_main ) ;
AssertLockHeld ( cs_main ) ;
bool fInvalidFound = false ;
CBlockIndex * pindexOldTip = chainActive . Tip ( ) ;
CBlockIndex * pindexOldTip = chainActive . Tip ( ) ;
bool fComplete = false ;
CBlockIndex * pindexFork = chainActive . FindFork ( pindexMostWork ) ;
while ( ! fComplete ) {
FindMostWorkChain ( ) ;
fComplete = true ;
// Check whether we have something to do.
if ( chainMostWork . Tip ( ) = = NULL ) break ;
// Disconnect active blocks which are no longer in the best chain.
// Disconnect active blocks which are no longer in the best chain.
while ( chainActive . Tip ( ) & & ! chainMostWork . Contains ( chainActive . Tip ( ) ) ) {
while ( chainActive . Tip ( ) & & chainActive . Tip ( ) ! = pindexFork ) {
if ( ! DisconnectTip ( state ) )
if ( ! DisconnectTip ( state ) )
return false ;
return false ;
}
}
// Build list of new blocks to connect.
std : : vector < CBlockIndex * > vpindexToConnect ;
vpindexToConnect . reserve ( pindexMostWork - > nHeight - ( pindexFork ? pindexFork - > nHeight : - 1 ) ) ;
while ( pindexMostWork & & pindexMostWork ! = pindexFork ) {
vpindexToConnect . push_back ( pindexMostWork ) ;
pindexMostWork = pindexMostWork - > pprev ;
}
// Connect new blocks.
// Connect new blocks.
while ( ! chainActive . Contains ( chainMostWork . Tip ( ) ) ) {
BOOST_REVERSE_FOREACH ( CBlockIndex * pindexConnect , vpindexToConnect ) {
CBlockIndex * pindexConnect = chainMostWork [ chainActive . Height ( ) + 1 ] ;
if ( ! ConnectTip ( state , pindexConnect ) ) {
if ( ! ConnectTip ( state , pindexConnect ) ) {
if ( state . IsInvalid ( ) ) {
if ( state . IsInvalid ( ) ) {
// The block violates a consensus rule.
// The block violates a consensus rule.
if ( ! state . CorruptionPossible ( ) )
if ( ! state . CorruptionPossible ( ) )
InvalidChainFound ( chainMostWork . Tip ( ) ) ;
InvalidChainFound ( vpindexToConnect . back ( ) ) ;
fComplete = false ;
state = CValidationState ( ) ;
state = CValidationState ( ) ;
fInvalidFound = true ;
break ;
break ;
} else {
} else {
// A system error occurred (disk space, database error, ...).
// A system error occurred (disk space, database error, ...).
return false ;
return false ;
}
}
} else {
if ( ! pindexOldTip | | chainActive . Tip ( ) - > nChainWork > pindexOldTip - > nChainWork ) {
// We're in a better position than we were. Return temporarily to release the lock.
break ;
}
}
}
}
}
}
if ( chainActive . Tip ( ) ! = pindexOldTip ) {
// Callbacks/notifications for a new best chain.
std : : string strCmd = GetArg ( " -blocknotify " , " " ) ;
if ( fInvalidFound )
if ( ! IsInitialBlockDownload ( ) & & ! strCmd . empty ( ) )
CheckForkWarningConditionsOnNewFork ( vpindexToConnect . back ( ) ) ;
else
CheckForkWarningConditions ( ) ;
if ( ! pblocktree - > Flush ( ) )
return state . Abort ( _ ( " Failed to sync block index " ) ) ;
return true ;
}
bool ActivateBestChain ( CValidationState & state ) {
CBlockIndex * pindexNewTip = NULL ;
CBlockIndex * pindexMostWork = NULL ;
do {
boost : : this_thread : : interruption_point ( ) ;
bool fInitialDownload ;
{
{
boost : : replace_all ( strCmd , " %s " , chainActive . Tip ( ) - > GetBlockHash ( ) . GetHex ( ) ) ;
LOCK ( cs_main ) ;
pindexMostWork = FindMostWorkChain ( ) ;
// Whether we have anything to do at all.
if ( pindexMostWork = = NULL | | pindexMostWork = = chainActive . Tip ( ) )
return true ;
if ( ! ActivateBestChainStep ( state , pindexMostWork ) )
return false ;
pindexNewTip = chainActive . Tip ( ) ;
fInitialDownload = IsInitialBlockDownload ( ) ;
}
// When we reach this point, we switched to a new tip (stored in pindexNewTip).
// Notifications/callbacks that can run without cs_main
if ( ! fInitialDownload ) {
uint256 hashNewTip = pindexNewTip - > GetBlockHash ( ) ;
// Relay inventory, but don't relay old inventory during initial block download.
int nBlockEstimate = Checkpoints : : GetTotalBlocksEstimate ( ) ;
LOCK ( cs_vNodes ) ;
BOOST_FOREACH ( CNode * pnode , vNodes )
if ( chainActive . Height ( ) > ( pnode - > nStartingHeight ! = - 1 ? pnode - > nStartingHeight - 2000 : nBlockEstimate ) )
pnode - > PushInventory ( CInv ( MSG_BLOCK , hashNewTip ) ) ;
std : : string strCmd = GetArg ( " -blocknotify " , " " ) ;
if ( ! strCmd . empty ( ) ) {
boost : : replace_all ( strCmd , " %s " , hashNewTip . GetHex ( ) ) ;
boost : : thread t ( runCommand , strCmd ) ; // thread runs free
boost : : thread t ( runCommand , strCmd ) ; // thread runs free
}
}
}
}
uiInterface . NotifyBlocksChanged ( ) ;
} while ( pindexMostWork ! = chainActive . Tip ( ) ) ;
return true ;
return true ;
}
}
CBlockIndex * AddToBlockIndex ( CBlockHeader & block )
CBlockIndex * AddToBlockIndex ( CBlockHeader & block )
{
{
// Check for duplicate
// Check for duplicate
@ -2198,26 +2243,6 @@ bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBl
if ( ! pblocktree - > WriteBlockIndex ( CDiskBlockIndex ( pindexNew ) ) )
if ( ! pblocktree - > WriteBlockIndex ( CDiskBlockIndex ( pindexNew ) ) )
return state . Abort ( _ ( " Failed to write block index " ) ) ;
return state . Abort ( _ ( " Failed to write block index " ) ) ;
// New best?
if ( ! ActivateBestChain ( state ) )
return false ;
LOCK ( cs_main ) ;
if ( pindexNew = = chainActive . Tip ( ) )
{
// Clear fork warning if its no longer applicable
CheckForkWarningConditions ( ) ;
// Notify UI to display prev block's coinbase if it was ours
static uint256 hashPrevBestCoinBase ;
g_signals . UpdatedTransaction ( hashPrevBestCoinBase ) ;
hashPrevBestCoinBase = block . GetTxHash ( 0 ) ;
} else
CheckForkWarningConditionsOnNewFork ( pindexNew ) ;
if ( ! pblocktree - > Flush ( ) )
return state . Abort ( _ ( " Failed to sync block index " ) ) ;
uiInterface . NotifyBlocksChanged ( ) ;
return true ;
return true ;
}
}
@ -2494,7 +2519,6 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex,
}
}
int nHeight = pindex - > nHeight ;
int nHeight = pindex - > nHeight ;
uint256 hash = pindex - > GetBlockHash ( ) ;
// Check that all transactions are finalized
// Check that all transactions are finalized
BOOST_FOREACH ( const CTransaction & tx , block . vtx )
BOOST_FOREACH ( const CTransaction & tx , block . vtx )
@ -2538,16 +2562,6 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex,
return state . Abort ( _ ( " System error: " ) + e . what ( ) ) ;
return state . Abort ( _ ( " System error: " ) + e . what ( ) ) ;
}
}
// Relay inventory, but don't relay old inventory during initial block download
int nBlockEstimate = Checkpoints : : GetTotalBlocksEstimate ( ) ;
if ( chainActive . Tip ( ) - > GetBlockHash ( ) = = hash )
{
LOCK ( cs_vNodes ) ;
BOOST_FOREACH ( CNode * pnode , vNodes )
if ( chainActive . Height ( ) > ( pnode - > nStartingHeight ! = - 1 ? pnode - > nStartingHeight - 2000 : nBlockEstimate ) )
pnode - > PushInventory ( CInv ( MSG_BLOCK , hash ) ) ;
}
return true ;
return true ;
}
}
@ -2577,10 +2591,11 @@ void PushGetBlocks(CNode* pnode, CBlockIndex* pindexBegin, uint256 hashEnd)
bool ProcessBlock ( CValidationState & state , CNode * pfrom , CBlock * pblock , CDiskBlockPos * dbp )
bool ProcessBlock ( CValidationState & state , CNode * pfrom , CBlock * pblock , CDiskBlockPos * dbp )
{
{
AssertLockHeld ( cs_main ) ;
// Check for duplicate
// Check for duplicate
uint256 hash = pblock - > GetHash ( ) ;
uint256 hash = pblock - > GetHash ( ) ;
{
LOCK ( cs_main ) ;
if ( mapBlockIndex . count ( hash ) )
if ( mapBlockIndex . count ( hash ) )
return state . Invalid ( error ( " ProcessBlock() : already have block %d %s " , mapBlockIndex [ hash ] - > nHeight , hash . ToString ( ) ) , 0 , " duplicate " ) ;
return state . Invalid ( error ( " ProcessBlock() : already have block %d %s " , mapBlockIndex [ hash ] - > nHeight , hash . ToString ( ) ) , 0 , " duplicate " ) ;
if ( mapOrphanBlocks . count ( hash ) )
if ( mapOrphanBlocks . count ( hash ) )
@ -2649,7 +2664,11 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl
mapOrphanBlocksByPrev . erase ( hashPrev ) ;
mapOrphanBlocksByPrev . erase ( hashPrev ) ;
}
}
LogPrintf ( " ProcessBlock: ACCEPTED \n " ) ;
}
if ( ! ActivateBestChain ( state ) )
return error ( " ProcessBlock() : ActivateBestChain failed " ) ;
return true ;
return true ;
}
}
@ -3085,6 +3104,8 @@ bool InitBlockIndex() {
CBlockIndex * pindex = AddToBlockIndex ( block ) ;
CBlockIndex * pindex = AddToBlockIndex ( block ) ;
if ( ! ReceivedBlockTransactions ( block , state , pindex , blockPos ) )
if ( ! ReceivedBlockTransactions ( block , state , pindex , blockPos ) )
return error ( " LoadBlockIndex() : genesis block not accepted " ) ;
return error ( " LoadBlockIndex() : genesis block not accepted " ) ;
if ( ! ActivateBestChain ( state ) )
return error ( " LoadBlockIndex() : genesis block cannot be activated " ) ;
} catch ( std : : runtime_error & e ) {
} catch ( std : : runtime_error & e ) {
return error ( " LoadBlockIndex() : failed to initialize block database : % s " , e.what()) ;
return error ( " LoadBlockIndex() : failed to initialize block database : % s " , e.what()) ;
}
}
@ -3214,7 +3235,6 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp)
// process block
// process block
if ( nBlockPos > = nStartByte ) {
if ( nBlockPos > = nStartByte ) {
LOCK ( cs_main ) ;
if ( dbp )
if ( dbp )
dbp - > nPos = nBlockPos ;
dbp - > nPos = nBlockPos ;
CValidationState state ;
CValidationState state ;
@ -3903,10 +3923,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
CInv inv ( MSG_BLOCK , block . GetHash ( ) ) ;
CInv inv ( MSG_BLOCK , block . GetHash ( ) ) ;
pfrom - > AddInventoryKnown ( inv ) ;
pfrom - > AddInventoryKnown ( inv ) ;
{
LOCK ( cs_main ) ;
LOCK ( cs_main ) ;
// Remember who we got this block from.
// Remember who we got this block from.
mapBlockSource [ inv . hash ] = pfrom - > GetId ( ) ;
mapBlockSource [ inv . hash ] = pfrom - > GetId ( ) ;
MarkBlockAsReceived ( inv . hash , pfrom - > GetId ( ) ) ;
MarkBlockAsReceived ( inv . hash , pfrom - > GetId ( ) ) ;
}
CValidationState state ;
CValidationState state ;
ProcessBlock ( state , pfrom , & block ) ;
ProcessBlock ( state , pfrom , & block ) ;