XHash

A Prova de Trabalho memory-hard usada pelo Parallax. Hashimoto no estilo Ethash com a dificuldade baseada em ASERT, as regras de consenso e o tratamento de épocas do Parallax.

Detalhes relevantes ao consenso
Conforme refletido em xhash/consensus.go e na configuração da chain Parallax.
AspectoValor / ComportamentoNotas
Função de hash (selo)
Legacy Keccak-256
RLP sobre campos específicos do cabeçalho
Mapeamento de alvo
target = ⌊(2^256−1)/D⌋
O resultado precisa ser ≤ target
MixDigest
Precisa ser igual ao digest computado
Divergência ⇒ PoW inválido
MTP
Mediana dos últimos 11
Imposto: Time > MTP(parent); desvio futuro ≤ 300s
Tamanho da época
Definido por configuração (ex.: 720 blocos)
Determina a cadência de regeneração de cache/DAG
Algoritmo de dificuldade
ASERT (por bloco, baseado em âncora)
aserti3-2d; o consenso calcula D, o XHash o impõe via PoW
Visão geral
O XHash é o motor de Prova de Trabalho do Parallax: Hashimoto no estilo Ethash (light/full) com integração de consenso específica do Parallax, mapeamento de dificuldade baseado em ASERT e tratamento de épocas.
  • A mineração avalia o Hashimoto sobre um seal hash de cabeçalho e um nonce de 64 bits, usando um cache (light) ou dataset (full).
  • A verificação checa a igualdade do MixDigest e compara o resultado a um alvo derivado da dificuldade: target = ⌊(2^256−1)/D⌋.
  • O seal hash usa Legacy Keccak-256 sobre uma lista RLP de campos específicos do cabeçalho.
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))
Loop de mineração
Hashimoto light/full com busca de nonce de 64 bits e comparação de alvo em little-endian no loop interno.
  • Os mineradores iteram nonce ∈ [0..2^64−1], computando (digest, result) = hashimoto(cache/dataset, sealHash, nonce).
  • O MixDigest precisa corresponder exatamente ao campo do cabeçalho; o resultado precisa ser ≤ target.
  • Mineradores full usam o dataset por época; verificadores e nós leves podem validar com caches (sem a DAG completa).
  • O dataset e o cache são regenerados nas fronteiras de época (por exemplo, a cada 720 blocos).
Busca 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
Verificação de cabeçalho
O que um nó verifica antes de aceitar um cabeçalho com PoW.
  • Tamanho de Extra ≤ MaximumExtraDataSize.
  • Time ≤ agora + 300s e Time > MTP(parent) (mediana dos últimos 11).
  • A dificuldade precisa coincidir com o motor de dificuldade de consenso (ASERT) para o pai e o cabeçalho informados.
  • Selo PoW: igualdade do MixDigest e XHash(header) ≤ target(two256m1 / D).
verifySeal (conceitual)
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 e dataset (DAG)
Cadência de regeneração e notas de compatibilidade com os mineradores.
  • O número da época é derivado da altura do bloco; os tamanhos de cache e dataset dependem da época via datasetSize(height).
  • O Parallax usa épocas mais curtas do que as do Ethash legado (por exemplo, épocas de 720 blocos) para caber em uma regeneração de cerca de 5 dias com blocos de 10 minutos.
  • Os nós mantêm caches para manter a verificação leve; não é preciso uma DAG completa para validar cabeçalhos.
Gatilho de regeneração
pseudocódigo
if newEpoch(height):
  regenerate cache
  if mining full: regenerate dataset
Dificuldade e âncoras
Interação entre o PoW e o cronograma de dificuldade do ASERT.
  • A dificuldade é calculada pelo agendador ASERT; o XHash apenas impõe a dificuldade escolhida por meio da verificação de alvo.
  • O consenso mantém uma âncora ASERT (altura, parentTime, target) e usa metadados do cabeçalho (por exemplo, EpochStartTime ou campos dedicados) para reconstruir o contexto da âncora.
  • CalcAsertDifficulty(config, anchor, parent, header) deriva a dificuldade esperada para o cabeçalho.
  • As invariantes de dificuldade e de âncora são aplicadas na verificação do cabeçalho, antes da escolha de fork.
Invariantes de dificuldade (conceitual)
pseudocódigo
verifyDifficulty(h, parent, anchor):
  expected = CalcAsertDifficulty(config, anchor, parent, h)
  require(h.Difficulty == expected)