Difficulty Algorithm & Fork-choice Rules

A precise walk‑through of Parallax’s difficulty retargeting (XHash) and the Nakamoto fork‑choice rule based on cumulative work.

Consensus Parameters
ParameterSymbolValueNotes
Target block interval
τ
600 s
Bitcoin‑like target
Future time drift bound
300 s
5 minutes
MTP sample size
11 blocks
Median of last 11 timestamps
Retarget interval
R
2016 blocks
Bitcoin-like retarget
Overview
XHash difficulty retargets on fixed block boundaries (epoch anchors) and fork choice selects the valid chain with the greatest cumulative work.
  • Retarget occurs every 2016 blocks.
  • Each retarget epoch has an anchor time recorded in headers (EpochStartTime).
  • Median‑Time‑Past (MTP, median of last 11) guards timestamp validity; a block’s time must be strictly greater than parent MTP.
  • Nodes reject headers more than +300s in the future, and verify PoW with target = ⌊(2^256−1)/D⌋.
pseudocode
Target ↔ Difficulty
Work threshold mapping used by XHash verification.
  • Let TWO256M1 = 2^256 − 1. The header is valid iff XHash(header) ≤ target, where target = ⌊TWO256M1 / D⌋.
  • Higher difficulty D ⇒ smaller target ⇒ harder block.
  • Header.MixDigest must equal the computed digest from hashimoto (light/full paths).
  • Difficulty must be strictly positive; zero/negative is invalid.
Target calculation (conceptual)
pseudocode
// Given difficulty D (big integer)
TWO256M1 = (1n << 256n) - 1n
target   = TWO256M1 / D
valid    = BigIntFromBytes(result) <= target
Retargeting via Epoch Anchors
Difficulty is derived at fixed block intervals using epoch start times.
  • Let R = 2016 blocks.
  • If height % R == 0: header.EpochStartTime = header.Time (start a new epoch).
  • Else: header.EpochStartTime = parent.EpochStartTime (propagate the current anchor).
  • CalcNakamotoDifficulty() implements the Nakamoto‑style difficulty adjustment using these anchors.
Header preparation & check (from consensus.go semantics)
pseudocode
// Prepare (when building a block)
if height % R == 0:
  header.EpochStartTime = header.Time
else:
  header.EpochStartTime = parent.EpochStartTime

header.Difficulty = CalcNakamotoDifficulty(config, parent)

// Verify (when receiving a header)
if height % R == 0:
  require(header.EpochStartTime == header.Time)
else:
  require(header.EpochStartTime == parent.EpochStartTime)
Median‑Time‑Past (MTP)
Timestamp sanity for validity and anti‑warp defenses.
  • MTP(parent) = median of the last 11 block timestamps ending at parent.
  • Validity requires header.Time > MTP(parent) (strict inequality).
  • Future‑drift bound: header.Time ≤ now + 300s.
  • MTP is used for validity checks; the retarget algorithm itself relies on epoch anchors.
MTP computation
pseudocode
MTP(n):
  ts = timestamps(n, upTo=11) // back from n inclusive
  sort(ts)
  return ts[len(ts)//2]
Fork Choice Rule
Heaviest valid chain by cumulative work.
  • Maintain ChainWork[tip] = ChainWork[parent] + Work(block).
  • Work(block) is a monotone function of target/difficulty; any consistent definition yields equivalent ordering.
  • Select the valid tip with greatest ChainWork; ties can be broken lexicographically by tip hash.
  • Invalid headers (time, PoW, difficulty/epoch rules) are excluded before fork choice.
Cumulative work (conceptual)
pseudocode
Work(block):
  target = TWO256M1 / Difficulty(block)
  // Use an approximation that preserves ordering; e.g.,
  return TWO256M1 / (target + 1)

SelectBest(tips):
  return argmax(tips, ChainWork[tip])
Reorgs & Probabilistic Finality
Depth‑based assurances instead of absolute finality.
  • Confirmation depth k lowers reorg probability exponentially with k.
  • Wallets/UIs choose k by value at risk (e.g., 6‑conf defaults for high‑value).
  • Nodes can implement practical guards (e.g., max reorg depth) to avoid DoS from pathological peers.
  • Miner economics disfavor long reorgs absent majority hashpower collusion.
Reorg handling (conceptual)
pseudocode
OnNewTip(candidate):
  if ChainWork[candidate] > ChainWork[currentTip]:
    currentTip = candidate
    ReorgTo(candidate)
Attacks & Mitigations
Key vectors relevant to the Parallax protocol specification.
  • Time‑warp: strict MTP enforcement and epoch‑anchor checks mitigate manipulation.
  • Future timestamp skew: reject headers more than +300s ahead of local time.
  • MixDigest spoofing: header.MixDigest must match hashimoto output (light/full).
Header validity subset
pseudocode
ValidHeader(h, parent):
  require(len(h.Extra) <= MaximumExtraDataSize)
  require(h.Time <= now() + 300)
  require(h.Time > MTP(parent))
  require(h.Difficulty > 0)
  // epoch anchor invariants per height % R
  // PoW: MixDigest match & XHash(h) <= targetFrom(D)

End‑to‑end selection flow

Headers are checked for Extra size, time (MTP & future drift), epoch‑anchor invariants, exact difficulty, gas limits/EIPs, height increment, and PoW seal. Valid blocks extend ChainWork, and the heaviest tip is canonical.

1
Validate
2
Check Epoch Anchor
3
Compute Difficulty
4
Accumulate Work
5
Select Heaviest