aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Lodder <[email protected]>2021-08-17 09:12:27 +0200
committerGitHub <[email protected]>2021-08-17 09:12:27 +0200
commitfe1bca68da8d5d98d3379a98b3c896a87cdf2273 (patch)
tree5228cca35287dccc0b841f0e14a41f6127e3a530
parentMerge pull request #2446 from patricklodder/1.14.4-mintxfee-tests (diff)
parent[ #2297 ] Implemented suggestions: camel casing as suggested and printing deb... (diff)
downloaddiscoin-fe1bca68da8d5d98d3379a98b3c896a87cdf2273.tar.xz
discoin-fe1bca68da8d5d98d3379a98b3c896a87cdf2273.zip
Merge pull request #2457 from ReverseControl/1.14.4-suggested-changes-for-2297
1.14.4 suggested changes for 2297
-rw-r--r--src/validation.cpp83
1 files changed, 75 insertions, 8 deletions
diff --git a/src/validation.cpp b/src/validation.cpp
index c81ab3c20..8fc4ef6c7 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -160,6 +160,26 @@ namespace {
/** 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*> gFailedBlocks;
+
/** Dirty block index entries. */
std::set<CBlockIndex*> setDirtyBlockIndex;
@@ -1338,6 +1358,7 @@ void static InvalidChainFound(CBlockIndex* pindexNew)
void static InvalidBlockFound(CBlockIndex *pindex, const CValidationState &state) {
if (!state.CorruptionPossible()) {
pindex->nStatus |= BLOCK_FAILED_VALID;
+ gFailedBlocks.insert(pindex);
setDirtyBlockIndex.insert(pindex);
setBlockIndexCandidates.erase(pindex);
InvalidChainFound(pindex);
@@ -2621,16 +2642,17 @@ bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, C
{
AssertLockHeld(cs_main);
- // Mark the block itself as invalid.
- pindex->nStatus |= BLOCK_FAILED_VALID;
- setDirtyBlockIndex.insert(pindex);
- setBlockIndexCandidates.erase(pindex);
+ // We first disconnect backwards and then mark the blocks as invalid.
+ // This prevents a case where pruned nodes may fail to invalidateblock
+ // and be left unable to start as they have no tip candidates (as there
+ // are no blocks that meet the "have data and are not invalid per
+ // nStatus" criteria for inclusion in setBlockIndexCandidates).
+
+ bool findexWasInChain = false;
+ CBlockIndex *invalidWalkTip = chainActive.Tip();
while (chainActive.Contains(pindex)) {
- CBlockIndex *pindexWalk = chainActive.Tip();
- pindexWalk->nStatus |= BLOCK_FAILED_CHILD;
- setDirtyBlockIndex.insert(pindexWalk);
- setBlockIndexCandidates.erase(pindexWalk);
+ findexWasInChain = true;
// ActivateBestChain considers blocks already in chainActive
// unconditionally valid already, so force disconnect away from it.
if (!DisconnectTip(state, chainparams)) {
@@ -2639,6 +2661,27 @@ bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, C
}
}
+ // Debug print the invalid parent's hash, later list the child hashes.
+ LogPrintf("Invalid Block %s.", pindex->GetBlockHash().ToString() );
+
+ // Now mark the blocks we just disconnected as descendants invalid
+ // Note: this may not be all descendants, e.g. the disconnected block
+ // may be the root of competing block chains that have not settled into
+ // one single block chain yet.
+ while (findexWasInChain && invalidWalkTip != pindex) {
+ LogPrintf(" Invalid Child Block %s.", invalidWalkTip->GetBlockHash().ToString() );
+ invalidWalkTip->nStatus |= BLOCK_FAILED_CHILD;
+ setDirtyBlockIndex.insert(invalidWalkTip);
+ setBlockIndexCandidates.erase(invalidWalkTip);
+ invalidWalkTip = invalidWalkTip->pprev;
+ }
+
+ // Mark the block itself as invalid.
+ pindex->nStatus |= BLOCK_FAILED_VALID;
+ setDirtyBlockIndex.insert(pindex);
+ setBlockIndexCandidates.erase(pindex);
+ gFailedBlocks.insert(pindex);
+
LimitMempoolSize(mempool, GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000, GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY) * 60 * 60);
// The resulting new best tip may not be in setBlockIndexCandidates anymore, so
@@ -2647,6 +2690,7 @@ bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, C
while (it != mapBlockIndex.end()) {
if (it->second->IsValid(BLOCK_VALID_TRANSACTIONS) && it->second->nChainTx && !setBlockIndexCandidates.value_comp()(it->second, chainActive.Tip())) {
setBlockIndexCandidates.insert(it->second);
+ gFailedBlocks.erase(it->second);
}
it++;
}
@@ -3180,6 +3224,23 @@ static bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state
if (!ContextualCheckBlockHeader(block, state, pindexPrev, GetAdjustedTime()))
return error("%s: Consensus::ContextualCheckBlockHeader: %s, %s", __func__, hash.ToString(), FormatStateMessage(state));
+
+ if (!pindexPrev->IsValid(BLOCK_VALID_SCRIPTS)) {
+ for (const CBlockIndex* failedit : gFailedBlocks) {
+ if (pindexPrev->GetAncestor(failedit->nHeight) == failedit) {
+ assert(failedit->nStatus & BLOCK_FAILED_VALID);
+ CBlockIndex* invalidWalk = pindexPrev;
+ while (invalidWalk != failedit) {
+ invalidWalk->nStatus |= BLOCK_FAILED_CHILD;
+ setDirtyBlockIndex.insert(invalidWalk);
+ invalidWalk = invalidWalk->pprev;
+ }
+
+ LogPrintf( "AcceptBlockHeader(): Invalid block %s, rejected child hash %s.", invalidWalk->GetBlockHash().ToString(), hash.ToString() );
+ return state.DoS(100, error("%s: prev block invalid", __func__), REJECT_INVALID, "bad-prevblk");
+ }
+ }
+ }
}
if (pindex == NULL)
pindex = AddToBlockIndex(block);
@@ -3600,6 +3661,11 @@ bool static LoadBlockIndexDB(const CChainParams& chainparams)
} else {
pindex->nChainTx = pindex->nTx;
}
+ if (!(pindex->nStatus & BLOCK_FAILED_MASK) && pindex->pprev && (pindex->pprev->nStatus & BLOCK_FAILED_MASK)) {
+ LogPrintf("Invalid Block %s.", pindex->GetBlockHash().ToString() );
+ pindex->nStatus |= BLOCK_FAILED_CHILD;
+ setDirtyBlockIndex.insert(pindex);
+ }
}
if (pindex->IsValid(BLOCK_VALID_TRANSACTIONS) && (pindex->nChainTx || pindex->pprev == NULL))
setBlockIndexCandidates.insert(pindex);
@@ -3879,6 +3945,7 @@ void UnloadBlockIndex()
nLastBlockFile = 0;
nBlockSequenceId = 1;
setDirtyBlockIndex.clear();
+ gFailedBlocks.clear();
setDirtyFileInfo.clear();
versionbitscache.Clear();
for (int b = 0; b < VERSIONBITS_NUM_BITS; b++) {