Coinbase-Reife-Scheduling

Wie Parallax Miner-Subventionen bis zur Reife mittels deterministischer, kanonischer Zustandsaktualisierungen hinterlegt.

Reife-Parameter
ParameterSymbolWert / QuelleAnmerkungen
Coinbase-Reife in Blöcken
M
100 Blöcke
Bitcoin-artige Coinbase-Reife
Lockbox-Adresse
0x0000000000000000000000000000000000000042
Reserviertes Systemkonto
Schlüsselpräfixe
"maturity:addr:", "maturity:amt:"
Keccak256(prefix || big-endian height)
Überblick
Parallax hinterlegt Blocksubventionen bis zu einer festen Reifehöhe und gibt sie deterministisch aus einer Lockbox im State Trie frei.
  • Jeder Block plant seine eigene Coinbase-Auszahlung für height + M Blöcke, wobei M = 100 Blöcke.
  • Ein spezielles Lockbox-Konto speichert Paare „Wann" (Höhe) → (Adresse, Betrag) als Zustandsslots.
  • Bei jeder Höhe h prüft das Protokoll, ob eine Auszahlung für h fällig ist, und überweist sie an die hinterlegte Adresse.
  • Dies trennt ausstehende Emission von verfügbarem Angebot und glättet das Reorg-Handling.
Ablauf auf hoher Ebene
Pseudocode
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(...)
Zustandsschlüssel & Lockbox-Adresse
Zwei Speicherslots pro Freigabehöhe unter einer reservierten Systemadresse.
  • Für eine Freigabehöhe H: Adresse unter schedKeyAddr(H) und Betrag unter schedKeyAmt(H) speichern.
  • Beide Schlüssel werden per keccak256 eines festen ASCII-Präfixes plus H als Big-Endian-uint64 abgeleitet.
  • Das Vorhandensein wird am Betragsslot festgemacht; bei Auszahlung werden beide Slots geleert, um Trie-Speicher freizugeben.
Schlüsselableitung (aus consensus.go)
Pseudocode
schedKeyAddr(H):
  b = bigEndianUint64(H)
  return keccak256("maturity:addr:" || b)

schedKeyAmt(H):
  b = bigEndianUint64(H)
  return keccak256("maturity:amt:" || b)
Auszahlungs-Lebenszyklus
Von der Blockaufnahme bis zur ausgereiften Überweisung.
  • Block N wird gemined → Belohnung R_N wird aus dem Halving-Plan berechnet.
  • Planung von (addr=coinbase_N, amt=R_N) bei Freigabehöhe U = N + M.
  • Bei Höhe U liest der Node (addr_U, amt_U); ist amt_U ≠ 0, wird gutgeschrieben und die Slots werden geleert.
  • Die Genesis (Höhe 0) kennt keine ausgabefähige Subvention.
Zeitleiste (textuelles Diagramm)
Pseudocode
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
Validierung & Sicherheitseigenschaften
Deterministische Freigaben, replay-sicher und reorg-resistent.
  • Die Freigabelogik wird aus der kanonischen Höhe berechnet; weder Signaturen noch Off-Chain-Trigger sind erforderlich.
  • Beträge werden protokollseitig berechnet (calcBlockReward) — Peers können die Auszahlungen nicht inflationieren.
  • Das Vorhandensein eines Zustandsschlüssels ist die Fälligkeitsanzeige; Double-Spend wird durch das Leeren nach der Gutschrift verhindert.
  • Die Reifeverzögerung schiebt die Ausgabefähigkeit auf und verringert den Anreiz für Near-Tip-Reorgs, um Gebühren und Subvention sofort einzusacken.
Fälligkeitsprüfung & Leeren
Pseudocode
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)
Reorg-Verhalten
Was passiert, wenn sich die Kette um Freigabehöhen herum reorganisiert.
  • Bei einem Reorg wird der Zustand aus der neuen kanonischen Kette neu berechnet; geplante Einträge spiegeln die kanonische Blockfolge wider.
  • Fand eine Auszahlung bei Höhe H auf der alten Spitze statt, nicht aber auf der neuen Kette, schreibt das Zustands-Replay nur das gut, was unter der neuen Historie fällig ist.
  • Da Einträge an Höhen geknüpft sind, können „Phantom-Gutschriften" einen Reorg nicht überstehen — der Status geleert/nicht geleert folgt der kanonischen Ausführung.
  • Dies entspricht der Art und Weise, wie sich Guthaben und Quittungen bei der Neu-Ausführung von Blöcken ebenfalls neu berechnen.
Konzeptioneller Reorg-Pseudocode
Pseudocode
ReorgTo(newTip):
  rewind state → parent of fork
  for block in pathTo(newTip):
    Execute(block) // schedules & payouts naturally recompute
Konfiguration
Wo der Reife-Parameter verankert ist und wie Clients ihn verwenden.
  • Die Reife M ist mit 100 Blöcken definiert.
  • Clients müssen für Miner sowohl „ausstehende" (geplante) als auch „verfügbare" Guthaben anzeigen.
  • Explorer können bevorstehende Freigaben anzeigen, indem sie nach einem von null verschiedenen schedKeyAmt(h) scannen.
  • Wallets sollten Miner darauf hinweisen, dass Belohnungs-UTXOs (Kontogutschriften) erst bei Höhe U verfügbar sind.
Explorer-Hinweis (Pseudo-RPC)
Pseudocode
for h in [current..current+K]:
  if getState(lockbox, schedKeyAmt(h)) != 0:
    // list upcoming payout at height h