Changeset View
Changeset View
Standalone View
Standalone View
src/validation.cpp
Show First 20 Lines • Show All 129 Lines • ▼ Show 20 Lines | |||||
*/ | */ | ||||
std::atomic<int32_t> nBlockSequenceId{1}; | std::atomic<int32_t> nBlockSequenceId{1}; | ||||
/** Decreasing counter (used by subsequent preciousblock calls). */ | /** Decreasing counter (used by subsequent preciousblock calls). */ | ||||
int32_t nBlockReverseSequenceId = -1; | int32_t nBlockReverseSequenceId = -1; | ||||
/** chainwork for the last block that preciousblock has been applied to. */ | /** chainwork for the last block that preciousblock has been applied to. */ | ||||
arith_uint256 nLastPreciousChainwork = 0; | arith_uint256 nLastPreciousChainwork = 0; | ||||
/** Dirty block index entries. */ | /** Dirty block index entries. */ | ||||
std::set<CBlockIndex *> setDirtyBlockIndex; | std::set<const CBlockIndex *> setDirtyBlockIndex; | ||||
/** Dirty block file entries. */ | /** Dirty block file entries. */ | ||||
std::set<int> setDirtyFileInfo; | std::set<int> setDirtyFileInfo; | ||||
} // namespace | } // namespace | ||||
CBlockIndex *FindForkInGlobalIndex(const CChain &chain, | CBlockIndex *FindForkInGlobalIndex(const CChain &chain, | ||||
const CBlockLocator &locator) { | const CBlockLocator &locator) { | ||||
// Find the first block the caller has in the main chain | // Find the first block the caller has in the main chain | ||||
▲ Show 20 Lines • Show All 2,310 Lines • ▼ Show 20 Lines | |||||
/** | /** | ||||
* Delete all entries in setBlockIndexCandidates that are worse than the current | * Delete all entries in setBlockIndexCandidates that are worse than the current | ||||
* tip. | * tip. | ||||
*/ | */ | ||||
static void PruneBlockIndexCandidates() { | static void PruneBlockIndexCandidates() { | ||||
// Note that we can't delete the current block itself, as we may need to | // Note that we can't delete the current block itself, as we may need to | ||||
// return to it later in case a reorganization to a better block fails. | // return to it later in case a reorganization to a better block fails. | ||||
std::set<CBlockIndex *, CBlockIndexWorkComparator>::iterator it = | auto it = setBlockIndexCandidates.begin(); | ||||
setBlockIndexCandidates.begin(); | |||||
while (it != setBlockIndexCandidates.end() && | while (it != setBlockIndexCandidates.end() && | ||||
setBlockIndexCandidates.value_comp()(*it, chainActive.Tip())) { | setBlockIndexCandidates.value_comp()(*it, chainActive.Tip())) { | ||||
setBlockIndexCandidates.erase(it++); | setBlockIndexCandidates.erase(it++); | ||||
} | } | ||||
// Either the current tip or a successor of it we're working towards is left | // Either the current tip or a successor of it we're working towards is left | ||||
// in setBlockIndexCandidates. | // in setBlockIndexCandidates. | ||||
assert(!setBlockIndexCandidates.empty()); | assert(!setBlockIndexCandidates.empty()); | ||||
▲ Show 20 Lines • Show All 246 Lines • ▼ Show 20 Lines | bool PreciousBlock(const Config &config, CValidationState &state, | ||||
setBlockIndexCandidates.insert(pindex); | setBlockIndexCandidates.insert(pindex); | ||||
PruneBlockIndexCandidates(); | PruneBlockIndexCandidates(); | ||||
} | } | ||||
} | } | ||||
return ActivateBestChain(config, state); | return ActivateBestChain(config, state); | ||||
} | } | ||||
bool InvalidateBlock(const Config &config, CValidationState &state, | static bool UnwindBlock(const Config &config, CValidationState &state, | ||||
CBlockIndex *pindex) { | CBlockIndex *pindex, bool invalidate) { | ||||
AssertLockHeld(cs_main); | AssertLockHeld(cs_main); | ||||
// Mark the block itself as invalid. | // Mark the block itself as invalid. | ||||
pindex->nStatus = pindex->nStatus.withFailed(); | pindex->nStatus = | ||||
pindex->nStatus.withFailed(invalidate).withParked(!invalidate); | |||||
setDirtyBlockIndex.insert(pindex); | setDirtyBlockIndex.insert(pindex); | ||||
DisconnectedBlockTransactions disconnectpool; | DisconnectedBlockTransactions disconnectpool; | ||||
while (chainActive.Contains(pindex)) { | while (chainActive.Contains(pindex)) { | ||||
CBlockIndex *pindexWalk = chainActive.Tip(); | CBlockIndex *pindexWalk = chainActive.Tip(); | ||||
pindexWalk->nStatus = pindexWalk->nStatus.withFailedParent(); | pindexWalk->nStatus = | ||||
pindexWalk->nStatus.withFailed(invalidate).withParked(!invalidate); | |||||
setDirtyBlockIndex.insert(pindexWalk); | setDirtyBlockIndex.insert(pindexWalk); | ||||
// ActivateBestChain considers blocks already in chainActive | // ActivateBestChain considers blocks already in chainActive | ||||
// unconditionally valid already, so force disconnect away from it. | // unconditionally valid already, so force disconnect away from it. | ||||
if (!DisconnectTip(config, state, &disconnectpool)) { | if (!DisconnectTip(config, state, &disconnectpool)) { | ||||
// It's probably hopeless to try to make the mempool consistent | // It's probably hopeless to try to make the mempool consistent | ||||
// here if DisconnectTip failed, but we can try. | // here if DisconnectTip failed, but we can try. | ||||
disconnectpool.updateMempoolForReorg(config, false); | disconnectpool.updateMempoolForReorg(config, false); | ||||
return false; | return false; | ||||
} | } | ||||
} | } | ||||
// DisconnectTip will add transactions to disconnectpool; try to add these | // DisconnectTip will add transactions to disconnectpool; try to add these | ||||
// back to the mempool. | // back to the mempool. | ||||
disconnectpool.updateMempoolForReorg(config, true); | disconnectpool.updateMempoolForReorg(config, true); | ||||
// The resulting new best tip may not be in setBlockIndexCandidates anymore, | // The resulting new best tip may not be in setBlockIndexCandidates anymore, | ||||
// so add it again. | // so add it again. | ||||
for (const std::pair<const uint256, CBlockIndex *> &it : mapBlockIndex) { | for (const std::pair<const uint256, CBlockIndex *> &it : mapBlockIndex) { | ||||
CBlockIndex *i = it.second; | CBlockIndex *i = it.second; | ||||
if (i->IsValid(BlockValidity::TRANSACTIONS) && i->nChainTx && | if (i->IsValid(BlockValidity::TRANSACTIONS) && i->nChainTx && | ||||
!setBlockIndexCandidates.value_comp()(i, chainActive.Tip())) { | !setBlockIndexCandidates.value_comp()(i, chainActive.Tip())) { | ||||
setBlockIndexCandidates.insert(i); | setBlockIndexCandidates.insert(i); | ||||
} | } | ||||
} | } | ||||
if (invalidate) { | |||||
InvalidChainFound(pindex); | InvalidChainFound(pindex); | ||||
} | |||||
uiInterface.NotifyBlockTip(IsInitialBlockDownload(), pindex->pprev); | uiInterface.NotifyBlockTip(IsInitialBlockDownload(), pindex->pprev); | ||||
return true; | return true; | ||||
} | } | ||||
bool ResetBlockFailureFlags(CBlockIndex *pindex) { | bool InvalidateBlock(const Config &config, CValidationState &state, | ||||
CBlockIndex *pindex) { | |||||
return UnwindBlock(config, state, pindex, true); | |||||
} | |||||
bool ParkBlock(const Config &config, CValidationState &state, | |||||
CBlockIndex *pindex) { | |||||
return UnwindBlock(config, state, pindex, false); | |||||
} | |||||
template <typename F> bool UpdateFlags(CBlockIndex *pindex, F f) { | |||||
AssertLockHeld(cs_main); | AssertLockHeld(cs_main); | ||||
int nHeight = pindex->nHeight; | int nHeight = pindex->nHeight; | ||||
// Remove the invalidity flag from this block and all its descendants. | // Update the flags 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() && | BlockStatus newStatus = f(it->second->nStatus); | ||||
if (it->second->nStatus != newStatus && | |||||
it->second->GetAncestor(nHeight) == pindex) { | it->second->GetAncestor(nHeight) == pindex) { | ||||
it->second->nStatus = it->second->nStatus.withClearedFailureFlags(); | it->second->nStatus = newStatus; | ||||
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) { | |||||
// Reset invalid block marker if it was pointing to one of | |||||
// those. | |||||
pindexBestInvalid = nullptr; | |||||
} | |||||
} | } | ||||
it++; | it++; | ||||
} | } | ||||
// Remove the invalidity flag from all ancestors too. | // Update the flags from all ancestors too. | ||||
while (pindex != nullptr) { | while (pindex != nullptr) { | ||||
if (pindex->nStatus.isInvalid()) { | BlockStatus newStatus = f(pindex->nStatus); | ||||
pindex->nStatus = pindex->nStatus.withClearedFailureFlags(); | if (pindex->nStatus != newStatus) { | ||||
pindex->nStatus = newStatus; | |||||
setDirtyBlockIndex.insert(pindex); | setDirtyBlockIndex.insert(pindex); | ||||
} | } | ||||
pindex = pindex->pprev; | pindex = pindex->pprev; | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
bool ResetBlockFailureFlags(CBlockIndex *pindex) { | |||||
AssertLockHeld(cs_main); | |||||
if (pindexBestInvalid && | |||||
(pindexBestInvalid->GetAncestor(pindex->nHeight) == pindex || | |||||
pindex->GetAncestor(pindexBestInvalid->nHeight) == | |||||
pindexBestInvalid)) { | |||||
// Reset the invalid block marker if it is about to be cleared. | |||||
pindexBestInvalid = nullptr; | |||||
} | |||||
return UpdateFlags(pindex, [](const BlockStatus status) { | |||||
return status.withClearedFailureFlags(); | |||||
}); | |||||
} | |||||
bool UnparkBlock(CBlockIndex *pindex) { | |||||
AssertLockHeld(cs_main); | |||||
if (pindexBestParked && | |||||
(pindexBestParked->GetAncestor(pindex->nHeight) == pindex || | |||||
pindex->GetAncestor(pindexBestParked->nHeight) == pindexBestParked)) { | |||||
// Reset the parked block marker if it is about to be cleared. | |||||
pindexBestParked = nullptr; | |||||
} | |||||
return UpdateFlags(pindex, [](const BlockStatus status) { | |||||
return status.withClearedParkedFlags(); | |||||
}); | |||||
} | |||||
static CBlockIndex *AddToBlockIndex(const CBlockHeader &block) { | static CBlockIndex *AddToBlockIndex(const CBlockHeader &block) { | ||||
// Check for duplicate | // Check for duplicate | ||||
uint256 hash = block.GetHash(); | uint256 hash = block.GetHash(); | ||||
BlockMap::iterator it = mapBlockIndex.find(hash); | BlockMap::iterator it = mapBlockIndex.find(hash); | ||||
if (it != mapBlockIndex.end()) { | if (it != mapBlockIndex.end()) { | ||||
return it->second; | return it->second; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 2,379 Lines • Show Last 20 Lines |