@ -515,28 +515,28 @@ int CMerkleTx::SetMerkleBranch(const CBlock* pblock)
@@ -515,28 +515,28 @@ int CMerkleTx::SetMerkleBranch(const CBlock* pblock)
bool CTransaction : : CheckTransaction ( ) const
bool CTransaction : : CheckTransaction ( CValidationState & state ) const
{
// Basic checks that don't depend on any context
if ( vin . empty ( ) )
return DoS ( 10 , error ( " CTransaction::CheckTransaction() : vin empty " ) );
return state . DoS ( 10 , error ( " CTransaction::CheckTransaction() : vin empty " ) ) ;
if ( vout . empty ( ) )
return DoS ( 10 , error ( " CTransaction::CheckTransaction() : vout empty " ) );
return state . DoS ( 10 , error ( " CTransaction::CheckTransaction() : vout empty " ) ) ;
// Size limits
if ( : : GetSerializeSize ( * this , SER_NETWORK , PROTOCOL_VERSION ) > MAX_BLOCK_SIZE )
return DoS ( 100 , error ( " CTransaction::CheckTransaction() : size limits failed " ) );
return state . DoS ( 100 , error ( " CTransaction::CheckTransaction() : size limits failed " ) ) ;
// Check for negative or overflow output values
int64 nValueOut = 0 ;
BOOST_FOREACH ( const CTxOut & txout , vout )
{
if ( txout . nValue < 0 )
return DoS ( 100 , error ( " CTransaction::CheckTransaction() : txout . nValue negative " ) ) ;
return state . DoS ( 100 , error ( " CTransaction::CheckTransaction() : txout.nValue negative " ) ) ;
if ( txout . nValue > MAX_MONEY )
return DoS ( 100 , error ( " CTransaction::CheckTransaction() : txout . nValue too high " ) );
return state . DoS ( 100 , error ( " CTransaction::CheckTransaction() : txout.nValue too high " ) ) ;
nValueOut + = txout . nValue ;
if ( ! MoneyRange ( nValueOut ) )
return DoS ( 100 , error ( " CTransaction::CheckTransaction() : txout total out of range " ) );
return state . DoS ( 100 , error ( " CTransaction::CheckTransaction() : txout total out of range " ) ) ;
}
// Check for duplicate inputs
@ -544,20 +544,20 @@ bool CTransaction::CheckTransaction() const
@@ -544,20 +544,20 @@ bool CTransaction::CheckTransaction() const
BOOST_FOREACH ( const CTxIn & txin , vin )
{
if ( vInOutPoints . count ( txin . prevout ) )
return false ;
return state . DoS ( 100 , error ( " CTransaction::CheckTransaction() : duplicate inputs " ) ) ;
vInOutPoints . insert ( txin . prevout ) ;
}
if ( IsCoinBase ( ) )
{
if ( vin [ 0 ] . scriptSig . size ( ) < 2 | | vin [ 0 ] . scriptSig . size ( ) > 100 )
return DoS ( 100 , error ( " CTransaction::CheckTransaction() : c oinbase script size " ) );
return state . DoS ( 100 , error ( " CTransaction::CheckTransaction() : c oinbase script size " ) ) ;
}
else
{
BOOST_FOREACH ( const CTxIn & txin , vin )
if ( txin . prevout . IsNull ( ) )
return DoS ( 10 , error ( " CTransaction::CheckTransaction() : prevout is null " ) );
return state . DoS ( 10 , error ( " CTransaction::CheckTransaction() : prevout is null " ) ) ;
}
return true ;
@ -624,18 +624,18 @@ void CTxMemPool::pruneSpent(const uint256 &hashTx, CCoins &coins)
@@ -624,18 +624,18 @@ void CTxMemPool::pruneSpent(const uint256 &hashTx, CCoins &coins)
}
}
bool CTxMemPool : : accept ( CTransaction & tx , bool fCheckInputs , bool fLimitFree ,
bool CTxMemPool : : accept ( CValidationState & state , C Transaction & tx , bool fCheckInputs , bool fLimitFree ,
bool * pfMissingInputs )
{
if ( pfMissingInputs )
* pfMissingInputs = false ;
if ( ! tx . CheckTransaction ( ) )
if ( ! tx . CheckTransaction ( state ) )
return error ( " CTxMemPool::accept() : CheckTransaction failed " ) ;
// Coinbase is only valid in a block, not as a loose transaction
if ( tx . IsCoinBase ( ) )
return tx . DoS ( 100 , error ( " CTxMemPool::accept() : coinbase as individual tx " ) ) ;
return state . DoS ( 100 , error ( " CTxMemPool::accept() : coinbase as individual tx " ) ) ;
// To help v0.1.5 clients who would see it as a negative number
if ( ( int64 ) tx . nLockTime > std : : numeric_limits < int > : : max ( ) )
@ -708,7 +708,7 @@ bool CTxMemPool::accept(CTransaction &tx, bool fCheckInputs, bool fLimitFree,
@@ -708,7 +708,7 @@ bool CTxMemPool::accept(CTransaction &tx, bool fCheckInputs, bool fLimitFree,
// are the actual inputs available?
if ( ! tx . HaveInputs ( view ) )
return error ( " CTxMemPool::accept() : inputs already spent " ) ;
return state . Invalid ( error ( " CTxMemPool::accept() : inputs already spent " ) ) ;
// Bring the best block into scope
view . GetBestBlock ( ) ;
@ -760,7 +760,7 @@ bool CTxMemPool::accept(CTransaction &tx, bool fCheckInputs, bool fLimitFree,
@@ -760,7 +760,7 @@ bool CTxMemPool::accept(CTransaction &tx, bool fCheckInputs, bool fLimitFree,
// Check against previous transactions
// This is done last to help prevent CPU exhaustion denial-of-service attacks.
if ( ! tx . CheckInputs ( view , true , SCRIPT_VERIFY_P2SH ) )
if ( ! tx . CheckInputs ( state , view , true , SCRIPT_VERIFY_P2SH ) )
{
return error ( " CTxMemPool::accept() : ConnectInputs failed % s " , hash.ToString().substr(0,10).c_str()) ;
}
@ -789,9 +789,13 @@ bool CTxMemPool::accept(CTransaction &tx, bool fCheckInputs, bool fLimitFree,
@@ -789,9 +789,13 @@ bool CTxMemPool::accept(CTransaction &tx, bool fCheckInputs, bool fLimitFree,
return true ;
}
bool CTransaction : : AcceptToMemoryPool ( bool fCheckInputs , bool fLimitFree , bool * pfMissingInputs )
bool CTransaction : : AcceptToMemoryPool ( CValidationState & state , bool fCheckInputs , bool fLimitFree , bool * pfMissingInputs )
{
return mempool . accept ( * this , fCheckInputs , fLimitFree , pfMissingInputs ) ;
try {
return mempool . accept ( state , * this , fCheckInputs , fLimitFree , pfMissingInputs ) ;
} catch ( std : : runtime_error & e ) {
return state . Abort ( _ ( " System error: " ) + e . what ( ) ) ;
}
}
bool CTxMemPool : : addUnchecked ( const uint256 & hash , CTransaction & tx )
@ -904,7 +908,8 @@ int CMerkleTx::GetBlocksToMaturity() const
@@ -904,7 +908,8 @@ int CMerkleTx::GetBlocksToMaturity() const
bool CMerkleTx : : AcceptToMemoryPool ( bool fCheckInputs , bool fLimitFree )
{
return CTransaction : : AcceptToMemoryPool ( fCheckInputs , fLimitFree ) ;
CValidationState state ;
return CTransaction : : AcceptToMemoryPool ( state , fCheckInputs , fLimitFree ) ;
}
@ -1200,11 +1205,13 @@ void static InvalidBlockFound(CBlockIndex *pindex) {
@@ -1200,11 +1205,13 @@ void static InvalidBlockFound(CBlockIndex *pindex) {
pblocktree - > WriteBlockIndex ( CDiskBlockIndex ( pindex ) ) ;
setBlockIndexValid . erase ( pindex ) ;
InvalidChainFound ( pindex ) ;
if ( pindex - > pnext )
ConnectBestBlock ( ) ; // reorganise away from the failed block
if ( pindex - > pnext ) {
CValidationState stateDummy ;
ConnectBestBlock ( stateDummy ) ; // reorganise away from the failed block
}
}
bool ConnectBestBlock ( ) {
bool ConnectBestBlock ( CValidationState & state ) {
do {
CBlockIndex * pindexNewBest ;
@ -1243,8 +1250,13 @@ bool ConnectBestBlock() {
@@ -1243,8 +1250,13 @@ bool ConnectBestBlock() {
BOOST_FOREACH ( CBlockIndex * pindexSwitch , vAttach ) {
if ( fRequestShutdown )
break ;
if ( ! SetBestChain ( pindexSwitch ) )
CValidationState state ;
try {
if ( ! SetBestChain ( state , pindexSwitch ) )
return false ;
} catch ( std : : runtime_error & e ) {
return state . Abort ( _ ( " System error: " ) + e . what ( ) ) ;
}
}
return true ;
}
@ -1306,22 +1318,20 @@ unsigned int CTransaction::GetP2SHSigOpCount(CCoinsViewCache& inputs) const
@@ -1306,22 +1318,20 @@ unsigned int CTransaction::GetP2SHSigOpCount(CCoinsViewCache& inputs) const
return nSigOps ;
}
bool CTransaction : : UpdateCoins ( CCoinsViewCache & inputs , CTxUndo & txundo , int nHeight , const uint256 & txhash ) const
bool CTransaction : : UpdateCoins ( CValidationState & state , C CoinsViewCache & inputs , CTxUndo & txundo , int nHeight , const uint256 & txhash ) const
{
// mark inputs spent
if ( ! IsCoinBase ( ) ) {
BOOST_FOREACH ( const CTxIn & txin , vin ) {
CCoins & coins = inputs . GetCoins ( txin . prevout . hash ) ;
CTxInUndo undo ;
if ( ! coins . Spend ( txin . prevout , undo ) )
return error ( " UpdateCoins() : cannot spend input " ) ;
assert ( coins . Spend ( txin . prevout , undo ) ) ;
txundo . vprevout . push_back ( undo ) ;
}
}
// add outputs
if ( ! inputs . SetCoins ( txhash , CCoins ( * this , nHeight ) ) )
return error ( " UpdateCoins() : cannot update output " ) ;
assert ( inputs . SetCoins ( txhash , CCoins ( * this , nHeight ) ) ) ;
return true ;
}
@ -1359,7 +1369,7 @@ bool VerifySignature(const CCoins& txFrom, const CTransaction& txTo, unsigned in
@@ -1359,7 +1369,7 @@ bool VerifySignature(const CCoins& txFrom, const CTransaction& txTo, unsigned in
return CScriptCheck ( txFrom , txTo , nIn , flags , nHashType ) ( ) ;
}
bool CTransaction : : CheckInputs ( CCoinsViewCache & inputs , bool fScriptChecks , unsigned int flags , std : : vector < CScriptCheck > * pvChecks ) const
bool CTransaction : : CheckInputs ( CValidationState & state , C CoinsViewCache & inputs , bool fScriptChecks , unsigned int flags , std : : vector < CScriptCheck > * pvChecks ) const
{
if ( ! IsCoinBase ( ) )
{
@ -1369,7 +1379,7 @@ bool CTransaction::CheckInputs(CCoinsViewCache &inputs, bool fScriptChecks, unsi
@@ -1369,7 +1379,7 @@ bool CTransaction::CheckInputs(CCoinsViewCache &inputs, bool fScriptChecks, unsi
// This doesn't trigger the DoS code on purpose; if it did, it would make it easier
// for an attacker to attempt to split the network.
if ( ! HaveInputs ( inputs ) )
return error ( " CheckInputs() : % s inputs unavailable " , GetHash().ToString().substr(0,10).c_str() ) ;
return state . Invalid ( error ( " CheckInputs() : %s inputs unavailable " , GetHash ( ) . ToString ( ) . substr ( 0 , 10 ) . c_str ( ) ) ) ;
// While checking, GetBestBlock() refers to the parent block.
// This is also true for mempool checks.
@ -1384,26 +1394,26 @@ bool CTransaction::CheckInputs(CCoinsViewCache &inputs, bool fScriptChecks, unsi
@@ -1384,26 +1394,26 @@ bool CTransaction::CheckInputs(CCoinsViewCache &inputs, bool fScriptChecks, unsi
// If prev is coinbase, check that it's matured
if ( coins . IsCoinBase ( ) ) {
if ( nSpendHeight - coins . nHeight < COINBASE_MATURITY )
return error ( " CheckInputs() : tried to spend coinbase at depth % d " , nSpendHeight - coins.nHeight );
return state . Invalid ( error ( " CheckInputs() : tried to spend coinbase at depth %d " , nSpendHeight - coins . nHeight ) ) ;
}
// Check for negative or overflow input values
nValueIn + = coins . vout [ prevout . n ] . nValue ;
if ( ! MoneyRange ( coins . vout [ prevout . n ] . nValue ) | | ! MoneyRange ( nValueIn ) )
return DoS ( 100 , error ( " CheckInputs() : txin values out of range " ) ) ;
return state . DoS ( 100 , error ( " CheckInputs() : txin values out of range " ) ) ;
}
if ( nValueIn < GetValueOut ( ) )
return DoS ( 100 , error ( " ChecktInputs() : % s value in < value out " , GetHash().ToString().substr(0,10).c_str()) ) ;
return state . DoS ( 100 , error ( " ChecktInputs() : %s value in < value out " , GetHash ( ) . ToString ( ) . substr ( 0 , 10 ) . c_str ( ) ) ) ;
// Tally transaction fees
int64 nTxFee = nValueIn - GetValueOut ( ) ;
if ( nTxFee < 0 )
return DoS ( 100 , error ( " CheckInputs() : % s nTxFee < 0 " , GetHash().ToString().substr(0,10).c_str()) ) ;
return state . DoS ( 100 , error ( " CheckInputs() : %s nTxFee < 0 " , GetHash ( ) . ToString ( ) . substr ( 0 , 10 ) . c_str ( ) ) ) ;
nFees + = nTxFee ;
if ( ! MoneyRange ( nFees ) )
return DoS ( 100 , error ( " CheckInputs() : nFees out of range " ) ) ;
return state . DoS ( 100 , error ( " CheckInputs() : nFees out of range " ) ) ;
// The first loop above does all the inexpensive checks.
// Only if ALL inputs pass do we perform expensive ECDSA signature checks.
@ -1423,56 +1433,9 @@ bool CTransaction::CheckInputs(CCoinsViewCache &inputs, bool fScriptChecks, unsi
@@ -1423,56 +1433,9 @@ bool CTransaction::CheckInputs(CCoinsViewCache &inputs, bool fScriptChecks, unsi
pvChecks - > push_back ( CScriptCheck ( ) ) ;
check . swap ( pvChecks - > back ( ) ) ;
} else if ( ! check ( ) )
return DoS ( 100 , false ) ;
}
return state . DoS ( 100 , false ) ;
}
}
return true ;
}
bool CTransaction : : ClientCheckInputs ( ) const
{
if ( IsCoinBase ( ) )
return false ;
// Take over previous transactions' spent pointers
{
LOCK ( mempool . cs ) ;
int64 nValueIn = 0 ;
for ( unsigned int i = 0 ; i < vin . size ( ) ; i + + )
{
// Get prev tx from single transactions in memory
COutPoint prevout = vin [ i ] . prevout ;
if ( ! mempool . exists ( prevout . hash ) )
return false ;
CTransaction & txPrev = mempool . lookup ( prevout . hash ) ;
if ( prevout . n > = txPrev . vout . size ( ) )
return false ;
// Verify signature
if ( ! VerifySignature ( CCoins ( txPrev , - 1 ) , * this , i , SCRIPT_VERIFY_P2SH , 0 ) )
return error ( " ConnectInputs() : VerifySignature failed " ) ;
///// this is redundant with the mempool.mapNextTx stuff,
///// not sure which I want to get rid of
///// this has to go away now that posNext is gone
// // Check for conflicts
// if (!txPrev.vout[prevout.n].posNext.IsNull())
// return error("ConnectInputs() : prev tx already used");
//
// // Flag outpoints as used
// txPrev.vout[prevout.n].posNext = posThisTx;
nValueIn + = txPrev . vout [ prevout . n ] . nValue ;
if ( ! MoneyRange ( txPrev . vout [ prevout . n ] . nValue ) | | ! MoneyRange ( nValueIn ) )
return error ( " ClientConnectInputs() : txin values out of range " ) ;
}
if ( GetValueOut ( ) > nValueIn )
return false ;
}
return true ;
@ -1481,7 +1444,7 @@ bool CTransaction::ClientCheckInputs() const
@@ -1481,7 +1444,7 @@ bool CTransaction::ClientCheckInputs() const
bool CBlock : : DisconnectBlock ( CBlockIndex * pindex , CCoinsViewCache & view , bool * pfClean )
bool CBlock : : DisconnectBlock ( CValidationState & state , C BlockIndex * pindex , CCoinsViewCache & view , bool * pfClean )
{
assert ( pindex = = view . GetBestBlock ( ) ) ;
@ -1582,7 +1545,7 @@ void static FlushBlockFile()
@@ -1582,7 +1545,7 @@ void static FlushBlockFile()
}
}
bool FindUndoPos ( int nFile , CDiskBlockPos & pos , unsigned int nAddSize ) ;
bool FindUndoPos ( CValidationState & state , int nFile , CDiskBlockPos & pos , unsigned int nAddSize ) ;
static CCheckQueue < CScriptCheck > scriptcheckqueue ( 128 ) ;
@ -1597,10 +1560,10 @@ void ThreadScriptCheckQuit() {
@@ -1597,10 +1560,10 @@ void ThreadScriptCheckQuit() {
scriptcheckqueue . Quit ( ) ;
}
bool CBlock : : ConnectBlock ( CBlockIndex * pindex , CCoinsViewCache & view , bool fJustCheck )
bool CBlock : : ConnectBlock ( CValidationState & state , C BlockIndex * pindex , CCoinsViewCache & view , bool fJustCheck )
{
// Check it again in case a previous version let a bad block in
if ( ! CheckBlock ( ! fJustCheck , ! fJustCheck ) )
if ( ! CheckBlock ( state , ! fJustCheck , ! fJustCheck ) )
return false ;
// verify that the view's current state corresponds to the previous block
@ -1665,12 +1628,12 @@ bool CBlock::ConnectBlock(CBlockIndex* pindex, CCoinsViewCache &view, bool fJust
@@ -1665,12 +1628,12 @@ bool CBlock::ConnectBlock(CBlockIndex* pindex, CCoinsViewCache &view, bool fJust
nInputs + = tx . vin . size ( ) ;
nSigOps + = tx . GetLegacySigOpCount ( ) ;
if ( nSigOps > MAX_BLOCK_SIGOPS )
return DoS ( 100 , error ( " ConnectBlock() : too many sigops " ) );
return state . DoS ( 100 , error ( " ConnectBlock() : too many sigops " ) ) ;
if ( ! tx . IsCoinBase ( ) )
{
if ( ! tx . HaveInputs ( view ) )
return DoS ( 100 , error ( " ConnectBlock() : inputs missing / sp ent" ) );
return state . DoS ( 100 , error ( " ConnectBlock() : inputs missing/sp ent " ) ) ;
if ( fStrictPayToScriptHash )
{
@ -1679,19 +1642,19 @@ bool CBlock::ConnectBlock(CBlockIndex* pindex, CCoinsViewCache &view, bool fJust
@@ -1679,19 +1642,19 @@ bool CBlock::ConnectBlock(CBlockIndex* pindex, CCoinsViewCache &view, bool fJust
// an incredibly-expensive-to-validate block.
nSigOps + = tx . GetP2SHSigOpCount ( view ) ;
if ( nSigOps > MAX_BLOCK_SIGOPS )
return DoS ( 100 , error ( " ConnectBlock() : too many sigops " ) );
return state . DoS ( 100 , error ( " ConnectBlock() : too many sigops " ) ) ;
}
nFees + = tx . GetValueIn ( view ) - tx . GetValueOut ( ) ;
std : : vector < CScriptCheck > vChecks ;
if ( ! tx . CheckInputs ( view , fScriptChecks , flags , nScriptCheckThreads ? & vChecks : NULL ) )
if ( ! tx . CheckInputs ( state , view , fScriptChecks , flags , nScriptCheckThreads ? & vChecks : NULL ) )
return false ;
control . Add ( vChecks ) ;
}
CTxUndo txundo ;
if ( ! tx . UpdateCoins ( view , txundo , pindex - > nHeight , GetTxHash ( i ) ) )
if ( ! tx . UpdateCoins ( state , view , txundo , pindex - > nHeight , GetTxHash ( i ) ) )
return error ( " ConnectBlock() : UpdateInputs failed " ) ;
if ( ! tx . IsCoinBase ( ) )
blockundo . vtxundo . push_back ( txundo ) ;
@ -1704,10 +1667,10 @@ bool CBlock::ConnectBlock(CBlockIndex* pindex, CCoinsViewCache &view, bool fJust
@@ -1704,10 +1667,10 @@ bool CBlock::ConnectBlock(CBlockIndex* pindex, CCoinsViewCache &view, bool fJust
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 ) ) ;
if ( vtx [ 0 ] . GetValueOut ( ) > GetBlockValue ( pindex - > nHeight , nFees ) )
return error ( " ConnectBlock() : coinbase pays too much ( actual = % " PRI64d " vs limit = % " PRI64d " ) " , vtx[0].GetValueOut(), GetBlockValue(pindex->nHeight, nFees) );
return state . DoS ( 100 , error ( " ConnectBlock() : coinbase pays too much (actual=% " PRI64d " vs limit=% " PRI64d " ) " , vtx [ 0 ] . GetValueOut ( ) , GetBlockValue ( pindex - > nHeight , nFees ) ) ) ;
if ( ! control . Wait ( ) )
return DoS ( 100 , false ) ;
return state . DoS ( 100 , false ) ;
int64 nTime2 = GetTimeMicros ( ) - nStart ;
if ( fBenchmark )
printf ( " - Verify %u txins: %.2fms (%.3fms/txin) \n " , nInputs - 1 , 0.001 * nTime2 , nInputs < = 1 ? 0 : 0.001 * nTime2 / ( nInputs - 1 ) ) ;
@ -1720,10 +1683,10 @@ bool CBlock::ConnectBlock(CBlockIndex* pindex, CCoinsViewCache &view, bool fJust
@@ -1720,10 +1683,10 @@ bool CBlock::ConnectBlock(CBlockIndex* pindex, CCoinsViewCache &view, bool fJust
{
if ( pindex - > GetUndoPos ( ) . IsNull ( ) ) {
CDiskBlockPos pos ;
if ( ! FindUndoPos ( pindex - > nFile , pos , : : GetSerializeSize ( blockundo , SER_DISK , CLIENT_VERSION ) + 40 ) )
if ( ! FindUndoPos ( state , pindex - > nFile , pos , : : GetSerializeSize ( blockundo , SER_DISK , CLIENT_VERSION ) + 40 ) )
return error ( " ConnectBlock() : FindUndoPos failed " ) ;
if ( ! blockundo . WriteToDisk ( pos , pindex - > pprev - > GetBlockHash ( ) ) )
return error ( " ConnectBlock() : CBlockUndo : : WriteToDisk failed " ) ;
return state . Abort ( _ ( " Failed to write undo data " ) ) ;
// update nUndoPos in block index
pindex - > nUndoPos = pos . nPos ;
@ -1734,15 +1697,15 @@ bool CBlock::ConnectBlock(CBlockIndex* pindex, CCoinsViewCache &view, bool fJust
@@ -1734,15 +1697,15 @@ bool CBlock::ConnectBlock(CBlockIndex* pindex, CCoinsViewCache &view, bool fJust
CDiskBlockIndex blockindex ( pindex ) ;
if ( ! pblocktree - > WriteBlockIndex ( blockindex ) )
return error ( " ConnectBlock() : WriteBlockIndex failed " ) ;
return state . Abort ( _ ( " Failed to write block index " ) ) ;
}
if ( fTxIndex )
pblocktree - > WriteTxIndex ( vPos ) ;
if ( ! pblocktree - > WriteTxIndex ( vPos ) )
return state . Abort ( _ ( " Failed to write transaction index " ) ) ;
// add this block to the view's block chain
if ( ! view . SetBestBlock ( pindex ) )
return false ;
assert ( view . SetBestBlock ( pindex ) ) ;
// Watch for transactions paying to me
for ( unsigned int i = 0 ; i < vtx . size ( ) ; i + + )
@ -1751,7 +1714,7 @@ bool CBlock::ConnectBlock(CBlockIndex* pindex, CCoinsViewCache &view, bool fJust
@@ -1751,7 +1714,7 @@ bool CBlock::ConnectBlock(CBlockIndex* pindex, CCoinsViewCache &view, bool fJust
return true ;
}
bool SetBestChain ( CBlockIndex * pindexNew )
bool SetBestChain ( CValidationState & state , C BlockIndex * pindexNew )
{
// All modifications to the coin state will be done in this cache.
// Only when all have succeeded, we push it to pcoinsTip.
@ -1762,13 +1725,14 @@ bool SetBestChain(CBlockIndex* pindexNew)
@@ -1762,13 +1725,14 @@ bool SetBestChain(CBlockIndex* pindexNew)
CBlockIndex * plonger = pindexNew ;
while ( pfork & & pfork ! = plonger )
{
while ( plonger - > nHeight > pfork - > nHeight )
if ( ! ( plonger = plonger - > pprev ) )
return error ( " SetBestChain() : plonger - > pprev is null " ) ;
while ( plonger - > nHeight > pfork - > nHeight ) {
plonger = plonger - > pprev ;
assert ( plonger ! = NULL ) ;
}
if ( pfork = = plonger )
break ;
if ( ! ( pfork = pfork - > pprev ) )
return error ( " SetBestChain() : pfork - > pprev is null " ) ;
pfork = pfork - > pprev ;
assert ( pfork ! = NULL ) ;
}
// List of what to disconnect (typically nothing)
@ -1792,9 +1756,9 @@ bool SetBestChain(CBlockIndex* pindexNew)
@@ -1792,9 +1756,9 @@ bool SetBestChain(CBlockIndex* pindexNew)
BOOST_FOREACH ( CBlockIndex * pindex , vDisconnect ) {
CBlock block ;
if ( ! block . ReadFromDisk ( pindex ) )
return error ( " SetBestBlock() : ReadFromDisk for disconnect failed " ) ;
return state . Abort ( _ ( " Failed to read block " ) ) ;
int64 nStart = GetTimeMicros ( ) ;
if ( ! block . DisconnectBlock ( pindex , view ) )
if ( ! block . DisconnectBlock ( state , pindex , view ) )
return error ( " SetBestBlock() : DisconnectBlock % s failed " , BlockHashStr(pindex->GetBlockHash()).c_str()) ;
if ( fBenchmark )
printf ( " - Disconnect: %.2fms \n " , ( GetTimeMicros ( ) - nStart ) * 0.001 ) ;
@ -1812,11 +1776,13 @@ bool SetBestChain(CBlockIndex* pindexNew)
@@ -1812,11 +1776,13 @@ bool SetBestChain(CBlockIndex* pindexNew)
BOOST_FOREACH ( CBlockIndex * pindex , vConnect ) {
CBlock block ;
if ( ! block . ReadFromDisk ( pindex ) )
return error ( " SetBestBlock() : ReadFromDisk for connect failed " ) ;
return state . Abort ( _ ( " Failed to read block " ) ) ;
int64 nStart = GetTimeMicros ( ) ;
if ( ! block . ConnectBlock ( pindex , view ) ) {
if ( ! block . ConnectBlock ( state , pindex , view ) ) {
if ( state . IsInvalid ( ) ) {
InvalidChainFound ( pindexNew ) ;
InvalidBlockFound ( pindex ) ;
}
return error ( " SetBestBlock() : ConnectBlock % s failed " , BlockHashStr(pindex->GetBlockHash()).c_str()) ;
}
if ( fBenchmark )
@ -1830,8 +1796,7 @@ bool SetBestChain(CBlockIndex* pindexNew)
@@ -1830,8 +1796,7 @@ bool SetBestChain(CBlockIndex* pindexNew)
// Flush changes to global coin state
int64 nStart = GetTimeMicros ( ) ;
int nModified = view . GetCacheSize ( ) ;
if ( ! view . Flush ( ) )
return error ( " SetBestBlock() : unable to modify coin state " ) ;
assert ( view . Flush ( ) ) ;
int64 nTime = GetTimeMicros ( ) - nStart ;
if ( fBenchmark )
printf ( " - Flush %i transactions: %.2fms (%.4fms/tx) \n " , nModified , 0.001 * nTime , 0.001 * nTime / nModified ) ;
@ -1839,10 +1804,17 @@ bool SetBestChain(CBlockIndex* pindexNew)
@@ -1839,10 +1804,17 @@ bool SetBestChain(CBlockIndex* pindexNew)
// Make sure it's successfully written to disk before changing memory structure
bool fIsInitialDownload = IsInitialBlockDownload ( ) ;
if ( ! fIsInitialDownload | | pcoinsTip - > GetCacheSize ( ) > nCoinCacheSize ) {
// Typical CCoins structures on disk are around 100 bytes in size.
// 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
// an overestimation, as most will delete an existing entry or
// overwrite one. Still, use a conservative safety factor of 2.
if ( ! CheckDiskSpace ( 100 * 2 * 2 * pcoinsTip - > GetCacheSize ( ) ) )
return state . Error ( ) ;
FlushBlockFile ( ) ;
pblocktree - > Sync ( ) ;
if ( ! pcoinsTip - > Flush ( ) )
return false ;
return state . Abort ( _ ( " Failed to write to coin database " ) ) ;
}
// At this point, all changes have been done to the database.
@ -1859,8 +1831,11 @@ bool SetBestChain(CBlockIndex* pindexNew)
@@ -1859,8 +1831,11 @@ bool SetBestChain(CBlockIndex* pindexNew)
pindex - > pprev - > pnext = pindex ;
// Resurrect memory transactions that were in the disconnected branch
BOOST_FOREACH ( CTransaction & tx , vResurrect )
tx . AcceptToMemoryPool ( true , false ) ;
BOOST_FOREACH ( CTransaction & tx , vResurrect ) {
// ignore validation errors in resurrected transactions
CValidationState stateDummy ;
tx . AcceptToMemoryPool ( stateDummy , true , false ) ;
}
// Delete redundant memory transactions that are in the connected branch
BOOST_FOREACH ( CTransaction & tx , vDelete ) {
@ -1917,17 +1892,16 @@ bool SetBestChain(CBlockIndex* pindexNew)
@@ -1917,17 +1892,16 @@ bool SetBestChain(CBlockIndex* pindexNew)
}
bool CBlock : : AddToBlockIndex ( const CDiskBlockPos & pos )
bool CBlock : : AddToBlockIndex ( CValidationState & state , const CDiskBlockPos & pos )
{
// Check for duplicate
uint256 hash = GetHash ( ) ;
if ( mapBlockIndex . count ( hash ) )
return error ( " AddToBlockIndex() : % s already exists " , BlockHashStr(hash).c_str() ) ;
return state . Invalid ( error ( " AddToBlockIndex() : %s already exists " , BlockHashStr ( hash ) . c_str ( ) ) ) ;
// Construct new block index object
CBlockIndex * pindexNew = new CBlockIndex ( * this ) ;
if ( ! pindexNew )
return error ( " AddToBlockIndex() : new CBlockIndex failed " ) ;
assert ( pindexNew ) ;
map < uint256 , CBlockIndex * > : : iterator mi = mapBlockIndex . insert ( make_pair ( hash , pindexNew ) ) . first ;
pindexNew - > phashBlock = & ( ( * mi ) . first ) ;
map < uint256 , CBlockIndex * > : : iterator miPrev = mapBlockIndex . find ( hashPrevBlock ) ;
@ -1945,10 +1919,11 @@ bool CBlock::AddToBlockIndex(const CDiskBlockPos &pos)
@@ -1945,10 +1919,11 @@ bool CBlock::AddToBlockIndex(const CDiskBlockPos &pos)
pindexNew - > nStatus = BLOCK_VALID_TRANSACTIONS | BLOCK_HAVE_DATA ;
setBlockIndexValid . insert ( pindexNew ) ;
pblocktree - > WriteBlockIndex ( CDiskBlockIndex ( pindexNew ) ) ;
if ( ! pblocktree - > WriteBlockIndex ( CDiskBlockIndex ( pindexNew ) ) )
return state . Abort ( _ ( " Failed to write block index " ) ) ;
// New best?
if ( ! ConnectBestBlock ( ) )
if ( ! ConnectBestBlock ( state ) )
return false ;
if ( pindexNew = = pindexBest )
@ -1959,14 +1934,15 @@ bool CBlock::AddToBlockIndex(const CDiskBlockPos &pos)
@@ -1959,14 +1934,15 @@ bool CBlock::AddToBlockIndex(const CDiskBlockPos &pos)
hashPrevBestCoinBase = GetTxHash ( 0 ) ;
}
pblocktree - > Flush ( ) ;
if ( ! pblocktree - > Flush ( ) )
return state . Abort ( _ ( " Failed to sync block index " ) ) ;
uiInterface . NotifyBlocksChanged ( ) ;
return true ;
}
bool FindBlockPos ( CDiskBlockPos & pos , unsigned int nAddSize , unsigned int nHeight , uint64 nTime , bool fKnown = false )
bool FindBlockPos ( CValidationState & state , C DiskBlockPos & pos , unsigned int nAddSize , unsigned int nHeight , uint64 nTime , bool fKnown = false )
{
bool fUpdatedLast = false ;
@ -2008,19 +1984,19 @@ bool FindBlockPos(CDiskBlockPos &pos, unsigned int nAddSize, unsigned int nHeigh
@@ -2008,19 +1984,19 @@ bool FindBlockPos(CDiskBlockPos &pos, unsigned int nAddSize, unsigned int nHeigh
}
}
else
return error ( " FindBlockPos() : out of disk space " ) ;
return state . Error ( ) ;
}
}
if ( ! pblocktree - > WriteBlockFileInfo ( nLastBlockFile , infoLastBlockFile ) )
return error ( " FindBlockPos() : cannot write updated block info " ) ;
return state . Abort ( _ ( " Failed to write file info " ) ) ;
if ( fUpdatedLast )
pblocktree - > WriteLastBlockFile ( nLastBlockFile ) ;
return true ;
}
bool FindUndoPos ( int nFile , CDiskBlockPos & pos , unsigned int nAddSize )
bool FindUndoPos ( CValidationState & state , int nFile , CDiskBlockPos & pos , unsigned int nAddSize )
{
pos . nFile = nFile ;
@ -2031,15 +2007,15 @@ bool FindUndoPos(int nFile, CDiskBlockPos &pos, unsigned int nAddSize)
@@ -2031,15 +2007,15 @@ bool FindUndoPos(int nFile, CDiskBlockPos &pos, unsigned int nAddSize)
pos . nPos = infoLastBlockFile . nUndoSize ;
nNewSize = ( infoLastBlockFile . nUndoSize + = nAddSize ) ;
if ( ! pblocktree - > WriteBlockFileInfo ( nLastBlockFile , infoLastBlockFile ) )
return error ( " FindUndoPos() : cannot write updated block info " ) ;
return state . Abort ( _ ( " Failed to write block info " ) ) ;
} else {
CBlockFileInfo info ;
if ( ! pblocktree - > ReadBlockFileInfo ( nFile , info ) )
return error ( " FindUndoPos() : cannot read block info " ) ;
return state . Abort ( _ ( " Failed to read block info " ) ) ;
pos . nPos = info . nUndoSize ;
nNewSize = ( info . nUndoSize + = nAddSize ) ;
if ( ! pblocktree - > WriteBlockFileInfo ( nFile , info ) )
return error ( " FindUndoPos() : cannot write updated block info " ) ;
return state . Abort ( _ ( " Failed to write block info " ) ) ;
}
unsigned int nOldChunks = ( pos . nPos + UNDOFILE_CHUNK_SIZE - 1 ) / UNDOFILE_CHUNK_SIZE ;
@ -2054,41 +2030,41 @@ bool FindUndoPos(int nFile, CDiskBlockPos &pos, unsigned int nAddSize)
@@ -2054,41 +2030,41 @@ bool FindUndoPos(int nFile, CDiskBlockPos &pos, unsigned int nAddSize)
}
}
else
return error ( " FindUndoPos() : out of disk space " ) ;
return state . Error ( ) ;
}
return true ;
}
bool CBlock : : CheckBlock ( bool fCheckPOW , bool fCheckMerkleRoot ) const
bool CBlock : : CheckBlock ( CValidationState & state , bool fCheckPOW , bool fCheckMerkleRoot ) const
{
// These are checks that are independent of context
// that can be verified before saving an orphan block.
// Size limits
if ( vtx . empty ( ) | | vtx . size ( ) > MAX_BLOCK_SIZE | | : : GetSerializeSize ( * this , SER_NETWORK , PROTOCOL_VERSION ) > MAX_BLOCK_SIZE )
return DoS ( 100 , error ( " CheckBlock() : size limits failed " ) );
return state . DoS ( 100 , error ( " CheckBlock() : size limits failed " ) ) ;
// Check proof of work matches claimed amount
if ( fCheckPOW & & ! CheckProofOfWork ( GetHash ( ) , nBits ) )
return DoS ( 50 , error ( " CheckBlock() : proof of work failed " ) ) ;
return state . DoS ( 50 , error ( " CheckBlock() : proof of work failed " ) ) ;
// Check timestamp
if ( GetBlockTime ( ) > GetAdjustedTime ( ) + 2 * 60 * 60 )
return 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
if ( vtx . empty ( ) | | ! vtx [ 0 ] . IsCoinBase ( ) )
return DoS ( 100 , error ( " CheckBlock() : first tx is not c oinbase " ) );
return state . DoS ( 100 , error ( " CheckBlock() : first tx is not c oinbase " ) ) ;
for ( unsigned int i = 1 ; i < vtx . size ( ) ; i + + )
if ( vtx [ i ] . IsCoinBase ( ) )
return DoS ( 100 , error ( " CheckBlock() : more than one coinbase " ) ) ;
return state . DoS ( 100 , error ( " CheckBlock() : more than one coinbase " ) ) ;
// Check transactions
BOOST_FOREACH ( const CTransaction & tx , vtx )
if ( ! tx . CheckTransaction ( ) )
return DoS ( tx . nDoS , error ( " CheckBlock() : CheckTransaction failed " ) );
if ( ! tx . CheckTransaction ( state ) )
return error ( " CheckBlock() : CheckTransaction failed " ) ;
// 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
@ -2102,7 +2078,7 @@ bool CBlock::CheckBlock(bool fCheckPOW, bool fCheckMerkleRoot) const
@@ -2102,7 +2078,7 @@ bool CBlock::CheckBlock(bool fCheckPOW, bool fCheckMerkleRoot) const
uniqueTx . insert ( GetTxHash ( i ) ) ;
}
if ( uniqueTx . size ( ) ! = vtx . size ( ) )
return DoS ( 100 , error ( " CheckBlock() : duplicate transaction " ) );
return state . DoS ( 100 , error ( " CheckBlock() : duplicate transaction " ) ) ;
unsigned int nSigOps = 0 ;
BOOST_FOREACH ( const CTransaction & tx , vtx )
@ -2110,21 +2086,21 @@ bool CBlock::CheckBlock(bool fCheckPOW, bool fCheckMerkleRoot) const
@@ -2110,21 +2086,21 @@ bool CBlock::CheckBlock(bool fCheckPOW, bool fCheckMerkleRoot) const
nSigOps + = tx . GetLegacySigOpCount ( ) ;
}
if ( nSigOps > MAX_BLOCK_SIGOPS )
return DoS ( 100 , error ( " CheckBlock() : out - of - bounds SigOpCount " ) ) ;
return state . DoS ( 100 , error ( " CheckBlock() : out-of-bounds SigOpCount " ) ) ;
// Check merkle root
if ( fCheckMerkleRoot & & hashMerkleRoot ! = BuildMerkleTree ( ) )
return DoS ( 100 , error ( " CheckBlock() : hashMerkleRoot mismatch " ) );
return state . DoS ( 100 , error ( " CheckBlock() : hashMerkleRoot mismatch " ) ) ;
return true ;
}
bool CBlock : : AcceptBlock ( CDiskBlockPos * dbp )
bool CBlock : : AcceptBlock ( CValidationState & state , C DiskBlockPos * dbp )
{
// Check for duplicate
uint256 hash = GetHash ( ) ;
if ( mapBlockIndex . count ( hash ) )
return error ( " AcceptBlock() : block already in mapBlockIndex " ) ;
return state . Invalid ( error ( " AcceptBlock() : block already in mapBlockIndex " ) ) ;
// Get prev block index
CBlockIndex * pindexPrev = NULL ;
@ -2132,26 +2108,26 @@ bool CBlock::AcceptBlock(CDiskBlockPos *dbp)
@@ -2132,26 +2108,26 @@ bool CBlock::AcceptBlock(CDiskBlockPos *dbp)
if ( hash ! = hashGenesisBlock ) {
map < uint256 , CBlockIndex * > : : iterator mi = mapBlockIndex . find ( hashPrevBlock ) ;
if ( mi = = mapBlockIndex . end ( ) )
return DoS ( 10 , error ( " AcceptBlock() : prev block not found " ) ) ;
return state . DoS ( 10 , error ( " AcceptBlock() : prev block not found " ) ) ;
pindexPrev = ( * mi ) . second ;
nHeight = pindexPrev - > nHeight + 1 ;
// Check proof of work
if ( nBits ! = GetNextWorkRequired ( pindexPrev , this ) )
return DoS ( 100 , error ( " AcceptBlock() : incorrect proof of work " ) );
return state . DoS ( 100 , error ( " AcceptBlock() : incorrect proof of work " ) ) ;
// Check timestamp against prev
if ( GetBlockTime ( ) < = pindexPrev - > GetMedianTimePast ( ) )
return 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
BOOST_FOREACH ( const CTransaction & tx , vtx )
if ( ! tx . IsFinal ( nHeight , GetBlockTime ( ) ) )
return 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
if ( ! Checkpoints : : CheckBlock ( nHeight , hash ) )
return 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:
if ( nVersion < 2 )
@ -2159,7 +2135,7 @@ bool CBlock::AcceptBlock(CDiskBlockPos *dbp)
@@ -2159,7 +2135,7 @@ bool CBlock::AcceptBlock(CDiskBlockPos *dbp)
if ( ( ! fTestNet & & CBlockIndex : : IsSuperMajority ( 2 , pindexPrev , 950 , 1000 ) ) | |
( fTestNet & & CBlockIndex : : IsSuperMajority ( 2 , pindexPrev , 75 , 100 ) ) )
{
return error ( " AcceptBlock() : rejected nVersion = 1 block " ) ;
return state . Invalid ( error ( " AcceptBlock() : rejected nVersion=1 block " ) ) ;
}
}
// Enforce block.nVersion=2 rule that the coinbase starts with serialized block height
@ -2171,23 +2147,27 @@ bool CBlock::AcceptBlock(CDiskBlockPos *dbp)
@@ -2171,23 +2147,27 @@ bool CBlock::AcceptBlock(CDiskBlockPos *dbp)
{
CScript expect = CScript ( ) < < nHeight ;
if ( ! std : : equal ( expect . begin ( ) , expect . end ( ) , vtx [ 0 ] . vin [ 0 ] . scriptSig . begin ( ) ) )
return DoS ( 100 , error ( " AcceptBlock() : block height mismatch in coinbase " ) ) ;
return state . DoS ( 100 , error ( " AcceptBlock() : block height mismatch in coinbase " ) ) ;
}
}
}
// Write block to history file
try {
unsigned int nBlockSize = : : GetSerializeSize ( * this , SER_DISK , CLIENT_VERSION ) ;
CDiskBlockPos blockPos ;
if ( dbp ! = NULL )
blockPos = * dbp ;
if ( ! FindBlockPos ( blockPos , nBlockSize + 8 , nHeight , nTime , dbp ! = NULL ) )
if ( ! FindBlockPos ( state , blockPos , nBlockSize + 8 , nHeight , nTime , dbp ! = NULL ) )
return error ( " AcceptBlock() : FindBlockPos failed " ) ;
if ( dbp = = NULL )
if ( ! WriteToDisk ( blockPos ) )
return error ( " AcceptBlock() : WriteToDisk failed " ) ;
if ( ! AddToBlockIndex ( blockPos ) )
return state . Abort ( _ ( " Failed to write block " ) ) ;
if ( ! AddToBlockIndex ( state , blockPos ) )
return error ( " AcceptBlock() : AddToBlockIndex failed " ) ;
} catch ( std : : runtime_error & e ) {
return state . Abort ( _ ( " System error: " ) + e . what ( ) ) ;
}
// Relay inventory, but don't relay old inventory during initial block download
int nBlockEstimate = Checkpoints : : GetTotalBlocksEstimate ( ) ;
@ -2214,17 +2194,17 @@ bool CBlockIndex::IsSuperMajority(int minVersion, const CBlockIndex* pstart, uns
@@ -2214,17 +2194,17 @@ bool CBlockIndex::IsSuperMajority(int minVersion, const CBlockIndex* pstart, uns
return ( nFound > = nRequired ) ;
}
bool ProcessBlock ( CNode * pfrom , CBlock * pblock , CDiskBlockPos * dbp )
bool ProcessBlock ( CValidationState & state , C Node * pfrom , CBlock * pblock , CDiskBlockPos * dbp )
{
// Check for duplicate
uint256 hash = pblock - > GetHash ( ) ;
if ( mapBlockIndex . count ( hash ) )
return error ( " ProcessBlock() : already have block % d % s " , mapBlockIndex[hash]->nHeight, BlockHashStr(hash).c_str() ) ;
return state . Invalid ( error ( " ProcessBlock() : already have block %d %s " , mapBlockIndex [ hash ] - > nHeight , BlockHashStr ( hash ) . c_str ( ) ) ) ;
if ( mapOrphanBlocks . count ( hash ) )
return error ( " ProcessBlock() : already have block ( orphan ) % s " , BlockHashStr(hash).c_str() );
return state . Invalid ( error ( " ProcessBlock() : already have block (orphan) %s " , BlockHashStr ( hash ) . c_str ( ) ) ) ;
// Preliminary checks
if ( ! pblock - > CheckBlock ( ) )
if ( ! pblock - > CheckBlock ( state ) )
return error ( " ProcessBlock() : CheckBlock FAILED " ) ;
CBlockIndex * pcheckpoint = Checkpoints : : GetLastCheckpoint ( mapBlockIndex ) ;
@ -2234,9 +2214,7 @@ bool ProcessBlock(CNode* pfrom, CBlock* pblock, CDiskBlockPos *dbp)
@@ -2234,9 +2214,7 @@ bool ProcessBlock(CNode* pfrom, CBlock* pblock, CDiskBlockPos *dbp)
int64 deltaTime = pblock - > GetBlockTime ( ) - pcheckpoint - > nTime ;
if ( deltaTime < 0 )
{
if ( pfrom )
pfrom - > Misbehaving ( 100 ) ;
return error ( " ProcessBlock() : block with timestamp before last checkpoint " ) ;
return state . DoS ( 100 , error ( " ProcessBlock() : block with timestamp before last checkpoint " ) ) ;
}
CBigNum bnNewBlock ;
bnNewBlock . SetCompact ( pblock - > nBits ) ;
@ -2244,9 +2222,7 @@ bool ProcessBlock(CNode* pfrom, CBlock* pblock, CDiskBlockPos *dbp)
@@ -2244,9 +2222,7 @@ bool ProcessBlock(CNode* pfrom, CBlock* pblock, CDiskBlockPos *dbp)
bnRequired . SetCompact ( ComputeMinWork ( pcheckpoint - > nBits , deltaTime ) ) ;
if ( bnNewBlock > bnRequired )
{
if ( pfrom )
pfrom - > Misbehaving ( 100 ) ;
return error ( " ProcessBlock() : block with too little proof - of - work " ) ;
return state . DoS ( 100 , error ( " ProcessBlock() : block with too little proof-of-work " ) ) ;
}
}
@ -2269,7 +2245,7 @@ bool ProcessBlock(CNode* pfrom, CBlock* pblock, CDiskBlockPos *dbp)
@@ -2269,7 +2245,7 @@ bool ProcessBlock(CNode* pfrom, CBlock* pblock, CDiskBlockPos *dbp)
}
// Store to disk
if ( ! pblock - > AcceptBlock ( dbp ) )
if ( ! pblock - > AcceptBlock ( state , dbp ) )
return error ( " ProcessBlock() : AcceptBlock FAILED " ) ;
// Recursively process any orphan blocks that depended on this one
@ -2283,7 +2259,7 @@ bool ProcessBlock(CNode* pfrom, CBlock* pblock, CDiskBlockPos *dbp)
@@ -2283,7 +2259,7 @@ bool ProcessBlock(CNode* pfrom, CBlock* pblock, CDiskBlockPos *dbp)
+ + mi )
{
CBlock * pblockOrphan = ( * mi ) . second ;
if ( pblockOrphan - > AcceptBlock ( ) )
if ( pblockOrphan - > AcceptBlock ( state ) )
vWorkQueue . push_back ( pblockOrphan - > GetHash ( ) ) ;
mapOrphanBlocks . erase ( pblockOrphan - > GetHash ( ) ) ;
delete pblockOrphan ;
@ -2455,6 +2431,14 @@ uint256 CPartialMerkleTree::ExtractMatches(std::vector<uint256> &vMatch) {
@@ -2455,6 +2431,14 @@ uint256 CPartialMerkleTree::ExtractMatches(std::vector<uint256> &vMatch) {
bool AbortNode ( const std : : string & strMessage ) {
fRequestShutdown = true ;
strMiscWarning = strMessage ;
printf ( " *** %s \n " , strMessage . c_str ( ) ) ;
uiInterface . ThreadSafeMessageBox ( strMessage , " " , CClientUIInterface : : MSG_ERROR | CClientUIInterface : : MODAL ) ;
StartShutdown ( ) ;
return false ;
}
bool CheckDiskSpace ( uint64 nAdditionalBytes )
{
@ -2462,15 +2446,8 @@ bool CheckDiskSpace(uint64 nAdditionalBytes)
@@ -2462,15 +2446,8 @@ bool CheckDiskSpace(uint64 nAdditionalBytes)
// Check for nMinDiskSpace bytes (currently 50MB)
if ( nFreeBytesAvailable < nMinDiskSpace + nAdditionalBytes )
{
fShutdown = true ;
string strMessage = _ ( " Error: Disk space is low! " ) ;
strMiscWarning = strMessage ;
printf ( " *** %s \n " , strMessage . c_str ( ) ) ;
uiInterface . ThreadSafeMessageBox ( strMessage , " " , CClientUIInterface : : MSG_ERROR ) ;
StartShutdown ( ) ;
return false ;
}
return AbortNode ( _ ( " Error: Disk space is low! " ) ) ;
return true ;
}
@ -2612,6 +2589,7 @@ bool VerifyDB() {
@@ -2612,6 +2589,7 @@ bool VerifyDB() {
CBlockIndex * pindexState = pindexBest ;
CBlockIndex * pindexFailure = NULL ;
int nGoodTransactions = 0 ;
CValidationState state ;
for ( CBlockIndex * pindex = pindexBest ; pindex & & pindex - > pprev ; pindex = pindex - > pprev )
{
if ( fRequestShutdown | | pindex - > nHeight < nBestHeight - nCheckDepth )
@ -2621,7 +2599,7 @@ bool VerifyDB() {
@@ -2621,7 +2599,7 @@ bool VerifyDB() {
if ( ! block . ReadFromDisk ( pindex ) )
return error ( " VerifyDB() : * * * block . ReadFromDisk failed at % d , hash = % s " , pindex->nHeight, pindex->GetBlockHash().ToString().c_str()) ;
// check level 1: verify block validity
if ( nCheckLevel > = 1 & & ! block . CheckBlock ( ) )
if ( nCheckLevel > = 1 & & ! block . CheckBlock ( state ) )
return error ( " VerifyDB() : * * * found bad block at % d , hash = % s \ n " , pindex->nHeight, pindex->GetBlockHash().ToString().c_str()) ;
// check level 2: verify undo validity
if ( nCheckLevel > = 2 & & pindex ) {
@ -2635,7 +2613,7 @@ bool VerifyDB() {
@@ -2635,7 +2613,7 @@ bool VerifyDB() {
// 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 ) {
bool fClean = true ;
if ( ! block . DisconnectBlock ( pindex , coins , & fClean ) )
if ( ! block . DisconnectBlock ( state , pindex , coins , & fClean ) )
return error ( " VerifyDB() : * * * irrecoverable inconsistency in block data at % d , hash = % s " , pindex->nHeight, pindex->GetBlockHash().ToString().c_str()) ;
pindexState = pindex - > pprev ;
if ( ! fClean ) {
@ -2656,7 +2634,7 @@ bool VerifyDB() {
@@ -2656,7 +2634,7 @@ bool VerifyDB() {
CBlock block ;
if ( ! block . ReadFromDisk ( pindex ) )
return error ( " VerifyDB() : * * * block . ReadFromDisk failed at % d , hash = % s " , pindex->nHeight, pindex->GetBlockHash().ToString().c_str()) ;
if ( ! block . ConnectBlock ( pindex , coins ) )
if ( ! block . ConnectBlock ( state , pindex , coins ) )
return error ( " VerifyDB() : * * * found unconnectable block at % d , hash = % s " , pindex->nHeight, pindex->GetBlockHash().ToString().c_str()) ;
}
}
@ -2737,11 +2715,12 @@ bool LoadBlockIndex()
@@ -2737,11 +2715,12 @@ bool LoadBlockIndex()
// Start new block file
unsigned int nBlockSize = : : GetSerializeSize ( block , SER_DISK , CLIENT_VERSION ) ;
CDiskBlockPos blockPos ;
if ( ! FindBlockPos ( blockPos , nBlockSize + 8 , 0 , block . nTime ) )
CValidationState state ;
if ( ! FindBlockPos ( state , blockPos , nBlockSize + 8 , 0 , block . nTime ) )
return error ( " AcceptBlock() : FindBlockPos failed " ) ;
if ( ! block . WriteToDisk ( blockPos ) )
return error ( " LoadBlockIndex() : writing genesis block to disk failed " ) ;
if ( ! block . AddToBlockIndex ( blockPos ) )
if ( ! block . AddToBlockIndex ( state , blockPos ) )
return error ( " LoadBlockIndex() : genesis block not accepted " ) ;
}
@ -2825,7 +2804,7 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp)
@@ -2825,7 +2804,7 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp)
int64 nStart = GetTimeMillis ( ) ;
int nLoaded = 0 ;
{
try {
CBufferedFile blkdat ( fileIn , 2 * MAX_BLOCK_SIZE , MAX_BLOCK_SIZE + 8 , SER_DISK , CLIENT_VERSION ) ;
uint64 nStartByte = 0 ;
if ( dbp ) {
@ -2871,14 +2850,19 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp)
@@ -2871,14 +2850,19 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp)
LOCK ( cs_main ) ;
if ( dbp )
dbp - > nPos = nBlockPos ;
if ( ProcessBlock ( NULL , & block , dbp ) )
CValidationState state ;
if ( ProcessBlock ( state , NULL , & block , dbp ) )
nLoaded + + ;
if ( state . IsError ( ) )
break ;
}
} catch ( std : : exception & e ) {
printf ( " %s() : Deserialize or I/O error caught during load \n " , __PRETTY_FUNCTION__ ) ;
}
}
fclose ( fileIn ) ;
} catch ( std : : runtime_error & e ) {
AbortNode ( _ ( " Error: system error: " ) + e . what ( ) ) ;
}
if ( nLoaded > 0 )
printf ( " Loaded %i blocks from external file in % " PRI64d " ms \n " , nLoaded , GetTimeMillis ( ) - nStart ) ;
@ -3448,7 +3432,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
@@ -3448,7 +3432,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
pfrom - > AddInventoryKnown ( inv ) ;
bool fMissingInputs = false ;
if ( tx . AcceptToMemoryPool ( true , true , & fMissingInputs ) )
CValidationState state ;
if ( tx . AcceptToMemoryPool ( state , true , true , & fMissingInputs ) )
{
RelayTransaction ( tx , inv . hash , vMsg ) ;
mapAlreadyAskedFor . erase ( inv ) ;
@ -3469,7 +3454,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
@@ -3469,7 +3454,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
CInv inv ( MSG_TX , tx . GetHash ( ) ) ;
bool fMissingInputs2 = false ;
if ( tx . AcceptToMemoryPool ( true , true , & fMissingInputs2 ) )
if ( tx . AcceptToMemoryPool ( state , true , true , & fMissingInputs2 ) )
{
printf ( " accepted orphan tx %s \n " , inv . hash . ToString ( ) . substr ( 0 , 10 ) . c_str ( ) ) ;
RelayTransaction ( tx , inv . hash , vMsg ) ;
@ -3498,7 +3483,9 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
@@ -3498,7 +3483,9 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
if ( nEvicted > 0 )
printf ( " mapOrphan overflow, removed %u tx \n " , nEvicted ) ;
}
if ( tx . nDoS ) pfrom - > Misbehaving ( tx . nDoS ) ;
int nDoS ;
if ( state . IsInvalid ( nDoS ) )
pfrom - > Misbehaving ( nDoS ) ;
}
@ -3513,9 +3500,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
@@ -3513,9 +3500,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
CInv inv ( MSG_BLOCK , block . GetHash ( ) ) ;
pfrom - > AddInventoryKnown ( inv ) ;
if ( ProcessBlock ( pfrom , & block ) )
CValidationState state ;
if ( ProcessBlock ( state , pfrom , & block ) )
mapAlreadyAskedFor . erase ( inv ) ;
if ( block . nDoS ) pfrom - > Misbehaving ( block . nDoS ) ;
int nDoS ;
if ( state . IsInvalid ( nDoS ) )
pfrom - > Misbehaving ( nDoS ) ;
}
@ -4265,12 +4255,13 @@ CBlockTemplate* CreateNewBlock(CReserveKey& reservekey)
@@ -4265,12 +4255,13 @@ CBlockTemplate* CreateNewBlock(CReserveKey& reservekey)
if ( nBlockSigOps + nTxSigOps > = MAX_BLOCK_SIGOPS )
continue ;
if ( ! tx . CheckInputs ( viewTemp , true , SCRIPT_VERIFY_P2SH ) )
CValidationState state ;
if ( ! tx . CheckInputs ( state , viewTemp , true , SCRIPT_VERIFY_P2SH ) )
continue ;
CTxUndo txundo ;
uint256 hash = tx . GetHash ( ) ;
if ( ! tx . UpdateCoins ( viewTemp , txundo , pindexPrev - > nHeight + 1 , hash ) )
if ( ! tx . UpdateCoins ( state , viewTemp , txundo , pindexPrev - > nHeight + 1 , hash ) )
continue ;
// push changes from the second layer cache to the first one
@ -4328,7 +4319,8 @@ CBlockTemplate* CreateNewBlock(CReserveKey& reservekey)
@@ -4328,7 +4319,8 @@ CBlockTemplate* CreateNewBlock(CReserveKey& reservekey)
indexDummy . pprev = pindexPrev ;
indexDummy . nHeight = pindexPrev - > nHeight + 1 ;
CCoinsViewCache viewNew ( * pcoinsTip , true ) ;
if ( ! pblock - > ConnectBlock ( & indexDummy , viewNew , true ) )
CValidationState state ;
if ( ! pblock - > ConnectBlock ( state , & indexDummy , viewNew , true ) )
throw std : : runtime_error ( " CreateNewBlock() : ConnectBlock failed " ) ;
}
@ -4430,7 +4422,8 @@ bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey)
@@ -4430,7 +4422,8 @@ bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey)
}
// Process this block the same as if we had received it from another node
if ( ! ProcessBlock ( NULL , pblock ) )
CValidationState state ;
if ( ! ProcessBlock ( state , NULL , pblock ) )
return error ( " BitcoinMiner : ProcessBlock, block not accepted " ) ;
}