Merge #11028: Avoid masking of difficulty adjustment errors by checkpoints

85c82b5 Avoid masking of difficulty adjustment errors by checkpoints (Pieter Wuille)

Pull request description:

  Currently difficulty adjustment violations are not reported for chains that branch off before the last checkpoint. Change this by moving the checkpoint check after the difficulty check.

Tree-SHA512: 33666f2c3459151b28c42041a463779e6df18f61d3dd5b1879a0af4e5b199ef74d1e33e06af68bebfdfb211569ad5fb56556bfebe9d63b5688d910ea211b839a
This commit is contained in:
Wladimir J. van der Laan 2017-08-14 16:12:34 +02:00
commit 6bdf4b3c7c
No known key found for this signature in database
GPG key ID: 1E4AED62986CD25D

View file

@ -2835,22 +2835,6 @@ bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::P
return true; return true;
} }
static bool CheckIndexAgainstCheckpoint(const CBlockIndex* pindexPrev, CValidationState& state, const CChainParams& chainparams, const uint256& hash)
{
if (*pindexPrev->phashBlock == chainparams.GetConsensus().hashGenesisBlock)
return true;
int nHeight = pindexPrev->nHeight+1;
// Don't accept any forks from the main chain prior to last checkpoint.
// GetLastCheckpoint finds the last checkpoint in MapCheckpoints that's in our
// MapBlockIndex.
CBlockIndex* pcheckpoint = Checkpoints::GetLastCheckpoint(chainparams.Checkpoints());
if (pcheckpoint && nHeight < pcheckpoint->nHeight)
return state.DoS(100, error("%s: forked chain older than last checkpoint (height %d)", __func__, nHeight), REJECT_CHECKPOINT, "bad-fork-prior-to-checkpoint");
return true;
}
bool IsWitnessEnabled(const CBlockIndex* pindexPrev, const Consensus::Params& params) bool IsWitnessEnabled(const CBlockIndex* pindexPrev, const Consensus::Params& params)
{ {
LOCK(cs_main); LOCK(cs_main);
@ -2916,14 +2900,26 @@ std::vector<unsigned char> GenerateCoinbaseCommitment(CBlock& block, const CBloc
/** Context-dependent validity checks. /** Context-dependent validity checks.
* By "context", we mean only the previous block headers, but not the UTXO * By "context", we mean only the previous block headers, but not the UTXO
* set; UTXO-related validity checks are done in ConnectBlock(). */ * set; UTXO-related validity checks are done in ConnectBlock(). */
static bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& state, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev, int64_t nAdjustedTime) static bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& state, const CChainParams& params, const CBlockIndex* pindexPrev, int64_t nAdjustedTime)
{ {
assert(pindexPrev != NULL); assert(pindexPrev != NULL);
const int nHeight = pindexPrev->nHeight + 1; const int nHeight = pindexPrev->nHeight + 1;
// Check proof of work // Check proof of work
const Consensus::Params& consensusParams = params.GetConsensus();
if (block.nBits != GetNextWorkRequired(pindexPrev, &block, consensusParams)) if (block.nBits != GetNextWorkRequired(pindexPrev, &block, consensusParams))
return state.DoS(100, false, REJECT_INVALID, "bad-diffbits", false, "incorrect proof of work"); return state.DoS(100, false, REJECT_INVALID, "bad-diffbits", false, "incorrect proof of work");
// Check against checkpoints
if (fCheckpointsEnabled) {
// Don't accept any forks from the main chain prior to last checkpoint.
// GetLastCheckpoint finds the last checkpoint in MapCheckpoints that's in our
// MapBlockIndex.
CBlockIndex* pcheckpoint = Checkpoints::GetLastCheckpoint(params.Checkpoints());
if (pcheckpoint && nHeight < pcheckpoint->nHeight)
return state.DoS(100, error("%s: forked chain older than last checkpoint (height %d)", __func__, nHeight), REJECT_CHECKPOINT, "bad-fork-prior-to-checkpoint");
}
// Check timestamp against prev // Check timestamp against prev
if (block.GetBlockTime() <= pindexPrev->GetMedianTimePast()) if (block.GetBlockTime() <= pindexPrev->GetMedianTimePast())
return state.Invalid(false, REJECT_INVALID, "time-too-old", "block's timestamp is too early"); return state.Invalid(false, REJECT_INVALID, "time-too-old", "block's timestamp is too early");
@ -3054,12 +3050,7 @@ static bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state
pindexPrev = (*mi).second; pindexPrev = (*mi).second;
if (pindexPrev->nStatus & BLOCK_FAILED_MASK) if (pindexPrev->nStatus & BLOCK_FAILED_MASK)
return state.DoS(100, error("%s: prev block invalid", __func__), REJECT_INVALID, "bad-prevblk"); return state.DoS(100, error("%s: prev block invalid", __func__), REJECT_INVALID, "bad-prevblk");
if (!ContextualCheckBlockHeader(block, state, chainparams, pindexPrev, GetAdjustedTime()))
assert(pindexPrev);
if (fCheckpointsEnabled && !CheckIndexAgainstCheckpoint(pindexPrev, state, chainparams, hash))
return error("%s: CheckIndexAgainstCheckpoint(): %s", __func__, state.GetRejectReason().c_str());
if (!ContextualCheckBlockHeader(block, state, chainparams.GetConsensus(), 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 (pindex == NULL) if (pindex == NULL)
@ -3208,16 +3199,13 @@ bool TestBlockValidity(CValidationState& state, const CChainParams& chainparams,
{ {
AssertLockHeld(cs_main); AssertLockHeld(cs_main);
assert(pindexPrev && pindexPrev == chainActive.Tip()); assert(pindexPrev && pindexPrev == chainActive.Tip());
if (fCheckpointsEnabled && !CheckIndexAgainstCheckpoint(pindexPrev, state, chainparams, block.GetHash()))
return error("%s: CheckIndexAgainstCheckpoint(): %s", __func__, state.GetRejectReason().c_str());
CCoinsViewCache viewNew(pcoinsTip); CCoinsViewCache viewNew(pcoinsTip);
CBlockIndex indexDummy(block); CBlockIndex indexDummy(block);
indexDummy.pprev = pindexPrev; indexDummy.pprev = pindexPrev;
indexDummy.nHeight = pindexPrev->nHeight + 1; indexDummy.nHeight = pindexPrev->nHeight + 1;
// NOTE: CheckBlockHeader is called by CheckBlock // NOTE: CheckBlockHeader is called by CheckBlock
if (!ContextualCheckBlockHeader(block, state, chainparams.GetConsensus(), pindexPrev, GetAdjustedTime())) if (!ContextualCheckBlockHeader(block, state, chainparams, pindexPrev, GetAdjustedTime()))
return error("%s: Consensus::ContextualCheckBlockHeader: %s", __func__, FormatStateMessage(state)); return error("%s: Consensus::ContextualCheckBlockHeader: %s", __func__, FormatStateMessage(state));
if (!CheckBlock(block, state, chainparams.GetConsensus(), fCheckPOW, fCheckMerkleRoot)) if (!CheckBlock(block, state, chainparams.GetConsensus(), fCheckPOW, fCheckMerkleRoot))
return error("%s: Consensus::CheckBlock: %s", __func__, FormatStateMessage(state)); return error("%s: Consensus::CheckBlock: %s", __func__, FormatStateMessage(state));