igneum/proto-cuda/WINDOWS-MINER.md
igneum-labs 7eed16a29a Pre-public scrub, the text pass (7 October 2026, 19:5x UK): no founder name, personal login, earlier business or personal address in any tracked text file, and a gate check that keeps it so
The sweep (main's item 1): 199 tracked text files, 783 lines. The founder's full name, first name and possessive become "the founder" (sentence starts capitalised); the lowercase operating-system user name in WSL paths and commands becomes <user>; the second owner login becomes "the second owner login"; the three earlier businesses and the two other brands become "the other business", "the earlier entity", "the earlier business" and "another brand"; the Chrome profile rule names the igneum.network profile, not the profile's label. The standing commit login igneum-labs is not a founder term here: the fresh-repository step renames it in the history (docs/plans/history-rewrite.md, tools/repo/fresh-repo.sh).

The patterns never appear in plain text in the tree (a plaintext list would be the hit): tools/ci/founder-strings.b64 (perl regex, tab, a sample per row) is read by tools/ci/founder-strings-check.sh (every tracked text file, perl, known-failed first: the self-test plants each row's sample in a fixture and the hit must name the file), by tools/community/discord-hooks.mjs (the guard's founder and business rows; the test takes its fixtures from the samples) and by tools/repo/fresh-repo.sh (the business names of the rewrite rules). site/forbidden-strings.txt carries the same patterns as b64: lines, decoded case-insensitive by site/scrub.mjs and tools/ci/launch-gates-check.mjs (whose fixture now plants an encoded made-up name). The check runs in the gate's tree checks on every merge.

Not in this commit, by main's word: the 105 commit messages and 40 personal-identity commits that need the history rewrite (listed, not run), and the secrets found by gitleaks over the history (reported with owners).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-07 18:39:50 +00:00

20 KiB

Mining the Igneum devnet from a Windows PC

Package 0.3.0 (4 October 2026) ships prebuilt workers: igneum-worker-cuda.exe (driver API + NVRTC, compiles each hourly program on the card) and igneum-worker-opencl.exe; nothing to install but the driver, no CUDA Toolkit, no Visual Studio. The build path below (nvcc, cl.exe) is now the fallback for a missing worker or FORCE_BUILD=1. See windows-app/README.txt, windows-app/TEST.md and README.md (the nvrtc/ section). The rest of this page is the 3 October 2026 build-on-the-PC design and stays valid for that path.

Written 3 October 2026 for the founder's PC (RTX 5090 at about 229 MH/s on the memory-hard hash, Ryzen 9800X3D with the gfx1036 integrated AMD GPU at about 4 MH/s; docs/bench-log.md). Two ways: the packaged test (one double-click), or by hand from this repository. Both mine against node 1 on the Mac (LAN 192.168.68.64, gRPC 26610, p2p 26611), which runs igneumd --devnet (the node binary, renamed from kaspad on 3 October 2026) built with --features igneum-pow, so every block is checked with the real header-bound lottery hash.

The packaged test (igneum-mine-test.zip)

Unzip anywhere, double-click START-MINING.bat. The package is built by windows-miner/make-package.sh on the Mac from windows-miner/ (START-MINING.bat, start-mining.ps1, README.txt, upload-log.bat), proto-cuda/ (host.cu, build.bat), proto-opencl/ (host.c, build.bat) and a cross-compiled igneum-miner.exe (cargo build --release -p igneum-miner --target x86_64-pc-windows-gnu with Homebrew mingw-w64, so no Rust on the PC).

What the launcher does: lists GPUs and tools; exports the pack for the node's current epoch and day (igneum-miner.exe export-pack); builds proto-cuda\igneum-bench-cuda-devnet.exe and proto-opencl\igneum-bench-cl-devnet.exe from it (cached by the pack's seeds.txt); starts MINERS (default 8) igneum-miner mine ... --worker <exe> --exit-on-seed-change identities per GPU vendor, each with its own worker process (about 1.3 GiB of GPU memory: 256 MiB cache plus 1 GiB dataset), its own vote key and payout address derived from the PC name and the index (--payout-label nvidia-<PC>-<i>, the same on a rerun) and its own random 64-bit nonce start per job; writes a status line per identity and a total per vendor to the launcher log every 30 s; uploads the logs every 60 s under <vendor>-<PC>-<index>; on miner exit code 42 (the epoch or day seed changed) stops that vendor's identities, re-exports, rebuilds and restarts them all, logging the time (the exe cannot be rebuilt while an instance runs it); on any other exit restarts that identity after 10 s; Ctrl+C prints a summary and uploads once more. One shared worker per vendor would need a multiplexing protocol and is not built; with 8 identities the 5090 holds about 10 GiB of worker memory, the integrated AMD GPU takes the same from system RAM.

The window (since 3 October 2026, evening) is a dashboard redrawn in place every 2 s with [Console]::SetCursorPosition and Write-Host colours only: a header (the Igneum mark in the half-block font, the PC name, the node address, "connected" in green or "waiting for the node" in yellow); one card per vendor with the card name from WMI ("RTX 5090", "Radeon Graphics"), the summed hash rate of the identities' last STATUS lines in big digits, blocks found this run and in the last 10 minutes, and one cell per identity (index, state, heartbeat marker, its own MH/s); a network line; the last 5 events; a footer. States: mining (green), starting (no worker: ready line yet), warming up (ready, no STATUS line yet), rebuilding, restarting, waiting (no STATUS for 150 s and no block) in yellow, errors (a stderr line in the last 60 s) and stopped in red. The network line comes from igneum-miner watch 1 <url> started in the background every 30 s (its first line gives blocks=, daa=, difficulty=): blocks/s over the last 60 to 90 s, difficulty rising/falling/steady against the reading 5 min back (2% band), and "your share of the last 100 blocks" = accepted blocks of this PC in the time the network took to add its last 100. Found blocks are folded into one event per card per minute. The launcher log keeps every line as before (events are logged too). PLAIN=1 in the bat, a redirected output, the ISE host or a window under 60x12 give the old scrolling output.

Why some identities showed 0.00 MH/s, template age n/a (fixed 3 October 2026): the miner prints its STATUS line only after a job ends (mine_worker checks last_report once per job), and a job is --job-nonces nonces, 16,777,216 by default. An RTX 5090 identity finishes that in under a second; the gfx1036 integrated GPU at 0.17 MH/s per identity (eight share one compute unit) took 100 s, so the launcher's first status rounds found no STATUS line at all, and when one came its template was 100 s old. The parser was matching the right format. The launcher now says "warming up" until the first STATUS line, and the bat sets AMD_JOB_NONCES=2097152 (a 2^21 job, about 10 s on that GPU; NVIDIA_JOB_NONCES stays empty for the miner's default). The regex and the line it matches are quoted at the top of start-mining.ps1.

Settings at the top of START-MINING.bat: NODE_HOST, NODE_PORT, PAYOUT_ADDRESS (one address for every identity; empty = derived per identity), MINERS, NVIDIA_JOB_NONCES and AMD_JOB_NONCES (nonces per job, see above), PLAIN (1 = scrolling output instead of the dashboard), NVIDIA_DEVICE (CUDA index), CUDA_ARCH (sm_120, or native), AMD_VENDOR (the OpenCL vendor string to match, default "Advanced Micro Devices", so NVIDIA's OpenCL device is never picked for the AMD worker), AMD_DEVICE (flat index override), USE_NVIDIA, USE_AMD, VCVARS and VCVARS_VER (14.30, the MSVC v143 toolset CUDA 12.8 accepts; Visual Studio 2026's own 14.5x crashes cudafe++, see build.bat).

By hand, from the repository

Prerequisites on the PC:

  1. CUDA Toolkit 12.8 or newer (nvcc on PATH; it also ships CL\cl.h and OpenCL.lib for the AMD worker).
  2. Visual Studio 2026 with the "MSVC v143 - VS 2022 C++ x64 build tools" component (toolset 14.30).
  3. Rust, only if you build the miner on the PC: winget install Rustlang.Rustup then open a new prompt.
  4. The repository, for example git clone of igneum-network/igneum into C:\igneum (the fork is vendor\igneum-node, the hash crate igneum-pow; the miner depends on both by relative path, so keep the layout).

Open a plain command prompt and select the toolset first (every build command below assumes this):

"C:\Program Files\Microsoft Visual Studio\18\Community\VC\Auxiliary\Build\vcvarsall.bat" x64 -vcvars_ver=14.30

Build the miner (10 to 15 minutes the first time; rand, ring, secp256k1-sys and the gRPC stack build with MSVC; rocksdb is not in the miner's dependency closure, so no CMake or clang is needed; a full node build (cargo build -p kaspad, the package that produces igneumd) on Windows would need them and is not required for mining):

cd C:\igneum\vendor\igneum-node
cargo build --release -p igneum-miner

Export the pack for the node's current epoch and day, then build the workers from it:

cd C:\igneum\proto-cuda
..\vendor\igneum-node\target\release\igneum-miner.exe export-pack grpc://192.168.68.64:26610 packs\devnet
build.bat devnet sm_120                  (adds -allow-unsupported-compiler and kernel_bound.cu itself)
cd ..\proto-opencl
build.bat devnet                         (MSVC, OpenCL.lib from %CUDA_PATH%)

Run (one window per worker; each miner starts every job at its own random 64-bit nonce):

cd C:\igneum\vendor\igneum-node
target\release\igneum-miner.exe mine grpc://192.168.68.64:26610 1 100000000 rtx5090 --worker ..\..\proto-cuda\igneum-bench-cuda-devnet.exe --worker-args "--device 0" --status-secs 30 --exit-on-seed-change
target\release\igneum-miner.exe mine grpc://192.168.68.64:26610 1 100000000 gfx1036 --worker ..\..\proto-opencl\igneum-bench-cl-devnet.exe --worker-args "--vendor Advanced_Micro_Devices" --status-secs 30 --exit-on-seed-change

--exit-on-seed-change makes the miner exit with code 42 when the epoch (3,600 DAA blocks) or the day changes, because the CUDA and OpenCL workers are built ahead of time for one pack: export again, rebuild, restart (the launcher does this). The Metal worker on the Mac recompiles at runtime instead. Every found nonce is re-checked on the CPU by the miner before it is submitted; a WORKER MISMATCH line means the GPU and the CPU disagree and nothing is submitted.

The worker protocol (shared by proto-metal, proto-cuda and proto-opencl)

stdin   job <job_id> <header_prehash_hex 64> <target_hex 16> <nonce_start u64> <nonce_count u64> <epoch_seed_hex 64> <day_seed_hex>
        quit
stdout  ready <metal|cuda|opencl> <device> ...
        found <job_id> <nonce u64> <hash_hex 16>      every nonce with hash <= target (the 64-bit lane hash against target256 >> 192)
        done <job_id> <hashes> <ms>
        error <job_id> <text>

nonce_start is 32-aligned, nonce_count a multiple of 32; lane nonces are the low 32 bits, the high word enters the init words seed_words_from_bytes("igneum-block/" || prehash || nonce_hi_le32) (igneum-pow/src/bind.rs). The CUDA and OpenCL workers answer error ... seed mismatch for a job whose seeds are not the pack's.

What was and was not tested on the Mac (3 October 2026)

Tested: the Metal worker against the devnet (5,636 blocks accepted in 300 s, 0 mismatches, an epoch change crossed live); the OpenCL worker built with clang against Apple's OpenCL runtime (same bound hashes as Rust); the CUDA host with kernel_bound.cu through the clang emulation shim (emu/emu.sh igneum-devnet-emu, bench PASS and a serve job bit-exact with Rust, seed-mismatch error exercised); igneum-miner.exe cross-compiled for x86_64-pc-windows-gnu. Not tested here: nvcc and cl.exe builds, the WMI GPU listing, vcvarsall import, winget, taskkill and Ctrl+C handling in start-mining.ps1 (no PowerShell on this Mac), the dashboard drawing (cursor positioning, the half-block glyphs in the console font, the window-height fallback), and running the .exe files on Windows. The 3 October 2026 dashboard version was checked only with a bracket and quote balance pass and a read-through; the first Windows run is the real test, and PLAIN=1 is the way back if the window misbehaves.

Run your own node (igneum-node-windows.zip, 3 October 2026, evening)

The PC runs its own igneumd and the miners mine against localhost; the PC and the Mac are two peers of the same devnet. Package built by windows-node/make-package.sh from windows-node/ (START-NODE.bat, start-node.ps1, BUILD-NODE.bat, build-node.ps1, ALLOW-FIREWALL.bat, allow-firewall.ps1, README.txt), windows-miner/upload-log.bat, this file, a cross-compiled igneumd.exe and igneum-miner.exe, and src.zip: a git archive of the node worktree's HEAD (branch windows-node, commit 352495f6, the rename commit plus one miner change) under vendor/igneum-node/ with igneum-pow/ from this repository's HEAD next to it, the layout the fork's relative path dependency needs. No GitHub access from the PC; the repository stays private.

Steps on the PC: extract to a short path (C:\igneum-node), double-click START-NODE.bat, click "Allow access" on the firewall prompt (tick Private networks), then START-MINING.bat as before. BUILD-NODE.bat is only for the case where igneumd.exe is missing or has to be rebuilt from the snapshot.

The exe: cross-compiled on the Mac (the path that worked)

windows-node/cross-build.sh: cargo build --release -p kaspad -p igneum-miner --features igneum-pow --target x86_64-pc-windows-gnu with Homebrew mingw-w64 (gcc 16.2.0) and Homebrew llvm's libclang. The feared blocker, librocksdb-sys, built: bindgen parsed rocksdb/c.h once LIBCLANG_PATH pointed at /opt/homebrew/opt/llvm/lib and BINDGEN_EXTRA_CLANG_ARGS_x86_64_pc_windows_gnu gave clang the mingw target and sysroot (--target=x86_64-w64-mingw32 --sysroot=<mingw>/x86_64-w64-mingw32 -I<mingw>/x86_64-w64-mingw32/include); the bundled rocksdb and snappy C++ sources compiled with CXX_x86_64_pc_windows_gnu=x86_64-w64-mingw32-g++ through the cc crate (the crate's own x86_64-pc-windows-gnu branch defines _POSIX_C_SOURCE and _WIN32_WINNT_VISTA); zstd, lz4, bzip2, zlib, secp256k1 and mimalloc (no malloc override on Windows, the crate builds without it) compiled with the mingw gcc. First build 8 min 25 s with -j 6 at nice -n 19 on the loaded M5 Max; igneumd.exe 43.2 MB (thin LTO, stripped).

One real problem: the exe imports libstdc++-6.dll, which Windows does not have. -C link-arg=-static-libstdc++ means nothing to the gcc (C) driver rustc links with, and -C link-arg=-static does not reach it either: rustc passes the cc crate's -lstdc++ as -Wl,-Bdynamic -lstdc++, so ld takes the import library whatever comes later (both tried, two full rebuilds, the second 8 min). The package therefore ships the three mingw runtime DLLs next to the exe (libstdc++-6.dll, which itself needs libgcc_s_seh-1.dll and libwinpthread-1.dll, from the Homebrew toolchain; GCC runtime library exception). The clean fix for next time is CXXSTDLIB_x86_64_pc_windows_gnu= (empty, so the cc crate emits no -lstdc++) plus -C link-arg=-Wl,-Bstatic -C link-arg=-lstdc++ so the archive is taken; not done tonight because each flag change is a full rebuild and the founder wanted the package. The other imports are Windows' own (kernel32, ws2_32, bcrypt, the api-ms-win-crt-* UCRT forwarders the miner already imports, rpcrt4 and shlwapi for rocksdb, pdh, powrprof, psapi and iphlpapi for sysinfo).

Not tested here: running igneumd.exe on Windows (the miner exe from the same toolchain ran on the PC on 3 October). If the exe fails to start, BUILD-NODE.bat is the fallback; the PC build is upstream's own release path (rusty-kaspa ships Windows binaries built with MSVC).

BUILD-NODE.bat (the fallback, builds on the PC)

build-node.ps1 unpacks src.zip to src\, checks the tools and installs the missing ones with winget, silent: Rustlang.Rustup (stable, MSVC host), LLVM.LLVM (libclang.dll for the rocksdb bindings; LIBCLANG_PATH is set to C:\Program Files\LLVM\bin), Google.Protobuf for protoc (the gRPC and p2p crates run protoc from prost-build, no vendored copy; if winget has no such package the script downloads protoc-33.1-win64.zip from the protobuf releases into tools\protoc), and the MSVC toolset through vcvarsall.bat x64 with its default version (14.5x is fine for Rust and the cc crate; the CUDA 14.30 trick is not used). Then cargo build --release -p kaspad --features igneum-pow (the crate keeps its upstream name kaspad, the binary is igneumd.exe; without the feature the node would check blocks with the kHeavyHash stub and reject every devnet block) with a progress line every minute (elapsed, crates compiled, the crate being compiled; cargo's output in build-<stamp>.cargo.log), then copies igneumd.exe next to the bat. No CMake: every native dependency builds through the cc crate. Estimate on the 9800X3D: 15 to 25 minutes for the first build (approximate; about 500 crates plus the rocksdb C++ sources, thin LTO at the end, Defender's scan of target\), under a minute to rebuild with nothing changed. Checked only by read-through and the bracket and quote balance pass (no PowerShell on this Mac).

START-NODE.bat

Settings at the top: MAC_NODE (192.168.68.64:26611), RPC_LISTEN (127.0.0.1:26610, so the miner launcher's default port is the same on either host), P2P_LISTEN (0.0.0.0:26611), APPDIR (%LOCALAPPDATA%\igneum\devnet), UNSYNCED_MINING (0: the node hands out no template until synced, rpc/service/src/service.rs refuses get_block_template without --enable-unsynced-mining; the Mac node runs with 1 because it mines alone), STATUS_SECS, EXTRA_ARGS. The node starts as igneumd --devnet --appdir=... --rpclisten=... --listen=... --addpeer=<MAC_NODE> --nodnsseed --disable-upnp --nologfiles. It is --addpeer, not --connect: kaspad/src/daemon.rs sets the inbound limit to 0 and the outbound target to 0 when --connect is given, so the Mac could never dial the PC. --addpeer is a permanent connection request retried with backoff up to 8 minutes (components/connectionmanager/src/lib.rs), and the listener stays open.

The launcher (start-node.ps1): refuses to start when 26610 or 26611 is already in use (names the process), prints the node version, tests the Mac's p2p port once, keeps the PC awake (SetThreadExecutionState), logs the node's output to node-<stamp>.log next to the bat (a new segment per start) and its own lines to node-launcher-<stamp>.log (uploaded every 5 min with upload-log.bat under node-<PC> and nodelog-<PC>), prints a status line every 30 s read with igneum-miner.exe watch 1 grpc://127.0.0.1:26610 in the background (blocks, headers, peers, blue score, DAA, tips, difficulty, synced yes or no; the miner's watch line gained blue= and synced= after sink= in commit 352495f6, appended last so the mining launcher's regex still matches), restarts the node after a crash with a random 5 to 60 s delay (exit code and the last stderr lines logged), and stops it with taskkill on Ctrl+C (rocksdb recovers from its WAL; no graceful signal reaches a console child while the launcher owns Ctrl+C). The "extract the zip first" check in the bats escapes its brackets (^( and ^)), as cmd ends a parenthesised block at a bare ).

Firewall: the first time igneumd.exe listens on 0.0.0.0:26611, Windows Defender Firewall shows "Windows Defender Firewall has blocked some features of this app". Tick "Private networks", click "Allow access". That rule is what lets the Mac dial the PC; the PC dials the Mac anyway, so the chain syncs even without it. "Cancel" creates a block rule: ALLOW-FIREWALL.bat removes it and adds an inbound allow rule for the exe (private and domain profiles, elevated once). The gRPC port is loopback only and never prompts.

The mining launcher: NODE_HOST=auto

START-MINING.bat now sets NODE_HOST=auto and start-mining.ps1 resolves it before anything else: a TCP connect to 127.0.0.1:NODE_PORT with a 1.5 s timeout picks the node on the PC, otherwise the Mac at 192.168.68.64; the choice is on the launcher log's first line ("NODE_HOST=auto: using the node on this PC" or "nothing listens on 127.0.0.1:26610, using the Mac node"). An explicit NODE_HOST still wins. Nothing else in the launcher changed (the hot-swap work is another agent's).

Sync test on the Mac

The Windows scripts cannot run here, so the flags and the sync were tested with the worktree's native igneumd (target/release, built from the same commit) as a stand-in for the PC, 3 October 2026, 21:44 to 21:46 BST, against the live node (gRPC 26610, p2p 26611, which stayed up throughout): node A --devnet --appdir=/tmp/igneum-win-test/nodeA --rpclisten=127.0.0.1:27000 --listen=0.0.0.0:27001 --addpeer=192.168.68.64:26611 --nodnsseed --disable-upnp --nologfiles, exactly START-NODE.bat's flags with the test ports. Banner igneumd/2.1.0-2873fed; "P2P Connected to outgoing peer 192.168.68.64:26611", "IBD started" within 20 ms of the start; every header checked by igneum-lottery-v1-bound ("PoW accepted ... daa 0, 1, 2 ..."). igneum-miner watch 60 on A and the live node: at the first sample (7 s in) A had 5,144 headers and 1,386 blocks, synced=false; from the second sample on (17 s) A and the live node reported the same block count, DAA score, blue score and sink at every reading (5,157 to 5,175 blocks, blue 5,126 to 5,143, synced=true), sink identical at 5 of 6 samples (the first was mid-IBD). The live node showed peers=2 while A ran and peers=1 after it stopped. Inbound: a third node B on 27010/27011 with --addpeer=127.0.0.1:27001 connected to A's listener (A peers=2), synced to the same sink within 25 s (B also picked up the live node from A's address exchange, "outbound: 2"), so a node started with --addpeer plus --listen accepts connections, which is what the Mac needs when it dials the PC. SIGINT stopped B and A cleanly ("P2P Server stopped", "GRPC Server stopped", "igneumd has stopped"); /tmp/igneum-win-test removed afterwards. The blue= and synced= fields on the watch line are from the new miner build and parsed as the launcher does.

Not tested here: everything Windows (winget, vcvarsall, MSVC, the firewall prompt, Get-NetTCPConnection, taskkill, Ctrl+C, the random restart delay, upload-log.bat from the node launcher, running the cross-compiled exe). The scripts passed the bracket and quote balance pass (windows-node/ and the two edited lines of start-mining.ps1).