qt: add Mining sub-tab in Text Based Worship — solo (done) + in-wallet stratum pool client (post-Codex, v2.1+) #8
Labels
No labels
enhancement
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
SubGeniusFinance/Offerings-to-Cthulhu#8
Loading…
Reference in a new issue
No description provided.
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?
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:
Help → Text Based Worshipsetgenerate true 1from external docs (solo, high variance)cpuminer-multiexternally for pool miningQuark 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_miningwidget added totabWidgetinsrc/qt/forms/rpcconsole.uiQThread::idealThreadCount())getmininginfo[999991, 1050666]— controls grey out, dark-red banner explainscthulhu-dark.qssregistered#tab_miningfor the dark-fill rule so it inherits the dialog paletteWhat'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:The
QTabWidgetinfrastructure atsrc/qt/forms/rpcconsole.uialready supports new sub-tabs trivially. Discoverable for users who exploreHelp, 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:
setgeneratesolo miner. Variance-prone, sovereign, no external dependencies.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:
chainActive.Tip()->nHeightis within[999991, 1050666], the toggle + thread spinner grey out and a banner explains the Codex window with countdown to block 1,050,667setgenerate falseand restore at block 1,050,667 (TODO — currently the user just sees the controls go grey on the next tip update)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-multias a subprocess (the earlier plan):Why this is non-trivial nonetheless:
Scope breakdown
mining.subscribe / authorize / set_difficulty / notify / submit, JSON-RPC line-framed over TCP. New filessrc/stratum.{h,cpp}(or similar). Use raw boost::asio to match existing P2P style, or a dedicated boost::thread with blocking sockets for simplicity.BitcoinMinerinsrc/miner.cpp.mining.set_difficultymid-job,clean_jobs=trueonmining.notify.src/qt/rpcconsole.cpp+ form): mode radio, pool URL (read-only label, advanced users editOfferings.conf), payout address (auto-getnewaddresson first activation, regenerate button), worker name, threads spinner, big "Mine Offerings" toggle, status line.optionsmodel.cppfor pool prefs (mining_mode,mining_pool_url,mining_pool_address,mining_pool_worker). UI prefs, not consensus flags.src/test/.Status line states (pool mode)
Pool mining stoppedConnecting to pool.23skidoo.info…Authorizing as Q…<addr>.<worker>Connected · ~X.YZ MH/s · accepted Y / rejected Z shares · pool diff DPool unreachable — retrying in 30s (attempt N)Pool authentication failed — check payout addressWhat pool mode does NOT do
[999991, 1050666]; pool routes through the pool daemon and is unaffected.Calendar estimate (honest)
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
Reference behavior to mirror
src/miner.cpp::GenerateBitcoins, wired viasrc/rpcmining.cpp::setgenerate. Solo-mode UI wraps these (done).getmininginforeturns the data for solo status display (done).src/quark.cpp— already callable; pool mode's hash worker loop calls it directly with nonce-incremented headers.QTabWidgetatsrc/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).pool.23skidoo.info:3040from day one.Open questions (decide in PR review when this comes back)
Offerings.confoverride is the simplest; editable-in-UI is more flexible but more rope. Lean: hardcoded with conf override.src/stratum.{h,cpp}lives at top level (mining is a daemon-adjacent function) vssrc/qt/stratum.{h,cpp}(it only matters when the GUI is up). Lean: top-level so a headless RPC likesetpoolminingbecomes possible later.References
src/qt/forms/rpcconsole.ui—QTabWidget name="tabWidget"(done:tab_miningadded)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 wrapssrc/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ä.
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 wheresetgeneratecurrently lives, fits the OFF Cthulhu lore aesthetic ("the Ritual is in the basement"), uses the existingQTabWidgetatsrc/qt/forms/rpcconsole.ui:18so 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
windowTitleatrpcconsole.ui:14still reads "Debug window" — the menu was rebranded to "Text Based Worship" atbitcoingui.cpp:314but the dialog title wasn't. Easy 1-line cleanup to include in the same PR.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:
setgenerate. Sovereign, no external deps, high variance. OFFSIG-window locks it out automatically.QProcesspointed atpool.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.uiwindowTitle cleanup, same Worthless On Purpose framing.Rescoped 2026-06-18.
The original pool-mode design (bundle
cpuminer-multias aQProcesssubprocess) 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-solokeeps the three commits that landed today as the foundation:70170752— Mining tab solo mode + OFFSIG window guard4afadb94— registertab_miningfor the dark-fill rulea475f2eb— drop Solo/Pool radios + voice cleanup on the headerSolo 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.
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:3040captured 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 inresearch/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/-stratumuserdebug 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.
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 throughCBlockHeader::GetHashso header serialization is byte-identical to consensus, share bounddiff1 / vardiff(the pool's coin definition runs shareMultiplier 1), andmining.submitin 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, stampswallet-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.
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 ofpool.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 throughCBlockHeader::GetHashso header serialization stays byte-identical to consensus, per-worker extranonce2 partitioning.2551dfbc— Win64 cross build,compat.hclosesocketmacro 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
mainby 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.
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-269restores endpoint, pay-to address, and thread count in the constructor (endpoint falling back topool.23skidoo.info:3040, threads bounded byidealThreadCount());rpcconsole.cpp:681-683writes them back afterStartStratum()succeeds, so only settings that actually brought up a client are stored. Nothing auto-starts on launch. The shippedOfferings-qt.exefromwallet-mining-ef3672fcarries all threepoolMining*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
QSettingson the same line as pool/stratum/mining, while the declaration sits on a line of its own.UPnP verified on real hardware (2026-08-12). The commit message for
fb5378acsays 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:
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
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.