igneum/proto-cuda/windows-app/start-igneum.ps1
igneum-labs 7717c4fdac Windows CI: the one-click app built on GitHub runners, no PC needed
windows.yml: parse job (every .ps1 through the Windows PowerShell 5.1 parser with a negative fixture, PSScriptAnalyzer
as warnings, parenthesis check of every .bat/.cmd with a negative fixture), build job (engine on the MSVC target,
window host through BUILD-APP.bat as it is, payload through make-payload.sh in Git Bash, installer through
build-installer.ps1, smoke run of both exes, launcher DRY_RUN, three artifacts for 90 days).
push-inputs.sh publishes payload-inputs.zip (node, miner, workers, NVRTC DLLs) to the downloads host from the Mac;
fetch-ci-artifacts.sh pulls the green run's installer and payload back into the downloads folder.
Host: --version and --help, version.h shared with host.rc. Launcher: DRY_RUN=1 prints the plan and starts nothing.

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

114 lines
6.5 KiB
PowerShell

# Igneum for Windows: the node and the miners in one window. Started by START-IGNEUM.bat, which sets the settings as
# environment variables (node: PEER_NODES, MAC_NODE, RPC_LISTEN, P2P_LISTEN, APPDIR, UNSYNCED_MINING, EXTRA_ARGS; miners:
# PAYOUT_EVM, PAYOUT_ADDRESS, VOTE, NVIDIA_DEVICE, CUDA_ARCH, AMD_VENDOR, AMD_DEVICE, MINERS, ONE_PROCESS_PER_IDENTITY,
# USE_NVIDIA, USE_AMD, NVIDIA_JOB_NONCES, AMD_JOB_NONCES, PLAIN, VCVARS, VCVARS_VER). 3 October 2026; devnet v4 (package
# 0.2.0) 4 October 2026. The functions live in igneum-common.ps1.
#
# Order:
# 1. igneumd starts (devnet v4, database under %LOCALAPPDATA%\igneum\devnet-v4, RPC 127.0.0.1:26610, p2p 0.0.0.0:26611,
# peered to the seed node and the Mac), unless a node already answers on the RPC port: then that node is used and only watched.
# 2. The GPUs and the tools are listed while the node opens its database.
# 3. The dashboard waits for the node to report synced (one reading every 5 s: "node: syncing, N blocks").
# 4. The pack is exported from the node, the workers are built, one miner per GPU vendor starts with MINERS identities.
# 5. The loop: readings every 30 s, a status block every 30 s, uploads every 60 s, restarts (seed change, crashes),
# the node restarted after a crash with a random 5 to 60 s delay; the miners are restarted once it is back and
# synced, because their gRPC client never reconnects.
# 6. Ctrl+C: the miners stop first, then the node, then the logs are uploaded one last time.
$launcherName = 'igneum'
. (Join-Path $PSScriptRoot 'igneum-common.ps1')
$script:title = 'Igneum: node and miners'
Set-NodeTarget $rpcHost $rpcPort # the miners always dial the node on this PC
Log "igneum launcher $packageVersion ($chainVersion) on $machine (run $stamp): node $rpcListen, p2p $p2pListen, peers $($peerNodes -join ' '), appdir $appDir, unsynced mining $(if ($unsyncedMining) { 'on' } else { 'off' }), identities $minersPerVendor per vendor"
Log "If Windows Firewall asks about igneumd.exe: tick Private networks and click Allow access (the Mac node dials this PC on port $p2pPort). If you clicked Cancel once, run ALLOW-FIREWALL.bat."
# DRY_RUN=1 (CI, .github/workflows/windows.yml; or a quick check on a PC): print the plan and start nothing.
if ($env:DRY_RUN -eq '1') {
Log 'DRY_RUN=1: printing the plan, starting nothing'
Log "node command: `"$nodeExe`" $((Get-NodeArgs) -join ' ')"
Log "node binary present: $(Test-Path $nodeExe); miner binary present: $(Test-Path $miner)"
$plan = Find-Hardware
Log "miners to start: $(if ($plan.Count) { $plan -join ', ' } else { 'none' }) ($minersPerVendor identities per vendor, payout $(if ($payoutEvm) { $payoutEvm } else { 'derived from the PC name' }))"
Log 'dry run done'
exit 0
}
# ---- 1. the node ----------------------------------------------------------------------------------------------------------
$script:node.on = $true
$ports = Test-NodePorts
if ($ports -eq 'external') {
Log "a node already answers on ${rpcHost}:${rpcPort}; using it (it was not started by this window and will not be stopped by it)"
Add-Event "using the node already running on ${rpcHost}:${rpcPort}" 'info'
} elseif ($ports -ne 'free') {
Log $ports
exit 1
} else {
if (-not (Test-Path $nodeExe)) { Log 'igneumd.exe is missing from this folder. Extract the whole zip first.'; exit 1 }
$ver = ''
try { $ver = (& $nodeExe --version 2>&1 | Select-Object -First 1) } catch { $ver = "could not run igneumd.exe: $_" }
Log "node binary: $nodeExe ($ver)"
if (Test-TcpPort $macHost ([int]$macPort) 1500) { Log "the Mac node answers on $macNode" } else { Log "the Mac node at $macNode does not answer right now; igneumd will keep retrying (backoff up to 8 minutes)" }
New-Item -ItemType Directory -Force -Path $appDir | Out-Null
$script:node.managed = $true
Start-Node
}
Enable-KeepAwake 'the node and the miners run'
[Console]::TreatControlCAsInput = $true
$stop = $false
$exitCode = 0
$readyCheckAt = $null
try {
# ---- 2. GPUs and tools, while the node opens its database ------------------------------------------------------------
$plan = Find-Hardware
if ($plan.Count -eq 0) { Add-Event 'no GPU worker can run (a tool is missing, see the launcher log); the node runs alone' 'error' }
if ($plan.Count -gt 0 -and -not (Confirm-Miner)) { $plan = @(); Add-Event 'no igneum-miner.exe; the node runs alone' 'error' }
# ---- 3. wait until the node is synced ----------------------------------------------------------------------------------
Start-Dashboard
if ($plan.Count -gt 0) { $script:phase = 'waiting for the node to sync' }
Log 'running. Press Ctrl+C to stop.'
Start-ChainSample
$noPeerWarned = $false
while (-not $stop) {
Start-Sleep -Milliseconds 500
if (Test-StopKey) { $stop = $true; break }
Invoke-CommonStep
if ($script:node.gaveUp) { break }
if ($plan.Count -eq 0) { continue } # node only: stay in this loop
if ($script:node.synced) { break }
$last = $script:chain.last
if (-not $noPeerWarned -and $last -and $last.peers -eq 0 -and ((Get-Date) - $started).TotalSeconds -gt 90) {
$noPeerWarned = $true
Add-Event "no peer after 90 s: is the Mac node running at $macNode? Did the firewall prompt get Allow access?" 'error'
}
}
# ---- 4. pack, workers, miners -----------------------------------------------------------------------------------------
if (-not $stop -and -not $script:node.gaveUp -and $plan.Count -gt 0) {
if (-not (Initialize-Vendors $plan)) { Add-Event 'no worker could be built (see the launcher log); the node runs alone' 'error'; $script:phase = '' }
else {
Start-AllMiners
$readyCheckAt = (Get-Date).AddSeconds(10)
Upload-Logs # first upload right after the start, so a failed start reaches the intake too
Log 'first upload done'
}
}
# ---- 5. the loop ------------------------------------------------------------------------------------------------------
while (-not $stop) {
Start-Sleep -Milliseconds 500
if (Test-StopKey) { $stop = $true; break }
Update-AllInstances
if ($readyCheckAt -and (Get-Date) -ge $readyCheckAt) { Report-WorkerReady; $readyCheckAt = $null }
Invoke-CommonStep
Update-Miners
if ($script:node.gaveUp) { break }
}
} finally {
if ($script:node.gaveUp) { $exitCode = 1 }
Stop-Everything $(if ($stop) { 'Ctrl+C: stopping' } else { '' })
}
exit $exitCode