Comparison: dvb-WarpPool vs. ckpool vs. public-pool vs. mkpool
Choosing a self-hosted solo pool comes down to a handful of open-source candidates. This page compares them feature by feature so you can pick the right tool for your setup.
How this table was made — and how to read it fairly:
- Every claim was verified against the source code of the compared
projects, not against their marketing. Full re-verification on
2026-07-21 against ckpool master
308410d(2026-07-20), public-pool master96a9202(2026-06-05, one commit past95565ee, which the Umbrel app pins), and mkpool masterd2e4819(2026-07-19). dvb-WarpPool claims reflect v1.24.0. - All four are actively maintained open-source projects making different trade-offs. ckpool has been the workhorse of solo mining for a decade (the hosted solo.ckpool.org has found hundreds of mainnet blocks); mkpool is a modern multi-coin C++ engine; public-pool is the familiar TypeScript pool with a web UI. Nothing here means “those are bad.”
- The table tracks what ships in the open-source code. Hosted instances (solo.ckpool.org, public-pool.io, mkpool.com) run additional private code you don’t get when self-hosting — mkpool’s README states its database/analytics service, REST API and website are not in the open release, so those rows reflect the engine only. Where a project’s README claims a feature its open code doesn’t implement, we go by the code — and equally, where the code has moved ahead of what this page used to say, the code wins (mkpool’s multi-node failover was listed here as unimplemented and is now wired up end to end).
- Competitor repos move. If a cell is outdated,
open an issue — this
page is only useful while it’s accurate. All rows — ours and the
competitors’ — were last verified 2026-07-21 against the commits named
above. The 2026-07-21 pass changed several rows in the competitors’ favour:
ckpool has gained a Bitcoin Core IPC template path and BIP54 coinbase
handling, and mkpool has gained working multi-node failover, tagged
releases and CI. Those corrections are reflected below. The
address-ownership owner-panel row was re-verified 2026-07-24 against fresh
heads (ckpool
308410d, public-pool96a9202, mkpool4785cd5): none of the three has any signed-message ownership mechanism.
| dvb-WarpPool | ckpool (solo) | public-pool | mkpool | |
|---|---|---|---|---|
| Coins | Bitcoin | Bitcoin | Bitcoin | 9 chains (BTC, BCH, BitcoinII, DigiByte, eCash, ZEC, LTC, DOGE, BCH II; DOGE also merge-mined under LTC) |
| Starting difficulty | hardware-aware, 7 device classes from user agent (unrecognised falls back to the profile default) | 42 by default, operator-configurable (startdiff), same value for every miner | 100,000, same value for every miner | fixed per port tier (default 65,536; SV2 extended channels: seeded from the miner’s nominal hashrate) |
| Sub-1 difficulty | from the first share (NerdMiner class) | no (mindiff 1) | yes — reachable both by the starvation descent (÷6 below 5 recent shares) and by ordinary VarDiff; floor 0.00001 | no (floor 1; configured floors 1024) |
| Difficulty persistence | survives reconnects and pool restarts | no | no | no |
suggest_difficulty / d= | both, clamped to the device class; a repeat or below-current suggest is deduped and treated as a seed, not continuous control | suggest only (no d= password syntax); clamped up to mindiff, and a repeat or already-current suggest is deduped | suggest unclamped, one-shot (latched); d= integer, upward only | both; suggest_difficulty clamped to the tier’s vardiff min/max, d=/diff= clamped per coin — both re-emit set_difficulty (+ a job re-push) on every repeat, and are ignored on fixed-diff tiers |
| VarDiff style | EMA + Poisson significance gate (retarget only when the share-rate clears a 1/√N confidence band) + guarded idle decay, per-class floors | dual EMA (60 s / 300 s window) + fixed 0.15–0.4 share-rate hysteresis band, retarget gated on ≥72 shares or 240 s | 60 s timer + ±2× hysteresis, power-of-2 snaps (downward starvation step ÷6) | dual EMA + fixed hysteresis — a faithful ckpool port, same 0.15/0.40 and 72-share/240 s constants |
| Fixed-difficulty ports | no — VarDiff adapts per device | via separate instances | no | yes (one fixed-diff TCP port per tier) |
| Stratum V2 | 2024 spec, live-verified (Bitaxe / NerdQAxe) | no | not in master (side branch) | yes — Noise NX handshake, EllSwift/BIP324 key exchange, encrypted transport (the source names no spec version) |
| TLS for miners | out of the box + Let’s Encrypt guide | no | no | yes (in-binary) |
| Block/coinbase standards | BIP34 height, SegWit commitment, BIP310 version-rolling (overt ASICBoost), BIP54-forward-compatible coinbase locktime | BIP34, SegWit, version-rolling, and BIP54 (nSequence fffffffe + nLockTime = height−1) | BIP34, SegWit, version-rolling | BIP34, SegWit, version-rolling (mask 1fffe000, off for BCH) |
| Payout model | two modes: a single operator-configured address (default), or opt-in per-worker coinbase — each miner mines to the address in its own stratum login, full reward, one output, and the config rejects a pool fee in that mode | solo mode (btcsolo) pays each miner’s own address from the stratum username; auth is refused if the username is not a valid address. Optional operator donation output, default 0 (shipped example config sets 2%) | pays the address in the stratum username. Optional dev-fee output (1.5%) when DEV_FEE_ADDRESS is set, automatically waived below 50 TH/s | pays the address in the stratum username (V1 and both SV2 channel types), validated twice — locally, then via validateaddress. Optional operator donation output, default 1% but with no default address, so it is inert until configured. Merge-mined DOGE falls back to an operator address if the miner supplies none |
| Coinbase outputs (solo/per-miner path) | 1 (+ SegWit commitment) | 1 (+ commitment), 2 with a donation | 1 (+ commitment), 2 with the dev fee | 1 (+ commitment), 2 with a donation; more on eCash (consensus-mandated outputs) |
| Multi-node failover | yes — sub-second switch, submitblock to all nodes in parallel | yes (btcd failover list) | no (single RPC endpoint) | yes — RPC fallback nodes with automatic switch-back, plus redundant submitblock fan-out and upstream-link failover for the new proxy role |
| Block-change latency | ZMQ from every configured node, first wins | Core IPC notifications when configured, otherwise ZMQ, plus a polling backstop | ZMQ (optional; falls back to a 500 ms poll), which triggers a getmininginfo poll | ZMQ + polling fallback + watchdog |
| Template source | getblocktemplate (RPC) by default + optional Bitcoin Core IPC (Cap’n Proto, experimental, requires Core ≥ 31) — templates straight from kernel notifications, measured ~5–12 ms vs ~89–101 ms for GBT+ZMQ | also both — getblocktemplate by default, with an opt-in Core IPC template path (ipcmining / ipctemplate) that falls back to RPC | getblocktemplate (RPC) | getblocktemplate (RPC) |
| Rate-limit / auto-ban | per-IP on connect/auth/API + escalating ban + manual block list | per-user exponential auth backoff (capped 600 s); no IP or share-rate bans | connection cap, socket timeout, user-agent filter; no per-IP limit or ban list | token-bucket + invalid-share ban, plus a DB-backed address/worker blacklist |
| Web UI / API | PWA, 8 languages, authenticated, live SSE | none (logs + unix socket) | yes — UI in a separate repo; read APIs unauthenticated and CORS fully open (one share-submission endpoint takes an API key) | none in the open release (engine + Postgres writer, plus a local control socket) |
Prometheus /metrics | yes (pool + per-miner + network) | no | no | yes (opt-in build flag) |
| Notifications | 5 sinks + Web Push; friends can subscribe | none | Telegram/Discord (block found, plus a Discord restart notice) | none in the open release |
| Address-ownership owner panel | yes — a miner proves control of the payout address by signing a challenge (BIP-137 for legacy/SegWit, BIP-322 for Taproot), which unlocks a per-address privacy toggle and notification target; no account, no funds moved | no (no per-address owner controls) | no — per-address pages are public, the “settings” route is a no-op stub, and the Telegram/Discord subscribe is unauthenticated (anyone can subscribe to any address) | no (no per-address owner surface in the open release) |
| Device telemetry | Bitaxe / Antminer / Avalon / Whatsminer probes + mDNS | no | no | no |
| Energy & solar tracking | yes | no | no | no |
| Tests | 1201, gating every release in CI | one SHA-256 self-test; no pool-level tests | 63, not run in CI (workflows build/scan the image only) | Catch2 (12 files) + ASan/TSan/UBSan + fuzz harnesses, in CI on a monthly cron and manual dispatch rather than per-push |
| Releases | signed checksums; .deb / .rpm / AppImage / multi-arch Docker from CI, plus a manually built .dmg; reproducible + SBOM (no macOS or Windows CI runner since the forge move: the .dmg is built by hand per release, the Windows .msi is paused with the WiX packaging still maintained) | build from source (autotools); no tags, no in-repo packaging | build from source / Docker image from CI; no tags or releases | build from source; tags v0.2.0 and v.0.3.0 present, plus a release workflow |
| Mainnet track record | not yet — the project is young | many (hosted, since 2014) | yes (hosted) | hosted instance live on mainnet |
| License | AGPLv3 + commercial | GPLv3 | GPLv3 (UI repo: no license file) | GPLv3 |
Note on the IPC template source — no firstness claim
This row previously said that none of the compared pools carried a Bitcoin
Core IPC path. That is no longer true: as of the 2026-07-21 re-check,
ckpool ships an in-tree Cap’n Proto mining IPC implementation
(ipc/mining/mining.capnp, ipc/mining/mining_ipc.cpp) used for both block
notification and template generation, opt-in via the ipcmining and
ipctemplate config keys and falling back to getblocktemplate. That is
architecturally the same choice dvb-WarpPool made. public-pool and mkpool
still go through getblocktemplate only.
It is explicitly not a claim to be “first” or “fastest” with IPC.
Stratum Reference Implementation (SRI) was the first consumer of Core’s IPC
mining interface, and other projects outside this three-way comparison may
well use it too. Core’s IPC interface is itself experimental and has
broken its mining.capnp schema across releases, which is why dvb-WarpPool
keeps GBT+ZMQ as the default and ships IPC strictly opt-in. The latency
figures are our own measurements on our own hardware, not a cross-pool
benchmark.
When the others are the better pick
Honesty cuts both ways:
- ckpool — a minimal, battle-hardened C daemon with a decade of track record, if you’re comfortable with logfiles and a unix socket as your interface. It needs the least trust in young code.
- public-pool — the exact software behind public-pool.io, a familiar UI, and a large user base running the same commit.
- mkpool — if you want multi-coin solo mining (BTC, BCH, LTC, merge-mined DOGE, ZEC and more from one binary), fixed-difficulty ports, RPC-node failover, or a lean modern C++ engine, and you don’t need a built-in operator UI, device telemetry, or packaged/signed releases. It also now ships proxy, passthrough and redirector roles for scaling out across machines, and it’s already live on mainnet.
- dvb-WarpPool — if you run mixed home hardware (NerdMiner next to a Bitaxe next to an Avalon), want TLS / SV2 / notifications / energy tracking and a full operator UI without bolting on extra services, and value tested, signed, reproducible releases. Bitcoin-only by design.
See also
- Performance Benchmarks — measured numbers behind the claims, including the 1,000-miner load test
- Scaling Tiers — what this pool is and isn’t designed for
- Getting Started