Changeset View
Changeset View
Standalone View
Standalone View
src/validation.cpp
Show First 20 Lines • Show All 96 Lines • ▼ Show 20 Lines | |||||
// Internal stuff | // Internal stuff | ||||
namespace { | namespace { | ||||
CBlockIndex *pindexBestInvalid; | CBlockIndex *pindexBestInvalid; | ||||
CBlockIndex *pindexBestParked; | CBlockIndex *pindexBestParked; | ||||
/** | /** | ||||
* The best finalized block. | |||||
* This block cannot be reorged in any way, shape or form. | |||||
*/ | |||||
CBlockIndex const *pindexFinalized; | |||||
/** | |||||
* The set of all CBlockIndex entries with BLOCK_VALID_TRANSACTIONS (for itself | * The set of all CBlockIndex entries with BLOCK_VALID_TRANSACTIONS (for itself | ||||
* and all ancestors) and as good as our current tip or better. Entries may be | * and all ancestors) and as good as our current tip or better. Entries may be | ||||
* failed, though, and pruning nodes may be missing the data for the block. | * failed, though, and pruning nodes may be missing the data for the block. | ||||
*/ | */ | ||||
std::set<CBlockIndex *, CBlockIndexWorkComparator> setBlockIndexCandidates; | std::set<CBlockIndex *, CBlockIndexWorkComparator> setBlockIndexCandidates; | ||||
/** | /** | ||||
* All pairs A->B, where A (or one of its ancestors) misses transactions, but B | * All pairs A->B, where A (or one of its ancestors) misses transactions, but B | ||||
* has transactions. Pruned nodes may have entries where B is missing data. | * has transactions. Pruned nodes may have entries where B is missing data. | ||||
▲ Show 20 Lines • Show All 2,074 Lines • ▼ Show 20 Lines | if ((IsReplayProtectionEnabled(config, pindexDelete) && | ||||
disconnectpool->clear(); | disconnectpool->clear(); | ||||
} | } | ||||
} | } | ||||
if (disconnectpool) { | if (disconnectpool) { | ||||
disconnectpool->addForBlock(block.vtx); | disconnectpool->addForBlock(block.vtx); | ||||
} | } | ||||
// If the tip is finalized, then undo it. | |||||
if (pindexFinalized == pindexDelete) { | |||||
pindexFinalized = pindexDelete->pprev; | |||||
} | |||||
// Update chainActive and related variables. | // Update chainActive and related variables. | ||||
UpdateTip(config, pindexDelete->pprev); | UpdateTip(config, pindexDelete->pprev); | ||||
// Let wallets know transactions went from 1-confirmed to | // Let wallets know transactions went from 1-confirmed to | ||||
// 0-confirmed or conflicted: | // 0-confirmed or conflicted: | ||||
GetMainSignals().BlockDisconnected(pblock); | GetMainSignals().BlockDisconnected(pblock); | ||||
return true; | return true; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 166 Lines • ▼ Show 20 Lines | static bool ConnectTip(const Config &config, CValidationState &state, | ||||
return true; | return true; | ||||
} | } | ||||
/** | /** | ||||
* Return the tip of the chain with the most work in it, that isn't known to be | * Return the tip of the chain with the most work in it, that isn't known to be | ||||
* invalid (it's however far from certain to be valid). | * invalid (it's however far from certain to be valid). | ||||
*/ | */ | ||||
static CBlockIndex *FindMostWorkChain() { | static CBlockIndex *FindMostWorkChain() { | ||||
AssertLockHeld(cs_main); | |||||
sickpig: Was it something we need to have done independently from the change introduced in this diff? | |||||
deadalnixAuthorUnsubmitted Done Inline ActionsJust checking existing invariants. deadalnix: Just checking existing invariants. | |||||
do { | do { | ||||
CBlockIndex *pindexNew = nullptr; | CBlockIndex *pindexNew = nullptr; | ||||
// Find the best candidate header. | // Find the best candidate header. | ||||
{ | { | ||||
std::set<CBlockIndex *, CBlockIndexWorkComparator>::reverse_iterator | std::set<CBlockIndex *, CBlockIndexWorkComparator>::reverse_iterator | ||||
it = setBlockIndexCandidates.rbegin(); | it = setBlockIndexCandidates.rbegin(); | ||||
if (it == setBlockIndexCandidates.rend()) { | if (it == setBlockIndexCandidates.rend()) { | ||||
return nullptr; | return nullptr; | ||||
} | } | ||||
pindexNew = *it; | pindexNew = *it; | ||||
} | } | ||||
// If this block will cause a finalized block to be reorged, then we | |||||
// mark it as invalid. | |||||
if (pindexFinalized && !AreOnTheSameFork(pindexNew, pindexFinalized)) { | |||||
LogPrintf("Mark block %s invalid because it forks past the " | |||||
"finalization point %d.\n", | |||||
pindexNew->GetBlockHash().ToString(), | |||||
pindexFinalized->nHeight); | |||||
pindexNew->nStatus = pindexNew->nStatus.withFailed(); | |||||
} | |||||
const CBlockIndex *pindexFork = chainActive.FindFork(pindexNew); | const CBlockIndex *pindexFork = chainActive.FindFork(pindexNew); | ||||
// 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) { | ||||
▲ Show 20 Lines • Show All 427 Lines • ▼ Show 20 Lines | static bool UnwindBlock(const Config &config, CValidationState &state, | ||||
if (invalidate) { | if (invalidate) { | ||||
InvalidChainFound(pindex); | InvalidChainFound(pindex); | ||||
} | } | ||||
uiInterface.NotifyBlockTip(IsInitialBlockDownload(), pindex->pprev); | uiInterface.NotifyBlockTip(IsInitialBlockDownload(), pindex->pprev); | ||||
return true; | return true; | ||||
} | } | ||||
bool FinalizeBlock(const Config &config, CValidationState &state, | |||||
CBlockIndex *pindex) { | |||||
AssertLockHeld(cs_main); | |||||
if (pindex->nStatus.isInvalid()) { | |||||
// We try to finalize an invalid block. | |||||
return state.DoS(100, | |||||
error("%s: Trying to finalize invalid block %s", | |||||
__func__, pindex->GetBlockHash().ToString()), | |||||
REJECT_INVALID, "finalize-invalid-block"); | |||||
} | |||||
// Check that the request is consistent with current finalization. | |||||
if (pindexFinalized && !AreOnTheSameFork(pindex, pindexFinalized)) { | |||||
return state.DoS( | |||||
20, error("%s: Trying to finalize block %s which conflicts " | |||||
"with already finalized block", | |||||
__func__, pindex->GetBlockHash().ToString()), | |||||
REJECT_AGAINST_FINALIZED, "bad-fork-prior-finalized"); | |||||
} | |||||
// We have a valid candidate, make sure it is not parked. | |||||
pindexFinalized = pindex; | |||||
if (pindex->nStatus.isOnParkedChain()) { | |||||
UnparkBlock(pindex); | |||||
} | |||||
// If the finalized block is not on the active chain, we need to rewind. | |||||
if (!AreOnTheSameFork(pindex, chainActive.Tip())) { | |||||
const CBlockIndex *pindexFork = chainActive.FindFork(pindex); | |||||
CBlockIndex *pindexToInvalidate = | |||||
chainActive.Tip()->GetAncestor(pindexFork->nHeight + 1); | |||||
return InvalidateBlock(config, state, pindexToInvalidate); | |||||
} | |||||
return true; | |||||
} | |||||
bool InvalidateBlock(const Config &config, CValidationState &state, | bool InvalidateBlock(const Config &config, CValidationState &state, | ||||
CBlockIndex *pindex) { | CBlockIndex *pindex) { | ||||
return UnwindBlock(config, state, pindex, true); | return UnwindBlock(config, state, pindex, true); | ||||
} | } | ||||
bool ParkBlock(const Config &config, CValidationState &state, | bool ParkBlock(const Config &config, CValidationState &state, | ||||
CBlockIndex *pindex) { | CBlockIndex *pindex) { | ||||
return UnwindBlock(config, state, pindex, false); | return UnwindBlock(config, state, pindex, false); | ||||
▲ Show 20 Lines • Show All 655 Lines • ▼ Show 20 Lines | if (hash != chainparams.GetConsensus().hashGenesisBlock) { | ||||
} | } | ||||
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; | |||||
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; | CBlockIndex *pindexPrev = (*mi).second; | ||||
assert(pindexPrev); | |||||
if (pindexPrev->nStatus.isInvalid()) { | 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); | |||||
if (fCheckpointsEnabled && | if (fCheckpointsEnabled && | ||||
!CheckIndexAgainstCheckpoint(pindexPrev, state, chainparams, | !CheckIndexAgainstCheckpoint(pindexPrev, state, chainparams, | ||||
hash)) { | hash)) { | ||||
return error("%s: CheckIndexAgainstCheckpoint(): %s", __func__, | return error("%s: CheckIndexAgainstCheckpoint(): %s", __func__, | ||||
state.GetRejectReason().c_str()); | state.GetRejectReason().c_str()); | ||||
} | } | ||||
if (!ContextualCheckBlockHeader(config, block, state, pindexPrev, | if (!ContextualCheckBlockHeader(config, block, state, pindexPrev, | ||||
GetAdjustedTime())) { | GetAdjustedTime())) { | ||||
return error("%s: Consensus::ContextualCheckBlockHeader: %s, %s", | return error("%s: Consensus::ContextualCheckBlockHeader: %s, %s", | ||||
__func__, hash.ToString(), FormatStateMessage(state)); | __func__, hash.ToString(), FormatStateMessage(state)); | ||||
} | } | ||||
} | } | ||||
if (pindex == nullptr) { | if (pindex == nullptr) { | ||||
pindex = AddToBlockIndex(block); | pindex = AddToBlockIndex(block); | ||||
} | } | ||||
if (ppindex) { | if (ppindex) { | ||||
*ppindex = pindex; | *ppindex = pindex; | ||||
} | } | ||||
CheckBlockIndex(chainparams.GetConsensus()); | CheckBlockIndex(chainparams.GetConsensus()); | ||||
return true; | return true; | ||||
} | } | ||||
// Exposed wrapper for AcceptBlockHeader | // Exposed wrapper for AcceptBlockHeader | ||||
bool ProcessNewBlockHeaders(const Config &config, | bool ProcessNewBlockHeaders(const Config &config, | ||||
const std::vector<CBlockHeader> &headers, | const std::vector<CBlockHeader> &headers, | ||||
CValidationState &state, | CValidationState &state, | ||||
const CBlockIndex **ppindex, | const CBlockIndex **ppindex, | ||||
▲ Show 20 Lines • Show All 1,802 Lines • Show Last 20 Lines |
Was it something we need to have done independently from the change introduced in this diff?