Add share cards

This commit is contained in:
satoshi committed 2026-09-04 00:54:26 +03:00
1 parent ec42ce9b54
commit 4669bf10c0
51 files changed
+1193 -239

No files matched your search

+43 -43
View File
@@ -24,7 +24,7 @@ Kamado exists because existing CKPool wrappers like Bassin read only a handful o
| `api/` | Go | Socket client, bitcoind RPC, ZMQ subscriber, log tailer, state aggregator, REST + WebSocket API, SQLite persistence |
| `ui/` | Svelte 5 | Real-time dashboard with pool overview, miner stats, block history, best share tracking, transaction accelerator |
The Go binary embeds the built Svelte app via `//go:embed` and serves it at `/` — a single static binary with no external web server.
The Go binary embeds the built Svelte app via `//go:embed` and serves it at `/`, a single static binary with no external web server.
## Improvements Over Upstream CKPool
@@ -50,18 +50,18 @@ Nine patches are applied to upstream commit `cfb0f83` (which itself includes the
The Go API (`kamado-api`) bridges CKPool's Unix socket protocol, bitcoind's JSON-RPC, and ZMQ into a unified HTTP/WebSocket interface:
- **Socket client** — CKPool uses a 4-byte length-prefixed binary protocol on a Unix domain socket. kamado-api opens a fresh connection per request and queries pool, user, worker, and client state in real time.
- **State aggregator** — Merges socket responses, bitcoind chain info, ZMQ events, and log-tailed block solves into a single thread-safe snapshot, refreshed on a configurable interval.
- **ZMQ subscriber** — Listens to bitcoind's `hashblock` topic for sub-second block notifications, triggering an immediate state refresh. Falls back to RPC polling if ZMQ is unavailable.
- **Log tailer** — Watches CKPool's log file (inotify-based) for "Solved and confirmed block" lines, extracts height and hash, enriches via bitcoind RPC (reward, confirmations), and records to SQLite.
- **Block reconciliation** — On startup, cross-references in-memory blocks with the database and bitcoind to detect orphans and fill gaps.
- **Chain reorg detection** — Scoped to the active chain; clears stale state on tip changes.
- **SQLite persistence** — Blocks, accelerated transactions, and log cursor survive restarts. Non-fatal if unavailable (in-memory ring fallback).
- **Transaction accelerator** — Inspects the current block template to find the marginal (lowest fee-rate) transaction, calls `prioritisetransaction` to boost a target tx, and reports the displaced fee as revenue impact. Includes a hard cap (2000 sat/vB) and lifecycle cleanup.
- **Socket client**: CKPool uses a 4-byte length-prefixed binary protocol on a Unix domain socket. kamado-api opens a fresh connection per request and queries pool, user, worker, and client state in real time.
- **State aggregator**: Merges socket responses, bitcoind chain info, ZMQ events, and log-tailed block solves into a single thread-safe snapshot, refreshed on a configurable interval.
- **ZMQ subscriber**: Listens to bitcoind's `hashblock` topic for sub-second block notifications, triggering an immediate state refresh. Falls back to RPC polling if ZMQ is unavailable.
- **Log tailer**: Watches CKPool's log file (inotify-based) for "Solved and confirmed block" lines, extracts height and hash, enriches via bitcoind RPC (reward, confirmations), and records to SQLite.
- **Block reconciliation**: On startup, cross-references in-memory blocks with the database and bitcoind to detect orphans and fill gaps.
- **Chain reorg detection**: Scoped to the active chain; clears stale state on tip changes.
- **SQLite persistence**: Blocks, accelerated transactions, and log cursor survive restarts. Non-fatal if unavailable (in-memory ring fallback).
- **Transaction accelerator**: Inspects the current block template to find the marginal (lowest fee-rate) transaction, calls `prioritisetransaction` to boost a target tx, and reports the displaced fee as revenue impact. Includes a hard cap (2000 sat/vB) and lifecycle cleanup.
### Stratum TLS
Optional encrypted stratum via stunnel. CKPool binds a public plaintext socket plus one loopback-only socket per TLS certificate; stunnel terminates TLS on the external port and forwards decrypted traffic to the matching internal bind. CKPool tags each connection with its `serverurl` index, and the deployment declares what those indices mean via the `STRATUM_SERVERS` env — so the dashboard shows a lock icon next to encrypted miners and names the certificate in use on hover, with no source-IP heuristics.
Optional encrypted stratum via stunnel. CKPool binds a public plaintext socket plus one loopback-only socket per TLS certificate; stunnel terminates TLS on the external port and forwards decrypted traffic to the matching internal bind. CKPool tags each connection with its `serverurl` index, and the deployment declares what those indices mean via the `STRATUM_SERVERS` env, so the dashboard shows a lock icon next to encrypted miners and names the certificate in use on hover, with no source-IP heuristics.
Under StartOS this drives two certificates on one port, chosen per connection by SNI: a CA-issued (Let's Encrypt) certificate for miners connecting over a clearnet domain, and the self-signed one for miners on the LAN, which send no SNI and fall through to it.
@@ -71,33 +71,33 @@ The self-signed certificate is auto-generated on first start with broad SAN cove
The Svelte 5 dashboard connects via WebSocket for real-time push updates (no polling in normal operation) and includes:
- **Pool overview** — Hashrate (1m/5m/1h/24h), uptime, workers online, shares accepted/rejected, expected time to block, round effort
- **Hashrate chart** — Interactive multi-window visualization
- **Miners table** — Per-user and per-worker stats: hashrate, difficulty, latency, best shares, idle detection
- **Hardware detection** — Parses stratum user-agent strings to identify miner hardware (Bitaxe, Bitaxe Hex, NerdMiner, NerdAxe, NerdQAxe, NerdOCTAXE, NerdEKO, NerdNOS, PiAxe, QAxe, 0xAxe, LeafMiner, and more). Open-source hardware is flagged with a star badge so operators can see their fleet composition at a glance.
- **TLS badges** — Miners connected via the encrypted stratum port display a lock icon in the miners table, derived from CKPool's `server` field (no IP heuristics).
- **User/worker detail pages** — Deep dive into individual miner stats, cumulative work, and luck
- **Block history** — Found blocks with height, hash, reward, solving worker, chain name, orphan status
- **Best share leaderboard** — "This round" and "all-time" tracking with per-worker breakdown and glowing difficulty range indicators
- **PoW inspector** — Graphical breakdown of the block header behind the best share (version, prev block, merkle root, time, bits, nonce), the raw 80-byte header hex, and the coinbase + merkle branches that reproduce the merkle root — with one-click in-browser verification that replays the real SHA-256 compression rounds as an animation, ending at the share's block hash — self-contained implementation, no external services, works over plain-HTTP LAN
- **Transaction accelerator** — Boost transactions via `prioritisetransaction` with marginal fee displacement analysis showing the revenue impact of each boost
- **Block-found animation** — Celebratory toast on solve events
- **Health banners** — Live status indicators for CKPool, bitcoind, ZMQ, and submit-gap diagnostics
- **Block-update latency** — Tracks and displays average, last, and wasted-work latency for block notifications so operators can tune ZMQ and polling
- **Shares bar** — Accepted/rejected/stale share summary with ratio visualization
- **Custom mempool explorer** — Transaction and block links can point at a self-hosted mempool instance instead of the public mempool.space
- **Mobile responsive** — Full breakpoint coverage for phone and tablet
- **Donation footer** — BTC address with hover QR code
- **Pool overview**: Hashrate (1m/5m/1h/24h), uptime, workers online, shares accepted/rejected, expected time to block, round effort
- **Hashrate chart**: Interactive multi-window visualization
- **Miners table**: Per-user and per-worker stats: hashrate, difficulty, latency, best shares, idle detection
- **Hardware detection**: Parses stratum user-agent strings to identify miner hardware (Bitaxe, Bitaxe Hex, NerdMiner, NerdAxe, NerdQAxe, NerdOCTAXE, NerdEKO, NerdNOS, PiAxe, QAxe, 0xAxe, LeafMiner, and more). Open-source hardware is flagged with a star badge so operators can see their fleet composition at a glance.
- **TLS badges**: Miners connected via the encrypted stratum port display a lock icon in the miners table, derived from CKPool's `server` field (no IP heuristics).
- **User/worker detail pages**: Deep dive into individual miner stats, cumulative work, and luck
- **Block history**: Found blocks with height, hash, reward, solving worker, chain name, orphan status
- **Best share leaderboard**: "This round" and "all-time" tracking with per-worker breakdown and glowing difficulty range indicators
- **PoW inspector**: Graphical breakdown of the block header behind the best share (version, prev block, merkle root, time, bits, nonce), the raw 80-byte header hex, and the coinbase + merkle branches that reproduce the merkle root, with one-click in-browser verification that replays the real SHA-256 compression rounds as an animation, ending at the share's block hash, self-contained implementation, no external services, works over plain-HTTP LAN
- **Transaction accelerator**: Boost transactions via `prioritisetransaction` with marginal fee displacement analysis showing the revenue impact of each boost
- **Block-found animation**: Celebratory toast on solve events
- **Health banners**: Live status indicators for CKPool, bitcoind, ZMQ, and submit-gap diagnostics
- **Block-update latency**: Tracks and displays average, last, and wasted-work latency for block notifications so operators can tune ZMQ and polling
- **Shares bar**: Accepted/rejected/stale share summary with ratio visualization
- **Custom mempool explorer**: Transaction and block links can point at a self-hosted mempool instance instead of the public mempool.space
- **Mobile responsive**: Full breakpoint coverage for phone and tablet
- **Donation footer**: BTC address with hover QR code
### Reliability
- **Dual block notification** — ZMQ hashblock for instant detection + RPC polling as fallback. Both run simultaneously; every second of stale work in solo mode is hashrate burned on a dead block.
- **ckpool kill-on-failure** — When bitcoind becomes unreachable, kamado-api kills ckpool so miners can failover to another pool. ckpool restarts automatically when bitcoind recovers.
- **Deferred RPC** — Dashboard RPCs wait until the ckpool notifier completes on tip change to prioritize system resources for block reconstruction and validation.
- **Log cursor persistence** — The tailer's file offset is stored in SQLite so block-solve detection resumes correctly after restart.
- **Load before ingest** — Persisted counters are restored *before* the log-tailer goroutines start. They share the same state and persist it on their first event, so starting them against a half-restored aggregator would write a few seconds of new shares over the accumulated all-time history — and then read that back as the new truth. `RebuildShareStatsFromLog` (exposed as `POST /api/admin/rebuild-share-stats`) recounts the all-time difficulty distribution and rejection reasons from the ckpool log if they are ever lost; it only adopts the result when the log accounts for more shares than the stored totals, so it can restore history but never erase it.
- **Clean restarts for miners** — Upstream ckpool sends a reconnecting miner its first job *before* telling it the difficulty, and resets every client to the pool's `startdiff`, discarding what vardiff had tuned. Both produce a burst of "Above target" rejects on every pool restart. Patch `0009` sends `mining.set_difficulty` first, seeds the starting difficulty from the worker's retained hashrate, and accepts shares for the already-in-flight job down to the pool minimum until the next `mining.notify`.
- **Warm-up resilience** — The ckpool socket client handles transient EOFs during startup gracefully instead of crashing.
- **Dual block notification**: ZMQ hashblock for instant detection + RPC polling as fallback. Both run simultaneously; every second of stale work in solo mode is hashrate burned on a dead block.
- **ckpool kill-on-failure**: When bitcoind becomes unreachable, kamado-api kills ckpool so miners can failover to another pool. ckpool restarts automatically when bitcoind recovers.
- **Deferred RPC**: Dashboard RPCs wait until the ckpool notifier completes on tip change to prioritize system resources for block reconstruction and validation.
- **Log cursor persistence**: The tailer's file offset is stored in SQLite so block-solve detection resumes correctly after restart.
- **Load before ingest**: Persisted counters are restored *before* the log-tailer goroutines start. They share the same state and persist it on their first event, so starting them against a half-restored aggregator would write a few seconds of new shares over the accumulated all-time history, and then read that back as the new truth. `RebuildShareStatsFromLog` (exposed as `POST /api/admin/rebuild-share-stats`) recounts the all-time difficulty distribution and rejection reasons from the ckpool log if they are ever lost; it only adopts the result when the log accounts for more shares than the stored totals, so it can restore history but never erase it.
- **Clean restarts for miners**: Upstream ckpool sends a reconnecting miner its first job *before* telling it the difficulty, and resets every client to the pool's `startdiff`, discarding what vardiff had tuned. Both produce a burst of "Above target" rejects on every pool restart. Patch `0009` sends `mining.set_difficulty` first, seeds the starting difficulty from the worker's retained hashrate, and accepts shares for the already-in-flight job down to the pool minimum until the next `mining.notify`.
- **Warm-up resilience**: The ckpool socket client handles transient EOFs during startup gracefully instead of crashing.
## API Reference
@@ -157,9 +157,9 @@ The dashboard is at `http://localhost:8080`. Point a miner at `stratum+tcp://loc
| Variable | Default | Required | Description |
|----------|---------|----------|-------------|
| `BITCOIN_RPC_URL` | — | yes | bitcoind RPC endpoint (e.g. `http://127.0.0.1:8332`) |
| `BITCOIN_RPC_USER` | — | yes | RPC username |
| `BITCOIN_RPC_PASSWORD` | — | yes | RPC password |
| `BITCOIN_RPC_URL` |, | yes | bitcoind RPC endpoint (e.g. `http://127.0.0.1:8332`) |
| `BITCOIN_RPC_USER` |, | yes | RPC username |
| `BITCOIN_RPC_PASSWORD` |, | yes | RPC password |
| `LISTEN_ADDR` | `:8080` | no | HTTP bind address |
| `CKPOOL_SOCKDIR` | `/run/ckpool` | no | CKPool Unix socket directory |
| `CKPOOL_LOGFILE` | `/var/log/ckpool/ckpool.log` | no | CKPool log path for block-solve detection |
@@ -168,7 +168,7 @@ The dashboard is at `http://localhost:8080`. Point a miner at `stratum+tcp://loc
| `BITCOIN_ZMQ_BLOCK` | (disabled) | no | ZMQ hashblock endpoint (e.g. `tcp://127.0.0.1:28332`) |
| `BITCOIN_RPC_TIMEOUT` | `10s` | no | RPC call timeout |
| `MEMPOOL_BASE_URL` | (mempool.space) | no | Custom mempool explorer URL |
| `STRATUM_SERVERS` | (undeclared) | no | JSON array describing ckpool's `serverurl[]` binds, e.g. `[{"kind":"plain","label":"Plaintext"},{"kind":"tls-local","label":"TLS — self-signed"}]`. Entry N labels clients with `server == N` in the dashboard. Unset falls back to treating index 1 as TLS |
| `STRATUM_SERVERS` | (undeclared) | no | JSON array describing ckpool's `serverurl[]` binds, e.g. `[{"kind":"plain","label":"Plaintext"},{"kind":"tls-local","label":"TLS, self-signed"}]`. Entry N labels clients with `server == N` in the dashboard. Unset falls back to treating index 1 as TLS |
### UI Development
@@ -176,7 +176,7 @@ The dashboard is at `http://localhost:8080`. Point a miner at `stratum+tcp://loc
make ui-dev
```
Starts Vite on `:5173` with hot reload. API calls are proxied to `:8080` — run `make up` first so the backend is available.
Starts Vite on `:5173` with hot reload. API calls are proxied to `:8080`, run `make up` first so the backend is available.
### Testing
@@ -202,8 +202,8 @@ The test suite covers the critical mining path with 38 tests across 5 packages:
The smoke test runs two phases on regtest:
1. **Log-inject path** — Injects a synthetic block-solve line into ckpool's log, verifies the tailer detects it, enriches it via bitcoind RPC, and surfaces it at `/api/blocks`. Quick, no ckpool binary needed.
2. **Full stratum path** — Starts ckpool, connects a Python stratum miner, mines a real block, verifies the coinbase contains the "kamado" tag and the configured pool identifier, validates that bitcoind accepted the block with confirmations > 0, and checks that the block validation log shows correct chain acceptance.
1. **Log-inject path**, Injects a synthetic block-solve line into ckpool's log, verifies the tailer detects it, enriches it via bitcoind RPC, and surfaces it at `/api/blocks`. Quick, no ckpool binary needed.
2. **Full stratum path**, Starts ckpool, connects a Python stratum miner, mines a real block, verifies the coinbase contains the "kamado" tag and the configured pool identifier, validates that bitcoind accepted the block with confirmations > 0, and checks that the block validation log shows correct chain acceptance.
The smoke test auto-builds ckpool from the pinned upstream source with patches applied if not cached (build cached in `~/.cache/kamado-dev/`).
@@ -243,10 +243,10 @@ The StartOS wrapper packages Kamado Pool as an `.s9pk` for StartOS 0.3.5.1 with
## Upstream
CKPool by Con Kolivas — https://bitbucket.org/ckolivas/ckpool
CKPool by Con Kolivas, https://bitbucket.org/ckolivas/ckpool
Pinned commit: `cfb0f83b70d7b382b85d2bd0710cf4cb2dda4007`
## License
GPL-3.0 — see [LICENSE](LICENSE).
GPL-3.0, see [LICENSE](LICENSE).