satoshi df0dbf89e5 Harden block-recording pipeline: P0 reliability fixes
Closes the silent-failure modes between "ckpool logs a solve" and
"block correctly displayed":

* Difficulty estimate matched mempool.space — the projection now uses
  (inEpoch + 1) intervals so it converges on Bitcoin Core's eventual
  retarget formula at end-of-epoch instead of undershooting by ~0.05–
  0.10 % throughout.

* Tailer resumes mid-log on restart — persists (inode, offset) to kv
  every EOF + on shutdown, and replays the unread tail next time. Any
  solve line written while kamado-api was down would previously be
  invisible forever.

* Background reconcile loop (60 s) retries hash/reward enrichment for
  blocks the original RPC missed, so a transient bitcoind-index race no
  longer permanently leaves a block hashless.

* Reorg detection: same loop compares each recent stored hash against
  getblockhash(height); a mismatch stamps orphaned_at. UI renders these
  strikethrough with a red "orphaned" tag instead of showing illusory
  rewards forever.

* InsertBlock now reports whether a row was actually inserted; the
  caller WARN-logs duplicate-height ignores so a re-mined orphaned
  height can't disappear silently.

* Submit-attempt vs confirmed counters surface failed submissions:
  every "Possible/Submitting block solve" log line increments
  block_submit_attempts; "Solved and confirmed" increments
  block_submits_confirmed. A growing gap means bitcoind is rejecting
  our submissions — previously invisible.

* share_err patch refreshed against pinned ckpool source: added
  SE_NO_JOBID -> 21 and SE_WORKER_MISMATCH -> 24 mappings, kept
  SE_INVALID_NONCE2 in 20 (it's a malformed-input error, not low-diff).
  AxeOS users now see actionable Stratum codes instead of
  "unknown error".

UI gets new orphaned_at + block_submit_attempts/confirmed fields on
the snapshot type and a strikethrough-with-tag rendering for orphaned
blocks in BlocksTable.
2026-04-27 16:30:15 +03:00
2026-04-12 19:41:13 +03:00

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 bestever in 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-api embeds ui/dist via //go:embed and 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 both api/ and ui/ 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.

S
Description
No description provided
Readme
640 KiB
Languages
Go 46.7%
Svelte 36.4%
Shell 9.2%
TypeScript 4.7%
Dockerfile 1.4%
Other 1.5%