@ -627,7 +627,7 @@ int CMerkleTx::SetMerkleBranch(const CBlock* pblock)
if ( pcoinsTip - > GetCoins ( GetHash ( ) , coins ) ) {
if ( pcoinsTip - > GetCoins ( GetHash ( ) , coins ) ) {
CBlockIndex * pindex = FindBlockByHeight ( coins . nHeight ) ;
CBlockIndex * pindex = FindBlockByHeight ( coins . nHeight ) ;
if ( pindex ) {
if ( pindex ) {
if ( ! blockTmp . ReadFromDisk ( pindex ) )
if ( ! ReadBlockFromDisk ( blockTmp , pindex ) )
return 0 ;
return 0 ;
pblock = & blockTmp ;
pblock = & blockTmp ;
}
}
@ -1114,7 +1114,7 @@ bool GetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock
if ( pindexSlow ) {
if ( pindexSlow ) {
CBlock block ;
CBlock block ;
if ( block . ReadFromDisk ( pindexSlow ) ) {
if ( ReadBlockFromDisk ( block , pindexSlow ) ) {
BOOST_FOREACH ( const CTransaction & tx , block . vtx ) {
BOOST_FOREACH ( const CTransaction & tx , block . vtx ) {
if ( tx . GetHash ( ) = = hash ) {
if ( tx . GetHash ( ) = = hash ) {
txOut = tx ;
txOut = tx ;
@ -1146,12 +1146,62 @@ CBlockIndex* FindBlockByHeight(int nHeight)
return vBlockIndexByHeight [ nHeight ] ;
return vBlockIndexByHeight [ nHeight ] ;
}
}
bool CBlock : : ReadFromDisk ( const CBlockIndex * pindex )
bool WriteBlockToDisk ( CBlock & block , CDiskBlockPos & pos )
{
{
if ( ! ReadFromDisk ( pindex - > GetBlockPos ( ) ) )
// Open history file to append
CAutoFile fileout = CAutoFile ( OpenBlockFile ( pos ) , SER_DISK , CLIENT_VERSION ) ;
if ( ! fileout )
return error ( " WriteBlockToDisk() : OpenBlockFile failed " ) ;
// Write index header
unsigned int nSize = fileout . GetSerializeSize ( block ) ;
fileout < < FLATDATA ( Params ( ) . MessageStart ( ) ) < < nSize ;
// Write block
long fileOutPos = ftell ( fileout ) ;
if ( fileOutPos < 0 )
return error ( " WriteBlockToDisk() : ftell failed " ) ;
pos . nPos = ( unsigned int ) fileOutPos ;
fileout < < block ;
// Flush stdio buffers and commit to disk before returning
fflush ( fileout ) ;
if ( ! IsInitialBlockDownload ( ) )
FileCommit ( fileout ) ;
return true ;
}
bool ReadBlockFromDisk ( CBlock & block , const CDiskBlockPos & pos )
{
block . SetNull ( ) ;
// Open history file to read
CAutoFile filein = CAutoFile ( OpenBlockFile ( pos , true ) , SER_DISK , CLIENT_VERSION ) ;
if ( ! filein )
return error ( " ReadBlockFromDisk(CBlock&, CDiskBlockPos&) : OpenBlockFile failed " ) ;
// Read block
try {
filein > > block ;
}
catch ( std : : exception & e ) {
return error ( " %s() : deserialize or I / O error " , __PRETTY_FUNCTION__) ;
}
// Check the header
if ( ! CheckProofOfWork ( block . GetHash ( ) , block . nBits ) )
return error ( " ReadBlockFromDisk(CBlock&, CDiskBlockPos&) : errors in block header " ) ;
return true ;
}
bool ReadBlockFromDisk ( CBlock & block , const CBlockIndex * pindex )
{
if ( ! ReadBlockFromDisk ( block , pindex - > GetBlockPos ( ) ) )
return false ;
return false ;
if ( GetHash ( ) ! = pindex - > GetBlockHash ( ) )
if ( block . GetHash ( ) ! = pindex - > GetBlockHash ( ) )
return error ( " CBlock::ReadFromDisk() : GetHash ( ) doesn ' t match index " ) ;
return error ( " ReadBlockFromDisk(CBlock&, CBlockIndex* ) : GetHash ( ) doesn ' t match index " ) ;
return true ;
return true ;
}
}
@ -1553,7 +1603,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, CCoinsViewCach
bool CBlock : : DisconnectBlock ( CValidationState & state , CBlockIndex * pindex , CCoinsViewCache & view , bool * pfClean )
bool DisconnectBlock ( CBlock & block , CValidationState & state , CBlockIndex * pindex , CCoinsViewCache & view , bool * pfClean )
{
{
assert ( pindex = = view . GetBestBlock ( ) ) ;
assert ( pindex = = view . GetBestBlock ( ) ) ;
@ -1569,12 +1619,12 @@ bool CBlock::DisconnectBlock(CValidationState &state, CBlockIndex *pindex, CCoin
if ( ! blockUndo . ReadFromDisk ( pos , pindex - > pprev - > GetBlockHash ( ) ) )
if ( ! blockUndo . ReadFromDisk ( pos , pindex - > pprev - > GetBlockHash ( ) ) )
return error ( " DisconnectBlock() : failure reading undo data " ) ;
return error ( " DisconnectBlock() : failure reading undo data " ) ;
if ( blockUndo . vtxundo . size ( ) + 1 ! = vtx . size ( ) )
if ( blockUndo . vtxundo . size ( ) + 1 ! = block . vtx . size ( ) )
return error ( " DisconnectBlock() : block and undo data inconsistent " ) ;
return error ( " DisconnectBlock() : block and undo data inconsistent " ) ;
// undo transactions in reverse order
// undo transactions in reverse order
for ( int i = vtx . size ( ) - 1 ; i > = 0 ; i - - ) {
for ( int i = block . vtx . size ( ) - 1 ; i > = 0 ; i - - ) {
const CTransaction & tx = vtx [ i ] ;
const CTransaction & tx = block . vtx [ i ] ;
uint256 hash = tx . GetHash ( ) ;
uint256 hash = tx . GetHash ( ) ;
// check that all outputs are available
// check that all outputs are available
@ -1667,10 +1717,10 @@ void ThreadScriptCheck() {
scriptcheckqueue . Thread ( ) ;
scriptcheckqueue . Thread ( ) ;
}
}
bool CBlock : : ConnectBlock ( CValidationState & state , CBlockIndex * pindex , CCoinsViewCache & view , bool fJustCheck )
bool ConnectBlock ( CBlock & block , CValidationState & state , CBlockIndex * pindex , CCoinsViewCache & view , bool fJustCheck )
{
{
// Check it again in case a previous version let a bad block in
// Check it again in case a previous version let a bad block in
if ( ! CheckBlock ( state , ! fJustCheck , ! fJustCheck ) )
if ( ! CheckBlock ( block , state , ! fJustCheck , ! fJustCheck ) )
return false ;
return false ;
// verify that the view's current state corresponds to the previous block
// verify that the view's current state corresponds to the previous block
@ -1678,7 +1728,7 @@ bool CBlock::ConnectBlock(CValidationState &state, CBlockIndex* pindex, CCoinsVi
// Special case for the genesis block, skipping connection of its transactions
// Special case for the genesis block, skipping connection of its transactions
// (its coinbase is unspendable)
// (its coinbase is unspendable)
if ( GetHash ( ) = = Params ( ) . HashGenesisBlock ( ) ) {
if ( block . GetHash ( ) = = Params ( ) . HashGenesisBlock ( ) ) {
view . SetBestBlock ( pindex ) ;
view . SetBestBlock ( pindex ) ;
pindexGenesisBlock = pindex ;
pindexGenesisBlock = pindex ;
return true ;
return true ;
@ -1702,8 +1752,8 @@ bool CBlock::ConnectBlock(CValidationState &state, CBlockIndex* pindex, CCoinsVi
! ( ( pindex - > nHeight = = 91842 & & pindex - > GetBlockHash ( ) = = uint256 ( " 0x00000000000a4d0a398161ffc163c503763b1f4360639393e0e4c8e300e0caec " ) ) | |
! ( ( pindex - > nHeight = = 91842 & & pindex - > GetBlockHash ( ) = = uint256 ( " 0x00000000000a4d0a398161ffc163c503763b1f4360639393e0e4c8e300e0caec " ) ) | |
( pindex - > nHeight = = 91880 & & pindex - > GetBlockHash ( ) = = uint256 ( " 0x00000000000743f190a18c5577a3c2d2a1f610ae9601ac046a38084ccb7cd721 " ) ) ) ;
( pindex - > nHeight = = 91880 & & pindex - > GetBlockHash ( ) = = uint256 ( " 0x00000000000743f190a18c5577a3c2d2a1f610ae9601ac046a38084ccb7cd721 " ) ) ) ;
if ( fEnforceBIP30 ) {
if ( fEnforceBIP30 ) {
for ( unsigned int i = 0 ; i < vtx . size ( ) ; i + + ) {
for ( unsigned int i = 0 ; i < block . vtx . size ( ) ; i + + ) {
uint256 hash = GetTxHash ( i ) ;
uint256 hash = block . GetTxHash ( i ) ;
if ( view . HaveCoins ( hash ) & & ! view . GetCoins ( hash ) . IsPruned ( ) )
if ( view . HaveCoins ( hash ) & & ! view . GetCoins ( hash ) . IsPruned ( ) )
return state . DoS ( 100 , error ( " ConnectBlock() : tried to overwrite transaction " ) ) ;
return state . DoS ( 100 , error ( " ConnectBlock() : tried to overwrite transaction " ) ) ;
}
}
@ -1724,12 +1774,12 @@ bool CBlock::ConnectBlock(CValidationState &state, CBlockIndex* pindex, CCoinsVi
int64 nFees = 0 ;
int64 nFees = 0 ;
int nInputs = 0 ;
int nInputs = 0 ;
unsigned int nSigOps = 0 ;
unsigned int nSigOps = 0 ;
CDiskTxPos pos ( pindex - > GetBlockPos ( ) , GetSizeOfCompactSize ( vtx . size ( ) ) ) ;
CDiskTxPos pos ( pindex - > GetBlockPos ( ) , GetSizeOfCompactSize ( block . vtx . size ( ) ) ) ;
std : : vector < std : : pair < uint256 , CDiskTxPos > > vPos ;
std : : vector < std : : pair < uint256 , CDiskTxPos > > vPos ;
vPos . reserve ( vtx . size ( ) ) ;
vPos . reserve ( block . vtx . size ( ) ) ;
for ( unsigned int i = 0 ; i < vtx . size ( ) ; i + + )
for ( unsigned int i = 0 ; i < block . vtx . size ( ) ; i + + )
{
{
const CTransaction & tx = vtx [ i ] ;
const CTransaction & tx = block . vtx [ i ] ;
nInputs + = tx . vin . size ( ) ;
nInputs + = tx . vin . size ( ) ;
nSigOps + = GetLegacySigOpCount ( tx ) ;
nSigOps + = GetLegacySigOpCount ( tx ) ;
@ -1760,19 +1810,19 @@ bool CBlock::ConnectBlock(CValidationState &state, CBlockIndex* pindex, CCoinsVi
}
}
CTxUndo txundo ;
CTxUndo txundo ;
UpdateCoins ( tx , state , view , txundo , pindex - > nHeight , GetTxHash ( i ) ) ;
UpdateCoins ( tx , state , view , txundo , pindex - > nHeight , block . GetTxHash ( i ) ) ;
if ( ! tx . IsCoinBase ( ) )
if ( ! tx . IsCoinBase ( ) )
blockundo . vtxundo . push_back ( txundo ) ;
blockundo . vtxundo . push_back ( txundo ) ;
vPos . push_back ( std : : make_pair ( GetTxHash ( i ) , pos ) ) ;
vPos . push_back ( std : : make_pair ( block . GetTxHash ( i ) , pos ) ) ;
pos . nTxOffset + = : : GetSerializeSize ( tx , SER_DISK , CLIENT_VERSION ) ;
pos . nTxOffset + = : : GetSerializeSize ( tx , SER_DISK , CLIENT_VERSION ) ;
}
}
int64 nTime = GetTimeMicros ( ) - nStart ;
int64 nTime = GetTimeMicros ( ) - nStart ;
if ( fBenchmark )
if ( fBenchmark )
printf ( " - Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin) \n " , ( unsigned ) vtx . size ( ) , 0.001 * nTime , 0.001 * nTime / vtx . size ( ) , nInputs < = 1 ? 0 : 0.001 * nTime / ( nInputs - 1 ) ) ;
printf ( " - Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin) \n " , ( unsigned ) block . vtx . size ( ) , 0.001 * nTime , 0.001 * nTime / block . vtx . size ( ) , nInputs < = 1 ? 0 : 0.001 * nTime / ( nInputs - 1 ) ) ;
if ( GetValueOut ( vtx [ 0 ] ) > GetBlockValue ( pindex - > nHeight , nFees ) )
if ( GetValueOut ( block . vtx [ 0 ] ) > GetBlockValue ( pindex - > nHeight , nFees ) )
return state . DoS ( 100 , error ( " ConnectBlock() : coinbase pays too much (actual=% " PRI64d " vs limit=% " PRI64d " ) " , GetValueOut ( vtx [ 0 ] ) , GetBlockValue ( pindex - > nHeight , nFees ) ) ) ;
return state . DoS ( 100 , error ( " ConnectBlock() : coinbase pays too much (actual=% " PRI64d " vs limit=% " PRI64d " ) " , GetValueOut ( block . vtx [ 0 ] ) , GetBlockValue ( pindex - > nHeight , nFees ) ) ) ;
if ( ! control . Wait ( ) )
if ( ! control . Wait ( ) )
return state . DoS ( 100 , false ) ;
return state . DoS ( 100 , false ) ;
@ -1813,8 +1863,8 @@ bool CBlock::ConnectBlock(CValidationState &state, CBlockIndex* pindex, CCoinsVi
assert ( view . SetBestBlock ( pindex ) ) ;
assert ( view . SetBestBlock ( pindex ) ) ;
// Watch for transactions paying to me
// Watch for transactions paying to me
for ( unsigned int i = 0 ; i < vtx . size ( ) ; i + + )
for ( unsigned int i = 0 ; i < block . vtx . size ( ) ; i + + )
SyncWithWallets ( GetTxHash ( i ) , vtx [ i ] , this , true ) ;
SyncWithWallets ( block . GetTxHash ( i ) , block . vtx [ i ] , & block , true ) ;
return true ;
return true ;
}
}
@ -1860,10 +1910,10 @@ bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew)
vector < CTransaction > vResurrect ;
vector < CTransaction > vResurrect ;
BOOST_FOREACH ( CBlockIndex * pindex , vDisconnect ) {
BOOST_FOREACH ( CBlockIndex * pindex , vDisconnect ) {
CBlock block ;
CBlock block ;
if ( ! block . ReadFromDisk ( pindex ) )
if ( ! ReadBlockFromDisk ( block , pindex ) )
return state . Abort ( _ ( " Failed to read block " ) ) ;
return state . Abort ( _ ( " Failed to read block " ) ) ;
int64 nStart = GetTimeMicros ( ) ;
int64 nStart = GetTimeMicros ( ) ;
if ( ! block . DisconnectBlock ( state , pindex , view ) )
if ( ! DisconnectBlock ( block , state , pindex , view ) )
return error ( " SetBestBlock() : DisconnectBlock % s failed " , pindex->GetBlockHash().ToString().c_str()) ;
return error ( " SetBestBlock() : DisconnectBlock % s failed " , pindex->GetBlockHash().ToString().c_str()) ;
if ( fBenchmark )
if ( fBenchmark )
printf ( " - Disconnect: %.2fms \n " , ( GetTimeMicros ( ) - nStart ) * 0.001 ) ;
printf ( " - Disconnect: %.2fms \n " , ( GetTimeMicros ( ) - nStart ) * 0.001 ) ;
@ -1880,10 +1930,10 @@ bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew)
vector < CTransaction > vDelete ;
vector < CTransaction > vDelete ;
BOOST_FOREACH ( CBlockIndex * pindex , vConnect ) {
BOOST_FOREACH ( CBlockIndex * pindex , vConnect ) {
CBlock block ;
CBlock block ;
if ( ! block . ReadFromDisk ( pindex ) )
if ( ! ReadBlockFromDisk ( block , pindex ) )
return state . Abort ( _ ( " Failed to read block " ) ) ;
return state . Abort ( _ ( " Failed to read block " ) ) ;
int64 nStart = GetTimeMicros ( ) ;
int64 nStart = GetTimeMicros ( ) ;
if ( ! block . ConnectBlock ( state , pindex , view ) ) {
if ( ! ConnectBlock ( block , state , pindex , view ) ) {
if ( state . IsInvalid ( ) ) {
if ( state . IsInvalid ( ) ) {
InvalidChainFound ( pindexNew ) ;
InvalidChainFound ( pindexNew ) ;
InvalidBlockFound ( pindex ) ;
InvalidBlockFound ( pindex ) ;
@ -1993,25 +2043,25 @@ bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew)
}
}
bool CBlock : : AddToBlockIndex ( CValidationState & state , const CDiskBlockPos & pos )
bool AddToBlockIndex ( CBlock & block , CValidationState & state , const CDiskBlockPos & pos )
{
{
// Check for duplicate
// Check for duplicate
uint256 hash = GetHash ( ) ;
uint256 hash = block . GetHash ( ) ;
if ( mapBlockIndex . count ( hash ) )
if ( mapBlockIndex . count ( hash ) )
return state . Invalid ( error ( " AddToBlockIndex() : %s already exists " , hash . ToString ( ) . c_str ( ) ) ) ;
return state . Invalid ( error ( " AddToBlockIndex() : %s already exists " , hash . ToString ( ) . c_str ( ) ) ) ;
// Construct new block index object
// Construct new block index object
CBlockIndex * pindexNew = new CBlockIndex ( * this ) ;
CBlockIndex * pindexNew = new CBlockIndex ( block ) ;
assert ( pindexNew ) ;
assert ( pindexNew ) ;
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 ( hashPrevBlock ) ;
map < uint256 , CBlockIndex * > : : iterator miPrev = mapBlockIndex . find ( block . hashPrevBlock ) ;
if ( miPrev ! = mapBlockIndex . end ( ) )
if ( miPrev ! = mapBlockIndex . end ( ) )
{
{
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 - > 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 - > nChainTx = ( pindexNew - > pprev ? pindexNew - > pprev - > nChainTx : 0 ) + pindexNew - > nTx ;
pindexNew - > nFile = pos . nFile ;
pindexNew - > nFile = pos . nFile ;
@ -2032,7 +2082,7 @@ bool CBlock::AddToBlockIndex(CValidationState &state, const CDiskBlockPos &pos)
// Notify UI to display prev block's coinbase if it was ours
// Notify UI to display prev block's coinbase if it was ours
static uint256 hashPrevBestCoinBase ;
static uint256 hashPrevBestCoinBase ;
UpdatedTransaction ( hashPrevBestCoinBase ) ;
UpdatedTransaction ( hashPrevBestCoinBase ) ;
hashPrevBestCoinBase = GetTxHash ( 0 ) ;
hashPrevBestCoinBase = block . GetTxHash ( 0 ) ;
}
}
if ( ! pblocktree - > Flush ( ) )
if ( ! pblocktree - > Flush ( ) )
@ -2138,51 +2188,51 @@ bool FindUndoPos(CValidationState &state, int nFile, CDiskBlockPos &pos, unsigne
}
}
bool CBlock : : CheckBlock ( CValidationState & state , bool fCheckPOW , bool fCheckMerkleRoot ) const
bool CheckBlock ( const CBlock & block , CValidationState & state , bool fCheckPOW , bool fCheckMerkleRoot )
{
{
// These are checks that are independent of context
// These are checks that are independent of context
// that can be verified before saving an orphan block.
// that can be verified before saving an orphan block.
// Size limits
// Size limits
if ( vtx . empty ( ) | | vtx . size ( ) > MAX_BLOCK_SIZE | | : : GetSerializeSize ( * this , SER_NETWORK , PROTOCOL_VERSION ) > MAX_BLOCK_SIZE )
if ( block . vtx . empty ( ) | | block . vtx . size ( ) > MAX_BLOCK_SIZE | | : : GetSerializeSize ( block , SER_NETWORK , PROTOCOL_VERSION ) > MAX_BLOCK_SIZE )
return state . DoS ( 100 , error ( " CheckBlock() : size limits failed " ) ) ;
return state . DoS ( 100 , error ( " CheckBlock() : size limits failed " ) ) ;
// Check proof of work matches claimed amount
// Check proof of work matches claimed amount
if ( fCheckPOW & & ! CheckProofOfWork ( GetHash ( ) , nBits ) )
if ( fCheckPOW & & ! CheckProofOfWork ( block . GetHash ( ) , block . nBits ) )
return state . DoS ( 50 , error ( " CheckBlock() : proof of work failed " ) ) ;
return state . DoS ( 50 , error ( " CheckBlock() : proof of work failed " ) ) ;
// Check timestamp
// Check timestamp
if ( 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 ( " CheckBlock() : block timestamp too far in the future " ) ) ;
// First transaction must be coinbase, the rest must not be
// First transaction must be coinbase, the rest must not be
if ( vtx . empty ( ) | | ! vtx [ 0 ] . IsCoinBase ( ) )
if ( block . vtx . empty ( ) | | ! block . vtx [ 0 ] . IsCoinBase ( ) )
return state . DoS ( 100 , error ( " CheckBlock() : first tx is not coinbase " ) ) ;
return state . DoS ( 100 , error ( " CheckBlock() : first tx is not coinbase " ) ) ;
for ( unsigned int i = 1 ; i < vtx . size ( ) ; i + + )
for ( unsigned int i = 1 ; i < block . vtx . size ( ) ; i + + )
if ( vtx [ i ] . IsCoinBase ( ) )
if ( block . vtx [ i ] . IsCoinBase ( ) )
return state . DoS ( 100 , error ( " CheckBlock() : more than one coinbase " ) ) ;
return state . DoS ( 100 , error ( " CheckBlock() : more than one coinbase " ) ) ;
// Check transactions
// Check transactions
BOOST_FOREACH ( const CTransaction & tx , vtx )
BOOST_FOREACH ( const CTransaction & tx , block . vtx )
if ( ! CheckTransaction ( tx , state ) )
if ( ! CheckTransaction ( tx , state ) )
return error ( " CheckBlock() : CheckTransaction failed " ) ;
return error ( " CheckBlock() : CheckTransaction failed " ) ;
// Build the merkle tree already. We need it anyway later, and it makes the
// Build the merkle tree already. We need it anyway later, and it makes the
// block cache the transaction hashes, which means they don't need to be
// block cache the transaction hashes, which means they don't need to be
// recalculated many times during this block's validation.
// recalculated many times during this block's validation.
BuildMerkleTree ( ) ;
block . BuildMerkleTree ( ) ;
// Check for duplicate txids. This is caught by ConnectInputs(),
// Check for duplicate txids. This is caught by ConnectInputs(),
// but catching it earlier avoids a potential DoS attack:
// but catching it earlier avoids a potential DoS attack:
set < uint256 > uniqueTx ;
set < uint256 > uniqueTx ;
for ( unsigned int i = 0 ; i < vtx . size ( ) ; i + + ) {
for ( unsigned int i = 0 ; i < block . vtx . size ( ) ; i + + ) {
uniqueTx . insert ( GetTxHash ( i ) ) ;
uniqueTx . insert ( block . GetTxHash ( i ) ) ;
}
}
if ( uniqueTx . size ( ) ! = vtx . size ( ) )
if ( uniqueTx . size ( ) ! = block . vtx . size ( ) )
return state . DoS ( 100 , error ( " CheckBlock() : duplicate transaction " ) ) ;
return state . DoS ( 100 , error ( " CheckBlock() : duplicate transaction " ) ) ;
unsigned int nSigOps = 0 ;
unsigned int nSigOps = 0 ;
BOOST_FOREACH ( const CTransaction & tx , vtx )
BOOST_FOREACH ( const CTransaction & tx , block . vtx )
{
{
nSigOps + = GetLegacySigOpCount ( tx ) ;
nSigOps + = GetLegacySigOpCount ( tx ) ;
}
}
@ -2190,16 +2240,16 @@ bool CBlock::CheckBlock(CValidationState &state, bool fCheckPOW, bool fCheckMerk
return state . DoS ( 100 , error ( " CheckBlock() : out-of-bounds SigOpCount " ) ) ;
return state . DoS ( 100 , error ( " CheckBlock() : out-of-bounds SigOpCount " ) ) ;
// Check merkle root
// Check merkle root
if ( fCheckMerkleRoot & & hashMerkleRoot ! = BuildMerkleTree ( ) )
if ( fCheckMerkleRoot & & block . hashMerkleRoot ! = block . BuildMerkleTree ( ) )
return state . DoS ( 100 , error ( " CheckBlock() : hashMerkleRoot mismatch " ) ) ;
return state . DoS ( 100 , error ( " CheckBlock() : hashMerkleRoot mismatch " ) ) ;
return true ;
return true ;
}
}
bool CBlock : : AcceptBlock ( CValidationState & state , CDiskBlockPos * dbp )
bool AcceptBlock ( CBlock & block , CValidationState & state , CDiskBlockPos * dbp )
{
{
// Check for duplicate
// Check for duplicate
uint256 hash = GetHash ( ) ;
uint256 hash = block . GetHash ( ) ;
if ( mapBlockIndex . count ( hash ) )
if ( mapBlockIndex . count ( hash ) )
return state . Invalid ( error ( " AcceptBlock() : block already in mapBlockIndex " ) ) ;
return state . Invalid ( error ( " AcceptBlock() : block already in mapBlockIndex " ) ) ;
@ -2207,23 +2257,23 @@ bool CBlock::AcceptBlock(CValidationState &state, CDiskBlockPos *dbp)
CBlockIndex * pindexPrev = NULL ;
CBlockIndex * pindexPrev = NULL ;
int nHeight = 0 ;
int nHeight = 0 ;
if ( hash ! = Params ( ) . HashGenesisBlock ( ) ) {
if ( hash ! = Params ( ) . HashGenesisBlock ( ) ) {
map < uint256 , CBlockIndex * > : : iterator mi = mapBlockIndex . find ( hashPrevBlock ) ;
map < uint256 , CBlockIndex * > : : iterator mi = mapBlockIndex . find ( block . hashPrevBlock ) ;
if ( mi = = mapBlockIndex . end ( ) )
if ( mi = = mapBlockIndex . end ( ) )
return state . DoS ( 10 , error ( " AcceptBlock() : prev block not found " ) ) ;
return state . DoS ( 10 , error ( " AcceptBlock() : prev block not found " ) ) ;
pindexPrev = ( * mi ) . second ;
pindexPrev = ( * mi ) . second ;
nHeight = pindexPrev - > nHeight + 1 ;
nHeight = pindexPrev - > nHeight + 1 ;
// Check proof of work
// Check proof of work
if ( nBits ! = GetNextWorkRequired ( pindexPrev , this ) )
if ( block . nBits ! = GetNextWorkRequired ( pindexPrev , & block ) )
return state . DoS ( 100 , error ( " AcceptBlock() : incorrect proof of work " ) ) ;
return state . DoS ( 100 , error ( " AcceptBlock() : incorrect proof of work " ) ) ;
// Check timestamp against prev
// Check timestamp against prev
if ( GetBlockTime ( ) < = pindexPrev - > GetMedianTimePast ( ) )
if ( block . GetBlockTime ( ) < = pindexPrev - > GetMedianTimePast ( ) )
return state . Invalid ( error ( " AcceptBlock() : block's timestamp is too early " ) ) ;
return state . Invalid ( error ( " AcceptBlock() : block's timestamp is too early " ) ) ;
// Check that all transactions are finalized
// Check that all transactions are finalized
BOOST_FOREACH ( const CTransaction & tx , vtx )
BOOST_FOREACH ( const CTransaction & tx , block . vtx )
if ( ! IsFinalTx ( tx , nHeight , GetBlockTime ( ) ) )
if ( ! IsFinalTx ( tx , nHeight , block . GetBlockTime ( ) ) )
return state . DoS ( 10 , error ( " AcceptBlock() : contains a non-final transaction " ) ) ;
return state . DoS ( 10 , error ( " AcceptBlock() : contains a non-final transaction " ) ) ;
// 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
@ -2231,7 +2281,7 @@ bool CBlock::AcceptBlock(CValidationState &state, CDiskBlockPos *dbp)
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 ) ) ;
// Reject block.nVersion=1 blocks when 95% (75% on testnet) of the network has upgraded:
// Reject block.nVersion=1 blocks when 95% (75% on testnet) of the network has upgraded:
if ( nVersion < 2 )
if ( block . nVersion < 2 )
{
{
if ( ( ! TestNet ( ) & & CBlockIndex : : IsSuperMajority ( 2 , pindexPrev , 950 , 1000 ) ) | |
if ( ( ! TestNet ( ) & & CBlockIndex : : IsSuperMajority ( 2 , pindexPrev , 950 , 1000 ) ) | |
( TestNet ( ) & & CBlockIndex : : IsSuperMajority ( 2 , pindexPrev , 75 , 100 ) ) )
( TestNet ( ) & & CBlockIndex : : IsSuperMajority ( 2 , pindexPrev , 75 , 100 ) ) )
@ -2240,14 +2290,14 @@ bool CBlock::AcceptBlock(CValidationState &state, CDiskBlockPos *dbp)
}
}
}
}
// Enforce block.nVersion=2 rule that the coinbase starts with serialized block height
// Enforce block.nVersion=2 rule that the coinbase starts with serialized block height
if ( nVersion > = 2 )
if ( block . nVersion > = 2 )
{
{
// if 750 of the last 1,000 blocks are version 2 or greater (51/100 if testnet):
// if 750 of the last 1,000 blocks are version 2 or greater (51/100 if testnet):
if ( ( ! TestNet ( ) & & CBlockIndex : : IsSuperMajority ( 2 , pindexPrev , 750 , 1000 ) ) | |
if ( ( ! TestNet ( ) & & CBlockIndex : : IsSuperMajority ( 2 , pindexPrev , 750 , 1000 ) ) | |
( TestNet ( ) & & CBlockIndex : : IsSuperMajority ( 2 , pindexPrev , 51 , 100 ) ) )
( TestNet ( ) & & CBlockIndex : : IsSuperMajority ( 2 , pindexPrev , 51 , 100 ) ) )
{
{
CScript expect = CScript ( ) < < nHeight ;
CScript expect = CScript ( ) < < nHeight ;
if ( ! std : : equal ( expect . begin ( ) , expect . end ( ) , vtx [ 0 ] . vin [ 0 ] . scriptSig . begin ( ) ) )
if ( ! std : : equal ( expect . begin ( ) , expect . end ( ) , block . vtx [ 0 ] . vin [ 0 ] . scriptSig . begin ( ) ) )
return state . DoS ( 100 , error ( " AcceptBlock() : block height mismatch in coinbase " ) ) ;
return state . DoS ( 100 , error ( " AcceptBlock() : block height mismatch in coinbase " ) ) ;
}
}
}
}
@ -2255,16 +2305,16 @@ bool CBlock::AcceptBlock(CValidationState &state, CDiskBlockPos *dbp)
// Write block to history file
// Write block to history file
try {
try {
unsigned int nBlockSize = : : GetSerializeSize ( * this , SER_DISK , CLIENT_VERSION ) ;
unsigned int nBlockSize = : : GetSerializeSize ( block , SER_DISK , CLIENT_VERSION ) ;
CDiskBlockPos blockPos ;
CDiskBlockPos blockPos ;
if ( dbp ! = NULL )
if ( dbp ! = NULL )
blockPos = * dbp ;
blockPos = * dbp ;
if ( ! FindBlockPos ( state , blockPos , nBlockSize + 8 , nHeight , nTime , dbp ! = NULL ) )
if ( ! FindBlockPos ( state , blockPos , nBlockSize + 8 , nHeight , block . nTime , dbp ! = NULL ) )
return error ( " AcceptBlock() : FindBlockPos failed " ) ;
return error ( " AcceptBlock() : FindBlockPos failed " ) ;
if ( dbp = = NULL )
if ( dbp = = NULL )
if ( ! WriteToDisk ( blockPos ) )
if ( ! WriteBlock ToDisk ( block , blockPos ) )
return state . Abort ( _ ( " Failed to write block " ) ) ;
return state . Abort ( _ ( " Failed to write block " ) ) ;
if ( ! AddToBlockIndex ( state , blockPos ) )
if ( ! AddToBlockIndex ( block , state , blockPos ) )
return error ( " AcceptBlock() : AddToBlockIndex failed " ) ;
return error ( " AcceptBlock() : AddToBlockIndex 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 ( ) ) ;
@ -2316,7 +2366,7 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl
return state . Invalid ( error ( " ProcessBlock() : already have block (orphan) %s " , hash . ToString ( ) . c_str ( ) ) ) ;
return state . Invalid ( error ( " ProcessBlock() : already have block (orphan) %s " , hash . ToString ( ) . c_str ( ) ) ) ;
// Preliminary checks
// Preliminary checks
if ( ! pblock - > CheckBlock ( state ) )
if ( ! CheckBlock ( * pblock , state ) )
return error ( " ProcessBlock() : CheckBlock FAILED " ) ;
return error ( " ProcessBlock() : CheckBlock FAILED " ) ;
CBlockIndex * pcheckpoint = Checkpoints : : GetLastCheckpoint ( mapBlockIndex ) ;
CBlockIndex * pcheckpoint = Checkpoints : : GetLastCheckpoint ( mapBlockIndex ) ;
@ -2357,7 +2407,7 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl
}
}
// Store to disk
// Store to disk
if ( ! pblock - > AcceptBlock ( state , dbp ) )
if ( ! AcceptBlock ( * pblock , state , dbp ) )
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
@ -2373,7 +2423,7 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl
CBlock * pblockOrphan = ( * mi ) . second ;
CBlock * pblockOrphan = ( * mi ) . second ;
// 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 ( pblockOrphan - > AcceptBlock ( stateDummy ) )
if ( AcceptBlock ( * pblockOrphan , stateDummy ) )
vWorkQueue . push_back ( pblockOrphan - > GetHash ( ) ) ;
vWorkQueue . push_back ( pblockOrphan - > GetHash ( ) ) ;
mapOrphanBlocks . erase ( pblockOrphan - > GetHash ( ) ) ;
mapOrphanBlocks . erase ( pblockOrphan - > GetHash ( ) ) ;
delete pblockOrphan ;
delete pblockOrphan ;
@ -2710,10 +2760,10 @@ bool VerifyDB(int nCheckLevel, int nCheckDepth)
break ;
break ;
CBlock block ;
CBlock block ;
// check level 0: read from disk
// check level 0: read from disk
if ( ! block . ReadFromDisk ( pindex ) )
if ( ! ReadBlockFromDisk ( block , pindex ) )
return error ( " VerifyDB() : * * * block . Read FromDisk failed at % d , hash = % s " , pindex->nHeight, pindex->GetBlockHash().ToString().c_str()) ;
return error ( " VerifyDB() : * * * ReadBlock FromDisk failed at % d , hash = % s " , pindex->nHeight, pindex->GetBlockHash().ToString().c_str()) ;
// check level 1: verify block validity
// check level 1: verify block validity
if ( nCheckLevel > = 1 & & ! block . CheckBlock ( state ) )
if ( nCheckLevel > = 1 & & ! CheckBlock ( block , state ) )
return error ( " VerifyDB() : * * * found bad block at % d , hash = % s \ n " , pindex->nHeight, pindex->GetBlockHash().ToString().c_str()) ;
return error ( " VerifyDB() : * * * found bad block at % d , hash = % s \ n " , pindex->nHeight, pindex->GetBlockHash().ToString().c_str()) ;
// check level 2: verify undo validity
// check level 2: verify undo validity
if ( nCheckLevel > = 2 & & pindex ) {
if ( nCheckLevel > = 2 & & pindex ) {
@ -2727,7 +2777,7 @@ bool VerifyDB(int nCheckLevel, int nCheckDepth)
// check level 3: check for inconsistencies during memory-only disconnect of tip blocks
// check level 3: check for inconsistencies during memory-only disconnect of tip blocks
if ( nCheckLevel > = 3 & & pindex = = pindexState & & ( coins . GetCacheSize ( ) + pcoinsTip - > GetCacheSize ( ) ) < = 2 * nCoinCacheSize + 32000 ) {
if ( nCheckLevel > = 3 & & pindex = = pindexState & & ( coins . GetCacheSize ( ) + pcoinsTip - > GetCacheSize ( ) ) < = 2 * nCoinCacheSize + 32000 ) {
bool fClean = true ;
bool fClean = true ;
if ( ! block . DisconnectBlock ( state , pindex , coins , & fClean ) )
if ( ! DisconnectBlock ( block , state , pindex , coins , & fClean ) )
return error ( " VerifyDB() : * * * irrecoverable inconsistency in block data at % d , hash = % s " , pindex->nHeight, pindex->GetBlockHash().ToString().c_str()) ;
return error ( " VerifyDB() : * * * irrecoverable inconsistency in block data at % d , hash = % s " , pindex->nHeight, pindex->GetBlockHash().ToString().c_str()) ;
pindexState = pindex - > pprev ;
pindexState = pindex - > pprev ;
if ( ! fClean ) {
if ( ! fClean ) {
@ -2747,9 +2797,9 @@ bool VerifyDB(int nCheckLevel, int nCheckDepth)
boost : : this_thread : : interruption_point ( ) ;
boost : : this_thread : : interruption_point ( ) ;
pindex = pindex - > GetNextInMainChain ( ) ;
pindex = pindex - > GetNextInMainChain ( ) ;
CBlock block ;
CBlock block ;
if ( ! block . ReadFromDisk ( pindex ) )
if ( ! ReadBlockFromDisk ( block , pindex ) )
return error ( " VerifyDB() : * * * block . Read FromDisk failed at % d , hash = % s " , pindex->nHeight, pindex->GetBlockHash().ToString().c_str()) ;
return error ( " VerifyDB() : * * * ReadBlock FromDisk failed at % d , hash = % s " , pindex->nHeight, pindex->GetBlockHash().ToString().c_str()) ;
if ( ! block . ConnectBlock ( state , pindex , coins ) )
if ( ! ConnectBlock ( block , state , pindex , coins ) )
return error ( " VerifyDB() : * * * found unconnectable block at % d , hash = % s " , pindex->nHeight, pindex->GetBlockHash().ToString().c_str()) ;
return error ( " VerifyDB() : * * * found unconnectable block at % d , hash = % s " , pindex->nHeight, pindex->GetBlockHash().ToString().c_str()) ;
}
}
}
}
@ -2800,9 +2850,9 @@ bool InitBlockIndex() {
CValidationState state ;
CValidationState state ;
if ( ! FindBlockPos ( state , blockPos , nBlockSize + 8 , 0 , block . nTime ) )
if ( ! FindBlockPos ( state , blockPos , nBlockSize + 8 , 0 , block . nTime ) )
return error ( " LoadBlockIndex() : FindBlockPos failed " ) ;
return error ( " LoadBlockIndex() : FindBlockPos failed " ) ;
if ( ! block . WriteToDisk ( blockPos ) )
if ( ! WriteBlockToDisk ( block , blockPos ) )
return error ( " LoadBlockIndex() : writing genesis block to disk failed " ) ;
return error ( " LoadBlockIndex() : writing genesis block to disk failed " ) ;
if ( ! block . AddToBlockIndex ( state , blockPos ) )
if ( ! AddToBlockIndex ( block , state , 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()) ;
@ -2858,7 +2908,7 @@ void PrintBlockTree()
// print item
// print item
CBlock block ;
CBlock block ;
block . ReadFromDisk ( pindex ) ;
ReadBlockFromDisk ( block , pindex ) ;
printf ( " %d (blk%05u.dat:0x%x) %s tx % " PRIszu " " ,
printf ( " %d (blk%05u.dat:0x%x) %s tx % " PRIszu " " ,
pindex - > nHeight ,
pindex - > nHeight ,
pindex - > GetBlockPos ( ) . nFile , pindex - > GetBlockPos ( ) . nPos ,
pindex - > GetBlockPos ( ) . nFile , pindex - > GetBlockPos ( ) . nPos ,
@ -3082,7 +3132,7 @@ void static ProcessGetData(CNode* pfrom)
if ( mi ! = mapBlockIndex . end ( ) )
if ( mi ! = mapBlockIndex . end ( ) )
{
{
CBlock block ;
CBlock block ;
block . ReadFromDisk ( ( * mi ) . second ) ;
ReadBlockFromDisk ( block , ( * mi ) . second ) ;
if ( inv . type = = MSG_BLOCK )
if ( inv . type = = MSG_BLOCK )
pfrom - > PushMessage ( " block " , block ) ;
pfrom - > PushMessage ( " block " , block ) ;
else // MSG_FILTERED_BLOCK)
else // MSG_FILTERED_BLOCK)
@ -4404,7 +4454,7 @@ CBlockTemplate* CreateNewBlock(CReserveKey& reservekey)
indexDummy . nHeight = pindexPrev - > nHeight + 1 ;
indexDummy . nHeight = pindexPrev - > nHeight + 1 ;
CCoinsViewCache viewNew ( * pcoinsTip , true ) ;
CCoinsViewCache viewNew ( * pcoinsTip , true ) ;
CValidationState state ;
CValidationState state ;
if ( ! pblock - > ConnectBlock ( state , & indexDummy , viewNew , true ) )
if ( ! ConnectBlock ( * pblock , state , & indexDummy , viewNew , true ) )
throw std : : runtime_error ( " CreateNewBlock() : ConnectBlock failed " ) ;
throw std : : runtime_error ( " CreateNewBlock() : ConnectBlock failed " ) ;
}
}