aboutsummaryrefslogtreecommitdiff
path: root/src/validation.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/validation.cpp')
-rw-r--r--src/validation.cpp199
1 files changed, 133 insertions, 66 deletions
diff --git a/src/validation.cpp b/src/validation.cpp
index 16bba4f7b9..d107fec70c 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -260,12 +260,12 @@ namespace {
CBlockIndex* FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& locator)
{
+ AssertLockHeld(cs_main);
+
// Find the first block the caller has in the main chain
for (const uint256& hash : locator.vHave) {
- BlockMap::iterator mi = mapBlockIndex.find(hash);
- if (mi != mapBlockIndex.end())
- {
- CBlockIndex* pindex = (*mi).second;
+ CBlockIndex* pindex = LookupBlockIndex(hash);
+ if (pindex) {
if (chain.Contains(pindex))
return pindex;
if (pindex->GetAncestor(chain.Height()) == chain.Tip()) {
@@ -280,11 +280,11 @@ std::unique_ptr<CCoinsViewDB> pcoinsdbview;
std::unique_ptr<CCoinsViewCache> pcoinsTip;
std::unique_ptr<CBlockTreeDB> pblocktree;
-enum FlushStateMode {
- FLUSH_STATE_NONE,
- FLUSH_STATE_IF_NEEDED,
- FLUSH_STATE_PERIODIC,
- FLUSH_STATE_ALWAYS
+enum class FlushStateMode {
+ NONE,
+ IF_NEEDED,
+ PERIODIC,
+ ALWAYS
};
// See definition for documentation
@@ -949,7 +949,7 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool
// This transaction should only count for fee estimation if:
// - it isn't a BIP 125 replacement transaction (may not be widely supported)
- // - it's not being readded during a reorg which bypasses typical mempool fee limits
+ // - it's not being re-added during a reorg which bypasses typical mempool fee limits
// - the node is not behind
// - the transaction is not dependent on any other transactions in the mempool
bool validForFeeEstimation = !fReplacementTransaction && !bypass_limits && IsCurrentForFeeEstimation() && pool.HasNoInputsOf(tx);
@@ -983,7 +983,7 @@ static bool AcceptToMemoryPoolWithTime(const CChainParams& chainparams, CTxMemPo
}
// After we've (potentially) uncached entries, ensure our coins cache is still within its size limits
CValidationState stateDummy;
- FlushStateToDisk(chainparams, stateDummy, FLUSH_STATE_PERIODIC);
+ FlushStateToDisk(chainparams, stateDummy, FlushStateMode::PERIODIC);
return res;
}
@@ -1267,13 +1267,12 @@ void static InvalidChainFound(CBlockIndex* pindexNew)
LogPrintf("%s: invalid block=%s height=%d log2_work=%.8g date=%s\n", __func__,
pindexNew->GetBlockHash().ToString(), pindexNew->nHeight,
- log(pindexNew->nChainWork.getdouble())/log(2.0), DateTimeStrFormat("%Y-%m-%d %H:%M:%S",
- pindexNew->GetBlockTime()));
+ log(pindexNew->nChainWork.getdouble())/log(2.0), FormatISO8601DateTime(pindexNew->GetBlockTime()));
CBlockIndex *tip = chainActive.Tip();
assert (tip);
LogPrintf("%s: current best=%s height=%d log2_work=%.8g date=%s\n", __func__,
tip->GetBlockHash().ToString(), chainActive.Height(), log(tip->nChainWork.getdouble())/log(2.0),
- DateTimeStrFormat("%Y-%m-%d %H:%M:%S", tip->GetBlockTime()));
+ FormatISO8601DateTime(tip->GetBlockTime()));
CheckForkWarningConditions();
}
@@ -1317,7 +1316,7 @@ bool CScriptCheck::operator()() {
int GetSpendHeight(const CCoinsViewCache& inputs)
{
LOCK(cs_main);
- CBlockIndex* pindexPrev = mapBlockIndex.find(inputs.GetBestBlock())->second;
+ CBlockIndex* pindexPrev = LookupBlockIndex(inputs.GetBestBlock());
return pindexPrev->nHeight + 1;
}
@@ -1685,7 +1684,7 @@ int32_t ComputeBlockVersion(const CBlockIndex* pindexPrev, const Consensus::Para
for (int i = 0; i < (int)Consensus::MAX_VERSION_BITS_DEPLOYMENTS; i++) {
ThresholdState state = VersionBitsState(pindexPrev, params, static_cast<Consensus::DeploymentPos>(i), versionbitscache);
- if (state == THRESHOLD_LOCKED_IN || state == THRESHOLD_STARTED) {
+ if (state == ThresholdState::LOCKED_IN || state == ThresholdState::STARTED) {
nVersion |= VersionBitsMask(params, static_cast<Consensus::DeploymentPos>(i));
}
}
@@ -1741,7 +1740,7 @@ static unsigned int GetBlockScriptFlags(const CBlockIndex* pindex, const Consens
}
// Start enforcing BIP68 (sequence locks) and BIP112 (CHECKSEQUENCEVERIFY) using versionbits logic.
- if (VersionBitsState(pindex->pprev, consensusparams, Consensus::DEPLOYMENT_CSV, versionbitscache) == THRESHOLD_ACTIVE) {
+ if (VersionBitsState(pindex->pprev, consensusparams, Consensus::DEPLOYMENT_CSV, versionbitscache) == ThresholdState::ACTIVE) {
flags |= SCRIPT_VERIFY_CHECKSEQUENCEVERIFY;
}
@@ -1853,15 +1852,68 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
// Once BIP34 activated it was not possible to create new duplicate coinbases and thus other than starting
// with the 2 existing duplicate coinbase pairs, not possible to create overwriting txs. But by the
// time BIP34 activated, in each of the existing pairs the duplicate coinbase had overwritten the first
- // before the first had been spent. Since those coinbases are sufficiently buried its no longer possible to create further
+ // before the first had been spent. Since those coinbases are sufficiently buried it's no longer possible to create further
// duplicate transactions descending from the known pairs either.
// If we're on the known chain at height greater than where BIP34 activated, we can save the db accesses needed for the BIP30 check.
+
+ // BIP34 requires that a block at height X (block X) has its coinbase
+ // scriptSig start with a CScriptNum of X (indicated height X). The above
+ // logic of no longer requiring BIP30 once BIP34 activates is flawed in the
+ // case that there is a block X before the BIP34 height of 227,931 which has
+ // an indicated height Y where Y is greater than X. The coinbase for block
+ // X would also be a valid coinbase for block Y, which could be a BIP30
+ // violation. An exhaustive search of all mainnet coinbases before the
+ // BIP34 height which have an indicated height greater than the block height
+ // reveals many occurrences. The 3 lowest indicated heights found are
+ // 209,921, 490,897, and 1,983,702 and thus coinbases for blocks at these 3
+ // heights would be the first opportunity for BIP30 to be violated.
+
+ // The search reveals a great many blocks which have an indicated height
+ // greater than 1,983,702, so we simply remove the optimization to skip
+ // BIP30 checking for blocks at height 1,983,702 or higher. Before we reach
+ // that block in another 25 years or so, we should take advantage of a
+ // future consensus change to do a new and improved version of BIP34 that
+ // will actually prevent ever creating any duplicate coinbases in the
+ // future.
+ static constexpr int BIP34_IMPLIES_BIP30_LIMIT = 1983702;
+
+ // There is no potential to create a duplicate coinbase at block 209,921
+ // because this is still before the BIP34 height and so explicit BIP30
+ // checking is still active.
+
+ // The final case is block 176,684 which has an indicated height of
+ // 490,897. Unfortunately, this issue was not discovered until about 2 weeks
+ // before block 490,897 so there was not much opportunity to address this
+ // case other than to carefully analyze it and determine it would not be a
+ // problem. Block 490,897 was, in fact, mined with a different coinbase than
+ // block 176,684, but it is important to note that even if it hadn't been or
+ // is remined on an alternate fork with a duplicate coinbase, we would still
+ // not run into a BIP30 violation. This is because the coinbase for 176,684
+ // is spent in block 185,956 in transaction
+ // d4f7fbbf92f4a3014a230b2dc70b8058d02eb36ac06b4a0736d9d60eaa9e8781. This
+ // spending transaction can't be duplicated because it also spends coinbase
+ // 0328dd85c331237f18e781d692c92de57649529bd5edf1d01036daea32ffde29. This
+ // coinbase has an indicated height of over 4.2 billion, and wouldn't be
+ // duplicatable until that height, and it's currently impossible to create a
+ // chain that long. Nevertheless we may wish to consider a future soft fork
+ // which retroactively prevents block 490,897 from creating a duplicate
+ // coinbase. The two historical BIP30 violations often provide a confusing
+ // edge case when manipulating the UTXO and it would be simpler not to have
+ // another edge case to deal with.
+
+ // testnet3 has no blocks before the BIP34 height with indicated heights
+ // post BIP34 before approximately height 486,000,000 and presumably will
+ // be reset before it reaches block 1,983,702 and starts doing unnecessary
+ // BIP30 checking again.
assert(pindex->pprev);
CBlockIndex *pindexBIP34height = pindex->pprev->GetAncestor(chainparams.GetConsensus().BIP34Height);
//Only continue to enforce if we're below BIP34 activation height or the block hash at that height doesn't correspond.
fEnforceBIP30 = fEnforceBIP30 && (!pindexBIP34height || !(pindexBIP34height->GetBlockHash() == chainparams.GetConsensus().BIP34Hash));
- if (fEnforceBIP30) {
+ // TODO: Remove BIP30 checking from block height 1,983,702 on, once we have a
+ // consensus change that ensures coinbases at those heights can not
+ // duplicate earlier coinbases.
+ if (fEnforceBIP30 || pindex->nHeight >= BIP34_IMPLIES_BIP30_LIMIT) {
for (const auto& tx : block.vtx) {
for (size_t o = 0; o < tx->vout.size(); o++) {
if (view.HaveCoin(COutPoint(tx->GetHash(), o))) {
@@ -1874,7 +1926,7 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
// Start enforcing BIP68 (sequence locks) and BIP112 (CHECKSEQUENCEVERIFY) using versionbits logic.
int nLockTimeFlags = 0;
- if (VersionBitsState(pindex->pprev, chainparams.GetConsensus(), Consensus::DEPLOYMENT_CSV, versionbitscache) == THRESHOLD_ACTIVE) {
+ if (VersionBitsState(pindex->pprev, chainparams.GetConsensus(), Consensus::DEPLOYMENT_CSV, versionbitscache) == ThresholdState::ACTIVE) {
nLockTimeFlags |= LOCKTIME_VERIFY_SEQUENCE;
}
@@ -2044,15 +2096,15 @@ bool static FlushStateToDisk(const CChainParams& chainparams, CValidationState &
int64_t cacheSize = pcoinsTip->DynamicMemoryUsage();
int64_t nTotalSpace = nCoinCacheUsage + std::max<int64_t>(nMempoolSizeMax - nMempoolUsage, 0);
// 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).
- bool fCacheLarge = mode == FLUSH_STATE_PERIODIC && cacheSize > std::max((9 * nTotalSpace) / 10, nTotalSpace - MAX_BLOCK_COINSDB_USAGE * 1024 * 1024);
+ bool fCacheLarge = mode == FlushStateMode::PERIODIC && cacheSize > std::max((9 * nTotalSpace) / 10, nTotalSpace - MAX_BLOCK_COINSDB_USAGE * 1024 * 1024);
// The cache is over the limit, we have to write now.
- bool fCacheCritical = mode == FLUSH_STATE_IF_NEEDED && cacheSize > nTotalSpace;
+ bool fCacheCritical = mode == FlushStateMode::IF_NEEDED && cacheSize > nTotalSpace;
// 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.
- bool fPeriodicWrite = mode == FLUSH_STATE_PERIODIC && nNow > nLastWrite + (int64_t)DATABASE_WRITE_INTERVAL * 1000000;
+ bool fPeriodicWrite = mode == FlushStateMode::PERIODIC && nNow > nLastWrite + (int64_t)DATABASE_WRITE_INTERVAL * 1000000;
// It's been very long since we flushed the cache. Do this infrequently, to optimize cache usage.
- bool fPeriodicFlush = mode == FLUSH_STATE_PERIODIC && nNow > nLastFlush + (int64_t)DATABASE_FLUSH_INTERVAL * 1000000;
+ bool fPeriodicFlush = mode == FlushStateMode::PERIODIC && nNow > nLastFlush + (int64_t)DATABASE_FLUSH_INTERVAL * 1000000;
// Combine all conditions that result in a full cache flush.
- fDoFullFlush = (mode == FLUSH_STATE_ALWAYS) || fCacheLarge || fCacheCritical || fPeriodicFlush || fFlushForPrune;
+ fDoFullFlush = (mode == FlushStateMode::ALWAYS) || fCacheLarge || fCacheCritical || fPeriodicFlush || fFlushForPrune;
// Write blocks and block index to disk.
if (fDoFullFlush || fPeriodicWrite) {
// Depend on nMinDiskSpace to ensure we can write block index
@@ -2098,7 +2150,7 @@ bool static FlushStateToDisk(const CChainParams& chainparams, CValidationState &
nLastFlush = nNow;
}
}
- if (fDoFullFlush || ((mode == FLUSH_STATE_ALWAYS || mode == FLUSH_STATE_PERIODIC) && nNow > nLastSetChain + (int64_t)DATABASE_WRITE_INTERVAL * 1000000)) {
+ if (fDoFullFlush || ((mode == FlushStateMode::ALWAYS || mode == FlushStateMode::PERIODIC) && nNow > nLastSetChain + (int64_t)DATABASE_WRITE_INTERVAL * 1000000)) {
// Update best block in wallet (so we can detect restored wallets).
GetMainSignals().SetBestChain(chainActive.GetLocator());
nLastSetChain = nNow;
@@ -2112,14 +2164,14 @@ bool static FlushStateToDisk(const CChainParams& chainparams, CValidationState &
void FlushStateToDisk() {
CValidationState state;
const CChainParams& chainparams = Params();
- FlushStateToDisk(chainparams, state, FLUSH_STATE_ALWAYS);
+ FlushStateToDisk(chainparams, state, FlushStateMode::ALWAYS);
}
void PruneAndFlush() {
CValidationState state;
fCheckForPruning = true;
const CChainParams& chainparams = Params();
- FlushStateToDisk(chainparams, state, FLUSH_STATE_NONE);
+ FlushStateToDisk(chainparams, state, FlushStateMode::NONE);
}
static void DoWarning(const std::string& strWarning)
@@ -2147,9 +2199,9 @@ void static UpdateTip(const CBlockIndex *pindexNew, const CChainParams& chainPar
for (int bit = 0; bit < VERSIONBITS_NUM_BITS; bit++) {
WarningBitsConditionChecker checker(bit);
ThresholdState state = checker.GetStateFor(pindex, chainParams.GetConsensus(), warningcache[bit]);
- if (state == THRESHOLD_ACTIVE || state == THRESHOLD_LOCKED_IN) {
+ if (state == ThresholdState::ACTIVE || state == ThresholdState::LOCKED_IN) {
const std::string strWarning = strprintf(_("Warning: unknown new rules activated (versionbit %i)"), bit);
- if (state == THRESHOLD_ACTIVE) {
+ if (state == ThresholdState::ACTIVE) {
DoWarning(strWarning);
} else {
warningMessages.push_back(strWarning);
@@ -2176,7 +2228,7 @@ void static UpdateTip(const CBlockIndex *pindexNew, const CChainParams& chainPar
LogPrintf("%s: new best=%s height=%d version=0x%08x log2_work=%.8g tx=%lu date='%s' progress=%f cache=%.1fMiB(%utxo)", __func__,
pindexNew->GetBlockHash().ToString(), pindexNew->nHeight, pindexNew->nVersion,
log(pindexNew->nChainWork.getdouble())/log(2.0), (unsigned long)pindexNew->nChainTx,
- DateTimeStrFormat("%Y-%m-%d %H:%M:%S", pindexNew->GetBlockTime()),
+ FormatISO8601DateTime(pindexNew->GetBlockTime()),
GuessVerificationProgress(chainParams.TxData(), pindexNew), pcoinsTip->DynamicMemoryUsage() * (1.0 / (1<<20)), pcoinsTip->GetCacheSize());
if (!warningMessages.empty())
LogPrintf(" warning='%s'", boost::algorithm::join(warningMessages, ", "));
@@ -2215,7 +2267,7 @@ bool CChainState::DisconnectTip(CValidationState& state, const CChainParams& cha
}
LogPrint(BCLog::BENCH, "- Disconnect block: %.2fms\n", (GetTimeMicros() - nStart) * MILLI);
// Write the chain state to disk, if necessary.
- if (!FlushStateToDisk(chainparams, state, FLUSH_STATE_IF_NEEDED))
+ if (!FlushStateToDisk(chainparams, state, FlushStateMode::IF_NEEDED))
return false;
if (disconnectpool) {
@@ -2353,7 +2405,7 @@ bool CChainState::ConnectTip(CValidationState& state, const CChainParams& chainp
int64_t nTime4 = GetTimeMicros(); nTimeFlush += nTime4 - nTime3;
LogPrint(BCLog::BENCH, " - Flush: %.2fms [%.2fs (%.2fms/blk)]\n", (nTime4 - nTime3) * MILLI, nTimeFlush * MICRO, nTimeFlush * MILLI / nBlocksTotal);
// Write the chain state to disk, if necessary.
- if (!FlushStateToDisk(chainparams, state, FLUSH_STATE_IF_NEEDED))
+ if (!FlushStateToDisk(chainparams, state, FlushStateMode::IF_NEEDED))
return false;
int64_t nTime5 = GetTimeMicros(); nTimeChainState += nTime5 - nTime4;
LogPrint(BCLog::BENCH, " - Writing chainstate: %.2fms [%.2fs (%.2fms/blk)]\n", (nTime5 - nTime4) * MILLI, nTimeChainState * MICRO, nTimeChainState * MILLI / nBlocksTotal);
@@ -2630,7 +2682,7 @@ bool CChainState::ActivateBestChain(CValidationState &state, const CChainParams&
CheckBlockIndex(chainparams.GetConsensus());
// Write changes periodically to disk, after relay.
- if (!FlushStateToDisk(chainparams, state, FLUSH_STATE_PERIODIC)) {
+ if (!FlushStateToDisk(chainparams, state, FlushStateMode::PERIODIC)) {
return false;
}
@@ -2728,7 +2780,11 @@ bool CChainState::InvalidateBlock(CValidationState& state, const CChainParams& c
}
InvalidChainFound(pindex);
- uiInterface.NotifyBlockTip(IsInitialBlockDownload(), pindex->pprev);
+
+ // Only notify about a new block tip if the active chain was modified.
+ if (pindex_was_in_chain) {
+ uiInterface.NotifyBlockTip(IsInitialBlockDownload(), pindex->pprev);
+ }
return true;
}
bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, CBlockIndex *pindex) {
@@ -2774,6 +2830,8 @@ bool ResetBlockFailureFlags(CBlockIndex *pindex) {
CBlockIndex* CChainState::AddToBlockIndex(const CBlockHeader& block)
{
+ AssertLockHeld(cs_main);
+
// Check for duplicate
uint256 hash = block.GetHash();
BlockMap::iterator it = mapBlockIndex.find(hash);
@@ -3018,7 +3076,7 @@ bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::P
bool IsWitnessEnabled(const CBlockIndex* pindexPrev, const Consensus::Params& params)
{
LOCK(cs_main);
- return (VersionBitsState(pindexPrev, params, Consensus::DEPLOYMENT_SEGWIT, versionbitscache) == THRESHOLD_ACTIVE);
+ return (VersionBitsState(pindexPrev, params, Consensus::DEPLOYMENT_SEGWIT, versionbitscache) == ThresholdState::ACTIVE);
}
// Compute at which vout of the block's coinbase transaction the witness
@@ -3137,7 +3195,7 @@ static bool ContextualCheckBlock(const CBlock& block, CValidationState& state, c
// Start enforcing BIP113 (Median Time Past) using versionbits logic.
int nLockTimeFlags = 0;
- if (VersionBitsState(pindexPrev, consensusParams, Consensus::DEPLOYMENT_CSV, versionbitscache) == THRESHOLD_ACTIVE) {
+ if (VersionBitsState(pindexPrev, consensusParams, Consensus::DEPLOYMENT_CSV, versionbitscache) == ThresholdState::ACTIVE) {
nLockTimeFlags |= LOCKTIME_MEDIAN_TIME_PAST;
}
@@ -3171,7 +3229,7 @@ static bool ContextualCheckBlock(const CBlock& block, CValidationState& state, c
// {0xaa, 0x21, 0xa9, 0xed}, and the following 32 bytes are SHA256^2(witness root, witness nonce). In case there are
// multiple, the last one is used.
bool fHaveWitness = false;
- if (VersionBitsState(pindexPrev, consensusParams, Consensus::DEPLOYMENT_SEGWIT, versionbitscache) == THRESHOLD_ACTIVE) {
+ if (VersionBitsState(pindexPrev, consensusParams, Consensus::DEPLOYMENT_SEGWIT, versionbitscache) == ThresholdState::ACTIVE) {
int commitpos = GetWitnessCommitmentIndex(block);
if (commitpos != -1) {
bool malleated = false;
@@ -3220,7 +3278,6 @@ bool CChainState::AcceptBlockHeader(const CBlockHeader& block, CValidationState&
BlockMap::iterator miSelf = mapBlockIndex.find(hash);
CBlockIndex *pindex = nullptr;
if (hash != chainparams.GetConsensus().hashGenesisBlock) {
-
if (miSelf != mapBlockIndex.end()) {
// Block header is already known.
pindex = miSelf->second;
@@ -3386,7 +3443,7 @@ bool CChainState::AcceptBlock(const std::shared_ptr<const CBlock>& pblock, CVali
}
if (fCheckForPruning)
- FlushStateToDisk(chainparams, state, FLUSH_STATE_NONE); // we just allocated more disk space for block files
+ FlushStateToDisk(chainparams, state, FlushStateMode::NONE); // we just allocated more disk space for block files
CheckBlockIndex(chainparams.GetConsensus());
@@ -3539,7 +3596,7 @@ void PruneBlockFilesManual(int nManualPruneHeight)
{
CValidationState state;
const CChainParams& chainparams = Params();
- FlushStateToDisk(chainparams, state, FLUSH_STATE_NONE, nManualPruneHeight);
+ FlushStateToDisk(chainparams, state, FlushStateMode::NONE, nManualPruneHeight);
}
/**
@@ -3654,6 +3711,8 @@ fs::path GetBlockPosFilename(const CDiskBlockPos &pos, const char *prefix)
CBlockIndex * CChainState::InsertBlockIndex(const uint256& hash)
{
+ AssertLockHeld(cs_main);
+
if (hash.IsNull())
return nullptr;
@@ -3781,6 +3840,8 @@ bool static LoadBlockIndexDB(const CChainParams& chainparams)
bool LoadChainTip(const CChainParams& chainparams)
{
+ AssertLockHeld(cs_main);
+
if (chainActive.Tip() && chainActive.Tip()->GetBlockHash() == pcoinsTip->GetBestBlock()) return true;
if (pcoinsTip->GetBestBlock().IsNull() && mapBlockIndex.size() == 1) {
@@ -3794,16 +3855,17 @@ bool LoadChainTip(const CChainParams& chainparams)
}
// Load pointer to end of best chain
- BlockMap::iterator it = mapBlockIndex.find(pcoinsTip->GetBestBlock());
- if (it == mapBlockIndex.end())
+ CBlockIndex* pindex = LookupBlockIndex(pcoinsTip->GetBestBlock());
+ if (!pindex) {
return false;
- chainActive.SetTip(it->second);
+ }
+ chainActive.SetTip(pindex);
g_chainstate.PruneBlockIndexCandidates();
LogPrintf("Loaded best chain: hashBestChain=%s height=%d date=%s progress=%f\n",
chainActive.Tip()->GetBlockHash().ToString(), chainActive.Height(),
- DateTimeStrFormat("%Y-%m-%d %H:%M:%S", chainActive.Tip()->GetBlockTime()),
+ FormatISO8601DateTime(chainActive.Tip()->GetBlockTime()),
GuessVerificationProgress(chainparams.TxData(), chainActive.Tip()));
return true;
}
@@ -4032,7 +4094,7 @@ bool CChainState::RewindBlockIndex(const CChainParams& params)
return error("RewindBlockIndex: unable to disconnect block at height %i", pindex->nHeight);
}
// Occasionally flush state to disk.
- if (!FlushStateToDisk(params, state, FLUSH_STATE_PERIODIC))
+ if (!FlushStateToDisk(params, state, FlushStateMode::PERIODIC))
return false;
}
@@ -4098,7 +4160,7 @@ bool RewindBlockIndex(const CChainParams& params) {
// and skip it here, we're about to -reindex-chainstate anyway, so
// it'll get called a bunch real soon.
CValidationState state;
- if (!FlushStateToDisk(params, state, FLUSH_STATE_ALWAYS)) {
+ if (!FlushStateToDisk(params, state, FlushStateMode::ALWAYS)) {
return false;
}
}
@@ -4244,26 +4306,31 @@ bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, CDiskB
blkdat >> block;
nRewind = blkdat.GetPos();
- // detect out of order blocks, and store them for later
uint256 hash = block.GetHash();
- if (hash != chainparams.GetConsensus().hashGenesisBlock && mapBlockIndex.find(block.hashPrevBlock) == mapBlockIndex.end()) {
- LogPrint(BCLog::REINDEX, "%s: Out of order block %s, parent %s not known\n", __func__, hash.ToString(),
- block.hashPrevBlock.ToString());
- if (dbp)
- mapBlocksUnknownParent.insert(std::make_pair(block.hashPrevBlock, *dbp));
- continue;
- }
-
- // process in case the block isn't known yet
- if (mapBlockIndex.count(hash) == 0 || (mapBlockIndex[hash]->nStatus & BLOCK_HAVE_DATA) == 0) {
+ {
LOCK(cs_main);
- CValidationState state;
- if (g_chainstate.AcceptBlock(pblock, state, chainparams, nullptr, true, dbp, nullptr))
- nLoaded++;
- if (state.IsError())
- break;
- } else if (hash != chainparams.GetConsensus().hashGenesisBlock && mapBlockIndex[hash]->nHeight % 1000 == 0) {
- LogPrint(BCLog::REINDEX, "Block Import: already had block %s at height %d\n", hash.ToString(), mapBlockIndex[hash]->nHeight);
+ // detect out of order blocks, and store them for later
+ if (hash != chainparams.GetConsensus().hashGenesisBlock && !LookupBlockIndex(block.hashPrevBlock)) {
+ LogPrint(BCLog::REINDEX, "%s: Out of order block %s, parent %s not known\n", __func__, hash.ToString(),
+ block.hashPrevBlock.ToString());
+ if (dbp)
+ mapBlocksUnknownParent.insert(std::make_pair(block.hashPrevBlock, *dbp));
+ continue;
+ }
+
+ // process in case the block isn't known yet
+ CBlockIndex* pindex = LookupBlockIndex(hash);
+ if (!pindex || (pindex->nStatus & BLOCK_HAVE_DATA) == 0) {
+ CValidationState state;
+ if (g_chainstate.AcceptBlock(pblock, state, chainparams, nullptr, true, dbp, nullptr)) {
+ nLoaded++;
+ }
+ if (state.IsError()) {
+ break;
+ }
+ } else if (hash != chainparams.GetConsensus().hashGenesisBlock && pindex->nHeight % 1000 == 0) {
+ LogPrint(BCLog::REINDEX, "Block Import: already had block %s at height %d\n", hash.ToString(), pindex->nHeight);
+ }
}
// Activate the genesis block so normal node progress can continue
@@ -4501,7 +4568,7 @@ void CChainState::CheckBlockIndex(const Consensus::Params& consensusParams)
std::string CBlockFileInfo::ToString() const
{
- return strprintf("CBlockFileInfo(blocks=%u, size=%u, heights=%u...%u, time=%s...%s)", nBlocks, nSize, nHeightFirst, nHeightLast, DateTimeStrFormat("%Y-%m-%d", nTimeFirst), DateTimeStrFormat("%Y-%m-%d", nTimeLast));
+ return strprintf("CBlockFileInfo(blocks=%u, size=%u, heights=%u...%u, time=%s...%s)", nBlocks, nSize, nHeightFirst, nHeightLast, FormatISO8601Date(nTimeFirst), FormatISO8601Date(nTimeLast));
}
CBlockFileInfo* GetBlockFileInfo(size_t n)