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 sBitcoin‑like target
Future time drift bound300 s5 minutes
MTP sample size11 blocksMedian of last 11 timestamps
Retarget intervalR2016 blocksBitcoin-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