Unify best-share semantics across leaderboard / miners / user page

BestShares read worker.bestdiff for its "Best (round)" column,
while MinersTable used client.bestdiff for online workers (and
worker.bestdiff only as a fallback for offline ones). ckpool
resets *both* fields in reset_bestshares() when the pool finds a
block, but reconnect / timing can leave them briefly divergent,
so the same worker could show different values in the two tables.

Switch every "session best" display to the same computation:

    max(client.bestdiff, worker.bestdiff)

…picking whichever is currently higher. Relabel the column from
"Best (round)" to "Best (session)" in MinersTable, BestShares, and
UserDetailPage so the meaning matches the value. UserDetailPage's
per-user summary tile used to show the user's round-best as a
sub-line; drop it, since it contradicts the "session" framing at
the row level.

Net effect: scroll between the leaderboard and the miners table
and the same worker's best-share number stays put.
This commit is contained in:
satoshi
2026-04-24 01:34:04 +03:00
parent 49c951f94f
commit 91902f38a0
3 changed files with 41 additions and 17 deletions
+24 -11
View File
@@ -1,18 +1,31 @@
<script lang="ts">
import { snap } from "../stores/snapshot.svelte";
import { formatDifficulty } from "../format";
import type { StratumClient } from "../types";
// Top 10 workers by all-time best share. `bestever` requires the
// Kamado ckpool patch (0001-expose-bestever-in-runtime-json.patch)
// — on an unpatched ckpool it will be zero everywhere and we fall
// back to the current round's best diff.
// Join client data into worker rows so the "session best" column
// matches what the Miners table renders for the same worker.
// ckpool's reset_bestshares() zeroes both worker.best_diff and
// client.best_diff when the pool finds a block, but timing or
// reconnect can leave the two briefly divergent — take the larger
// of the two to stay consistent with the Miners table.
const rows = $derived.by(() => {
const ws = snap.data?.workers ?? [];
const enriched = ws.map((w) => ({
worker: w.worker,
bestRound: w.bestdiff,
bestEver: w.bestever || w.bestdiff,
}));
const cs = snap.data?.clients ?? [];
const clientByWorker = new Map<string, StratumClient>();
for (const c of cs) {
const wname = c.workername || `${c.address}.unnamed`;
clientByWorker.set(wname, c);
}
const enriched = ws.map((w) => {
const c = clientByWorker.get(w.worker);
const sessionBest = Math.max(c?.bestdiff ?? 0, w.bestdiff);
return {
worker: w.worker,
sessionBest,
bestEver: w.bestever || sessionBest,
};
});
enriched.sort((a, b) => b.bestEver - a.bestEver);
return enriched.slice(0, 10);
});
@@ -28,7 +41,7 @@
<tr>
<th>#</th>
<th>Worker</th>
<th class="num">Best (round)</th>
<th class="num">Best (session)</th>
<th class="num">Best (ever)</th>
</tr>
</thead>
@@ -37,7 +50,7 @@
<tr>
<td>{i + 1}</td>
<td class="mono">{r.worker}</td>
<td class="num">{formatDifficulty(r.bestRound)}</td>
<td class="num">{formatDifficulty(r.sessionBest)}</td>
<td class="num">{formatDifficulty(r.bestEver)}</td>
</tr>
{/each}
+9 -3
View File
@@ -35,14 +35,20 @@
const wname = c.workername || `${c.address}.unnamed`;
seen.add(wname);
const w = byWorker.get(wname);
// "Session best" is the larger of the live stratum client's
// best_diff and the worker_instance's best_diff. ckpool's
// reset_bestshares() clears both when the pool finds a block,
// but reconnect / timing can leave them briefly divergent —
// max() keeps this column aligned with the leaderboard.
const sessionBest = Math.max(c.bestdiff, w?.bestdiff ?? 0);
out.push({
workerName: wname,
user: c.address,
hardware: detectHardware(c.useragent),
hashrate1m: c.dsps1 * 2 ** 32,
hashrate1h: c.dsps60 * 2 ** 32,
bestDiff: c.bestdiff,
bestEver: w?.bestever ?? 0,
bestDiff: sessionBest,
bestEver: w?.bestever ?? sessionBest,
lastShare: c.lastshare,
difficulty: c.diff,
address: c.address,
@@ -88,7 +94,7 @@
<th class="num">Hashrate (1m)</th>
<th class="num">Hashrate (1h)</th>
<th class="num">Diff</th>
<th class="num">Best (round)</th>
<th class="num">Best (session)</th>
<th class="num">Best (ever)</th>
<th class="num">Last share</th>
</tr>
+8 -3
View File
@@ -49,7 +49,12 @@
hashrate1m: (c?.dsps1 ?? w.dsps1) * 2 ** 32,
hashrate1h: (c?.dsps60 ?? w.dsps60) * 2 ** 32,
diff: c?.diff ?? w.mindiff,
bestRound: c?.bestdiff ?? w.bestdiff,
// Session best = larger of client.bestdiff (this stratum
// connection) and worker.bestdiff (this worker in the
// current round). Matches the MinersTable / BestShares
// leaderboard semantics so values are consistent across
// screens.
bestRound: Math.max(c?.bestdiff ?? 0, w.bestdiff),
bestEver: w.bestever,
lastShare: c?.lastshare ?? w.lastshare,
online: !!c,
@@ -138,7 +143,7 @@
<div class="card">
<div class="stat-label">Best share (ever)</div>
<div class="stat-value">{formatDifficulty(totals.bestEver || totals.bestDiff)}</div>
<div class="stat-sub">round best {formatDifficulty(totals.bestDiff)}</div>
<div class="stat-sub">across all this user's workers</div>
</div>
<div class="card">
<div class="stat-label">Workers</div>
@@ -166,7 +171,7 @@
<th class="num">Hashrate (1m)</th>
<th class="num">Hashrate (1h)</th>
<th class="num">Diff</th>
<th class="num">Best (round)</th>
<th class="num">Best (session)</th>
<th class="num">Best (ever)</th>
<th class="num">Last share</th>
</tr>