@ -1849,8 +1849,13 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C
if ( fJustCheck )
if ( fJustCheck )
return true ;
return true ;
// Correct transaction counts.
pindex - > nTx = block . vtx . size ( ) ;
if ( pindex - > pprev )
pindex - > nChainTx = pindex - > pprev - > nChainTx + block . vtx . size ( ) ;
// Write undo information to disk
// Write undo information to disk
if ( pindex - > GetUndoPos ( ) . IsNull ( ) | | ( pindex - > nStatus & BLOCK_VALID_MASK ) < BLOCK_VALID_SCRIPTS )
if ( pindex - > GetUndoPos ( ) . IsNull ( ) | | ! pindex - > IsValid ( BLOCK_VALID_SCRIPTS ) )
{
{
if ( pindex - > GetUndoPos ( ) . IsNull ( ) ) {
if ( pindex - > GetUndoPos ( ) . IsNull ( ) ) {
CDiskBlockPos pos ;
CDiskBlockPos pos ;
@ -1864,7 +1869,7 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C
pindex - > nStatus | = BLOCK_HAVE_UNDO ;
pindex - > nStatus | = BLOCK_HAVE_UNDO ;
}
}
pindex - > nStatus = ( pindex - > nStatus & ~ BLOCK_VALID_MASK ) | BLOCK_VALID_SCRIPTS ;
pindex - > RaiseValidity ( BLOCK_VALID_SCRIPTS ) ;
CDiskBlockIndex blockindex ( pindex ) ;
CDiskBlockIndex blockindex ( pindex ) ;
if ( ! pblocktree - > WriteBlockIndex ( blockindex ) )
if ( ! pblocktree - > WriteBlockIndex ( blockindex ) )
@ -2058,10 +2063,11 @@ void static FindMostWorkChain() {
CBlockIndex * pindexTest = pindexNew ;
CBlockIndex * pindexTest = pindexNew ;
bool fInvalidAncestor = false ;
bool fInvalidAncestor = false ;
while ( pindexTest & & ! chainActive . Contains ( pindexTest ) ) {
while ( pindexTest & & ! chainActive . Contains ( pindexTest ) ) {
if ( pindexTest - > nStatus & BLOCK_FAILED_MASK ) {
if ( ! pindexTest - > IsValid ( BLOCK_VALID_TRANSACTIONS ) | | ! ( pindexTest - > nStatus & BLOCK_HAVE_DATA ) ) {
// Candidate has an invalid ancestor, remove entire chain from the set.
// Candidate has an invalid ancestor, remove entire chain from the set.
if ( pindexBestInvalid = = NULL | | pindexNew - > nChainWork > pindexBestInvalid - > nChainWork )
if ( pindexBestInvalid = = NULL | | pindexNew - > nChainWork > pindexBestInvalid - > nChainWork )
pindexBestInvalid = pindexNew ; CBlockIndex * pindexFailed = pindexNew ;
pindexBestInvalid = pindexNew ;
CBlockIndex * pindexFailed = pindexNew ;
while ( pindexTest ! = pindexFailed ) {
while ( pindexTest ! = pindexFailed ) {
pindexFailed - > nStatus | = BLOCK_FAILED_CHILD ;
pindexFailed - > nStatus | = BLOCK_FAILED_CHILD ;
setBlockIndexValid . erase ( pindexFailed ) ;
setBlockIndexValid . erase ( pindexFailed ) ;
@ -2135,12 +2141,14 @@ bool ActivateBestChain(CValidationState &state) {
return true ;
return true ;
}
}
bool AddToBlockIndex ( CBlock & block , CValidationState & state , const CDiskBlockPos & pos )
CBlockIndex * AddToBlockIndex ( CBlockHeader & block )
{
{
// Check for duplicate
// Check for duplicate
uint256 hash = block . GetHash ( ) ;
uint256 hash = block . GetHash ( ) ;
if ( mapBlockIndex . count ( hash ) )
std : : map < uint256 , CBlockIndex * > : : iterator it = mapBlockIndex . find ( hash ) ;
return state . Invalid ( error ( " AddToBlockIndex() : %s already exists " , hash . ToString ( ) ) , 0 , " duplicate " ) ;
if ( it ! = mapBlockIndex . end ( ) )
return it - > second ;
// Construct new block index object
// Construct new block index object
CBlockIndex * pindexNew = new CBlockIndex ( block ) ;
CBlockIndex * pindexNew = new CBlockIndex ( block ) ;
@ -2157,14 +2165,38 @@ bool AddToBlockIndex(CBlock& block, CValidationState& state, const CDiskBlockPos
pindexNew - > pprev = ( * miPrev ) . second ;
pindexNew - > pprev = ( * miPrev ) . second ;
pindexNew - > nHeight = pindexNew - > pprev - > nHeight + 1 ;
pindexNew - > nHeight = pindexNew - > pprev - > nHeight + 1 ;
}
}
pindexNew - > nTx = block . vtx . size ( ) ;
pindexNew - > nChainWork = ( pindexNew - > pprev ? pindexNew - > pprev - > nChainWork : 0 ) + pindexNew - > GetBlockWork ( ) . getuint256 ( ) ;
pindexNew - > nChainWork = ( pindexNew - > pprev ? pindexNew - > pprev - > nChainWork : 0 ) + pindexNew - > GetBlockWork ( ) . getuint256 ( ) ;
pindexNew - > nChainTx = ( pindexNew - > pprev ? pindexNew - > pprev - > nChainTx : 0 ) + pindexNew - > nTx ;
pindexNew - > RaiseValidity ( BLOCK_VALID_TREE ) ;
return pindexNew ;
}
// Mark a block as having its data received and checked (up to BLOCK_VALID_TRANSACTIONS).
bool ReceivedBlockTransactions ( const CBlock & block , CValidationState & state , CBlockIndex * pindexNew , const CDiskBlockPos & pos )
{
pindexNew - > nTx = block . vtx . size ( ) ;
if ( pindexNew - > pprev ) {
// Not the genesis block.
if ( pindexNew - > pprev - > nChainTx ) {
// This parent's block's total number transactions is known, so compute outs.
pindexNew - > nChainTx = pindexNew - > pprev - > nChainTx + pindexNew - > nTx ;
} else {
// The total number of transactions isn't known yet.
// We will compute it when the block is connected.
pindexNew - > nChainTx = 0 ;
}
} else {
// Genesis block.
pindexNew - > nChainTx = pindexNew - > nTx ;
}
pindexNew - > nFile = pos . nFile ;
pindexNew - > nFile = pos . nFile ;
pindexNew - > nDataPos = pos . nPos ;
pindexNew - > nDataPos = pos . nPos ;
pindexNew - > nUndoPos = 0 ;
pindexNew - > nUndoPos = 0 ;
pindexNew - > nStatus = BLOCK_VALID_TRANSACTIONS | BLOCK_HAVE_DATA ;
pindexNew - > nStatus | = BLOCK_HAVE_DATA ;
setBlockIndexValid . insert ( pindexNew ) ;
if ( pindexNew - > RaiseValidity ( BLOCK_VALID_TRANSACTIONS ) )
setBlockIndexValid . insert ( pindexNew ) ;
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 " ) ) ;
@ -2292,14 +2324,35 @@ bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, bool f
{
{
// Check proof of work matches claimed amount
// Check proof of work matches claimed amount
if ( fCheckPOW & & ! CheckProofOfWork ( block . GetHash ( ) , block . nBits ) )
if ( fCheckPOW & & ! CheckProofOfWork ( block . GetHash ( ) , block . nBits ) )
return state . DoS ( 50 , error ( " CheckBlock() : proof of work failed " ) ,
return state . DoS ( 50 , error ( " CheckBlockHeader () : proof of work failed " ) ,
REJECT_INVALID , " high-hash " ) ;
REJECT_INVALID , " high-hash " ) ;
// Check timestamp
// Check timestamp
if ( block . GetBlockTime ( ) > GetAdjustedTime ( ) + 2 * 60 * 60 )
if ( block . GetBlockTime ( ) > GetAdjustedTime ( ) + 2 * 60 * 60 )
return state . Invalid ( error ( " CheckBlock() : block timestamp too far in the future " ) ,
return state . Invalid ( error ( " CheckBlockHeader () : block timestamp too far in the future " ) ,
REJECT_INVALID , " time-too-new " ) ;
REJECT_INVALID , " time-too-new " ) ;
CBlockIndex * pcheckpoint = Checkpoints : : GetLastCheckpoint ( mapBlockIndex ) ;
if ( pcheckpoint & & block . hashPrevBlock ! = ( chainActive . Tip ( ) ? chainActive . Tip ( ) - > GetBlockHash ( ) : uint256 ( 0 ) ) )
{
// Extra checks to prevent "fill up memory by spamming with bogus blocks"
int64_t deltaTime = block . GetBlockTime ( ) - pcheckpoint - > nTime ;
if ( deltaTime < 0 )
{
return state . DoS ( 100 , error ( " CheckBlockHeader() : block with timestamp before last checkpoint " ) ,
REJECT_CHECKPOINT , " time-too-old " ) ;
}
CBigNum bnNewBlock ;
bnNewBlock . SetCompact ( block . nBits ) ;
CBigNum bnRequired ;
bnRequired . SetCompact ( ComputeMinWork ( pcheckpoint - > nBits , deltaTime ) ) ;
if ( bnNewBlock > bnRequired )
{
return state . DoS ( 100 , error ( " CheckBlockHeader() : block with too little proof-of-work " ) ,
REJECT_INVALID , " bad-diffbits " ) ;
}
}
return true ;
return true ;
}
}
@ -2362,13 +2415,18 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo
return true ;
return true ;
}
}
bool AcceptBlock ( CBlock & block , CValidationState & state , CDiskBlockPos * dbp )
bool AcceptBlockHeader ( CBlockHeader & block , CValidationState & state , CBlockIndex * * ppindex )
{
{
AssertLockHeld ( cs_main ) ;
AssertLockHeld ( cs_main ) ;
// Check for duplicate
// Check for duplicate
uint256 hash = block . GetHash ( ) ;
uint256 hash = block . GetHash ( ) ;
if ( mapBlockIndex . count ( hash ) )
std : : map < uint256 , CBlockIndex * > : : iterator miSelf = mapBlockIndex . find ( hash ) ;
return state . Invalid ( error ( " AcceptBlock() : block already in mapBlockIndex " ) , 0 , " duplicate " ) ;
CBlockIndex * pindex = NULL ;
if ( miSelf ! = mapBlockIndex . end ( ) ) {
pindex = miSelf - > second ;
if ( pindex - > nStatus & BLOCK_FAILED_MASK )
return state . Invalid ( error ( " AcceptBlock() : block is marked invalid " ) , 0 , " duplicate " ) ;
}
// Get prev block index
// Get prev block index
CBlockIndex * pindexPrev = NULL ;
CBlockIndex * pindexPrev = NULL ;
@ -2390,12 +2448,6 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CDiskBlockPos* dbp)
return state . Invalid ( error ( " AcceptBlock() : block's timestamp is too early " ) ,
return state . Invalid ( error ( " AcceptBlock() : block's timestamp is too early " ) ,
REJECT_INVALID , " time-too-old " ) ;
REJECT_INVALID , " time-too-old " ) ;
// Check that all transactions are finalized
BOOST_FOREACH ( const CTransaction & tx , block . vtx )
if ( ! IsFinalTx ( tx , nHeight , block . GetBlockTime ( ) ) )
return state . DoS ( 10 , error ( " AcceptBlock() : contains a non-final transaction " ) ,
REJECT_INVALID , " bad-txns-nonfinal " ) ;
// Check that the block chain matches the known block chain up to a checkpoint
// Check that the block chain matches the known block chain up to a checkpoint
if ( ! Checkpoints : : CheckBlock ( nHeight , hash ) )
if ( ! Checkpoints : : CheckBlock ( nHeight , hash ) )
return state . DoS ( 100 , error ( " AcceptBlock() : rejected by checkpoint lock-in at %d " , nHeight ) ,
return state . DoS ( 100 , error ( " AcceptBlock() : rejected by checkpoint lock-in at %d " , nHeight ) ,
@ -2416,18 +2468,57 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CDiskBlockPos* dbp)
REJECT_OBSOLETE , " bad-version " ) ;
REJECT_OBSOLETE , " bad-version " ) ;
}
}
}
}
// Enforce block.nVersion=2 rule that the coinbase starts with serialized block height
}
if ( block . nVersion > = 2 )
if ( pindex = = NULL )
pindex = AddToBlockIndex ( block ) ;
if ( ppindex )
* ppindex = pindex ;
return true ;
}
bool AcceptBlock ( CBlock & block , CValidationState & state , CBlockIndex * * ppindex , CDiskBlockPos * dbp )
{
AssertLockHeld ( cs_main ) ;
CBlockIndex * & pindex = * ppindex ;
if ( ! AcceptBlockHeader ( block , state , & pindex ) )
return false ;
if ( ! CheckBlock ( block , state ) ) {
if ( state . Invalid ( ) & & ! state . CorruptionPossible ( ) ) {
pindex - > nStatus | = BLOCK_FAILED_VALID ;
}
return false ;
}
int nHeight = pindex - > nHeight ;
uint256 hash = pindex - > GetBlockHash ( ) ;
// Check that all transactions are finalized
BOOST_FOREACH ( const CTransaction & tx , block . vtx )
if ( ! IsFinalTx ( tx , nHeight , block . GetBlockTime ( ) ) ) {
pindex - > nStatus | = BLOCK_FAILED_VALID ;
return state . DoS ( 10 , error ( " AcceptBlock() : contains a non-final transaction " ) ,
REJECT_INVALID , " bad-txns-nonfinal " ) ;
}
// Enforce block.nVersion=2 rule that the coinbase starts with serialized block height
if ( block . nVersion > = 2 )
{
// if 750 of the last 1,000 blocks are version 2 or greater (51/100 if testnet):
if ( ( ! TestNet ( ) & & CBlockIndex : : IsSuperMajority ( 2 , pindex - > pprev , 750 , 1000 ) ) | |
( TestNet ( ) & & CBlockIndex : : IsSuperMajority ( 2 , pindex - > pprev , 51 , 100 ) ) )
{
{
// if 750 of the last 1,000 blocks are version 2 or greater (51/100 if testnet):
CScript expect = CScript ( ) < < nHeight ;
if ( ( ! TestNet ( ) & & CBlockIndex : : IsSuperMajority ( 2 , pindexPrev , 750 , 1000 ) ) | |
if ( block . vtx [ 0 ] . vin [ 0 ] . scriptSig . size ( ) < expect . size ( ) | |
( TestNet ( ) & & CBlockIndex : : IsSuperMajority ( 2 , pindexPrev , 51 , 100 ) ) )
! std : : equal ( expect . begin ( ) , expect . end ( ) , block . vtx [ 0 ] . vin [ 0 ] . scriptSig . begin ( ) ) ) {
{
pindex - > nStatus | = BLOCK_FAILED_VALID ;
CScript expect = CScript ( ) < < nHeight ;
return state . DoS ( 100 , error ( " AcceptBlock() : block height mismatch in coinbase " ) ,
if ( block . vtx [ 0 ] . vin [ 0 ] . scriptSig . size ( ) < expect . size ( ) | |
REJECT_INVALID , " bad-cb-height " ) ;
! std : : equal ( expect . begin ( ) , expect . end ( ) , block . vtx [ 0 ] . vin [ 0 ] . scriptSig . begin ( ) ) )
return state . DoS ( 100 , error ( " AcceptBlock() : block height mismatch in coinbase " ) ,
REJECT_INVALID , " bad-cb-height " ) ;
}
}
}
}
}
}
@ -2443,8 +2534,8 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CDiskBlockPos* dbp)
if ( dbp = = NULL )
if ( dbp = = NULL )
if ( ! WriteBlockToDisk ( block , blockPos ) )
if ( ! WriteBlockToDisk ( block , blockPos ) )
return state . Abort ( _ ( " Failed to write block " ) ) ;
return state . Abort ( _ ( " Failed to write block " ) ) ;
if ( ! AddToBlockIndex ( block , state , blockPos ) )
if ( ! ReceivedBlockTransactions ( block , state , pindex , blockPos ) )
return error ( " AcceptBlock() : AddToBlockIndex failed " ) ;
return error ( " AcceptBlock() : ReceivedBlockTransactions failed " ) ;
} catch ( std : : runtime_error & e ) {
} catch ( std : : runtime_error & e ) {
return state . Abort ( _ ( " System error: " ) + e . what ( ) ) ;
return state . Abort ( _ ( " System error: " ) + e . what ( ) ) ;
}
}
@ -2514,30 +2605,9 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl
if ( ! CheckBlock ( * pblock , state ) )
if ( ! CheckBlock ( * pblock , state ) )
return error ( " ProcessBlock() : CheckBlock FAILED " ) ;
return error ( " ProcessBlock() : CheckBlock FAILED " ) ;
CBlockIndex * pcheckpoint = Checkpoints : : GetLastCheckpoint ( mapBlockIndex ) ;
// If we don't already have its previous block (with full data), shunt it off to holding area until we get it
if ( pcheckpoint & & pblock - > hashPrevBlock ! = ( chainActive . Tip ( ) ? chainActive . Tip ( ) - > GetBlockHash ( ) : uint256 ( 0 ) ) )
std : : map < uint256 , CBlockIndex * > : : iterator it = mapBlockIndex . find ( pblock - > hashPrevBlock ) ;
{
if ( pblock - > hashPrevBlock ! = 0 & & ( it = = mapBlockIndex . end ( ) | | ! ( it - > second - > nStatus & BLOCK_HAVE_DATA ) ) )
// Extra checks to prevent "fill up memory by spamming with bogus blocks"
int64_t deltaTime = pblock - > GetBlockTime ( ) - pcheckpoint - > nTime ;
if ( deltaTime < 0 )
{
return state . DoS ( 100 , error ( " ProcessBlock() : block with timestamp before last checkpoint " ) ,
REJECT_CHECKPOINT , " time-too-old " ) ;
}
CBigNum bnNewBlock ;
bnNewBlock . SetCompact ( pblock - > nBits ) ;
CBigNum bnRequired ;
bnRequired . SetCompact ( ComputeMinWork ( pcheckpoint - > nBits , deltaTime ) ) ;
if ( bnNewBlock > bnRequired )
{
return state . DoS ( 100 , error ( " ProcessBlock() : block with too little proof-of-work " ) ,
REJECT_INVALID , " bad-diffbits " ) ;
}
}
// If we don't already have its previous block, shunt it off to holding area until we get it
if ( pblock - > hashPrevBlock ! = 0 & & ! mapBlockIndex . count ( pblock - > hashPrevBlock ) )
{
{
LogPrintf ( " ProcessBlock: ORPHAN BLOCK %lu, prev=%s \n " , ( unsigned long ) mapOrphanBlocks . size ( ) , pblock - > hashPrevBlock . ToString ( ) ) ;
LogPrintf ( " ProcessBlock: ORPHAN BLOCK %lu, prev=%s \n " , ( unsigned long ) mapOrphanBlocks . size ( ) , pblock - > hashPrevBlock . ToString ( ) ) ;
@ -2562,7 +2632,9 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl
}
}
// Store to disk
// Store to disk
if ( ! AcceptBlock ( * pblock , state , dbp ) )
CBlockIndex * pindex = NULL ;
bool ret = AcceptBlock ( * pblock , state , & pindex , dbp ) ;
if ( ! ret )
return error ( " ProcessBlock() : AcceptBlock FAILED " ) ;
return error ( " ProcessBlock() : AcceptBlock FAILED " ) ;
// Recursively process any orphan blocks that depended on this one
// Recursively process any orphan blocks that depended on this one
@ -2583,7 +2655,8 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl
block . BuildMerkleTree ( ) ;
block . BuildMerkleTree ( ) ;
// Use a dummy CValidationState so someone can't setup nodes to counter-DoS based on orphan resolution (that is, feeding people an invalid block based on LegitBlockX in order to get anyone relaying LegitBlockX banned)
// Use a dummy CValidationState so someone can't setup nodes to counter-DoS based on orphan resolution (that is, feeding people an invalid block based on LegitBlockX in order to get anyone relaying LegitBlockX banned)
CValidationState stateDummy ;
CValidationState stateDummy ;
if ( AcceptBlock ( block , stateDummy ) )
CBlockIndex * pindexChild = NULL ;
if ( AcceptBlock ( block , stateDummy , & pindexChild ) )
vWorkQueue . push_back ( mi - > second - > hashBlock ) ;
vWorkQueue . push_back ( mi - > second - > hashBlock ) ;
mapOrphanBlocks . erase ( mi - > second - > hashBlock ) ;
mapOrphanBlocks . erase ( mi - > second - > hashBlock ) ;
delete mi - > second ;
delete mi - > second ;
@ -2846,7 +2919,7 @@ bool static LoadBlockIndexDB()
CBlockIndex * pindex = item . second ;
CBlockIndex * pindex = item . second ;
pindex - > nChainWork = ( pindex - > pprev ? pindex - > pprev - > nChainWork : 0 ) + pindex - > GetBlockWork ( ) . getuint256 ( ) ;
pindex - > nChainWork = ( pindex - > pprev ? pindex - > pprev - > nChainWork : 0 ) + pindex - > GetBlockWork ( ) . getuint256 ( ) ;
pindex - > nChainTx = ( pindex - > pprev ? pindex - > pprev - > nChainTx : 0 ) + pindex - > nTx ;
pindex - > nChainTx = ( pindex - > pprev ? pindex - > pprev - > nChainTx : 0 ) + pindex - > nTx ;
if ( ( pindex - > nStatus & BLOCK_VALID_MASK ) > = BLOCK_VALID_TRANSACTIONS & & ! ( pindex - > nStatus & BLOCK_FAILED_MASK ) )
if ( pindex - > IsValid ( BLOCK_VALID_TRANSACTIONS ) )
setBlockIndexValid . insert ( pindex ) ;
setBlockIndexValid . insert ( pindex ) ;
if ( pindex - > nStatus & BLOCK_FAILED_MASK & & ( ! pindexBestInvalid | | pindex - > nChainWork > pindexBestInvalid - > nChainWork ) )
if ( pindex - > nStatus & BLOCK_FAILED_MASK & & ( ! pindexBestInvalid | | pindex - > nChainWork > pindexBestInvalid - > nChainWork ) )
pindexBestInvalid = pindex ;
pindexBestInvalid = pindex ;
@ -2993,7 +3066,8 @@ bool InitBlockIndex() {
return error ( " LoadBlockIndex() : FindBlockPos failed " ) ;
return error ( " LoadBlockIndex() : FindBlockPos failed " ) ;
if ( ! WriteBlockToDisk ( block , blockPos ) )
if ( ! WriteBlockToDisk ( block , blockPos ) )
return error ( " LoadBlockIndex() : writing genesis block to disk failed " ) ;
return error ( " LoadBlockIndex() : writing genesis block to disk failed " ) ;
if ( ! AddToBlockIndex ( block , state , blockPos ) )
CBlockIndex * pindex = AddToBlockIndex ( block ) ;
if ( ! ReceivedBlockTransactions ( block , state , pindex , blockPos ) )
return error ( " LoadBlockIndex() : genesis block not accepted " ) ;
return error ( " LoadBlockIndex() : genesis block not accepted " ) ;
} 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()) ;