Algorithme de difficulté et règles de choix de fork

Un parcours précis de l'historique d'ajustement de difficulté de Parallax — DAA à la BTC depuis le genesis, mise à jour ASERT au bloc 17 560 (PIP-0002) et règle Nakamoto de choix de fork fondée sur le travail cumulé.

Paramètres de consensus
ParamètreSymboleValeurNotes
Intervalle de bloc cible
τ
600 s
Cible à la Bitcoin
Borne de dérive temporelle future
300 s
5 minutes
Taille d'échantillon MTP
11 blocs
Médiane des 11 derniers horodatages
Historique de l'algorithme de difficulté
DAA à la BTC → ASERT
Fenêtres de 2016 blocs à la BTC du genesis au bloc 17 559 ; ASERT (aserti3-2d) pour les blocs ≥ 17 560 (PIP-0002).
Vue d'ensemble
Parallax vise des blocs de 10 minutes grâce à la preuve de travail XHash et à un algorithme de difficulté ASERT par bloc, après une phase initiale de DAA à la BTC.
  • Du genesis jusqu'au bloc 17 559, Parallax utilisait une fenêtre d'ajustement de difficulté à la Bitcoin sur 2016 blocs (DAA à la BTC).
  • PIP-0002 (Migration de l'algorithme d'ajustement de difficulté à la BTC vers ASERT) a activé ASERT au bloc 17 560.
  • ASERT (aserti3-2d, tel qu'utilisé par Bitcoin Cash) ajuste la difficulté à chaque bloc par rapport à une ancre fixe, convergeant en douceur vers la cible de 600 s lors de chocs de hashrate.
  • Le Median-Time-Past (MTP, médiane des 11 derniers) garantit la validité des horodatages ; les nœuds rejettent les en-têtes plus de 300 s dans le futur et vérifient la PoW avec target = ⌊(2^256−1)/D⌋.
Cible ↔ Difficulté
Mappage du seuil de travail utilisé par la vérification XHash (commun aux ères DAA-BTC et ASERT).
  • Soit TWO256M1 = 2^256 − 1. L'en-tête est valide si XHash(header) ≤ target, où target = ⌊TWO256M1 / D⌋.
  • Une difficulté D plus élevée ⇒ une cible plus petite ⇒ un bloc plus difficile.
  • Header.MixDigest doit être égal au digest calculé par hashimoto (chemins light/full).
  • La difficulté doit être strictement positive ; une valeur nulle ou négative est invalide.
Calcul de la cible (conceptuel)
pseudocode
// Given difficulty D (big integer)
TWO256M1 = (1n << 256n) - 1n
target   = TWO256M1 / D
valid    = BigIntFromBytes(result) <= target
Ajustement de difficulté : DAA à la BTC → ASERT
Fenêtres historiques de 2016 blocs, puis ASERT moderne par bloc relatif à une ancre.
  • Genesis → bloc 17 559 : CalcNakamotoDifficulty() implémente une fenêtre de 2016 blocs à la Bitcoin à l'aide d'ancres d'époque.
  • Bloc 17 560 et au-delà : CalcAsertDifficulty() implémente aserti3-2d à l'aide d'une ancre fixe {anchorHeight, anchorParentTime, anchorTarget}.
  • ASERT utilise le décalage de hauteur Δh et le temps écoulé Δt par rapport à l'ancre pour pousser la difficulté vers la cible de 600 s avec une demi-vie de 2 jours.
  • Les blocs historiques conservent leur difficulté DAA à la BTC d'origine et restent validés selon ces règles ; l'ajustement prospectif est entièrement fondé sur ASERT.
Sélection de difficulté dépendant de la hauteur (conceptuelle)
pseudocode
// Difficulty selection by era
CalcDifficulty(config, anchor, parent, header):
  if height(header) < 17560:
    // BTC-style DAA: 2016-block window with epoch anchors
    return CalcNakamotoDifficulty(config, parent)
  else:
    // ASERT: per-block retarget relative to fixed anchor
    return CalcAsertDifficulty(config, anchor, parent, header)

// ASERT core idea (fixed-point, aserti3-2d)
CalcAsertDifficulty(config, anchor, parent, header):
  Δh = height(header) - anchor.height
  Δt = header.Time - anchor.parentTime   // seconds
  // τ = 600 s target, T_half = 172800 s (2 days)
  e  = ((Δt - Δh * τ) * RADIX) / T_half  // fixed-point exponent
  target = anchor.target * 2^e           // via cubic approximation in integer math
  target = clamp(target, 1, maxTarget)
  return DifficultyFromTarget(target)
Median-Time-Past (MTP)
Contrôle de sanité des horodatages, pour la validité et la résistance aux attaques time-warp.
  • MTP(parent) = médiane des 11 derniers horodatages de blocs se terminant au parent.
  • La validité exige header.Time > MTP(parent) (inégalité stricte).
  • Borne de dérive future : header.Time ≤ now + 300 s.
  • Sous ASERT, le temps écoulé relatif à l'ancre est piloté par des horodatages contraints par MTP, ce qui empêche les attaques time-warp classiques à long terme contre l'algorithme de difficulté.
Calcul du MTP
pseudocode
MTP(n):
  ts = timestamps(n, upTo=11) // back from n inclusive
  sort(ts)
  return ts[len(ts)//2]
Règle de choix de fork
La chaîne valide la plus lourde en travail cumulé, indépendamment de l'ère de difficulté active.
  • Maintenir ChainWork[tip] = ChainWork[parent] + Work(block).
  • Work(block) est une fonction monotone de target/difficulty ; toute définition cohérente aboutit à un ordonnancement équivalent.
  • Sélectionner la tête valide au plus grand ChainWork ; les égalités peuvent être départagées lexicographiquement par le hash de tête.
  • Les en-têtes invalides (temps, PoW, règles DAA-BTC / ASERT) sont exclus avant le choix de fork.
Travail cumulé (conceptuel)
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])
Réorganisations et finalité probabiliste
Garanties fondées sur la profondeur plutôt que sur une finalité absolue.
  • Une profondeur de confirmation k abaisse exponentiellement la probabilité de réorg avec k.
  • Portefeuilles et interfaces choisissent k selon la valeur exposée au risque (par ex. 6 confirmations par défaut pour les montants élevés).
  • Les nœuds peuvent mettre en place des garde-fous pratiques (par ex. profondeur de réorg maximale) pour éviter des attaques DoS venant de pairs pathologiques.
  • La réponse plus douce d'ASERT, par bloc, réduit l'incitation aux longues réorgs opportunistes ou dictées par l'oscillation, comparativement au DAA à la BTC à grande fenêtre.
Gestion des réorganisations (conceptuelle)
pseudocode
OnNewTip(candidate):
  if ChainWork[candidate] > ChainWork[currentTip]:
    currentTip = candidate
    ReorgTo(candidate)
Attaques et parades
Vecteurs clés pertinents pour la conception de la difficulté de Parallax.
  • Time-warp : l'application stricte du MTP, combinée à la rétroaction par bloc d'ASERT (sans longues fenêtres statiques), atténue la manipulation time-warp classique sur 2016 blocs à la BTC.
  • Dérive d'horodatage future : rejeter les en-têtes plus de 300 s au-delà de l'heure locale.
  • Falsification du MixDigest : header.MixDigest doit correspondre à la sortie de hashimoto (light/full).
Sous-ensemble de validité d'en-tête
pseudocode
ValidHeader(h, parent):
  require(len(h.Extra) <= MaximumExtraDataSize)
  require(h.Time <= now() + 300)
  require(h.Time > MTP(parent))
  require(h.Difficulty > 0)
  // difficulty rules depend on height:
  //   < 17560: BTC-style DAA epoch invariants
  //   ≥ 17560: ASERT anchor-based invariants
  // PoW: MixDigest match & XHash(h) <= targetFrom(D)
Pipeline

Flux de sélection de bout en bout

Les en-têtes sont vérifiés quant à la taille d'Extra, au temps (MTP et dérive future), aux règles de difficulté spécifiques à l'ère (DAA à la BTC pour les premiers blocs, ASERT pour une hauteur ≥ 17 560), aux limites de gas et EIP, à l'incrément de hauteur et au seal PoW. Les blocs valides étendent ChainWork, et la tête la plus lourde est canonique.

1
Valider
2
Vérifier l'ancre / l'ère
3
Calculer la difficulté (DAA/ASERT)
4
Cumuler le travail
5
Sélectionner la plus lourde