XHash

Parallax 所用的内存难解工作量证明。Ethash 风格的 Hashimoto,结合 Parallax 基于 ASERT 的难度、共识规则与 epoch 处理。

共识相关细节
依据 xhash/consensus.go 与 Parallax 链配置。
项目数值 / 行为说明
哈希函数(seal)
Legacy Keccak-256
对特定区块头字段进行 RLP 编码
目标映射
target = ⌊(2^256−1)/D⌋
结果必须 ≤ target
MixDigest
必须等于计算所得的摘要
不一致 ⇒ PoW 无效
MTP
最近 11 个时间戳的中位数
强制:Time > MTP(parent);未来漂移 ≤ 300 秒
Epoch 长度
由配置定义(例如 720 区块)
决定 cache/DAG 重建的频率
难度算法
ASERT(基于锚点的逐区块算法)
aserti3-2d;共识负责计算 D,XHash 通过 PoW 强制执行
概览
XHash 是 Parallax 的工作量证明引擎:Ethash 风格的 Hashimoto(light/full),配以 Parallax 专属的共识接线、基于 ASERT 的难度映射以及 epoch 处理。
  • 挖矿过程在区块头 seal 哈希与 64 位 nonce 之上对 Hashimoto 求值,可使用 cache(light)或 dataset(full)。
  • 校验时检查 MixDigest 是否相等,并将结果与由难度推导出的 target 进行比较:target = ⌊(2^256−1)/D⌋。
  • Seal 哈希对特定区块头字段做 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))
挖矿循环
Hashimoto-light/full,在内层循环中以 64 位 nonce 搜索并以小端方式比较 target。
  • 矿工在 nonce ∈ [0..2^64−1] 范围内迭代,计算 (digest, result) = hashimoto(cache/dataset, sealHash, nonce)。
  • MixDigest 必须与区块头字段完全一致;result 必须 ≤ target。
  • 全节点矿工使用按 epoch 切分的 dataset;轻量验证者与节点可仅凭 cache 完成校验,无需完整 DAG。
  • Dataset 与 cache 在 epoch 边界处重建(例如每 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 个的中位数)。
  • 对于给定的 parent 和 header,Difficulty 必须与共识难度引擎(ASERT)一致。
  • PoW seal: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)
Epoch、Cache 与 Dataset(DAG)
重建频率与对矿工兼容性的说明。
  • Epoch 编号由区块高度推导而来;cache/dataset 的大小依赖于 epoch,由 datasetSize(height) 决定。
  • Parallax 使用比传统 Ethash 更短的 epoch(例如 720 区块),以匹配 10 分钟出块下约 5 天一次的重建节奏。
  • 节点保留 cache 即可让校验保持轻量;校验区块头并不需要完整 DAG。
重建触发条件
伪代码
if newEpoch(height):
  regenerate cache
  if mining full: regenerate dataset
难度与锚点
PoW 与 ASERT 难度时间表之间的相互作用。
  • 难度由 ASERT 调度器计算;XHash 只是通过 target 检查来强制执行已选定的难度。
  • 共识维护一个 ASERT 锚点 (height, parentTime, target),并通过区块头中的元数据(例如 EpochStartTime 或专用字段)来重建锚点上下文。
  • CalcAsertDifficulty(config, anchor, parent, header) 为该区块头推导出预期难度。
  • 难度与锚点的不变量在分叉选择之前的区块头校验阶段就被强制执行。
难度不变量(概念)
伪代码
verifyDifficulty(h, parent, anchor):
  expected = CalcAsertDifficulty(config, anchor, parent, h)
  require(h.Difficulty == expected)