igneum/packaging/hive/h-run.sh
igneum-labs c83ea0f5d4 Pool finished (mission item 11): pool-0's fee published beside the dev fee, TLS 1.3 on the member port with the authorize binding (spec 9.3, O-9.7 closed), the page rows Q68 to Q73, and the open pool: a share sidechain with no operator (spec 9.12)
Pool-0: welcome carries software_dev_fee_percent beside the pool fee, the page's Fees row and site/miner.html say pool-0 charges the same 1 percent as the solo dev fee; jobs and seeds carry the latency ladder's rung for 0.3.19.

TLS (pool/src/tls.rs): --tls-cert/--tls-key or --tls-self-signed (a P-256 pair under the data dir, the certificate pin printed at start); the binding is the member's BLS signature over this connection's exporter (label EXPORTER-igneum-pool-binding, context the chain id), refused on any other connection; testnet and mainnet refuse the clear without --allow-plain. HiveOS: pools:// and POOL_PIN.

Page rows: node state in words (Q68), one formatter set and luck in MiningPoolStats' convention (Q69), samples and check costs persisted (Q70), payments under the lookup (Q71), hourly history with a sparkline, --alert-webhook, /metrics, /health on the node (Q72), the network's finality state beside "payouts follow blue confirmation, not finality" (Q73).

The open pool (pool/src/sidechain.rs, open.rs, p2p.rs; igneum-pool --open): the member's own node and daemon, no payout key, no balance; every coinbase carries the member's own address, the share chain's parent (IGNS) and the window's split (IGNP); templates re-stamped on a new chain tip without a node call; shares gossiped and checked by every member (structure, the node's seeds, the PoW); heaviest work wins, a fork's loser is stale; the dev fee as one split entry; shares.log and verify-share for the drop proof; the gate harness pool/tools/open-gate.mjs. The node side (the executor's split from pool_split_activation_daa) is on the fork branch pool-finish-node.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
(cherry picked from commit 57954a43eb)
2026-10-07 14:03:05 +00:00

118 lines
7 KiB
Bash
Executable file

#!/usr/bin/env bash
# Igneum Miner for HiveOS: starts the bundled node when asked, exports the hourly program pack, then one igneum-miner
# per GPU with the matching worker (igneum-worker-cuda on NVIDIA, igneum-worker-opencl on AMD). Each miner mines
# against the node for its own payout address; the software dev fee (1 template in 100) is the miner's default and
# DEV_FEE=0 in the Flight Sheet's extra config turns it off. Per-GPU logs: $CUSTOM_LOG_BASENAME.gpu<N>.log; the main
# log is their merged tail. Run by Hive with the working directory at the miner folder.
cd "$(dirname "$0")" || exit 1
HERE="$(pwd)"
[[ -z "$CUSTOM_LOG_BASENAME" || -z "$CUSTOM_CONFIG_FILENAME" ]] && . "$HERE/h-manifest.conf"
[[ -z "$CUSTOM_LOG_BASENAME" ]] && echo "No CUSTOM_LOG_BASENAME is set" && exit 1
[[ -f "$CUSTOM_CONFIG_FILENAME" ]] || { echo "No config at $CUSTOM_CONFIG_FILENAME (apply the Flight Sheet first)"; exit 1; }
. "$CUSTOM_CONFIG_FILENAME"
BIN="${IGNEUM_BIN:-$HERE/bin}"
mkdir -p "$(dirname "$CUSTOM_LOG_BASENAME")" "$HERE/packs" "$HERE/data"
date +%s > "$CUSTOM_LOG_BASENAME.started"
MAIN="$CUSTOM_LOG_BASENAME.log"
: > "$MAIN"
say() { printf '%s %s\n' "$(date -u +%Y-%m-%dT%H:%M:%SZ)" "$*" | tee -a "$MAIN"; }
echo $$ > "$CUSTOM_LOG_BASENAME.pid"
pids=()
cleanup() { say "stopping"; for p in "${pids[@]}"; do kill "$p" 2>/dev/null; done; pkill -TERM -P $$ 2>/dev/null; sleep 2; for p in "${pids[@]}"; do kill -9 "$p" 2>/dev/null; done; pkill -KILL -P $$ 2>/dev/null; exit 0; }
trap cleanup INT TERM
# 1. the node (in pool mode, NODE_URL is "none" unless the Flight Sheet asked for a verifier node with NODE=)
POOL_URL="${POOL_URL:-}"
POOL_TLS="${POOL_TLS:-0}"
POOL_PIN="${POOL_PIN:-}"
if [[ "$NODE_URL" == "local" ]]; then
NODE_URL="grpc://127.0.0.1:26610"
peers=()
if [[ -n "$PEERS" ]]; then IFS=',' read -r -a plist <<< "$PEERS"; for p in "${plist[@]}"; do peers+=("--addpeer=$p"); done
else peers+=("--addpeer=188.245.5.161:26611"); fi # the public devnet seed (app/igneum-app/src/config.rs)
# the consensus override (OVERRIDE in the Flight Sheet's extra config, written to igneum.conf by h-config.sh): the
# devnet's activation heights. A node without it runs on genesis parameters, prints another digest in the p2p
# handshake and is refused by every devnet peer (release 0.3.11, section 5, C41).
override=()
if [[ -n "${OVERRIDE:-}" ]]; then
printf '%s\n' "$OVERRIDE" > "$HERE/data/override-params.json"
override=("--override-params-file=$HERE/data/override-params.json")
say "consensus override from the Flight Sheet: $OVERRIDE"
else
say "WARNING: no OVERRIDE in the Flight Sheet; the node runs on genesis parameters and every devnet peer will refuse it. Set OVERRIDE from the downloads page."
fi
say "starting the bundled node (devnet, data $HERE/data, peers ${peers[*]#--addpeer=})"
"$BIN/igneumd" --devnet "--appdir=$HERE/data" --rpclisten=127.0.0.1:26610 --listen=0.0.0.0:26611 "${peers[@]}" \
${override[@]+"${override[@]}"} --nodnsseed --disable-upnp --nologfiles --yes >> "$CUSTOM_LOG_BASENAME.node.log" 2>&1 &
pids+=($!)
fi
if [[ "$NODE_URL" != "none" ]]; then
say "node $NODE_URL; waiting for it to answer"
for _ in $(seq 1 60); do
"$BIN/igneum-miner" watch 1 "$NODE_URL" >/dev/null 2>&1 && break
sleep 2
done
fi
if [[ -f "$CUSTOM_LOG_BASENAME.node.log" ]]; then
# the switch lines and the digest the node printed at start, so the operator can compare the digest with the one
# on the downloads page (another digest = refused by every peer)
n=0
while IFS= read -r l; do say "node: $l"; n=$((n + 1)); done < <(grep -E 'override params file|from the override file|Consensus params digest' "$CUSTOM_LOG_BASENAME.node.log" | head -12)
[[ $n == 0 ]] && say "node: no digest line yet in $CUSTOM_LOG_BASENAME.node.log (an older node, or not started); check it by hand"
fi
[[ -n "$POOL_URL" ]] && say "pool mode: shares to $POOL_URL, payout $WALLET, worker $LABEL-gpuN, verifier node $NODE_URL (the vote key stays this rig's; no software dev fee)"
# 2. the GPUs: Hive's gpu-detect when present, else the driver tools
nv=0; amd=0
if command -v gpu-detect >/dev/null 2>&1; then nv=$(gpu-detect NVIDIA 2>/dev/null || echo 0); amd=$(gpu-detect AMD 2>/dev/null || echo 0)
else
command -v nvidia-smi >/dev/null 2>&1 && nv=$(nvidia-smi -L 2>/dev/null | grep -c '^GPU')
[[ -d /sys/bus/pci/drivers/amdgpu ]] && amd=$(ls /sys/bus/pci/drivers/amdgpu 2>/dev/null | grep -c '^0000:')
fi
nv=${nv:-0}; amd=${amd:-0}
say "GPUs: $nv NVIDIA, $amd AMD (worker setting: $WORKER)"
[[ "$nv" == "0" && "$amd" == "0" ]] && say "no GPU found; nothing to mine with" && sleep 30 && exit 1
# 3. the hourly program pack from the node (the workers read it with --pack; the miner writes the next one to packs/prepare)
export_pack() { [[ "$NODE_URL" == "none" ]] && return 0; rm -rf "$HERE/packs/devnet"; "$BIN/igneum-miner" export-pack "$NODE_URL" "$HERE/packs/devnet" >> "$MAIN" 2>&1; }
export_pack || say "pack export failed; the miners retry"
# 4. one miner per GPU, restarted on exit (exit 42 = the program changed and the worker cannot prepare: re-export the pack)
run_gpu() {
local idx="$1" worker="$2" dev="$3" tag="$4"
local log="$CUSTOM_LOG_BASENAME.gpu$idx.log"
local args=(mine "$NODE_URL" 1 100000000 "$LABEL-gpu$idx" --worker "$BIN/$worker" --worker-args "--device $dev --pack packs/devnet"
--prepare-packs packs/prepare --exit-on-seed-change --evm-address "$WALLET" --payout-label "$LABEL-gpu$idx" --status-secs 30)
if [[ -n "$POOL_URL" ]]; then
# pool mode: one vote key per operator (spec 9.6), the worker name labels the card, no software dev fee
args+=(--pool "$POOL_URL" --worker-name "$LABEL-gpu$idx")
# spec 9.3: TLS 1.3 to the pool (pools:// in the Flight Sheet), or a pinned self-signed certificate (POOL_PIN=)
if [[ -n "$POOL_PIN" ]]; then args+=(--pool-pin "$POOL_PIN"); elif [[ "$POOL_TLS" == "1" ]]; then args+=(--pool-tls); fi
else
local identv="IDENTITIES_GPU$idx" ident="$IDENTITIES"; [[ -n "${!identv:-}" ]] && ident="${!identv}" # per-card from h-config.sh, else the fallback
[[ "$ident" -gt 1 ]] && args+=(--identities "$ident")
[[ "$DEV_FEE" != "1" ]] && args+=(--dev-fee "$DEV_FEE")
fi
[[ "$VOTE" == "0" ]] && args+=(--no-vote)
[[ -n "$EXTRA" ]] && args+=($EXTRA)
while :; do
echo "$(date -u +%Y-%m-%dT%H:%M:%SZ) gpu$idx ($tag $dev): igneum-miner ${args[*]}" >> "$log"
"$BIN/igneum-miner" "${args[@]}" >> "$log" 2>&1
rc=$?
if [[ $rc == 42 ]]; then export_pack; else sleep 5; fi
done
}
idx=0
if [[ "$nv" -gt 0 && "$WORKER" != "opencl" ]]; then
for ((d = 0; d < nv; d++)); do run_gpu "$idx" igneum-worker-cuda "$d" nvidia & pids+=($!); idx=$((idx + 1)); done
fi
if [[ "$amd" -gt 0 && "$WORKER" != "cuda" ]]; then
for ((d = 0; d < amd; d++)); do run_gpu "$idx" igneum-worker-opencl "$d" amd & pids+=($!); idx=$((idx + 1)); done
fi
say "$idx miner(s) started; dev fee ${DEV_FEE}% (the miner prints its own dev fee line below)"
# 5. the main log: every GPU's lines, merged
sleep 1
tail -q -n +1 -F "$CUSTOM_LOG_BASENAME".gpu*.log 2>/dev/null | tee -a "$MAIN" &
pids+=($!)
wait