igneum/packaging/mac/README.md
igneum-labs 38380d9035 Release: devnet v4 cut-over staged (Windows 0.2.0 packages, Mac app 0.2.0, seed igneumd-v4 unit, runbook)
Windows combined package 0.2.0 (proto-cuda/windows-app): v4 exes from target-integration, peers = seed then Mac,
fresh appdir devnet-v4, one miner and one worker per card with --identities 8, --evm-address (PAYOUT_EVM or derived
per vendor from the PC name), voting on (VOTE=0 opts out), --prepare-packs for the hot swap with --exit-on-seed-change
as the fallback, --yes on the node, STATUS regex tolerant of the v4 now= segment, version in the dashboard header.
Mac app 0.2.0 (packaging/mac): v4 binaries, Metal worker rebuilt for macOS 11, data folder devnet-v4, EVM payout,
identities in one process, synced= flag honoured. Seed (infra/seed-nodes): stage-v4.sh builds v4 on the VM as a
niced, memory-capped transient service and installs a disabled igneumd-v4 unit with a fresh data dir; switch-v4.sh
swaps the units (--back reverses); health.sh reports active-v4. Runbook: docs/plans/cutover-2026-10-04.md.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-04 01:48:56 +00:00

123 lines
9.9 KiB
Markdown

# Igneum Miner for Mac (packaging/mac)
A DMG a miner can open on an Apple silicon Mac to run a node and the Metal miner, and show up on igneum.network/live.
Built 3 October 2026 from the binaries already compiled in this repo; nothing is compiled here except the Metal worker
(one `swiftc` call, about 7 s). Renamed from "Igneum Devnet" to "Igneum Miner" the same evening (bundle id
network.igneum.miner, version 0.1.0); the devnet is still the only network and its name appears in the status lines,
never in a window title. Version 0.2.0 (4 October 2026) is the devnet v4 build: a new chain from genesis, so the data
folder moved to `devnet-v4`; the miner takes an EVM payout address (`--evm-address`, `PAYOUT_EVM`), runs every identity
through one process (`--identities`), votes on finality by default (`VOTE=0` turns it off) and hot-swaps the hourly
program through the worker's `prepare` command.
## Build
packaging/mac/build-dmg.sh
Output: `packaging/mac/dist/Igneum-Miner-0.2.0.dmg` (about 16 MB, lzfse). The script takes
`vendor/igneum-node/target-integration/release/igneumd` and `igneum-miner` (the devnet-v4 integration build of
`vendor/igneum-node-v4` at dc749905, `NODE=` and `MINER=` override) and rebuilds the Metal worker from
`proto-metal/main.swift` (the hot-swap source) with `-target arm64-apple-macos11`, so it loads on any Apple silicon macOS
and not only on the build machine's (the committed `proto-metal/igneum-bench-hotswap` says minos 16.0; `REBUILD_WORKER=0`
ships it as is, `WORKER=` names another one). It copies the three into the bundle, strips the copies and signs them ad
hoc again (strip invalidates the linker signature and arm64 macOS refuses an unsigned binary), and checks that each copy
still runs, that the worker says `prepare 1` and that the miner is the v4 one (`--evm-address` in its usage). The
originals are untouched. The icon is `brand/icons/igneum.icns` and the DMG art `brand/icons/dmg-background.tiff`
(both from `python3 brand/icons/make-icons.py`). The image is laid out by `dmgbuild` (`pip3 install dmgbuild`, settings in
`dmg/settings.py`: volume "Igneum Miner", hidden `.VolumeIcon.icns` with the custom-icon flag, background, icon slots app
(165,130), Applications (495,130), README and Stop command on the row below, no Finder scripting needed). Without dmgbuild
the script builds a plain hdiutil image and says so. `build/` and `dist/` are ignored by git.
## What is on the DMG
| Item | What it is |
|---|---|
| `Igneum Miner.app` | the launcher bundle (below) |
| `README.txt` | 10 lines for the miner (`dmg/README.txt`), with the seed line |
| `Stop Igneum Miner.command` | stops a copy whose window was closed without Ctrl+C (`app/Stop Igneum Miner.command`) |
| `Applications` | symlink, for the drag |
## The app bundle
Igneum Miner.app/Contents/MacOS/Igneum Miner app/launcher.sh: removes quarantine from Resources, opens the script in Terminal
Igneum Miner.app/Contents/Resources/igneum-miner.sh the run script (app/igneum-miner.sh); sets the Terminal title "Igneum Miner"
Igneum Miner.app/Contents/Resources/bin/igneumd, igneum-miner, igneum-bench
Igneum Miner.app/Contents/Resources/igneum.icns
Igneum Miner.app/Contents/Info.plist app/Info.plist (CFBundleVersion = build stamp, LSMinimumSystemVersion 11.0)
Why a shell launcher and not an AppleScript applet: `open -a Terminal <script>` needs no Automation consent;
`tell application "Terminal" to do script` would prompt "Igneum Miner wants to control Terminal" on first run.
The launcher strips `com.apple.quarantine` from its own Resources first, because after Gatekeeper lets the app
through, every binary inside would still be checked on its first exec and refused as unidentified. That only works on
a writable volume, so the app refuses (with a dialog) to run straight from the DMG.
## The run script (settings at the top)
| Variable | Default | Meaning |
|---|---|---|
| `SEED_PEERS` | `188.245.5.161:26611,192.168.68.64:26611` | the seed node, then the Mac node on the project lead's LAN; comma list |
| `MINERS` | `1` | miner identities, all inside one miner process (`--identities`); 0 = node only. One worker owns the whole GPU |
| `PAYOUT_EVM` | empty | EVM payout address for the block rewards; empty = 20 bytes of SHA-256 over `igneum-evm-payout-v0:mac-<hostname>`, printed at start |
| `VOTE` | `1` | finality voting; 0 adds `--no-vote` |
| `STATUS_SECS`, `UPLOAD_SECS` | 30, 60 | status line and log upload periods |
| `IGNEUM_RPC_PORT`, `IGNEUM_P2P_PORT` | 26610, 26611 | environment overrides (tests) |
| `IGNEUM_DATA`, `IGNEUM_LOGS` | `~/Library/Application Support/Igneum/devnet-v4`, `~/Library/Logs/Igneum` | the only places written outside the bundle (0.1.0 wrote `devnet`, left alone) |
Order: checks (arm64, binaries, ports, no second copy via the pid file) > `caffeinate -dims -w <launcher>` >
`igneumd --devnet --appdir ... --rpclisten 127.0.0.1:26610 --listen 0.0.0.0:26611 --addpeer <each seed> --nodnsseed
--disable-upnp --nologfiles` > every 5 s `igneum-miner watch 1` until synced (peers > 0, blocks >= headers > 1 and
the count moving between readings, or stable for 60 s; this build's watch line has no synced= field) > `igneum-miner
mine grpc://127.0.0.1:26610 1 100000000 mac-<hostname> --worker igneum-bench --status-secs 30 --exit-on-seed-change
--payout-label mac-<hostname>` > loop: status every 30 s, uploads every 60 s (labels `mac-<host>`, `nodelog-mac-<host>`,
`miner-mac-<host>`, run id `mac-<host>-<stamp>`), node crash restarted after 5 to 60 s with the miners stopped until it
is synced again, miner exit 42 (hourly program change) restarted at once, other miner exits after 5 to 60 s.
Stopping: Ctrl+C (SIGINT), the window closing (SIGHUP) or SIGTERM set a flag; the loop then stops the miners and their
workers (TERM, 8 s, KILL), the node (TERM, 30 s, KILL), caffeinate, uploads the logs once more and prints a summary.
Children are started with SIGHUP ignored (bash already makes background children of a script ignore SIGINT), so the
launcher controls the order. `igneum-miner.sh --stop` and `Stop Igneum Miner.command` signal the launcher from the pid file
and fall back to `pkill -f 'Igneum Miner.app/Contents/Resources/bin/'` (the bundle path only, never a bare name).
The miner identity shows on igneum.network/live as the first 8 hex of its vote key hash; the window prints it.
## Gatekeeper (expected on macOS 15 and 26)
The app is unsigned and not notarized. Double-click gives "Apple could not verify ... is free of malware" with no
Open button (unsigned and not notarized until the foundation has an Apple developer account). Right-click > Open offers Open on older systems; on macOS 15 and later the route is System Settings >
Privacy & Security > "Open Anyway" (the button appears after the first refusal), then open the app again. Both are in
README.txt. Removing the flag by hand also works: `xattr -dr com.apple.quarantine "/Applications/Igneum Miner.app"`.
The first time igneumd listens on 0.0.0.0:26611 the macOS firewall (if on) asks to allow incoming connections; Allow.
## Test (3 October 2026, this Mac, macOS 26.6.2, M5 Max)
Mounted the DMG and ran the script from the mounted bundle with `SEED_PEERS=127.0.0.1:26611 MINERS=1
IGNEUM_RPC_PORT=27310 IGNEUM_P2P_PORT=27311 IGNEUM_DATA=/tmp/igneum-mac-test/data IGNEUM_LOGS=/tmp/igneum-mac-test/logs`
(the live node as the seed, own node on 27300+, the Metal miner against that node).
| Check | Result |
|---|---|
| fresh database to synced | 22 s (0 blocks, 5,017 headers at 5 s; 9,988 blocks at 22 s); existing database 12 to 13 s |
| miner | started at sync, id 0aa660fe printed, first block 6 to 11 s later, 24 accepted blocks in 3 min 17 s, 0 rejected, 0 mismatched |
| rate | 16 to 18 MH/s wall, 40 MH/s inside jobs (the Mac was running two cargo builds and a census) |
| status line | every 30 s: `status: accepted 22 blocks, 17.76 MH/s, template 0.89 s old \| node 10205 blocks, 1 peers, synced \| up 00:03:02` |
| uploads | 12 uploads in the intake under run id mac-MacBook-Pro-20261003-224420 (`node tools/logs.mjs`) |
| live page | 0aa660fe listed in igneum.network/api/live miners within a minute |
| Ctrl+C (SIGINT) | miners, worker, node gone in 5 s, summary printed, no stray process, pid and run files removed, ports free |
| SIGTERM | same, 4 s |
| Stop Igneum.command | node-only run stopped in 2 s; a second run says "Igneum is not running" |
Two things the test caught and fixed: an unquoted `$NODE_EXE` in the version line (the bundle path has a space), and
`uname -m` as the Apple silicon check (an x86_64 process, Rosetta, reports x86_64; now `sysctl hw.optional.arm64`).
Note for harness tests: a script started as a background job of a non-interactive shell has SIGINT ignored at entry
and cannot trap it; run it in the foreground or through `perl -e '$SIG{INT}="DEFAULT"; exec ...'`.
## Test of the renamed bundle (3 October 2026, 23:20, this Mac)
Mounted `Igneum-Miner-0.1.0.dmg` (16,994,318 bytes): volume "Igneum Miner", `.VolumeIcon.icns` present and the custom-icon
flag set on the root (`xattr -px com.apple.FinderInfo`), `.DS_Store` with the four icon slots, `.background.tiff`. Copied the
app out and ran its script in a real Terminal window (`open -a Terminal`, as the launcher does) with `MINERS=0
SEED_PEERS=127.0.0.1:26611 IGNEUM_RPC_PORT=27400 IGNEUM_P2P_PORT=27401` and scratch data and log folders: the window title
read "joshm, Igneum Miner, sleep, igneum-miner.sh, 80x24" (Terminal joins those with its own dashes), the first two log lines are the version line and the seed
line, synced in 77 s (11,995 blocks, the Mac was under load 25+), `igneum-miner.sh --stop` stopped it in 4 s through the
pid file, no leftover process, ports free. The live node on 26610/26611 was only a peer. Note: `proto-metal/igneum-bench`
carries `minos 16.0` in its load command (built without a `-target`), so on a Mac older than macOS 26 the worker may refuse
to load even though the bundle says 11.0; a rebuild with `-target arm64-apple-macos11` fixes that.