Architecture: loose coupling to origin for a performance-tuned miner #1

Open
opened 2026-09-03 09:07:32 +00:00 by grenade · 4 comments
Owner

Purpose

This repo is a private fork of Quantus-Network/quantus-miner. We do not submit PRs to origin. We do evaluate every origin release for inclusion here. The perf workstreams tracked under the perf label all have to be built so that:

  1. origin updates merge mechanically, not by hand-porting;
  2. a protocol change at origin (mining protocol, PoW hash, seal format) never strands us: it must land here as a merge plus a rebuild, not a rewrite;
  3. none of that closes off any of the perf potentials identified in the audit.

This issue records the rules the workstreams follow. Individual workstreams: see the perf label. Each one references this issue.

Branch model

  • origin-main: a read-only mirror of origin main, fast-forwarded only. Never committed to directly.
  • main: lair. Contains origin-main plus our changes.
  • An origin update is git merge origin-main into main, reviewed as one PR here. Divergent files show up in that diff and nowhere else, so the review is the list of places we have to think.
  • Origin release tags are the evaluation cadence. Untagged origin commits are not merged.

Where our changes are allowed to live

Origin already provides the seam we need: the MinerEngine trait in crates/engine-cpu/src/lib.rs. WorkerPool and the QUIC loop only ever see Arc<dyn MinerEngine>. Everything perf-related goes behind that trait.

Layer Rule
crates/pow-core, crates/quic-transport, protocol message types in crates/miner-service Origin-identical. Never edited here. If a workstream needs something from them, it is a bug in the workstream design.
crates/engine-gpu (origin's wgpu engine) Edited only where a workstream cannot avoid it, in small blocks marked // lair: so they are recognisable in a merge diff. Default: leave it alone and put the change in a new module or crate.
crates/miner-service engine resolution (resolve_gpu_configuration) and crates/miner-cli flags The one place we accept a standing diff: engine selection and new flags. Kept to a few lines.
New crates (crates/engine-cuda, benchmark harness) Ours entirely. Origin merges never touch them.

Consequence: our miner must stay a drop-in replacement for an origin miner against an origin node. Every new behaviour is opt-in via flag or auto-detected with a fallback to origin behaviour.

Correctness gate

The PoW is consensus. Every kernel we ship must be bit-exact against pow_core (which is origin's, which wraps qpow_math). Origin already has crates/engine-gpu/examples/gpu_cpu_parity.rs and the component tests in crates/engine-gpu/src/tests.rs. Ours reuse those, parameterised by engine, and a workstream is not mergeable here until parity passes on the fleet GPUs. Hash constants must come from qp-poseidon-constants at build time, not be hand-copied (see #3), so a change to the hash at origin is a dependency bump for us.

Measurement gate

No perf change merges on an estimate. #2 defines the protocol: same host, same power limit, same batch size, before and after, numbers in the closing comment (per architecture/generic.md, "close the tracking issue with a comment carrying the actual measured numbers").

Node coupling

quantus/chain is the lair counterpart of origin's node. Preference order:

  1. No node change. The miner-side workstreams need none.
  2. Node change that is invisible to an origin miner (latency, scheduling). Tracked in quantus/chain with the same branch model.
  3. Node change that alters the miner protocol. Avoid. If unavoidable, the miner must detect the node's capability and fall back, so a lair miner still works against an origin node and vice versa.

Scoping on the node side: quantus/chain#1.

What we deliberately do not do

  • Fork the protocol. The whole point of the branch model is that origin remains our upstream.
  • Keep a private patch series on top of origin's engine-gpu. Patch stacks rot; a separate crate does not.
  • Optimise the hash itself. Two Poseidon2 permutations per nonce is the floor; the audit found no algorithmic slack. All gains are in how the work is fed to the silicon.

Audit summary (2026-09-03, v4.0.2, target host 2x RTX 5090)

Multi-GPU works as-is: one worker thread per card, round-robin assignment at crates/engine-gpu/src/lib.rs (ASSIGNED_GPU_DEVICE), independent submission streams. Perf left on the table, in order of expected payoff:

  1. WGSL cannot express a 64x64 to 128-bit multiply, so every field multiply is a four-partial schoolbook. A native CUDA kernel is the large lever.
  2. One synchronous batch in flight per card; the GPU sits empty during readback and resubmit.
  3. Default batch of 1M nonces is ~2.7 ms of work on a 5090, so the per-batch bubble is a double-digit fraction. Tunable today by flag.
  4. NVIDIA runs the older unrolled kernel; the arithmetic ideas from the Apple kernel were only measured bundled with code-size changes that hurt NVIDIA.

Workstreams

In suggested order. #2 first because nothing else can be judged without it; #4 and #6 next because they are flag-sized and give the baseline the larger ones must beat.

Issue Workstream Expected gain Origin coupling
#2 Benchmark and parity harness, per-device metric none directly; gates everything zero
#4 Multiple worker threads per device hides the readback bubble, est. 5 to 15% at 1M batch one flag
#6 Batch size default and auto-sizing similar to #4, they overlap one flag
#5 Double-buffered submission in engine-gpu supersedes #4 on the wgpu engine one branch point in origin code
#7 NVIDIA WGSL kernel arithmetic est. 5 to 15% new kernel file plus selection arm
#3 engine-cuda native kernel est. 1.5x to 2.5x new crate plus selection arm
quantus/chain#1 Node job-turnaround latency scoping unknown until measured see that issue

Gains are not additive: #3 makes #5 and #7 irrelevant on NVIDIA hosts, which then serve only as the fallback engine. Each issue closes with its measured number.

## Purpose This repo is a private fork of [Quantus-Network/quantus-miner](https://github.com/Quantus-Network/quantus-miner). We do not submit PRs to origin. We do evaluate every origin release for inclusion here. The perf workstreams tracked under the `perf` label all have to be built so that: 1. origin updates merge mechanically, not by hand-porting; 2. a protocol change at origin (mining protocol, PoW hash, seal format) never strands us: it must land here as a merge plus a rebuild, not a rewrite; 3. none of that closes off any of the perf potentials identified in the audit. This issue records the rules the workstreams follow. Individual workstreams: see the `perf` label. Each one references this issue. ## Branch model - `origin-main`: a read-only mirror of origin `main`, fast-forwarded only. Never committed to directly. - `main`: lair. Contains `origin-main` plus our changes. - An origin update is `git merge origin-main` into `main`, reviewed as one PR here. Divergent files show up in that diff and nowhere else, so the review is the list of places we have to think. - Origin release tags are the evaluation cadence. Untagged origin commits are not merged. ## Where our changes are allowed to live Origin already provides the seam we need: the `MinerEngine` trait in `crates/engine-cpu/src/lib.rs`. `WorkerPool` and the QUIC loop only ever see `Arc<dyn MinerEngine>`. Everything perf-related goes behind that trait. | Layer | Rule | | --- | --- | | `crates/pow-core`, `crates/quic-transport`, protocol message types in `crates/miner-service` | **Origin-identical.** Never edited here. If a workstream needs something from them, it is a bug in the workstream design. | | `crates/engine-gpu` (origin's wgpu engine) | Edited only where a workstream cannot avoid it, in small blocks marked `// lair:` so they are recognisable in a merge diff. Default: leave it alone and put the change in a new module or crate. | | `crates/miner-service` engine resolution (`resolve_gpu_configuration`) and `crates/miner-cli` flags | The one place we accept a standing diff: engine selection and new flags. Kept to a few lines. | | New crates (`crates/engine-cuda`, benchmark harness) | Ours entirely. Origin merges never touch them. | Consequence: our miner must stay a **drop-in replacement for an origin miner against an origin node**. Every new behaviour is opt-in via flag or auto-detected with a fallback to origin behaviour. ## Correctness gate The PoW is consensus. Every kernel we ship must be bit-exact against `pow_core` (which is origin's, which wraps `qpow_math`). Origin already has `crates/engine-gpu/examples/gpu_cpu_parity.rs` and the component tests in `crates/engine-gpu/src/tests.rs`. Ours reuse those, parameterised by engine, and a workstream is not mergeable here until parity passes on the fleet GPUs. Hash constants must come from `qp-poseidon-constants` at build time, not be hand-copied (see #3), so a change to the hash at origin is a dependency bump for us. ## Measurement gate No perf change merges on an estimate. #2 defines the protocol: same host, same power limit, same batch size, before and after, numbers in the closing comment (per `architecture/generic.md`, "close the tracking issue with a comment carrying the actual measured numbers"). ## Node coupling `quantus/chain` is the lair counterpart of origin's node. Preference order: 1. No node change. The miner-side workstreams need none. 2. Node change that is invisible to an origin miner (latency, scheduling). Tracked in `quantus/chain` with the same branch model. 3. Node change that alters the miner protocol. Avoid. If unavoidable, the miner must detect the node's capability and fall back, so a lair miner still works against an origin node and vice versa. Scoping on the node side: quantus/chain#1. ## What we deliberately do not do - Fork the protocol. The whole point of the branch model is that origin remains our upstream. - Keep a private patch series on top of origin's `engine-gpu`. Patch stacks rot; a separate crate does not. - Optimise the hash itself. Two Poseidon2 permutations per nonce is the floor; the audit found no algorithmic slack. All gains are in how the work is fed to the silicon. ## Audit summary (2026-09-03, v4.0.2, target host 2x RTX 5090) Multi-GPU works as-is: one worker thread per card, round-robin assignment at `crates/engine-gpu/src/lib.rs` (`ASSIGNED_GPU_DEVICE`), independent submission streams. Perf left on the table, in order of expected payoff: 1. WGSL cannot express a 64x64 to 128-bit multiply, so every field multiply is a four-partial schoolbook. A native CUDA kernel is the large lever. 2. One synchronous batch in flight per card; the GPU sits empty during readback and resubmit. 3. Default batch of 1M nonces is ~2.7 ms of work on a 5090, so the per-batch bubble is a double-digit fraction. Tunable today by flag. 4. NVIDIA runs the older unrolled kernel; the arithmetic ideas from the Apple kernel were only measured bundled with code-size changes that hurt NVIDIA. ## Workstreams In suggested order. #2 first because nothing else can be judged without it; #4 and #6 next because they are flag-sized and give the baseline the larger ones must beat. | Issue | Workstream | Expected gain | Origin coupling | | --- | --- | --- | --- | | #2 | Benchmark and parity harness, per-device metric | none directly; gates everything | zero | | #4 | Multiple worker threads per device | hides the readback bubble, est. 5 to 15% at 1M batch | one flag | | #6 | Batch size default and auto-sizing | similar to #4, they overlap | one flag | | #5 | Double-buffered submission in `engine-gpu` | supersedes #4 on the wgpu engine | one branch point in origin code | | #7 | NVIDIA WGSL kernel arithmetic | est. 5 to 15% | new kernel file plus selection arm | | #3 | `engine-cuda` native kernel | est. 1.5x to 2.5x | new crate plus selection arm | | quantus/chain#1 | Node job-turnaround latency scoping | unknown until measured | see that issue | Gains are not additive: #3 makes #5 and #7 irrelevant on NVIDIA hosts, which then serve only as the fallback engine. Each issue closes with its measured number.
grenade added the origin-couplingperf labels 2026-09-03 09:10:13 +00:00
Author
Owner

CI and deployment workstreams (added 2026-09-03)

Deployment follows main of each fork, built as one fat binary carrying native code for every card in the fleet, with continuous post-deploy measurement. These sit alongside the perf table above and #8 is a prerequisite for anything reaching a host.

Issue Workstream Origin coupling
#8 Replace inherited GitHub workflows; one fat-binary build (cubins sm_86, sm_89, sm_120 plus compute_120 PTX) with the CUDA 13.0 toolkit on the cuda-13.0 runner; deploy-on-main with rollback and validate; miner assets and sudoers role move here. Carries the measured fleet driver table. .github/workflows deleted, recurring git rm on merge
#9 miner_build_info, per-device and per-job efficiency metrics, recording rules and a "Performance by build" dashboard row, regression rule metric additions only
quantus/chain#2 Same for the node: build on a big runner, deploy to the node host, node assets and sudoers role move there same .github/workflows deletion
lair/quantus#4 Retire fetch / deploy-node / deploy-miner; keep monitoring, GPU power/textfile units, edge role; cut-over sequence n/a

Merge checklist for every origin-main merge PR, collected from the above:

  1. git rm -r .github/workflows if the merge resurrects any of it.
  2. Parity (#2) and the ci.yml gates green.
  3. Bench harness (#2) shows no regression against the previous main on the reference card.
  4. Deploy runs in validate mode first when the merge touches engine-gpu, miner-service or quic-transport.
## CI and deployment workstreams (added 2026-09-03) Deployment follows `main` of each fork, built as one fat binary carrying native code for every card in the fleet, with continuous post-deploy measurement. These sit alongside the perf table above and #8 is a prerequisite for anything reaching a host. | Issue | Workstream | Origin coupling | | --- | --- | --- | | #8 | Replace inherited GitHub workflows; one fat-binary build (cubins `sm_86`, `sm_89`, `sm_120` plus `compute_120` PTX) with the CUDA 13.0 toolkit on the `cuda-13.0` runner; deploy-on-main with rollback and validate; miner assets and sudoers role move here. Carries the measured fleet driver table. | `.github/workflows` deleted, recurring `git rm` on merge | | #9 | `miner_build_info`, per-device and per-job efficiency metrics, recording rules and a "Performance by build" dashboard row, regression rule | metric additions only | | quantus/chain#2 | Same for the node: build on a big runner, deploy to the node host, node assets and sudoers role move there | same `.github/workflows` deletion | | lair/quantus#4 | Retire `fetch` / `deploy-node` / `deploy-miner`; keep monitoring, GPU power/textfile units, edge role; cut-over sequence | n/a | Merge checklist for every `origin-main` merge PR, collected from the above: 1. `git rm -r .github/workflows` if the merge resurrects any of it. 2. Parity (#2) and the `ci.yml` gates green. 3. Bench harness (#2) shows no regression against the previous `main` on the reference card. 4. Deploy runs in `validate` mode first when the merge touches `engine-gpu`, `miner-service` or `quic-transport`.
Author
Owner

Operating policy and deadline (set 2026-09-03)

Goal by 2026-09-09 (expected mainnet): a CUDA miner binary that outperforms origin's wgpu build by a significant margin, measured per #2 and #9. Whether non-mining workloads leave the GPU hosts once mining has value is a separate call made closer to that date.

Until then (Planck testnet, tokens valueless):

Host Role Miner
benjy (4090) mines continuously, reference card for merge decisions latest performant main build
quadbrat (3060) mines continuously latest performant main build
beast (2x 5090) inference, left mostly undisturbed; not mining not deployed
  • Pausing benjy's or quadbrat's miner for a benchmark is fine at any time; nothing of value is lost. The harness in #2 does this itself.
  • Beast's inference can be stopped for short benchmark bursts when a 5090 number is needed, but that is a manual decision per run, not something a workflow does on its own.
  • The deploy matrix in #8 therefore ships to benjy and quadbrat only for now. Beast stays in the matrix commented out with its gpu_devices: "2" so enabling it on the day is a one-line change.

Readiness state: origin-main exists on both forks (miner at cb6deb9 = v4.0.2, chain at 1f43947), RSYNC_SSH_KEY is set on both, all three hosts verified on 580 drivers with a CUDA 13.0 ceiling.

## Operating policy and deadline (set 2026-09-03) **Goal by 2026-09-09 (expected mainnet):** a CUDA miner binary that outperforms origin's wgpu build by a significant margin, measured per #2 and #9. Whether non-mining workloads leave the GPU hosts once mining has value is a separate call made closer to that date. **Until then (Planck testnet, tokens valueless):** | Host | Role | Miner | | --- | --- | --- | | benjy (4090) | mines continuously, **reference card** for merge decisions | latest performant `main` build | | quadbrat (3060) | mines continuously | latest performant `main` build | | beast (2x 5090) | inference, left mostly undisturbed; **not mining** | not deployed | - Pausing benjy's or quadbrat's miner for a benchmark is fine at any time; nothing of value is lost. The harness in #2 does this itself. - Beast's inference can be stopped for short benchmark bursts when a 5090 number is needed, but that is a manual decision per run, not something a workflow does on its own. - The `deploy` matrix in #8 therefore ships to benjy and quadbrat only for now. Beast stays in the matrix commented out with its `gpu_devices: "2"` so enabling it on the day is a one-line change. Readiness state: `origin-main` exists on both forks (miner at `cb6deb9` = v4.0.2, chain at `1f43947`), `RSYNC_SSH_KEY` is set on both, all three hosts verified on 580 drivers with a CUDA 13.0 ceiling.
Author
Owner

Goal check (2026-09-03)

The deadline goal was a CUDA binary that beats origin's wgpu build by a significant margin, measured. #16 delivers 2.06x on the 4090 (297.7 vs 144.4 MH/s at 250 W) and 1.59x on the 3060, bit-exact, deployed to both mining hosts from main by this repo's own workflow with rollback and a kernel assertion in validate. The 5090 number is pending a manual bench dispatch on beast when inference can be paused.

Order of remaining work, revised by measurement:

  1. #3 steps 5 and 6: kernel tuning on the 4090 and 5090 with the harness, then pipelined submission. Each a few percent at most, but each is measured now.
  2. #6 batch size for the CUDA engine: sweep first, since 4M was slower than 1M on the 3060.
  3. #7 (wgpu arithmetic) drops to fallback-only interest. #4 and #5 stay low priority per the 1.9% host-share measurement in #9.
  4. quantus/chain#1 and #2 remain the node-side items.

Power limits are the last knob, after the software is squeezed, and only expected to move the number modestly.

## Goal check (2026-09-03) The deadline goal was a CUDA binary that beats origin's wgpu build by a significant margin, measured. #16 delivers 2.06x on the 4090 (297.7 vs 144.4 MH/s at 250 W) and 1.59x on the 3060, bit-exact, deployed to both mining hosts from `main` by this repo's own workflow with rollback and a kernel assertion in validate. The 5090 number is pending a manual bench dispatch on beast when inference can be paused. Order of remaining work, revised by measurement: 1. #3 steps 5 and 6: kernel tuning on the 4090 and 5090 with the harness, then pipelined submission. Each a few percent at most, but each is measured now. 2. #6 batch size for the CUDA engine: sweep first, since 4M was slower than 1M on the 3060. 3. #7 (wgpu arithmetic) drops to fallback-only interest. #4 and #5 stay low priority per the 1.9% host-share measurement in #9. 4. quantus/chain#1 and #2 remain the node-side items. Power limits are the last knob, after the software is squeezed, and only expected to move the number modestly.
Author
Owner

State of play (2026-09-14)

Several statements above are stale; this comment is the current reading.

The repository is public and publishes release binaries (#28, first tag v4.0.2-lair.1). The purpose has widened from a fleet advantage to an open miner that independent operators can run against the closed pool binaries: on 2026-09-13 one reward preimage authored ~62% of blocks in the exporter's window. The branch model and the no-PRs-to-origin rule are unchanged; origin's own CUDA engine (v4.2.0, --cuda-gpu) measured 944 MH/s on a 5090 against our 1104 (#27), so there is nothing to take from it yet.

All three hosts mine since the mainnet call on 2026-09-09 (#20); beast's inference is off. The "beast does not mine" policy above is history.

Perf, measured, per card at the power caps: 5090 283 (wgpu) -> 1104 MH/s, 4090 144 -> 716, 3060 37 -> 141. The steps: #16 native CUDA (2x), #17 deferred carries, #22 per-arch carry path (+20% sm_120), #23 fused-PTX arithmetic (+54..66%), #26 whole-grid batches, early reject, nonce direction (+3%). Memory clock lock on all hosts (lair/quantus#10; +2% on the 5090, +13% on the 4090).

Workstream table, resolved: #2, #3, #4, #6, #9 closed with numbers earlier; #5 and #7 closed today as superseded by the CUDA engine; #8 closed as complete. Open: #25 (ptxas anomaly, a standing warning: every kernel change passes exhaustive parity on all three architectures before merge), #27 (the remaining ~10% to the fastest closed binary: a loop-structured permute with one continuous carry chain per round; the tensor-core idea #24 was measured and rejected).

Correction to the audit's "no algorithmic slack": still true for the hash, but the closed kernels showed slack in how the arithmetic is scheduled, and the largest single gain of the whole effort (#23) came from there.

## State of play (2026-09-14) Several statements above are stale; this comment is the current reading. **The repository is public** and publishes release binaries (#28, first tag `v4.0.2-lair.1`). The purpose has widened from a fleet advantage to an open miner that independent operators can run against the closed pool binaries: on 2026-09-13 one reward preimage authored ~62% of blocks in the exporter's window. The branch model and the no-PRs-to-origin rule are unchanged; origin's own CUDA engine (v4.2.0, `--cuda-gpu`) measured 944 MH/s on a 5090 against our 1104 (#27), so there is nothing to take from it yet. **All three hosts mine** since the mainnet call on 2026-09-09 (#20); beast's inference is off. The "beast does not mine" policy above is history. **Perf, measured, per card at the power caps:** 5090 283 (wgpu) -> 1104 MH/s, 4090 144 -> 716, 3060 37 -> 141. The steps: #16 native CUDA (2x), #17 deferred carries, #22 per-arch carry path (+20% sm_120), #23 fused-PTX arithmetic (+54..66%), #26 whole-grid batches, early reject, nonce direction (+3%). Memory clock lock on all hosts (lair/quantus#10; +2% on the 5090, +13% on the 4090). **Workstream table, resolved:** #2, #3, #4, #6, #9 closed with numbers earlier; #5 and #7 closed today as superseded by the CUDA engine; #8 closed as complete. **Open:** #25 (ptxas anomaly, a standing warning: every kernel change passes exhaustive parity on all three architectures before merge), #27 (the remaining ~10% to the fastest closed binary: a loop-structured `permute` with one continuous carry chain per round; the tensor-core idea #24 was measured and rejected). **Correction to the audit's "no algorithmic slack":** still true for the hash, but the closed kernels showed slack in how the arithmetic is scheduled, and the largest single gain of the whole effort (#23) came from there.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: blackbeard/miner#1