qt: add Mining sub-tab in Text Based Worship — solo (done) + in-wallet stratum pool client (post-Codex, v2.1+) #8

Closed
opened 2026-06-03 23:29:32 +00:00 by dobbscoin · 8 comments
dobbscoin commented 2026-06-03 23:29:32 +00:00

Why

OFF inherits Bitcoin Core 0.8/0.10's UI with no mining surface — upstream removed it in v0.4. Today, to mine, a new user has to:

  1. Find Help → Text Based Worship
  2. Click into the Console sub-tab
  3. Discover setgenerate true 1 from external docs (solo, high variance)
  4. Or install + configure cpuminer-multi externally for pool mining
  5. Hope they got the right command line

Quark is CPU-friendly, no ASICs exist, and the chain's framing of OFF as a participatory ritual is undermined by hiding the entire mining surface. Most users running this on a laptop will earn fractions of OFF per hour, but the act of offering CPU cycles to the Slumbering Lord is the point. Engagement, not yield.

(Cf. Dogecoin's early wallets which shipped a similar surface specifically to lower the on-ramp for amateur miners. Community-building effect was significant; mining contribution was negligible. Both outcomes were the goal.)

Current state on the branch

The Mining sub-tab scaffold and solo path have already landed on feat/issue-8-mining-tab-solo:

  • tab_mining widget added to tabWidget in src/qt/forms/rpcconsole.ui
  • "Mine Offerings" checkbox + CPU-threads spinner (capped at QThread::idealThreadCount())
  • Live status line wired to getmininginfo
  • OFFSIG window guard at [999991, 1050666] — controls grey out, dark-red banner explains
  • cthulhu-dark.qss registered #tab_mining for the dark-fill rule so it inherits the dialog palette
  • "Solo CPU Mining" header; "Worthless On Purpose" copy removed

What's not done and is the remaining scope of this issue: pool mode.

Placement: sub-tab inside Text Based Worship

Not a new main tab. The wallet's main tab strip is already crowded (Overview / Send / Receive / Transactions / Address Book / Codex) and tabs hide behind a chevron at narrow window widths. Mining belongs as a fourth sub-tab inside Help → Text Based Worship, alongside:

  • Information
  • Console
  • Network Traffic
  • Mining (done)

The QTabWidget infrastructure at src/qt/forms/rpcconsole.ui already supports new sub-tabs trivially. Discoverable for users who explore Help, invisible for users who don't want it.

Two modes: solo and pool

Solo CPU mining alone is a poor demo of "mining works" because of Poisson variance — a single laptop at ~2-3% of network hash will find a block on average every 30-60 minutes, but with luck variance that can easily be 4+ hours between finds. Casual users try it for an hour, see nothing, give up.

Pool mode smooths payouts: hash contribution earns proportional shares of every pool block, balance ticks up reliably. The participation feedback loop becomes positive within minutes.

So the sub-tab grows a mode selector when pool mode lands:

  • ( ) Solo — uses the built-in setgenerate solo miner. Variance-prone, sovereign, no external dependencies.
  • ( ) Pool — connects to pool.23skidoo.info:3040 (Miningcore, Quark, PPLNS, 0.1 OFF min payout) via an in-wallet stratum client. Smoother payouts, the pool sees your IP + payout address, requires the pool to be up.

Default: Pool for new users (better UX), with a clearly-labeled solo option for sovereignty-conscious users.

Solo mode — already on the branch

Wired up. Lock behavior during the Codex inscription window is the load-bearing constraint:

  • When chainActive.Tip()->nHeight is within [999991, 1050666], the toggle + thread spinner grey out and a banner explains the Codex window with countdown to block 1,050,667
  • If solo mining was enabled going into the window, the wallet should auto-setgenerate false and restore at block 1,050,667 (TODO — currently the user just sees the controls go grey on the next tip update)
  • Pool mode is unaffected by the Codex window — the pool's backend daemon holds a Conclave key, so pool-mined blocks are signed correctly throughout the window

Pool mode — in-wallet stratum v1 client

Approach: implement Stratum v1 in the wallet itself, as a dedicated subsystem with its own worker threads. Not a subprocess.

Why not bundle cpuminer-multi as a subprocess (the earlier plan):

  • Bundling a GPLv2 binary alongside an MIT-licensed wallet creates packaging-and-distribution drag — separate licenses, separate update paths, SHA256-verification of the bundled binary at startup to defend against tampering, separate Windows-codesign considerations
  • Subprocess management on Windows is its own footgun set (QProcess + console handles + signal forwarding)
  • Once you've done all of the above you've spent the LOC budget you would have spent writing stratum directly
  • An in-wallet stratum client uses dependencies the wallet already has (boost::asio + univalue + the existing Quark hash + serialization)

Why this is non-trivial nonetheless:

  • ~1,300-1,700 LOC of new code, all of it has to compile on linux + Win64 cross via depends/
  • Stratum's difficulty-to-target math is straightforward for SHA256/scrypt-family pools but Miningcore's Quark stratum byte-order needs verification — a misordered hash means every share rejects, and "why are all shares being rejected" can eat 1-3 days of debugging on its own

Scope breakdown

  • Stratum v1 protocol layer (~500-800 LOC) — mining.subscribe / authorize / set_difficulty / notify / submit, JSON-RPC line-framed over TCP. New files src/stratum.{h,cpp} (or similar). Use raw boost::asio to match existing P2P style, or a dedicated boost::thread with blocking sockets for simplicity.
  • Job → block-header assembly (~150 LOC) — coinbase1 + extranonce1 + extranonce2 + coinbase2 → coinbase tx → fold merkle branch → 80-byte header. Reuses existing serialization helpers.
  • Hash worker loop (~100 LOC) — N threads incrementing nonce + rolling extranonce2, checking against share target. Mirror the existing BitcoinMiner in src/miner.cpp.
  • Reconnect / backoff / error handling (~150 LOC) — pool drops, sockets time out, jobs go stale, server-side mining.set_difficulty mid-job, clean_jobs=true on mining.notify.
  • Qt UI controls (~200 LOC, mostly in src/qt/rpcconsole.cpp + form): mode radio, pool URL (read-only label, advanced users edit Offerings.conf), payout address (auto-getnewaddress on first activation, regenerate button), worker name, threads spinner, big "Mine Offerings" toggle, status line.
  • Settings persistence (~50 LOC) — optionsmodel.cpp for pool prefs (mining_mode, mining_pool_url, mining_pool_address, mining_pool_worker). UI prefs, not consensus flags.
  • Tests (~200 LOC) — stratum framing + difficulty-to-target conversion + merkle-branch fold unit tests. Boost.Test in src/test/.

Status line states (pool mode)

  • Pool mining stopped
  • Connecting to pool.23skidoo.info…
  • Authorizing as Q…<addr>.<worker>
  • Connected · ~X.YZ MH/s · accepted Y / rejected Z shares · pool diff D
  • Pool unreachable — retrying in 30s (attempt N)
  • Pool authentication failed — check payout address

What pool mode does NOT do

  • It does not affect the solo path's OFFSIG-window guard. Solo is consensus-locked during [999991, 1050666]; pool routes through the pool daemon and is unaffected.
  • It does not implement Stratum v2 / BetterHash / version-rolling. Plain Stratum v1.
  • It does not bundle any external miner binary. Wallet is the miner.
  • It does not become a sovereignty hazard — pool mode is opt-in via a radio button, never the silent default for sovereignty-conscious users.

Calendar estimate (honest)

  • 4-7 working days if Miningcore's Quark stratum byte-order is conventional and shares accept on first correct hash
  • 10-14 working days if pool.23skidoo.info has any non-standard stratum behavior (very plausible given Quark is a niche stratum variant)

Iteration cycles dominated by Windows depends/ cross-compile (~11 min per round). Plan for ~30-50 CI cycles before "shares accept reliably."

What this isn't

  • Not a consensus change. No fork, no activation height, no upgrade pressure.
  • Not a financial product. Expected earnings per CPU-hour are genuinely fractional at current network hashrate.
  • Not urgent. Door-opener feature for the post-Codex window (block 1,050,667 onward). Could land in v2.1.x or v2.2.x. Branch sits.
  • Not a maintenance burden after landing. Stratum v1 is frozen; no protocol churn to chase.

Reference behavior to mirror

  • Built-in solo miner: src/miner.cpp::GenerateBitcoins, wired via src/rpcmining.cpp::setgenerate. Solo-mode UI wraps these (done).
  • getmininginfo returns the data for solo status display (done).
  • Quark hash: src/quark.cpp — already callable; pool mode's hash worker loop calls it directly with nonce-incremented headers.
  • QTabWidget at src/qt/forms/rpcconsole.ui — integration point (done).
  • src/qt/rpcconsole.cpp::on_tabWidget_currentChanged — polling start/stop hook based on which sub-tab is visible (done).
  • Stratum v1 reference: there's no single canonical spec; cgminer/sgminer/Miningcore-side implementations diverge in small ways. Match Miningcore's Quark output by integration-testing against pool.23skidoo.info:3040 from day one.

Open questions (decide in PR review when this comes back)

  • Default mode — pool (recommended for UX) or solo (recommended for sovereignty)? Lean: pool by default with a one-click switch.
  • Pool URL hardcoded or editable in UI? — hardcoded with Offerings.conf override is the simplest; editable-in-UI is more flexible but more rope. Lean: hardcoded with conf override.
  • Block-found notification (solo) / share-accepted notification (pool) — toast and/or sound? Defer to v2 of this feature.
  • Subsystem location — src/stratum.{h,cpp} lives at top level (mining is a daemon-adjacent function) vs src/qt/stratum.{h,cpp} (it only matters when the GUI is up). Lean: top-level so a headless RPC like setpoolmining becomes possible later.

References

  • src/qt/forms/rpcconsole.ui — QTabWidget name="tabWidget" (done: tab_mining added)
  • src/qt/rpcconsole.cpp — Mining tab slots + OFFSIG guard (done)
  • src/qt/res/css/cthulhu-dark.qss — dark-fill rule includes #tab_mining (done)
  • src/miner.cpp::GenerateBitcoins — built-in miner (solo path, already wrapped)
  • src/rpcmining.cpp::setgenerate — RPC the solo path wraps
  • src/quark.cpp — Quark Hash9 (callable directly from pool-mode hash workers)
  • pool.23skidoo.info:3040 — pool endpoint (Miningcore, Quark, PPLNS)

The Slumbering Lord does not need your CPU. He simply notices when you offer it. Iä Iä.

## Why OFF inherits Bitcoin Core 0.8/0.10's UI with no mining surface — upstream removed it in v0.4. Today, to mine, a new user has to: 1. Find `Help → Text Based Worship` 2. Click into the Console sub-tab 3. Discover `setgenerate true 1` from external docs (solo, high variance) 4. *Or* install + configure `cpuminer-multi` externally for pool mining 5. Hope they got the right command line Quark is CPU-friendly, no ASICs exist, and the chain's framing of OFF as a participatory ritual is undermined by hiding the entire mining surface. Most users running this on a laptop will earn fractions of OFF per hour, but the act of offering CPU cycles to the Slumbering Lord is the point. Engagement, not yield. (Cf. Dogecoin's early wallets which shipped a similar surface specifically to lower the on-ramp for amateur miners. Community-building effect was significant; mining contribution was negligible. Both outcomes were the goal.) ## Current state on the branch The Mining sub-tab scaffold and solo path have already landed on `feat/issue-8-mining-tab-solo`: - `tab_mining` widget added to `tabWidget` in `src/qt/forms/rpcconsole.ui` - "Mine Offerings" checkbox + CPU-threads spinner (capped at `QThread::idealThreadCount()`) - Live status line wired to `getmininginfo` - OFFSIG window guard at `[999991, 1050666]` — controls grey out, dark-red banner explains - `cthulhu-dark.qss` registered `#tab_mining` for the dark-fill rule so it inherits the dialog palette - "Solo CPU Mining" header; "Worthless On Purpose" copy removed What's **not** done and is the remaining scope of this issue: pool mode. ## Placement: sub-tab inside Text Based Worship **Not a new main tab.** The wallet's main tab strip is already crowded (Overview / Send / Receive / Transactions / Address Book / Codex) and tabs hide behind a chevron at narrow window widths. Mining belongs as a **fourth sub-tab inside `Help → Text Based Worship`**, alongside: - Information - Console - Network Traffic - **Mining** *(done)* The `QTabWidget` infrastructure at `src/qt/forms/rpcconsole.ui` already supports new sub-tabs trivially. Discoverable for users who explore `Help`, invisible for users who don't want it. ## Two modes: solo and pool Solo CPU mining alone is a poor demo of "mining works" because of Poisson variance — a single laptop at ~2-3% of network hash will find a block on average every 30-60 minutes, but with luck variance that can easily be 4+ hours between finds. Casual users try it for an hour, see nothing, give up. Pool mode smooths payouts: hash contribution earns proportional shares of every pool block, balance ticks up reliably. The participation feedback loop becomes positive within minutes. So the sub-tab grows a **mode selector** when pool mode lands: - **( ) Solo** — uses the built-in `setgenerate` solo miner. Variance-prone, sovereign, no external dependencies. - **( ) Pool** — connects to `pool.23skidoo.info:3040` (Miningcore, Quark, PPLNS, 0.1 OFF min payout) via an in-wallet stratum client. Smoother payouts, the pool sees your IP + payout address, requires the pool to be up. Default: **Pool** for new users (better UX), with a clearly-labeled solo option for sovereignty-conscious users. ## Solo mode — already on the branch Wired up. Lock behavior during the Codex inscription window is the load-bearing constraint: - When `chainActive.Tip()->nHeight` is within `[999991, 1050666]`, the toggle + thread spinner grey out and a banner explains the Codex window with countdown to block 1,050,667 - If solo mining was enabled going into the window, the wallet should auto-`setgenerate false` and restore at block 1,050,667 (TODO — currently the user just sees the controls go grey on the next tip update) - Pool mode is *unaffected* by the Codex window — the pool's backend daemon holds a Conclave key, so pool-mined blocks are signed correctly throughout the window ## Pool mode — in-wallet stratum v1 client **Approach: implement Stratum v1 in the wallet itself, as a dedicated subsystem with its own worker threads. Not a subprocess.** Why not bundle `cpuminer-multi` as a subprocess (the earlier plan): - Bundling a GPLv2 binary alongside an MIT-licensed wallet creates packaging-and-distribution drag — separate licenses, separate update paths, SHA256-verification of the bundled binary at startup to defend against tampering, separate Windows-codesign considerations - Subprocess management on Windows is its own footgun set (QProcess + console handles + signal forwarding) - Once you've done all of the above you've spent the LOC budget you would have spent writing stratum directly - An in-wallet stratum client uses dependencies the wallet already has (boost::asio + univalue + the existing Quark hash + serialization) Why this is non-trivial nonetheless: - ~1,300-1,700 LOC of new code, all of it has to compile on linux + Win64 cross via depends/ - Stratum's difficulty-to-target math is straightforward for SHA256/scrypt-family pools but **Miningcore's Quark stratum byte-order needs verification** — a misordered hash means every share rejects, and "why are all shares being rejected" can eat 1-3 days of debugging on its own ### Scope breakdown - **Stratum v1 protocol layer** (~500-800 LOC) — `mining.subscribe / authorize / set_difficulty / notify / submit`, JSON-RPC line-framed over TCP. New files `src/stratum.{h,cpp}` (or similar). Use raw boost::asio to match existing P2P style, or a dedicated boost::thread with blocking sockets for simplicity. - **Job → block-header assembly** (~150 LOC) — coinbase1 + extranonce1 + extranonce2 + coinbase2 → coinbase tx → fold merkle branch → 80-byte header. Reuses existing serialization helpers. - **Hash worker loop** (~100 LOC) — N threads incrementing nonce + rolling extranonce2, checking against share target. Mirror the existing `BitcoinMiner` in `src/miner.cpp`. - **Reconnect / backoff / error handling** (~150 LOC) — pool drops, sockets time out, jobs go stale, server-side `mining.set_difficulty` mid-job, `clean_jobs=true` on `mining.notify`. - **Qt UI controls** (~200 LOC, mostly in `src/qt/rpcconsole.cpp` + form): mode radio, pool URL (read-only label, advanced users edit `Offerings.conf`), payout address (auto-`getnewaddress` on first activation, regenerate button), worker name, threads spinner, big "Mine Offerings" toggle, status line. - **Settings persistence** (~50 LOC) — `optionsmodel.cpp` for pool prefs (`mining_mode`, `mining_pool_url`, `mining_pool_address`, `mining_pool_worker`). UI prefs, not consensus flags. - **Tests** (~200 LOC) — stratum framing + difficulty-to-target conversion + merkle-branch fold unit tests. Boost.Test in `src/test/`. ### Status line states (pool mode) - `Pool mining stopped` - `Connecting to pool.23skidoo.info…` - `Authorizing as Q…<addr>.<worker>` - `Connected · ~X.YZ MH/s · accepted Y / rejected Z shares · pool diff D` - `Pool unreachable — retrying in 30s (attempt N)` - `Pool authentication failed — check payout address` ### What pool mode does NOT do - It does not affect the solo path's OFFSIG-window guard. Solo is consensus-locked during `[999991, 1050666]`; pool routes through the pool daemon and is unaffected. - It does not implement Stratum v2 / BetterHash / version-rolling. Plain Stratum v1. - It does not bundle any external miner binary. Wallet is the miner. - It does not become a sovereignty hazard — pool mode is opt-in via a radio button, never the silent default for sovereignty-conscious users. ## Calendar estimate (honest) - **4-7 working days** if Miningcore's Quark stratum byte-order is conventional and shares accept on first correct hash - **10-14 working days** if pool.23skidoo.info has any non-standard stratum behavior (very plausible given Quark is a niche stratum variant) Iteration cycles dominated by Windows depends/ cross-compile (~11 min per round). Plan for ~30-50 CI cycles before "shares accept reliably." ## What this isn't - **Not a consensus change.** No fork, no activation height, no upgrade pressure. - **Not a financial product.** Expected earnings per CPU-hour are genuinely fractional at current network hashrate. - **Not urgent.** Door-opener feature for the post-Codex window (block 1,050,667 onward). Could land in v2.1.x or v2.2.x. Branch sits. - **Not a maintenance burden after landing.** Stratum v1 is frozen; no protocol churn to chase. ## Reference behavior to mirror - Built-in solo miner: `src/miner.cpp::GenerateBitcoins`, wired via `src/rpcmining.cpp::setgenerate`. Solo-mode UI wraps these (done). - `getmininginfo` returns the data for solo status display (done). - Quark hash: `src/quark.cpp` — already callable; pool mode's hash worker loop calls it directly with nonce-incremented headers. - `QTabWidget` at `src/qt/forms/rpcconsole.ui` — integration point (done). - `src/qt/rpcconsole.cpp::on_tabWidget_currentChanged` — polling start/stop hook based on which sub-tab is visible (done). - Stratum v1 reference: there's no single canonical spec; cgminer/sgminer/Miningcore-side implementations diverge in small ways. Match Miningcore's Quark output by integration-testing against `pool.23skidoo.info:3040` from day one. ## Open questions (decide in PR review when this comes back) - **Default mode** — pool (recommended for UX) or solo (recommended for sovereignty)? Lean: pool by default with a one-click switch. - **Pool URL hardcoded or editable in UI?** — hardcoded with `Offerings.conf` override is the simplest; editable-in-UI is more flexible but more rope. Lean: hardcoded with conf override. - **Block-found notification (solo) / share-accepted notification (pool)** — toast and/or sound? Defer to v2 of this feature. - **Subsystem location** — `src/stratum.{h,cpp}` lives at top level (mining is a daemon-adjacent function) vs `src/qt/stratum.{h,cpp}` (it only matters when the GUI is up). Lean: top-level so a headless RPC like `setpoolmining` becomes possible later. ## References - `src/qt/forms/rpcconsole.ui` — `QTabWidget name="tabWidget"` (done: `tab_mining` added) - `src/qt/rpcconsole.cpp` — Mining tab slots + OFFSIG guard (done) - `src/qt/res/css/cthulhu-dark.qss` — dark-fill rule includes `#tab_mining` (done) - `src/miner.cpp::GenerateBitcoins` — built-in miner (solo path, already wrapped) - `src/rpcmining.cpp::setgenerate` — RPC the solo path wraps - `src/quark.cpp` — Quark Hash9 (callable directly from pool-mode hash workers) - `pool.23skidoo.info:3040` — pool endpoint (Miningcore, Quark, PPLNS) --- *The Slumbering Lord does not need your CPU. He simply notices when you offer it. Iä Iä.*
dobbscoin commented 2026-06-04 00:00:33 +00:00

Redirect — sub-tab placement instead of new main tab.

After discussion with @BtcBob: the wallet's main tab strip is already crowded enough that some tabs hide behind a chevron at narrow window widths. Adding a sixth or seventh top-level tab is the wrong direction.

Re-scoped above to add Mining as a sub-tab inside Help → Text Based Worship, alongside Information / Console / Network Traffic. Contextually adjacent to the Console where setgenerate currently lives, fits the OFF Cthulhu lore aesthetic ("the Ritual is in the basement"), uses the existing QTabWidget at src/qt/forms/rpcconsole.ui:18 so the integration is one widget add — no main-window plumbing.

Net delta drops from ~300 LOC to ~150 LOC across 2 files. Same OFFSIG-window guard. Same Worthless On Purpose framing.

Also flagged: the dialog's windowTitle at rpcconsole.ui:14 still reads "Debug window" — the menu was rebranded to "Text Based Worship" at bitcoingui.cpp:314 but the dialog title wasn't. Easy 1-line cleanup to include in the same PR.

**Redirect — sub-tab placement instead of new main tab.** After discussion with @BtcBob: the wallet's main tab strip is already crowded enough that some tabs hide behind a chevron at narrow window widths. Adding a sixth or seventh top-level tab is the wrong direction. Re-scoped above to add Mining as a **sub-tab inside `Help → Text Based Worship`**, alongside Information / Console / Network Traffic. Contextually adjacent to the Console where `setgenerate` currently lives, fits the OFF Cthulhu lore aesthetic ("the Ritual is in the basement"), uses the existing `QTabWidget` at `src/qt/forms/rpcconsole.ui:18` so the integration is one widget add — no main-window plumbing. Net delta drops from ~300 LOC to ~150 LOC across 2 files. Same OFFSIG-window guard. Same Worthless On Purpose framing. Also flagged: the dialog's `windowTitle` at `rpcconsole.ui:14` still reads "Debug window" — the menu was rebranded to "Text Based Worship" at `bitcoingui.cpp:314` but the dialog title wasn't. Easy 1-line cleanup to include in the same PR.
dobbscoin commented 2026-06-04 00:33:40 +00:00

Expansion: solo + pool modes via bundled cpuminer-multi.

After follow-up discussion: solo CPU mining alone has Poisson-variance problems that make it a poor demo (4+ hours between block finds isn't uncommon, casuals give up). Pool mode smooths payouts so a user sees their balance tick up reliably within minutes — much better community-onramp feedback loop.

Re-scoped above to support both modes with a UI radio selector:

  • Solo — wraps existing setgenerate. Sovereign, no external deps, high variance. OFFSIG-window locks it out automatically.
  • Pool — spawns bundled cpuminer-multi (GPLv2, has Quark support) as a QProcess pointed at pool.23skidoo.info:3040. Smoother payouts, pool sees IP+address, OFFSIG-window unaffected (pool daemon signs).

Approach: subprocess wrapper around the existing cpuminer-multi rather than reimplementing Stratum in the wallet — keeps the wallet codebase focused on being a wallet, leverages a battle-tested miner, smaller security surface. License is fine (separate binaries; GPL miner + MIT wallet ship side-by-side).

Net delta jumps from ~150 LOC (solo-only) to ~350 LOC Qt + ~80 LOC build-system + cpuminer bundling logistics. Release archives gain ~1-2 MB per platform for the bundled miner.

Default mode for new users: pool (better UX). One-click switch to solo for sovereignty-minded users.

Same OFFSIG-window guard for solo, same rpcconsole.ui windowTitle cleanup, same Worthless On Purpose framing.

**Expansion: solo + pool modes via bundled cpuminer-multi.** After follow-up discussion: solo CPU mining alone has Poisson-variance problems that make it a poor demo (4+ hours between block finds isn't uncommon, casuals give up). Pool mode smooths payouts so a user sees their balance tick up reliably within minutes — much better community-onramp feedback loop. Re-scoped above to support both modes with a UI radio selector: - **Solo** — wraps existing `setgenerate`. Sovereign, no external deps, high variance. OFFSIG-window locks it out automatically. - **Pool** — spawns bundled cpuminer-multi (GPLv2, has Quark support) as a `QProcess` pointed at `pool.23skidoo.info:3040`. Smoother payouts, pool sees IP+address, OFFSIG-window unaffected (pool daemon signs). Approach: subprocess wrapper around the existing cpuminer-multi rather than reimplementing Stratum in the wallet — keeps the wallet codebase focused on being a wallet, leverages a battle-tested miner, smaller security surface. License is fine (separate binaries; GPL miner + MIT wallet ship side-by-side). Net delta jumps from ~150 LOC (solo-only) to ~350 LOC Qt + ~80 LOC build-system + cpuminer bundling logistics. Release archives gain ~1-2 MB per platform for the bundled miner. Default mode for new users: **pool** (better UX). One-click switch to solo for sovereignty-minded users. Same OFFSIG-window guard for solo, same `rpcconsole.ui` windowTitle cleanup, same Worthless On Purpose framing.
dobbscoin commented 2026-06-18 14:46:28 +00:00

Rescoped 2026-06-18.

The original pool-mode design (bundle cpuminer-multi as a QProcess subprocess) is retired in favor of an in-wallet Stratum v1 client. Rationale captured in the issue body; tl;dr the bundling-and-verification logistics for a GPLv2 subprocess miner cost about the same LOC budget as just writing Stratum v1 directly, and the in-wallet path uses dependencies already in the tree (boost::asio + univalue + Quark + serialization helpers).

Branch feat/issue-8-mining-tab-solo keeps the three commits that landed today as the foundation:

  • 70170752 — Mining tab solo mode + OFFSIG window guard
  • 4afadb94 — register tab_mining for the dark-fill rule
  • a475f2eb — drop Solo/Pool radios + voice cleanup on the header

Solo mining works now (and is correctly locked-out during the Codex inscription window [999991, 1050666], which mainnet is currently inside at tip ~1,005,374). Pool mode is the remaining scope.

The branch sleeps. We come back to it after the Codex window closes or when the v2.1 milestone opens, whichever comes first. That is not dead which can eternal lie — issues, too.

Rescoped 2026-06-18. The original pool-mode design (bundle `cpuminer-multi` as a `QProcess` subprocess) is retired in favor of an **in-wallet Stratum v1 client**. Rationale captured in the issue body; tl;dr the bundling-and-verification logistics for a GPLv2 subprocess miner cost about the same LOC budget as just writing Stratum v1 directly, and the in-wallet path uses dependencies already in the tree (boost::asio + univalue + Quark + serialization helpers). Branch `feat/issue-8-mining-tab-solo` keeps the three commits that landed today as the foundation: - `70170752` — Mining tab solo mode + OFFSIG window guard - `4afadb94` — register `tab_mining` for the dark-fill rule - `a475f2eb` — drop Solo/Pool radios + voice cleanup on the header Solo mining works now (and is correctly locked-out during the Codex inscription window `[999991, 1050666]`, which mainnet is currently inside at tip ~1,005,374). Pool mode is the remaining scope. The branch sleeps. We come back to it after the Codex window closes or when the v2.1 milestone opens, whichever comes first. *That is not dead which can eternal lie* — issues, too.
dobbscoin commented 2026-08-07 13:38:20 +00:00

Pool-mode work has resumed on feat/issue-8-mining-tab-solo. Status of this round:

Branch restructured — rebased onto current main (54ab4bed), so it now carries the Overview vitals panel (#62) and the categorized Console help (#64) alongside the Mining tab. Per maintainer decision this branch is a standalone opt-in build lineage and will not merge to main — stock releases stay lean; this build goes to people who ask for it.

Stratum dialect pinned before writing code — a read-only probe of pool.23skidoo.info:3040 captured the full wire format across several live block rotations: standard Miningcore Stratum v1, extranonce1 4 bytes + extranonce2_size 4, prevhash encoding confirmed as plain dword-order reversal against the explorer's block hash. The feared Quark-specific byte-order archaeology largely evaporated. Details in research/stratum-dialect-probe-2026-08-07.md (includes remaining open items: share-target multiplier, version-field semantics, submit param order).

Phase-1 protocol client landed (ff11e083) — src/stratum.{h,cpp}: connect/subscribe/authorize, job + vardiff tracking, reconnect with backoff, correct line framing across TCP segmentation (caught live: a notify split mid-line). Runs headless behind hidden -stratum/-stratumuser debug args. Verified against the production pool: authorize ACCEPTED, multi-job capture with clean-jobs rotations parsed.

Next: job→80-byte-header assembly + coinbase/merkle fold (the wire reference doc has the layout), then the Quark hash worker loop, then share submission — UI last, once shares accept.

Pool-mode work has resumed on `feat/issue-8-mining-tab-solo`. Status of this round: **Branch restructured** — rebased onto current main (`54ab4bed`), so it now carries the Overview vitals panel (#62) and the categorized Console help (#64) alongside the Mining tab. Per maintainer decision this branch is a standalone opt-in build lineage and will not merge to main — stock releases stay lean; this build goes to people who ask for it. **Stratum dialect pinned before writing code** — a read-only probe of `pool.23skidoo.info:3040` captured the full wire format across several live block rotations: standard Miningcore Stratum v1, extranonce1 4 bytes + extranonce2_size 4, prevhash encoding confirmed as plain dword-order reversal against the explorer's block hash. The feared Quark-specific byte-order archaeology largely evaporated. Details in `research/stratum-dialect-probe-2026-08-07.md` (includes remaining open items: share-target multiplier, version-field semantics, submit param order). **Phase-1 protocol client landed** (`ff11e083`) — `src/stratum.{h,cpp}`: connect/subscribe/authorize, job + vardiff tracking, reconnect with backoff, correct line framing across TCP segmentation (caught live: a notify split mid-line). Runs headless behind hidden `-stratum`/`-stratumuser` debug args. Verified against the production pool: authorize ACCEPTED, multi-job capture with clean-jobs rotations parsed. Next: job→80-byte-header assembly + coinbase/merkle fold (the wire reference doc has the layout), then the Quark hash worker loop, then share submission — UI last, once shares accept.
dobbscoin commented 2026-08-07 14:03:42 +00:00

Phase 2 landed and live-fire verified: 19 shares submitted, 19 accepted, 0 rejected against the production pool in a 6-minute run (3 worker threads, vardiff 0.001).

686f6504 (post auto-rebase) adds the hash workers on top of the phase-1 protocol client: coinbase splice + merkle fold + prevhash dword transform straight off the documented wire format, Quark grind through CBlockHeader::GetHash so header serialization is byte-identical to consensus, share bound diff1 / vardiff (the pool's coin definition runs shareMultiplier 1), and mining.submit in the [worker, jobId, extraNonce2, nTime, nonce] order verified against the pool's own Miningcore source. -stratumthreads=<n> controls workers; extranonce2 partitions per worker so nonce spaces never collide. A zero-reject first run means every byte-order and target detail survived contact with production.

Also new since the last update: .github/workflows/offering-branch-track.yml (merged to main as #65) — every push to main now auto-rebases this branch, stamps wallet-mining-<main-sha>, and dispatches all three build workflows at the tag. Fresh artifacts equal to "current main + the miner" appear without anyone touching this branch; a conflicting rebase fails loudly here instead of blocking main. Corollary: never commit to this branch without pulling first — CI force-pushes it.

The stars come right for the worshipper who would mine from the wallet itself: what remains is the Mining tab's pool-mode face — wire the tab to the client's state (connection, vardiff, hashrate, accepted tally), settings persistence, and then offering builds for those who ask.

Phase 2 landed and live-fire verified: **19 shares submitted, 19 accepted, 0 rejected** against the production pool in a 6-minute run (3 worker threads, vardiff 0.001). `686f6504` (post auto-rebase) adds the hash workers on top of the phase-1 protocol client: coinbase splice + merkle fold + prevhash dword transform straight off the documented wire format, Quark grind through `CBlockHeader::GetHash` so header serialization is byte-identical to consensus, share bound `diff1 / vardiff` (the pool's coin definition runs shareMultiplier 1), and `mining.submit` in the `[worker, jobId, extraNonce2, nTime, nonce]` order verified against the pool's own Miningcore source. `-stratumthreads=<n>` controls workers; extranonce2 partitions per worker so nonce spaces never collide. A zero-reject first run means every byte-order and target detail survived contact with production. Also new since the last update: `.github/workflows/offering-branch-track.yml` (merged to main as #65) — every push to main now auto-rebases this branch, stamps `wallet-mining-<main-sha>`, and dispatches all three build workflows at the tag. Fresh artifacts equal to "current main + the miner" appear without anyone touching this branch; a conflicting rebase fails loudly here instead of blocking main. Corollary: never commit to this branch without pulling first — CI force-pushes it. The stars come right for the worshipper who would mine from the wallet itself: what remains is the Mining tab's pool-mode face — wire the tab to the client's state (connection, vardiff, hashrate, accepted tally), settings persistence, and then offering builds for those who ask.
dobbscoin commented 2026-08-11 01:24:14 +00:00

Both halves of this issue are delivered. Closing.

Solo — 70170752 (tab + OFFSIG window guard), 4afadb94 (dark-fill registration), a475f2eb / 14f4702f (radio drop + voice).

Pool, in-wallet Stratum v1 — the path chosen over bundling cpuminer-multi:

  • 379f2f18 — live dialect probe of pool.23skidoo.info:3040, pinning the wire format before a line of client code was written. The feared Quark byte-order archaeology turned out to be plain dword-order reversal.
  • 453910f6 — phase-1 protocol client: connect/subscribe/authorize, job + vardiff tracking, backoff reconnect, line framing that survives TCP segmentation.
  • 0ff24658 — phase-2 hash workers: coinbase splice, merkle fold, Quark grind through CBlockHeader::GetHash so header serialization stays byte-identical to consensus, per-worker extranonce2 partitioning.
  • 2551dfbc — Win64 cross build, compat.h closesocket macro clash.
  • 0a0f3ccb — the Mining tab's pool face. Not OFFSIG-gated: pool blocks carry the Conclave signature, so the communal rite continues while solo is barred.
  • 6b8ab83b — setstratum / getstratuminfo, -stratum* args promoted into --help, create/destroy unified under one lock (closing a GUI-vs-shutdown double-free).
  • ce1590ec — depends fix, zlib off sourceforge; zlib.net serves a bot wall that beats checksum-then-fallback.

Live-fire against the production pool: 19 shares submitted, 19 accepted, 0 rejected over six minutes at three threads. A zero-reject first run means every byte-order and target detail survived contact with production. A public build shipped 2026-08-07.

Closing rather than leaving this open indefinitely, because this lineage never merges to main by maintainer decision — stock releases stay lean, this build goes to those who ask. "Merged" was never going to be the close condition here, so the shipped client is.

One item from the last status comment did not land: pool settings are not persisted across restarts. That's a one-file change and it shouldn't inherit five rescopes of history, so it continues as #66.

Ph'nglui mglw'nafh — the worshipper mines from the wallet itself.

Both halves of this issue are delivered. Closing. **Solo** — `70170752` (tab + OFFSIG window guard), `4afadb94` (dark-fill registration), `a475f2eb` / `14f4702f` (radio drop + voice). **Pool, in-wallet Stratum v1** — the path chosen over bundling `cpuminer-multi`: - `379f2f18` — live dialect probe of `pool.23skidoo.info:3040`, pinning the wire format before a line of client code was written. The feared Quark byte-order archaeology turned out to be plain dword-order reversal. - `453910f6` — phase-1 protocol client: connect/subscribe/authorize, job + vardiff tracking, backoff reconnect, line framing that survives TCP segmentation. - `0ff24658` — phase-2 hash workers: coinbase splice, merkle fold, Quark grind through `CBlockHeader::GetHash` so header serialization stays byte-identical to consensus, per-worker extranonce2 partitioning. - `2551dfbc` — Win64 cross build, `compat.h` `closesocket` macro clash. - `0a0f3ccb` — the Mining tab's pool face. Not OFFSIG-gated: pool blocks carry the Conclave signature, so the communal rite continues while solo is barred. - `6b8ab83b` — `setstratum` / `getstratuminfo`, `-stratum*` args promoted into `--help`, create/destroy unified under one lock (closing a GUI-vs-shutdown double-free). - `ce1590ec` — depends fix, zlib off sourceforge; zlib.net serves a bot wall that beats checksum-then-fallback. Live-fire against the production pool: **19 shares submitted, 19 accepted, 0 rejected** over six minutes at three threads. A zero-reject first run means every byte-order and target detail survived contact with production. A public build shipped 2026-08-07. Closing rather than leaving this open indefinitely, because this lineage never merges to `main` by maintainer decision — stock releases stay lean, this build goes to those who ask. "Merged" was never going to be the close condition here, so the shipped client is. One item from the last status comment did not land: pool settings are not persisted across restarts. That's a one-file change and it shouldn't inherit five rescopes of history, so it continues as **#66**. *Ph'nglui mglw'nafh — the worshipper mines from the wallet itself.*
dobbscoin closed this issue 2026-08-11 01:24:15 +00:00
dobbscoin commented 2026-08-11 01:54:56 +00:00

Correction to the close comment above.

The last paragraph is wrong. It says pool settings are not persisted across restarts and hands that off to #66. They are persisted — by 0a0f3ccb, the same commit that added the pool section.

src/qt/rpcconsole.cpp:255-269 restores endpoint, pay-to address, and thread count in the constructor (endpoint falling back to pool.23skidoo.info:3040, threads bounded by idealThreadCount()); rpcconsole.cpp:681-683 writes them back after StartStratum() succeeds, so only settings that actually brought up a client are stored. Nothing auto-starts on launch. The shipped Offerings-qt.exe from wallet-mining-ef3672f carries all three poolMining* keys.

#66 has been closed as invalid. Nothing was outstanding when this issue closed — the scope was complete, and this one stays closed.

The filing error was mine: a grep that required QSettings on the same line as pool/stratum/mining, while the declaration sits on a line of its own.

**Correction to the close comment above.** The last paragraph is wrong. It says pool settings are not persisted across restarts and hands that off to #66. They are persisted — by `0a0f3ccb`, the same commit that added the pool section. `src/qt/rpcconsole.cpp:255-269` restores endpoint, pay-to address, and thread count in the constructor (endpoint falling back to `pool.23skidoo.info:3040`, threads bounded by `idealThreadCount()`); `rpcconsole.cpp:681-683` writes them back after `StartStratum()` succeeds, so only settings that actually brought up a client are stored. Nothing auto-starts on launch. The shipped `Offerings-qt.exe` from `wallet-mining-ef3672f` carries all three `poolMining*` keys. #66 has been closed as invalid. Nothing was outstanding when this issue closed — the scope was complete, and this one stays closed. The filing error was mine: a grep that required `QSettings` on the same line as pool/stratum/mining, while the declaration sits on a line of its own.
dobbscoin commented 2026-08-12 13:50:55 +00:00

UPnP verified on real hardware (2026-08-12). The commit message for fb5378ac says UPnP's mapping path is unverified — that is now stale, and this is the correction.

The refreshed Windows private build was run on a physical machine behind a TP-Link Omada gateway. Ticking Settings → Options → Network → "Open my port on the router automatically" produced:

Mapped via UPnP - external port 20000

The fallback chain behaved exactly as designed. The Omada does not speak NAT-PMP, so that attempt burned its 4-second probe budget and handed off; UPnP took over and succeeded. The operator never had to know which protocol won — which was the entire point of collapsing the two into one checkbox.

Independently confirmed from outside the network, because a router returning success is not the same as a router forwarding. A TCP connect from vps3 to the machine's public address on port 20000 came back OPEN, and this node shows two inbound connections from it. The mapping carries real traffic, and Windows Firewall permits it.

Also worth recording: this retires an earlier reading in which the Omada appeared to answer neither protocol. That came from an SSDP probe that returned nothing — but the probe was invalid, since the host firewall (ufw, INPUT policy DROP) dropped the multicast reply, which does not match a conntrack entry. It was flagged inconclusive at the time. The gateway does speak UPnP. The NAT-PMP negative stands and was confirmed at wire level.

Verification status for the port-mapping stack on this branch

Path Status
NAT-PMP maps + response parsed correctly ✅ synthetic gateway (granted port deliberately ≠ requested, so a union-parsing bug cannot hide)
Gateway refuses (ICMP unreachable) ✅ immediate fallback
Gateway silently drops ✅ 16s to honest status; ~256s before the probe deadline was added
Shutdown mid-cycle ✅ 1s, mapping deleted via lifetime-0
Builds: Linux daemon, Linux Qt5, Windows ✅
UPnP mapping a real port ✅ real hardware
Mapping actually forwards traffic ✅ verified from outside
NAT-PMP against real hardware ❌ still synthetic only — wants pfSense/OpenWrt

The only remaining gap is a physical router that actually speaks NAT-PMP. Everything else in the stack has now been exercised end to end.

**UPnP verified on real hardware (2026-08-12).** The commit message for `fb5378ac` says UPnP's mapping path is unverified — that is now stale, and this is the correction. The refreshed Windows private build was run on a physical machine behind a **TP-Link Omada** gateway. Ticking Settings → Options → Network → "Open my port on the router automatically" produced: ``` Mapped via UPnP - external port 20000 ``` The fallback chain behaved exactly as designed. The Omada does not speak NAT-PMP, so that attempt burned its 4-second probe budget and handed off; UPnP took over and succeeded. The operator never had to know which protocol won — which was the entire point of collapsing the two into one checkbox. **Independently confirmed from outside the network,** because a router returning success is not the same as a router forwarding. A TCP connect from vps3 to the machine's public address on port 20000 came back **OPEN**, and this node shows two inbound connections from it. The mapping carries real traffic, and Windows Firewall permits it. Also worth recording: this retires an earlier reading in which the Omada appeared to answer *neither* protocol. That came from an SSDP probe that returned nothing — but the probe was invalid, since the host firewall (`ufw`, `INPUT policy DROP`) dropped the multicast reply, which does not match a conntrack entry. It was flagged inconclusive at the time. The gateway does speak UPnP. The NAT-PMP negative stands and was confirmed at wire level. ### Verification status for the port-mapping stack on this branch | Path | Status | |---|---| | NAT-PMP maps + response parsed correctly | ✅ synthetic gateway (granted port deliberately ≠ requested, so a union-parsing bug cannot hide) | | Gateway refuses (ICMP unreachable) | ✅ immediate fallback | | Gateway silently drops | ✅ 16s to honest status; ~256s before the probe deadline was added | | Shutdown mid-cycle | ✅ 1s, mapping deleted via lifetime-0 | | Builds: Linux daemon, Linux Qt5, Windows | ✅ | | **UPnP mapping a real port** | ✅ **real hardware** | | **Mapping actually forwards traffic** | ✅ **verified from outside** | | NAT-PMP against real hardware | ❌ still synthetic only — wants pfSense/OpenWrt | The only remaining gap is a physical router that actually speaks NAT-PMP. Everything else in the stack has now been exercised end to end.
Sign in to join this conversation.
No labels
enhancement
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
SubGeniusFinance/Offerings-to-Cthulhu#8
No description provided.