XHash

Parallax가 사용하는 메모리 하드 작업증명. Parallax의 ASERT 기반 난이도, 합의 규칙, 에포크 처리를 갖춘 Ethash 스타일 Hashimoto입니다.

합의 관련 세부사항
xhash/consensus.go와 Parallax 체인 설정에 반영된 내용.
항목값 / 동작비고
해시 함수 (씰)
Legacy Keccak-256
특정 헤더 필드에 대한 RLP
타깃 매핑
target = ⌊(2^256−1)/D⌋
결과는 ≤ target 이어야 함
MixDigest
계산된 digest와 같아야 함
불일치 ⇒ 유효하지 않은 PoW
MTP
최근 11개의 중앙값
강제: Time > MTP(parent); 미래 드리프트 ≤ 300초
에포크 길이
설정에서 정의 (예: 720 블록)
캐시/DAG 재생성 주기를 결정
난이도 알고리즘
ASERT (블록당, 앵커 기반)
aserti3-2d; 합의가 D를 계산하고 XHash가 PoW로 강제
개요
XHash는 Parallax의 작업증명 엔진입니다: Ethash 스타일 Hashimoto(라이트/풀)에 Parallax 전용 합의 결선, ASERT 기반 난이도 매핑, 에포크 처리를 갖춘 구조입니다.
  • 채굴은 헤더 씰 해시와 64비트 nonce에 대해 Hashimoto를 평가하며, 캐시(라이트) 또는 데이터셋(풀)을 사용합니다.
  • 검증은 MixDigest 동등성을 확인하고, 결과를 난이도에서 파생된 타깃(target = ⌊(2^256−1)/D⌋)과 비교합니다.
  • 씰 해시는 특정 헤더 필드의 RLP 리스트에 대해 Legacy Keccak-256을 사용합니다.
SealHash
의사코드
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))
채굴 루프
64비트 nonce 탐색과 내부 루프의 리틀엔디안 타깃 비교를 포함한 Hashimoto 라이트/풀.
  • 채굴자는 nonce ∈ [0..2^64−1]를 순회하며 (digest, result) = hashimoto(cache/dataset, sealHash, nonce)를 계산합니다.
  • MixDigest는 헤더 필드와 정확히 일치해야 하며, result는 ≤ target 이어야 합니다.
  • 풀 채굴자는 에포크별 데이터셋을 사용하고, 라이트 검증자/노드는 캐시로 검증할 수 있습니다(풀 DAG 불필요).
  • 데이터셋/캐시는 에포크 경계(예: 매 720 블록)에서 재생성됩니다.
Nonce 탐색 (의사코드)
의사코드
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
헤더 검증
PoW 헤더를 수락하기 전에 노드가 확인하는 항목.
  • Extra 크기 ≤ MaximumExtraDataSize.
  • Time ≤ now + 300초 및 Time > MTP(parent) (최근 11의 중앙값).
  • 난이도는 주어진 부모와 헤더에 대해 합의 난이도 엔진(ASERT)과 일치해야 합니다.
  • PoW 씰: MixDigest 동등성 및 XHash(header) ≤ target(two256m1 / D).
verifySeal (개념적)
의사코드
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)
에포크, 캐시 & 데이터셋 (DAG)
재생성 주기와 채굴자 호환성에 관한 메모.
  • 에포크 번호는 블록 높이로부터 파생되며, 캐시/데이터셋 크기는 에포크에 따라 datasetSize(height)로 결정됩니다.
  • Parallax는 10분 블록에서 약 5일 재생성에 맞추기 위해 기존 Ethash보다 짧은 에포크(예: 720 블록 에포크)를 사용합니다.
  • 노드는 검증을 가볍게 유지하기 위해 캐시를 보관하며, 헤더 검증에 풀 DAG는 필요 없습니다.
재생성 트리거
의사코드
if newEpoch(height):
  regenerate cache
  if mining full: regenerate dataset
난이도 & 앵커
PoW와 ASERT 난이도 스케줄 간의 상호작용.
  • 난이도는 ASERT 스케줄러가 계산하며, XHash는 타깃 검사로 선택된 난이도를 단순히 강제합니다.
  • 합의는 ASERT 앵커(height, parentTime, target)를 유지하고, 헤더 메타데이터(예: EpochStartTime 또는 전용 필드)를 사용해 앵커 문맥을 재구성합니다.
  • CalcAsertDifficulty(config, anchor, parent, header)는 헤더에 대한 기대 난이도를 도출합니다.
  • 난이도와 앵커 불변성은 포크 선택 전에 헤더 검증에서 강제됩니다.
난이도 불변성 (개념적)
의사코드
verifyDifficulty(h, parent, anchor):
  expected = CalcAsertDifficulty(config, anchor, parent, h)
  require(h.Difficulty == expected)