Skip to content

Add Extension 0x0003: Coinbase Output Weights#195

Open
warioishere wants to merge 2 commits into
stratum-mining:mainfrom
warioishere:add-extension-0x0003-coinbase-output-weights
Open

Add Extension 0x0003: Coinbase Output Weights#195
warioishere wants to merge 2 commits into
stratum-mining:mainfrom
warioishere:add-extension-0x0003-coinbase-output-weights

Conversation

@warioishere
Copy link
Copy Markdown

Summary

Adds a draft extension 0x0003 — Coinbase Output Weights that allows a Job Declaration Server (JDS) to specify how the Job Declaration Client (JDC) should distribute coinbase template revenue across multiple pool-defined coinbase outputs. The mechanism is a TLV appended to AllocateMiningJobToken.Success carrying a per-output weight vector (SEQ0_64K[U32]).

This continues the conversation from:

Why an extension (not a breaking spec change)

Per @Fi3's guidance in #192 ("I'm leaning to use an extension here"), this is structured as a TLV extension. When the extension is not negotiated, nothing changes — the implicit weight vector is [1, 0, …, 0] and the existing single-output payout rule of §6.4.3 applies exactly as before.

Design choices made in this draft

A few decisions had to be made to write the doc. None of them are load-bearing — happy to flip any of them based on review.

  1. Wire shape. TLV appended to AllocateMiningJobToken.Success, mirroring the pattern of extension 0x0002 and §3.4.3.
  2. Inner encoding inside the TLV value. Canonical SEQ0_64K[U32] (explicit U16 count prefix), matching how every other array is encoded in §3.1. An alternative would be implying the count from the outer TLV Length / 4. I went with the canonical type-system encoding for consistency, but it is two bytes more on the wire.
  3. Allocation rule. amount[i] = floor(T * weights[i] / S), where T is template_revenue minus any non-zero outputs the JDC added itself, and S is the sum of weights. Uses 128-bit arithmetic to avoid overflow.
  4. Residual rule. The rounding residual (bounded by 0 ≤ residual < S) goes to the highest-weight output, tie-broken by lowest index. This was chosen because it does not assume any particular output is the pool's own — fee-less pools and pools without an output for themselves are first-class deployments. The proportionally-largest output absorbs the dust, so the bias is smallest as a percentage of that output's amount. Alternatives considered: residual to output[0] (assumes pool fee output exists), residual to last output (arbitrary).
  5. Backward-compat framing. The extension is presented as a generalization of §6.4.3, with [1, 0, …, 0] as the implicit weight vector that produces the existing behavior. I think this reads more cleanly than "this extension overrides §6.4.3" — but I am not married to the framing if the maintainers prefer to phrase it as a supersession instead.

Explicitly out of scope

Per the conversation in #192, the following are intentionally not part of this extension and are deferred to follow-up extensions, so this proposal stays narrow enough to actually land:

  • Fee-vs-subsidy split policy.
  • Trustless share attestation between JDC and JDS.
  • Pool-side share-accounting consensus (PPLNS, PPS+, etc.).
  • Output-count limits and per-miner payout thresholds. These were considered carefully — every extra output costs coinbase space that would otherwise carry fee-bearing transactions, so a 1000-output PPLNS distribution genuinely shrinks template_revenue. The conclusion is that this is operator policy, not protocol semantics: the existing coinbase_output_max_additional_size field in §6.4.3 already lets the JDS commit a space envelope that the JDC reserves on the Template Provider side, and pool-side machinery (dust thresholds, pending balance ledgers, per-block output caps, payout consolidation) sits naturally behind the weights this extension delivers. Section 4.5 of the new doc spells this out so reviewers and implementers see we considered the trade-off rather than overlooked it.

Section 4.4 of the extension doc lists the scope split, so future extensions can layer on top without conflict.

Open to feedback

This is a draft. Areas where I would value maintainer guidance:

  • Extension number. 0x0003 is a placeholder; happy to use whatever number the registry should allocate.
  • Generalization vs. supersession framing. Section 0 / §2.2 of the doc currently use the generalization framing. If a supersession framing is preferred, I will rewrite.
  • Residual rule. If "highest-weight, lowest-index tie-break" seems wrong for any reason — including reasons I have not thought of — I am open to changing it. The driver is just that fee-less and zero-pool-output pools should not have a positional bias.
  • Inner SEQ encoding. If implied-length-from-TLV is preferred over explicit SEQ0_64K[U32], I will swap it.
  • Anything else the maintainers see that I have missed.

I'd rather iterate on this PR until the shape is right than assume it's right and merge.

Files changed

  • extensions/0x0003-coinbase-output-weights.md — new extension doc (mirrors structure of 0x0002-worker-specific-hashrate-tracking.md).
  • 09-Extensions.md — registry row added.

wario_is_here added 2 commits May 10, 2026 12:32
Generalises Section 6.4.3 single-output payout rule via a TLV on
AllocateMiningJobToken.Success carrying a SEQ0_64K[U32] weight
vector. Opt-in; when not negotiated, implicit weights [1, 0, ..., 0]
preserve existing behaviour.

Continues sv2-spec discussion stratum-mining#192 / sv2-apps #388.
Clarify that the extension does not impose a wire-format cap on
output count. coinbase_output_max_additional_size from §6.4.3 already
governs space commitment; per-block output limits, dust thresholds
and pending ledgers are pool-side accounting and out of scope.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant