Changeset View
Changeset View
Standalone View
Standalone View
src/validation.cpp
Show All 40 Lines | |||||
#include <txdb.h> | #include <txdb.h> | ||||
#include <txmempool.h> | #include <txmempool.h> | ||||
#include <ui_interface.h> | #include <ui_interface.h> | ||||
#include <undo.h> | #include <undo.h> | ||||
#include <util/moneystr.h> | #include <util/moneystr.h> | ||||
#include <util/strencodings.h> | #include <util/strencodings.h> | ||||
#include <util/system.h> | #include <util/system.h> | ||||
#include <util/translation.h> | #include <util/translation.h> | ||||
#include <util/validation.h> | |||||
#include <validationinterface.h> | #include <validationinterface.h> | ||||
#include <warnings.h> | #include <warnings.h> | ||||
#include <boost/algorithm/string/replace.hpp> | #include <boost/algorithm/string/replace.hpp> | ||||
#include <boost/thread.hpp> // boost::this_thread::interruption_point() (mingw) | #include <boost/thread.hpp> // boost::this_thread::interruption_point() (mingw) | ||||
#include <string> | #include <string> | ||||
#include <thread> | #include <thread> | ||||
▲ Show 20 Lines • Show All 392 Lines • ▼ Show 20 Lines | for (const CTxIn &txin : tx.vin) { | ||||
return state.Invalid(TxValidationResult::TX_PREMATURE_SPEND, | return state.Invalid(TxValidationResult::TX_PREMATURE_SPEND, | ||||
"non-BIP68-final"); | "non-BIP68-final"); | ||||
} | } | ||||
Amount nFees = Amount::zero(); | Amount nFees = Amount::zero(); | ||||
if (!Consensus::CheckTxInputs(tx, state, view, GetSpendHeight(view), | if (!Consensus::CheckTxInputs(tx, state, view, GetSpendHeight(view), | ||||
nFees)) { | nFees)) { | ||||
return error("%s: Consensus::CheckTxInputs: %s, %s", __func__, | return error("%s: Consensus::CheckTxInputs: %s, %s", __func__, | ||||
tx.GetId().ToString(), FormatStateMessage(state)); | tx.GetId().ToString(), state.ToString()); | ||||
} | } | ||||
const uint32_t nextBlockScriptVerifyFlags = | const uint32_t nextBlockScriptVerifyFlags = | ||||
GetNextBlockScriptFlags(consensusParams, ::ChainActive().Tip()); | GetNextBlockScriptFlags(consensusParams, ::ChainActive().Tip()); | ||||
// Check for non-standard pay-to-script-hash in inputs | // Check for non-standard pay-to-script-hash in inputs | ||||
if (fRequireStandard && | if (fRequireStandard && | ||||
!AreInputsStandard(tx, view, nextBlockScriptVerifyFlags)) { | !AreInputsStandard(tx, view, nextBlockScriptVerifyFlags)) { | ||||
▲ Show 20 Lines • Show All 98 Lines • ▼ Show 20 Lines | for (const CTxIn &txin : tx.vin) { | ||||
if (!CheckInputsFromMempoolAndCache(tx, state, view, pool, | if (!CheckInputsFromMempoolAndCache(tx, state, view, pool, | ||||
nextBlockScriptVerifyFlags, true, | nextBlockScriptVerifyFlags, true, | ||||
txdata, nSigChecksConsensus)) { | txdata, nSigChecksConsensus)) { | ||||
// This can occur under some circumstances, if the node receives an | // This can occur under some circumstances, if the node receives an | ||||
// unrequested tx which is invalid due to new consensus rules not | // unrequested tx which is invalid due to new consensus rules not | ||||
// being activated yet (during IBD). | // being activated yet (during IBD). | ||||
return error("%s: BUG! PLEASE REPORT THIS! CheckInputs failed " | return error("%s: BUG! PLEASE REPORT THIS! CheckInputs failed " | ||||
"against next-block but not STANDARD flags %s, %s", | "against next-block but not STANDARD flags %s, %s", | ||||
__func__, txid.ToString(), FormatStateMessage(state)); | __func__, txid.ToString(), state.ToString()); | ||||
} | } | ||||
if (nSigChecksStandard != nSigChecksConsensus) { | if (nSigChecksStandard != nSigChecksConsensus) { | ||||
// We can't accept this transaction as we've used the standard count | // We can't accept this transaction as we've used the standard count | ||||
// for the mempool/mining, but the consensus count will be enforced | // for the mempool/mining, but the consensus count will be enforced | ||||
// in validation (we don't want to produce bad block templates). | // in validation (we don't want to produce bad block templates). | ||||
return error( | return error( | ||||
"%s: BUG! PLEASE REPORT THIS! SigChecks count differed between " | "%s: BUG! PLEASE REPORT THIS! SigChecks count differed between " | ||||
▲ Show 20 Lines • Show All 906 Lines • ▼ Show 20 Lines | if (!CheckBlock(block, state, consensusParams, | ||||
if (state.GetResult() == BlockValidationResult::BLOCK_MUTATED) { | if (state.GetResult() == BlockValidationResult::BLOCK_MUTATED) { | ||||
// We don't write down blocks to disk if they may have been | // We don't write down blocks to disk if they may have been | ||||
// corrupted, so this should be impossible unless we're having | // corrupted, so this should be impossible unless we're having | ||||
// hardware problems. | // hardware problems. | ||||
return AbortNode(state, "Corrupt block found indicating potential " | return AbortNode(state, "Corrupt block found indicating potential " | ||||
"hardware failure; shutting down"); | "hardware failure; shutting down"); | ||||
} | } | ||||
return error("%s: Consensus::CheckBlock: %s", __func__, | return error("%s: Consensus::CheckBlock: %s", __func__, | ||||
FormatStateMessage(state)); | state.ToString()); | ||||
} | } | ||||
// Verify that the view's current state corresponds to the previous block | // Verify that the view's current state corresponds to the previous block | ||||
BlockHash hashPrevBlock = | BlockHash hashPrevBlock = | ||||
pindex->pprev == nullptr ? BlockHash() : pindex->pprev->GetBlockHash(); | pindex->pprev == nullptr ? BlockHash() : pindex->pprev->GetBlockHash(); | ||||
assert(hashPrevBlock == view.GetBestBlock()); | assert(hashPrevBlock == view.GetBestBlock()); | ||||
// Special case for the genesis block, skipping connection of its | // Special case for the genesis block, skipping connection of its | ||||
▲ Show 20 Lines • Show All 232 Lines • ▼ Show 20 Lines | for (const auto &ptx : block.vtx) { | ||||
txfee)) { | txfee)) { | ||||
// Any transaction validation failure in ConnectBlock is a block | // Any transaction validation failure in ConnectBlock is a block | ||||
// consensus failure. | // consensus failure. | ||||
state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, | state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, | ||||
tx_state.GetRejectReason(), | tx_state.GetRejectReason(), | ||||
tx_state.GetDebugMessage()); | tx_state.GetDebugMessage()); | ||||
return error("%s: Consensus::CheckTxInputs: %s, %s", __func__, | return error("%s: Consensus::CheckTxInputs: %s, %s", __func__, | ||||
tx.GetId().ToString(), FormatStateMessage(state)); | tx.GetId().ToString(), state.ToString()); | ||||
} | } | ||||
nFees += txfee; | nFees += txfee; | ||||
} | } | ||||
if (!MoneyRange(nFees)) { | if (!MoneyRange(nFees)) { | ||||
LogPrintf("ERROR: %s: accumulated fee in the block out of range.\n", | LogPrintf("ERROR: %s: accumulated fee in the block out of range.\n", | ||||
__func__); | __func__); | ||||
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, | return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, | ||||
▲ Show 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | for (const auto &ptx : block.vtx) { | ||||
nSigChecksRet, nSigChecksTxLimiters[txIndex], | nSigChecksRet, nSigChecksTxLimiters[txIndex], | ||||
&nSigChecksBlockLimiter, &vChecks)) { | &nSigChecksBlockLimiter, &vChecks)) { | ||||
// Any transaction validation failure in ConnectBlock is a block | // Any transaction validation failure in ConnectBlock is a block | ||||
// consensus failure | // consensus failure | ||||
state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, | state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, | ||||
tx_state.GetRejectReason(), | tx_state.GetRejectReason(), | ||||
tx_state.GetDebugMessage()); | tx_state.GetDebugMessage()); | ||||
return error("ConnectBlock(): CheckInputs on %s failed with %s", | return error("ConnectBlock(): CheckInputs on %s failed with %s", | ||||
tx.GetId().ToString(), FormatStateMessage(state)); | tx.GetId().ToString(), state.ToString()); | ||||
} | } | ||||
control.Add(vChecks); | control.Add(vChecks); | ||||
// Note: this must execute in the same iteration as CheckTxInputs (not | // Note: this must execute in the same iteration as CheckTxInputs (not | ||||
// in a separate loop) in order to detect double spends. However, | // in a separate loop) in order to detect double spends. However, | ||||
// this does not prevent double-spending by duplicated transaction | // this does not prevent double-spending by duplicated transaction | ||||
// inputs in the same transaction (cf. CVE-2018-17144) -- that check is | // inputs in the same transaction (cf. CVE-2018-17144) -- that check is | ||||
▲ Show 20 Lines • Show All 250 Lines • ▼ Show 20 Lines | bool CChainState::FlushStateToDisk(const CChainParams &chainparams, | ||||
return true; | return true; | ||||
} | } | ||||
void CChainState::ForceFlushStateToDisk() { | void CChainState::ForceFlushStateToDisk() { | ||||
BlockValidationState state; | BlockValidationState state; | ||||
const CChainParams &chainparams = Params(); | const CChainParams &chainparams = Params(); | ||||
if (!this->FlushStateToDisk(chainparams, state, FlushStateMode::ALWAYS)) { | if (!this->FlushStateToDisk(chainparams, state, FlushStateMode::ALWAYS)) { | ||||
LogPrintf("%s: failed to flush state (%s)\n", __func__, | LogPrintf("%s: failed to flush state (%s)\n", __func__, | ||||
FormatStateMessage(state)); | state.ToString()); | ||||
} | } | ||||
} | } | ||||
void CChainState::PruneAndFlush() { | void CChainState::PruneAndFlush() { | ||||
BlockValidationState state; | BlockValidationState state; | ||||
fCheckForPruning = true; | fCheckForPruning = true; | ||||
const CChainParams &chainparams = Params(); | const CChainParams &chainparams = Params(); | ||||
if (!this->FlushStateToDisk(chainparams, state, FlushStateMode::NONE)) { | if (!this->FlushStateToDisk(chainparams, state, FlushStateMode::NONE)) { | ||||
LogPrintf("%s: failed to flush state (%s)\n", __func__, | LogPrintf("%s: failed to flush state (%s)\n", __func__, | ||||
FormatStateMessage(state)); | state.ToString()); | ||||
} | } | ||||
} | } | ||||
/** Check warning conditions and do some notifications on new chain tip set. */ | /** Check warning conditions and do some notifications on new chain tip set. */ | ||||
static void UpdateTip(const CChainParams ¶ms, CBlockIndex *pindexNew) | static void UpdateTip(const CChainParams ¶ms, CBlockIndex *pindexNew) | ||||
EXCLUSIVE_LOCKS_REQUIRED(::cs_main) { | EXCLUSIVE_LOCKS_REQUIRED(::cs_main) { | ||||
// New best block | // New best block | ||||
g_mempool.AddTransactionsUpdated(1); | g_mempool.AddTransactionsUpdated(1); | ||||
▲ Show 20 Lines • Show All 303 Lines • ▼ Show 20 Lines | LogPrint(BCLog::BENCH, " - Load block from disk: %.2fms [%.2fs]\n", | ||||
GetMainSignals().BlockChecked(blockConnecting, state); | GetMainSignals().BlockChecked(blockConnecting, state); | ||||
if (!rv) { | if (!rv) { | ||||
if (state.IsInvalid()) { | if (state.IsInvalid()) { | ||||
InvalidBlockFound(pindexNew, state); | InvalidBlockFound(pindexNew, state); | ||||
} | } | ||||
return error("%s: ConnectBlock %s failed, %s", __func__, | return error("%s: ConnectBlock %s failed, %s", __func__, | ||||
pindexNew->GetBlockHash().ToString(), | pindexNew->GetBlockHash().ToString(), | ||||
FormatStateMessage(state)); | state.ToString()); | ||||
} | } | ||||
// Update the finalized block. | // Update the finalized block. | ||||
const CBlockIndex *pindexToFinalize = | const CBlockIndex *pindexToFinalize = | ||||
FindBlockToFinalize(config, pindexNew); | FindBlockToFinalize(config, pindexNew); | ||||
if (pindexToFinalize && | if (pindexToFinalize && | ||||
!MarkBlockAsFinal(config, state, pindexToFinalize)) { | !MarkBlockAsFinal(config, state, pindexToFinalize)) { | ||||
return error("ConnectTip(): MarkBlockAsFinal %s failed (%s)", | return error("ConnectTip(): MarkBlockAsFinal %s failed (%s)", | ||||
pindexNew->GetBlockHash().ToString(), | pindexNew->GetBlockHash().ToString(), | ||||
FormatStateMessage(state)); | state.ToString()); | ||||
} | } | ||||
nTime3 = GetTimeMicros(); | nTime3 = GetTimeMicros(); | ||||
nTimeConnectTotal += nTime3 - nTime2; | nTimeConnectTotal += nTime3 - nTime2; | ||||
LogPrint(BCLog::BENCH, | LogPrint(BCLog::BENCH, | ||||
" - Connect total: %.2fms [%.2fs (%.2fms/blk)]\n", | " - Connect total: %.2fms [%.2fs (%.2fms/blk)]\n", | ||||
(nTime3 - nTime2) * MILLI, nTimeConnectTotal * MICRO, | (nTime3 - nTime2) * MILLI, nTimeConnectTotal * MICRO, | ||||
nTimeConnectTotal * MILLI / nBlocksTotal); | nTimeConnectTotal * MILLI / nBlocksTotal); | ||||
▲ Show 20 Lines • Show All 1,463 Lines • ▼ Show 20 Lines | if (hash != chainparams.GetConsensus().hashGenesisBlock) { | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
if (!CheckBlockHeader(block, state, chainparams.GetConsensus(), | if (!CheckBlockHeader(block, state, chainparams.GetConsensus(), | ||||
BlockValidationOptions(config))) { | BlockValidationOptions(config))) { | ||||
return error("%s: Consensus::CheckBlockHeader: %s, %s", __func__, | return error("%s: Consensus::CheckBlockHeader: %s, %s", __func__, | ||||
hash.ToString(), FormatStateMessage(state)); | hash.ToString(), state.ToString()); | ||||
} | } | ||||
// Get prev block index | // Get prev block index | ||||
BlockMap::iterator mi = m_block_index.find(block.hashPrevBlock); | BlockMap::iterator mi = m_block_index.find(block.hashPrevBlock); | ||||
if (mi == m_block_index.end()) { | if (mi == m_block_index.end()) { | ||||
LogPrintf("ERROR: %s: prev block not found\n", __func__); | LogPrintf("ERROR: %s: prev block not found\n", __func__); | ||||
return state.Invalid(BlockValidationResult::BLOCK_MISSING_PREV, | return state.Invalid(BlockValidationResult::BLOCK_MISSING_PREV, | ||||
"prev-blk-not-found"); | "prev-blk-not-found"); | ||||
} | } | ||||
CBlockIndex *pindexPrev = (*mi).second; | CBlockIndex *pindexPrev = (*mi).second; | ||||
assert(pindexPrev); | assert(pindexPrev); | ||||
if (pindexPrev->nStatus.isInvalid()) { | if (pindexPrev->nStatus.isInvalid()) { | ||||
LogPrintf("ERROR: %s: prev block invalid\n", __func__); | LogPrintf("ERROR: %s: prev block invalid\n", __func__); | ||||
return state.Invalid(BlockValidationResult::BLOCK_INVALID_PREV, | return state.Invalid(BlockValidationResult::BLOCK_INVALID_PREV, | ||||
"bad-prevblk"); | "bad-prevblk"); | ||||
} | } | ||||
if (!ContextualCheckBlockHeader(chainparams, block, state, pindexPrev, | if (!ContextualCheckBlockHeader(chainparams, block, state, pindexPrev, | ||||
GetAdjustedTime())) { | GetAdjustedTime())) { | ||||
return error("%s: Consensus::ContextualCheckBlockHeader: %s, %s", | return error("%s: Consensus::ContextualCheckBlockHeader: %s, %s", | ||||
__func__, hash.ToString(), FormatStateMessage(state)); | __func__, hash.ToString(), state.ToString()); | ||||
} | } | ||||
/* Determine if this block descends from any block which has been found | /* Determine if this block descends from any block which has been found | ||||
* invalid (m_failed_blocks), then mark pindexPrev and any blocks | * invalid (m_failed_blocks), then mark pindexPrev and any blocks | ||||
* between them as failed. For example: | * between them as failed. For example: | ||||
* | * | ||||
* D3 | * D3 | ||||
* / | * / | ||||
▲ Show 20 Lines • Show All 224 Lines • ▼ Show 20 Lines | if (!CheckBlock(block, state, consensusParams, | ||||
BlockValidationOptions(config)) || | BlockValidationOptions(config)) || | ||||
!ContextualCheckBlock(block, state, consensusParams, pindex->pprev)) { | !ContextualCheckBlock(block, state, consensusParams, pindex->pprev)) { | ||||
if (state.IsInvalid() && | if (state.IsInvalid() && | ||||
state.GetResult() != BlockValidationResult::BLOCK_MUTATED) { | state.GetResult() != BlockValidationResult::BLOCK_MUTATED) { | ||||
pindex->nStatus = pindex->nStatus.withFailed(); | pindex->nStatus = pindex->nStatus.withFailed(); | ||||
setDirtyBlockIndex.insert(pindex); | setDirtyBlockIndex.insert(pindex); | ||||
} | } | ||||
return error("%s: %s (block %s)", __func__, FormatStateMessage(state), | return error("%s: %s (block %s)", __func__, state.ToString(), | ||||
block.GetHash().ToString()); | block.GetHash().ToString()); | ||||
} | } | ||||
// If connecting the new block would require rewinding more than one block | // If connecting the new block would require rewinding more than one block | ||||
// from the active chain (i.e., a "deep reorg"), then mark the new block as | // from the active chain (i.e., a "deep reorg"), then mark the new block as | ||||
// parked. If it has enough work then it will be automatically unparked | // parked. If it has enough work then it will be automatically unparked | ||||
// later, during FindMostWorkChain. We mark the block as parked at the very | // later, during FindMostWorkChain. We mark the block as parked at the very | ||||
// last minute so we can make sure everything is ready to be reorged if | // last minute so we can make sure everything is ready to be reorged if | ||||
▲ Show 20 Lines • Show All 67 Lines • ▼ Show 20 Lines | AssertLockNotHeld(cs_main); | ||||
// Store to disk | // Store to disk | ||||
ret = ::ChainstateActive().AcceptBlock( | ret = ::ChainstateActive().AcceptBlock( | ||||
config, pblock, state, fForceProcessing, nullptr, fNewBlock); | config, pblock, state, fForceProcessing, nullptr, fNewBlock); | ||||
} | } | ||||
if (!ret) { | if (!ret) { | ||||
GetMainSignals().BlockChecked(*pblock, state); | GetMainSignals().BlockChecked(*pblock, state); | ||||
return error("%s: AcceptBlock FAILED (%s)", __func__, | return error("%s: AcceptBlock FAILED (%s)", __func__, | ||||
FormatStateMessage(state)); | state.ToString()); | ||||
} | } | ||||
} | } | ||||
NotifyHeaderTip(); | NotifyHeaderTip(); | ||||
// Only used to report errors, not invalidity - ignore it | // Only used to report errors, not invalidity - ignore it | ||||
BlockValidationState state; | BlockValidationState state; | ||||
if (!::ChainstateActive().ActivateBestChain(config, state, pblock)) { | if (!::ChainstateActive().ActivateBestChain(config, state, pblock)) { | ||||
return error("%s: ActivateBestChain failed (%s)", __func__, | return error("%s: ActivateBestChain failed (%s)", __func__, | ||||
FormatStateMessage(state)); | state.ToString()); | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
bool TestBlockValidity(BlockValidationState &state, const CChainParams ¶ms, | bool TestBlockValidity(BlockValidationState &state, const CChainParams ¶ms, | ||||
const CBlock &block, CBlockIndex *pindexPrev, | const CBlock &block, CBlockIndex *pindexPrev, | ||||
BlockValidationOptions validationOptions) { | BlockValidationOptions validationOptions) { | ||||
AssertLockHeld(cs_main); | AssertLockHeld(cs_main); | ||||
assert(pindexPrev && pindexPrev == ::ChainActive().Tip()); | assert(pindexPrev && pindexPrev == ::ChainActive().Tip()); | ||||
CCoinsViewCache viewNew(&::ChainstateActive().CoinsTip()); | CCoinsViewCache viewNew(&::ChainstateActive().CoinsTip()); | ||||
BlockHash block_hash(block.GetHash()); | BlockHash block_hash(block.GetHash()); | ||||
CBlockIndex indexDummy(block); | CBlockIndex indexDummy(block); | ||||
indexDummy.pprev = pindexPrev; | indexDummy.pprev = pindexPrev; | ||||
indexDummy.nHeight = pindexPrev->nHeight + 1; | indexDummy.nHeight = pindexPrev->nHeight + 1; | ||||
indexDummy.phashBlock = &block_hash; | indexDummy.phashBlock = &block_hash; | ||||
// NOTE: CheckBlockHeader is called by CheckBlock | // NOTE: CheckBlockHeader is called by CheckBlock | ||||
if (!ContextualCheckBlockHeader(params, block, state, pindexPrev, | if (!ContextualCheckBlockHeader(params, block, state, pindexPrev, | ||||
GetAdjustedTime())) { | GetAdjustedTime())) { | ||||
return error("%s: Consensus::ContextualCheckBlockHeader: %s", __func__, | return error("%s: Consensus::ContextualCheckBlockHeader: %s", __func__, | ||||
FormatStateMessage(state)); | state.ToString()); | ||||
} | } | ||||
if (!CheckBlock(block, state, params.GetConsensus(), validationOptions)) { | if (!CheckBlock(block, state, params.GetConsensus(), validationOptions)) { | ||||
return error("%s: Consensus::CheckBlock: %s", __func__, | return error("%s: Consensus::CheckBlock: %s", __func__, | ||||
FormatStateMessage(state)); | state.ToString()); | ||||
} | } | ||||
if (!ContextualCheckBlock(block, state, params.GetConsensus(), | if (!ContextualCheckBlock(block, state, params.GetConsensus(), | ||||
pindexPrev)) { | pindexPrev)) { | ||||
return error("%s: Consensus::ContextualCheckBlock: %s", __func__, | return error("%s: Consensus::ContextualCheckBlock: %s", __func__, | ||||
FormatStateMessage(state)); | state.ToString()); | ||||
} | } | ||||
if (!::ChainstateActive().ConnectBlock(block, state, &indexDummy, viewNew, | if (!::ChainstateActive().ConnectBlock(block, state, &indexDummy, viewNew, | ||||
params, validationOptions, true)) { | params, validationOptions, true)) { | ||||
return false; | return false; | ||||
} | } | ||||
assert(state.IsValid()); | assert(state.IsValid()); | ||||
▲ Show 20 Lines • Show All 97 Lines • ▼ Show 20 Lines | |||||
/* This function is called from the RPC code for pruneblockchain */ | /* This function is called from the RPC code for pruneblockchain */ | ||||
void PruneBlockFilesManual(int nManualPruneHeight) { | void PruneBlockFilesManual(int nManualPruneHeight) { | ||||
BlockValidationState state; | BlockValidationState state; | ||||
const CChainParams &chainparams = Params(); | const CChainParams &chainparams = Params(); | ||||
if (!::ChainstateActive().FlushStateToDisk( | if (!::ChainstateActive().FlushStateToDisk( | ||||
chainparams, state, FlushStateMode::NONE, nManualPruneHeight)) { | chainparams, state, FlushStateMode::NONE, nManualPruneHeight)) { | ||||
LogPrintf("%s: failed to flush state (%s)\n", __func__, | LogPrintf("%s: failed to flush state (%s)\n", __func__, | ||||
FormatStateMessage(state)); | state.ToString()); | ||||
} | } | ||||
} | } | ||||
/** | /** | ||||
* Prune block and undo files (blk???.dat and undo???.dat) so that the disk | * Prune block and undo files (blk???.dat and undo???.dat) so that the disk | ||||
* space used is less than a user-defined target. The user sets the target (in | * space used is less than a user-defined target. The user sets the target (in | ||||
* MB) on the command line or in config file. This will be run on startup and | * MB) on the command line or in config file. This will be run on startup and | ||||
* whenever new space is allocated in a block or undo file, staying below the | * whenever new space is allocated in a block or undo file, staying below the | ||||
▲ Show 20 Lines • Show All 349 Lines • ▼ Show 20 Lines | for (pindex = ::ChainActive().Tip(); pindex && pindex->pprev; | ||||
pindex->nHeight, pindex->GetBlockHash().ToString()); | pindex->nHeight, pindex->GetBlockHash().ToString()); | ||||
} | } | ||||
// check level 1: verify block validity | // check level 1: verify block validity | ||||
if (nCheckLevel >= 1 && !CheckBlock(block, state, consensusParams, | if (nCheckLevel >= 1 && !CheckBlock(block, state, consensusParams, | ||||
BlockValidationOptions(config))) { | BlockValidationOptions(config))) { | ||||
return error("%s: *** found bad block at %d, hash=%s (%s)\n", | return error("%s: *** found bad block at %d, hash=%s (%s)\n", | ||||
__func__, pindex->nHeight, | __func__, pindex->nHeight, | ||||
pindex->GetBlockHash().ToString(), | pindex->GetBlockHash().ToString(), state.ToString()); | ||||
FormatStateMessage(state)); | |||||
} | } | ||||
// check level 2: verify undo validity | // check level 2: verify undo validity | ||||
if (nCheckLevel >= 2 && pindex) { | if (nCheckLevel >= 2 && pindex) { | ||||
CBlockUndo undo; | CBlockUndo undo; | ||||
if (!pindex->GetUndoPos().IsNull()) { | if (!pindex->GetUndoPos().IsNull()) { | ||||
if (!UndoReadFromDisk(undo, pindex)) { | if (!UndoReadFromDisk(undo, pindex)) { | ||||
return error( | return error( | ||||
▲ Show 20 Lines • Show All 65 Lines • ▼ Show 20 Lines | if (nCheckLevel >= 4) { | ||||
pindex->nHeight, pindex->GetBlockHash().ToString()); | pindex->nHeight, pindex->GetBlockHash().ToString()); | ||||
} | } | ||||
if (!::ChainstateActive().ConnectBlock( | if (!::ChainstateActive().ConnectBlock( | ||||
block, state, pindex, coins, params, | block, state, pindex, coins, params, | ||||
BlockValidationOptions(config))) { | BlockValidationOptions(config))) { | ||||
return error("VerifyDB(): *** found unconnectable block at %d, " | return error("VerifyDB(): *** found unconnectable block at %d, " | ||||
"hash=%s (%s)", | "hash=%s (%s)", | ||||
pindex->nHeight, pindex->GetBlockHash().ToString(), | pindex->nHeight, pindex->GetBlockHash().ToString(), | ||||
FormatStateMessage(state)); | state.ToString()); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
LogPrintf("[DONE].\n"); | LogPrintf("[DONE].\n"); | ||||
LogPrintf("No coin database inconsistencies in last %i blocks (%i " | LogPrintf("No coin database inconsistencies in last %i blocks (%i " | ||||
"transactions)\n", | "transactions)\n", | ||||
block_count, nGoodTransactions); | block_count, nGoodTransactions); | ||||
▲ Show 20 Lines • Show All 933 Lines • Show Last 20 Lines |