Inspired by Scaling Noncustodial Mining Payouts with CTV, I’ve been working on a qbit pool implementation. qbit is a UTXO chain with post-quantum signatures and OP_CTV, so it has been a useful testbed for CTV-based mining payouts.
Direct coinbase outputs are scarce because the coinbase has to stay small enough for stock miner firmware to handle. So most recipients settle through precommitted CTV fanouts. The fanout’s fee is fixed by the covenant hash at template-build time, ~17 hours (1,000-block coinbase maturity) before it can be broadcast. How to choose that fee is the decision I’d like feedback on.
We ruled out the zero-fee-parent + P2A/CPFP route and instead build the fee into the fanout, with every recipient paying a proportional share of it, for two reasons:
No funded relayer. Anyone holding the published artifact bytes can broadcast a fee-paying fanout at maturity, with no wallet, no capital, and no package relay. A zero-fee parent instead needs a funded broadcaster around for as long as any fanout is unclaimed.
Dust defense. Every payout must cover its fee share and still clear the economic floor, or it’s pruned back to carry-forward. Sybil swarms of tiny mining identities therefore can’t force uneconomic outputs onto the pool or other miners. The floor is unusually high on qbit because post-quantum P2MR inputs cost ~3,680 bytes to spend, so keeping uneconomic outputs off the chain matters even more here than it would on Bitcoin.
We also learned live that the obvious hybrid of built-in fee plus a 0-sat P2A anchor for top-ups is nonstandard: qbit inherits Bitcoin Core’s ephemeral-dust policy (`dust, tx with dust output must be 0-fee`), so the same limitation applies to any Bitcoin CTV pool.
That makes the committed fee the only fee. Today we use the node’s fee rate estimate × 1.2. If it proves too low, recipients can CPFP their own outputs.
The question: how would you price a fee committed ~17 hours before broadcast? Spot estimate × fixed premium, a multi-day fee average to smooth out spikes, or just a larger fixed premium?
Curious how others would weigh this, thanks in advance!
It sounds like you are optimizing for the initial onboarding transaction over the steady state of payouts. This feels like a strange choice to me. Do you expect most miners to churn out after their first payout? I would expect the opposite and optimize for the 99.9% case instead of the 0.1% case. The downside of having users pay the fee to mine the fanout transaction doesn’t seem that bad either. A miner who can’t pay the fee can simply wait for someone else to fee bump the fanout transaction.
My approach in the original design was to attach a 1sat/vb fee, funded from the coinbase output, and also an anchor output for users to fee bump if necessary. This way they can simply wait for the fanout to get mined during a low fee period or if someone is motivated enough to fee bump the whole fanout transaction they can pay to accelerate everyone’s payouts. So low time preference miners always get paid eventually, high time preference miners are forced to subsidize the fee bump of everyone else in that fanout. Seems fair to me.
I also ran into the standardness problem when building the fanout transaction. I limited it to 319 outputs due to one rule and a ~300 sat anchor output due to another rule. (This was before zero-fee anchors were implemented.) This is very frustrating for a mining pool because block producers don’t need to follow standardness rules.
Your pool can include non-standard payout transactions in the blocks it mines with zero problems. You only need to produce standard fanout transactions if you want every block producer to have a chance to mine those transactions.
Standardness rules are not really bitcoin rules. They are an attempt to control (or censor ) transactions that flow through the node network before they are mined. But, as Peter Todd has shown with Libre Relay, these rules are easy to loosen with a preferential peering subnet of nodes and as slipstream has shown, they are not necessary at all to get your transaction mined.
Another thought occurred to me overnight. If you host the non-standard fanout transaction somewhere your miners can access them, probably via an API, the miners can simply attach their own fee to the 0-sat anchor and broadcast it to the mempool. Once the fee is attached the pair is now a standard 1p1c package that can be relayed across the node network.
Appreciate the detailed feedback @vnprc! It means a lot
What I’m optimizing for is minimal trust and liveness assumptions in the pool software. Anyone can broadcast a CTV fanout once the coinbase matures: the bytes that unlock it are published over the API (a better data-availability story is a fair open question), and the release ships a daemon that broadcasts at maturity. Since the parent carries its own fee, no operator has to manage a funded wallet. Worth noting we’re also pre-mainnet, so the 0.1% case is our 100% case for a while: mining is the initial coin distribution, and early miners will have no spendable coins.
One clarification first: a built-in-fee fanout is still CPFP-able without an anchor. Any recipient can spend their own payout output as a high-fee child while the fanout is unconfirmed. If the committed fee has fallen below the mempool floor instead, they can submit the pair as a 1p1c package. What the anchor adds is keyless bumping (someone with no payout in the fanout can sponsor it), not bumpability itself. On qbit we raised the TRUC child cap to 45,500 vB specifically so a child spending a ~3.7 kB post-quantum input is valid.
That said, “wait for someone else” looks like a free-rider problem to me: most miners will wait, and bumping ends up depending on the pool and thus a funded relayer wallet. It also opens up a Sybil-dust attack: someone mining small amounts from many addresses inflates the parent until bumping is cost-prohibitive for everyone else. And the economics are rough for small miners regardless: the sponsor pays fees on the entire parent, and for a full ~43 kB fanout that’s several times a floor-sized payout, so in practice only whales or the pool would ever bump. Building the fee in means the smallest miner’s first payout confirms with no one’s help.
For a zero-fee parent, that’s exactly how our anchored shape gets rescued today: artifact from the API, miner attaches the child. The caveat is it only works at zero fee, since ephemeral dust is a parent-level rule (a dust output is only legal on a transaction paying no fee) and package relay relaxes the fee-rate check, nothing else. So no child can standardize a fee-paying parent with a 0-sat anchor. The hybrid that is standard is your original design: a small built-in fee plus an anchor at the dust limit instead of 0 sats. If committed fees start going stale as the fee market matures, that’s the shape I’d move to, and I’d happily take a spec or patch if you beat me to it.
True, but I want every block producer able to mine these; settlement shouldn’t depend on us winning another block.
It also opens up a Sybil-dust attack: someone mining small amounts from many addresses inflates the parent until bumping is cost-prohibitive for everyone else.
This is why I am excited about ecash payouts for small miners. I haven’t built it yet but it looks like this (in my head): the pool operator decides on a ceiling value N for how many payouts it will put in the coinbase transaction. When constructing the coinbase, the pool includes the largest N-1 balances. The Nth output is sent to an ecash mint to distribute payouts for all miners below the threshold. This is essentially how Ocean works today except the custodial balance is shifted to an ecash mint. It pushes the custodial trust and liveness guarantees to a different party, but does not eliminate them.
You could use an ark service provider in place of the mint, which makes the solution more trustless (maybe), at a cost. This design disaggregates individual payouts from each other, so it solves the dust attack you mentioned, but like all trustless layer 2 solutions, you have to go on chain to get your money out. So if a tiny miner gets a tiny vtxo payout their only choices are to accrue a larger balance before going on chain or let on-chain fees eat up the majority of their earnings. If the vtxo amount is smaller than on-chain fees then you actually can’t take custody. There is no unilateral exit anymore. We are right back at custodial balances.
Ark replaces custodial trust with a much higher fee floor (MUCH higher in the post-quantum era!). The only way out of this trap is to loosen the trust requirements. In the long arc of history I think we will grow the adoption of trustless off-chain means of exchange. The best outcome is a world where miners can receive their earnings off-chain and spend them off-chain. If your balance is large enough, you can store value in a vtxo or lightning channel, but for the small fish their only option is custodial solutions. I don’t see this ever changing. It is a fundamental limitation of blockchains.