Summary
Invalidate any non-difficulty-adjustment block whose timestamp is more than 20 minutes than its previous block's timestamp, after block height 151,200 (epoch 75 boundary).
Motivation
Testnet4's min-difficulty rule (allowing difficulty-1 blocks after 20 minutes) is being exploited, causing ~85-90% of blocks to be CPU-mined min-difficulty blocks. This results in a race of CPU miners broadcasting blocks at exactly the second that it's acceptable. This race is so intense that CPU miners have figured out sending empty blocks, as they propagate faster than those that contain transactions, resulting in a network where transactions are confirmed at only the remaining ASIC blocks, that have ~1 hour average block times.
After the fork, min difficulty blocks will no longer be allowed, as blocks that have a timestamp longer than 20 minutes than their previous blocks become invalid, except difficulty-adjusting blocks (epoch boundary blocks).
Previously, PR #34420 addressed the same issue, but the change was a hard fork. The current soft fork proposal fixes the problem for non-upgraded nodes as long as majority of the hashrate is mining on upgraded clients, and therefore fixes the problem with the least network disruption.
Changes
- Add
min_difficulty_blocks_fix_heightconsensus parameter (default0= disabled). - Set fork height to 151,200 for testnet4 (epoch 75 boundary).
- In
ContextualCheckBlockHeader(), reject any block whose timestamp exceeds the previous block's timestamp by more than2 * nPowTargetSpacing(1200 seconds on testnet4) once the activation height is reached. Because the min-difficulty rule only kicks in when the inter-block gap is strictly greater than2 * nPowTargetSpacing, capping the gap at exactly that boundary makes min-difficulty blocks impossible -- without touching the min-difficulty rule itself. Difficulty-adjustment blocks (heights divisible byDifficultyAdjustmentInterval()) are exempt from the cap:GetNextWorkRequired()already bypasses the min-difficulty rule on those blocks and requires the retargeted difficulty regardless of timestamp, so there is no exploit to close there. Leaving adjustment blocks uncapped lets miners publish a truthful wall-clock timestamp every 2016 blocks, so that chain time can track real time instead of drifting indefinitely behind it under the per-block cap. - Add
GetMaximumTime()innode/minermirroringGetMinimumTime(), and clamp candidate block timestamps (both inBlockAssembler::CreateNewBlock()andUpdateTime()) so thatgetblocktemplatenever returns acurtimethat would produce a block rejected by the new rule. The same adjustment-block exemption applies:GetMaximumTime()returnsstd::numeric_limits<int64_t>::max()when the next block is a difficulty-adjustment block, so the template is not clamped there and ASIC miners are free to stamp it with wall-clock time. - Add unit tests covering boundary behavior of
GetMaximumTime(pre-fork, first post-fork non-adjustment block, activation block at height 151,200 which is itself an adjustment block, a later adjustment block at height 153,216, and disabled on other chains) and clamping behavior ofUpdateTime(wall-clock past the cap, below the cap, and exactly at the cap).
Soft fork properties
This is a strict tightening of consensus rules:
- Any block valid under the new rule is also valid under the old rules.
- Blocks at heights below 151,200 are completely unaffected.
- Non-upgraded nodes continue to accept blocks mined by upgraded miners (they satisfy the old ruleset). Propagation to non-upgraded nodes happens naturally through normal chain gossip, so no coordinated upgrade is required beyond sufficient hashrate majority adopting the rule by the activation height.
Test Plan
./build/bin/test_bitcoin --run_test=testnet4_miner_tests-- all boundary and clamping tests pass.- Regression:
./build/bin/test_bitcoin --run_test=miner_tests,pow_tests,validation_tests,validation_block_tests-- no regressions. - Manual: pre-activation behavior on live testnet4 matches expectations (
getblocktemplatereturns acurtimebelow the prospective cap).
Discussion
bitcoin-dev mailing list thread [#1](/bitcoin-bitcoin/1/) bitcoin-dev mailing list thread [#2](/bitcoin-bitcoin/2/) Bitcointalk thread Supersedes hard fork proposal #34420