§ 09 · Difficulty
Timestamps
Why a miner's clock matters when difficulty moves every block
On this page 7 sections
A block’s timestampTimestamp: The time a miner writes into a block header. On Pearl it must be at least 1 second after the previous block's, and at most 5 minutes ahead of the network's clock. is the miner’s word on when the block was made. Nobody can check it exactly: there is no clock everyone shares.
On Bitcoin a wrong timestamp matters much less, because difficulty looks at time only once every 2,016 blocks. On Pearl, difficulty moves after every block, using the gap between two timestamps. So Pearl needs rules that keep every gap positive and every lie small.
This page is about those rules and what they protect. How the 4 bytes are stored and decoded is on time.
Try it
Fake some slow blocks and watch the target loosen, then see the next blocks pull it back.
What are the rules?
A node accepts a block’s timestamp only inside this window:
| Field | Size | Description |
|---|---|---|
| Lower bound | — | At least 1 second after the parent's timestamp. Anything earlier fails with ErrTimeTooOld. |
| Upper bound | — | At most 5 minutes past the node's network-adjusted time. Anything later fails with ErrTimeTooNew. |
Pearl’s own code was run on the edges: the parent’s second is rejected, parent + 1 s is accepted, the node’s adjusted time + 5 min 0 s is accepted, and + 5 min 1 s is rejected.
The upper bound is checked against the receiving node’s own idea of the time, so it can differ slightly from node to node. The lower bound depends only on the chain, so every node agrees on it.
What is network-adjusted time?
Every node has its own clock, and some clocks are wrong. So a node uses network-adjusted timeNetwork-adjusted time: A node's own clock, corrected by the median of the time differences its peers report. Pearl rejects blocks timestamped more than 5 minutes past it.: its own clock, shifted by the median of the time differences its peers report when they connect. Offsets beyond ±70 minutes are ignored. This is btcd’s logic, unchanged.
Why did Pearl drop the median rule?
Bitcoin only requires a block to be later than the median time pastMedian time past: The median timestamp of the previous 11 blocks. Time-based locktimes are compared against it, not against the clock, so miners cannot unlock coins early by lying about the time. (MTP), the median of the previous 11 timestamps. That lets block times go backwards a little, and the gap between a block and its parent can be zero or negative.
That would break Pearl’s difficulty rule. WTEMAWTEMA: Pearl's difficulty rule. After every block it nudges the target slightly: easier if that block took longer than 194 seconds, harder if it was quicker, with a one-week time constant. computes the next target from the parent’s solve time, t = its timestamp minus its own parent’s:
A negative t would be read as a block found impossibly fast. So Pearl requires t ≥ 1. The code comment says it plainly: the rule “is stricter than the original median-time rule and makes the median time check redundant. Required for WTEMA difficulty adjustment.”
It also caps how fast difficulty can climb: with t ≥ 1, one block can shrink the target by at most a factor of (1 − 193 ÷ 604,800) = 0.99968.
Can a miner cheat with the clock?
Not by much. Here is why.
Each block multiplies the target by about (1 + (t − 194) ÷ 604,800). Over several blocks the factors multiply, and the gaps t add up. But the gaps telescope: their sum is just the newest timestamp minus the oldest. So, to a very good approximation, the target after a run of blocks depends on the newest timestamp, not on the ones in between. A lie in the middle is undone by the blocks after it, which must be stamped later still.
The only timestamp that is never “undone” is the newest one, and the 5-minute rule limits it. Five minutes of fake lateness moves the next target by at most 300 ÷ 604,800, about 0.05%.
Where does the median time past still matter?
In lock times. The rule for blocks changed; the rule for transactions did not. A transaction locked until a certain time becomes valid when the MTP of the last 11 blocks passes that time (BIP-113), and relative time locks (BIP-68) measure from the MTP too, exactly as in Bitcoin. See locktime and sequence.
On Pearl, the MTP has a neat shortcut. Every timestamp is later than its parent’s, so the last 11 are already in order, and their median is just the 6th newest. At the normal pace that’s about 5 × 194 = 970 seconds, roughly 16 minutes, behind the newest block.
What did launch look like?
Genesis is stamped 1,777,280,400: 2026-04-27 09:00:00 UTC. Blocks 1 to 5 followed at 1,777,280,401, …402, …403, …404 and …405: exactly one second apart, the minimum the rules allow.
At difficulty 1 that was all the time miners needed. Each 1-second block tightened the target by the largest step WTEMA allows, which is how difficulty began its climb. The full story is on WTEMA.
Make a guess
Could a miner stamp a block 90 minutes in the future, which Bitcoin's 2-hour rule allows?
Think of your answer first, then check it.
Answer No. Every node rejects it as too new.
Pearl’s limit is 5 minutes past network-adjusted time, so a node that receives a block stamped 90
minutes ahead fails it with ErrTimeTooNew. On Bitcoin, the same block would pass the time check.
Code: the two checks and their parameters
The lower bound, from validate.go (node/blockchain/validate.go:686-696 at v1.5.2, on GitHub), with
MinTimestampDeltaSeconds = 1 at line 26 (node/blockchain/validate.go:23-26 at v1.5.2, on GitHub):
prevTimestamp := time.Unix(prevNode.Timestamp(), 0)
minTimestamp := prevTimestamp.Add(time.Duration(MinTimestampDeltaSeconds) * time.Second)
if header.Timestamp.Before(minTimestamp) {
return ruleError(ErrTimeTooOld, str)
} The upper bound, from validate.go (node/blockchain/validate.go:390-396 at v1.5.2, on GitHub), with
MaxTimeOffsetMinutes: 5 in params.go (node/chaincfg/params.go:362 at v1.5.2, on GitHub) (regtest and simnet use 120):
maxTimestamp := timeSource.AdjustedTime().Add(time.Minute * time.Duration(maxTimeOffsetMinutes))
if header.Timestamp.After(maxTimestamp) {
return ruleError(ErrTimeTooNew, str)
} The adjusted time comes from mediantime.go (node/blockchain/mediantime.go:14-30 at v1.5.2, on GitHub), and lock-time
finality still uses CalcPastMedianTime in validate.go (node/blockchain/validate.go:768-781 at v1.5.2, on GitHub).