@ -37,6 +37,7 @@ CBigNum bnBestChainWork = 0;
CBigNum bnBestInvalidWork = 0 ;
CBigNum bnBestInvalidWork = 0 ;
uint256 hashBestChain = 0 ;
uint256 hashBestChain = 0 ;
CBlockIndex * pindexBest = NULL ;
CBlockIndex * pindexBest = NULL ;
set < CBlockIndex * , CBlockIndexWorkComparator > setBlockIndexValid ; // may contain all CBlockIndex*'s that have validness >=BLOCK_VALID_TRANSACTIONS, and must contain those who aren't failed
int64 nTimeBestReceived = 0 ;
int64 nTimeBestReceived = 0 ;
bool fImporting = false ;
bool fImporting = false ;
@ -1156,6 +1157,62 @@ void static InvalidChainFound(CBlockIndex* pindexNew)
printf ( " InvalidChainFound: Warning: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade. \n " ) ;
printf ( " InvalidChainFound: Warning: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade. \n " ) ;
}
}
void static InvalidBlockFound ( CBlockIndex * pindex ) {
pindex - > nStatus | = BLOCK_FAILED_VALID ;
CChainDB ( ) . WriteBlockIndex ( CDiskBlockIndex ( pindex ) ) ;
setBlockIndexValid . erase ( pindex ) ;
InvalidChainFound ( pindex ) ;
if ( pindex - > pnext )
ConnectBestBlock ( ) ; // reorganise away from the failed block
}
bool ConnectBestBlock ( ) {
do {
CBlockIndex * pindexNewBest ;
{
std : : set < CBlockIndex * , CBlockIndexWorkComparator > : : reverse_iterator it = setBlockIndexValid . rbegin ( ) ;
if ( it = = setBlockIndexValid . rend ( ) )
return true ;
pindexNewBest = * it ;
}
if ( pindexNewBest = = pindexBest )
return true ; // nothing to do
// check ancestry
CBlockIndex * pindexTest = pindexNewBest ;
std : : vector < CBlockIndex * > vAttach ;
do {
if ( pindexTest - > nStatus & BLOCK_FAILED_MASK ) {
// mark descendants failed
CChainDB chaindb ;
CBlockIndex * pindexFailed = pindexNewBest ;
while ( pindexTest ! = pindexFailed ) {
pindexFailed - > nStatus | = BLOCK_FAILED_CHILD ;
setBlockIndexValid . erase ( pindexFailed ) ;
chaindb . WriteBlockIndex ( CDiskBlockIndex ( pindexFailed ) ) ;
pindexFailed = pindexFailed - > pprev ;
}
InvalidChainFound ( pindexNewBest ) ;
break ;
}
if ( pindexBest = = NULL | | pindexTest - > bnChainWork > pindexBest - > bnChainWork )
vAttach . push_back ( pindexTest ) ;
if ( pindexTest - > pprev = = NULL | | pindexTest - > pnext ! = NULL ) {
reverse ( vAttach . begin ( ) , vAttach . end ( ) ) ;
BOOST_FOREACH ( CBlockIndex * pindexSwitch , vAttach )
if ( ! SetBestChain ( pindexSwitch ) )
return false ;
return true ;
}
pindexTest = pindexTest - > pprev ;
} while ( true ) ;
} while ( true ) ;
}
void CBlock : : UpdateTime ( const CBlockIndex * pindexPrev )
void CBlock : : UpdateTime ( const CBlockIndex * pindexPrev )
{
{
nTime = max ( pindexPrev - > GetMedianTimePast ( ) + 1 , GetAdjustedTime ( ) ) ;
nTime = max ( pindexPrev - > GetMedianTimePast ( ) + 1 , GetAdjustedTime ( ) ) ;
@ -1522,17 +1579,24 @@ bool CBlock::ConnectBlock(CBlockIndex* pindex, CCoinsViewCache &view, bool fJust
return true ;
return true ;
// Write undo information to disk
// Write undo information to disk
if ( pindex - > GetUndoPos ( ) . IsNull ( ) )
if ( pindex - > GetUndoPos ( ) . IsNull ( ) | | ( pindex - > nStatus & BLOCK_VALID_MASK ) < BLOCK_VALID_SCRIPTS )
{
{
CChainDB chaindb ;
CChainDB chaindb ;
CDiskBlockPos pos ;
if ( ! FindUndoPos ( chaindb , pindex - > pos . nFile , pos , : : GetSerializeSize ( blockundo , SER_DISK , CLIENT_VERSION ) + 8 ) )
if ( pindex - > GetUndoPos ( ) . IsNull ( ) ) {
return error ( " ConnectBlock() : FindUndoPos failed " ) ;
CDiskBlockPos pos ;
if ( ! blockundo . WriteToDisk ( pos ) )
if ( ! FindUndoPos ( chaindb , pindex - > nFile , pos , : : GetSerializeSize ( blockundo , SER_DISK , CLIENT_VERSION ) + 8 ) )
return error ( " ConnectBlock() : CBlockUndo : : WriteToDisk failed " ) ;
return error ( " ConnectBlock() : FindUndoPos failed " ) ;
if ( ! blockundo . WriteToDisk ( pos ) )
// update nUndoPos in block index
return error ( " ConnectBlock() : CBlockUndo : : WriteToDisk failed " ) ;
pindex - > nUndoPos = pos . nPos + 1 ;
// update nUndoPos in block index
pindex - > nUndoPos = pos . nPos ;
pindex - > nStatus | = BLOCK_HAVE_UNDO ;
}
pindex - > nStatus = ( pindex - > nStatus & ~ BLOCK_VALID_MASK ) | BLOCK_VALID_SCRIPTS ;
CDiskBlockIndex blockindex ( pindex ) ;
CDiskBlockIndex blockindex ( pindex ) ;
if ( ! chaindb . WriteBlockIndex ( blockindex ) )
if ( ! chaindb . WriteBlockIndex ( blockindex ) )
return error ( " ConnectBlock() : WriteBlockIndex failed " ) ;
return error ( " ConnectBlock() : WriteBlockIndex failed " ) ;
@ -1549,7 +1613,7 @@ bool CBlock::ConnectBlock(CBlockIndex* pindex, CCoinsViewCache &view, bool fJust
return true ;
return true ;
}
}
bool CBlock : : SetBestChain ( CBlockIndex * pindexNew )
bool SetBestChain ( CBlockIndex * pindexNew )
{
{
CCoinsViewCache & view = * pcoinsTip ;
CCoinsViewCache & view = * pcoinsTip ;
@ -1620,24 +1684,19 @@ bool CBlock::SetBestChain(CBlockIndex* pindexNew)
vector < CTransaction > vDelete ;
vector < CTransaction > vDelete ;
BOOST_FOREACH ( CBlockIndex * pindex , vConnect ) {
BOOST_FOREACH ( CBlockIndex * pindex , vConnect ) {
CBlock block ;
CBlock block ;
CBlock * pblock ;
if ( ! block . ReadFromDisk ( pindex ) )
if ( pindex = = pindexNew ) // connecting *this block
return error ( " SetBestBlock() : ReadFromDisk for connect failed " ) ;
pblock = this ;
else { // other block; read it from disk
if ( ! block . ReadFromDisk ( pindex ) )
return error ( " SetBestBlock() : ReadFromDisk for connect failed " ) ;
pblock = & block ;
}
CCoinsViewCache viewTemp ( view , true ) ;
CCoinsViewCache viewTemp ( view , true ) ;
if ( ! pblock - > ConnectBlock ( pindex , viewTemp ) ) {
if ( ! block . ConnectBlock ( pindex , viewTemp ) ) {
InvalidChainFound ( pindexNew ) ;
InvalidChainFound ( pindexNew ) ;
InvalidBlockFound ( pindex ) ;
return error ( " SetBestBlock() : ConnectBlock % s failed " , pindex->GetBlockHash().ToString().substr(0,20).c_str()) ;
return error ( " SetBestBlock() : ConnectBlock % s failed " , pindex->GetBlockHash().ToString().substr(0,20).c_str()) ;
}
}
if ( ! viewTemp . Flush ( ) )
if ( ! viewTemp . Flush ( ) )
return error ( " SetBestBlock() : Cache flush failed after connect " ) ;
return error ( " SetBestBlock() : Cache flush failed after connect " ) ;
// Queue memory transactions to delete
// Queue memory transactions to delete
BOOST_FOREACH ( const CTransaction & tx , pblock - > vtx )
BOOST_FOREACH ( const CTransaction & tx , block . vtx )
vDelete . push_back ( tx ) ;
vDelete . push_back ( tx ) ;
}
}
@ -1683,8 +1742,8 @@ bool CBlock::SetBestChain(CBlockIndex* pindexNew)
bnBestChainWork = pindexNew - > bnChainWork ;
bnBestChainWork = pindexNew - > bnChainWork ;
nTimeBestReceived = GetTime ( ) ;
nTimeBestReceived = GetTime ( ) ;
nTransactionsUpdated + + ;
nTransactionsUpdated + + ;
printf ( " SetBestChain: new best=%s height=%d work=%s date=%s \n " ,
printf ( " SetBestChain: new best=%s height=%d work=%s tx=%lu date=%s \n " ,
hashBestChain . ToString ( ) . substr ( 0 , 20 ) . c_str ( ) , nBestHeight , bnBestChainWork . ToString ( ) . c_str ( ) ,
hashBestChain . ToString ( ) . substr ( 0 , 20 ) . c_str ( ) , nBestHeight , bnBestChainWork . ToString ( ) . c_str ( ) , ( unsigned long ) pindexNew - > nChainTx ,
DateTimeStrFormat ( " %x %H:%M:%S " , pindexBest - > GetBlockTime ( ) ) . c_str ( ) ) ;
DateTimeStrFormat ( " %x %H:%M:%S " , pindexBest - > GetBlockTime ( ) ) . c_str ( ) ) ;
// Check the version of the last 100 blocks to see if we need to upgrade:
// Check the version of the last 100 blocks to see if we need to upgrade:
@ -1736,9 +1795,14 @@ bool CBlock::AddToBlockIndex(const CDiskBlockPos &pos)
pindexNew - > pprev = ( * miPrev ) . second ;
pindexNew - > pprev = ( * miPrev ) . second ;
pindexNew - > nHeight = pindexNew - > pprev - > nHeight + 1 ;
pindexNew - > nHeight = pindexNew - > pprev - > nHeight + 1 ;
}
}
pindexNew - > nTx = vtx . size ( ) ;
pindexNew - > bnChainWork = ( pindexNew - > pprev ? pindexNew - > pprev - > bnChainWork : 0 ) + pindexNew - > GetBlockWork ( ) ;
pindexNew - > bnChainWork = ( pindexNew - > pprev ? pindexNew - > pprev - > bnChainWork : 0 ) + pindexNew - > GetBlockWork ( ) ;
pindexNew - > pos = pos ;
pindexNew - > nChainTx = ( pindexNew - > pprev ? pindexNew - > pprev - > nChainTx : 0 ) + pindexNew - > nTx ;
pindexNew - > nFile = pos . nFile ;
pindexNew - > nDataPos = pos . nPos ;
pindexNew - > nUndoPos = 0 ;
pindexNew - > nUndoPos = 0 ;
pindexNew - > nStatus = BLOCK_VALID_TRANSACTIONS | BLOCK_HAVE_DATA ;
setBlockIndexValid . insert ( pindexNew ) ;
CChainDB chaindb ;
CChainDB chaindb ;
if ( ! chaindb . TxnBegin ( ) )
if ( ! chaindb . TxnBegin ( ) )
@ -1747,8 +1811,8 @@ bool CBlock::AddToBlockIndex(const CDiskBlockPos &pos)
if ( ! chaindb . TxnCommit ( ) )
if ( ! chaindb . TxnCommit ( ) )
return false ;
return false ;
// New best
// New best?
if ( ! SetBestChain ( pindexNew ) )
if ( ! ConnectBestBlock ( ) )
return false ;
return false ;
if ( pindexNew = = pindexBest )
if ( pindexNew = = pindexBest )