Changeset View
Changeset View
Standalone View
Standalone View
src/validation.cpp
Show First 20 Lines • Show All 1,877 Lines • ▼ Show 20 Lines | |||||
/** | /** | ||||
* Apply the effects of this block (with given index) on the UTXO set | * Apply the effects of this block (with given index) on the UTXO set | ||||
* represented by coins. Validity checks that depend on the UTXO set are also | * represented by coins. Validity checks that depend on the UTXO set are also | ||||
* done; ConnectBlock() can fail if those validity checks fail (among other | * done; ConnectBlock() can fail if those validity checks fail (among other | ||||
* reasons). | * reasons). | ||||
*/ | */ | ||||
static bool ConnectBlock(const Config &config, const CBlock &block, | static bool ConnectBlock(const Config &config, const CBlock &block, | ||||
CValidationState &state, CBlockIndex *pindex, | CValidationState &state, CBlockIndex *pindex, | ||||
CCoinsViewCache &view, const CChainParams &chainparams, | CCoinsViewCache &view, bool fJustCheck = false) { | ||||
bool fJustCheck = false) { | |||||
AssertLockHeld(cs_main); | AssertLockHeld(cs_main); | ||||
int64_t nTimeStart = GetTimeMicros(); | int64_t nTimeStart = GetTimeMicros(); | ||||
// 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(config, block, state, !fJustCheck, !fJustCheck)) { | if (!CheckBlock(config, block, state, !fJustCheck, !fJustCheck)) { | ||||
return error("%s: Consensus::CheckBlock: %s", __func__, | return error("%s: Consensus::CheckBlock: %s", __func__, | ||||
FormatStateMessage(state)); | FormatStateMessage(state)); | ||||
} | } | ||||
// Verify that the view's current state corresponds to the previous block | // Verify that the view's current state corresponds to the previous block | ||||
uint256 hashPrevBlock = | uint256 hashPrevBlock = | ||||
pindex->pprev == nullptr ? uint256() : pindex->pprev->GetBlockHash(); | pindex->pprev == nullptr ? uint256() : 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 | ||||
// transactions (its coinbase is unspendable) | // transactions (its coinbase is unspendable) | ||||
if (block.GetHash() == chainparams.GetConsensus().hashGenesisBlock) { | const Consensus::Params &consensusParams = | ||||
config.GetChainParams().GetConsensus(); | |||||
if (block.GetHash() == consensusParams.hashGenesisBlock) { | |||||
if (!fJustCheck) { | if (!fJustCheck) { | ||||
view.SetBestBlock(pindex->GetBlockHash()); | view.SetBestBlock(pindex->GetBlockHash()); | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
bool fScriptChecks = true; | bool fScriptChecks = true; | ||||
if (!hashAssumeValid.IsNull()) { | if (!hashAssumeValid.IsNull()) { | ||||
// We've been configured with the hash of a block which has been | // We've been configured with the hash of a block which has been | ||||
// externally verified to have a valid history. A suitable default value | // externally verified to have a valid history. A suitable default value | ||||
// is included with the software and updated from time to time. Because | // is included with the software and updated from time to time. Because | ||||
// validity relative to a piece of software is an objective fact these | // validity relative to a piece of software is an objective fact these | ||||
// defaults can be easily reviewed. This setting doesn't force the | // defaults can be easily reviewed. This setting doesn't force the | ||||
// selection of any particular chain but makes validating some faster by | // selection of any particular chain but makes validating some faster by | ||||
// effectively caching the result of part of the verification. | // effectively caching the result of part of the verification. | ||||
BlockMap::const_iterator it = mapBlockIndex.find(hashAssumeValid); | BlockMap::const_iterator it = mapBlockIndex.find(hashAssumeValid); | ||||
if (it != mapBlockIndex.end()) { | if (it != mapBlockIndex.end()) { | ||||
if (it->second->GetAncestor(pindex->nHeight) == pindex && | if (it->second->GetAncestor(pindex->nHeight) == pindex && | ||||
pindexBestHeader->GetAncestor(pindex->nHeight) == pindex && | pindexBestHeader->GetAncestor(pindex->nHeight) == pindex && | ||||
pindexBestHeader->nChainWork >= | pindexBestHeader->nChainWork >= | ||||
UintToArith256( | UintToArith256( | ||||
chainparams.GetConsensus().nMinimumChainWork)) { | consensusParams.nMinimumChainWork)) { | ||||
// This block is a member of the assumed verified chain and an | // This block is a member of the assumed verified chain and an | ||||
// ancestor of the best header. The equivalent time check | // ancestor of the best header. The equivalent time check | ||||
// discourages hashpower from extorting the network via DOS | // discourages hashpower from extorting the network via DOS | ||||
// attack into accepting an invalid block through telling users | // attack into accepting an invalid block through telling users | ||||
// they must manually set assumevalid. Requiring a software | // they must manually set assumevalid. Requiring a software | ||||
// change or burying the invalid block, regardless of the | // change or burying the invalid block, regardless of the | ||||
// setting, makes it hard to hide the implication of the demand. | // setting, makes it hard to hide the implication of the demand. | ||||
// This also avoids having release candidates that are hardly | // This also avoids having release candidates that are hardly | ||||
// doing any signature verification at all in testing without | // doing any signature verification at all in testing without | ||||
// having to artificially set the default assumed verified block | // having to artificially set the default assumed verified block | ||||
// further back. The test against nMinimumChainWork prevents the | // further back. The test against nMinimumChainWork prevents the | ||||
// skipping when denied access to any chain at least as good as | // skipping when denied access to any chain at least as good as | ||||
// the expected chain. | // the expected chain. | ||||
fScriptChecks = | fScriptChecks = | ||||
(GetBlockProofEquivalentTime( | (GetBlockProofEquivalentTime( | ||||
*pindexBestHeader, *pindex, *pindexBestHeader, | *pindexBestHeader, *pindex, *pindexBestHeader, | ||||
chainparams.GetConsensus()) <= 60 * 60 * 24 * 7 * 2); | consensusParams) <= 60 * 60 * 24 * 7 * 2); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
int64_t nTime1 = GetTimeMicros(); | int64_t nTime1 = GetTimeMicros(); | ||||
nTimeCheck += nTime1 - nTimeStart; | nTimeCheck += nTime1 - nTimeStart; | ||||
LogPrint(BCLog::BENCH, " - Sanity checks: %.2fms [%.2fs]\n", | LogPrint(BCLog::BENCH, " - Sanity checks: %.2fms [%.2fs]\n", | ||||
0.001 * (nTime1 - nTimeStart), nTimeCheck * 0.000001); | 0.001 * (nTime1 - nTimeStart), nTimeCheck * 0.000001); | ||||
Show All 28 Lines | static bool ConnectBlock(const Config &config, const CBlock &block, | ||||
// coinbase pairs, not possible to create overwriting txs. But by the time | // coinbase pairs, not possible to create overwriting txs. But by the time | ||||
// BIP34 activated, in each of the existing pairs the duplicate coinbase had | // BIP34 activated, in each of the existing pairs the duplicate coinbase had | ||||
// overwritten the first before the first had been spent. Since those | // overwritten the first before the first had been spent. Since those | ||||
// coinbases are sufficiently buried its no longer possible to create | // coinbases are sufficiently buried its no longer possible to create | ||||
// further duplicate transactions descending from the known pairs either. If | // further duplicate transactions descending from the known pairs either. If | ||||
// we're on the known chain at height greater than where BIP34 activated, we | // we're on the known chain at height greater than where BIP34 activated, we | ||||
// can save the db accesses needed for the BIP30 check. | // can save the db accesses needed for the BIP30 check. | ||||
CBlockIndex *pindexBIP34height = | CBlockIndex *pindexBIP34height = | ||||
pindex->pprev->GetAncestor(chainparams.GetConsensus().BIP34Height); | pindex->pprev->GetAncestor(consensusParams.BIP34Height); | ||||
// Only continue to enforce if we're below BIP34 activation height or the | // Only continue to enforce if we're below BIP34 activation height or the | ||||
// block hash at that height doesn't correspond. | // block hash at that height doesn't correspond. | ||||
fEnforceBIP30 = fEnforceBIP30 && (!pindexBIP34height || | fEnforceBIP30 = fEnforceBIP30 && (!pindexBIP34height || | ||||
!(pindexBIP34height->GetBlockHash() == | !(pindexBIP34height->GetBlockHash() == | ||||
chainparams.GetConsensus().BIP34Hash)); | consensusParams.BIP34Hash)); | ||||
if (fEnforceBIP30) { | if (fEnforceBIP30) { | ||||
for (const auto &tx : block.vtx) { | for (const auto &tx : block.vtx) { | ||||
for (size_t o = 0; o < tx->vout.size(); o++) { | for (size_t o = 0; o < tx->vout.size(); o++) { | ||||
if (view.HaveCoin(COutPoint(tx->GetId(), o))) { | if (view.HaveCoin(COutPoint(tx->GetId(), o))) { | ||||
return state.DoS( | return state.DoS( | ||||
100, | 100, | ||||
error("ConnectBlock(): tried to overwrite transaction"), | error("ConnectBlock(): tried to overwrite transaction"), | ||||
REJECT_INVALID, "bad-txns-BIP30"); | REJECT_INVALID, "bad-txns-BIP30"); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
} | } | ||||
// Start enforcing BIP68 (sequence locks) using versionbits logic. | // Start enforcing BIP68 (sequence locks) using versionbits logic. | ||||
int nLockTimeFlags = 0; | int nLockTimeFlags = 0; | ||||
if (VersionBitsState(pindex->pprev, chainparams.GetConsensus(), | if (VersionBitsState(pindex->pprev, consensusParams, | ||||
Consensus::DEPLOYMENT_CSV, | Consensus::DEPLOYMENT_CSV, | ||||
versionbitscache) == THRESHOLD_ACTIVE) { | versionbitscache) == THRESHOLD_ACTIVE) { | ||||
nLockTimeFlags |= LOCKTIME_VERIFY_SEQUENCE; | nLockTimeFlags |= LOCKTIME_VERIFY_SEQUENCE; | ||||
} | } | ||||
uint32_t flags = GetBlockScriptFlags(pindex, config); | uint32_t flags = GetBlockScriptFlags(pindex, config); | ||||
int64_t nTime2 = GetTimeMicros(); | int64_t nTime2 = GetTimeMicros(); | ||||
▲ Show 20 Lines • Show All 100 Lines • ▼ Show 20 Lines | LogPrint(BCLog::BENCH, | ||||
" - Connect %u transactions: %.2fms (%.3fms/tx, " | " - Connect %u transactions: %.2fms (%.3fms/tx, " | ||||
"%.3fms/txin) [%.2fs]\n", | "%.3fms/txin) [%.2fs]\n", | ||||
(unsigned)block.vtx.size(), 0.001 * (nTime3 - nTime2), | (unsigned)block.vtx.size(), 0.001 * (nTime3 - nTime2), | ||||
0.001 * (nTime3 - nTime2) / block.vtx.size(), | 0.001 * (nTime3 - nTime2) / block.vtx.size(), | ||||
nInputs <= 1 ? 0 : 0.001 * (nTime3 - nTime2) / (nInputs - 1), | nInputs <= 1 ? 0 : 0.001 * (nTime3 - nTime2) / (nInputs - 1), | ||||
nTimeConnect * 0.000001); | nTimeConnect * 0.000001); | ||||
Amount blockReward = | Amount blockReward = | ||||
nFees + GetBlockSubsidy(pindex->nHeight, chainparams.GetConsensus()); | nFees + GetBlockSubsidy(pindex->nHeight, consensusParams); | ||||
if (block.vtx[0]->GetValueOut() > blockReward) { | if (block.vtx[0]->GetValueOut() > blockReward) { | ||||
return state.DoS(100, error("ConnectBlock(): coinbase pays too much " | return state.DoS(100, error("ConnectBlock(): coinbase pays too much " | ||||
"(actual=%d vs limit=%d)", | "(actual=%d vs limit=%d)", | ||||
block.vtx[0]->GetValueOut(), blockReward), | block.vtx[0]->GetValueOut(), blockReward), | ||||
REJECT_INVALID, "bad-cb-amount"); | REJECT_INVALID, "bad-cb-amount"); | ||||
} | } | ||||
if (!control.Wait()) { | if (!control.Wait()) { | ||||
Show All 20 Lines | if (pindex->GetUndoPos().IsNull() || | ||||
CDiskBlockPos _pos; | CDiskBlockPos _pos; | ||||
if (!FindUndoPos( | if (!FindUndoPos( | ||||
state, pindex->nFile, _pos, | state, pindex->nFile, _pos, | ||||
::GetSerializeSize(blockundo, SER_DISK, CLIENT_VERSION) + | ::GetSerializeSize(blockundo, SER_DISK, CLIENT_VERSION) + | ||||
40)) { | 40)) { | ||||
return error("ConnectBlock(): FindUndoPos failed"); | return error("ConnectBlock(): FindUndoPos failed"); | ||||
} | } | ||||
if (!UndoWriteToDisk(blockundo, _pos, pindex->pprev->GetBlockHash(), | if (!UndoWriteToDisk(blockundo, _pos, pindex->pprev->GetBlockHash(), | ||||
chainparams.DiskMagic())) { | config.GetChainParams().DiskMagic())) { | ||||
return AbortNode(state, "Failed to write undo data"); | return AbortNode(state, "Failed to write undo data"); | ||||
} | } | ||||
// update nUndoPos in block index | // update nUndoPos in block index | ||||
pindex->nUndoPos = _pos.nPos; | pindex->nUndoPos = _pos.nPos; | ||||
pindex->nStatus |= BLOCK_HAVE_UNDO; | pindex->nStatus |= BLOCK_HAVE_UNDO; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 175 Lines • ▼ Show 20 Lines | |||||
void PruneAndFlush() { | void PruneAndFlush() { | ||||
CValidationState state; | CValidationState state; | ||||
fCheckForPruning = true; | fCheckForPruning = true; | ||||
FlushStateToDisk(state, FLUSH_STATE_NONE); | FlushStateToDisk(state, FLUSH_STATE_NONE); | ||||
} | } | ||||
/** Update chainActive and related internal data structures. */ | /** Update chainActive and related internal data structures. */ | ||||
static void UpdateTip(const Config &config, CBlockIndex *pindexNew) { | static void UpdateTip(const Config &config, CBlockIndex *pindexNew) { | ||||
const CChainParams &chainParams = config.GetChainParams(); | const Consensus::Params &consensusParams = | ||||
config.GetChainParams().GetConsensus(); | |||||
chainActive.SetTip(pindexNew); | chainActive.SetTip(pindexNew); | ||||
// New best block | // New best block | ||||
mempool.AddTransactionsUpdated(1); | mempool.AddTransactionsUpdated(1); | ||||
cvBlockChange.notify_all(); | cvBlockChange.notify_all(); | ||||
static bool fWarned = false; | static bool fWarned = false; | ||||
std::vector<std::string> warningMessages; | std::vector<std::string> warningMessages; | ||||
if (!IsInitialBlockDownload()) { | if (!IsInitialBlockDownload()) { | ||||
int nUpgraded = 0; | int nUpgraded = 0; | ||||
const CBlockIndex *pindex = chainActive.Tip(); | const CBlockIndex *pindex = chainActive.Tip(); | ||||
for (int bit = 0; bit < VERSIONBITS_NUM_BITS; bit++) { | for (int bit = 0; bit < VERSIONBITS_NUM_BITS; bit++) { | ||||
WarningBitsConditionChecker checker(bit); | WarningBitsConditionChecker checker(bit); | ||||
ThresholdState state = checker.GetStateFor( | ThresholdState state = checker.GetStateFor( | ||||
pindex, chainParams.GetConsensus(), warningcache[bit]); | pindex, consensusParams, warningcache[bit]); | ||||
if (state == THRESHOLD_ACTIVE || state == THRESHOLD_LOCKED_IN) { | if (state == THRESHOLD_ACTIVE || state == THRESHOLD_LOCKED_IN) { | ||||
if (state == THRESHOLD_ACTIVE) { | if (state == THRESHOLD_ACTIVE) { | ||||
std::string strWarning = | std::string strWarning = | ||||
strprintf(_("Warning: unknown new rules activated " | strprintf(_("Warning: unknown new rules activated " | ||||
"(versionbit %i)"), | "(versionbit %i)"), | ||||
bit); | bit); | ||||
SetMiscWarning(strWarning); | SetMiscWarning(strWarning); | ||||
if (!fWarned) { | if (!fWarned) { | ||||
AlertNotify(strWarning); | AlertNotify(strWarning); | ||||
fWarned = true; | fWarned = true; | ||||
} | } | ||||
} else { | } else { | ||||
warningMessages.push_back( | warningMessages.push_back( | ||||
strprintf("unknown new rules are about to activate " | strprintf("unknown new rules are about to activate " | ||||
"(versionbit %i)", | "(versionbit %i)", | ||||
bit)); | bit)); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
// Check the version of the last 100 blocks to see if we need to | // Check the version of the last 100 blocks to see if we need to | ||||
// upgrade: | // upgrade: | ||||
for (int i = 0; i < 100 && pindex != nullptr; i++) { | for (int i = 0; i < 100 && pindex != nullptr; i++) { | ||||
int32_t nExpectedVersion = | int32_t nExpectedVersion = | ||||
ComputeBlockVersion(pindex->pprev, chainParams.GetConsensus()); | ComputeBlockVersion(pindex->pprev, consensusParams); | ||||
if (pindex->nVersion > VERSIONBITS_LAST_OLD_BLOCK_VERSION && | if (pindex->nVersion > VERSIONBITS_LAST_OLD_BLOCK_VERSION && | ||||
(pindex->nVersion & ~nExpectedVersion) != 0) | (pindex->nVersion & ~nExpectedVersion) != 0) | ||||
++nUpgraded; | ++nUpgraded; | ||||
pindex = pindex->pprev; | pindex = pindex->pprev; | ||||
} | } | ||||
if (nUpgraded > 0) | if (nUpgraded > 0) | ||||
warningMessages.push_back(strprintf( | warningMessages.push_back(strprintf( | ||||
"%d of last 100 blocks have unexpected version", nUpgraded)); | "%d of last 100 blocks have unexpected version", nUpgraded)); | ||||
Show All 14 Lines | LogPrintf( | ||||
"%s: new best=%s height=%d version=0x%08x log2_work=%.8g tx=%lu " | "%s: new best=%s height=%d version=0x%08x log2_work=%.8g tx=%lu " | ||||
"date='%s' progress=%f cache=%.1fMiB(%utxo)", | "date='%s' progress=%f cache=%.1fMiB(%utxo)", | ||||
__func__, chainActive.Tip()->GetBlockHash().ToString(), | __func__, chainActive.Tip()->GetBlockHash().ToString(), | ||||
chainActive.Height(), chainActive.Tip()->nVersion, | chainActive.Height(), chainActive.Tip()->nVersion, | ||||
log(chainActive.Tip()->nChainWork.getdouble()) / log(2.0), | log(chainActive.Tip()->nChainWork.getdouble()) / log(2.0), | ||||
(unsigned long)chainActive.Tip()->nChainTx, | (unsigned long)chainActive.Tip()->nChainTx, | ||||
DateTimeStrFormat("%Y-%m-%d %H:%M:%S", | DateTimeStrFormat("%Y-%m-%d %H:%M:%S", | ||||
chainActive.Tip()->GetBlockTime()), | chainActive.Tip()->GetBlockTime()), | ||||
GuessVerificationProgress(chainParams.TxData(), chainActive.Tip()), | GuessVerificationProgress(config.GetChainParams().TxData(), chainActive.Tip()), | ||||
pcoinsTip->DynamicMemoryUsage() * (1.0 / (1 << 20)), | pcoinsTip->DynamicMemoryUsage() * (1.0 / (1 << 20)), | ||||
pcoinsTip->GetCacheSize()); | pcoinsTip->GetCacheSize()); | ||||
if (!warningMessages.empty()) | if (!warningMessages.empty()) | ||||
LogPrintf(" warning='%s'", | LogPrintf(" warning='%s'", | ||||
boost::algorithm::join(warningMessages, ", ")); | boost::algorithm::join(warningMessages, ", ")); | ||||
LogPrintf("\n"); | LogPrintf("\n"); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 174 Lines • ▼ Show 20 Lines | static bool ConnectTip(const Config &config, CValidationState &state, | ||||
// Apply the block atomically to the chain state. | // Apply the block atomically to the chain state. | ||||
int64_t nTime2 = GetTimeMicros(); | int64_t nTime2 = GetTimeMicros(); | ||||
nTimeReadFromDisk += nTime2 - nTime1; | nTimeReadFromDisk += nTime2 - nTime1; | ||||
int64_t nTime3; | int64_t nTime3; | ||||
LogPrint(BCLog::BENCH, " - Load block from disk: %.2fms [%.2fs]\n", | LogPrint(BCLog::BENCH, " - Load block from disk: %.2fms [%.2fs]\n", | ||||
(nTime2 - nTime1) * 0.001, nTimeReadFromDisk * 0.000001); | (nTime2 - nTime1) * 0.001, nTimeReadFromDisk * 0.000001); | ||||
{ | { | ||||
CCoinsViewCache view(pcoinsTip); | CCoinsViewCache view(pcoinsTip); | ||||
bool rv = ConnectBlock(config, blockConnecting, state, pindexNew, view, | bool rv = ConnectBlock(config, blockConnecting, state, pindexNew, view); | ||||
config.GetChainParams()); | |||||
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("ConnectTip(): ConnectBlock %s failed", | return error("ConnectTip(): ConnectBlock %s failed", | ||||
pindexNew->GetBlockHash().ToString()); | pindexNew->GetBlockHash().ToString()); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 972 Lines • ▼ Show 20 Lines | if (hash != chainparams.GetConsensus().hashGenesisBlock) { | ||||
pindexPrev = (*mi).second; | pindexPrev = (*mi).second; | ||||
if (pindexPrev->nStatus & BLOCK_FAILED_MASK) { | if (pindexPrev->nStatus & BLOCK_FAILED_MASK) { | ||||
return state.DoS(100, error("%s: prev block invalid", __func__), | return state.DoS(100, error("%s: prev block invalid", __func__), | ||||
REJECT_INVALID, "bad-prevblk"); | REJECT_INVALID, "bad-prevblk"); | ||||
} | } | ||||
assert(pindexPrev); | assert(pindexPrev); | ||||
if (fCheckpointsEnabled && | if (fCheckpointsEnabled && !CheckIndexAgainstCheckpoint( | ||||
!CheckIndexAgainstCheckpoint(pindexPrev, state, chainparams, | pindexPrev, state, chainparams, hash)) { | ||||
hash)) { | |||||
return error("%s: CheckIndexAgainstCheckpoint(): %s", __func__, | return error("%s: CheckIndexAgainstCheckpoint(): %s", __func__, | ||||
state.GetRejectReason().c_str()); | state.GetRejectReason().c_str()); | ||||
} | } | ||||
if (!ContextualCheckBlockHeader(config, block, state, pindexPrev, | if (!ContextualCheckBlockHeader(config, 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(), FormatStateMessage(state)); | ||||
▲ Show 20 Lines • Show All 225 Lines • ▼ Show 20 Lines | bool TestBlockValidity(const Config &config, CValidationState &state, | ||||
if (!CheckBlock(config, block, state, fCheckPOW, fCheckMerkleRoot)) { | if (!CheckBlock(config, block, state, fCheckPOW, fCheckMerkleRoot)) { | ||||
return error("%s: Consensus::CheckBlock: %s", __func__, | return error("%s: Consensus::CheckBlock: %s", __func__, | ||||
FormatStateMessage(state)); | FormatStateMessage(state)); | ||||
} | } | ||||
if (!ContextualCheckBlock(config, block, state, pindexPrev)) { | if (!ContextualCheckBlock(config, block, state, pindexPrev)) { | ||||
return error("%s: Consensus::ContextualCheckBlock: %s", __func__, | return error("%s: Consensus::ContextualCheckBlock: %s", __func__, | ||||
FormatStateMessage(state)); | FormatStateMessage(state)); | ||||
} | } | ||||
if (!ConnectBlock(config, block, state, &indexDummy, viewNew, chainparams, | if (!ConnectBlock(config, block, state, &indexDummy, viewNew, true)) { | ||||
true)) { | |||||
return false; | return false; | ||||
} | } | ||||
assert(state.IsValid()); | assert(state.IsValid()); | ||||
return true; | return true; | ||||
} | } | ||||
/** | /** | ||||
▲ Show 20 Lines • Show All 362 Lines • ▼ Show 20 Lines | bool CVerifyDB::VerifyDB(const Config &config, CCoinsView *coinsview, | ||||
if (nCheckDepth > chainActive.Height()) { | if (nCheckDepth > chainActive.Height()) { | ||||
nCheckDepth = chainActive.Height(); | nCheckDepth = chainActive.Height(); | ||||
} | } | ||||
nCheckLevel = std::max(0, std::min(4, nCheckLevel)); | nCheckLevel = std::max(0, std::min(4, nCheckLevel)); | ||||
LogPrintf("Verifying last %i blocks at level %i\n", nCheckDepth, | LogPrintf("Verifying last %i blocks at level %i\n", nCheckDepth, | ||||
nCheckLevel); | nCheckLevel); | ||||
const CChainParams &chainparams = config.GetChainParams(); | |||||
CCoinsViewCache coins(coinsview); | CCoinsViewCache coins(coinsview); | ||||
CBlockIndex *pindexState = chainActive.Tip(); | CBlockIndex *pindexState = chainActive.Tip(); | ||||
CBlockIndex *pindexFailure = nullptr; | CBlockIndex *pindexFailure = nullptr; | ||||
int nGoodTransactions = 0; | int nGoodTransactions = 0; | ||||
CValidationState state; | CValidationState state; | ||||
int reportDone = 0; | int reportDone = 0; | ||||
LogPrintf("[0%%]..."); | LogPrintf("[0%%]..."); | ||||
for (CBlockIndex *pindex = chainActive.Tip(); pindex && pindex->pprev; | for (CBlockIndex *pindex = chainActive.Tip(); pindex && pindex->pprev; | ||||
▲ Show 20 Lines • Show All 102 Lines • ▼ Show 20 Lines | if (nCheckLevel >= 4) { | ||||
(double)nCheckDepth * 50)))); | (double)nCheckDepth * 50)))); | ||||
pindex = chainActive.Next(pindex); | pindex = chainActive.Next(pindex); | ||||
CBlock block; | CBlock block; | ||||
if (!ReadBlockFromDisk(block, pindex, config)) { | if (!ReadBlockFromDisk(block, pindex, config)) { | ||||
return error( | return error( | ||||
"VerifyDB(): *** ReadBlockFromDisk failed at %d, hash=%s", | "VerifyDB(): *** ReadBlockFromDisk failed at %d, hash=%s", | ||||
pindex->nHeight, pindex->GetBlockHash().ToString()); | pindex->nHeight, pindex->GetBlockHash().ToString()); | ||||
} | } | ||||
if (!ConnectBlock(config, block, state, pindex, coins, | if (!ConnectBlock(config, block, state, pindex, coins)) { | ||||
chainparams)) { | |||||
return error( | return error( | ||||
"VerifyDB(): *** found unconnectable block at %d, hash=%s", | "VerifyDB(): *** found unconnectable block at %d, hash=%s", | ||||
pindex->nHeight, pindex->GetBlockHash().ToString()); | pindex->nHeight, pindex->GetBlockHash().ToString()); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
LogPrintf("[DONE].\n"); | LogPrintf("[DONE].\n"); | ||||
▲ Show 20 Lines • Show All 782 Lines • Show Last 20 Lines |