ADR-012 — No timewarp rule; pin nMinimumChainWork, assumevalid and checkpoints
- Status: Accepted
- Date: 2026-10-09
- Related: ADR-010 (2-minute blocks, 60-block retarget), bug-bounty 2026-10-09
findings #4 (timewarp) and #6 (no minimum chain work), infra audit 2026-10-09 (C1, M1).
Context
Bug-bounty finding #4 proposed a Bitcoin "consensus-cleanup" style timewarp rule: the first block of each difficulty period may not be timestamped more than 600 s before the last block of the previous period, activating at mainnet height 20000. A draft was written into the core tree. The infra audit (C1) reviewed it against the actual retarget code and found it to be a no-op that also schedules a hard fork.
Analysis
The classic Bitcoin timewarp exists because Bitcoin's retarget window is off by one: it measures the time between block H-2016 and block H-1, so consecutive windows do not share an endpoint. A majority miner can push the last block of a period far into the future and start the next period in the past; the gap between periods is never measured, so the error accumulates without bound and difficulty collapses.
MoonBite inherits Litecoin's fix (src/pow.cpp, "Code courtesy of Art Forz"): after the first retarget the window goes back the full period — DifficultyAdjustmentInterval() = 60 blocks — so period *k* is measured from block H-61 to H-1, and period *k+1* from H-1 to H+59. Consecutive windows share their endpoint. Consequences:
- The measured timespans telescope: the sum of all window timespans equals
the time between the first and the last sampled block. A timestamp pushed backward at one boundary shortens the next window by exactly as much as it lengthened the previous one. There is no un-measured gap to exploit.
- Each window's adjustment is clamped to 4× / 0.25× (Bitcoin/Litecoin rule),
and the median-time-past rule plus the 2-hour future-time bound limit how far any single timestamp can be moved. The residual attacker freedom is a transient easing of at most about 2× in one window, which is paid back in the next window. The "33× faster collapse" claimed in bounty #4 does not hold under a full-period window.
- The draft rule constrained block
H % 60 == 0, which is not a window
endpoint in this retarget (the endpoints are H-61 and H-1 relative to the block being mined). It therefore removed zero attacker freedom.
- Worse, an honest miner with roughly +1 h of clock skew followed by an honest
block with a correct clock would trip the 600 s rule at a period boundary, splitting upgraded from non-upgraded nodes. Activating it at height 20000 would have been a scheduled hard fork with no security benefit.
Decision
1. No timewarp rule is added. The validation.cpp rule, the Consensus::Params::nTimeWarpFixHeight field and all chainparams settings for it are dropped. The retarget stays exactly as ADR-010 defines it. 2. Pin a minimum chain work, an assumevalid block and buried checkpoints (bounty #6 / audit M1). Previously all three were zero / genesis-only, so a fresh node would accept and RandomX-verify arbitrarily long floor-difficulty header chains from any peer. Values were read from a live seed via read-only RPC on 2026-10-09 (tip 12656):
| Parameter | Value |
|---|---|
nMinimumChainWork | 0x…aa9c1b51 (chainwork at height 12000) |
defaultAssumeValid | b0b48cbf1cf1666c861c359a1b7abe72f141e794662c6f8dc72261596c58d82e (height 12500) |
| checkpoints | {12000, 67b4f7d0af4fa721a4a9f00d09838d4324dd598d930a25c22480b67459d76b14}, {12500, b0b48cbf…} |
Both heights are below the deepest observed live fork point (12579), so no honest node can be stalled by them. These values are policy, not consensus: a node that lacks them still follows the same chain, it just does more work to reject junk during initial sync.
Consequences
- No hard fork is scheduled. Nodes on the previous release remain fully
compatible with this one.
- Every release should re-bump
nMinimumChainWork/defaultAssumeValid/
checkpoints to a recent buried height, as Bitcoin and Litecoin do.
- If the retarget is ever changed to a non-overlapping window, this analysis
must be redone and a real timewarp rule (constraining the actual window endpoints) considered at that time.