Changeset View
Changeset View
Standalone View
Standalone View
src/validation.cpp
Show First 20 Lines • Show All 2,391 Lines • ▼ Show 20 Lines | do { | ||||
// Check whether all blocks on the path between the currently active | // Check whether all blocks on the path between the currently active | ||||
// chain and the candidate are valid. Just going until the active chain | // chain and the candidate are valid. Just going until the active chain | ||||
// is an optimization, as we know all blocks in it are valid already. | // is an optimization, as we know all blocks in it are valid already. | ||||
CBlockIndex *pindexTest = pindexNew; | CBlockIndex *pindexTest = pindexNew; | ||||
bool hasValidAncestor = true; | bool hasValidAncestor = true; | ||||
while (hasValidAncestor && pindexTest && pindexTest != pindexFork) { | while (hasValidAncestor && pindexTest && pindexTest != pindexFork) { | ||||
assert(pindexTest->nChainTx || pindexTest->nHeight == 0); | assert(pindexTest->nChainTx || pindexTest->nHeight == 0); | ||||
// If this is a parked chain, but it has enough PoW, clear the park | |||||
// state. | |||||
bool fParkedChain = pindexTest->nStatus.isOnParkedChain(); | |||||
if (fParkedChain && gArgs.GetBoolArg("-parkdeepreorg", true)) { | |||||
const CBlockIndex *pindexTip = chainActive.Tip(); | |||||
// During initialization, pindexTip and/or pindexFork may be | |||||
// null. In this case, we just ignore the fact that the chain is | |||||
// parked. | |||||
if (!pindexTip || !pindexFork) { | |||||
UnparkBlock(pindexTest); | |||||
continue; | |||||
} | |||||
// A parked chain can be unparked if it has twice as much PoW | |||||
// accumulated as the main chain has since the fork block. | |||||
CBlockIndex const *pindexExtraPow = pindexTip; | |||||
arith_uint256 requiredWork = pindexTip->nChainWork; | |||||
switch (pindexTip->nHeight - pindexFork->nHeight) { | |||||
// Limit the penality for depth 1, 2 and 3 to half a block | |||||
// worth of work to ensure we don't fork accidentaly. | |||||
case 3: | |||||
case 2: | |||||
pindexExtraPow = pindexExtraPow->pprev; | |||||
// FALLTHROUGH | |||||
case 1: { | |||||
const arith_uint256 deltaWork = | |||||
pindexExtraPow->nChainWork - pindexFork->nChainWork; | |||||
requiredWork += (deltaWork >> 1); | |||||
break; | |||||
} | |||||
default: | |||||
requiredWork += | |||||
pindexExtraPow->nChainWork - pindexFork->nChainWork; | |||||
break; | |||||
} | |||||
if (pindexNew->nChainWork > requiredWork) { | |||||
// We have enough, clear the parked state. | |||||
LogPrintf("Unpark block %s as its chain has accumulated " | |||||
"enough PoW.\n", | |||||
pindexTest->GetBlockHash().ToString()); | |||||
fParkedChain = false; | |||||
UnparkBlock(pindexTest); | |||||
} | |||||
} | |||||
// 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 || fParkedChain || fMissingData)) { | if (!(fInvalidChain || fParkedChain || fMissingData)) { | ||||
// The current block is acceptable, move to the parent, up to | // The current block is acceptable, move to the parent, up to | ||||
// the fork point. | // the fork point. | ||||
pindexTest = pindexTest->pprev; | pindexTest = pindexTest->pprev; | ||||
continue; | continue; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 302 Lines • ▼ Show 20 Lines | bool PreciousBlock(const Config &config, CValidationState &state, | ||||
setBlockIndexCandidates.erase(pindex); | setBlockIndexCandidates.erase(pindex); | ||||
pindex->nSequenceId = nBlockReverseSequenceId; | pindex->nSequenceId = nBlockReverseSequenceId; | ||||
if (nBlockReverseSequenceId > std::numeric_limits<int32_t>::min()) { | if (nBlockReverseSequenceId > std::numeric_limits<int32_t>::min()) { | ||||
// We can't keep reducing the counter if somebody really wants to | // We can't keep reducing the counter if somebody really wants to | ||||
// call preciousblock 2**31-1 times on the same set of tips... | // call preciousblock 2**31-1 times on the same set of tips... | ||||
nBlockReverseSequenceId--; | nBlockReverseSequenceId--; | ||||
} | } | ||||
// In case this was parked, unpark it. | |||||
UnparkBlock(pindex); | |||||
// Make sure it is added to the candidate list if apropriate. | |||||
if (pindex->IsValid(BlockValidity::TRANSACTIONS) && pindex->nChainTx) { | if (pindex->IsValid(BlockValidity::TRANSACTIONS) && pindex->nChainTx) { | ||||
setBlockIndexCandidates.insert(pindex); | setBlockIndexCandidates.insert(pindex); | ||||
PruneBlockIndexCandidates(); | PruneBlockIndexCandidates(); | ||||
} | } | ||||
} | } | ||||
return ActivateBestChain(config, state); | return ActivateBestChain(config, state); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 884 Lines • ▼ Show 20 Lines | if (!CheckBlock(config, block, state) || | ||||
pindex->nStatus = pindex->nStatus.withFailed(); | pindex->nStatus = pindex->nStatus.withFailed(); | ||||
setDirtyBlockIndex.insert(pindex); | setDirtyBlockIndex.insert(pindex); | ||||
} | } | ||||
return error("%s: %s (block %s)", __func__, FormatStateMessage(state), | return error("%s: %s (block %s)", __func__, FormatStateMessage(state), | ||||
block.GetHash().ToString()); | block.GetHash().ToString()); | ||||
} | } | ||||
// If this is a deep reorg (a regorg of more than one block), preemptively | |||||
// mark the chain as parked. If it has enough work, it'll unpark | |||||
// automatically. We mark the block as parked at the very last minute so we | |||||
// can make sure everything is ready to be reorged if needed. | |||||
if (gArgs.GetBoolArg("-parkdeepreorg", true)) { | |||||
const CBlockIndex *pindexFork = chainActive.FindFork(pindex); | |||||
if (pindexFork && pindexFork->nHeight + 1 < pindex->nHeight) { | |||||
LogPrintf("Park block %s as it would cause a deep reorg.\n", | |||||
pindex->GetBlockHash().ToString()); | |||||
pindex->nStatus = pindex->nStatus.withParked(); | |||||
setDirtyBlockIndex.insert(pindex); | |||||
} | |||||
} | |||||
// Header is valid/has work and the merkle tree is good. | // Header is valid/has work and the merkle tree is good. | ||||
// Relay now, but if it does not build on our best tip, let the | // Relay now, but if it does not build on our best tip, let the | ||||
// SendMessages loop relay it. | // SendMessages loop relay it. | ||||
if (!IsInitialBlockDownload() && chainActive.Tip() == pindex->pprev) { | if (!IsInitialBlockDownload() && chainActive.Tip() == pindex->pprev) { | ||||
GetMainSignals().NewPoWValidBlock(pindex, pblock); | GetMainSignals().NewPoWValidBlock(pindex, pblock); | ||||
} | } | ||||
int nHeight = pindex->nHeight; | int nHeight = pindex->nHeight; | ||||
▲ Show 20 Lines • Show All 1,631 Lines • Show Last 20 Lines |