Bump version to 0.2.7 to add upstream share card features

This commit is contained in:
satoshi committed 2026-09-04 00:56:56 +03:00
1 parent c9da2ebc45
commit e23046fd39
28 files changed
+255 -254

No files matched your search

+4 -4
View File
@@ -26,7 +26,7 @@ export const inputSpec = InputSpec.of({
stratumTlsPort: Value.number({
name: i18n('Preferred Stratum TLS Port (Local Network)'),
description: i18n(
'Network port to publish local-network TLS stratum on, using the self-signed certificate. A request, not a guarantee — see Pool Status for the port actually in use.',
'Network port to publish local-network TLS stratum on, using the self-signed certificate. A request, not a guarantee, see Pool Status for the port actually in use.',
),
required: true,
default: defaultStratumTlsPort,
@@ -37,7 +37,7 @@ export const inputSpec = InputSpec.of({
stratumPublicTlsPort: Value.number({
name: i18n('Preferred Stratum TLS Port (Public Domain)'),
description: i18n(
'Network port to publish public-domain TLS stratum on. A domain attached to the Stratum (TLS, Public Domain) interface is published on THIS port, which can differ from the one the OS assigns for IP access, and StartOS issues a Let’s Encrypt certificate for it — miners validate it with nothing pasted in. See Pool Status for the ports and domains actually in use.',
'Network port to publish public-domain TLS stratum on. A domain attached to the Stratum (TLS, Public Domain) interface is published on THIS port, which can differ from the one the OS assigns for IP access, and StartOS issues a Let’s Encrypt certificate for it, miners validate it with nothing pasted in. See Pool Status for the ports and domains actually in use.',
),
required: true,
default: defaultStratumPublicTlsPort,
@@ -63,7 +63,7 @@ export const inputSpec = InputSpec.of({
}),
// Storage key stays `tlsEnabled` so existing installs keep their setting;
// only the scope it describes narrowed. TLS over a public domain is not
// covered by this toggle — it follows the domains attached to the Stratum
// covered by this toggle, it follows the domains attached to the Stratum
// (TLS) interface and needs no configuration here.
tlsEnabled: Value.toggle({
name: i18n('Stratum TLS (Local Network)'),
@@ -159,7 +159,7 @@ export const config = sdk.Action.withInput(
async ({ effects, input }) => {
// Refuse an unusable pair (both stratum ports set to the same number).
// In-container ports are fixed constants, so the user can no longer create
// a bind collision — only an ambiguous external-port request.
// a bind collision, only an ambiguous external-port request.
const conflict = validatePorts({
stratumPort: input.stratumPort,
stratumTlsPort: input.stratumTlsPort,
+25 -24
View File
@@ -121,7 +121,7 @@ interface Snapshot {
hash: string
seen_at: string
}
// Log-derived (tailer) session stats — nonzero proves kamado-api is
// Log-derived (tailer) session stats, nonzero proves kamado-api is
// actually reading ckpool's log, as opposed to the socket-derived
// share counters above.
diff_dist_session: number[]
@@ -256,13 +256,13 @@ export const poolStatus = sdk.Action.withoutInput(
const sep = () => log('──────────────────────────────────────────')
let allPass = true
log('Kamado Pool — Status')
log('Kamado Pool, Status')
sep()
// ── 1. Full snapshot ────────────────────────────────────────────────────
log('● Pool & Bitcoin Core status')
if (!snap) {
log(' API unreachable — service may still be starting.')
log(' API unreachable, service may still be starting.')
allPass = false
}
@@ -280,8 +280,8 @@ export const poolStatus = sdk.Action.withoutInput(
log(
` Sync: ${
ibd
? `IBD — ${syncPct}% (pool will not mine until synced)`
: `${syncPct}% — fully synced`
? `IBD, ${syncPct}% (pool will not mine until synced)`
: `${syncPct}%, fully synced`
}`,
)
log(` Block hash: ${chain.bestblockhash}`)
@@ -304,9 +304,7 @@ export const poolStatus = sdk.Action.withoutInput(
const age = snap.has_last_zmq_event
? `last event ${snap.last_zmq_event_age.toFixed(0)}s ago`
: 'no event yet since startup'
log(
` ZMQ: ${snap.zmq_stale ? 'STALE — ' : 'OK — '}${age}`,
)
log(` ZMQ: ${snap.zmq_stale ? 'STALE, ' : 'OK, '}${age}`)
if (snap.zmq_stale) allPass = false
} else {
log(` ZMQ: disabled`)
@@ -339,7 +337,7 @@ export const poolStatus = sdk.Action.withoutInput(
` Submit attempts: ${snap.block_submit_attempts} confirmed: ${snap.block_submits_confirmed}`,
)
log(
` Submit gap: ${gap > 0 ? `WARN — ${gap} unconfirmed` : 'OK (all confirmed)'}`,
` Submit gap: ${gap > 0 ? `WARN, ${gap} unconfirmed` : 'OK (all confirmed)'}`,
)
if (gap > 0) allPass = false
@@ -361,7 +359,7 @@ export const poolStatus = sdk.Action.withoutInput(
if (snap.workers && snap.workers.length > 0) {
log('')
log('● Workers — best shares')
log('● Workers, best shares')
for (const w of snap.workers) {
const ever = w.bestever > 0 ? w.bestever : w.bestdiff
log(
@@ -431,7 +429,7 @@ export const poolStatus = sdk.Action.withoutInput(
log('')
log('● PoW capture (best-share header inspector)')
log(
` ckpool binary: ${pow.binaryPatched ? 'patched (0008) ✓' : 'NOT PATCHED — image predates patch 0008'}`,
` ckpool binary: ${pow.binaryPatched ? 'patched (0008) ✓' : 'NOT PATCHED, image predates patch 0008'}`,
)
log(
` ckpool log: ${pow.logPowLines} PoW data line${pow.logPowLines === 1 ? '' : 's'}, ${pow.logAcceptedLines} accepted-share lines`,
@@ -440,11 +438,11 @@ export const poolStatus = sdk.Action.withoutInput(
log(
` kamado-api: ${
snapPow
? `record held — diff ${fmtDiff(snapPow.sdiff)} at height ${snapPow.height} (${snapPow.seen_at.slice(0, 19)})`
? `record held, diff ${fmtDiff(snapPow.sdiff)} at height ${snapPow.height} (${snapPow.seen_at.slice(0, 19)})`
: 'no PoW record in snapshot'
}`,
)
// Log-derived session stats prove the tailer reads the log at all —
// Log-derived session stats prove the tailer reads the log at all,
// the share counters above come from ckpool's socket instead.
const tailerShares = (snap?.diff_dist_session ?? []).reduce(
(a, b) => a + b,
@@ -455,10 +453,13 @@ export const poolStatus = sdk.Action.withoutInput(
)
// Replay kamado-api's parse on the newest real PoW line: decode one
// brace-balanced JSON object after the marker, ignoring any trailing
// bytes — the same tolerance the Go parser applies.
// bytes, the same tolerance the Go parser applies.
if (pow.lastPowLine) {
let parseVerdict: string
const start = pow.lastPowLine.indexOf('{', pow.lastPowLine.indexOf('Best share PoW data'))
const start = pow.lastPowLine.indexOf(
'{',
pow.lastPowLine.indexOf('Best share PoW data'),
)
if (start < 0) {
parseVerdict = 'NO JSON OBJECT after marker'
} else {
@@ -481,7 +482,7 @@ export const poolStatus = sdk.Action.withoutInput(
}
}
if (end < 0) {
parseVerdict = 'UNTERMINATED JSON — line truncated mid-record'
parseVerdict = 'UNTERMINATED JSON, line truncated mid-record'
} else {
try {
const j = JSON.parse(pow.lastPowLine.slice(start, end + 1))
@@ -490,7 +491,7 @@ export const poolStatus = sdk.Action.withoutInput(
? `parses ✓ (sdiff ${fmtDiff(j.sdiff ?? 0)}, height ${j.height}, header 160 hex)`
: `JSON ok but header field is ${typeof j.header === 'string' ? `${j.header.length} chars` : 'missing'}`
} catch (e) {
parseVerdict = `JSON PARSE FAILED — ${String(e).slice(0, 120)}`
parseVerdict = `JSON PARSE FAILED, ${String(e).slice(0, 120)}`
}
}
}
@@ -505,17 +506,17 @@ export const poolStatus = sdk.Action.withoutInput(
allPass = false
} else if (pow.logAcceptedLines === 0) {
log(
' → verdict: no accepted shares in the current log file — ckpool logging problem or log freshly rotated. Wait for shares, then re-run.',
' → verdict: no accepted shares in the current log file, ckpool logging problem or log freshly rotated. Wait for shares, then re-run.',
)
allPass = false
} else if (pow.logPowLines === 0) {
log(
' → verdict: binary is patched but has never logged PoW data — the running ckpool process likely predates the update. Restart the service.',
' → verdict: binary is patched but has never logged PoW data, the running ckpool process likely predates the update. Restart the service.',
)
allPass = false
} else if (!snapPow) {
log(
' → verdict: ckpool logged PoW data but kamado-api holds no record — restart the service so the startup backfill adopts it from the log.',
' → verdict: ckpool logged PoW data but kamado-api holds no record, restart the service so the startup backfill adopts it from the log.',
)
allPass = false
} else {
@@ -546,11 +547,11 @@ export const poolStatus = sdk.Action.withoutInput(
log(`● Stratum (port ${stratumPort})`)
if (snap?.ckpool_ok) {
log(
' ckpool process: healthy — stratum port is served by the same process',
' ckpool process: healthy, stratum port is served by the same process',
)
} else {
log(
' FAIL — ckpool is not running, stratum port will not accept connections',
' FAIL, ckpool is not running, stratum port will not accept connections',
)
}
@@ -559,8 +560,8 @@ export const poolStatus = sdk.Action.withoutInput(
sep()
const pass = allPass && (snap?.ckpool_ok ?? false)
const summary = pass
? i18n('PASS — pool is healthy')
: i18n('FAIL — see details above')
? i18n('PASS, pool is healthy')
: i18n('FAIL, see details above')
log(`Overall: ${summary}`)
return {
+2 -2
View File
@@ -10,7 +10,7 @@ export const rebuildShareStats = sdk.Action.withoutInput(
async ({ effects }) => ({
name: i18n('Rebuild Share Statistics'),
description: i18n(
'Recounts the all-time share statistics — the difficulty distribution and rejection reasons on the Stats page — by rereading CKPool’s log from the beginning. Use this if those totals look wrong or reset. The stored totals are only replaced when the log accounts for more shares than they do, so this can add history back but never erase it.',
'Recounts the all-time share statistics, the difficulty distribution and rejection reasons on the Stats page, by rereading CKPool’s log from the beginning. Use this if those totals look wrong or reset. The stored totals are only replaced when the log accounts for more shares than they do, so this can add history back but never erase it.',
),
warning: i18n(
'On a pool with a long history this reads millions of log lines and can take a while. The pool keeps mining throughout.',
@@ -43,7 +43,7 @@ export const rebuildShareStats = sdk.Action.withoutInput(
version: '1',
title: i18n('Rebuild Share Statistics'),
message: i18n(
'Failed to rebuild share statistics — the Kamado API did not respond',
'Failed to rebuild share statistics, the Kamado API did not respond',
),
result: null,
}
+1 -1
View File
@@ -38,7 +38,7 @@ export const regenTlsCert = sdk.Action.withoutInput(
const hadCert = removed.length > 0
const message = hadCert
? i18n(
'TLS certificate cleared — restart the service to generate a new one',
'TLS certificate cleared, restart the service to generate a new one',
)
: i18n('No TLS certificate files found (TLS may not have been enabled)')
+1 -1
View File
@@ -44,7 +44,7 @@ export const resetLatency = sdk.Action.withoutInput(
version: '1',
title: i18n('Reset Block Latency'),
message: i18n(
'Failed to reset latency stats — the Kamado API did not respond',
'Failed to reset latency stats, the Kamado API did not respond',
),
result: null,
}
+2 -2
View File
@@ -33,7 +33,7 @@ export const showTlsCert = sdk.Action.withoutInput(
const tlsPort =
(await storeJson.read((s) => s.stratumTlsPort).once()) ??
defaultStratumTlsPort
const notYet = i18n('(not yet generated — start the service once)')
const notYet = i18n('(not yet generated, start the service once)')
const fingerprint = await readFile(
sdk.volumes.main.subpath('tls/fingerprint.txt'),
'utf-8',
@@ -51,7 +51,7 @@ export const showTlsCert = sdk.Action.withoutInput(
version: '1',
title: i18n('Stratum TLS Certificate'),
message: i18n(
'Connect miners with stratum+ssl:// to the Stratum (TLS, Local Network) interface. The certificate is self-signed: paste the PEM into firmware that accepts a custom root, pin the fingerprint, or disable verification. Miners connecting over a public domain do not need any of this — they use the Stratum (TLS, Public Domain) interface and its CA-issued certificate.',
'Connect miners with stratum+ssl:// to the Stratum (TLS, Local Network) interface. The certificate is self-signed: paste the PEM into firmware that accepts a custom root, pin the fingerprint, or disable verification. Miners connecting over a public domain do not need any of this, they use the Stratum (TLS, Public Domain) interface and its CA-issued certificate.',
),
result: {
type: 'group',