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>
123 lines
9.9 KiB
Markdown
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.
|