@ -41,6 +41,7 @@ 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 ;
@ -77,13 +78,21 @@ namespace {
struct CBlockIndexWorkComparator
struct CBlockIndexWorkComparator
{
{
bool operator ( ) ( CBlockIndex * pa , CBlockIndex * pb ) {
bool operator ( ) ( CBlockIndex * pa , CBlockIndex * pb ) {
// First sort by most total work, ...
if ( pa - > nChainWork > pb - > nChainWork ) return false ;
if ( pa - > nChainWork > pb - > nChainWork ) return false ;
if ( pa - > nChainWork < pb - > nChainWork ) return true ;
if ( pa - > nChainWork < pb - > nChainWork ) return true ;
if ( pa - > GetBlockHash ( ) < pb - > GetBlockHash ( ) ) return false ;
// ... then by earliest time received, ...
if ( pa - > GetBlockHash ( ) > pb - > GetBlockHash ( ) ) return true ;
if ( pa - > nSequenceId < pb - > nSequenceId ) return false ;
if ( pa - > nSequenceId > pb - > nSequenceId ) return true ;
return false ; // identical blocks
// 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 ;
}
}
} ;
} ;
@ -93,6 +102,16 @@ set<CBlockIndex*, CBlockIndexWorkComparator> setBlockIndexValid; // may contain
CCriticalSection cs_LastBlockFile ;
CCriticalSection cs_LastBlockFile ;
CBlockFileInfo infoLastBlockFile ;
CBlockFileInfo infoLastBlockFile ;
int nLastBlockFile = 0 ;
int nLastBlockFile = 0 ;
// Every received block is assigned a unique and increasing identifier, so we
// know which one to give priority in case of a fork.
CCriticalSection cs_nBlockSequenceId ;
// Blocks loaded from disk are assigned id 0, so start the counter at 1.
uint32_t nBlockSequenceId = 1 ;
// Sources of received blocks, to be able to send them reject messages or ban
// them, if processing happens afterwards. Protected by cs_main.
map < uint256 , NodeId > mapBlockSource ;
}
}
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
@ -156,14 +175,26 @@ void SyncWithWallets(const uint256 &hash, const CTransaction &tx, const CBlock *
//
//
namespace {
namespace {
struct CBlockReject {
unsigned char chRejectCode ;
string strRejectReason ;
uint256 hashBlock ;
} ;
// Maintain validation-specific state about nodes, protected by cs_main, instead
// Maintain validation-specific state about nodes, protected by cs_main, instead
// by CNode's own locks. This simplifies asynchronous operation, where
// by CNode's own locks. This simplifies asynchronous operation, where
// processing of incoming data is done after the ProcessMessage call returns,
// processing of incoming data is done after the ProcessMessage call returns,
// and we're no longer holding the node's locks.
// and we're no longer holding the node's locks.
struct CNodeState {
struct CNodeState {
// Accumulated misbehaviour score for this peer.
int nMisbehavior ;
int nMisbehavior ;
// Whether this peer should be disconnected and banned.
bool fShouldBan ;
bool fShouldBan ;
// String name of this peer (debugging/logging purposes).
std : : string name ;
std : : string name ;
// List of asynchronously-determined block rejections to notify this peer about.
std : : vector < CBlockReject > rejects ;
CNodeState ( ) {
CNodeState ( ) {
nMisbehavior = 0 ;
nMisbehavior = 0 ;
@ -171,6 +202,7 @@ struct CNodeState {
}
}
} ;
} ;
// Map maintaining per-node state. Requires cs_main.
map < NodeId , CNodeState > mapNodeState ;
map < NodeId , CNodeState > mapNodeState ;
// Requires cs_main.
// Requires cs_main.
@ -1242,6 +1274,24 @@ void CheckForkWarningConditionsOnNewFork(CBlockIndex* pindexNewForkTip)
CheckForkWarningConditions ( ) ;
CheckForkWarningConditions ( ) ;
}
}
void Misbehaving ( NodeId pnode , int howmuch )
{
if ( howmuch = = 0 )
return ;
CNodeState * state = State ( pnode ) ;
if ( state = = NULL )
return ;
state - > nMisbehavior + = howmuch ;
if ( state - > nMisbehavior > = GetArg ( " -banscore " , 100 ) )
{
LogPrintf ( " Misbehaving: %s (%d -> %d) BAN THRESHOLD EXCEEDED \n " , state - > name , state - > nMisbehavior - howmuch , state - > nMisbehavior ) ;
state - > fShouldBan = true ;
} else
LogPrintf ( " Misbehaving: %s (%d -> %d) \n " , state - > name , state - > nMisbehavior - howmuch , state - > nMisbehavior ) ;
}
void static InvalidChainFound ( CBlockIndex * pindexNew )
void static InvalidChainFound ( CBlockIndex * pindexNew )
{
{
if ( ! pindexBestInvalid | | pindexNew - > nChainWork > pindexBestInvalid - > nChainWork )
if ( ! pindexBestInvalid | | pindexNew - > nChainWork > pindexBestInvalid - > nChainWork )
@ -1263,67 +1313,23 @@ void static InvalidChainFound(CBlockIndex* pindexNew)
CheckForkWarningConditions ( ) ;
CheckForkWarningConditions ( ) ;
}
}
void static InvalidBlockFound ( CBlockIndex * pindex ) {
void static InvalidBlockFound ( CBlockIndex * pindex , const CValidationState & state ) {
pindex - > nStatus | = BLOCK_FAILED_VALID ;
int nDoS = 0 ;
pblocktree - > WriteBlockIndex ( CDiskBlockIndex ( pindex ) ) ;
if ( state . IsInvalid ( nDoS ) ) {
setBlockIndexValid . erase ( pindex ) ;
std : : map < uint256 , NodeId > : : iterator it = mapBlockSource . find ( pindex - > GetBlockHash ( ) ) ;
InvalidChainFound ( pindex ) ;
if ( it ! = mapBlockSource . end ( ) & & State ( it - > second ) ) {
if ( chainActive . Next ( pindex ) ) {
CBlockReject reject = { state . GetRejectCode ( ) , state . GetRejectReason ( ) , pindex - > GetBlockHash ( ) } ;
CValidationState stateDummy ;
State ( it - > second ) - > rejects . push_back ( reject ) ;
ConnectBestBlock ( stateDummy ) ; // reorganise away from the failed block
if ( nDoS > 0 )
}
Misbehaving ( it - > second , nDoS ) ;
}
bool ConnectBestBlock ( CValidationState & state ) {
do {
CBlockIndex * pindexNewBest ;
{
std : : set < CBlockIndex * , CBlockIndexWorkComparator > : : reverse_iterator it = setBlockIndexValid . rbegin ( ) ;
if ( it = = setBlockIndexValid . rend ( ) )
return true ;
pindexNewBest = * it ;
}
}
}
if ( pindexNewBest = = chainActive . Tip ( ) | | ( chainActive . Tip ( ) & & pindexNewBest - > nChainWork = = chainActive . Tip ( ) - > nChainWork ) )
if ( ! state . CorruptionPossible ( ) ) {
return true ; // nothing to do
pindex - > nStatus | = BLOCK_FAILED_VALID ;
pblocktree - > WriteBlockIndex ( CDiskBlockIndex ( pindex ) ) ;
// check ancestry
setBlockIndexValid . erase ( pindex ) ;
CBlockIndex * pindexTest = pindexNewBest ;
InvalidChainFound ( pindex ) ;
std : : vector < CBlockIndex * > vAttach ;
}
do {
if ( pindexTest - > nStatus & BLOCK_FAILED_MASK ) {
// mark descendants failed
CBlockIndex * pindexFailed = pindexNewBest ;
while ( pindexTest ! = pindexFailed ) {
pindexFailed - > nStatus | = BLOCK_FAILED_CHILD ;
setBlockIndexValid . erase ( pindexFailed ) ;
pblocktree - > WriteBlockIndex ( CDiskBlockIndex ( pindexFailed ) ) ;
pindexFailed = pindexFailed - > pprev ;
}
InvalidChainFound ( pindexNewBest ) ;
break ;
}
if ( chainActive . Tip ( ) = = NULL | | pindexTest - > nChainWork > chainActive . Tip ( ) - > nChainWork )
vAttach . push_back ( pindexTest ) ;
if ( pindexTest - > pprev = = NULL | | chainActive . Next ( pindexTest ) ) {
reverse ( vAttach . begin ( ) , vAttach . end ( ) ) ;
BOOST_FOREACH ( CBlockIndex * pindexSwitch , vAttach ) {
boost : : this_thread : : interruption_point ( ) ;
try {
if ( ! SetBestChain ( state , pindexSwitch ) )
return false ;
} catch ( std : : runtime_error & e ) {
return state . Abort ( _ ( " System error: " ) + e . what ( ) ) ;
}
}
return true ;
}
pindexTest = pindexTest - > pprev ;
} while ( true ) ;
} while ( true ) ;
}
}
void UpdateTime ( CBlockHeader & block , const CBlockIndex * pindexPrev )
void UpdateTime ( CBlockHeader & block , const CBlockIndex * pindexPrev )
@ -1746,8 +1752,10 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C
return true ;
return true ;
}
}
// Update the on-disk chain state.
bool static WriteChainState ( CValidationState & state ) {
bool static WriteChainState ( CValidationState & state ) {
if ( ! IsInitialBlockDownload ( ) | | pcoinsTip - > GetCacheSize ( ) > nCoinCacheSize ) {
static int64_t nLastWrite = 0 ;
if ( ! IsInitialBlockDownload ( ) | | pcoinsTip - > GetCacheSize ( ) > nCoinCacheSize | | GetTimeMicros ( ) > nLastWrite + 600 * 1000000 ) {
// Typical CCoins structures on disk are around 100 bytes in size.
// Typical CCoins structures on disk are around 100 bytes in size.
// Pushing a new one to the database can cause it to be written
// Pushing a new one to the database can cause it to be written
// twice (once in the log, and once in the tables). This is already
// twice (once in the log, and once in the tables). This is already
@ -1759,10 +1767,12 @@ bool static WriteChainState(CValidationState &state) {
pblocktree - > Sync ( ) ;
pblocktree - > Sync ( ) ;
if ( ! pcoinsTip - > Flush ( ) )
if ( ! pcoinsTip - > Flush ( ) )
return state . Abort ( _ ( " Failed to write to coin database " ) ) ;
return state . Abort ( _ ( " Failed to write to coin database " ) ) ;
nLastWrite = GetTimeMicros ( ) ;
}
}
return true ;
return true ;
}
}
// Update chainActive and related internal data structures.
void static UpdateTip ( CBlockIndex * pindexNew ) {
void static UpdateTip ( CBlockIndex * pindexNew ) {
chainActive . SetTip ( pindexNew ) ;
chainActive . SetTip ( pindexNew ) ;
@ -1796,129 +1806,179 @@ void static UpdateTip(CBlockIndex *pindexNew) {
// strMiscWarning is read by GetWarnings(), called by Qt and the JSON-RPC code to warn the user:
// strMiscWarning is read by GetWarnings(), called by Qt and the JSON-RPC code to warn the user:
strMiscWarning = _ ( " Warning: This version is obsolete, upgrade required! " ) ;
strMiscWarning = _ ( " Warning: This version is obsolete, upgrade required! " ) ;
}
}
}
std : : string strCmd = GetArg ( " -blocknotify " , " " ) ;
// Disconnect chainActive's tip.
bool static DisconnectTip ( CValidationState & state ) {
if ( ! fIsInitialDownload & & ! strCmd . empty ( ) )
CBlockIndex * pindexDelete = chainActive . Tip ( ) ;
assert ( pindexDelete ) ;
mempool . check ( pcoinsTip ) ;
// Read block from disk.
CBlock block ;
if ( ! ReadBlockFromDisk ( block , pindexDelete ) )
return state . Abort ( _ ( " Failed to read block " ) ) ;
// Apply the block atomically to the chain state.
int64_t nStart = GetTimeMicros ( ) ;
{
{
boost : : replace_all ( strCmd , " %s " , chainActive . Tip ( ) - > GetBlockHash ( ) . GetHex ( ) ) ;
CCoinsViewCache view ( * pcoinsTip , true ) ;
boost : : thread t ( runCommand , strCmd ) ; // thread runs free
if ( ! DisconnectBlock ( block , state , pindexDelete , view ) )
return error ( " DisconnectTip() : DisconnectBlock % s failed " , pindexDelete->GetBlockHash().ToString()) ;
assert ( view . Flush ( ) ) ;
}
}
if ( fBenchmark )
LogPrintf ( " - Disconnect: %.2fms \n " , ( GetTimeMicros ( ) - nStart ) * 0.001 ) ;
// Write the chain state to disk, if necessary.
if ( ! WriteChainState ( state ) )
return false ;
// Ressurect mempool transactions from the disconnected block.
BOOST_FOREACH ( const CTransaction & tx , block . vtx ) {
// ignore validation errors in resurrected transactions
CValidationState stateDummy ;
if ( ! tx . IsCoinBase ( ) )
if ( ! AcceptToMemoryPool ( mempool , stateDummy , tx , false , NULL ) )
mempool . remove ( tx , true ) ;
}
mempool . check ( pcoinsTip ) ;
// Update chainActive and related variables.
UpdateTip ( pindexDelete - > pprev ) ;
return true ;
}
}
bool SetBestChain ( CValidationState & state , CBlockIndex * pindexNew )
// Connect a new block to chainActive.
{
bool static ConnectTip ( CValidationState & state , CBlockIndex * pindexNew ) {
assert ( pindexNew - > pprev = = chainActive . Tip ( ) ) ;
mempool . check ( pcoinsTip ) ;
mempool . check ( pcoinsTip ) ;
// Read block from disk.
// All modifications to the coin state will be done in this cache.
CBlock block ;
// Only when all have succeeded, we push it to pcoinsTip.
if ( ! ReadBlockFromDisk ( block , pindexNew ) )
CCoinsViewCache view ( * pcoinsTip , true ) ;
return state . Abort ( _ ( " Failed to read block " ) ) ;
// Apply the block atomically to the chain state.
// Find the fork (typically, there is none)
int64_t nStart = GetTimeMicros ( ) ;
std : : map < uint256 , CBlockIndex * > : : iterator it = mapBlockIndex . find ( view . GetBestBlock ( ) ) ;
CBlockIndex * ptip = ( it ! = mapBlockIndex . end ( ) ) ? it - > second : NULL ;
CBlockIndex * pfork = ptip ;
CBlockIndex * plonger = pindexNew ;
while ( pfork & & pfork ! = plonger )
{
{
while ( plonger - > nHeight > pfork - > nHeight ) {
CCoinsViewCache view ( * pcoinsTip , true ) ;
plonger = plonger - > pprev ;
CInv inv ( MSG_BLOCK , pindexNew - > GetBlockHash ( ) ) ;
assert ( plonger ! = NULL ) ;
if ( ! ConnectBlock ( block , state , pindexNew , view ) ) {
if ( state . IsInvalid ( ) )
InvalidBlockFound ( pindexNew , state ) ;
return error ( " ConnectTip() : ConnectBlock % s failed " , pindexNew->GetBlockHash().ToString()) ;
}
}
if ( pfork = = plonger )
mapBlockSource . erase ( inv . hash ) ;
break ;
assert ( view . Flush ( ) ) ;
pfork = pfork - > pprev ;
assert ( pfork ! = NULL ) ;
}
}
if ( fBenchmark )
LogPrintf ( " - Connect: %.2fms \n " , ( GetTimeMicros ( ) - nStart ) * 0.001 ) ;
// Write the chain state to disk, if necessary.
if ( ! WriteChainState ( state ) )
return false ;
// Remove conflicting transactions from the mempool.
BOOST_FOREACH ( const CTransaction & tx , block . vtx ) {
mempool . remove ( tx ) ;
mempool . removeConflicts ( tx ) ;
}
mempool . check ( pcoinsTip ) ;
// Update chainActive & related variables.
UpdateTip ( pindexNew ) ;
return true ;
}
// List of what to disconnect (typically nothing)
// Make chainMostWork correspond to the chain with the most work in it, that isn't
vector < CBlockIndex * > vDisconnect ;
// known to be invalid (it's however far from certain to be valid).
for ( CBlockIndex * pindex = ptip ; pindex ! = pfork ; pindex = pindex - > pprev )
void static FindMostWorkChain ( ) {
vDisconnect . push_back ( pindex ) ;
CBlockIndex * pindexNew = NULL ;
// List of what to connect (typically only pindexNew)
vector < CBlockIndex * > vConnect ;
for ( CBlockIndex * pindex = pindexNew ; pindex ! = pfork ; pindex = pindex - > pprev )
vConnect . push_back ( pindex ) ;
reverse ( vConnect . begin ( ) , vConnect . end ( ) ) ;
if ( vDisconnect . size ( ) > 0 ) {
// In case the current best is invalid, do not consider it.
LogPrintf ( " REORGANIZE: Disconnect % " PRIszu " blocks; %s... \n " , vDisconnect . size ( ) , pfork - > GetBlockHash ( ) . ToString ( ) ) ;
while ( chainMostWork . Tip ( ) & & ( chainMostWork . Tip ( ) - > nStatus & BLOCK_FAILED_MASK ) ) {
LogPrintf ( " REORGANIZE: Connect % " PRIszu " blocks; ...%s \n " , vConnect . size ( ) , pindexNew - > GetBlockHash ( ) . ToString ( ) ) ;
setBlockIndexValid . erase ( chainMostWork . Tip ( ) ) ;
chainMostWork . SetTip ( chainMostWork . Tip ( ) - > pprev ) ;
}
}
// Disconnect shorter branch
do {
list < CTransaction > vResurrect ;
// Find the best candidate header.
BOOST_FOREACH ( CBlockIndex * pindex , vDisconnect ) {
{
CBlock block ;
std : : set < CBlockIndex * , CBlockIndexWorkComparator > : : reverse_iterator it = setBlockIndexValid . rbegin ( ) ;
if ( ! ReadBlockFromDisk ( block , pindex ) )
if ( it = = setBlockIndexValid . rend ( ) )
return state . Abort ( _ ( " Failed to read block " ) ) ;
return ;
int64_t nStart = GetTimeMicros ( ) ;
pindexNew = * it ;
if ( ! DisconnectBlock ( block , state , pindex , view ) )
}
return error ( " SetBestBlock() : DisconnectBlock % s failed " , pindex->GetBlockHash().ToString()) ;
if ( fBenchmark )
LogPrintf ( " - Disconnect: %.2fms \n " , ( GetTimeMicros ( ) - nStart ) * 0.001 ) ;
// Queue memory transactions to resurrect.
// We only do this for blocks after the last checkpoint (reorganisation before that
// point should only happen with -reindex/-loadblock, or a misbehaving peer.
BOOST_REVERSE_FOREACH ( const CTransaction & tx , block . vtx )
if ( ! tx . IsCoinBase ( ) & & pindex - > nHeight > Checkpoints : : GetTotalBlocksEstimate ( ) )
vResurrect . push_front ( tx ) ;
}
// Connect longer branch
// Check whether all blocks on the path between the currently active chain and the candidate are valid.
vector < CTransaction > vDelete ;
// Just going until the active chain is an optimization, as we know all blocks in it are valid already.
BOOST_FOREACH ( CBlockIndex * pindex , vConnect ) {
CBlockIndex * pindexTest = pindexNew ;
CBlock block ;
bool fInvalidAncestor = false ;
if ( ! ReadBlockFromDisk ( block , pindex ) )
while ( pindexTest & & ! chainActive . Contains ( pindexTest ) ) {
return state . Abort ( _ ( " Failed to read block " ) ) ;
if ( pindexTest - > nStatus & BLOCK_FAILED_MASK ) {
int64_t nStart = GetTimeMicros ( ) ;
// Candidate has an invalid ancestor, remove entire chain from the set.
if ( ! ConnectBlock ( block , state , pindex , view ) ) {
if ( pindexBestInvalid = = NULL | | pindexNew - > nChainWork > pindexBestInvalid - > nChainWork )
if ( state . IsInvalid ( ) ) {
pindexBestInvalid = pindexNew ; CBlockIndex * pindexFailed = pindexNew ;
InvalidChainFound ( pindexNew ) ;
while ( pindexTest ! = pindexFailed ) {
InvalidBlockFound ( pindex ) ;
pindexFailed - > nStatus | = BLOCK_FAILED_CHILD ;
setBlockIndexValid . erase ( pindexFailed ) ;
pindexFailed = pindexFailed - > pprev ;
}
fInvalidAncestor = true ;
break ;
}
}
return error ( " SetBestBlock() : ConnectBlock % s failed " , pindex->GetBlockHash().ToString()) ;
pindexTest = pindexTest - > pprev ;
}
}
if ( fBenchmark )
if ( fInvalidAncestor )
LogPrintf ( " - Connect: %.2fms \n " , ( GetTimeMicros ( ) - nStart ) * 0.001 ) ;
continue ;
// Queue memory transactions to delete
break ;
BOOST_FOREACH ( const CTransaction & tx , block . vtx )
} while ( true ) ;
vDelete . push_back ( tx ) ;
}
// Flush changes to global coin state
// Check whether it's actually an improvement.
int64_t nStart = GetTimeMicros ( ) ;
if ( chainMostWork . Tip ( ) & & ! CBlockIndexWorkComparator ( ) ( chainMostWork . Tip ( ) , pindexNew ) )
int nModified = view . GetCacheSize ( ) ;
return ;
bool ret ;
ret = view . Flush ( ) ;
assert ( ret ) ;
int64_t nTime = GetTimeMicros ( ) - nStart ;
if ( fBenchmark )
LogPrintf ( " - Flush %i transactions: %.2fms (%.4fms/tx) \n " , nModified , 0.001 * nTime , 0.001 * nTime / nModified ) ;
if ( ! WriteChainState ( state ) )
// We have a new best.
return false ;
chainMostWork . SetTip ( pindexNew ) ;
}
// Resurrect memory transactions that were in the disconnected branch
// Try to activate to the most-work chain (thereby connecting it).
BOOST_FOREACH ( CTransaction & tx , vResurrect ) {
bool ActivateBestChain ( CValidationState & state ) {
// ignore validation errors in resurrected transactions
CBlockIndex * pindexOldTip = chainActive . Tip ( ) ;
CValidationState stateDummy ;
bool fComplete = false ;
if ( ! AcceptToMemoryPool ( mempool , stateDummy , tx , false , NULL ) )
while ( ! fComplete ) {
mempool . remove ( tx , true ) ;
FindMostWorkChain ( ) ;
}
fComplete = true ;
// Delete redundant memory transactions that are in the connected branch
// Check whether we have something to do.
BOOST_FOREACH ( CTransaction & tx , vDelete ) {
if ( chainMostWork . Tip ( ) = = NULL ) break ;
mempool . remove ( tx ) ;
mempool . removeConflicts ( tx ) ;
// Disconnect active blocks which are no longer in the best chain.
while ( chainActive . Tip ( ) & & ! chainMostWork . Contains ( chainActive . Tip ( ) ) ) {
if ( ! DisconnectTip ( state ) )
return false ;
}
// Connect new blocks.
while ( ! chainActive . Contains ( chainMostWork . Tip ( ) ) ) {
CBlockIndex * pindexConnect = chainMostWork [ chainActive . Height ( ) + 1 ] ;
if ( ! ConnectTip ( state , pindexConnect ) ) {
if ( state . IsInvalid ( ) ) {
// The block violates a consensus rule.
if ( ! state . CorruptionPossible ( ) )
InvalidChainFound ( chainMostWork . Tip ( ) ) ;
fComplete = false ;
state = CValidationState ( ) ;
break ;
} else {
// A system error occurred (disk space, database error, ...).
return false ;
}
}
}
}
}
mempool . check ( pcoinsTip ) ;
if ( chainActive . Tip ( ) ! = pindexOldTip ) {
std : : string strCmd = GetArg ( " -blocknotify " , " " ) ;
if ( ! IsInitialBlockDownload ( ) & & ! strCmd . empty ( ) )
{
boost : : replace_all ( strCmd , " %s " , chainActive . Tip ( ) - > GetBlockHash ( ) . GetHex ( ) ) ;
boost : : thread t ( runCommand , strCmd ) ; // thread runs free
}
}
UpdateTip ( pindexNew ) ;
return true ;
return true ;
}
}
@ -1931,7 +1991,12 @@ bool AddToBlockIndex(CBlock& block, CValidationState& state, const CDiskBlockPos
// Construct new block index object
// Construct new block index object
CBlockIndex * pindexNew = new CBlockIndex ( block ) ;
CBlockIndex * pindexNew = new CBlockIndex ( block ) ;
{
LOCK ( cs_nBlockSequenceId ) ;
pindexNew - > nSequenceId = nBlockSequenceId + + ;
}
assert ( pindexNew ) ;
assert ( pindexNew ) ;
mapAlreadyAskedFor . erase ( CInv ( MSG_BLOCK , hash ) ) ;
map < uint256 , CBlockIndex * > : : iterator mi = mapBlockIndex . insert ( make_pair ( hash , pindexNew ) ) . first ;
map < uint256 , CBlockIndex * > : : iterator mi = mapBlockIndex . insert ( make_pair ( hash , pindexNew ) ) . first ;
pindexNew - > phashBlock = & ( ( * mi ) . first ) ;
pindexNew - > phashBlock = & ( ( * mi ) . first ) ;
map < uint256 , CBlockIndex * > : : iterator miPrev = mapBlockIndex . find ( block . hashPrevBlock ) ;
map < uint256 , CBlockIndex * > : : iterator miPrev = mapBlockIndex . find ( block . hashPrevBlock ) ;
@ -1953,7 +2018,7 @@ bool AddToBlockIndex(CBlock& block, CValidationState& state, const CDiskBlockPos
return state . Abort ( _ ( " Failed to write block index " ) ) ;
return state . Abort ( _ ( " Failed to write block index " ) ) ;
// New best?
// New best?
if ( ! ConnectBestBlock ( state ) )
if ( ! ActivateBestChain ( state ) )
return false ;
return false ;
if ( pindexNew = = chainActive . Tip ( ) )
if ( pindexNew = = chainActive . Tip ( ) )
@ -2277,8 +2342,11 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl
return state . Invalid ( error ( " ProcessBlock() : already have block (orphan) %s " , hash . ToString ( ) ) ) ;
return state . Invalid ( error ( " ProcessBlock() : already have block (orphan) %s " , hash . ToString ( ) ) ) ;
// Preliminary checks
// Preliminary checks
if ( ! CheckBlock ( * pblock , state ) )
if ( ! CheckBlock ( * pblock , state ) ) {
if ( state . CorruptionPossible ( ) )
mapAlreadyAskedFor . erase ( CInv ( MSG_BLOCK , hash ) ) ;
return error ( " ProcessBlock() : CheckBlock FAILED " ) ;
return error ( " ProcessBlock() : CheckBlock FAILED " ) ;
}
CBlockIndex * pcheckpoint = Checkpoints : : GetLastCheckpoint ( mapBlockIndex ) ;
CBlockIndex * pcheckpoint = Checkpoints : : GetLastCheckpoint ( mapBlockIndex ) ;
if ( pcheckpoint & & pblock - > hashPrevBlock ! = ( chainActive . Tip ( ) ? chainActive . Tip ( ) - > GetBlockHash ( ) : uint256 ( 0 ) ) )
if ( pcheckpoint & & pblock - > hashPrevBlock ! = ( chainActive . Tip ( ) ? chainActive . Tip ( ) - > GetBlockHash ( ) : uint256 ( 0 ) ) )
@ -3007,24 +3075,6 @@ bool static AlreadyHave(const CInv& inv)
}
}
void Misbehaving ( NodeId pnode , int howmuch )
{
if ( howmuch = = 0 )
return ;
CNodeState * state = State ( pnode ) ;
if ( state = = NULL )
return ;
state - > nMisbehavior + = howmuch ;
if ( state - > nMisbehavior > = GetArg ( " -banscore " , 100 ) )
{
LogPrintf ( " Misbehaving: %s (%d -> %d) BAN THRESHOLD EXCEEDED \n " , state - > name , state - > nMisbehavior - howmuch , state - > nMisbehavior ) ;
state - > fShouldBan = true ;
} else
LogPrintf ( " Misbehaving: %s (%d -> %d) \n " , state - > name , state - > nMisbehavior - howmuch , state - > nMisbehavior ) ;
}
void static ProcessGetData ( CNode * pfrom )
void static ProcessGetData ( CNode * pfrom )
{
{
std : : deque < CInv > : : iterator it = pfrom - > vRecvGetData . begin ( ) ;
std : : deque < CInv > : : iterator it = pfrom - > vRecvGetData . begin ( ) ;
@ -3587,18 +3637,11 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
pfrom - > AddInventoryKnown ( inv ) ;
pfrom - > AddInventoryKnown ( inv ) ;
LOCK ( cs_main ) ;
LOCK ( cs_main ) ;
// Remember who we got this block from.
mapBlockSource [ inv . hash ] = pfrom - > GetId ( ) ;
CValidationState state ;
CValidationState state ;
if ( ProcessBlock ( state , pfrom , & block ) | | state . CorruptionPossible ( ) )
ProcessBlock ( state , pfrom , & block ) ;
mapAlreadyAskedFor . erase ( inv ) ;
int nDoS = 0 ;
if ( state . IsInvalid ( nDoS ) )
{
pfrom - > PushMessage ( " reject " , strCommand , state . GetRejectCode ( ) ,
state . GetRejectReason ( ) , inv . hash ) ;
if ( nDoS > 0 )
Misbehaving ( pfrom - > GetId ( ) , nDoS ) ;
}
}
}
@ -4045,16 +4088,21 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
if ( ! lockMain )
if ( ! lockMain )
return true ;
return true ;
if ( State ( pto - > GetId ( ) ) - > fShouldBan ) {
CNodeState & state = * State ( pto - > GetId ( ) ) ;
if ( state . fShouldBan ) {
if ( pto - > addr . IsLocal ( ) )
if ( pto - > addr . IsLocal ( ) )
LogPrintf ( " Warning: not banning local node %s! \n " , pto - > addr . ToString ( ) ) ;
LogPrintf ( " Warning: not banning local node %s! \n " , pto - > addr . ToString ( ) ) ;
else {
else {
pto - > fDisconnect = true ;
pto - > fDisconnect = true ;
CNode : : Ban ( pto - > addr ) ;
CNode : : Ban ( pto - > addr ) ;
}
}
State ( pto - > GetId ( ) ) - > fShouldBan = false ;
state . fShouldBan = false ;
}
}
BOOST_FOREACH ( const CBlockReject & reject , state . rejects )
pto - > PushMessage ( " reject " , ( string ) " block " , reject . chRejectCode , reject . strRejectReason , reject . hashBlock ) ;
state . rejects . clear ( ) ;
// Start block sync
// Start block sync
if ( pto - > fStartSync & & ! fImporting & & ! fReindex ) {
if ( pto - > fStartSync & & ! fImporting & & ! fReindex ) {
pto - > fStartSync = false ;
pto - > fStartSync = false ;