diff --git a/src/validation.cpp b/src/validation.cpp index f57851b4f7e01a..30c7653920ffb0 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -4028,6 +4028,16 @@ static bool ContextualCheckBlockHeader(const CBlockHeader& block, BlockValidatio if (block.GetBlockTime() <= pindexPrev->GetMedianTimePast()) return state.Invalid(BlockValidationResult::BLOCK_INVALID_HEADER, "time-too-old", "block's timestamp is too early"); + // Testnet4 only: Check timestamp against prev for difficulty-adjustment + // blocks to prevent timewarp attacks (see https://github.com/bitcoin/bitcoin/pull/15482). + if (consensusParams.hashGenesisBlock == uint256S("0x000000008d6faa98083fa55742aa82d4ed249bd1bfc3239c706e0a61ef9e3931")) { + if (pindexPrev->nHeight % consensusParams.DifficultyAdjustmentInterval() == consensusParams.DifficultyAdjustmentInterval() - 1) { + if (block.GetBlockTime() < pindexPrev->GetBlockTime() - 60 * 60 * 2) { + return state.Invalid(BlockValidationResult::BLOCK_INVALID_HEADER, "time-timewarp-attack", "block's timestamp is too early on diff adjustment block"); + } + } + } + // Check timestamp if (block.Time() > NodeClock::now() + std::chrono::seconds{MAX_FUTURE_BLOCK_TIME}) { return state.Invalid(BlockValidationResult::BLOCK_TIME_FUTURE, "time-too-new", "block timestamp too far in the future");