Changeset View
Changeset View
Standalone View
Standalone View
src/validation.cpp
Show First 20 Lines • Show All 2,868 Lines • ▼ Show 20 Lines | do { | ||||
bool fInvalidAncestor = false; | bool fInvalidAncestor = false; | ||||
while (pindexTest && !chainActive.Contains(pindexTest)) { | while (pindexTest && !chainActive.Contains(pindexTest)) { | ||||
assert(pindexTest->nChainTx || pindexTest->nHeight == 0); | assert(pindexTest->nChainTx || pindexTest->nHeight == 0); | ||||
// Pruned nodes may have entries in setBlockIndexCandidates for | // Pruned nodes may have entries in setBlockIndexCandidates for | ||||
// which block files have been deleted. Remove those as candidates | // which block files have been deleted. Remove those as candidates | ||||
// for the most work chain if we come across them; we can't switch | // for the most work chain if we come across them; we can't switch | ||||
// to a chain unless we have all the non-active-chain parent blocks. | // to a chain unless we have all the non-active-chain parent blocks. | ||||
bool fFailedChain = pindexTest->nStatus & BLOCK_FAILED_MASK; | bool fInvalidChain = pindexTest->nStatus.isInvalid(); | ||||
bool fMissingData = !pindexTest->nStatus.hasData(); | bool fMissingData = !pindexTest->nStatus.hasData(); | ||||
if (fFailedChain || fMissingData) { | if (fInvalidChain || fMissingData) { | ||||
// Candidate chain is not usable (either invalid or missing | // Candidate chain is not usable (either invalid or missing | ||||
// data) | // data) | ||||
if (fFailedChain && | if (fInvalidChain && | ||||
(pindexBestInvalid == nullptr || | (pindexBestInvalid == nullptr || | ||||
pindexNew->nChainWork > pindexBestInvalid->nChainWork)) { | pindexNew->nChainWork > pindexBestInvalid->nChainWork)) { | ||||
pindexBestInvalid = pindexNew; | pindexBestInvalid = pindexNew; | ||||
} | } | ||||
CBlockIndex *pindexFailed = pindexNew; | CBlockIndex *pindexFailed = pindexNew; | ||||
// Remove the entire chain from the set. | // Remove the entire chain from the set. | ||||
while (pindexTest != pindexFailed) { | while (pindexTest != pindexFailed) { | ||||
if (fFailedChain) { | if (fInvalidChain) { | ||||
pindexFailed->nStatus |= BLOCK_FAILED_CHILD; | pindexFailed->nStatus |= BLOCK_FAILED_CHILD; | ||||
} else if (fMissingData) { | } else if (fMissingData) { | ||||
// If we're missing data, then add back to | // If we're missing data, then add back to | ||||
// mapBlocksUnlinked, so that if the block arrives in | // mapBlocksUnlinked, so that if the block arrives in | ||||
// the future we can try adding to | // the future we can try adding to | ||||
// setBlockIndexCandidates again. | // setBlockIndexCandidates again. | ||||
mapBlocksUnlinked.insert( | mapBlocksUnlinked.insert( | ||||
std::make_pair(pindexFailed->pprev, pindexFailed)); | std::make_pair(pindexFailed->pprev, pindexFailed)); | ||||
▲ Show 20 Lines • Show All 321 Lines • ▼ Show 20 Lines | bool ResetBlockFailureFlags(CBlockIndex *pindex) { | ||||
int nHeight = pindex->nHeight; | int nHeight = pindex->nHeight; | ||||
// Remove the invalidity flag from this block and all its descendants. | // Remove the invalidity flag from this block and all its descendants. | ||||
BlockMap::iterator it = mapBlockIndex.begin(); | BlockMap::iterator it = mapBlockIndex.begin(); | ||||
while (it != mapBlockIndex.end()) { | while (it != mapBlockIndex.end()) { | ||||
if (!it->second->IsValid() && | if (!it->second->IsValid() && | ||||
it->second->GetAncestor(nHeight) == pindex) { | it->second->GetAncestor(nHeight) == pindex) { | ||||
it->second->nStatus &= ~BLOCK_FAILED_MASK; | it->second->nStatus = it->second->nStatus.withClearedFailureFlags(); | ||||
setDirtyBlockIndex.insert(it->second); | setDirtyBlockIndex.insert(it->second); | ||||
if (it->second->IsValid(BlockValidity::TRANSACTIONS) && | if (it->second->IsValid(BlockValidity::TRANSACTIONS) && | ||||
it->second->nChainTx && | it->second->nChainTx && | ||||
setBlockIndexCandidates.value_comp()(chainActive.Tip(), | setBlockIndexCandidates.value_comp()(chainActive.Tip(), | ||||
it->second)) { | it->second)) { | ||||
setBlockIndexCandidates.insert(it->second); | setBlockIndexCandidates.insert(it->second); | ||||
} | } | ||||
if (it->second == pindexBestInvalid) { | if (it->second == pindexBestInvalid) { | ||||
// Reset invalid block marker if it was pointing to one of | // Reset invalid block marker if it was pointing to one of | ||||
// those. | // those. | ||||
pindexBestInvalid = nullptr; | pindexBestInvalid = nullptr; | ||||
} | } | ||||
} | } | ||||
it++; | it++; | ||||
} | } | ||||
// Remove the invalidity flag from all ancestors too. | // Remove the invalidity flag from all ancestors too. | ||||
while (pindex != nullptr) { | while (pindex != nullptr) { | ||||
if (pindex->nStatus & BLOCK_FAILED_MASK) { | if (pindex->nStatus.isInvalid()) { | ||||
pindex->nStatus &= ~BLOCK_FAILED_MASK; | pindex->nStatus = pindex->nStatus.withClearedFailureFlags(); | ||||
setDirtyBlockIndex.insert(pindex); | setDirtyBlockIndex.insert(pindex); | ||||
} | } | ||||
pindex = pindex->pprev; | pindex = pindex->pprev; | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
static CBlockIndex *AddToBlockIndex(const CBlockHeader &block) { | static CBlockIndex *AddToBlockIndex(const CBlockHeader &block) { | ||||
▲ Show 20 Lines • Show All 531 Lines • ▼ Show 20 Lines | static bool AcceptBlockHeader(const Config &config, const CBlockHeader &block, | ||||
CBlockIndex *pindex = nullptr; | CBlockIndex *pindex = nullptr; | ||||
if (hash != chainparams.GetConsensus().hashGenesisBlock) { | if (hash != chainparams.GetConsensus().hashGenesisBlock) { | ||||
if (miSelf != mapBlockIndex.end()) { | if (miSelf != mapBlockIndex.end()) { | ||||
// Block header is already known. | // Block header is already known. | ||||
pindex = miSelf->second; | pindex = miSelf->second; | ||||
if (ppindex) { | if (ppindex) { | ||||
*ppindex = pindex; | *ppindex = pindex; | ||||
} | } | ||||
if (pindex->nStatus & BLOCK_FAILED_MASK) { | if (pindex->nStatus.isInvalid()) { | ||||
return state.Invalid(error("%s: block %s is marked invalid", | return state.Invalid(error("%s: block %s is marked invalid", | ||||
__func__, hash.ToString()), | __func__, hash.ToString()), | ||||
0, "duplicate"); | 0, "duplicate"); | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
if (!CheckBlockHeader(config, block, state)) { | if (!CheckBlockHeader(config, block, state)) { | ||||
return error("%s: Consensus::CheckBlockHeader: %s, %s", __func__, | return error("%s: Consensus::CheckBlockHeader: %s, %s", __func__, | ||||
hash.ToString(), FormatStateMessage(state)); | hash.ToString(), FormatStateMessage(state)); | ||||
} | } | ||||
// Get prev block index | // Get prev block index | ||||
CBlockIndex *pindexPrev = nullptr; | CBlockIndex *pindexPrev = nullptr; | ||||
BlockMap::iterator mi = mapBlockIndex.find(block.hashPrevBlock); | BlockMap::iterator mi = mapBlockIndex.find(block.hashPrevBlock); | ||||
if (mi == mapBlockIndex.end()) { | if (mi == mapBlockIndex.end()) { | ||||
return state.DoS(10, error("%s: prev block not found", __func__), 0, | return state.DoS(10, error("%s: prev block not found", __func__), 0, | ||||
"prev-blk-not-found"); | "prev-blk-not-found"); | ||||
} | } | ||||
pindexPrev = (*mi).second; | pindexPrev = (*mi).second; | ||||
if (pindexPrev->nStatus & BLOCK_FAILED_MASK) { | if (pindexPrev->nStatus.isInvalid()) { | ||||
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(pindexPrev, state, chainparams, | !CheckIndexAgainstCheckpoint(pindexPrev, state, chainparams, | ||||
hash)) { | hash)) { | ||||
▲ Show 20 Lines • Show All 544 Lines • ▼ Show 20 Lines | for (const std::pair<int, CBlockIndex *> &item : vSortedByHeight) { | ||||
} else { | } else { | ||||
pindex->nChainTx = pindex->nTx; | pindex->nChainTx = pindex->nTx; | ||||
} | } | ||||
} | } | ||||
if (pindex->IsValid(BlockValidity::TRANSACTIONS) && | if (pindex->IsValid(BlockValidity::TRANSACTIONS) && | ||||
(pindex->nChainTx || pindex->pprev == nullptr)) { | (pindex->nChainTx || pindex->pprev == nullptr)) { | ||||
setBlockIndexCandidates.insert(pindex); | setBlockIndexCandidates.insert(pindex); | ||||
} | } | ||||
if (pindex->nStatus & BLOCK_FAILED_MASK && | if (pindex->nStatus.isInvalid() && | ||||
(!pindexBestInvalid || | (!pindexBestInvalid || | ||||
pindex->nChainWork > pindexBestInvalid->nChainWork)) { | pindex->nChainWork > pindexBestInvalid->nChainWork)) { | ||||
pindexBestInvalid = pindex; | pindexBestInvalid = pindex; | ||||
} | } | ||||
if (pindex->pprev) { | if (pindex->pprev) { | ||||
pindex->BuildSkip(); | pindex->BuildSkip(); | ||||
} | } | ||||
if (pindex->IsValid(BlockValidity::TREE) && | if (pindex->IsValid(BlockValidity::TREE) && | ||||
▲ Show 20 Lines • Show All 802 Lines • ▼ Show 20 Lines | while (pindex != nullptr) { | ||||
} | } | ||||
if ((pindex->nStatus & BLOCK_VALID_MASK) >= BLOCK_VALID_SCRIPTS) { | if ((pindex->nStatus & BLOCK_VALID_MASK) >= BLOCK_VALID_SCRIPTS) { | ||||
// SCRIPTS valid implies all parents are SCRIPTS valid | // SCRIPTS valid implies all parents are SCRIPTS valid | ||||
assert(pindexFirstNotScriptsValid == nullptr); | assert(pindexFirstNotScriptsValid == nullptr); | ||||
} | } | ||||
if (pindexFirstInvalid == nullptr) { | if (pindexFirstInvalid == nullptr) { | ||||
// Checks for not-invalid blocks. | // Checks for not-invalid blocks. | ||||
// The failed mask cannot be set for blocks without invalid parents. | // The failed mask cannot be set for blocks without invalid parents. | ||||
assert((pindex->nStatus & BLOCK_FAILED_MASK) == 0); | assert(!pindex->nStatus.isInvalid()); | ||||
} | } | ||||
if (!CBlockIndexWorkComparator()(pindex, chainActive.Tip()) && | if (!CBlockIndexWorkComparator()(pindex, chainActive.Tip()) && | ||||
pindexFirstNeverProcessed == nullptr) { | pindexFirstNeverProcessed == nullptr) { | ||||
if (pindexFirstInvalid == nullptr) { | if (pindexFirstInvalid == nullptr) { | ||||
// If this block sorts at least as good as the current tip and | // If this block sorts at least as good as the current tip and | ||||
// is valid and we have all data for its parents, it must be in | // is valid and we have all data for its parents, it must be in | ||||
// setBlockIndexCandidates. chainActive.Tip() must also be there | // setBlockIndexCandidates. chainActive.Tip() must also be there | ||||
// even if some data has been pruned. | // even if some data has been pruned. | ||||
▲ Show 20 Lines • Show All 322 Lines • Show Last 20 Lines |