The CKPool fork built for Bitcoin Cash solo mining — native CashAddr, per-address on-chain payouts, a configurable operator fee, sub-100 ms multi-node failover, and out-of-the-box NiceHash / MiningRigRentals compatibility.
Running in production at blocksniper.ai · stratum+tcp://solo.blocksniper.ai:3333
Same fork, same maintainer, same repository, same stratum endpoint. Only the name changed. Existing
elopool.cloudcoinbase tags in historical blocks refer to this software.
If you are searching for CKPool for Bitcoin Cash, BCH pool software, or a BCH stratum server you can actually put real money behind — this is it. Upstream CKPool is excellent Bitcoin software, but it is Bitcoin software: it does not understand CashAddr, it has no operator fee mechanism, its node failover takes seconds, and rental services trip over its difficulty handling.
BlockSniper.ai is a heavily modified BCH-only fork that fixes all four, and has 66 blocks found on BCH mainnet to show for it.
| You want to… | Stock CKPool | BlockSniper.ai |
|---|---|---|
Let miners use a bitcoincash:q… address as their username |
❌ Rejected | ✅ Native CashAddr, all prefixes |
| Pay every miner on-chain, directly, in the block they found | ❌ | ✅ Per-address dual-output coinbase |
| Take a pool fee without hacking the source | ❌ Donation code only | ✅ poolfee, 0–50%, configurable |
| Survive a node restart without dropping miners | ✅ <100 ms, sync-aware | |
| Accept NiceHash / MiningRigRentals hashrate | ✅ Auto-detected by useragent | |
| Brand your own coinbase tag | ❌ Hardcoded ckpool |
✅ btcsig, up to 38 bytes |
Keywords: bitcoin cash mining pool software · BCH stratum server · ckpool fork · solo mining BCH · CashAddr pool · bitcoin cash solo pool · ASIC mining pool · Bitaxe BCH.
Solo Mode (-B): The pool now supports mining directly to your personal BCH address. Each miner is paid on-chain automatically when they find a block, receiving their share minus the pool operator fee.
Simply use your BCH address as your mining username:
# CashAddr format (with prefix) - recommended
./cgminer -o stratum+tcp://pool:3333 -u bitcoincash:qr95sy3j9xwd2ap32xkykttr4cvcu7as4y0qverfuy -p x
# CashAddr format (without prefix)
./cgminer -o stratum+tcp://pool:3333 -u qr95sy3j9xwd2ap32xkykttr4cvcu7as4y0qverfuy -p x
# Legacy Base58 format
./cgminer -o stratum+tcp://pool:3333 -u 1A1z7agoat8Bt8ZVUUxkKvWAWgHtdNi3nn -p x
# Multi-worker mode (add `.workername` or `_workername` suffix)
./cgminer -o stratum+tcp://pool:3333 -u bitcoincash:qr95sy3j9xwd2ap32xkykttr4cvcu7as4y0qverfuy.rig01 -p xWhen you find a block:
- 98% goes to your on-chain address automatically
- 2% (configurable 0–50%) goes to the pool operator as fee
The pool creates a dual-output coinbase transaction splitting the block reward. All outputs sum to the full block reward; if the fee would be dust (<546 sats), the fee output is omitted.
- Non-address username (e.g.,
rig01,miner1): You mine for the pool's own address (bchaddressconfig) but keep all rewards - Invalid address (bad checksum/wrong network): You're rejected immediately with the message "Invalid BCH address (bad checksum or wrong network) - check your username for typos" — this protects you from accidentally donating a block to a mistyped address
The pool automatically detects your network (mainnet/testnet/regtest) from the BCH node and validates addresses accordingly. CashAddr prefixes must match the network:
bitcoincash:addresses → mainnetbchtest:addresses → testnetbchreg:addresses → regtest
This is not just a simple fork. BlockSniper.ai has been extensively modified for Bitcoin Cash:
| Feature | Original CKPool | BlockSniper.ai |
|---|---|---|
| CashAddr Support | ❌ None | ✅ Native implementation |
| Pool Fee System | ❌ Donation only | ✅ Configurable dual-output |
| Node Failover | ❌ Slow (40+ failures) | ✅ Instant (<100ms) |
| Sync-Aware Failover | ❌ No | ✅ Stays on backup during sync |
| Difficulty Management | Basic vardiff | 3 methods: Password, Useragent, Pattern |
| Password Difficulty | ❌ Not supported | ✅ -p d=X or -p diff=X |
| Rental Detection | ❌ Manual config | ✅ Auto-detect via useragent |
| NiceHash Support | ❌ Issues | ✅ Full compatibility |
| MiningRigRentals | ❌ Issues | ✅ Full compatibility |
| Share Validation | Rejects below target | Only rejects below mindiff |
| BCH Optimizations | ❌ BTC focused | ✅ BCH specific |
| Coinbase Message | Hardcoded "ckpool" | Fully configurable |
| ZMQ Support | Limited | Multi-node redundancy |
- 66 Blocks mined on BCH mainnet - Proven reliability in production
- Successfully mining on BCH mainnet since 2025
- Battle-tested with real ASIC hardware (Bitaxe, rental services)
- Zero share rejections - Smart validation accepts all valid work
- Native CashAddr working - Proven with millions of shares
- Pool fees working - Automatic 98/2% split in every block
- Ultra-low overhead massively scalable multi-process, multi-threaded architecture
- Multiple deployment modes: Pool, Solo, Proxy, Passthrough, Node
- Seamless restarts with socket handover for zero-downtime upgrades
- ASICBoost support for improved mining efficiency
- Advanced vardiff algorithm with stable high-difficulty handling
- Automatic fee distribution in coinbase transaction
- Dual-output coinbase splitting (miner + pool operator)
- Configurable percentage (0.0% - 100.0%)
- Testnet Verified: Blocks 1677558 (1% fee), 1677572 (2% fee)
- Clean implementation without donation code
- Full Documentation
- Full Bitcoin Cash address format support
- Zero external dependencies (pure C implementation)
- Supports all BCH prefixes:
bitcoincash:(mainnet)bchtest:(testnet)bchreg:(regtest)
- Backwards compatible with legacy Base58 addresses
- Production Proven: Successfully mining on mainnet and testnet
Three Methods of Difficulty Control (Priority Order):
- Set difficulty via password field:
-p d=500000or-p diff=1000000 - Both formats supported:
d=(short) anddiff=(long) - Overrides ALL other difficulty settings
- Applied immediately upon authorization
- Perfect for individual miner control
- Testnet verified: Successfully tested with
d=41245on Bitaxe - Examples:
# Short format (tested & working) ./bfgminer -o stratum+tcp://pool:3333 -u wallet.worker -p d=500000 # Long format (also supported) ./cgminer -o stratum+tcp://pool:3333 -u wallet.worker -p diff=1000000
- Automatically detects rental services from mining.subscribe
- No special configuration needed by miners!
- Applied immediately during connection
- Supported services:
- NiceHash: Detects
"NiceHashMiner"in useragent → 500k diff - MiningRigRentals: Detects
"MiningRigRentals"→ 1M diff
- NiceHash: Detects
- Works exactly like AsicSteer and other modern pools
- Configure patterns in
mindiff_overrides:"mindiff_overrides": { "nicehash": 500000, // Matches: wallet.nicehash_rig1 "MiningRigRentals": 1000000, // Matches: wallet.MiningRigRentals_xyz "bitaxe": 100, // Matches: wallet.bitaxe_home "high": 2000000 // Matches: wallet.high_performance }
- Case-insensitive substring matching
- Applied during worker authorization
- Useful for custom miner groups
"nicehash" (8 chars), "high" (4 chars), "test123" (7 chars)
- ❌ Avoid: "hi" (2 chars), "rig" (contains i), "old" (contains o)
- Instant failover - Switches to backup on first RPC failure (~100ms)
- Intelligent node selection - Prefers primary, automatically fails back when recovered
- Sync-aware - Stays on backup while primary node is syncing/loading
- Zero mining downtime - Continuous operation during node maintenance
- Multi-node ZMQ - Receives block notifications from all nodes
- Production proven - Handles node restarts gracefully
Failover Performance:
- Old behavior: 40+ failed attempts before failover (4+ seconds)
- New behavior: 1 failed attempt, instant failover (<100ms)
- Automatic recovery detection every 5 seconds
- Seamless failback when primary node is ready
- Complete control via
btcsigparameter - No hardcoded "ckpool" text
- Pool operators have full branding flexibility
- Supports up to 38 bytes of custom text
- SegWit code completely removed
- Optimized for ASIC miners (default 500k+ difficulty)
- BCH-specific block validation
- Proper ASERT DAA handling
- Operating System: Ubuntu 18.04+ or Debian 10+
- Dependencies:
- Build tools:
build-essential autoconf automake libtool - Libraries:
libssl-dev libjansson-dev libzmq3-dev
- Build tools:
- Bitcoin Cash Node: One or more BCH full nodes with RPC and ZMQ enabled
# 1. Clone the repository
git clone https://github.com/skaisser/ckpool.git
cd ckpool
# 2. Install dependencies and build
./install-ckpool.sh
# 3. Configure your pool settings
nano ~/ckpool/ckpool.conf
# Edit: bchaddress, pooladdress, poolfee, btcd credentials
# 4. Set up systemd service and firewall (requires sudo)
sudo ./post-install.shWhat each script does:
install-ckpool.sh- Checks dependencies, builds CKPool, creates configspost-install.sh- Creates systemd service, configures firewall, enables auto-start
# Clone the repository
git clone https://github.com/skaisser/ckpool.git
cd ckpool
# Build and install
./autogen.sh
./configure
make
sudo make installNote: Manual install does not create systemd service or configure firewall. You'll need to run post-install.sh separately or manage the service manually.
{
"bchaddress": "bitcoincash:qqqupxkkrjew738czfzpz5e33sej6wm9zqdquq0aze", // Miner receives 98%
"pooladdress": "bitcoincash:qregedwmg8tr2ymnp8j6f0tesuj4r9lqnqjfmlvj6w", // Pool receives 2%
"poolfee": 2.0 // 2% pool fee (configurable 0-50, must include decimal)
}Note: The config key btcaddress is deprecated. Use bchaddress (same functionality, BCH-specific naming).
This creates a dual-output coinbase transaction automatically splitting the block reward. See Pool Fee Details for the complete mechanics (rounding, dust handling, verification).
The btcsig parameter controls the entire coinbase message that appears in mined blocks. There is no hardcoded text - whatever you set in btcsig is exactly what will appear in the blockchain.
Examples:
"btcsig": "MyPool.com"→ Coinbase shows:MyPool.com"btcsig": "PoolName/[Solo]"→ Coinbase shows:PoolName/[Solo]"btcsig": "/[Solo]"→ Coinbase shows:/[Solo]"btcsig": ""→ No coinbase message
"mindiff_overrides": {
"nicehash": 500000, // Auto-detected via useragent OR worker name
"NiceHash": 500000, // Alternative capitalization
"MiningRigRentals": 1000000, // Auto-detected via useragent OR worker name
"miningrigrentals": 1000000 // Alternative capitalization
}Note: Rental services are automatically detected via useragent. The mindiff_overrides values are used as the difficulty to apply when detected.
"mindiff_overrides": {
"bitaxe": 100, // Low-power miners
"s19": 1000000, // Antminer S19 rigs
"high": 5000000, // High-performance farms
"stratum-proxy": 10000 // Proxy connections
}# Set specific difficulty via password
./cgminer -o stratum+tcp://pool:3333 -u BCH_ADDRESS.worker -p d=500000
# Or using long format
./bfgminer -o stratum+tcp://pool:3333 -u BCH_ADDRESS.worker -p diff=1000000
# Combine with other password options
./cgminer -o stratum+tcp://pool:3333 -u BCH_ADDRESS.worker -p d=500000,stats{
"btcd": [{
"url": "127.0.0.1:8332",
"auth": "rpcuser",
"pass": "rpcpassword",
"notify": true,
"zmqnotify": "tcp://127.0.0.1:28333"
}],
"bchaddress": "bitcoincash:qqqupxkkrjew738czfzpz5e33sej6wm9zqdquq0aze", // Main mining address (solo mode fallback)
"pooladdress": "bitcoincash:qregedwmg8tr2ymnp8j6f0tesuj4r9lqnqjfmlvj6w", // Pool fee address
"poolfee": 2.0, // 2% pool fee (configurable 0-50)
"btcsig": "YourPool.com", // Your pool branding
"blockpoll": 50,
"update_interval": 15,
"serverurl": ["0.0.0.0:3333"],
"mindiff": 500000, // ASIC optimized
"startdiff": 500000,
"maxdiff": 1000000,
"mindiff_overrides": { // Per-pattern difficulty
"nicehash": 500000,
"MiningRigRentals": 1000000
}
}Why Multi-Node?
- Zero downtime during node maintenance or updates
- Instant failover on node failure (<100ms switching time)
- Automatic recovery when primary node comes back online
- Production-grade reliability - no single point of failure
{
"btcd": [
{
"url": "10.0.1.10:8332", // Primary node
"auth": "rpcuser",
"pass": "rpcpassword",
"notify": true,
"zmqnotify": "tcp://10.0.1.10:28333"
},
{
"url": "10.0.1.11:8332", // Backup node
"auth": "rpcuser",
"pass": "rpcpassword",
"notify": true,
"zmqnotify": "tcp://10.0.1.11:28333"
}
],
"bchaddress": "bitcoincash:qqqupxkkrjew738czfzpz5e33sej6wm9zqdquq0aze",
"pooladdress": "bitcoincash:qregedwmg8tr2ymnp8j6f0tesuj4r9lqnqjfmlvj6w",
"poolfee": 2.0,
"btcsig": "BlockSniper.ai",
"mindiff": 500000,
"startdiff": 500000,
"maxdiff": 1000000,
"asicboost": true,
"version_mask": "1fffe000"
}Node Priority:
- First node in array = Primary (always preferred when available)
- Subsequent nodes = Backup (used during primary failure/maintenance)
- Pool automatically fails back to primary when it recovers
Example Failover Behavior:
# Startup - Both nodes detected
[18:24:02.087] Connected to bitcoind: 10.12.112.3:8332
[18:24:02.088] Server alive: 10.12.112.3:8332
[18:24:02.090] Server alive: 10.12.112.4:8332
# Primary node goes down - Instant failover (1 failure, <100ms)
[18:25:27.454] Unable to connect socket to 10.12.112.3:8332
[18:25:27.454] Failed to get best block hash from 10.12.112.3:8332
[18:25:27.454] Failed over to bitcoind: 10.12.112.4:8332 ← INSTANT
# Mining continues on backup without interruption
[18:25:32.151] Stored local workbase with 24 transactions
# Primary comes back but still syncing - Pool stays on backup
[18:26:07.112] "Loading block index..." (node not ready yet)
[18:26:07.112] 10.12.112.3:8332 Failed to get valid json response
# Primary fully synced - Automatic failback (5 seconds later)
[18:26:12.114] Server alive: 10.12.112.3:8332
[18:26:12.115] Failed over to bitcoind: 10.12.112.3:8332 ← Back to primary
# Continues mining on primary
[18:26:32.453] Stored local workbase with 29 transactions
Key Behaviors:
- ✅ Single failure triggers failover (not 40+ like before)
- ✅ Stays on backup during primary sync (sync-aware)
- ✅ Automatic failback when ready (intelligent recovery)
- ✅ Zero share loss during failover
- ✅ Miners never disconnected (seamless transition)
- ✅ Password-based difficulty: Tested & working in production
- ✅ Useragent detection: Tested & working with NiceHash
- ✅ Pattern matching: Tested & working in production
Important
Keep your stratum port below 4000. Any port above 4000 is silently treated
as a "highdiff" port (src/connector.c): every client on it is handed
highdiff — 1,000,000 by default — which overrides startdiff,
mindiff and your mindiff_overrides entirely. Rented hashrate then submits
far too few shares, the buyer's hashrate estimate goes ragged, and you see red
deltas and apparent drops with nothing wrong in the logs. The default 3333 is
fine; 3334 is fine; 8888 is not.
Also consider setting maxdiff to a real ceiling instead of the shipped
0 (unlimited). With no cap, vardiff can climb until the share rate is too
sparse for a rental service to measure your hashrate steadily.
Just add to your config:
{
"mindiff_overrides": {
"nicehash": 500000,
"NiceHash": 500000,
"MiningRigRentals": 1000000,
"miningrigrentals": 1000000
}
}That's it! The pool will automatically detect and apply correct difficulty.
All miners connect the same way using their own BCH address as the username. Blocks are mined directly to the miner's address:
# Basic setup (uses default difficulty)
./cgminer -o stratum+tcp://POOL_IP:3333 -u bitcoincash:qr95sy3j9xwd2ap32xkykttr4cvcu7as4y0qverfuy -p x
# Set custom difficulty via password
./cgminer -o stratum+tcp://POOL_IP:3333 -u bitcoincash:qr95sy3j9xwd2ap32xkykttr4cvcu7as4y0qverfuy -p d=500000
# Multi-worker setup
./cgminer -o stratum+tcp://POOL_IP:3333 -u bitcoincash:qr95sy3j9xwd2ap32xkykttr4cvcu7as4y0qverfuy.rig01 -p xWhen you find a block:
- 98% auto-pays to your address on-chain
- 2% (configurable) pays to the pool operator fee address
- Payment is automatic and non-custodial
If renting hashrate to this pool:
- Add pool:
stratum+tcp://POOL_IP:3333 - Use your BCH address as the username (same as solo miners)
- Auto-detection: Pool automatically detects NiceHash/MRR from useragent and applies appropriate difficulty
- NiceHash: 500k difficulty
- MiningRigRentals: 1M difficulty
- You can override with password:
-p d=1000000 - Note: Ensure pool's
maxdiffis 0 or > rental service difficulty
# RPC Settings
rpcuser=yourusername
rpcpassword=yourpassword
rpcallowip=10.0.0.0/8
rpcbind=0.0.0.0
# ZMQ Settings (Required for fast block detection)
zmqpubhashblock=tcp://0.0.0.0:28333
# Mining Optimizations
maxmempool=2000
dbcache=4096# On BCH nodes - allow ZMQ connections
sudo ufw allow 28333/tcp comment 'ZMQ block notifications'
sudo ufw allow from POOL_SERVER_IP to any port 8332 comment 'BCH RPC'
# On pool server - allow miner connections
sudo ufw allow 3333/tcp comment 'Stratum mining port'After running post-install.sh, manage the pool as a system service:
# Start the pool
sudo systemctl start ckpool
# Stop the pool
sudo systemctl stop ckpool
# Restart the pool
sudo systemctl restart ckpool
# Check status
sudo systemctl status ckpool
# View live logs
sudo journalctl -u ckpool -f
# Enable auto-start on boot
sudo systemctl enable ckpool
# Disable auto-start
sudo systemctl disable ckpoolTestnet Service:
# Same commands but replace 'ckpool' with 'ckpool-testnet'
sudo systemctl start ckpool-testnet
sudo journalctl -u ckpool-testnet -f# Start the pool
cd ~/ckpool
./start-ckpool.sh
# Stop the pool
./stop-ckpool.sh
# View logs
tail -f ~/ckpool/logs/ckpool.logTo activate solo mode mining where each miner is paid directly on-chain:
# Edit your ckpool.conf
nano ~/ckpool/ckpool.confSet these keys:
"bchaddress"- fallback address for non-address usernames (miners should use their own BCH address as username)"pooladdress"- your pool operator fee address (receives the configured poolfee %)"poolfee"- fee percentage (e.g., 2.0 for 2%; configurable 0–50)
Add -B flag to your pool start command. For systemd service:
# Edit the service file
sudo nano /etc/systemd/system/ckpool.serviceUpdate the ExecStart line to include -B:
ExecStart=/home/user/ckpool/ckpool -c /home/user/ckpool/ckpool.conf -L -B
# Reload systemd and restart
sudo systemctl daemon-reload
sudo systemctl restart ckpool
# Verify it's running
sudo systemctl status ckpoolExisting miners with plain usernames (e.g., rig01) continue mining:
- They automatically mine for your
bchaddresspool fallback - No action needed until they want individual payouts
Miners can opt-in to solo mode by using their own BCH address as username:
./cgminer -o stratum+tcp://pool:3333 -u bitcoincash:qr95sy3j9xwd2ap32xkykttr4cvcu7as4y0qverfuy -p x# Pool statistics
printf 'stats\n' | ./ckpmsg -s /tmp -n ckpool -N stratifier
# User information
printf 'users\n' | ./ckpmsg -s /tmp -n ckpool -N stratifier
# Worker details
printf 'workers\n' | ./ckpmsg -s /tmp -n ckpool -N stratifier
# View logs (systemd)
sudo journalctl -u ckpool -f --lines=100
# View logs (manual)
tail -f ~/ckpool/logs/ckpool.logTwo layers of tests ship with the pool. Run both before you point real hashrate at a build.
Built and run by the standard autotools target:
./autogen.sh && ./configure && make
make check| Test | Covers |
|---|---|
test/sha256 |
SHA-256 primitives used by block hashing |
test/cashaddr |
CashAddr encode/decode, checksum, prefix and case handling |
test/addrclassify |
Address classification across mainnet / testnet / regtest, legacy Base58 and CashAddr |
testing/regtest-e2e.sh is the test that actually proves your build pays the right
addresses. It spins up a throwaway bitcoind -regtest node, builds and starts
src/ckpool -B against it, drives the bundled CPU miner plus raw stratum probes through
every auth and payout scenario, and asserts each resulting coinbase against the expected
split.
./testing/regtest-e2e.sh
# exit 0 = every assertion passed
# exit 1 = an assertion FAILed
# exit 2 = missing prerequisites (nothing was started)| Scenario | What it proves |
|---|---|
| 1 | Prefixed CashAddr username pays that address, fee split applied |
| 2 | Bare (prefixless) CashAddr username resolves and pays identically |
| 3 | Legacy Base58 address username pays that address |
| 4 | Non-address username falls back to the pool's own bchaddress |
| 5 | Typo'd CashAddr is rejected with the explicit error, no work served |
| 5b | Typo'd legacy address is rejected, never silently redirected to the pool |
| 6 | UPPERCASE bare CashAddr normalizes to the same user account |
| 7 | Multiple workers under one address aggregate to a single payout |
Important
The e2e script must run on Linux. src/ckpool links against <sys/epoll.h> so it
does not build on macOS/BSD, and the bundled testing/minerd is a Linux ELF binary.
Run it on the pool server, not on your laptop.
.github/workflows/release-gate.yml runs the whole gate — build, make check, and the
full regtest money gate — on GitHub Actions.
It fires only on release tags (v*) and on manual dispatch, never on pushes to
master or homolog, so ordinary merges stay fast and the expensive end-to-end run
happens exactly when it matters: before a release is published.
No external BCH node is needed. regtest is a self-contained private chain that generates its own blocks, so the workflow downloads a pinned Bitcoin Cash Node binary and runs the real money path against a throwaway node inside the runner. On failure it preserves the ckpool log and configs as a downloadable artifact.
To run it by hand against a different node version, use Actions → Release gate → Run
workflow and set the bchn_version input.
-
Check if ZMQ is enabled on BCH node:
bitcoin-cli getzmqnotifications
-
Test ZMQ connectivity:
./test-zmq-connection.sh
-
Verify firewall rules:
sudo ufw status | grep 28333
# Fix buffer size warnings
sudo ./tune-system.sh
# Increase system limits
ulimit -n 1048576CKPool uses Unix sockets for administration. For read-only HTTP access suitable for dashboards, see the Go log API under api/.
# Pool statistics
printf 'stats\n' | ./ckpmsg -s /tmp -n ckpool -N stratifier
# User information
printf 'users\n' | ./ckpmsg -s /tmp -n ckpool -N stratifier
# Worker details
printf 'workers\n' | ./ckpmsg -s /tmp -n ckpool -N stratifier
# Change log level
printf 'loglevel=debug\n' | ./ckpmsg -s /tmp -n ckpool -N pool┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ BCH Node 1 │ │ BCH Node 2 │ │ BCH Node N │
│ RPC:8332 │ │ RPC:8332 │ │ RPC:8332 │
│ ZMQ:28333 │ │ ZMQ:28333 │ │ ZMQ:28333 │
└──────┬──────┘ └──────┬──────┘ └──────┬──────┘
│ │ │
└───────────────────┴───────────────────┘
│
┌──────┴──────┐
│ CKPool │
│ Generator │ ← Block Templates
│ Stratifier │ ← Share Validation
│ Connector │ ← Client Connections
└──────┬──────┘
│
┌──────┴──────┐
│ Port 3333 │
└──────┬──────┘
│
┌─────────────────┼─────────────────┐
│ │ │
┌────┴────┐ ┌────┴────┐ ┌────┴────┐
│ ASIC 1 │ │ ASIC 2 │ │ ASIC N │
└─────────┘ └─────────┘ └─────────┘
- Block 1677517: First CashAddr block
- Block 1677523: Confirmed CashAddr working
- Block 1677558: 1% pool fee distribution verified
- Block 1677572: 2% pool fee distribution verified
- 10+ additional blocks: Continuous stable operation
- ✅ CashAddr format (
bchtest:addresses) - ✅ Pool fee splitting (dual-output coinbase)
- ✅ Custom coinbase messages
- ✅ Password-based difficulty (
-p d=41245tested with Bitaxe) - ✅ Low difficulty for Bitaxe miners
- ✅ Stable operation over extended periods
Full history lives in ChangeLog. Most recent release below.
The headline change: in solo mode (-B) every miner is now paid directly to their own
BCH address, on-chain, in the coinbase of the block they found. Your username is your
payout address.
Per-Address Solo Payouts
- ✨ Mine to your own address by using it as your stratum username — CashAddr (prefixed or bare), UPPERCASE CashAddr, or legacy Base58 all resolve to the same account
- ✨ Dual-output coinbase splits the reward between the finder and the pool operator
- ✨ Multi-worker support —
<address>.rig01/<address>_rig01aggregate under one payout - ✨ New
bchaddressconfig key names the pool's own payout address - 🔧 Operator fee configurable 0–50% via
poolfee, defaulting to 2%
Payout Safety
- 🔒 Fee percentage clamped, coinbase size bounded, and dust fee outputs (<546 sats) omitted so every output sums cleanly to the full block reward
- 🔒 Unified local address classifier shared by the validation and script-building paths, so an address can never validate one way and pay another
- 🔒 Strict CashAddr verification — checksum, prefix and case are all enforced
- ✨ Smart fallback: a genuinely non-address username mines to the pool's
bchaddress - ✨ Typo protection: an address-shaped username that fails validation is rejected outright with "Invalid BCH address (bad checksum or wrong network) — check your username for typos", instead of silently donating your block to the pool
- 🐛 Typo'd testnet/regtest legacy addresses are now caught by that same guard — the
shape check was mainnet-only, so they previously fell through to pool fallback. The
non-mainnet leading characters are gated on the detected network, so mainnet worker
names beginning with
m,nor2still authorise normally
Reliability
- 🐛 An invalid address no longer marks bitcoind dead during
checkaddr - 🐛 Rental-detected clients skip
mindiff_overridespattern matching - 🐛 Ported upstream diff-window, burst vardiff and stats crash fixes
BCH-Only Cleanup
- 🔥 Stripped the BTC donation path and remaining segwit leftovers
Testing
- 🧪 New
testing/regtest-e2e.shend-to-end money gate — eight scenarios asserting real coinbase outputs on a throwaway regtest node - 🧪 New
test/addrclassifyunit test covering address classification across all networks
Installed by
install-ckpool.sh. The installer builds the binary, generates a 32-byte API key at~/ckpool/api/ckpool-api.env(mode 0600), andpost-install.shadds the systemd unit and a firewall rule scoped to one address — the key is the only authentication and HTTP sends it in cleartext, so the port must never face the internet. Interfaces may still move ahead of a tagged release.
CKPool's own administration interface is a Unix domain socket driven by ckpmsg. That is the
right design for control commands, and the wrong one for a dashboard: it needs shell access on
the pool host, it is not concurrent, and anything that wants pool state ends up shelling out or
tailing logs by hand. The Python service that filled that gap did not hold up either.
ckpool-api replaces it with a single static Go binary that exposes ckpool's log tree over
authenticated, read-only HTTP:
| Property | How |
|---|---|
| Millisecond responses | Responses are cached 60 s in-process; a hit never touches the disk |
| Thousands of concurrent readers | Goroutine-per-request, no interpreter, no GIL, no worker pool to size |
| Zero dependencies | Go standard library only — no go.sum, no vendoring, one binary to scp |
| Safe by default | Bearer-token auth, 20 req/min/IP rate limit, and it is read-only — it never touches the control sockets |
| Ships with the parser it needs | It decodes coinbase layout defined in src/stratifier.c, so it lives in this repo and changes in the same commit |
GET /health liveness, log presence and size
GET /stats parsed pool stats — hashrate, workers, users
GET /tail?lines=N tail the main log (capped at 1000)
GET /grep?pattern= search the main log
GET /find-block?height=N locate a solved block with context
GET /user-log?user=&lines=N tail one miner's log
GET /user-file?user= one miner's full status file
GET /coinbase?user=NAME decode the coinbase this miner is working on
GET /metrics service-level countersReach it once installed:
KEY=$(sudo sed -n 's/^CKPOOL_API_KEY=//p' ~/ckpool/api/ckpool-api.env)
curl -H "Authorization: Bearer $KEY" http://127.0.0.1:8888/statsFull documentation: api/README.md · api/COINBASE_API.md
This software writes coinbase outputs — it decides where block rewards go. Every extra pair of eyes on the payout path makes it safer for everyone, so bug reports, regression cases, production logs and pull requests are genuinely welcome.
- Fork the repository and create a feature branch off
homolog - Test thoroughly —
make checkfor units,./testing/regtest-e2e.shfor the money path, then testnet before mainnet - Submit a pull request describing what you observed, not just what you changed
Especially valuable contributions:
| What | Why it helps |
|---|---|
| Payout-path bug reports | Every real-world edge case found is money someone doesn't lose |
| Regression test cases | A failing scenario added to testing/regtest-e2e.sh is worth more than a description of the bug |
| Production logs | Failover behaviour, vardiff under real ASICs, and rental-service quirks are hard to reproduce synthetically |
| Miner/hardware compatibility reports | Which ASICs, firmware and rental services work (or don't) with which settings |
Running a pool with real money on it? Validate end-to-end on regtest or testnet first —
testing/regtest-e2e.shexercises the full money path (coinbase splits, fee outputs, address classification, typo rejection) and is the fastest way to prove your build pays the addresses you expect.
This fork is free, GPLv3, and developed in the open. If it earned you a block — or saved you from losing one — a donation keeps the lights on and the development going.
| Coin | Address |
|---|---|
| 🪙 Bitcoin Cash (BCH) | bitcoincash:qq6avlec5l7769jhk5mk7rnsgz49wcx2kgxaklp9e8 |
| ₿ Bitcoin (BTC) | bc1q8ukjnlykdpzry9j72lf7ekmpnf2umna6jyxqhn |
| 🔷 Ethereum (ETH) | 0x79eb82Ee97Ce9D02534f7927F64C5BdC4F396301 |
| ☀️ Solana (SOL) | CcnuMRpNapWboQYEGw3KKfC3Eum5JWosZeC9ktGr2oyQ |
| 🐕 Dogecoin (DOGE) | DNU41AwyLba2rCzmjjr8SoYuzhjWkWTHpB |
Starring the repo and reporting what you find are worth just as much. 🙏
GNU General Public License v3. See COPYING for details.
- Original CKPool — Con Kolivas and the CKPool team, for the base architecture
- BlockSniper.ai development (published as EloPool.cloud until 2026)
- Native CashAddr implementation (2025)
- Pool operator fee system (2025)
- Multi-difficulty management (2025)
- Per-address solo mining (2026)
- Go log API (2026)
- BCH-specific optimisations
- Contributors — everyone who has reported a bug, sent a log, or opened a PR. Thank you.
- Issues: GitHub Issues — bug reports and findings welcome
- Pool: blocksniper.ai — the live pool running this software
- Documentation: Wiki
- Pool fee details: POOL_FEE.md
- Solo mining notes: README-SOLOMINING
- Go log API: api/README.md
- CKPool control interface: CKPOOL_API_GUIDE.md
BlockSniper.ai — open-source Bitcoin Cash mining pool and stratum server software. Native CashAddr · per-address solo payouts · sub-100 ms node failover.
blocksniper.ai · Report an issue · GPLv3