Trustless mining pool: what the protocol allows, and what it would take #3
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Not worth building today. Raised so the analysis survives, and because it becomes worth revisiting if the miner population grows into the thousands — a pool only earns its keep for participants whose share is small enough that they wait days between blocks. On a network of ~9–21 active authors it earns nothing.
The bar this is judged against: no trust required. A custodial pool is not worth building.
Verified against
Quantus-Network/chain@4c4a8f2fandquantus-minerv4.0.0 on 2026-09-01.Direction 1 — pool trusting miners: solved
Shares are verifiable.
Poseidon2(header, nonce) < share_targetis cheap to check and impossible to forge, andcrates/pool-servicein the miner repo already implements the whole mechanism — it hands out low-difficulty share challenges over the real block header, verifies solves, tracksshares_accepted/shares_rejectedper session, and submits any share that happens to meet network difficulty as a block. It exists as a captcha pool (proof-of-work as anti-spam) rather than a reward pool, but the share machinery is done.Note the node↔miner protocol itself has no share concept:
MiningResultcarries onlycompleted/failed/cancelled/runningplus a self-reportedhash_countandelapsed_time.hash_countis trivially forgeable and must never be used for accounting. Shares have to come from apool-service-shaped intermediary, not from the miner protocol.Direction 2 — miners trusting the operator: structurally blocked
Three compounding reasons, none of them fixable off-protocol:
inner_hashinto the PreRuntime digest, then broadcasts the resultingpre_hashas the job (🎁 Prepared block … hash: 0xc067…→⛏️ Broadcasting job 190: pre_hash=c067…). Changing the payout address changes the hash and invalidates every nonce already searched. There is no post-hoc splitting.pallets/mining-rewardsmints inon_finalizeto the single author extracted from the digest. No vector, no split.pallet-contractsnorpallet-revive. And even with them, rewards land at a wormhole address spendable only by ZK proof of a secret — a contract cannot hold a secret, so the reward cannot be paid into one.A rotating-beneficiary scheme (pool picks whose address goes in each header, proportional to shares, so funds never touch the operator) was considered and does not work: because the payout address is fixed before mining, nobody has any reason to work a job that pays someone else. That is solo mining with extra steps.
The only thing that removes trust entirely: a payout vector
Extend the PreRuntime digest to carry several beneficiaries with weights, and have
mining-rewardscredit them proportionally inon_finalize.The pool commits the split before the work, derived from the previous round's shares. Miners verify the split matches their contribution before choosing to mine that job. The split is in every header, so it is publicly auditable forever, and the operator never custodies anything.
Contained change — one pallet plus the digest format. Worth putting to the Quantus team before mainnet freezes the reward path, and it is a general capability rather than a favour to us: no chain with a single-beneficiary header can ever have a non-custodial pool.
The strongest design available without a protocol change
This chain has a primitive most do not:
pallets/reversible-transfersgives an account a guardian and a delay.set_high_security(delay, guardian)— guardian may not be selfcancel_transferon a high-security account:ensure!(who == &pending.guardian, InvalidReverser)— the guardian cancels, not the ownerrecover_funds(account)— guardian-only; cancels all pending transfers and sweeps the balance to the guardianSo:
Every payout is public for the delay window. A payout to the operator instead of the miners gets cancelled by any k-of-n; a hostile operator gets
recover_funds'd and the balance swept to the multisig.What it still does not fix:
recover_fundssweeps to the guardian, so the multisig then has to distribute — the same problem one level up with n signers instead of one.Materially better than custodial: operator discretion is reduced to one bounded, observable window, and miners hold a real veto plus a nuclear option. Still not trustless.
Revisit when
Until then the existing multi-miner support is the honest answer for anyone who already trusts each other: one node, many miners, one address —
node/src/miner_server.rsbroadcasts each job to every connected miner and each picks its own random starting nonce. That is a pool whose counterparty is you.