Merge pull request #2457 from ReverseControl/1.14.4-suggested-changes-for-2297
1.14.4 suggested changes for 2297
This commit is contained in:
commit
fe1bca68da
|
@ -160,6 +160,26 @@ namespace {
|
||||||
/** chainwork for the last block that preciousblock has been applied to. */
|
/** chainwork for the last block that preciousblock has been applied to. */
|
||||||
arith_uint256 nLastPreciousChainwork = 0;
|
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. */
|
/** Dirty block index entries. */
|
||||||
std::set<CBlockIndex*> setDirtyBlockIndex;
|
std::set<CBlockIndex*> setDirtyBlockIndex;
|
||||||
|
|
||||||
|
@ -1338,6 +1358,7 @@ void static InvalidChainFound(CBlockIndex* pindexNew)
|
||||||
void static InvalidBlockFound(CBlockIndex *pindex, const CValidationState &state) {
|
void static InvalidBlockFound(CBlockIndex *pindex, const CValidationState &state) {
|
||||||
if (!state.CorruptionPossible()) {
|
if (!state.CorruptionPossible()) {
|
||||||
pindex->nStatus |= BLOCK_FAILED_VALID;
|
pindex->nStatus |= BLOCK_FAILED_VALID;
|
||||||
|
gFailedBlocks.insert(pindex);
|
||||||
setDirtyBlockIndex.insert(pindex);
|
setDirtyBlockIndex.insert(pindex);
|
||||||
setBlockIndexCandidates.erase(pindex);
|
setBlockIndexCandidates.erase(pindex);
|
||||||
InvalidChainFound(pindex);
|
InvalidChainFound(pindex);
|
||||||
|
@ -2621,16 +2642,17 @@ bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, C
|
||||||
{
|
{
|
||||||
AssertLockHeld(cs_main);
|
AssertLockHeld(cs_main);
|
||||||
|
|
||||||
// Mark the block itself as invalid.
|
// We first disconnect backwards and then mark the blocks as invalid.
|
||||||
pindex->nStatus |= BLOCK_FAILED_VALID;
|
// This prevents a case where pruned nodes may fail to invalidateblock
|
||||||
setDirtyBlockIndex.insert(pindex);
|
// and be left unable to start as they have no tip candidates (as there
|
||||||
setBlockIndexCandidates.erase(pindex);
|
// 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)) {
|
while (chainActive.Contains(pindex)) {
|
||||||
CBlockIndex *pindexWalk = chainActive.Tip();
|
findexWasInChain = true;
|
||||||
pindexWalk->nStatus |= BLOCK_FAILED_CHILD;
|
|
||||||
setDirtyBlockIndex.insert(pindexWalk);
|
|
||||||
setBlockIndexCandidates.erase(pindexWalk);
|
|
||||||
// ActivateBestChain considers blocks already in chainActive
|
// ActivateBestChain considers blocks already in chainActive
|
||||||
// unconditionally valid already, so force disconnect away from it.
|
// unconditionally valid already, so force disconnect away from it.
|
||||||
if (!DisconnectTip(state, chainparams)) {
|
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);
|
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
|
// 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()) {
|
while (it != mapBlockIndex.end()) {
|
||||||
if (it->second->IsValid(BLOCK_VALID_TRANSACTIONS) && it->second->nChainTx && !setBlockIndexCandidates.value_comp()(it->second, chainActive.Tip())) {
|
if (it->second->IsValid(BLOCK_VALID_TRANSACTIONS) && it->second->nChainTx && !setBlockIndexCandidates.value_comp()(it->second, chainActive.Tip())) {
|
||||||
setBlockIndexCandidates.insert(it->second);
|
setBlockIndexCandidates.insert(it->second);
|
||||||
|
gFailedBlocks.erase(it->second);
|
||||||
}
|
}
|
||||||
it++;
|
it++;
|
||||||
}
|
}
|
||||||
|
@ -3180,6 +3224,23 @@ static bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state
|
||||||
|
|
||||||
if (!ContextualCheckBlockHeader(block, state, pindexPrev, GetAdjustedTime()))
|
if (!ContextualCheckBlockHeader(block, state, pindexPrev, GetAdjustedTime()))
|
||||||
return error("%s: Consensus::ContextualCheckBlockHeader: %s, %s", __func__, hash.ToString(), FormatStateMessage(state));
|
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)
|
if (pindex == NULL)
|
||||||
pindex = AddToBlockIndex(block);
|
pindex = AddToBlockIndex(block);
|
||||||
|
@ -3600,6 +3661,11 @@ bool static LoadBlockIndexDB(const CChainParams& chainparams)
|
||||||
} else {
|
} else {
|
||||||
pindex->nChainTx = pindex->nTx;
|
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))
|
if (pindex->IsValid(BLOCK_VALID_TRANSACTIONS) && (pindex->nChainTx || pindex->pprev == NULL))
|
||||||
setBlockIndexCandidates.insert(pindex);
|
setBlockIndexCandidates.insert(pindex);
|
||||||
|
@ -3879,6 +3945,7 @@ void UnloadBlockIndex()
|
||||||
nLastBlockFile = 0;
|
nLastBlockFile = 0;
|
||||||
nBlockSequenceId = 1;
|
nBlockSequenceId = 1;
|
||||||
setDirtyBlockIndex.clear();
|
setDirtyBlockIndex.clear();
|
||||||
|
gFailedBlocks.clear();
|
||||||
setDirtyFileInfo.clear();
|
setDirtyFileInfo.clear();
|
||||||
versionbitscache.Clear();
|
versionbitscache.Clear();
|
||||||
for (int b = 0; b < VERSIONBITS_NUM_BITS; b++) {
|
for (int b = 0; b < VERSIONBITS_NUM_BITS; b++) {
|
||||||
|
|
Loading…
Reference in a new issue