XHash

Der speicherharte Proof of Work, der von Parallax verwendet wird. Ethash-artiges Hashimoto mit Parallax' ASERT-basierter Schwierigkeit, Konsensregeln und Epochen-Handling.

Konsensrelevante Details
Wie in xhash/consensus.go und der Parallax-Chain-Konfiguration hinterlegt.
AspektWert / VerhaltenAnmerkungen
Hashfunktion (Seal)
Legacy Keccak-256
RLP über bestimmte Headerfelder
Target-Mapping
target = ⌊(2^256−1)/D⌋
Ergebnis muss ≤ target sein
MixDigest
Muss dem berechneten Digest entsprechen
Abweichung ⇒ ungültiger PoW
MTP
Median der letzten 11
Erzwungen: Time > MTP(parent); zukünftige Abweichung ≤ 300 s
Epochenlänge
Per Konfiguration festgelegt (z. B. 720 Blöcke)
Bestimmt den Takt der Cache-/DAG-Regeneration
Schwierigkeitsalgorithmus
ASERT (pro Block, ankerbasiert)
aserti3-2d; der Konsens berechnet D, XHash setzt es per PoW durch
Überblick
XHash ist der Proof-of-Work-Motor von Parallax: Ethash-artiges Hashimoto (Light/Full) mit Parallax-spezifischer Konsens-Verdrahtung, ASERT-basierter Schwierigkeitszuordnung und Epochen-Handling.
  • Mining wertet Hashimoto über einen Header-Seal-Hash und eine 64-Bit-Nonce aus — wahlweise mit Cache (Light) oder Dataset (Full).
  • Die Verifikation prüft die MixDigest-Gleichheit und vergleicht das Ergebnis mit einem aus der Schwierigkeit abgeleiteten Target: target = ⌊(2^256−1)/D⌋.
  • Der Seal-Hash verwendet Legacy Keccak-256 über eine RLP-Liste bestimmter Headerfelder.
SealHash
Pseudocode
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))
Mining-Schleife
Hashimoto-Light/Full mit 64-Bit-Nonce-Suche und Little-Endian-Target-Vergleich in der inneren Schleife.
  • Miner iterieren nonce ∈ [0..2^64−1] und berechnen (digest, result) = hashimoto(cache/dataset, sealHash, nonce).
  • MixDigest muss exakt dem Headerfeld entsprechen; result muss ≤ target sein.
  • Full-Miner verwenden das Epochen-Dataset; Light-Verifier/Nodes können mit Caches validieren (ohne vollständigen DAG).
  • Dataset bzw. Cache werden an Epochen-Grenzen regeneriert (z. B. alle 720 Blöcke).
Nonce-Suche (Pseudocode)
Pseudocode
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
Header-Verifikation
Was ein Node prüft, bevor er einen PoW-Header akzeptiert.
  • Größe von Extra ≤ MaximumExtraDataSize.
  • Time ≤ jetzt + 300 s und Time > MTP(parent) (Median der letzten 11).
  • Difficulty muss dem Ergebnis des Konsens-Schwierigkeitsalgorithmus (ASERT) für Parent und Header entsprechen.
  • PoW-Seal: MixDigest-Gleichheit und XHash(header) ≤ target(two256m1 / D).
verifySeal (konzeptionell)
Pseudocode
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)
Epochen, Cache & Dataset (DAG)
Regenerationstakt und Hinweise zur Miner-Kompatibilität.
  • Die Epochennummer wird aus der Blockhöhe abgeleitet; Cache- und Dataset-Größen hängen per datasetSize(height) von der Epoche ab.
  • Parallax verwendet kürzere Epochen als Legacy-Ethash (z. B. 720 Blöcke), um bei 10-Minuten-Blöcken auf eine Regenerationsdauer von etwa 5 Tagen zu kommen.
  • Nodes halten Caches vor, um die Verifikation schlank zu halten; ein vollständiger DAG ist zur Header-Validierung nicht erforderlich.
Regenerations-Trigger
Pseudocode
if newEpoch(height):
  regenerate cache
  if mining full: regenerate dataset
Schwierigkeit & Anker
Zusammenspiel zwischen PoW und dem ASERT-Schwierigkeitsplan.
  • Die Schwierigkeit wird vom ASERT-Scheduler berechnet; XHash setzt die gewählte Schwierigkeit lediglich per Target-Prüfung durch.
  • Der Konsens pflegt einen ASERT-Anker (Höhe, parentTime, Target) und nutzt Header-Metadaten (z. B. EpochStartTime oder dedizierte Felder), um den Ankerkontext zu rekonstruieren.
  • CalcAsertDifficulty(config, anchor, parent, header) leitet die erwartete Schwierigkeit für den Header ab.
  • Schwierigkeits- und Ankerinvarianten werden in der Header-Verifikation vor der Fork-Auswahl durchgesetzt.
Schwierigkeitsinvarianten (konzeptionell)
Pseudocode
verifyDifficulty(h, parent, anchor):
  expected = CalcAsertDifficulty(config, anchor, parent, h)
  require(h.Difficulty == expected)