Algoritmo de dificuldade e regras de escolha de fork

Um passo a passo preciso do histórico de ajuste de dificuldade do Parallax — DAA no estilo BTC desde o gênesis, a atualização ASERT no bloco 17.560 (PIP-0002) e a regra de escolha de fork Nakamoto baseada em trabalho acumulado.

Parâmetros de consenso
ParâmetroSímboloValorNotas
Intervalo de bloco alvo
τ
600 s
Alvo no estilo do Bitcoin
Limite de desvio de tempo futuro
300 s
5 minutos
Tamanho da amostra do MTP
11 blocos
Mediana dos últimos 11 timestamps
Histórico do algoritmo de dificuldade
DAA no estilo BTC → ASERT
Janelas de 2016 blocos no estilo BTC do gênesis até 17.559; ASERT (aserti3-2d) para blocos ≥ 17.560 (PIP-0002).
Visão geral
O Parallax mira blocos de 10 minutos usando Prova de Trabalho XHash e um algoritmo de dificuldade ASERT por bloco, após uma fase inicial de DAA no estilo BTC.
  • Do gênesis até o bloco 17.559, o Parallax usou uma janela de ajuste de dificuldade de 2016 blocos no estilo Bitcoin (DAA no estilo BTC).
  • A PIP-0002 (Migração do Algoritmo de Ajuste de Dificuldade do Estilo BTC para ASERT) ativou o ASERT no bloco 17.560.
  • O ASERT (aserti3-2d, como usado pelo Bitcoin Cash) ajusta a dificuldade a cada bloco em relação a uma âncora fixa, convergindo suavemente para o alvo de 600 s mesmo sob choques de hashrate.
  • O Median-Time-Past (MTP, mediana dos últimos 11) protege a validade dos timestamps; os nós rejeitam cabeçalhos mais de +300s no futuro e verificam o PoW com target = ⌊(2^256−1)/D⌋.
Alvo ↔ Dificuldade
Mapeamento do limiar de trabalho usado pela verificação do XHash (comum tanto à era BTC-DAA quanto à era ASERT).
  • Seja TWO256M1 = 2^256 − 1. O cabeçalho é válido se XHash(header) ≤ target, em que target = ⌊TWO256M1 / D⌋.
  • Maior dificuldade D ⇒ menor alvo ⇒ bloco mais difícil.
  • Header.MixDigest precisa ser igual ao digest computado pelo hashimoto (caminhos light/full).
  • A dificuldade deve ser estritamente positiva; zero ou negativa é inválida.
Cálculo do alvo (conceitual)
pseudocódigo
// Given difficulty D (big integer)
TWO256M1 = (1n << 256n) - 1n
target   = TWO256M1 / D
valid    = BigIntFromBytes(result) <= target
Ajuste de dificuldade: DAA no estilo BTC → ASERT
Janelas históricas de 2016 blocos; ASERT moderno por bloco, relativo a uma âncora.
  • Do gênesis até o bloco 17.559: CalcNakamotoDifficulty() implementa uma janela de 2016 blocos no estilo Bitcoin usando âncoras de época.
  • Do bloco 17.560 em diante: CalcAsertDifficulty() implementa aserti3-2d usando uma âncora fixa {anchorHeight, anchorParentTime, anchorTarget}.
  • O ASERT usa o offset de altura Δh e o tempo decorrido Δt em relação à âncora para empurrar a dificuldade para o alvo de 600 s com meia-vida de 2 dias.
  • Blocos históricos mantêm sua dificuldade original no estilo BTC-DAA e continuam sendo validados sob essas regras; o ajuste para frente é inteiramente baseado em ASERT.
Seleção de dificuldade dependente da altura (conceitual)
pseudocódigo
// 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)
Sanidade de timestamp para garantir validade e resistência a time-warp.
  • MTP(parent) = mediana dos últimos 11 timestamps de bloco terminando no pai.
  • A validade exige header.Time > MTP(parent) (desigualdade estrita).
  • Limite de desvio futuro: header.Time ≤ agora + 300s.
  • Sob o ASERT, o tempo decorrido em relação à âncora é guiado por timestamps limitados pelo MTP, o que impede ataques clássicos de time-warp de longo alcance contra o algoritmo de dificuldade.
Cálculo do MTP
pseudocódigo
MTP(n):
  ts = timestamps(n, upTo=11) // back from n inclusive
  sort(ts)
  return ts[len(ts)//2]
Regra de escolha de fork
A cadeia válida mais pesada por trabalho acumulado, independentemente da era de dificuldade em vigor.
  • Mantenha ChainWork[tip] = ChainWork[parent] + Work(block).
  • Work(block) é uma função monotônica de target/dificuldade; qualquer definição consistente produz uma ordenação equivalente.
  • Selecione a ponta válida com o maior ChainWork; empates podem ser resolvidos lexicograficamente pelo hash da ponta.
  • Cabeçalhos inválidos (por tempo, PoW ou regras BTC-DAA/ASERT) são excluídos antes da escolha de fork.
Trabalho acumulado (conceitual)
pseudocódigo
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 e finalidade probabilística
Garantias baseadas em profundidade, no lugar de finalidade absoluta.
  • A profundidade de confirmação k reduz a probabilidade de reorg exponencialmente com k.
  • Carteiras e UIs escolhem k conforme o valor em risco (por exemplo, 6 confirmações por padrão para valores altos).
  • Os nós podem implementar salvaguardas práticas (por exemplo, profundidade máxima de reorg) para evitar DoS vindo de peers patológicos.
  • A resposta mais suave e por bloco do ASERT reduz o incentivo para reorgs longos oportunistas ou guiados por oscilação, em comparação com o DAA de janela grande no estilo BTC.
Tratamento de reorg (conceitual)
pseudocódigo
OnNewTip(candidate):
  if ChainWork[candidate] > ChainWork[currentTip]:
    currentTip = candidate
    ReorgTo(candidate)
Ataques e mitigações
Vetores principais relevantes para o design de dificuldade do Parallax.
  • Time-warp: a aplicação estrita do MTP somada ao feedback por bloco do ASERT (sem longas janelas estáticas) mitiga a clássica manipulação de time-warp de 2016 blocos no estilo BTC.
  • Desvio de timestamp futuro: rejeitar cabeçalhos mais de +300s à frente do relógio local.
  • Spoofing de MixDigest: header.MixDigest precisa coincidir com a saída do hashimoto (light/full).
Subconjunto de validade do cabeçalho
pseudocódigo
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

Fluxo de seleção de ponta a ponta

Os cabeçalhos são verificados quanto ao tamanho do Extra, tempo (MTP e desvio futuro), regras de dificuldade específicas da era (DAA no estilo BTC para blocos iniciais, ASERT para altura ≥ 17.560), limites de gas/EIPs, incremento de altura e selo de PoW. Blocos válidos estendem o ChainWork, e a ponta mais pesada é a canônica.

1
Validar
2
Verificar âncora / era
3
Computar dificuldade (DAA/ASERT)
4
Acumular trabalho
5
Selecionar a mais pesada