Changeset View
Changeset View
Standalone View
Standalone View
src/validation.cpp
Show First 20 Lines • Show All 181 Lines • ▼ Show 20 Lines | public: | ||||
template <typename F> | template <typename F> | ||||
void UpdateFlags(CBlockIndex *pindex, F f) | void UpdateFlags(CBlockIndex *pindex, F f) | ||||
EXCLUSIVE_LOCKS_REQUIRED(cs_main); | EXCLUSIVE_LOCKS_REQUIRED(cs_main); | ||||
/** Remove parked status from a block and its descendants. */ | /** Remove parked status from a block and its descendants. */ | ||||
void UnparkBlockImpl(CBlockIndex *pindex, bool fClearChildren) | void UnparkBlockImpl(CBlockIndex *pindex, bool fClearChildren) | ||||
EXCLUSIVE_LOCKS_REQUIRED(cs_main); | EXCLUSIVE_LOCKS_REQUIRED(cs_main); | ||||
bool ReplayBlocks(const Consensus::Params ¶ms, CCoinsView *view); | bool ReplayBlocks(const Consensus::Params ¶ms, CCoinsView *view); | ||||
bool RewindBlockIndex(const Config &config); | |||||
bool LoadGenesisBlock(const CChainParams &chainparams); | bool LoadGenesisBlock(const CChainParams &chainparams); | ||||
void PruneBlockIndexCandidates(); | void PruneBlockIndexCandidates(); | ||||
void UnloadBlockIndex(); | void UnloadBlockIndex(); | ||||
private: | private: | ||||
bool ActivateBestChainStep(const Config &config, CValidationState &state, | bool ActivateBestChainStep(const Config &config, CValidationState &state, | ||||
Show All 27 Lines | private: | ||||
bool ReceivedBlockTransactions(const CBlock &block, CValidationState &state, | bool ReceivedBlockTransactions(const CBlock &block, CValidationState &state, | ||||
CBlockIndex *pindexNew, | CBlockIndex *pindexNew, | ||||
const FlatFilePos &pos) | const FlatFilePos &pos) | ||||
EXCLUSIVE_LOCKS_REQUIRED(cs_main); | EXCLUSIVE_LOCKS_REQUIRED(cs_main); | ||||
bool RollforwardBlock(const CBlockIndex *pindex, CCoinsViewCache &inputs, | bool RollforwardBlock(const CBlockIndex *pindex, CCoinsViewCache &inputs, | ||||
const Consensus::Params ¶ms) | const Consensus::Params ¶ms) | ||||
EXCLUSIVE_LOCKS_REQUIRED(cs_main); | EXCLUSIVE_LOCKS_REQUIRED(cs_main); | ||||
//! Mark a block as not having block data | |||||
void EraseBlockData(CBlockIndex *index) EXCLUSIVE_LOCKS_REQUIRED(cs_main); | |||||
} g_chainstate; | } g_chainstate; | ||||
/** | /** | ||||
* Global state | * Global state | ||||
* | * | ||||
* Mutex to guard access to validation specific variables, such as reading | * Mutex to guard access to validation specific variables, such as reading | ||||
* or changing the chainstate. | * or changing the chainstate. | ||||
* | * | ||||
▲ Show 20 Lines • Show All 1,423 Lines • ▼ Show 20 Lines | bool CChainState::ConnectBlock(const CBlock &block, CValidationState &state, | ||||
// 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 | ||||
// NOTE: We don't currently (re-)invoke ContextualCheckBlock() or | // NOTE: We don't currently (re-)invoke ContextualCheckBlock() or | ||||
// ContextualCheckBlockHeader() here. This means that if we add a new | // ContextualCheckBlockHeader() here. This means that if we add a new | ||||
// consensus rule that is enforced in one of those two functions, then we | // consensus rule that is enforced in one of those two functions, then we | ||||
// may have let in a block that violates the rule prior to updating the | // may have let in a block that violates the rule prior to updating the | ||||
// software, and we would NOT be enforcing the rule here. Fully solving | // software, and we would NOT be enforcing the rule here. Fully solving | ||||
// upgrade from one software version to the next after a consensus rule | // upgrade from one software version to the next after a consensus rule | ||||
// change is potentially tricky and issue-specific (see RewindBlockIndex() | // change is potentially tricky and issue-specific. | ||||
// for one general approach that was used for BIP 141 deployment). | |||||
// Also, currently the rule against blocks more than 2 hours in the future | // Also, currently the rule against blocks more than 2 hours in the future | ||||
// is enforced in ContextualCheckBlockHeader(); we wouldn't want to | // is enforced in ContextualCheckBlockHeader(); we wouldn't want to | ||||
// re-enforce that rule here (at least until we make it impossible for | // re-enforce that rule here (at least until we make it impossible for | ||||
// GetAdjustedTime() to go backward). | // GetAdjustedTime() to go backward). | ||||
if (!CheckBlock(block, state, consensusParams, | if (!CheckBlock(block, state, consensusParams, | ||||
options.withCheckPoW(!fJustCheck) | options.withCheckPoW(!fJustCheck) | ||||
.withCheckMerkleRoot(!fJustCheck))) { | .withCheckMerkleRoot(!fJustCheck))) { | ||||
if (state.CorruptionPossible()) { | if (state.CorruptionPossible()) { | ||||
▲ Show 20 Lines • Show All 3,211 Lines • ▼ Show 20 Lines | bool CChainState::ReplayBlocks(const Consensus::Params ¶ms, | ||||
uiInterface.ShowProgress("", 100, false); | uiInterface.ShowProgress("", 100, false); | ||||
return true; | return true; | ||||
} | } | ||||
bool ReplayBlocks(const Consensus::Params ¶ms, CCoinsView *view) { | bool ReplayBlocks(const Consensus::Params ¶ms, CCoinsView *view) { | ||||
return g_chainstate.ReplayBlocks(params, view); | return g_chainstate.ReplayBlocks(params, view); | ||||
} | } | ||||
//! Helper for CChainState::RewindBlockIndex | |||||
void CChainState::EraseBlockData(CBlockIndex *index) { | |||||
AssertLockHeld(cs_main); | |||||
// Make sure this block isn't active | |||||
assert(!chainActive.Contains(index)); | |||||
// Reduce validity | |||||
index->nStatus = index->nStatus.withValidity( | |||||
std::min(index->nStatus.getValidity(), BlockValidity::TREE)); | |||||
// Remove have-data flags. | |||||
index->nStatus = index->nStatus.withData(false).withUndo(false); | |||||
// Remove storage location. | |||||
index->nFile = 0; | |||||
index->nDataPos = 0; | |||||
index->nUndoPos = 0; | |||||
// Remove various other things | |||||
index->nTx = 0; | |||||
index->nChainTx = 0; | |||||
index->nSequenceId = 0; | |||||
// Make sure it gets written. | |||||
setDirtyBlockIndex.insert(index); | |||||
// Update indexes | |||||
setBlockIndexCandidates.erase(index); | |||||
std::pair<std::multimap<CBlockIndex *, CBlockIndex *>::iterator, | |||||
std::multimap<CBlockIndex *, CBlockIndex *>::iterator> | |||||
ret = mapBlocksUnlinked.equal_range(index->pprev); | |||||
while (ret.first != ret.second) { | |||||
if (ret.first->second == index) { | |||||
mapBlocksUnlinked.erase(ret.first++); | |||||
} else { | |||||
++ret.first; | |||||
} | |||||
} | |||||
// Mark parent as eligible for main chain again | |||||
if (index->pprev && index->pprev->IsValid(BlockValidity::TRANSACTIONS) && | |||||
index->pprev->HaveTxsDownloaded()) { | |||||
setBlockIndexCandidates.insert(index->pprev); | |||||
} | |||||
} | |||||
bool CChainState::RewindBlockIndex(const Config &config) { | |||||
LOCK(cs_main); | |||||
const CChainParams ¶ms = config.GetChainParams(); | |||||
int nHeight = chainActive.Height() + 1; | |||||
// nHeight is now the height of the first insufficiently-validated block, or | |||||
// tipheight + 1 | |||||
CValidationState state; | |||||
CBlockIndex *pindex = chainActive.Tip(); | |||||
while (chainActive.Height() >= nHeight) { | |||||
if (fPruneMode && !chainActive.Tip()->nStatus.hasData()) { | |||||
// If pruning, don't try rewinding past the HAVE_DATA point; since | |||||
// older blocks can't be served anyway, there's no need to walk | |||||
// further, and trying to DisconnectTip() will fail (and require a | |||||
// needless reindex/redownload of the blockchain). | |||||
break; | |||||
} | |||||
if (!DisconnectTip(config, state, nullptr)) { | |||||
return error("RewindBlockIndex: unable to disconnect block at " | |||||
"height %i (%s)", | |||||
pindex->nHeight, FormatStateMessage(state)); | |||||
} | |||||
// Occasionally flush state to disk. | |||||
if (!FlushStateToDisk(params, state, FlushStateMode::PERIODIC)) { | |||||
LogPrintf("RewindBlockIndex: unable to flush state to disk (%s)\n", | |||||
FormatStateMessage(state)); | |||||
return false; | |||||
} | |||||
} | |||||
// Reduce validity flag and have-data flags. | |||||
// We do this after actual disconnecting, otherwise we'll end up writing the | |||||
// lack of data to disk before writing the chainstate, resulting in a | |||||
// failure to continue if interrupted. | |||||
for (const auto &entry : mapBlockIndex) { | |||||
CBlockIndex *pindexIter = entry.second; | |||||
if (pindexIter->IsValid(BlockValidity::TRANSACTIONS) && | |||||
pindexIter->HaveTxsDownloaded()) { | |||||
setBlockIndexCandidates.insert(pindexIter); | |||||
} | |||||
} | |||||
if (chainActive.Tip() != nullptr) { | |||||
// We can't prune block index candidates based on our tip if we have | |||||
// no tip due to chainActive being empty! | |||||
PruneBlockIndexCandidates(); | |||||
CheckBlockIndex(params.GetConsensus()); | |||||
} | |||||
return true; | |||||
} | |||||
bool RewindBlockIndex(const Config &config) { | |||||
if (!g_chainstate.RewindBlockIndex(config)) { | |||||
return false; | |||||
} | |||||
if (chainActive.Tip() != nullptr) { | |||||
// FlushStateToDisk can possibly read chainActive. Be conservative | |||||
// and skip it here, we're about to -reindex-chainstate anyway, so | |||||
// it'll get called a bunch real soon. | |||||
CValidationState state; | |||||
if (!FlushStateToDisk(config.GetChainParams(), state, | |||||
FlushStateMode::ALWAYS)) { | |||||
LogPrintf("RewindBlockIndex: unable to flush state to disk (%s)\n", | |||||
FormatStateMessage(state)); | |||||
return false; | |||||
} | |||||
} | |||||
return true; | |||||
} | |||||
// May NOT be used after any connections are up as much of the peer-processing | // May NOT be used after any connections are up as much of the peer-processing | ||||
// logic assumes a consistent block index state | // logic assumes a consistent block index state | ||||
void CChainState::UnloadBlockIndex() { | void CChainState::UnloadBlockIndex() { | ||||
nBlockSequenceId = 1; | nBlockSequenceId = 1; | ||||
m_failed_blocks.clear(); | m_failed_blocks.clear(); | ||||
setBlockIndexCandidates.clear(); | setBlockIndexCandidates.clear(); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 767 Lines • Show Last 20 Lines |