From b3a906fd0c337223f240f7552101a2b73618c89b Mon Sep 17 00:00:00 2001 From: Baldnerd Date: Tue, 13 Jan 2026 09:44:35 -0500 Subject: [PATCH] Update --- installer | 143 +++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 110 insertions(+), 33 deletions(-) diff --git a/installer b/installer index 84c0326..fee612c 100755 --- a/installer +++ b/installer @@ -4,11 +4,11 @@ # An Open Source Linux Appliance from Robbie Ferguson # (c) 2025 Robbie Ferguson -# Version 1.0.2 +# Version 1.0.3 set -e -BTC_VER="30.0" +BTC_VER="29.2" APP_ROOT="/opt/btc-solo" WWW_ROOT="/var/www/btc-solo" @@ -109,7 +109,7 @@ curl -fsSL "$BASE_URL/$TARBALL" -o "$TMPD/$TARBALL" curl -fsSL "$BASE_URL/SHA256SUMS" -o "$TMPD/SHA256SUMS" if command -v gpg >/dev/null 2>&1; then curl -fsSL "$BASE_URL/SHA256SUMS.asc" -o "$TMPD/SHA256SUMS.asc" || true - # If you’ve already imported the Bitcoin Core release keys, this will verify. + # If you've already imported the Bitcoin Core release keys, this will verify. # If not, we still proceed after SHA256 check below. gpg --verify "$TMPD/SHA256SUMS.asc" "$TMPD/SHA256SUMS" || echo "[WARN] Could not verify SHA256SUMS signature (no keys?). Continuing with SHA256 check." fi @@ -1166,7 +1166,7 @@ function drawLineGraph(containerId, points, opts = {}) { Range ${ isFinite(minVal) && isFinite(maxVal) - ? minVal.toFixed(2) + '–' + maxVal.toFixed(2) + ' ' + unit + ? minVal.toFixed(2) + '-' + maxVal.toFixed(2) + ' ' + unit : 'n/a' } @@ -1425,7 +1425,7 @@ async function loadStatus() { const rawIbd = data.initialblockdownload; const hasRealIbd = (typeof rawIbd === 'boolean'); const ibd = hasRealIbd ? rawIbd : true; - const blocks = data.blocks ?? '–'; + const blocks = data.blocks ?? '-'; const pruned = data.pruned ? '(pruned)' : ''; let progress = 0; if (typeof data.verificationprogress === 'number') { @@ -1591,7 +1591,7 @@ function parseHashrate(str) { } function formatHashrateHps(value) { - if (value == null || !isFinite(value) || value <= 0) return '–'; + if (value == null || !isFinite(value) || value <= 0) return '-'; let v = value; let unit = 'H/s'; @@ -1627,9 +1627,9 @@ const HIDE_SEC = 3 * 24 * 3600; // 3 days -> "inactive" list const PURGE_SEC = 30 * 24 * 3600; // 30 days -> purge from UI function formatShare(value) { - if (value == null) return '–'; + if (value == null) return '-'; const num = typeof value === 'number' ? value : parseFloat(value); - if (!isFinite(num)) return '–'; + if (!isFinite(num)) return '-'; const units = ['', 'k', 'M', 'G', 'T', 'P']; let v = num; let i = 0; @@ -1675,13 +1675,13 @@ function buildWorkerDetailHtml(worker, animate, graphId) { detail.push('
Last share: ' + lastRel + ' (' + lastAbs + ')
'); detail.push('
Hashrate (averages):
'); detail.push(''); - detail.push('
Shares: ' + (worker.shares ?? '–') + + detail.push('
Shares: ' + (worker.shares ?? '-') + ' • Best share: ' + formatShare(worker.bestshare) + ' • Best ever: ' + formatShare(worker.bestever) + '
'); @@ -1816,17 +1816,17 @@ async function loadPool() { const acceptedText = shares.accepted != null ? acceptedNum.toLocaleString() - : '–'; + : '-'; const rejectedText = shares.rejected != null ? rejectedNum.toLocaleString() - : '–'; + : '-'; let rejectPct = null; if (totalShares > 0 && rejectedNum >= 0) { rejectPct = ((rejectedNum / totalShares) * 100).toFixed(2); } - const bestHashText = bestPoolH1m ? formatHashrateHps(bestPoolH1m) : '–'; + const bestHashText = bestPoolH1m ? formatHashrateHps(bestPoolH1m) : '-'; summaryHtml += '
SHARES
'; summaryHtml += '
'; @@ -1932,12 +1932,12 @@ async function loadPool() { tableHtml += '' + '' + displayName + '' + - '' + (w.hashrate1m || '–') + '' + - '' + (w.hashrate5m || '–') + '' + - '' + (w.hashrate1hr || '–') + '' + - '' + (w.hashrate1d || '–') + '' + - '' + (w.hashrate7d || '–') + '' + - '' + (w.shares ?? '–') + '' + + '' + (w.hashrate1m || '-') + '' + + '' + (w.hashrate5m || '-') + '' + + '' + (w.hashrate1hr || '-') + '' + + '' + (w.hashrate1d || '-') + '' + + '' + (w.hashrate7d || '-') + '' + + '' + (w.shares ?? '-') + '' + '' + formatShare(w.bestshare) + '' + '' + lastCol + '' + ''; @@ -2349,7 +2349,7 @@ if (isset($_GET['addr'])) { $addr = trim($_GET['addr']); } -// light sanity check (not strict – CKPool does the real validation) +// light sanity check (not strict - CKPool does the real validation) if ($addr !== '' && !preg_match('/^[13bc][a-km-zA-HJ-NP-Z1-9]{25,}$/', $addr)) { $addr = ''; } @@ -2418,7 +2418,7 @@ if ($addr !== '') { } $resp['worker_count'] = count($resp['workers']); } else { - // Not a fatal error – just "no data yet" for that address + // Not a fatal error - just "no data yet" for that address if ($resp['error'] === null) { $resp['error'] = 'No worker stats yet for this address'; } @@ -2483,7 +2483,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {

Create New Admin User

- This sets the Bitcoin node’s administrative (RPC) credentials used to control the server itself.

+ This sets the Bitcoin node's administrative (RPC) credentials used to control the server itself.

Keep these private — they grant full access to your node.

These credentials are not used by miners to connect; miners only need your Bitcoin address and can use any password.

@@ -2742,10 +2742,10 @@ draw_dashboard() { tput cup 13 0; echo -e "Memory: ${mem}\033[K" tput cup 14 0; echo -e "Disk (${BTC_DIR}): ${disk}\033[K" - tput cup 16 0; echo -e "Workers:\033[K" + tput cup 16 0; echo -e "Mining:\033[K" tput cup 17 2; echo -e "${workers}\033[K" - tput cup 19 0; echo -e "(Appliance console view — use the web UI for full details.)\033[K" +# tput cup 19 0; echo -e "(Appliance console view — use the web UI for full details.)\033[K" } draw_header @@ -2768,7 +2768,84 @@ while true; do PROGRESS_LINE="" BAR_LINE="[--------------] 0.0%" SERVICES_LINE="Bitcoin: ${BTC_STATE} CKPool: ${CKP_STATE}" - WORKERS_LINE="No workers detected (point your ASICs at this node)" + + # --- CKPool worker summary (console-safe, no per-worker listing) --- + POOL_STATUS="/opt/btc-solo/logs/pool/pool.status" + + # Humanize hashrate (expects H/s as a number; falls back to raw if unknown) + human_hashrate() { + local v="$1" + if [[ -z "$v" || "$v" == "null" ]]; then echo "-"; return; fi + if ! [[ "$v" =~ ^[0-9]+([.][0-9]+)?$ ]]; then echo "$v"; return; fi + + awk -v x="$v" 'BEGIN{ + u[0]="H/s"; u[1]="kH/s"; u[2]="MH/s"; u[3]="GH/s"; u[4]="TH/s"; u[5]="PH/s"; u[6]="EH/s"; + i=0; + while (x>=1000 && i<6) { x/=1000; i++ } + if (x<10) printf("%.2f %s", x, u[i]); + else if (x<100)printf("%.1f %s", x, u[i]); + else printf("%.0f %s", x, u[i]); + }' + } + + # Add commas to large integers (e.g. 1000000 -> 1,000,000) + fmt_int() { + [[ "$1" =~ ^[0-9]+$ ]] && printf "%'d" "$1" || printf "%s" "$1" + } + + if command -v jq >/dev/null 2>&1; then + WORKERS_LINE="No workers detected (point your ASICs at this node)" + else + WORKERS_LINE="Install jq for worker stats." + fi + + if [[ -r "$POOL_STATUS" ]]; then + # pool.status is 3 JSON objects, one per line: counts, hashrate, shares + # Slurp into array so we can index [0],[1],[2] + POOL_JSON="$(jq -s '.' "$POOL_STATUS" 2>/dev/null || true)" + + if [[ -n "$POOL_JSON" && "$POOL_JSON" != "null" ]]; then + workers="$(jq -r '.[0].Workers // empty' <<<"$POOL_JSON")" + idle="$(jq -r '.[0].idle // empty' <<<"$POOL_JSON")" + disc="$(jq -r '.[0].disconnected // empty' <<<"$POOL_JSON")" + users="$(jq -r '.[0].users // empty' <<<"$POOL_JSON")" + + hr1m="$(jq -r '.[1].hashrate1m // empty' <<<"$POOL_JSON")" + hr5m="$(jq -r '.[1].hashrate5m // empty' <<<"$POOL_JSON")" + hr15m="$(jq -r '.[1].hashrate15m // empty' <<<"$POOL_JSON")" + + acc="$(jq -r '.[2].accepted // empty' <<<"$POOL_JSON")" + rej="$(jq -r '.[2].rejected // empty' <<<"$POOL_JSON")" + stale="$(jq -r '.[2].stale // empty' <<<"$POOL_JSON")" + dup="$(jq -r '.[2].dup // empty' <<<"$POOL_JSON")" + sps="$(jq -r '.[2].SPS1m // empty' <<<"$POOL_JSON")" + bestshare="$(jq -r '.[2].bestshare // empty' <<<"$POOL_JSON")" + + if [[ -n "$workers" && "$workers" != "0" ]]; then + # Compact worker line (single line, console-safe) + # Example: Workers: 3 (idle 1, disc 0) | HR: 1m 1.2 TH/s / 5m 1.1 TH/s / 15m 1.0 TH/s | Shares: acc 120 rej 0 stale 1 dup 0 | SPS 0.03 + WORKERS_LINE="Workers: ${workers}" + [[ -n "$idle" || -n "$disc" ]] && WORKERS_LINE+=" (idle ${idle:-0}, disc ${disc:-0})" + WORKERS_LINE+=" " # Extend a little beyond the end of the current text to blank if new output is shorter + [[ -n "$users" ]] && WORKERS_LINE+="\n Users: ${users}" + WORKERS_LINE+=" " # Extend a little beyond the end of the current text to blank if new output is shorter + + WORKERS_LINE+="\n Hashrate: 1m $(human_hashrate "$hr1m") / 5m $(human_hashrate "$hr5m") / 15m $(human_hashrate "$hr15m")" + WORKERS_LINE+=" " # Extend a little beyond the end of the current text to blank if new output is shorter + + # Shares (show only fields that exist; keep it tight) + WORKERS_LINE+="\n Shares:" + WORKERS_LINE+="\n Accepted: $(fmt_int "${acc:-0}") " + [[ -n "$rej" ]] && WORKERS_LINE+="\n Rejected: $(fmt_int "$rej") " + [[ -n "$stale" ]] && WORKERS_LINE+="\n Stale: $(fmt_int "$stale") " + [[ -n "$dup" ]] && WORKERS_LINE+="\n Duplicate:$(fmt_int "$dup") " + [[ -n "$sps" ]] && WORKERS_LINE+="\n Shares Per Second: $sps " + [[ -n "$bestshare" ]] && WORKERS_LINE+="\n Best Share: $(fmt_int "$bestshare") " + + fi + fi + fi + # --- /CKPool worker summary --- # cpu load if [ -r /proc/loadavg ]; then @@ -2812,7 +2889,7 @@ while true; do INFO="$LAST_INFO" fi else - # success – store and reset fail counter + # success - store and reset fail counter LAST_INFO="$INFO" CONSEC_FAILS=0 fi @@ -2844,12 +2921,12 @@ while true; do if [ "$IBD" = "true" ]; then if [ "$(echo "$PROG_PCT < 0.1" | bc -l 2>/dev/null || echo 0)" = "1" ]; then - STATUS_LINE="${YEL}⚠ Bitcoin Core is starting up and loading blockchain data…${RST}" + STATUS_LINE="${YEL}⚠ Bitcoin Core is starting up and loading blockchain data...${RST}" else - STATUS_LINE="${YEL}⚠ Syncing blockchain… ${PROG_PCT}%${RST}" + STATUS_LINE="${YEL}⚠ Syncing blockchain... ${PROG_PCT}%${RST}" fi else - STATUS_LINE="${GRN}✔ Bitcoin Core is ready.${RST}" + STATUS_LINE="${GRN}✔ Bitcoin Core is in sync.${RST}" fi PROGRESS_LINE="Blocks: ${BLOCKS} / ${HEADERS} $( [ "$PRUNED" = "true" ] && echo '(pruned)' )"