Changeset View
Changeset View
Standalone View
Standalone View
src/validation.cpp
Show First 20 Lines • Show All 87 Lines • ▼ Show 20 Lines | private: | ||||
/** | /** | ||||
* the ChainState CriticalSection | * the ChainState CriticalSection | ||||
* A lock that must be held when modifying this ChainState - held in | * A lock that must be held when modifying this ChainState - held in | ||||
* ActivateBestChain() | * ActivateBestChain() | ||||
*/ | */ | ||||
CCriticalSection m_cs_chainstate; | CCriticalSection m_cs_chainstate; | ||||
/** | |||||
* Every received block is assigned a unique and increasing identifier, so | |||||
* we know which one to give priority in case of a fork. | |||||
* Blocks loaded from disk are assigned id 0, so start the counter at 1. | |||||
*/ | |||||
std::atomic<int32_t> nBlockSequenceId{1}; | |||||
/** Decreasing counter (used by subsequent preciousblock calls). */ | |||||
int32_t nBlockReverseSequenceId = -1; | |||||
/** chainwork for the last block that preciousblock has been applied to. */ | |||||
arith_uint256 nLastPreciousChainwork = 0; | |||||
/** | |||||
* In order to efficiently track invalidity of headers, we keep the set of | |||||
* blocks which we tried to connect and found to be invalid here (ie which | |||||
* were set to BLOCK_FAILED_VALID since the last restart). We can then | |||||
* walk this set and check if a new header is a descendant of something in | |||||
* this set, preventing us from having to walk mapBlockIndex when we try | |||||
* to connect a bad block and fail. | |||||
* | |||||
* While this is more complicated than marking everything which descends | |||||
* from an invalid block as invalid at the time we discover it to be | |||||
* invalid, doing so would require walking all of mapBlockIndex to find all | |||||
* descendants. Since this case should be very rare, keeping track of all | |||||
* BLOCK_FAILED_VALID blocks in a set should be just fine and work just as | |||||
* well. | |||||
* | |||||
* Because we already walk mapBlockIndex in height-order at startup, we go | |||||
* ahead and mark descendants of invalid blocks as FAILED_CHILD at that | |||||
* time, instead of putting things in this set. | |||||
*/ | |||||
std::set<CBlockIndex *> g_failed_blocks; | |||||
public: | public: | ||||
CChain chainActive; | CChain chainActive; | ||||
BlockMap mapBlockIndex; | BlockMap mapBlockIndex; | ||||
std::multimap<CBlockIndex *, CBlockIndex *> mapBlocksUnlinked; | std::multimap<CBlockIndex *, CBlockIndex *> mapBlocksUnlinked; | ||||
CBlockIndex *pindexBestInvalid = nullptr; | CBlockIndex *pindexBestInvalid = nullptr; | ||||
CBlockIndex *pindexBestParked = nullptr; | CBlockIndex *pindexBestParked = nullptr; | ||||
bool LoadBlockIndex(const Config &config, CBlockTreeDB &blocktree); | bool LoadBlockIndex(const Config &config, CBlockTreeDB &blocktree); | ||||
▲ Show 20 Lines • Show All 130 Lines • ▼ Show 20 Lines | |||||
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. | ||||
*/ | */ | ||||
bool fCheckForPruning = false; | bool fCheckForPruning = false; | ||||
/** | |||||
* Every received block is assigned a unique and increasing identifier, so we | |||||
* know which one to give priority in case of a fork. | |||||
* Blocks loaded from disk are assigned id 0, so start the counter at 1. | |||||
*/ | |||||
std::atomic<int32_t> nBlockSequenceId{1}; | |||||
/** Decreasing counter (used by subsequent preciousblock calls). */ | |||||
int32_t nBlockReverseSequenceId = -1; | |||||
/** chainwork for the last block that preciousblock has been applied to. */ | |||||
arith_uint256 nLastPreciousChainwork = 0; | |||||
/** | |||||
* In order to efficiently track invalidity of headers, we keep the set of | |||||
* blocks which we tried to connect and found to be invalid here (ie which | |||||
* were set to BLOCK_FAILED_VALID since the last restart). We can then | |||||
* walk this set and check if a new header is a descendant of something in | |||||
* this set, preventing us from having to walk mapBlockIndex when we try | |||||
* to connect a bad block and fail. | |||||
* | |||||
* While this is more complicated than marking everything which descends | |||||
* from an invalid block as invalid at the time we discover it to be | |||||
* invalid, doing so would require walking all of mapBlockIndex to find all | |||||
* descendants. Since this case should be very rare, keeping track of all | |||||
* BLOCK_FAILED_VALID blocks in a set should be just fine and work just as | |||||
* well. | |||||
* | |||||
* Because we already walk mapBlockIndex in height-order at startup, we go | |||||
* ahead and mark descendants of invalid blocks as FAILED_CHILD at that time, | |||||
* instead of putting things in this set. | |||||
*/ | |||||
std::set<CBlockIndex *> g_failed_blocks; | |||||
/** Dirty block index entries. */ | /** Dirty block index entries. */ | ||||
std::set<const CBlockIndex *> setDirtyBlockIndex; | std::set<const CBlockIndex *> setDirtyBlockIndex; | ||||
/** Dirty block file entries. */ | /** Dirty block file entries. */ | ||||
std::set<int> setDirtyFileInfo; | std::set<int> setDirtyFileInfo; | ||||
} // namespace | } // namespace | ||||
CBlockIndex *FindForkInGlobalIndex(const CChain &chain, | CBlockIndex *FindForkInGlobalIndex(const CChain &chain, | ||||
▲ Show 20 Lines • Show All 1,826 Lines • ▼ Show 20 Lines | |||||
void PruneAndFlush() { | void PruneAndFlush() { | ||||
CValidationState state; | CValidationState state; | ||||
fCheckForPruning = true; | fCheckForPruning = true; | ||||
const CChainParams &chainparams = Params(); | const CChainParams &chainparams = Params(); | ||||
FlushStateToDisk(chainparams, state, FlushStateMode::NONE); | FlushStateToDisk(chainparams, state, FlushStateMode::NONE); | ||||
} | } | ||||
/** | /** Check warning conditions and do some notifications on new chain tip set. */ | ||||
* Update chainActive and related internal data structures when adding a new | |||||
* block to the chain tip. | |||||
*/ | |||||
static void UpdateTip(const Config &config, CBlockIndex *pindexNew) { | static void UpdateTip(const Config &config, CBlockIndex *pindexNew) { | ||||
chainActive.SetTip(pindexNew); | |||||
// New best block | // New best block | ||||
g_mempool.AddTransactionsUpdated(1); | g_mempool.AddTransactionsUpdated(1); | ||||
{ | { | ||||
LOCK(g_best_block_mutex); | LOCK(g_best_block_mutex); | ||||
g_best_block = pindexNew->GetBlockHash(); | g_best_block = pindexNew->GetBlockHash(); | ||||
g_best_block_cv.notify_all(); | g_best_block_cv.notify_all(); | ||||
} | } | ||||
LogPrintf("%s: new best=%s height=%d version=0x%08x log2_work=%.8g tx=%lu " | LogPrintf( | ||||
"%s: new best=%s height=%d version=0x%08x log2_work=%.8g tx=%lu " | |||||
"date='%s' progress=%f cache=%.1fMiB(%utxo)\n", | "date='%s' progress=%f cache=%.1fMiB(%utxo)\n", | ||||
__func__, chainActive.Tip()->GetBlockHash().ToString(), | __func__, pindexNew->GetBlockHash().ToString(), pindexNew->nHeight, | ||||
chainActive.Height(), chainActive.Tip()->nVersion, | pindexNew->nVersion, log(pindexNew->nChainWork.getdouble()) / log(2.0), | ||||
log(chainActive.Tip()->nChainWork.getdouble()) / log(2.0), | (unsigned long)pindexNew->nChainTx, | ||||
(unsigned long)chainActive.Tip()->nChainTx, | FormatISO8601DateTime(pindexNew->GetBlockTime()), | ||||
FormatISO8601DateTime(chainActive.Tip()->GetBlockTime()), | GuessVerificationProgress(config.GetChainParams().TxData(), pindexNew), | ||||
GuessVerificationProgress(config.GetChainParams().TxData(), | |||||
chainActive.Tip()), | |||||
pcoinsTip->DynamicMemoryUsage() * (1.0 / (1 << 20)), | pcoinsTip->DynamicMemoryUsage() * (1.0 / (1 << 20)), | ||||
pcoinsTip->GetCacheSize()); | pcoinsTip->GetCacheSize()); | ||||
} | } | ||||
/** | /** | ||||
* Disconnect chainActive's tip. | * Disconnect chainActive's tip. | ||||
* After calling, the mempool will be in an inconsistent state, with | * After calling, the mempool will be in an inconsistent state, with | ||||
* transactions from disconnected blocks being added to disconnectpool. You | * transactions from disconnected blocks being added to disconnectpool. You | ||||
* should make the mempool consistent again by calling updateMempoolForReorg. | * should make the mempool consistent again by calling updateMempoolForReorg. | ||||
* with cs_main held. | * with cs_main held. | ||||
▲ Show 20 Lines • Show All 55 Lines • ▼ Show 20 Lines | if (disconnectpool) { | ||||
disconnectpool->addForBlock(block.vtx); | disconnectpool->addForBlock(block.vtx); | ||||
} | } | ||||
// If the tip is finalized, then undo it. | // If the tip is finalized, then undo it. | ||||
if (pindexFinalized == pindexDelete) { | if (pindexFinalized == pindexDelete) { | ||||
pindexFinalized = pindexDelete->pprev; | pindexFinalized = pindexDelete->pprev; | ||||
} | } | ||||
chainActive.SetTip(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 255 Lines • ▼ Show 20 Lines | if (pindexNew->pprev != nullptr && | ||||
GetNextBlockScriptFlags(config, pindexNew) != | GetNextBlockScriptFlags(config, pindexNew) != | ||||
GetNextBlockScriptFlags(config, pindexNew->pprev)) { | GetNextBlockScriptFlags(config, pindexNew->pprev)) { | ||||
LogPrint(BCLog::MEMPOOL, | LogPrint(BCLog::MEMPOOL, | ||||
"Disconnecting mempool due to acceptance of upgrade block\n"); | "Disconnecting mempool due to acceptance of upgrade block\n"); | ||||
disconnectpool.importMempool(g_mempool); | disconnectpool.importMempool(g_mempool); | ||||
} | } | ||||
// Update chainActive & related variables. | // Update chainActive & related variables. | ||||
chainActive.SetTip(pindexNew); | |||||
UpdateTip(config, pindexNew); | UpdateTip(config, pindexNew); | ||||
int64_t nTime6 = GetTimeMicros(); | int64_t nTime6 = GetTimeMicros(); | ||||
nTimePostConnect += nTime6 - nTime5; | nTimePostConnect += nTime6 - nTime5; | ||||
nTimeTotal += nTime6 - nTime1; | nTimeTotal += nTime6 - nTime1; | ||||
LogPrint(BCLog::BENCH, | LogPrint(BCLog::BENCH, | ||||
" - Connect postprocess: %.2fms [%.2fs (%.2fms/blk)]\n", | " - Connect postprocess: %.2fms [%.2fs (%.2fms/blk)]\n", | ||||
(nTime6 - nTime5) * MILLI, nTimePostConnect * MICRO, | (nTime6 - nTime5) * MILLI, nTimePostConnect * MICRO, | ||||
▲ Show 20 Lines • Show All 2,368 Lines • ▼ Show 20 Lines | bool RewindBlockIndex(const Config &config) { | ||||
} | } | ||||
return true; | 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; | |||||
g_failed_blocks.clear(); | |||||
setBlockIndexCandidates.clear(); | setBlockIndexCandidates.clear(); | ||||
} | } | ||||
// 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); | ||||
pindexFinalized = nullptr; | pindexFinalized = nullptr; | ||||
pindexBestInvalid = nullptr; | pindexBestInvalid = nullptr; | ||||
pindexBestParked = nullptr; | pindexBestParked = nullptr; | ||||
pindexBestHeader = nullptr; | pindexBestHeader = nullptr; | ||||
pindexBestForkTip = nullptr; | pindexBestForkTip = nullptr; | ||||
pindexBestForkBase = nullptr; | pindexBestForkBase = nullptr; | ||||
g_mempool.clear(); | g_mempool.clear(); | ||||
mapBlocksUnlinked.clear(); | mapBlocksUnlinked.clear(); | ||||
vinfoBlockFile.clear(); | vinfoBlockFile.clear(); | ||||
nLastBlockFile = 0; | nLastBlockFile = 0; | ||||
nBlockSequenceId = 1; | |||||
setDirtyBlockIndex.clear(); | setDirtyBlockIndex.clear(); | ||||
g_failed_blocks.clear(); | |||||
setDirtyFileInfo.clear(); | setDirtyFileInfo.clear(); | ||||
for (BlockMap::value_type &entry : mapBlockIndex) { | for (BlockMap::value_type &entry : mapBlockIndex) { | ||||
delete entry.second; | delete entry.second; | ||||
} | } | ||||
mapBlockIndex.clear(); | mapBlockIndex.clear(); | ||||
fHavePruned = false; | fHavePruned = false; | ||||
▲ Show 20 Lines • Show All 732 Lines • Show Last 20 Lines |