packaging/linux: preflight (Ubuntu 24.04, NVIDIA driver 580 floor with libcuda and libnvrtc.so.12, AMD ROCm OpenCL ICD, Intel compute runtime, nvidia-smi and the OpenCL list printed, RAM, free disk, ports, ufw), the wallet and rig name asked once, the igneum system user, the Ed25519 check of dl/public/igneum-app-latest.json with the OTA public key (OpenSSL 3 pkeyutl -rawin, python3 cryptography fallback, never skipped), consensus.override written from the verified manifest and refreshed hourly (the HiveOS override rule without a package republish), the HiveOS package downloaded with size and sha256 checked (the signed linux entry when the manifest has one, else the .sha256 sidecar behind --allow-sidecar-sha256, said in capitals), releases under /opt/igneum with a current symlink and a 90-s rollback, one miner unit per card with CUDA_DEVICE_ORDER=PCI_BUS_ID and the OpenCL ordinal mapping, the integrated GPU and the BMC VGA excluded by the inventory, the prover unit as the proving-v1 loop in bash (12 GB gate, 20 GB mine-and-prove line with the card's miner paused per shard through a sudoers rule, idles in state setup while no Linux prover binary is published), telemetry in the app's line shapes with the relay upload under nodelog-linux/miner-<vendor>/linux labels, the identities rule with its 8 GiB threshold. Tested on the Mac: shellcheck -x -S style clean, bash -n, check-units.sh (6 units, the systemd-analyze stand-in; no systemd or Docker here), the inventory on a fake sysfs tree, the rules, the live manifest verified by both verifiers and tampered copies refused, the installer dry run with the 0.3.9 package downloaded and verified. Untested until a rig exists: listed in README.md. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
106 lines
9 KiB
Bash
Executable file
106 lines
9 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
# Self-test of the rig package on a machine that is not the rig (the Mac, 5 October 2026): bash -n and shellcheck on
|
|
# every script, the unit files through check-units.sh, the card inventory on a fake sysfs tree (NVIDIA, AMD, Intel,
|
|
# an AMD APU, an Intel iGPU and an ASPEED BMC VGA, the last three excluded), the OpenCL index mapping on a fake
|
|
# --list, the prover default rule and the identities rule on fake inventories, the Ed25519 check against the LIVE
|
|
# signed manifest (and a tampered copy refused), then the installer's --dry-run end to end, which downloads and
|
|
# verifies the live package into a scratch folder. Nothing under / is touched. Needs network for the last two.
|
|
set -euo pipefail
|
|
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
T="$(mktemp -d)"; trap 'rm -rf "$T"' EXIT
|
|
pass() { printf ' ok %s\n' "$*"; }
|
|
fail() { printf ' FAIL %s\n' "$*"; exit 1; }
|
|
|
|
echo "== bash -n and shellcheck"
|
|
for f in "$HERE"/install-rig.sh "$HERE"/selftest.sh "$HERE"/check-units.sh "$HERE"/bin/*; do bash -n "$f" || fail "bash -n $f"; done
|
|
pass "bash -n on $(find "$HERE/bin" -type f | wc -l | tr -d ' ') scripts plus the installer, the checker and this test"
|
|
if command -v shellcheck >/dev/null 2>&1; then
|
|
shellcheck -x -S style "$HERE"/install-rig.sh "$HERE"/selftest.sh "$HERE"/check-units.sh "$HERE"/bin/* || fail "shellcheck"
|
|
pass "shellcheck $(shellcheck --version | awk '/version:/ {print $2}') clean at -S style"
|
|
else echo " note shellcheck is not installed (brew install shellcheck); skipped"; fi
|
|
|
|
echo "== unit files"
|
|
"$HERE/check-units.sh" || fail "check-units.sh"
|
|
|
|
echo "== card inventory on a fake sysfs tree"
|
|
S="$T/sys"; P="$S/bus/pci/devices"; mkdir -p "$P" "$S/bus/pci/drivers/amdgpu" "$S/bus/pci/drivers/xe"
|
|
mk() { # <bus> <class> <vendor> <device> [vram bytes] [product]
|
|
mkdir -p "$P/$1"; printf '%s\n' "$2" > "$P/$1/class"; printf '%s\n' "$3" > "$P/$1/vendor"; printf '%s\n' "$4" > "$P/$1/device"
|
|
[[ -n "${5:-}" ]] && printf '%s\n' "$5" > "$P/$1/mem_info_vram_total"; [[ -n "${6:-}" ]] && printf '%s\n' "$6" > "$P/$1/product_name"; true
|
|
}
|
|
mk 0000:01:00.0 0x030000 0x10de 0x2b85 # RTX 5090
|
|
mk 0000:21:00.0 0x030000 0x10de 0x2b85 # RTX 5090
|
|
mk 0000:41:00.0 0x030000 0x1002 0x7550 17163091968 "AMD Radeon RX 9070 XT"
|
|
mk 0000:42:00.0 0x030000 0x1002 0x7550 17163091968 "AMD Radeon RX 9070 XT"
|
|
mk 0000:61:00.0 0x030000 0x8086 0xe20b # Arc B580
|
|
mk 0000:00:02.0 0x030000 0x8086 0x7d55 # Intel iGPU, excluded
|
|
mk 0000:0c:00.0 0x030000 0x1002 0x164e 536870912 "AMD Radeon Graphics" # APU, excluded
|
|
mk 0000:03:00.0 0x030000 0x1a03 0x2000 # ASPEED BMC VGA, excluded
|
|
mk 0000:05:00.0 0x020000 0x8086 0x1521 # a NIC, not a display device
|
|
inv="$(IGNEUM_SYS_ROOT="$S" "$HERE/bin/igneum-gpus.sh" 2> "$T/notes")"
|
|
printf '%s\n' "$inv" | sed 's/^/ card /'; sed 's/^/ note /' "$T/notes"
|
|
[[ "$(printf '%s\n' "$inv" | wc -l | tr -d ' ')" == 5 ]] || fail "expected 5 cards, got: $inv"
|
|
printf '%s\n' "$inv" | grep -q '^nvidia1 nvidia 0000:21:00.0 0 1 cuda NVIDIA 0x2b85$' || fail "nvidia1 line"
|
|
printf '%s\n' "$inv" | grep -q '^amd1 amd 0000:42:00.0 16368 1 opencl AMD Radeon RX 9070 XT$' || fail "amd1 line"
|
|
printf '%s\n' "$inv" | grep -q '^intel0 intel 0000:61:00.0 0 0 opencl Intel 0xe20b$' || fail "intel0 line"
|
|
if ! { grep -q 'skip 0000:00:02.0: Intel integrated' "$T/notes" && grep -q 'skip 0000:0c:00.0: AMD integrated' "$T/notes" && grep -q 'skip 0000:03:00.0: display device of vendor 0x1a03' "$T/notes"; }; then fail "exclusions"; fi
|
|
pass "5 cards in PCI order per vendor; the iGPU, the APU and the BMC VGA excluded; the NIC ignored"
|
|
|
|
echo "== library rules on the fake inventory"
|
|
# shellcheck source=bin/igneum-rig-lib.sh
|
|
. "$HERE/bin/igneum-rig-lib.sh"
|
|
IGNEUM_ROOT="$T/root"; mkdir -p "$IGNEUM_ROOT/bin"; cp "$HERE/bin/igneum-gpus.sh" "$IGNEUM_ROOT/bin/"
|
|
export IGNEUM_SYS_ROOT="$S"
|
|
IGNEUM_ETC="$T/etc"; mkdir -p "$IGNEUM_ETC"; RIG_CONF="$IGNEUM_ETC/rig.conf"
|
|
printf 'WALLET=0xdfaea6000000000000000000000000000000002c2e\nRIG_NAME=rig1\nNETWORK=devnet\n' > "$RIG_CONF"
|
|
load_conf
|
|
[[ "$(card_identities nvidia0)" == 8 && "$(card_identities amd0)" == 8 ]] || fail "identities auto: big cards get 8"
|
|
mk 0000:22:00.0 0x030000 0x10de 0x2882 ; nv_small="$(IGNEUM_SYS_ROOT="$S" "$HERE/bin/igneum-gpus.sh" 2>/dev/null | grep -c '^nvidia')"; [[ "$nv_small" == 3 ]] || fail "third NVIDIA card"
|
|
pass "identities: auto gives 8 to a card of 8 GiB or more (and to one whose VRAM is unknown), as the app's rule"
|
|
printf 'IDENTITIES=2\n' >> "$RIG_CONF"; load_conf; [[ "$(card_identities nvidia0)" == 2 ]] || fail "IDENTITIES=2 applies"; pass "IDENTITIES=2 applies to every card"
|
|
[[ "$(card_labels_with_identities amd1 | tr '\n' ' ')" == "rig1-amd1-1 rig1-amd1-2 " ]] || fail "labels"; pass "vote-key labels rig1-amd1-1, rig1-amd1-2 (the miner's <label>-<i> rule)"
|
|
# the prover rule: no VRAM known for the fake NVIDIA cards (nvidia-smi absent) -> off by default; PROVER=on picks one
|
|
d="$(prover_decision)"; [[ "$d" == off* ]] || fail "prover default with unknown VRAM: $d"
|
|
printf 'PROVER=on\n' >> "$RIG_CONF"; load_conf; d="$(prover_decision)"; [[ "$d" == "on nvidia0 pause PROVER=on"* ]] || fail "PROVER=on: $d"
|
|
pass "prover: off by default when no NVIDIA VRAM is known; PROVER=on takes nvidia0 and pauses its miner under the 20,480 MB line"
|
|
rm -r "$P/0000:22:00.0"
|
|
printf 'PROVER=auto\nPROVER_PAUSE_MINER=never\n' >> "$RIG_CONF"; load_conf; [[ "$(prover_decision)" == off* ]] || fail "auto stays off"
|
|
pass "prover_decision output shape: $(prover_decision | cut -c1-60)..."
|
|
|
|
echo "== OpenCL index mapping on a fake --list"
|
|
fake_list="$(cat <<'L'
|
|
[0] gfx1201 | AMD Accelerated Parallel Processing (OpenCL 2.1 AMD-APP (3649.0))
|
|
GPU, vendor Advanced Micro Devices, Inc., driver 3649.0, OpenCL C 2.0, 64 compute units, 2970 MHz
|
|
[1] gfx1201 | AMD Accelerated Parallel Processing (OpenCL 2.1 AMD-APP (3649.0))
|
|
GPU, vendor Advanced Micro Devices, Inc., driver 3649.0, OpenCL C 2.0, 64 compute units, 2970 MHz
|
|
[2] Intel(R) Arc(TM) B580 Graphics | Intel(R) OpenCL Graphics (OpenCL 3.0)
|
|
GPU, vendor Intel(R) Corporation, driver 25.05.32567, OpenCL C 1.2, 160 compute units, 2850 MHz
|
|
[3] Intel(R) Arc(TM) B580 Graphics | Intel(R) OpenCL Graphics (OpenCL 3.0)
|
|
GPU, vendor Intel(R) Corporation, driver 25.05.32567, OpenCL C 1.2, 160 compute units, 2850 MHz
|
|
L
|
|
)"
|
|
[[ "$(printf '%s\n' "$fake_list" | opencl_index_for amd 1)" == 1 && "$(printf '%s\n' "$fake_list" | opencl_index_for intel 0)" == 2 && "$(printf '%s\n' "$fake_list" | opencl_index_for intel 1)" == 3 && -z "$(printf '%s\n' "$fake_list" | opencl_index_for amd 2)" ]] || fail "opencl_index_for"
|
|
pass "amd1 -> OpenCL 1, intel0 -> 2, intel1 -> 3, amd2 -> none"
|
|
|
|
echo "== the live signed manifest (Ed25519 with the OTA public key)"
|
|
unset IGNEUM_SYS_ROOT
|
|
fetch_manifest "$T/live" || fail "fetch_manifest"
|
|
manifest="$T/live/igneum-app-latest.json"
|
|
pass "signature verifies ($MANIFEST_VERIFIER): version $(manifest_field "$manifest" 'm.get("version")'), override $(manifest_override "$manifest")"
|
|
cp "$manifest" "$T/live/tampered.json"; printf ' ' >> "$T/live/tampered.json"
|
|
if verify_manifest_signature "$T/live/tampered.json" "$manifest.sig"; then fail "a tampered manifest verified"; else pass "a tampered manifest is refused"; fi
|
|
printf '%s' "$(tr -d '[:space:]' < "$manifest.sig" | sed 's/^./0/')" > "$T/live/bad.sig"
|
|
if verify_manifest_signature "$manifest" "$T/live/bad.sig"; then fail "a bad signature verified"; else pass "a bad signature is refused"; fi
|
|
if [[ -z "$(manifest_package "$manifest")" ]]; then pass "the manifest names no linux package today (sidecar mode needed, as documented)"; else pass "the manifest names a linux package: $(manifest_package "$manifest")"; fi
|
|
|
|
echo "== install-rig.sh --dry-run (downloads and verifies the live package into a scratch folder)"
|
|
IGNEUM_ROOT="$T/opt" IGNEUM_ETC="$T/etc2" IGNEUM_VAR="$T/var" IGNEUM_RUN="$T/run" "$HERE/install-rig.sh" --dry-run --yes --wallet 0xDFAEA60000000000000000000000000000002C2E --name "rig 1" --allow-sidecar-sha256 --prover auto > "$T/dry.out" 2>&1 || { cat "$T/dry.out"; fail "dry run exited non-zero"; }
|
|
grep -q 'downloaded and verified: igneum-hive-' "$T/dry.out" || { cat "$T/dry.out"; fail "no verified download in the dry run"; }
|
|
grep -q '\.sha256 sidecar agrees' "$T/dry.out" || fail "sidecar check"
|
|
if ! { grep -q 'bin/igneumd .* bytes' "$T/dry.out" && grep -q 'bin/igneum-worker-opencl .* bytes' "$T/dry.out"; }; then fail "package contents"; fi
|
|
grep -q '\[dry-run\] systemctl enable igneum-node.service' "$T/dry.out" || fail "enable step"
|
|
if ! { grep -q 'WALLET=0xdfaea600' "$T/dry.out" && grep -q 'RIG_NAME=rig-1' "$T/dry.out"; }; then fail "config step (wallet lower-cased, name sanitised)"; fi
|
|
grep -c '^\[dry-run\]' "$T/dry.out" | sed 's/^/ dry-run steps printed: /'
|
|
grep -E 'glibc igneumd|glibc igneum-miner' "$T/dry.out" | sed 's/^ */ /'
|
|
pass "dry run: preflight (fails as expected off the rig), manifest, download, verification, config, units, enable, start all printed"
|
|
echo "== self-test passed (scripts, units, inventory, rules, the live manifest and package; the rig itself is untested)"
|