dvb-WarpPool — open-source solo mining pool written in Rust (Umbrel / macOS / Windows / Linux)

dvb-WarpPool — open-source solo mining pool written in Rust (Umbrel / macOS / Windows / Linux)

I’d like to introduce dvb-WarpPool, a Bitcoin solo pool written from scratch in Rust, made for self-hosting. The idea: if you’re chasing the lottery block with a NerdMiner, Bitaxe, NerdQaxe or Avalon Q, you don’t have to send your shares to a public solo pool — your own node builds the block templates, and when a block hits, the coinbase output already carries your wallet address. No middleman, no pool fee, no sign-up.

Under the hood: Stratum V1 (plain + TLS) and Stratum V2 with NOISE handshake, persistent VarDiff, getblocktemplate + ZMQ for millisecond job refresh, hardware detection with profile recommendation, and a SvelteKit PWA dashboard with live updates in 8 languages — now with freely sortable and collapsible cards (drag & drop, optionally saved as the default for all visitors). Plus block-found alerts via Telegram/Discord/ntfy/Slack/email/web push, and energy tracking including PV integration (Anker Solix, Home Assistant): on solar surplus the electricity price automatically drops to 0, and the kWh history splits solar and grid shares.

Easiest install is the Umbrel Community App Store (your own Bitcoin node required); alternatively signed packages for macOS/Windows/Linux or a multi-arch Docker image. Security: 2FA, Argon2, audit log, security audit, reproducible builds, Cosign-signed artifacts with SLSA attestation, currently 860+ tests.

Licensed MIT/Apache-2.0 — feedback and issues welcome on GitHub: GitHub - dvb-projekt/dvb-WarpPool: Rust Bitcoin Solo Mining Pool — Stratum V1+V2, PWA operator UI, signed multi-arch releases · GitHub

2 Likes

dvb-WarpPool — a solo mining pool that treats your hardware like it knows it

dvb-WarpPool is an open-source, self-hosted solo Bitcoin pool in Rust — one binary in front of your own Bitcoin Core, from a single Bitaxe to a 1,000-miner shed. 100% of a found block goes to the address your miner authorizes with. No custody, no payout ledger, no account.

The heart of it is VarDiff that actually knows mining hardware. The pool reads your miner’s user agent and starts every device in the right league — eight classes from Antminer-grade iron down to a NerdMiner V2, which gets sub-1 difficulty from the first second instead of starving at diff 1, plus deliberately lazy retargeting so its display isn’t constantly reset. Difficulty survives reconnects and pool restarts (persisted per worker), converges with an EMA plus hysteresis instead of jumping around, and never moves more than 4× per step. Your miner gets a say too: suggest_difficulty seeds the session, d=8192 in the password pins it — both safely clamped to the device class. And if a worker goes quiet because its difficulty ended up too high, a guarded idle decay walks it back down instead of stranding it forever — built by someone who filed the downward-crush bug against another pool and made that failure mode structurally impossible here.

Speaks everything your fleet does. Stratum V1, V1 over TLS (working out of the box, with a guided Let’s Encrypt setup for friends mining from outside), and Stratum V2 with the current 2024 handshake spec — verified live against the Bitaxe and NerdQAxe families, with share responses around 15 ms.

Built to stay up. Multiple Bitcoin Core nodes via [[node.backup]]: sub-second failover when the primary dies, automatic return when it’s back, block events taken from whichever node reports first — and a found block is submitted to all nodes in parallel, because that’s the one moment a dead node could cost real money. In load tests, 1,000 concurrent miners ran against the daemon at under 50 MB RAM and about a third of one CPU core.

Nice to live with. A PWA dashboard in 8 languages with background push to your phone, block alerts your whole friends group can subscribe to (one shared ntfy topic — no accounts), per-device telemetry for Bitaxe/Antminer/Avalon/Whatsminer, energy and solar tracking, and an admin cockpit instead of config-file archaeology. Install from the Umbrel app store, a signed-checksums release (.dmg, .msi, .deb/.rpm, AppImage) or multi-arch Docker — reproducible builds with SBOM included. 900+ tests run before every release.

The honest part: solo mining is a lottery — this pool makes the ticket-buying pleasant, not the odds better. The project is young; no mainnet block found yet (that’s how solo works at home scale). macOS/Windows binaries aren’t store-signed yet. Everything else is in the open: code, tests, benchmarks, and a handbook that documents the limitations too.

:link: GitHub - dvb-projekt/dvb-WarpPool: Rust Bitcoin Solo Mining Pool — Stratum V1+V2, PWA operator UI, signed multi-arch releases · GitHub · Handbook: Introduction - dvb-WarpPool

1 Like

dvb-WarpPool — update: hardening & operations (v1.4.0)

New here? dvb-WarpPool is an open-source, self-hosted Bitcoin solo mining pool — written in Rust, with a full operator web UI (PWA, 8 languages), built for mixed home hardware: NerdMiner next to Bitaxe next to Avalon. Stratum V1/V2/TLS, device telemetry, energy & solar tracking, signed builds for macOS/Windows/Linux/Docker/Umbrel.

This update shifts the focus from breadth to operations — what a solo pool needs to run continuously, and occasionally exposed to the open internet:

One profile switches the whole pool. Small/Medium/Large/Enterprise now apply everything live: VarDiff range, connection cap, data retention, poll intervals, rate limits. No restart — and the Hardware table honestly marks each value as live, restart-only, or advisory.

Abuse protection that leaves your home network alone. Internet scanners that hammer the connect limit are now auto-banned — escalating (5 min → doubling → up to 1 h), before the TLS handshake even happens. Loopback and LAN are never banned, so your NerdMiner can reconnect in a loop. Plus a manual block list (admin API + UI) and per-IP limits on connect, auth, and the HTTP API.

Strong miners get the right difficulty. Avalon Q, S19, Whatsminer & co. used to be capped artificially; now each hashrate class gets its proper range — stable difficulty, less waste.

Monitoring out of the box. The Prometheus /metrics endpoint now also exports the aggregate pool figures — pool and network hashrate, best share, active wallets, active bans — ready for Grafana, with recipes in the handbook.

Under the hood: a fuzz-hardened Stratum parser, 939 tests before every release, signed and reproducible artifacts.

Still honest: no mainnet block yet — the project is young.

dvb-WarpPool v1.4.2 — the setup wizard now speaks your language

This one is deliberately small — polish where newcomers look first:

The first-run wizard is now fully bilingual (DE/EN). A few cards — hardware detection, the Bitcoin Core health check and its warnings, the connectivity overview — still slipped through in German even with the UI set to English. They’re now fully translated, switching the language updates every card live, and ?lang=de / ?lang=en lets you deep-link straight into a locale.

One-click update works again. dvb-warppool-cli download-update and the “Install update” button in the admin area used to fetch the wrong asset names and fail every time. They now recognise the real release packages, extract the daemon binary from the tarball and swap it in cleanly — with the signature verified against SHA256SUMS.

Otherwise as solid as before: one profile switches the whole pool live, auto-ban against internet scanners (your LAN is spared), Prometheus /metrics for Grafana, a fuzz-hardened parser, 952 tests before every release, signed and reproducible artifacts.

Still honest: no mainnet block yet — the project is young.

dvb-WarpPool v1.4.3 — the all-time best-shares board now shows the real top hits, and the wizard speaks 8 languages

The “All-time” best-shares board now shows the absolute top hits. Until now every miner was capped at 10 entries in the shared table — so a single strong miner could never hold more than 10 of the 50 leaderboard slots, even when it genuinely produced the highest shares. The all-time view now reads from a dedicated, globally-ranked table with no per-worker cap, reflecting the true ranking: if one miner holds the top 50, that’s exactly what you see. The “Per-worker” view (one row per miner) and the best-share overlay on the hashrate chart stay unchanged on purpose. Existing best shares are carried over automatically on upgrade.

The setup wizard now speaks all 8 languages. After going bilingual in v1.4.2, it now adds Spanish, Portuguese (BR), French, Italian, Japanese and Chinese — the same language set as the dashboard. The picker is a clean dropdown (flag + native name, like the dashboard) rather than a row of buttons, the browser language is auto-detected, and ?lang=<code> deep-links straight into any locale.

Otherwise as solid as before: one profile switches the whole pool live, auto-ban against internet scanners (your LAN is spared), Prometheus /metrics for Grafana, a fuzz-hardened parser, 956 tests before every release, signed and reproducible artifacts.

Still honest: no mainnet block yet — the project is young.

dvb-WarpPool v1.4.5 — the setup wizard now opens with an animated intro

  • Animated warp intro on first-run setup. The wizard opens with a short vortex clip, then fades into setup (respects reduced-motion).
  • Calmer dashboard. The “API unreachable” notice no longer flashes on a brief network blip — it only shows after repeated failures.

Already on board: an 8-language setup wizard with a dropdown picker, an all-time best-shares board showing the real top hits, live profiles, auto-ban against internet scanners, Prometheus /metrics. No mainnet block yet (the project is young).

dvb-WarpPool v1.5.0 — a full-screen screensaver turns any always-on monitor into a pool dashboard

  • New full-screen screensaver for wall & kiosk displays. After a configurable idle time the dashboard fades into a seamlessly looping WarpPool clip with a live stat bar: best share (plus the worker that found it), hashrate, active miners, blocks found, and version/update status — with a “LIVE” badge and a ticking uptime. Any input (mouse/key/touch) brings the dashboard back.
  • Configurable per device via a new “Display” menu in the top bar: on/off, idle timeout (5/10/15/30 min), stats overlay. Off by default, respects reduced-motion (a static still instead of video).

Already on board: an animated setup intro, an 8-language setup wizard with a dropdown picker, an all-time best-shares board showing the real top hits, live profiles, auto-ban against internet scanners, Prometheus /metrics. No mainnet block yet (the project is young).

This sounds wild! I assume vibe coded? How long did it take you? I’m impressed by the feature list

Hi skot,

thank you very much for your feedback.

It’s been about four weeks of intensive work with Claude to implement all my ideas for WarpPool.

The goal was to create the best and most secure BTC solo pool available today—one that eliminates the drawbacks and limitations of existing pools and provides users with maximum support during setup and operation.

The pool was designed primarily for home mining, but also includes an extension for the commercial sector.

I think Claude and I have succeeded quite well in this. The performance metrics speak for themselves.

dvb-WarpPool v1.6.0 — a clear license (AGPLv3) + an optional legal notice for public operators

  • New license: AGPLv3 (previously MIT/Apache). For self-hosters nothing changes — running your own pool stays free. The switch just keeps improvements open and stops anyone from closing off a proprietary commercial fork. A separate commercial license is available for proprietary use.
  • Optional Terms/Privacy footer for public & commercial operators. If you run a pool for others, you can configure your own Terms-of-Use and Privacy-Policy links — the dashboard then shows a “By connecting … you agree …” notice. Off by default (solo setups don’t need it).

Already on board: a full-screen screensaver for wall displays, an animated setup intro, an 8-language wizard with a dropdown, an all-time best-shares board, live profiles, auto-ban against internet scanners, Prometheus /metrics, Stratum V2/TLS. No mainnet block yet (the project is young).

dvb-WarpPool v1.7.0 — outbound webhooks + read-only API tokens for your own add-ons & automations

  • Outbound webhooks. The pool can now POST pool events (block found, health, …) as JSON to your own URL — wire it into a script, a custom backend, or a no-code tool (Zapier etc.). HMAC-signed for verification, off by default. A push complement to the existing SSE live stream.
  • Read-only API tokens. Hand an add-on or dashboard a read-only token — even if it’s compromised, it can’t reconfigure the pool (least privilege).
  • Add-on handbook chapter. Covers the clean sidecar boundary (a separate process, not linked-in code), the stable interface contract, and the API-stability promise — for anyone building their own extensions.

Already on board: AGPLv3 + commercial option, optional legal footer, full-screen screensaver, animated setup intro, 8-language wizard, all-time best-shares board, auto-ban, Prometheus, Stratum V2/TLS. No mainnet block yet (the project is young).

dvb-WarpPool v1.8.0 — fewer false rejects: a VarDiff grace window for Stratum V1 + V2

  • VarDiff grace window. When the pool raises a miner’s difficulty, shares the device had already computed against the old (looser) target were briefly “in flight” — and were wrongly rejected as “low difficulty”, adding up to a few percent “rejected” / “shares above target” on busier miners. The pool now keeps accepting those in-flight shares for a short transition window. Fixed on both protocols — Stratum V1 and V2.
  • Honest reject stats. The dashboard’s rejected-shares total now reflects the real rate instead of always showing 0 — and is now tracked for Stratum V2 too (previously not at all).
  • download-update --tag. Self-update can now target a specific release — pin to a known-good version or roll back off a bad one.

For context: your solo block chances were never affected — block candidates are checked against the network target, not the pool target. This was about share accounting, VarDiff accuracy and the miner-side reject display. No mainnet block yet (the project is young).

Already on board: outbound webhooks + read-only API tokens, AGPLv3 + commercial option, legal footer, full-screen screensaver, 8-language wizard, all-time best-shares board, auto-ban, Prometheus, Stratum V2/TLS.

dvb-WarpPool v1.8.1 — smoother VarDiff: no more difficulty overshoot after a reconnect

  • VarDiff overshoot fixed. After a reconnect the pool’s difficulty estimate lagged and chained big jumps far past the optimum while ramping up, then swung back — visible as a wildly jittering hashrate curve on the miner display plus a short burst of rejects. The estimate now recalibrates at every step and lands straight on the optimum: calm display, fewer reconnect rejects, one stable difficulty instead of constant oscillation.
  • Under the hood: the share-interval EMA is scaled by the difficulty ratio at each retarget (standard VarDiff practice) — applies to Stratum V1 and V2 at once, since both share the same VarDiff engine. Live-verified: the same config that overshot to ~10× the optimum now settles cleanly.

For context: your block chances were never affected — this was purely difficulty stability, display and share accounting. Builds on v1.8.0 (which removed the grace-window rejects at difficulty changes); together VarDiff now runs smooth. No mainnet block yet (the project is young).

Already on board: VarDiff grace window (v1.8.0), outbound webhooks + read-only API tokens, AGPLv3 + commercial option, full-screen screensaver, 8-language wizard, all-time best-shares board, auto-ban, Prometheus, Stratum V2/TLS.

dvb-WarpPool v1.9.0 — best-share trail on the chart: a continuous peak line across the full 24 hours

  • Best-share dots over time. The amber dots on the hashrate curve now show the highest real share difficulty in each time slice — a continuous trail across the whole 24-hour window. Previously the overlay drew from the best-share leaderboard table (per-worker top-N), which ages out of the 24 h window for established workers — so it ran nearly empty, showing only the small fresh personal-bests of the weakest devices. Now your strong miners stay visible the whole way, in the real G/T range (the behaviour goPool’s chart already had). The best-share list is unchanged.
  • Under the hood: each 1-minute bucket records its highest actual hash difficulty (not the VarDiff plateau) and serves it via the hashrate API; the frontend draws the dots from that (downsampled to 160, highest per slice). Also drops one API call per dashboard refresh.
  • Also: the right-hand axis labels no longer get clipped on narrow phone screens.

For context: a display/UI feature only — the mining path and your block chances are untouched. After updating, the trail fills in over the first ~24 h, since the peak data is recorded going forward. No mainnet block yet (the project is young).

Already on board: smooth VarDiff with no reconnect overshoot (v1.8.0/v1.8.1), outbound webhooks + read-only API tokens, AGPLv3 + commercial option, full-screen screensaver, 8-language wizard, all-time best-shares board, auto-ban, Prometheus, Stratum V2/TLS.

dvb-WarpPool v1.10.0 — standards-compliant block construction, BIP-54-ready ahead of activation

  • BIP-54-forward-compatible coinbase. The coinbase now carries an enforced block-height timelock (nLockTime = height-1, nSequence = 0xfffffffe) — exactly what the upcoming Consensus Cleanup soft fork (BIP-54) will require. The block stays valid under today’s rules (the lock is always already satisfied when mining height) and is ready for activation at the same time. Future-proof, nothing to configure.
  • This rounds out the already standards-compliant block construction: BIP-34 coinbase height, SegWit witness commitment, BIP-310 version-rolling (overt ASICBoost). Those three are table stakes for any serious pool — being BIP-54-forward-compatible is (as far as I can tell) not yet common.
  • Applies to Stratum V1 and Sv2 alike (shared coinbase build). Verified end-to-end against a regtest block accepted by Bitcoin Core.

For context: a correctness / future-proofing feature only — your block chances are unchanged. No mainnet block yet (the project is young).

Already on board: best-share peak trail on the chart (v1.9.0), smooth VarDiff with no reconnect overshoot (v1.8.x), energy + solar tracking, outbound webhooks + read-only API tokens, AGPLv3 + commercial option, full-screen screensaver, 8-language wizard, per-miner telemetry, Stratum V2/TLS.

dvb-WarpPool v1.11.0 — a calmer VarDiff: less difficulty flapping for mixed home hardware

This release targets one concrete home-mining annoyance: the constant set_difficulty churn that makes ESP32 miner displays (NerdMiner et al.) flicker.

  • Poisson significance gate (on by default). VarDiff now re-targets only when the deviation is statistically significant for the number of shares seen, instead of reacting to every excursion past a fixed band. A low-rate miner’s observed share-rate is Poisson-noisy (~1/√N); a fixed hysteresis band reads that noise as a real hashrate change. The gate holds until the change is real — a genuine hashrate change still clears the band promptly. Opt out with significance_gate = false.
  • suggest_difficulty is a starting hint again, not continuous control. Devices (NerdMiner/NerdNOS) that re-send the same below-floor request every ~90 s used to trigger a set_difficulty each time. No more.
  • Avalon Q detection fix. An Avalon Q reports the generic cgminer user-agent, so it was misclassified as Bitaxe and capped ~5× too low; detection now consults the worker name.

Verified live on an 8-miner Box: NerdMiner ~17 → 0 re-targets/h, 6 of 7 device classes −46…−88 %, 0 rejects.

Honest framing: this is display calm / smoothness, not a hashrate or earnings difference. Versus ckpool/public-pool/mkpool, those run a fixed hysteresis band rather than a significance test, and on none of them does the converged difficulty survive a pool restart — on dvb-WarpPool it does (source-checked). Other pools (e.g. goPool) do have Poisson-aware VarDiff too — no superiority claimed there.

dvb-WarpPool v1.12.0 — Stratum V2 miners reach VarDiff parity with V1, plus a robustness pass

This release implements the full VarDiff/robustness backlog from the last review — three thrusts:

  • Stratum V2 miners get full VarDiff parity. Direct Sv2 miners used to run a hard-coded default VarDiff. They now use the same engine as V1: your [vardiff] operator config, the same idle-decay walk-down when a miner goes quiet, and their best-/lucky-share stats recorded for the leaderboard. One shared VarDiff engine for both protocols — no second code path lagging behind.
  • Robustness pass. Share writes are now atomic (one transaction per share instead of ~14 separate fsyncs → consistent tables, less I/O). The config is validated at startup (no sub-60s retention TTLs, no hysteresis_ticks = 0). The worker table is protected against unbounded growth via client-controlled worker names (idle workers are evicted after the TTL, block-finders are kept forever). And the ntime lower bound from the block template is now enforced — it was dead (hard-coded 0), so only the upper bound applied.
  • Admin saves preserve your comments. Editing the config from the UI no longer strips the hand-written comments/formatting from your config.toml (via toml_edit).

Honest framing: this is feature parity, data integrity and convenience — not a hashrate or earnings difference. V1-only operators mainly feel the hardening (atomic writes, startup validation); operators with direct Sv2 miners now get the same VarDiff quality they had on V1. Hot-path regtest-smoke-tested, 1018 tests green, reproducible build as always.

dvb-WarpPool v1.12.1 — Stratum V2 miners mine reject-free: the stale-share bug is gone

One concrete bug in direct Stratum V2 miners — and its clean fix:

  • The problem. A solo pool pushes a fresh mining job roughly every 30s to fold in new mempool transactions (same previous block, just a better template). A direct Sv2 miner (NerdQAxe family, NerdAxeGamma, or a Bitaxe over Sv2) submits a share in the brief window right after such a refresh — still on the job that was current when it started hashing it — which is valid work. But the Sv2 server only remembered the single newest job and rejected everything else as “stale”. V1 never had this: it always kept a short history of recent jobs. The Sv2 path was missing exactly that.
  • The fix. The Sv2 server now keeps a short rolling job history (like V1). Every submitted share is validated — proof-of-work reconstruction included — against the exact job it was built on, not just the newest one. A genuine new block is still detected (via the previous-block-hash change) and correctly purges the old jobs, so truly stale shares after a block change are still rejected.
  • The result, measured live. On the test box a NerdAxeGamma went from ~13% rejected shares to 0% — over a 10-minute window, pool and firmware counters in lockstep (+37 accepted / 0 rejected each). As a side effect the VarDiff starvation stops: previously the wrongly-rejected shares were dragging the miner’s difficulty into free-fall.

Plus three small things: an ntime acceptance window on the Sv2 path (a share’s timestamp is checked against a sane window), a retention-config fix, and a bit of UI polish (the “LIVE” indicator no longer flickers on every event — 3s debounce).

Honest framing: this is a correctness fix for direct Sv2 miners, not a hashrate gain. Your miner always did the same work — what’s new is that its valid shares get credited again instead of thrown away, the accepted/rejected counters are accurate, and VarDiff stays stable. V1-only operators are unaffected (V1 always did this right). If you run NerdQAxe-/Bitaxe-class hardware over Stratum V2, this is the release to take. Hot-path regtest-smoke-tested, 1020 tests green, reproducible build as always.