Coinbase 成熟度调度

Parallax 如何通过确定性、规范化的状态更新,把矿工的区块奖励托管至成熟期满。

成熟度参数
参数符号数值 / 来源说明
Coinbase 成熟区块数
M
100 区块
类似 Bitcoin 的 coinbase 成熟度
Lockbox 地址
0x0000000000000000000000000000000000000042
保留的系统账户
键前缀
"maturity:addr:","maturity:amt:"
Keccak256(prefix || 大端 height)
概览
Parallax 把区块奖励托管至固定的成熟高度,再以确定性的方式从状态 trie 的 lockbox 中释放出来。
  • 每个区块都会为高度 + M 区块预约自己的 coinbase 支付,其中 M = 100 区块。
  • 一个特殊的 lockbox 账户以状态槽的形式保存 "何时"(高度)→ (地址, 数额) 的映射。
  • 在每个高度 h,协议会检查是否有应于 h 支付的奖励,并将其转给记录在案的地址。
  • 这把待发行量与可花费供应分离开来,也让链重组的处理更平滑。
高层流程
伪代码
Finalize(header, state):
  h = header.number
  R = calcBlockReward(h)
  M = 100 blocks
  if R > 0:
    putScheduledPayout(state, h + M, header.coinbase, R)
  if due(h):
    (addr, amt) = popDuePayout(state, h)
    state.AddBalance(addr, amt)
  header.Root = state.IntermediateRoot(...)
状态键与 Lockbox 地址
保留的系统地址下,每个解锁高度对应两个存储槽。
  • 对于给定的解锁高度 H:在 schedKeyAddr(H) 处保存地址,在 schedKeyAmt(H) 处保存数额。
  • 两个键都通过对一个固定的 ASCII 前缀加上以大端 uint64 编码的 H,再做 keccak256 派生而来。
  • 是否存在以数额槽为依据;支付完成后会清除两个槽,以回收 trie 空间。
键派生(来自 consensus.go)
伪代码
schedKeyAddr(H):
  b = bigEndianUint64(H)
  return keccak256("maturity:addr:" || b)

schedKeyAmt(H):
  b = bigEndianUint64(H)
  return keccak256("maturity:amt:" || b)
支付生命周期
从被打包进区块到成熟后的转账。
  • 区块 N 被挖出 → 根据减半计划计算奖励 R_N。
  • 在解锁高度 U = N + M 处预约 (addr=coinbase_N, amt=R_N)。
  • 在高度 U 时,节点读取 (addr_U, amt_U);若 amt_U ≠ 0,则记账并清除两个槽。
  • 创世区块(高度 0)没有可花费的奖励。
时间线(文字示意)
伪代码
N:   mine block, schedule payout for U=N+M
...
U-1: pending only
U:   popDuePayout → AddBalance(addr_U, amt_U) → clear slots
U+1: nothing due for U anymore
校验与安全属性
确定性解锁、抗重放,并对链重组具有韧性。
  • 解锁逻辑由规范高度计算得出;不需要任何签名或链下触发。
  • 数额由协议自身计算(calcBlockReward)——任何 peer 都无法虚增支付。
  • 状态键的存在与否是 “应付” 的标志;记账后清除即可防止重复支付。
  • 成熟期机制延后矿工的可花费时间,降低了在链尾附近通过链重组立刻拿到手续费与区块奖励的动机。
应付检测与清除
伪代码
popDuePayout(state, H):
  rawAmt  = state.Get(lockbox, schedKeyAmt(H))
  if rawAmt == 0: return (zero, 0, false)
  rawAddr = state.Get(lockbox, schedKeyAddr(H))
  state.Set(lockbox, schedKeyAmt(H), 0)
  state.Set(lockbox, schedKeyAddr(H), 0)
  return (Address(rawAddr), BigInt(rawAmt), true)
链重组行为
围绕解锁高度发生链重组时会发生什么。
  • 发生链重组时,状态会从新的规范链重新计算;预约条目会反映规范区块序列的最新状态。
  • 如果某次支付在旧链尾的高度 H 已经发生但在新链中并未发生,那么状态回放只会按新历史记账应付的数额。
  • 由于条目以高度作为键,“幻影记账” 不可能在链重组中存活——是否清除完全跟随规范执行。
  • 这与区块在重新执行时余额和回执被重新计算的方式如出一辙。
链重组的概念伪代码
伪代码
ReorgTo(newTip):
  rewind state → parent of fork
  for block in pathTo(newTip):
    Execute(block) // schedules & payouts naturally recompute
配置
成熟度参数的位置以及客户端如何使用它。
  • 成熟度 M 被定义为 100 区块。
  • 客户端必须为矿工同时显示 “待解锁”(已预约)与 “可花费” 两类余额。
  • 区块浏览器可以通过扫描非零的 schedKeyAmt(h) 来展示即将解锁的奖励。
  • 钱包应当提示矿工:奖励的账户记账要等到高度 U 之后才可用。
区块浏览器提示(伪 RPC)
伪代码
for h in [current..current+K]:
  if getState(lockbox, schedKeyAmt(h)) != 0:
    // list upcoming payout at height h