Changeset View
Changeset View
Standalone View
Standalone View
src/validation.cpp
Show First 20 Lines • Show All 109 Lines • ▼ Show 20 Lines | |||||
/** Constant stuff for coinbase transactions we create: */ | /** Constant stuff for coinbase transactions we create: */ | ||||
CScript COINBASE_FLAGS; | CScript COINBASE_FLAGS; | ||||
// Internal stuff | // Internal stuff | ||||
namespace { | namespace { | ||||
CBlockIndex *pindexBestInvalid = nullptr; | CBlockIndex *pindexBestInvalid = nullptr; | ||||
CBlockIndex *pindexBestParked = nullptr; | CBlockIndex *pindexBestParked = nullptr; | ||||
/** | |||||
* The best finalized block. | |||||
* This block cannot be reorged in any way except by explicit user action. | |||||
*/ | |||||
CBlockIndex const *&pindexFinalized = ::ChainstateActive().pindexFinalized; | |||||
RecursiveMutex cs_LastBlockFile; | RecursiveMutex cs_LastBlockFile; | ||||
std::vector<CBlockFileInfo> vinfoBlockFile; | std::vector<CBlockFileInfo> vinfoBlockFile; | ||||
int nLastBlockFile = 0; | int nLastBlockFile = 0; | ||||
/** | /** | ||||
* Global flag to indicate we should check to see if there are block/undo files | * Global flag to indicate we should check to see if there are block/undo files | ||||
* that should be deleted. Set on startup or if we allocate more file space when | * that should be deleted. Set on startup or if we allocate more file space when | ||||
* we're in prune mode. | * we're in prune mode. | ||||
▲ Show 20 Lines • Show All 804 Lines • ▼ Show 20 Lines | void CChainState::InvalidChainFound(CBlockIndex *pindexNew) { | ||||
if (!pindexBestInvalid || | if (!pindexBestInvalid || | ||||
pindexNew->nChainWork > pindexBestInvalid->nChainWork) { | pindexNew->nChainWork > pindexBestInvalid->nChainWork) { | ||||
pindexBestInvalid = pindexNew; | pindexBestInvalid = pindexNew; | ||||
} | } | ||||
// If the invalid chain found is supposed to be finalized, we need to move | // If the invalid chain found is supposed to be finalized, we need to move | ||||
// back the finalization point. | // back the finalization point. | ||||
if (IsBlockFinalized(pindexNew)) { | if (IsBlockFinalized(pindexNew)) { | ||||
pindexFinalized = pindexNew->pprev; | m_finalizedBlockIndex = pindexNew->pprev; | ||||
} | } | ||||
LogPrintf("%s: invalid block=%s height=%d log2_work=%.8g date=%s\n", | LogPrintf("%s: invalid block=%s height=%d log2_work=%.8g date=%s\n", | ||||
__func__, pindexNew->GetBlockHash().ToString(), | __func__, pindexNew->GetBlockHash().ToString(), | ||||
pindexNew->nHeight, | pindexNew->nHeight, | ||||
log(pindexNew->nChainWork.getdouble()) / log(2.0), | log(pindexNew->nChainWork.getdouble()) / log(2.0), | ||||
FormatISO8601DateTime(pindexNew->GetBlockTime())); | FormatISO8601DateTime(pindexNew->GetBlockTime())); | ||||
CBlockIndex *tip = ::ChainActive().Tip(); | CBlockIndex *tip = ::ChainActive().Tip(); | ||||
▲ Show 20 Lines • Show All 1,204 Lines • ▼ Show 20 Lines | if (pindexDelete->pprev != nullptr && | ||||
g_mempool.clear(); | g_mempool.clear(); | ||||
} | } | ||||
if (disconnectpool) { | if (disconnectpool) { | ||||
disconnectpool->addForBlock(block.vtx, g_mempool); | disconnectpool->addForBlock(block.vtx, g_mempool); | ||||
} | } | ||||
// If the tip is finalized, then undo it. | // If the tip is finalized, then undo it. | ||||
if (pindexFinalized == pindexDelete) { | if (finalizedBlockIndex() == pindexDelete) { | ||||
pindexFinalized = pindexDelete->pprev; | m_finalizedBlockIndex = pindexDelete->pprev; | ||||
} | } | ||||
m_chain.SetTip(pindexDelete->pprev); | m_chain.SetTip(pindexDelete->pprev); | ||||
// Update ::ChainActive() and related variables. | // Update ::ChainActive() and related variables. | ||||
UpdateTip(params, pindexDelete->pprev); | UpdateTip(params, 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: | ||||
▲ Show 20 Lines • Show All 84 Lines • ▼ Show 20 Lines | if (pindex->nStatus.isInvalid()) { | ||||
// We try to finalize an invalid block. | // We try to finalize an invalid block. | ||||
LogPrintf("ERROR: %s: Trying to finalize invalid block %s\n", __func__, | LogPrintf("ERROR: %s: Trying to finalize invalid block %s\n", __func__, | ||||
pindex->GetBlockHash().ToString()); | pindex->GetBlockHash().ToString()); | ||||
return state.Invalid(BlockValidationResult::BLOCK_CACHED_INVALID, | return state.Invalid(BlockValidationResult::BLOCK_CACHED_INVALID, | ||||
REJECT_INVALID, "finalize-invalid-block"); | REJECT_INVALID, "finalize-invalid-block"); | ||||
} | } | ||||
// Check that the request is consistent with current finalization. | // Check that the request is consistent with current finalization. | ||||
if (pindexFinalized && !AreOnTheSameFork(pindex, pindexFinalized)) { | if (finalizedBlockIndex() && | ||||
!AreOnTheSameFork(pindex, finalizedBlockIndex())) { | |||||
LogPrintf("ERROR: %s: Trying to finalize block %s which conflicts with " | LogPrintf("ERROR: %s: Trying to finalize block %s which conflicts with " | ||||
"already finalized block\n", | "already finalized block\n", | ||||
__func__, pindex->GetBlockHash().ToString()); | __func__, pindex->GetBlockHash().ToString()); | ||||
return state.Invalid(BlockValidationResult::BLOCK_FINALIZATION, | return state.Invalid(BlockValidationResult::BLOCK_FINALIZATION, | ||||
REJECT_AGAINST_FINALIZED, | REJECT_AGAINST_FINALIZED, | ||||
"bad-fork-prior-finalized"); | "bad-fork-prior-finalized"); | ||||
} | } | ||||
if (IsBlockFinalized(pindex)) { | if (IsBlockFinalized(pindex)) { | ||||
// The block is already finalized. | // The block is already finalized. | ||||
return true; | return true; | ||||
} | } | ||||
// We have a new block to finalize. | // We have a new block to finalize. | ||||
pindexFinalized = pindex; | m_finalizedBlockIndex = pindex; | ||||
return true; | return true; | ||||
} | } | ||||
static const CBlockIndex *FindBlockToFinalize(const Config &config, | static const CBlockIndex *FindBlockToFinalize(const Config &config, | ||||
CBlockIndex *pindexNew) | CBlockIndex *pindexNew) | ||||
EXCLUSIVE_LOCKS_REQUIRED(cs_main) { | EXCLUSIVE_LOCKS_REQUIRED(cs_main) { | ||||
AssertLockHeld(cs_main); | AssertLockHeld(cs_main); | ||||
Show All 15 Lines | static const CBlockIndex *FindBlockToFinalize(const Config &config, | ||||
// finalization should be avoided. Header receive time is not saved to disk | // finalization should be avoided. Header receive time is not saved to disk | ||||
// and so cannot be anterior to startup time. | // and so cannot be anterior to startup time. | ||||
if (now < (GetStartupTime() + finalizationdelay)) { | if (now < (GetStartupTime() + finalizationdelay)) { | ||||
return nullptr; | return nullptr; | ||||
} | } | ||||
// While our candidate is not eligible (finalization delay not expired), try | // While our candidate is not eligible (finalization delay not expired), try | ||||
// the previous one. | // the previous one. | ||||
while (pindex && (pindex != pindexFinalized)) { | while (pindex && (pindex != ::ChainstateActive().finalizedBlockIndex())) { | ||||
// Check that the block to finalize is known for a long enough time. | // Check that the block to finalize is known for a long enough time. | ||||
// This test will ensure that an attacker could not cause a block to | // This test will ensure that an attacker could not cause a block to | ||||
// finalize by forking the chain with a depth > maxreorgdepth. | // finalize by forking the chain with a depth > maxreorgdepth. | ||||
// If the block is loaded from disk, header receive time is 0 and the | // If the block is loaded from disk, header receive time is 0 and the | ||||
// block will be finalized. This is safe because the delay since the | // block will be finalized. This is safe because the delay since the | ||||
// node startup is already expired. | // node startup is already expired. | ||||
auto headerReceivedTime = pindex->GetHeaderReceivedTime(); | auto headerReceivedTime = pindex->GetHeaderReceivedTime(); | ||||
▲ Show 20 Lines • Show All 153 Lines • ▼ Show 20 Lines | do { | ||||
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 | // If this block will cause a finalized block to be reorged, then we | ||||
// mark it as invalid. | // mark it as invalid. | ||||
if (pindexFinalized && !AreOnTheSameFork(pindexNew, pindexFinalized)) { | if (finalizedBlockIndex() && | ||||
!AreOnTheSameFork(pindexNew, finalizedBlockIndex())) { | |||||
LogPrintf("Mark block %s invalid because it forks prior to the " | LogPrintf("Mark block %s invalid because it forks prior to the " | ||||
"finalization point %d.\n", | "finalization point %d.\n", | ||||
pindexNew->GetBlockHash().ToString(), | pindexNew->GetBlockHash().ToString(), | ||||
pindexFinalized->nHeight); | finalizedBlockIndex()->nHeight); | ||||
pindexNew->nStatus = pindexNew->nStatus.withFailed(); | pindexNew->nStatus = pindexNew->nStatus.withFailed(); | ||||
InvalidChainFound(pindexNew); | InvalidChainFound(pindexNew); | ||||
} | } | ||||
const CBlockIndex *pindexFork = m_chain.FindFork(pindexNew); | const CBlockIndex *pindexFork = m_chain.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 | ||||
▲ Show 20 Lines • Show All 721 Lines • ▼ Show 20 Lines | CBlockIndex *pindexToInvalidate = nullptr; | ||||
} | } | ||||
} // end of locked cs_main scope | } // end of locked cs_main scope | ||||
// ... therefore, we invalidate the block on the active chain that comes | // ... therefore, we invalidate the block on the active chain that comes | ||||
// immediately after it | // immediately after it | ||||
return UnwindBlock(config, state, pindexToInvalidate, | return UnwindBlock(config, state, pindexToInvalidate, | ||||
true /* invalidating */); | true /* invalidating */); | ||||
} | } | ||||
/** Return the currently finalized block index. */ | |||||
const CBlockIndex *CChainState::finalizedBlockIndex() const { | |||||
AssertLockHeld(cs_main); | |||||
return m_finalizedBlockIndex; | |||||
} | |||||
template <typename F> | template <typename F> | ||||
bool CChainState::UpdateFlagsForBlock(CBlockIndex *pindexBase, | bool CChainState::UpdateFlagsForBlock(CBlockIndex *pindexBase, | ||||
CBlockIndex *pindex, F f) { | CBlockIndex *pindex, F f) { | ||||
BlockStatus newStatus = f(pindex->nStatus); | BlockStatus newStatus = f(pindex->nStatus); | ||||
if (pindex->nStatus != newStatus && | if (pindex->nStatus != newStatus && | ||||
(!pindexBase || | (!pindexBase || | ||||
pindex->GetAncestor(pindexBase->nHeight) == pindexBase)) { | pindex->GetAncestor(pindexBase->nHeight) == pindexBase)) { | ||||
▲ Show 20 Lines • Show All 46 Lines • ▼ Show 20 Lines | void CChainState::UpdateFlags(CBlockIndex *pindex, CBlockIndex *&pindexReset, | ||||
} | } | ||||
} | } | ||||
void CChainState::ResetBlockFailureFlags(CBlockIndex *pindex) { | void CChainState::ResetBlockFailureFlags(CBlockIndex *pindex) { | ||||
AssertLockHeld(cs_main); | AssertLockHeld(cs_main); | ||||
// In case we are reconsidering something before the finalization point, | // In case we are reconsidering something before the finalization point, | ||||
// move the finalization point to the last common ancestor. | // move the finalization point to the last common ancestor. | ||||
if (pindexFinalized) { | if (finalizedBlockIndex()) { | ||||
pindexFinalized = LastCommonAncestor(pindex, pindexFinalized); | m_finalizedBlockIndex = | ||||
LastCommonAncestor(pindex, finalizedBlockIndex()); | |||||
} | } | ||||
UpdateFlags( | UpdateFlags( | ||||
pindex, pindexBestInvalid, | pindex, pindexBestInvalid, | ||||
[](const BlockStatus status) { | [](const BlockStatus status) { | ||||
return status.withClearedFailureFlags(); | return status.withClearedFailureFlags(); | ||||
}, | }, | ||||
[](const BlockStatus status) { | [](const BlockStatus status) { | ||||
Show All 29 Lines | void UnparkBlockAndChildren(CBlockIndex *pindex) { | ||||
return ::ChainstateActive().UnparkBlockImpl(pindex, true); | return ::ChainstateActive().UnparkBlockImpl(pindex, true); | ||||
} | } | ||||
void UnparkBlock(CBlockIndex *pindex) { | void UnparkBlock(CBlockIndex *pindex) { | ||||
return ::ChainstateActive().UnparkBlockImpl(pindex, false); | return ::ChainstateActive().UnparkBlockImpl(pindex, false); | ||||
} | } | ||||
const CBlockIndex *GetFinalizedBlock() { | const CBlockIndex *GetFinalizedBlock() { | ||||
AssertLockHeld(cs_main); | return ::ChainstateActive().finalizedBlockIndex(); | ||||
return pindexFinalized; | |||||
} | } | ||||
bool IsBlockFinalized(const CBlockIndex *pindex) { | bool IsBlockFinalized(const CBlockIndex *pindex) { | ||||
AssertLockHeld(cs_main); | AssertLockHeld(cs_main); | ||||
return pindexFinalized && | auto finalizedBlockIndex = ::ChainstateActive().finalizedBlockIndex(); | ||||
pindexFinalized->GetAncestor(pindex->nHeight) == pindex; | return finalizedBlockIndex && | ||||
finalizedBlockIndex->GetAncestor(pindex->nHeight) == pindex; | |||||
} | } | ||||
CBlockIndex *BlockManager::AddToBlockIndex(const CBlockHeader &block) { | CBlockIndex *BlockManager::AddToBlockIndex(const CBlockHeader &block) { | ||||
AssertLockHeld(cs_main); | AssertLockHeld(cs_main); | ||||
// Check for duplicate | // Check for duplicate | ||||
BlockHash hash = block.GetHash(); | BlockHash hash = block.GetHash(); | ||||
BlockMap::iterator it = m_block_index.find(hash); | BlockMap::iterator it = m_block_index.find(hash); | ||||
▲ Show 20 Lines • Show All 1,661 Lines • ▼ Show 20 Lines | bool ReplayBlocks(const Consensus::Params ¶ms, CCoinsView *view) { | ||||
return ::ChainstateActive().ReplayBlocks(params, view); | return ::ChainstateActive().ReplayBlocks(params, view); | ||||
} | } | ||||
// 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; | ||||
setBlockIndexCandidates.clear(); | setBlockIndexCandidates.clear(); | ||||
// Do not point to CBlockIndex that has been free'd | |||||
m_finalizedBlockIndex = nullptr; | |||||
} | } | ||||
// May NOT be used after any connections are up as much | // May NOT be used after any connections are up as much | ||||
// of the peer-processing logic assumes a consistent | // of the peer-processing logic assumes a consistent | ||||
// block index state | // block index state | ||||
void UnloadBlockIndex() { | void UnloadBlockIndex() { | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
::ChainActive().SetTip(nullptr); | ::ChainActive().SetTip(nullptr); | ||||
g_blockman.Unload(); | g_blockman.Unload(); | ||||
pindexFinalized = nullptr; | |||||
pindexBestInvalid = nullptr; | pindexBestInvalid = nullptr; | ||||
pindexBestParked = nullptr; | pindexBestParked = nullptr; | ||||
pindexBestHeader = nullptr; | pindexBestHeader = nullptr; | ||||
pindexBestForkTip = nullptr; | pindexBestForkTip = nullptr; | ||||
pindexBestForkBase = nullptr; | pindexBestForkBase = nullptr; | ||||
ResetASERTAnchorBlockCache(); | ResetASERTAnchorBlockCache(); | ||||
g_mempool.clear(); | g_mempool.clear(); | ||||
vinfoBlockFile.clear(); | vinfoBlockFile.clear(); | ||||
▲ Show 20 Lines • Show All 774 Lines • Show Last 20 Lines |