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); | |||||
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 " | |||||
jasonbcox: `past` -> `prior to` since "past" sounds like a block that is coming after the finalized block | |||||
"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 654 Lines • ▼ Show 20 Lines | if (hash != chainparams.GetConsensus().hashGenesisBlock) { | ||||
return true; | return true; | ||||
} | } | ||||
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 | ||||
jasonbcoxUnsubmitted Not Done Inline ActionsThe changes below this line can go in their own diff and be landed on master. Please do this to make this diff smaller and allow others to work on the code that is most improved. jasonbcox: The changes below this line can go in their own diff and be landed on master. Please do this… | |||||
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 |
past -> prior to since "past" sounds like a block that is coming after the finalized block