Changeset View
Changeset View
Standalone View
Standalone View
src/validation.cpp
Show First 20 Lines • Show All 2,797 Lines • ▼ Show 20 Lines | do { | ||||
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 fInvalidChain = pindexTest->nStatus.isInvalid(); | bool fInvalidChain = pindexTest->nStatus.isInvalid(); | ||||
bool fParkedChain = pindexTest->nStatus.isOnParkedChain(); | |||||
bool fMissingData = !pindexTest->nStatus.hasData(); | bool fMissingData = !pindexTest->nStatus.hasData(); | ||||
if (fInvalidChain || fMissingData) { | if (fInvalidChain || fParkedChain || fMissingData) { | ||||
// Candidate chain is not usable (either invalid or missing | // Candidate chain is not usable (either invalid or missing | ||||
// data) | // data) | ||||
if (fInvalidChain && | 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 (fInvalidChain) { | if (fInvalidChain || fParkedChain) { | ||||
pindexFailed->nStatus = | pindexFailed->nStatus = | ||||
pindexFailed->nStatus.withFailedParent(); | pindexFailed->nStatus | ||||
.withFailedParent(fInvalidChain) | |||||
.withParkedParent(fParkedChain); | |||||
} 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 2,264 Lines • ▼ Show 20 Lines | static void CheckBlockIndex(const Consensus::Params &consensusParams) { | ||||
// Iterate over the entire block tree, using depth-first search. | // Iterate over the entire block tree, using depth-first search. | ||||
// Along the way, remember whether there are blocks on the path from genesis | // Along the way, remember whether there are blocks on the path from genesis | ||||
// block being explored which are the first to have certain properties. | // block being explored which are the first to have certain properties. | ||||
size_t nNodes = 0; | size_t nNodes = 0; | ||||
int nHeight = 0; | int nHeight = 0; | ||||
// Oldest ancestor of pindex which is invalid. | // Oldest ancestor of pindex which is invalid. | ||||
CBlockIndex *pindexFirstInvalid = nullptr; | CBlockIndex *pindexFirstInvalid = nullptr; | ||||
// Oldest ancestor of pindex which is parked. | |||||
CBlockIndex *pindexFirstParked = nullptr; | |||||
// Oldest ancestor of pindex which does not have data available. | // Oldest ancestor of pindex which does not have data available. | ||||
CBlockIndex *pindexFirstMissing = nullptr; | CBlockIndex *pindexFirstMissing = nullptr; | ||||
// Oldest ancestor of pindex for which nTx == 0. | // Oldest ancestor of pindex for which nTx == 0. | ||||
CBlockIndex *pindexFirstNeverProcessed = nullptr; | CBlockIndex *pindexFirstNeverProcessed = nullptr; | ||||
// Oldest ancestor of pindex which does not have BLOCK_VALID_TREE | // Oldest ancestor of pindex which does not have BLOCK_VALID_TREE | ||||
// (regardless of being valid or not). | // (regardless of being valid or not). | ||||
CBlockIndex *pindexFirstNotTreeValid = nullptr; | CBlockIndex *pindexFirstNotTreeValid = nullptr; | ||||
// Oldest ancestor of pindex which does not have BLOCK_VALID_TRANSACTIONS | // Oldest ancestor of pindex which does not have BLOCK_VALID_TRANSACTIONS | ||||
// (regardless of being valid or not). | // (regardless of being valid or not). | ||||
CBlockIndex *pindexFirstNotTransactionsValid = nullptr; | CBlockIndex *pindexFirstNotTransactionsValid = nullptr; | ||||
// Oldest ancestor of pindex which does not have BLOCK_VALID_CHAIN | // Oldest ancestor of pindex which does not have BLOCK_VALID_CHAIN | ||||
// (regardless of being valid or not). | // (regardless of being valid or not). | ||||
CBlockIndex *pindexFirstNotChainValid = nullptr; | CBlockIndex *pindexFirstNotChainValid = nullptr; | ||||
// Oldest ancestor of pindex which does not have BLOCK_VALID_SCRIPTS | // Oldest ancestor of pindex which does not have BLOCK_VALID_SCRIPTS | ||||
// (regardless of being valid or not). | // (regardless of being valid or not). | ||||
CBlockIndex *pindexFirstNotScriptsValid = nullptr; | CBlockIndex *pindexFirstNotScriptsValid = nullptr; | ||||
while (pindex != nullptr) { | while (pindex != nullptr) { | ||||
nNodes++; | nNodes++; | ||||
if (pindexFirstInvalid == nullptr && pindex->nStatus.hasFailed()) { | if (pindexFirstInvalid == nullptr && pindex->nStatus.hasFailed()) { | ||||
pindexFirstInvalid = pindex; | pindexFirstInvalid = pindex; | ||||
} | } | ||||
if (pindexFirstParked == nullptr && pindex->nStatus.isParked()) { | |||||
pindexFirstParked = pindex; | |||||
} | |||||
if (pindexFirstMissing == nullptr && !pindex->nStatus.hasData()) { | if (pindexFirstMissing == nullptr && !pindex->nStatus.hasData()) { | ||||
pindexFirstMissing = pindex; | pindexFirstMissing = pindex; | ||||
} | } | ||||
if (pindexFirstNeverProcessed == nullptr && pindex->nTx == 0) { | if (pindexFirstNeverProcessed == nullptr && pindex->nTx == 0) { | ||||
pindexFirstNeverProcessed = pindex; | pindexFirstNeverProcessed = pindex; | ||||
} | } | ||||
if (pindex->pprev != nullptr && pindexFirstNotTreeValid == nullptr && | if (pindex->pprev != nullptr && pindexFirstNotTreeValid == nullptr && | ||||
pindex->nStatus.getValidity() < BlockValidity::TREE) { | pindex->nStatus.getValidity() < BlockValidity::TREE) { | ||||
▲ Show 20 Lines • Show All 77 Lines • ▼ Show 20 Lines | while (pindex != nullptr) { | ||||
// 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.isInvalid()); | assert(!pindex->nStatus.isInvalid()); | ||||
} | } | ||||
if (pindexFirstParked == nullptr) { | |||||
// Checks for not-invalid blocks. | |||||
// The failed mask cannot be set for blocks without invalid parents. | |||||
assert(!pindex->nStatus.isOnParkedChain()); | |||||
} | |||||
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. | ||||
if (pindexFirstMissing == nullptr || | if (pindexFirstMissing == nullptr || | ||||
▲ Show 20 Lines • Show All 82 Lines • ▼ Show 20 Lines | while (pindex != nullptr) { | ||||
// have not yet visited the last child. | // have not yet visited the last child. | ||||
while (pindex) { | while (pindex) { | ||||
// We are going to either move to a parent or a sibling of pindex. | // We are going to either move to a parent or a sibling of pindex. | ||||
// If pindex was the first with a certain property, unset the | // If pindex was the first with a certain property, unset the | ||||
// corresponding variable. | // corresponding variable. | ||||
if (pindex == pindexFirstInvalid) { | if (pindex == pindexFirstInvalid) { | ||||
pindexFirstInvalid = nullptr; | pindexFirstInvalid = nullptr; | ||||
} | } | ||||
if (pindex == pindexFirstParked) { | |||||
pindexFirstParked = nullptr; | |||||
} | |||||
if (pindex == pindexFirstMissing) { | if (pindex == pindexFirstMissing) { | ||||
pindexFirstMissing = nullptr; | pindexFirstMissing = nullptr; | ||||
} | } | ||||
if (pindex == pindexFirstNeverProcessed) { | if (pindex == pindexFirstNeverProcessed) { | ||||
pindexFirstNeverProcessed = nullptr; | pindexFirstNeverProcessed = nullptr; | ||||
} | } | ||||
if (pindex == pindexFirstNotTreeValid) { | if (pindex == pindexFirstNotTreeValid) { | ||||
pindexFirstNotTreeValid = nullptr; | pindexFirstNotTreeValid = nullptr; | ||||
▲ Show 20 Lines • Show All 213 Lines • Show Last 20 Lines |