Commit Graph
55 Commits
Author SHA1 Message Date
satoshi d37a23bc57 Phase 3: Svelte 5 UI skeleton
Svelte 5 + Vite + TypeScript dashboard that consumes kamado-api over
REST for the first paint and then subscribes to /api/ws for live
updates. Zero runtime deps beyond svelte itself; plain CSS, no
component library.

Layout:

- Header with brand, WebSocket status badge, chain + height
- PoolOverview: hashrate (1m/5m/1h/24h), miner count, network
  hashrate + diff, pool share (ppb), expected time to block, uptime
- BlocksTable: recent solves from the in-memory ring (will be
  SQLite-backed in Phase 2b.5)
- BestShares: top-10 workers by bestever, falling back to bestdiff
  when the ckpool patch isn't present
- MinersTable: joined view of stratum clients and workers with
  user-agent-based hardware detection (Bitaxe, NerdQAxe, Antminer,
  ...), hashrate, best-round, best-ever, last share

State is a single $state() snapshot store in svelte-runes form;
components read from it via $derived. The store does one initial
REST snapshot fetch, then owns the WebSocket with exponential
backoff reconnects.

Vite dev server on :5173 proxies /api and /api/ws to localhost:8080
so you can run `make ui-dev` alongside `make up` in development.
Production serving (bundled into the Go binary via embed, behind /
on :8080) lands in Phase 4.
2026-04-13 03:07:59 +03:00
satoshi 36c08647e2 ckpool: expose bestever in runtime socket JSON
Upstream ckpool tracks user/worker best_ever across block solves but
only emits it in the on-disk users.json/workers.json persistence files,
not in the runtime socket API (userinfo() / workerinfo() in
stratifier.c). Consumers that poll the socket — like kamado-api — see
bestdiff reset to zero on every block solve via reset_bestshares()
with no all-time field to fall back on. That is the "best share stuck
at zero after a block" UX we want to fix in Kamado.

0001-expose-bestever-in-runtime-json.patch adds bestever to the two
JSON_CPACK calls so the UI can show current-round and all-time side
by side. No behavioral change, no impact on share validation or block
handling. Candidate for upstreaming.

Also surfaces BestEver in api/internal/ckpool types (User, Worker).
Gracefully degrades to 0 on an unpatched ckpool.
2026-04-13 03:03:21 +03:00
satoshi 0a40b8f84f Phase 2b: log tailer, block history, stdlib WebSocket push
Adds real-time block detection via ckpool log tailing and a push
channel for the upcoming Svelte UI, all stdlib-only:

- logmon.Tailer follows ckpool.log with rotation/truncation survival
  (inode + size tracking) and parses "Solved and confirmed block N"
  into BlockEvent values.
- state.Aggregator grows a 256-entry block ring, an OnRefresh hook,
  and IngestBlockEvents which best-effort enriches events with the
  block hash via bitcoind getblockhash.
- httpapi.Hub implements RFC 6455 from scratch (SHA1 handshake,
  unmasked text frames out, masked frames in, ping keepalive,
  per-client write mutex, slow-client drop) so we don't pull in a
  ws dependency before we can go mod tidy.
- New routes: GET /api/blocks and GET /api/ws. Snapshot pushes fire
  on every poll tick and immediately on block-solve.

ZMQ hashblock subscription and SQLite persistence are deferred to
Phase 2b.5 once the s9pk packaging repo exists and we have a real
build environment for adding Go deps.
2026-04-13 02:53:27 +03:00
satoshiandClaude Opus 4.6 bd0b1b0318 Phase 2a: kamado-api Go middleware (core MVP)
Go 1.22 module that polls CKPool's Unix socket control API, queries
Bitcoin Core over JSON-RPC, merges both into a thread-safe snapshot, and
serves it over REST. Layout:

  api/
  ├── cmd/kamado-api/main.go              signal-aware entrypoint
  └── internal/
      ├── config/       env var loader with validation
      ├── ckpool/       socket client (4-byte LE length-prefixed wire
      │                 protocol verified against libckpool.c), typed
      │                 response models for poolstats/users/workers/
      │                 clients/uptime, + unit tests using a fake
      │                 unix socket server
      ├── bitcoind/     minimal JSON-RPC client, getblockchaininfo
      │                 and getnetworkhashps
      ├── state/        Aggregator that refreshes a merged Snapshot
      │                 on a ticker; readers get a copy under RWMutex
      └── httpapi/      REST handlers on Go 1.22 ServeMux:
                        /api/health /api/pool /api/users
                        /api/workers /api/clients /api/snapshot

CKPool stores hashrate as "dsps" (diff shares per second); we convert
to H/s via the 2^32 constant used by GoBrrr-Pool and other clients.
Every stat CKPool exposes to its socket API is surfaced — useragent,
IP, per-client diff, per-worker best diff — closing the gap against
Bassin which only reads the 60-second stats files.

Dockerfile does a CGO_ENABLED=0 static build on golang:1.22-bookworm
with -trimpath -ldflags=-s -w. docker-compose now runs both ckpool and
kamado-api, sharing a named volume for /run/ckpool so the API can
dial the stratifier socket directly.

Deferred to Phase 2b (called out in README):
  - Bitcoin Core ZMQ hashblock subscriber
  - WebSocket push for real-time UI updates
  - SQLite persistence (block history, best-share history)
  - CKPool log tailer for "Solved and confirmed block" detection

Tests and build NOT run in this commit — Go isn't installed in the
dev environment. Run `make api-test` or `make api` to verify.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-12 19:52:27 +03:00
satoshiandClaude Opus 4.6 d48035b366 Phase 1: CKPool build infrastructure
Forks CKPool-solo at upstream commit cfb0f83b (v1.0) via a multi-stage
Docker build, with an env-driven entrypoint that renders ckpool.conf from
a template. The pinned commit already includes every fix referenced in
Bassin issue #29 (workbase_id double increment, extended low-power
timeouts, configurable dropidle, vardiff burst handling).

No patches are applied yet — the patches/ directory holds the workflow
and build wiring so Kamado-specific patches can be added incrementally.

Build is portable across aarch64/x86_64: yasm is intentionally omitted
so CKPool falls back to its C SHA256, and CFLAGS override drops upstream's
default -march=native. Runtime image ships ckpool and ckpmsg for socket
debugging; share logging (-L) is enabled by default.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-12 19:41:13 +03:00