XHash

El Proof-of-Work memory-hard utilizado por Parallax. Hashimoto estilo Ethash con la dificultad basada en ASERT, las reglas de consenso y la gestión de épocas de Parallax.

Detalles Relevantes para el Consenso
Según se refleja en xhash/consensus.go y la configuración de la cadena Parallax.
AspectoValor / ComportamientoNotas
Función hash (sello)
Legacy Keccak-256
RLP sobre campos específicos de la cabecera
Mapeo del objetivo
target = ⌊(2^256−1)/D⌋
El resultado debe ser ≤ target
MixDigest
Debe coincidir con el digest computado
Si no coincide ⇒ PoW inválido
MTP
Mediana de los últimos 11
Aplicado: Time > MTP(padre); deriva futura ≤ 300s
Longitud de época
Definida por config (p. ej., 720 bloques)
Determina la cadencia de regeneración de cache/DAG
Algoritmo de dificultad
ASERT (por bloque, basado en anclaje)
aserti3-2d; el consenso calcula D, XHash lo impone vía PoW
Visión General
XHash es el motor de Proof-of-Work de Parallax: Hashimoto estilo Ethash (light/full) con cableado de consenso específico de Parallax, mapeo de dificultad basado en ASERT y gestión de épocas.
  • La minería evalúa Hashimoto sobre un seal hash de cabecera y un nonce de 64 bits, usando una cache (light) o un dataset (full).
  • La verificación comprueba la igualdad del MixDigest y compara el resultado con un target derivado de la dificultad: target = ⌊(2^256−1)/D⌋.
  • El seal hash usa Legacy Keccak-256 sobre una lista RLP de campos específicos de la cabecera.
SealHash
pseudocódigo
SealHash(header):
  enc = [
    header.ParentHash,
    header.Coinbase,
    header.Root,
    header.TxHash,
    header.ReceiptHash,
    header.Bloom,
    header.Difficulty,
    header.Number,
    header.GasLimit,
    header.GasUsed,
    header.Time,
    header.Extra,
    header.EpochStartTime,
  ]
  if header.BaseFee != nil:
    enc.append(header.BaseFee)
  return keccak256(rlp.encode(enc))
Bucle de Minería
Hashimoto light/full con búsqueda de nonce de 64 bits y comparación de target little-endian en el bucle interno.
  • Los mineros iteran nonce ∈ [0..2^64−1], calculando (digest, result) = hashimoto(cache/dataset, sealHash, nonce).
  • MixDigest debe coincidir exactamente con el campo de la cabecera; result debe ser ≤ target.
  • Los mineros full usan el dataset por época; los verificadores/nodos light pueden validar con caches (sin DAG completo).
  • Dataset/cache se regeneran en los límites de época (p. ej., cada 720 bloques).
Búsqueda de nonce (pseudocódigo)
pseudocódigo
mine(header, cacheOrDataset):
  target = floor((2^256 - 1) / header.Difficulty)
  nonce  = random64()
  loop:
    (mix, res) = hashimoto(cacheOrDataset, SealHash(header), nonce)
    if mix == header.MixDigest and Big(res) <= target:
      return nonce
    nonce = (nonce + 1) mod 2^64
Verificación de Cabecera
Lo que un nodo comprueba antes de aceptar una cabecera PoW.
  • Tamaño de Extra ≤ MaximumExtraDataSize.
  • Time ≤ ahora + 300s y Time > MTP(padre) (mediana de los últimos 11).
  • La dificultad debe coincidir con el motor de dificultad de consenso (ASERT) para el padre y la cabecera dados.
  • Sello PoW: igualdad de MixDigest y XHash(header) ≤ target(two256m1 / D).
verifySeal (conceptual)
pseudocódigo
verifySeal(h):
  require(h.Difficulty > 0)
  if fulldag:
    (mix, res) = hashimotoFull(dataset(epoch(h.Number)), SealHash(h), h.Nonce)
  else:
    (mix, res) = hashimotoLight(datasetSize(h.Number), cache(epoch(h.Number)), SealHash(h), h.Nonce)
  require(mix == h.MixDigest)
  target = floor((2^256 - 1) / h.Difficulty)
  require(Big(res) <= target)
Épocas, Cache y Dataset (DAG)
Cadencia de regeneración y notas de compatibilidad con mineros.
  • El número de época se deriva de la altura del bloque; los tamaños de cache/dataset dependen de la época vía datasetSize(height).
  • Parallax usa épocas más cortas que el Ethash clásico (p. ej., épocas de 720 bloques) para encajar una regeneración de ~5 días con bloques de 10 minutos.
  • Los nodos mantienen caches para que la verificación sea ligera; no se requiere un DAG completo para validar cabeceras.
Disparador de regeneración
pseudocódigo
if newEpoch(height):
  regenerate cache
  if mining full: regenerate dataset
Dificultad y Anclajes
Interacción entre el PoW y el calendario de dificultad ASERT.
  • La dificultad la calcula el planificador ASERT; XHash simplemente impone la dificultad elegida mediante la comprobación del target.
  • El consenso mantiene un anclaje ASERT (altura, tiempo del padre, target) y usa metadatos de la cabecera (p. ej., EpochStartTime o campos dedicados) para reconstruir el contexto del anclaje.
  • CalcAsertDifficulty(config, anchor, parent, header) deriva la dificultad esperada para la cabecera.
  • Las invariantes de dificultad y anclaje se imponen en la verificación de cabecera antes de la elección de fork.
Invariantes de dificultad (conceptual)
pseudocódigo
verifyDifficulty(h, parent, anchor):
  expected = CalcAsertDifficulty(config, anchor, parent, h)
  require(h.Difficulty == expected)