난이도 알고리즘 & 포크 선택 규칙

Parallax 난이도 조정 역사에 대한 정확한 안내 — 제네시스부터의 BTC 스타일 DAA, 블록 17,560(PIP-0002)에서의 ASERT 업그레이드, 그리고 누적 작업량에 기반한 나카모토 포크 선택 규칙입니다.

합의 파라미터
파라미터기호비고
목표 블록 간격
τ
600 초
Bitcoin 스타일 목표
미래 시간 드리프트 한계
300 초
5분
MTP 샘플 크기
11 블록
최근 11개 타임스탬프의 중앙값
난이도 알고리즘 역사
BTC 스타일 DAA → ASERT
제네시스부터 17,559까지는 BTC 스타일 2016 블록 윈도우; 17,560 블록 이상은 ASERT(aserti3-2d) (PIP-0002).
개요
Parallax는 초기 BTC 스타일 DAA 단계 이후, XHash 작업증명과 블록당 ASERT 난이도 알고리즘으로 10분 블록을 목표합니다.
  • 제네시스부터 블록 17,559까지 Parallax는 Bitcoin 스타일 2016 블록 난이도 조정 윈도우(BTC 스타일 DAA)를 사용했습니다.
  • PIP-0002(BTC 스타일 난이도 조정 알고리즘에서 ASERT로의 마이그레이션)가 블록 17,560에서 ASERT를 활성화했습니다.
  • ASERT(Bitcoin Cash에서 사용되는 aserti3-2d)는 고정 앵커 대비 매 블록마다 난이도를 조정하여, 해시레이트 충격 속에서도 600초 목표로 부드럽게 수렴합니다.
  • Median-Time-Past(MTP, 최근 11개의 중앙값)는 타임스탬프 유효성을 보호합니다. 노드는 현재보다 +300초 이상 앞선 헤더를 거부하고, target = ⌊(2^256−1)/D⌋로 PoW를 검증합니다.
Target ↔ 난이도
XHash 검증에 사용되는 작업 임계값 매핑(BTC-DAA 및 ASERT 시대 모두에 공통).
  • TWO256M1 = 2^256 − 1이라 하자. 헤더는 XHash(header) ≤ target일 때 유효하며, target = ⌊TWO256M1 / D⌋.
  • 난이도 D가 높을수록 ⇒ target이 작아지고 ⇒ 블록 해결이 어려워짐.
  • Header.MixDigest는 hashimoto(라이트/풀 경로)에서 계산된 digest와 같아야 함.
  • 난이도는 반드시 양수; 0 또는 음수는 유효하지 않음.
타깃 계산 (개념적)
의사코드
// Given difficulty D (big integer)
TWO256M1 = (1n << 256n) - 1n
target   = TWO256M1 / D
valid    = BigIntFromBytes(result) <= target
난이도 조정: BTC 스타일 DAA → ASERT
과거의 2016 블록 윈도우, 현재의 앵커 대비 블록당 ASERT.
  • 제네시스 → 블록 17,559: CalcNakamotoDifficulty()가 에포크 앵커를 이용한 Bitcoin 스타일 2016 블록 윈도우를 구현.
  • 블록 17,560 이후: CalcAsertDifficulty()가 고정 앵커 {anchorHeight, anchorParentTime, anchorTarget}를 이용해 aserti3-2d를 구현.
  • ASERT는 앵커 대비 높이 오프셋 Δh와 경과 시간 Δt를 사용하여 2일 반감기로 난이도를 600초 목표로 이끕니다.
  • 과거 블록들은 원래의 BTC 스타일 DAA 난이도를 그대로 유지하며 여전히 그 규칙 하에 검증됩니다. 앞으로의 조정은 전적으로 ASERT 기반입니다.
높이 의존적 난이도 선택 (개념적)
의사코드
// 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)
유효성과 시간 왜곡 저항을 위한 타임스탬프 검증.
  • MTP(parent) = parent에서 끝나는 최근 11개 블록 타임스탬프의 중앙값.
  • 유효성 조건: header.Time > MTP(parent) (엄격한 부등식).
  • 미래 드리프트 한계: header.Time ≤ now + 300초.
  • ASERT 하에서 앵커 대비 경과 시간은 MTP에 의해 제약된 타임스탬프로 결정되므로, 난이도 알고리즘에 대한 고전적인 장기 시간 왜곡 공격을 방지합니다.
MTP 계산
의사코드
MTP(n):
  ts = timestamps(n, upTo=11) // back from n inclusive
  sort(ts)
  return ts[len(ts)//2]
포크 선택 규칙
활성 난이도 시대와 무관하게 누적 작업량이 가장 큰 유효 체인.
  • ChainWork[tip] = ChainWork[parent] + Work(block)을 유지.
  • Work(block)은 target/난이도의 단조 함수이며, 일관된 정의이기만 하면 동등한 순서를 산출합니다.
  • ChainWork가 가장 큰 유효 팁을 선택; 동률은 팁 해시의 사전식 순서로 깨뜨릴 수 있습니다.
  • 유효하지 않은 헤더(시간, PoW, BTC-DAA/ASERT 규칙 위반)는 포크 선택 전에 제외됩니다.
누적 작업량 (개념적)
의사코드
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])
재구성 & 확률적 최종성
절대 최종성 대신 깊이 기반의 보장.
  • 컨펌 깊이 k가 증가할수록 재구성 확률은 지수적으로 낮아집니다.
  • 지갑/UI는 위험 가치에 따라 k를 선택합니다(예: 고가치에는 기본 6 컨펌).
  • 노드는 병적 피어로부터의 DoS를 피하기 위해 실용적 가드(예: 최대 재구성 깊이)를 구현할 수 있습니다.
  • ASERT의 더 부드러운 블록당 난이도 반응은 대형 윈도우 BTC 스타일 DAA에 비해 진동 주도형 또는 기회주의적 장기 재구성의 유인을 줄입니다.
재구성 처리 (개념적)
의사코드
OnNewTip(candidate):
  if ChainWork[candidate] > ChainWork[currentTip]:
    currentTip = candidate
    ReorgTo(candidate)
공격 & 완화
Parallax 난이도 설계와 관련된 주요 공격 벡터.
  • 시간 왜곡: 엄격한 MTP 강제와 ASERT의 블록당 피드백(긴 정적 윈도우 없음)은 고전적인 BTC 스타일 2016 블록 시간 왜곡 조작을 완화합니다.
  • 미래 타임스탬프 왜곡: 로컬 시간보다 +300초 이상 앞선 헤더는 거부됩니다.
  • MixDigest 위조: header.MixDigest는 hashimoto(라이트/풀) 출력과 반드시 일치해야 합니다.
헤더 유효성 일부
의사코드
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)
파이프라인

엔드 투 엔드 선택 흐름

헤더는 Extra 크기, 시간(MTP & 미래 드리프트), 시대별 난이도 규칙(초기 블록은 BTC 스타일 DAA, 높이 ≥ 17,560은 ASERT), 가스 한도/EIP, 높이 증분, PoW 씰을 기준으로 검사됩니다. 유효한 블록은 ChainWork를 확장하며, 가장 무거운 팁이 정규입니다.

1
검증
2
앵커 / 시대 확인
3
난이도 계산 (DAA/ASERT)
4
작업량 누적
5
가장 무거운 체인 선택