208153bbee88cd5824eb87af5aae07ccef545b90
ckpool's share-rejection response sets the "error" field to a bare
JSON string ("Stale", "Above target", "Duplicate", ...). The
Stratum mining v1 spec, and every miner firmware that follows it,
expects that field to be a [code, message, traceback] array. AxeOS
parses with cJSON_GetArrayItem after a cJSON_IsArray check, sees a
string, falls back to "unknown error", and the rejection reason
disappears from the dashboard. Bassin / public-pool sends the
array form, which is why those rejections render as "stale" there.
Patch the JSON_ERR macro in stratifier.c to wrap the existing
share_errs[] string in json_pack("[isn]", ...) and add a small
share_err_code() helper mapping ckpool's enum to the standard
Slush stratum codes:
21 stale (SE_STALE, SE_INVALID_JOBID, SE_NTIME_INVALID)
22 duplicate (SE_DUPE)
23 low diff (SE_HIGH_DIFF)
24 unauthorized (SE_NO_USERNAME)
20 other (everything else)
All 14 JSON_ERR call sites in parse_submit pick this up
automatically — no other call site changes needed. Generated with
git diff against the pinned upstream commit so format is correct;
round-trip-tested with git apply --check.
Kamado Pool
A modern, feature-complete solo Bitcoin mining pool built on a patched fork of CKPool, with a real-time web dashboard and a Go-based API middleware that surfaces everything CKPool knows.
Why Kamado?
Existing CKPool-based solutions (like Bassin for Umbrel) read only a handful of periodic stats files and miss most of CKPool's rich data. Kamado talks directly to CKPool's Unix socket API to expose:
- Real-time per-client data: hashrate, difficulty, user agent, hardware detection
- Full block-found history with height, hash, reward, and solving worker
- Per-worker and per-client best share tracking (current + all-time)
- Network difficulty, pool efficiency, expected time to block
- Live dashboard updates via WebSocket (no 60-second file polls)
Architecture
┌────────────────────────────────────────────────────┐
│ ckpool-solo (C) ──Unix socket──► kamado-api (Go) │
│ ports: 3333 ports: 80 │
│ │
│ ▲ stratum ▲ HTTP/WS │
│ │ │ │
│ Miners Browser │
│ │
│ bitcoind ◄──── RPC + ZMQ ────── ckpool + kamado-api│
└────────────────────────────────────────────────────┘
Three main components:
| Component | Language | Purpose |
|---|---|---|
ckpool/ |
C | Stratum server, share validation, block submission |
api/ |
Go | Socket client, REST/WebSocket API, persistence |
ui/ |
Svelte | Real-time dashboard |
Phases
- Phase 1 — Fork & fix CKPool, build infrastructure
- [~] Phase 2 — Go API middleware
- Phase 2a: CKPool socket client, bitcoind RPC, state aggregator, REST API
- Phase 2b: CKPool log tailer, block history, stdlib WebSocket push
- Phase 2b.5: ZMQ block notifier, SQLite persistence (deferred until s9pk repo exists — need real Go build env for new deps)
- ckpool patch 0001: expose
besteverin runtime socket JSON so the UI can show "this round" and "all-time" best share side by side - [~] Phase 3 — Svelte UI dashboard (skeleton: header, pool overview, miners table, blocks, best shares leaderboard; live WS updates)
- Phase 4 — Monorepo Docker build:
kamado-apiembedsui/distvia//go:embedand serves it at/. The api Dockerfile has a node stage that builds the UI before the Go stage embeds and builds the binary; docker-compose uses the repo root as build context so bothapi/andui/are visible. - Phase 5 — Testing (regtest, testnet4), polish
Quick start (dev)
cp .env.example .env # set POOL_BTCADDRESS and bitcoind creds
make up # build + start ckpool + api
curl localhost:8080/api/health
curl localhost:8080/api/pool
REST endpoints:
| Route | Returns |
|---|---|
GET /api/health |
CKPool + bitcoind health |
GET /api/pool |
Pool stats + derived hashrate windows + chain info |
GET /api/users |
All users from users socket command |
GET /api/workers |
All workers from workers socket command |
GET /api/clients |
All connected stratum sessions (useragent, IP, diff) |
GET /api/blocks |
Recent solved blocks (in-memory ring, SQLite in Phase 2b.5) |
GET /api/snapshot |
Full merged snapshot (everything) |
GET /api/ws |
WebSocket push: full snapshot on every refresh + on solve |
StartOS packaging lives in a separate repository.
Upstream
CKPool by Con Kolivas: https://bitbucket.org/ckolivas/ckpool
Pinned commit: see ckpool/CKPOOL_COMMIT
License
GPL-3.0. CKPool itself is distributed under GPL-3.
Languages
Go
46.7%
Svelte
36.4%
Shell
9.2%
TypeScript
4.7%
Dockerfile
1.4%
Other
1.5%