Programación de Madurez de Coinbase

Cómo Parallax pone en depósito los subsidios del minero hasta su madurez mediante actualizaciones de estado canónicas y deterministas.

Parámetros de Madurez
ParámetroSímboloValor / FuenteNotas
Bloques de madurez de coinbase
M
100 bloques
Madurez de coinbase al estilo de Bitcoin
Dirección del lockbox
0x0000000000000000000000000000000000000042
Cuenta de sistema reservada
Prefijos de clave
"maturity:addr:", "maturity:amt:"
Keccak256(prefijo || altura big-endian)
Visión General
Parallax deposita los subsidios de bloque hasta una altura de madurez fija, liberándolos de forma determinista desde un lockbox en el state trie.
  • Cada bloque programa su propio pago de coinbase a altura + M bloques, donde M = 100 bloques.
  • Una cuenta lockbox especial almacena pares "cuándo" (altura) → (dirección, importe) como slots de estado.
  • En cada altura h, el protocolo comprueba si hay algún pago pendiente para h y lo transfiere a la dirección registrada.
  • Esto separa la emisión pendiente del suministro gastable y suaviza la gestión de reorgs.
Flujo de alto nivel
pseudocódigo
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(...)
Claves de Estado y Dirección del Lockbox
Dos slots de almacenamiento por altura de desbloqueo bajo una dirección de sistema reservada.
  • Para una altura de desbloqueo H dada: se almacena la dirección en schedKeyAddr(H) y el importe en schedKeyAmt(H).
  • Ambas claves se derivan por keccak256 de un prefijo ASCII fijo más H codificado como uint64 big-endian.
  • La presencia se determina por el slot del importe; el pago borra ambos slots para recuperar espacio en el trie.
Derivación de claves (de consensus.go)
pseudocódigo
schedKeyAddr(H):
  b = bigEndianUint64(H)
  return keccak256("maturity:addr:" || b)

schedKeyAmt(H):
  b = bigEndianUint64(H)
  return keccak256("maturity:amt:" || b)
Ciclo de Vida del Pago
Desde la inclusión en el bloque hasta la transferencia madurada.
  • Se mina el bloque N → se calcula la recompensa R_N a partir del calendario de halving.
  • Programar (addr=coinbase_N, amt=R_N) en la altura de desbloqueo U = N + M.
  • En la altura U, el nodo lee (addr_U, amt_U); si amt_U ≠ 0, acredita y borra los slots.
  • El génesis (altura 0) no tiene subsidio gastable.
Línea temporal (diagrama textual)
pseudocódigo
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
Propiedades de Validación y Seguridad
Desbloqueos deterministas, seguros frente a replay y resilientes a reorgs.
  • La lógica de desbloqueo se computa a partir de la altura canónica; no se requieren firmas ni disparadores off-chain.
  • Los importes los calcula el protocolo (calcBlockReward) — los pares no pueden inflar los pagos.
  • La presencia de la clave de estado es el indicador "pendiente"; el doble gasto se evita limpiando tras el crédito.
  • La madurez aplaza la capacidad de gasto del minero, reduciendo los incentivos para reorgs cerca de la punta que buscan capturar fees+subsidio inmediatamente.
Detección de pendientes y limpieza
pseudocódigo
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)
Comportamiento ante Reorgs
Qué ocurre si la cadena se reorganiza en torno a alturas de desbloqueo.
  • En un reorg, el estado se recomputa desde la nueva cadena canónica; las entradas programadas reflejan la secuencia canónica de bloques.
  • Si un pago ocurrió en la altura H en la antigua punta pero no en la nueva cadena, el replay de estado solo acreditará lo que corresponda bajo la nueva historia.
  • Como las entradas están indexadas por altura, los "créditos fantasma" no pueden sobrevivir a un reorg — el estado limpio/no limpio sigue la ejecución canónica.
  • Esto refleja cómo se recomputan saldos y recibos durante la re-ejecución de bloques.
Pseudocódigo conceptual de reorg
pseudocódigo
ReorgTo(newTip):
  rewind state → parent of fork
  for block in pathTo(newTip):
    Execute(block) // schedules & payouts naturally recompute
Configuración
Dónde vive el parámetro de madurez y cómo lo consumen los clientes.
  • La madurez M está definida como 100 bloques
  • Los clientes deben mostrar para los mineros tanto los saldos 'pendientes' (programados) como los 'gastables'.
  • Los exploradores pueden mostrar desbloqueos próximos escaneando valores no nulos de schedKeyAmt(h).
  • Las wallets deberían advertir a los mineros que los UTXOs de recompensa (créditos en cuenta) no están disponibles hasta la altura U.
Pista para explorador (pseudo-RPC)
pseudocódigo
for h in [current..current+K]:
  if getState(lockbox, schedKeyAmt(h)) != 0:
    // list upcoming payout at height h