Changeset View
Changeset View
Standalone View
Standalone View
src/validation.cpp
Show First 20 Lines • Show All 167 Lines • ▼ Show 20 Lines | CBlockIndex *FindForkInGlobalIndex(const CChain &chain, | ||||
} | } | ||||
return chain.Genesis(); | return chain.Genesis(); | ||||
} | } | ||||
std::unique_ptr<CCoinsViewDB> pcoinsdbview; | std::unique_ptr<CCoinsViewDB> pcoinsdbview; | ||||
std::unique_ptr<CCoinsViewCache> pcoinsTip; | std::unique_ptr<CCoinsViewCache> pcoinsTip; | ||||
std::unique_ptr<CBlockTreeDB> pblocktree; | std::unique_ptr<CBlockTreeDB> pblocktree; | ||||
enum FlushStateMode { | enum class FlushStateMode { NONE, IF_NEEDED, PERIODIC, ALWAYS }; | ||||
FLUSH_STATE_NONE, | |||||
FLUSH_STATE_IF_NEEDED, | |||||
FLUSH_STATE_PERIODIC, | |||||
FLUSH_STATE_ALWAYS | |||||
}; | |||||
// See definition for documentation | // See definition for documentation | ||||
static bool FlushStateToDisk(const CChainParams &chainParams, | static bool FlushStateToDisk(const CChainParams &chainParams, | ||||
CValidationState &state, FlushStateMode mode, | CValidationState &state, FlushStateMode mode, | ||||
int nManualPruneHeight = 0); | int nManualPruneHeight = 0); | ||||
static void FindFilesToPruneManual(std::set<int> &setFilesToPrune, | static void FindFilesToPruneManual(std::set<int> &setFilesToPrune, | ||||
int nManualPruneHeight); | int nManualPruneHeight); | ||||
static void FindFilesToPrune(std::set<int> &setFilesToPrune, | static void FindFilesToPrune(std::set<int> &setFilesToPrune, | ||||
▲ Show 20 Lines • Show All 565 Lines • ▼ Show 20 Lines | if (!res) { | ||||
for (const COutPoint &outpoint : coins_to_uncache) { | for (const COutPoint &outpoint : coins_to_uncache) { | ||||
pcoinsTip->Uncache(outpoint); | pcoinsTip->Uncache(outpoint); | ||||
} | } | ||||
} | } | ||||
// After we've (potentially) uncached entries, ensure our coins cache is | // After we've (potentially) uncached entries, ensure our coins cache is | ||||
// still within its size limits | // still within its size limits | ||||
CValidationState stateDummy; | CValidationState stateDummy; | ||||
FlushStateToDisk(config.GetChainParams(), stateDummy, FLUSH_STATE_PERIODIC); | FlushStateToDisk(config.GetChainParams(), stateDummy, | ||||
FlushStateMode::PERIODIC); | |||||
return res; | return res; | ||||
} | } | ||||
bool AcceptToMemoryPool(const Config &config, CTxMemPool &pool, | bool AcceptToMemoryPool(const Config &config, CTxMemPool &pool, | ||||
CValidationState &state, const CTransactionRef &tx, | CValidationState &state, const CTransactionRef &tx, | ||||
bool fLimitFree, bool *pfMissingInputs, | bool fLimitFree, bool *pfMissingInputs, | ||||
bool fOverrideMempoolLimit, const Amount nAbsurdFee) { | bool fOverrideMempoolLimit, const Amount nAbsurdFee) { | ||||
return AcceptToMemoryPoolWithTime(config, pool, state, tx, fLimitFree, | return AcceptToMemoryPoolWithTime(config, pool, state, tx, fLimitFree, | ||||
▲ Show 20 Lines • Show All 1,235 Lines • ▼ Show 20 Lines | try { | ||||
gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000; | gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000; | ||||
int64_t cacheSize = pcoinsTip->DynamicMemoryUsage(); | int64_t cacheSize = pcoinsTip->DynamicMemoryUsage(); | ||||
int64_t nTotalSpace = | int64_t nTotalSpace = | ||||
nCoinCacheUsage + | nCoinCacheUsage + | ||||
std::max<int64_t>(nMempoolSizeMax - nMempoolUsage, 0); | std::max<int64_t>(nMempoolSizeMax - nMempoolUsage, 0); | ||||
// The cache is large and we're within 10% and 10 MiB of the limit, | // The cache is large and we're within 10% and 10 MiB of the limit, | ||||
// but we have time now (not in the middle of a block processing). | // but we have time now (not in the middle of a block processing). | ||||
bool fCacheLarge = | bool fCacheLarge = | ||||
mode == FLUSH_STATE_PERIODIC && | mode == FlushStateMode::PERIODIC && | ||||
cacheSize > std::max((9 * nTotalSpace) / 10, | cacheSize > std::max((9 * nTotalSpace) / 10, | ||||
nTotalSpace - | nTotalSpace - | ||||
MAX_BLOCK_COINSDB_USAGE * 1024 * 1024); | MAX_BLOCK_COINSDB_USAGE * 1024 * 1024); | ||||
// The cache is over the limit, we have to write now. | // The cache is over the limit, we have to write now. | ||||
bool fCacheCritical = | bool fCacheCritical = | ||||
mode == FLUSH_STATE_IF_NEEDED && cacheSize > nTotalSpace; | mode == FlushStateMode::IF_NEEDED && cacheSize > nTotalSpace; | ||||
// It's been a while since we wrote the block index to disk. Do this | // It's been a while since we wrote the block index to disk. Do this | ||||
// frequently, so we don't need to redownload after a crash. | // frequently, so we don't need to redownload after a crash. | ||||
bool fPeriodicWrite = | bool fPeriodicWrite = | ||||
mode == FLUSH_STATE_PERIODIC && | mode == FlushStateMode::PERIODIC && | ||||
nNow > nLastWrite + (int64_t)DATABASE_WRITE_INTERVAL * 1000000; | nNow > nLastWrite + (int64_t)DATABASE_WRITE_INTERVAL * 1000000; | ||||
// It's been very long since we flushed the cache. Do this | // It's been very long since we flushed the cache. Do this | ||||
// infrequently, to optimize cache usage. | // infrequently, to optimize cache usage. | ||||
bool fPeriodicFlush = | bool fPeriodicFlush = | ||||
mode == FLUSH_STATE_PERIODIC && | mode == FlushStateMode::PERIODIC && | ||||
nNow > nLastFlush + (int64_t)DATABASE_FLUSH_INTERVAL * 1000000; | nNow > nLastFlush + (int64_t)DATABASE_FLUSH_INTERVAL * 1000000; | ||||
// Combine all conditions that result in a full cache flush. | // Combine all conditions that result in a full cache flush. | ||||
fDoFullFlush = (mode == FLUSH_STATE_ALWAYS) || fCacheLarge || | fDoFullFlush = (mode == FlushStateMode::ALWAYS) || fCacheLarge || | ||||
fCacheCritical || fPeriodicFlush || fFlushForPrune; | fCacheCritical || fPeriodicFlush || fFlushForPrune; | ||||
// Write blocks and block index to disk. | // Write blocks and block index to disk. | ||||
if (fDoFullFlush || fPeriodicWrite) { | if (fDoFullFlush || fPeriodicWrite) { | ||||
// Depend on nMinDiskSpace to ensure we can write block index | // Depend on nMinDiskSpace to ensure we can write block index | ||||
if (!CheckDiskSpace(0)) { | if (!CheckDiskSpace(0)) { | ||||
return state.Error("out of disk space"); | return state.Error("out of disk space"); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 49 Lines • ▼ Show 20 Lines | try { | ||||
if (!pcoinsTip->Flush()) { | if (!pcoinsTip->Flush()) { | ||||
return AbortNode(state, "Failed to write to coin database"); | return AbortNode(state, "Failed to write to coin database"); | ||||
} | } | ||||
nLastFlush = nNow; | nLastFlush = nNow; | ||||
} | } | ||||
} | } | ||||
if (fDoFullFlush || | if (fDoFullFlush || | ||||
((mode == FLUSH_STATE_ALWAYS || mode == FLUSH_STATE_PERIODIC) && | ((mode == FlushStateMode::ALWAYS || | ||||
mode == FlushStateMode::PERIODIC) && | |||||
nNow > | nNow > | ||||
nLastSetChain + (int64_t)DATABASE_WRITE_INTERVAL * 1000000)) { | nLastSetChain + (int64_t)DATABASE_WRITE_INTERVAL * 1000000)) { | ||||
// Update best block in wallet (so we can detect restored wallets). | // Update best block in wallet (so we can detect restored wallets). | ||||
GetMainSignals().SetBestChain(chainActive.GetLocator()); | GetMainSignals().SetBestChain(chainActive.GetLocator()); | ||||
nLastSetChain = nNow; | nLastSetChain = nNow; | ||||
} | } | ||||
} catch (const std::runtime_error &e) { | } catch (const std::runtime_error &e) { | ||||
return AbortNode(state, std::string("System error while flushing: ") + | return AbortNode(state, std::string("System error while flushing: ") + | ||||
e.what()); | e.what()); | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
void FlushStateToDisk() { | void FlushStateToDisk() { | ||||
CValidationState state; | CValidationState state; | ||||
const CChainParams &chainparams = Params(); | const CChainParams &chainparams = Params(); | ||||
FlushStateToDisk(chainparams, state, FLUSH_STATE_ALWAYS); | FlushStateToDisk(chainparams, state, FlushStateMode::ALWAYS); | ||||
} | } | ||||
void PruneAndFlush() { | void PruneAndFlush() { | ||||
CValidationState state; | CValidationState state; | ||||
fCheckForPruning = true; | fCheckForPruning = true; | ||||
const CChainParams &chainparams = Params(); | const CChainParams &chainparams = Params(); | ||||
FlushStateToDisk(chainparams, state, FLUSH_STATE_NONE); | FlushStateToDisk(chainparams, state, FlushStateMode::NONE); | ||||
} | } | ||||
/** | /** | ||||
* Update chainActive and related internal data structures when adding a new | * Update chainActive and related internal data structures when adding a new | ||||
* block to the chain tip. | * block to the chain tip. | ||||
*/ | */ | ||||
static void UpdateTip(const Config &config, CBlockIndex *pindexNew) { | static void UpdateTip(const Config &config, CBlockIndex *pindexNew) { | ||||
const Consensus::Params &consensusParams = | const Consensus::Params &consensusParams = | ||||
▲ Show 20 Lines • Show All 99 Lines • ▼ Show 20 Lines | int64_t nStart = GetTimeMicros(); | ||||
assert(flushed); | assert(flushed); | ||||
} | } | ||||
LogPrint(BCLog::BENCH, "- Disconnect block: %.2fms\n", | LogPrint(BCLog::BENCH, "- Disconnect block: %.2fms\n", | ||||
(GetTimeMicros() - nStart) * MILLI); | (GetTimeMicros() - nStart) * MILLI); | ||||
// Write the chain state to disk, if necessary. | // Write the chain state to disk, if necessary. | ||||
if (!FlushStateToDisk(config.GetChainParams(), state, | if (!FlushStateToDisk(config.GetChainParams(), state, | ||||
FLUSH_STATE_IF_NEEDED)) { | FlushStateMode::IF_NEEDED)) { | ||||
return false; | return false; | ||||
} | } | ||||
// If this block is deactivating a fork, we move all mempool transactions | // If this block is deactivating a fork, we move all mempool transactions | ||||
// in front of disconnectpool for reprocessing in a future | // in front of disconnectpool for reprocessing in a future | ||||
// updateMempoolForReorg call | // updateMempoolForReorg call | ||||
if (pindexDelete->pprev != nullptr && | if (pindexDelete->pprev != nullptr && | ||||
GetBlockScriptFlags(config, pindexDelete) != | GetBlockScriptFlags(config, pindexDelete) != | ||||
▲ Show 20 Lines • Show All 254 Lines • ▼ Show 20 Lines | static bool ConnectTip(const Config &config, CValidationState &state, | ||||
int64_t nTime4 = GetTimeMicros(); | int64_t nTime4 = GetTimeMicros(); | ||||
nTimeFlush += nTime4 - nTime3; | nTimeFlush += nTime4 - nTime3; | ||||
LogPrint(BCLog::BENCH, " - Flush: %.2fms [%.2fs (%.2fms/blk)]\n", | LogPrint(BCLog::BENCH, " - Flush: %.2fms [%.2fs (%.2fms/blk)]\n", | ||||
(nTime4 - nTime3) * MILLI, nTimeFlush * MICRO, | (nTime4 - nTime3) * MILLI, nTimeFlush * MICRO, | ||||
nTimeFlush * MILLI / nBlocksTotal); | nTimeFlush * MILLI / nBlocksTotal); | ||||
// Write the chain state to disk, if necessary. | // Write the chain state to disk, if necessary. | ||||
if (!FlushStateToDisk(config.GetChainParams(), state, | if (!FlushStateToDisk(config.GetChainParams(), state, | ||||
FLUSH_STATE_IF_NEEDED)) { | FlushStateMode::IF_NEEDED)) { | ||||
return false; | return false; | ||||
} | } | ||||
int64_t nTime5 = GetTimeMicros(); | int64_t nTime5 = GetTimeMicros(); | ||||
nTimeChainState += nTime5 - nTime4; | nTimeChainState += nTime5 - nTime4; | ||||
LogPrint(BCLog::BENCH, | LogPrint(BCLog::BENCH, | ||||
" - Writing chainstate: %.2fms [%.2fs (%.2fms/blk)]\n", | " - Writing chainstate: %.2fms [%.2fs (%.2fms/blk)]\n", | ||||
(nTime5 - nTime4) * MILLI, nTimeChainState * MICRO, | (nTime5 - nTime4) * MILLI, nTimeChainState * MICRO, | ||||
▲ Show 20 Lines • Show All 412 Lines • ▼ Show 20 Lines | do { | ||||
uiInterface.NotifyBlockTip(fInitialDownload, pindexNewTip); | uiInterface.NotifyBlockTip(fInitialDownload, pindexNewTip); | ||||
} | } | ||||
} while (pindexNewTip != pindexMostWork); | } while (pindexNewTip != pindexMostWork); | ||||
const CChainParams ¶ms = config.GetChainParams(); | const CChainParams ¶ms = config.GetChainParams(); | ||||
CheckBlockIndex(params.GetConsensus()); | CheckBlockIndex(params.GetConsensus()); | ||||
// Write changes periodically to disk, after relay. | // Write changes periodically to disk, after relay. | ||||
if (!FlushStateToDisk(params, state, FLUSH_STATE_PERIODIC)) { | if (!FlushStateToDisk(params, state, FlushStateMode::PERIODIC)) { | ||||
return false; | return false; | ||||
} | } | ||||
int nStopAtHeight = gArgs.GetArg("-stopatheight", DEFAULT_STOPATHEIGHT); | int nStopAtHeight = gArgs.GetArg("-stopatheight", DEFAULT_STOPATHEIGHT); | ||||
if (nStopAtHeight && pindexNewTip && | if (nStopAtHeight && pindexNewTip && | ||||
pindexNewTip->nHeight >= nStopAtHeight) { | pindexNewTip->nHeight >= nStopAtHeight) { | ||||
StartShutdown(); | StartShutdown(); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 1,035 Lines • ▼ Show 20 Lines | try { | ||||
return error("AcceptBlock(): ReceivedBlockTransactions failed"); | return error("AcceptBlock(): ReceivedBlockTransactions failed"); | ||||
} | } | ||||
} catch (const std::runtime_error &e) { | } catch (const std::runtime_error &e) { | ||||
return AbortNode(state, std::string("System error: ") + e.what()); | return AbortNode(state, std::string("System error: ") + e.what()); | ||||
} | } | ||||
if (fCheckForPruning) { | if (fCheckForPruning) { | ||||
// we just allocated more disk space for block files. | // we just allocated more disk space for block files. | ||||
FlushStateToDisk(config.GetChainParams(), state, FLUSH_STATE_NONE); | FlushStateToDisk(config.GetChainParams(), state, FlushStateMode::NONE); | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
bool ProcessNewBlock(const Config &config, | bool ProcessNewBlock(const Config &config, | ||||
const std::shared_ptr<const CBlock> pblock, | const std::shared_ptr<const CBlock> pblock, | ||||
bool fForceProcessing, bool *fNewBlock) { | bool fForceProcessing, bool *fNewBlock) { | ||||
▲ Show 20 Lines • Show All 172 Lines • ▼ Show 20 Lines | static void FindFilesToPruneManual(std::set<int> &setFilesToPrune, | ||||
LogPrintf("Prune (Manual): prune_height=%d removed %d blk/rev pairs\n", | LogPrintf("Prune (Manual): prune_height=%d removed %d blk/rev pairs\n", | ||||
nLastBlockWeCanPrune, count); | nLastBlockWeCanPrune, count); | ||||
} | } | ||||
/* This function is called from the RPC code for pruneblockchain */ | /* This function is called from the RPC code for pruneblockchain */ | ||||
void PruneBlockFilesManual(int nManualPruneHeight) { | void PruneBlockFilesManual(int nManualPruneHeight) { | ||||
CValidationState state; | CValidationState state; | ||||
const CChainParams &chainparams = Params(); | const CChainParams &chainparams = Params(); | ||||
FlushStateToDisk(chainparams, state, FLUSH_STATE_NONE, nManualPruneHeight); | FlushStateToDisk(chainparams, state, FlushStateMode::NONE, | ||||
nManualPruneHeight); | |||||
} | } | ||||
/** | /** | ||||
* Prune block and undo files (blk???.dat and undo???.dat) so that the disk | * Prune block and undo files (blk???.dat and undo???.dat) so that the disk | ||||
* space used is less than a user-defined target. The user sets the target (in | * space used is less than a user-defined target. The user sets the target (in | ||||
* MB) on the command line or in config file. This will be run on startup and | * MB) on the command line or in config file. This will be run on startup and | ||||
* whenever new space is allocated in a block or undo file, staying below the | * whenever new space is allocated in a block or undo file, staying below the | ||||
* target. Changing back to unpruned requires a reindex (which in this case | * target. Changing back to unpruned requires a reindex (which in this case | ||||
▲ Show 20 Lines • Show All 610 Lines • ▼ Show 20 Lines | while (chainActive.Height() >= nHeight) { | ||||
if (!DisconnectTip(config, state, nullptr)) { | if (!DisconnectTip(config, state, nullptr)) { | ||||
return error( | return error( | ||||
"RewindBlockIndex: unable to disconnect block at height %i", | "RewindBlockIndex: unable to disconnect block at height %i", | ||||
pindex->nHeight); | pindex->nHeight); | ||||
} | } | ||||
// Occasionally flush state to disk. | // Occasionally flush state to disk. | ||||
if (!FlushStateToDisk(params, state, FLUSH_STATE_PERIODIC)) { | if (!FlushStateToDisk(params, state, FlushStateMode::PERIODIC)) { | ||||
return false; | return false; | ||||
} | } | ||||
} | } | ||||
// Reduce validity flag and have-data flags. | // Reduce validity flag and have-data flags. | ||||
// We do this after actual disconnecting, otherwise we'll end up writing the | // We do this after actual disconnecting, otherwise we'll end up writing the | ||||
// lack of data to disk before writing the chainstate, resulting in a | // lack of data to disk before writing the chainstate, resulting in a | ||||
// failure to continue if interrupted. | // failure to continue if interrupted. | ||||
Show All 10 Lines | if (chainActive.Tip() != nullptr) { | ||||
// no tip due to chainActive being empty! | // no tip due to chainActive being empty! | ||||
PruneBlockIndexCandidates(); | PruneBlockIndexCandidates(); | ||||
CheckBlockIndex(params.GetConsensus()); | CheckBlockIndex(params.GetConsensus()); | ||||
// FlushStateToDisk can possibly read chainActive. Be conservative | // FlushStateToDisk can possibly read chainActive. Be conservative | ||||
// and skip it here, we're about to -reindex-chainstate anyway, so | // and skip it here, we're about to -reindex-chainstate anyway, so | ||||
// it'll get called a bunch real soon. | // it'll get called a bunch real soon. | ||||
if (!FlushStateToDisk(params, state, FLUSH_STATE_ALWAYS)) { | if (!FlushStateToDisk(params, state, FlushStateMode::ALWAYS)) { | ||||
return false; | return false; | ||||
} | } | ||||
} | } | ||||
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 | ||||
▲ Show 20 Lines • Show All 741 Lines • Show Last 20 Lines |