windows: plain TCP probe instead of Test-NetConnection, no progress banner

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
igneum-labs 2026-10-03 21:04:10 +00:00
parent 976c14ae1f
commit c6b48a033f
2 changed files with 60 additions and 14 deletions

View file

@ -15,8 +15,13 @@
# found, one line per identity), a network line (from igneum-miner watch every 30 s), the last 5 events and a
# footer. The launcher log keeps the full detail (a status line per identity every 30 s). PLAIN=1 in the bat, or
# a window that is not a real console, gives the old scrolling output instead.
# Every 60 s the logs are uploaded with upload-log.bat (if present); a miner that exits is restarted (code 42 =
# the epoch or day seed changed: re-export, rebuild, restart, with the rebuild time logged; anything else: after
# Every 60 s the logs are uploaded with upload-log.bat (if present). The hourly program change is a hot swap: the
# miner sends `prepare` to the worker as soon as the node reports the next seed (one lead ahead of the boundary),
# the worker builds the next program in the background and swaps at the boundary with no pause and no process
# exit (dashboard event "hourly program change, swapped with no pause (prepared in N s)"). A worker whose ready
# line has no "prepare 1" (no nvcc on PATH, an old build) falls back to the old path: a miner that exits with
# code 42 (the epoch or day seed changed) gets a re-export, a rebuild and a restart, with the rebuild time logged;
# a miner that exits for any other reason is restarted after a random 5 to 60 s delay (never in step with other rigs)
# 10 s); Ctrl+C stops everything and prints a summary.
#
# Miner log lines this script reads (vendor/igneum-node/igneum/miner/src/main.rs, mine_worker):
@ -29,13 +34,30 @@
# nothing for a while (the integrated AMD GPU took 100 s per 16.7M-nonce job on 3 Oct 2026; AMD_JOB_NONCES shortens it).
# igneum-miner watch prints: <unix> node1 blocks=N headers=N daa=N tips=N peers=N difficulty=X sink=...
$ProgressPreference = 'SilentlyContinue' # no blue progress banners (Test-NetConnection paints one over the dashboard)
$ProgressPreference = 'SilentlyContinue'
function Test-Port($h, $p) {
# Plain TCP probe. Test-NetConnection paints a blue progress banner in some consoles whatever $ProgressPreference says.
try { $c = New-Object Net.Sockets.TcpClient; $r = $c.BeginConnect($h, [int]$p, $null, $null); $ok = $r.AsyncWaitHandle.WaitOne(2000) -and $c.Connected; $c.Close(); return [bool]$ok } catch { return $false }
}
# no blue progress banners (Test-NetConnection paints one over the dashboard)
$ErrorActionPreference = 'Continue'
$root = Split-Path -Parent $MyInvocation.MyCommand.Path
Set-Location $root
$nodeHost = if ($env:NODE_HOST) { $env:NODE_HOST } else { '192.168.68.64' }
# NODE_HOST=auto (the default since 3 Oct 2026, evening): a node on this PC first (START-NODE.bat listens on
# 127.0.0.1:26610), else the Mac node. The choice is logged on the launcher's first line.
$nodeHost = if ($env:NODE_HOST) { $env:NODE_HOST } else { 'auto' }
$nodePort = if ($env:NODE_PORT) { $env:NODE_PORT } else { '26610' }
$nodeHostNote = ''
if ($nodeHost -eq 'auto') {
$nodeHost = '192.168.68.64'
$nodeHostNote = " (NODE_HOST=auto: nothing listens on 127.0.0.1:$nodePort, using the Mac node)"
try {
$tcp = New-Object Net.Sockets.TcpClient
if ($tcp.ConnectAsync('127.0.0.1', [int]$nodePort).Wait(1500) -and $tcp.Connected) { $nodeHost = '127.0.0.1'; $nodeHostNote = ' (NODE_HOST=auto: using the node on this PC)' }
$tcp.Close()
} catch { }
}
$nodeUrl = "grpc://${nodeHost}:${nodePort}"
$payout = $env:PAYOUT_ADDRESS
$nvidiaDevice = if ($env:NVIDIA_DEVICE) { $env:NVIDIA_DEVICE } else { '0' }
@ -114,7 +136,7 @@ function Add-FoundEvent([string]$card, [datetime]$at) {
while ($script:events.Count -gt 60) { $script:events.RemoveAt(0) }
}
Log "igneum-mine-test launcher $machine node $nodeUrl (run $stamp)"
Log "igneum-mine-test launcher $machine node $nodeUrl$nodeHostNote (run $stamp)"
# ---- 1. hardware and tools ---------------------------------------------------------------------------------------
@ -240,13 +262,16 @@ if (-not (Test-Path $miner)) {
if (-not (Test-Path $miner)) { Log 'the miner did not build; see the launcher log'; exit 1 }
}
try { $tnc = Test-NetConnection -ComputerName $nodeHost -Port ([int]$nodePort) -WarningAction SilentlyContinue -InformationLevel Quiet } catch { $tnc = $false }
try { $tnc = Test-Port $nodeHost $nodePort } catch { $tnc = $false }
if (-not $tnc) { Log "cannot reach the node at ${nodeHost}:${nodePort}. Is the Mac node running and on the same network?"; exit 1 }
Log "node reachable at ${nodeHost}:${nodePort}"
# ---- 3. pack and worker builds -------------------------------------------------------------------------------------------
$packDir = Join-Path $root 'proto-cuda\packs\devnet'
# Packs the miner writes for prepared seeds (one directory per epoch and day); the workers build their next kernel from them
$preparedPacks = Join-Path $root 'proto-cuda\packs\prepared'
New-Item -ItemType Directory -Force -Path $preparedPacks | Out-Null
function Export-Pack {
$t = Get-Date
@ -301,7 +326,8 @@ foreach ($name in $plan) {
$instances += @{ vendor = $name; index = $i; label = "$name-$machine$suffix"; file = "$name$suffix-$stamp"; log = $null; err = $null;
runId = "$name-$machine$suffix-$stamp"; proc = $null; restarts = 0; starts = 0; startedAt = $null; restartAt = $null; exitCode = $null;
logPos = [long]0; logRem = ''; errPos = [long]0; errRem = ''; accepted = 0; found = (New-Object System.Collections.ArrayList);
status = $null; ready = $false; readyAt = $null; lastLineAt = $null; errors = 0; lastError = ''; lastErrorAt = $null; rejected = 0 }
status = $null; ready = $false; readyAt = $null; lastLineAt = $null; errors = 0; lastError = ''; lastErrorAt = $null; rejected = 0;
prepare = $false; preparedS = $null }
}
$vendors[$name] = @{ name = $name; card = (Get-CardName $name); exe = $exe; instances = $instances; rebuilds = 0; building = $false }
}
@ -320,7 +346,9 @@ function Start-Miner($v, $inst) {
$inst.status = $null; $inst.ready = $false; $inst.readyAt = $null; $inst.restartAt = $null
# --worker-args takes ONE argument (quoted); the miner splits it on spaces and turns underscores into spaces.
# Start-Process joins the list with spaces and does not quote, so paths and the worker-args value are quoted here.
$margs = @('mine', $nodeUrl, '1', '100000000', $inst.label, '--worker', ('"' + $v.exe + '"'), '--status-secs', '30', '--exit-on-seed-change')
# --exit-on-seed-change is the fallback only: a worker that answers "prepare 1" on its ready line is never exited at a
# seed change; the miner writes the next pack under --prepare-packs and the worker builds it in the background.
$margs = @('mine', $nodeUrl, '1', '100000000', $inst.label, '--worker', ('"' + $v.exe + '"'), '--status-secs', '30', '--exit-on-seed-change', '--prepare-packs', ('"' + $preparedPacks + '"'))
if ($payout) { $margs += @('--address', $payout) } else { $margs += @('--payout-label', $inst.label) }
if ($v.name -eq 'nvidia') {
if ($nvidiaJobNonces) { $margs += @('--job-nonces', $nvidiaJobNonces) }
@ -393,6 +421,17 @@ function Update-Instance($v, $inst) {
age = [double]$Matches[9]; synced = ($Matches[10] -eq 'true') }
} elseif ($l -match ' worker: ready ') {
$inst.ready = $true; $inst.readyAt = Get-Date
$inst.prepare = ($l -match ' prepare 1')
} elseif ($l -match ' worker: prepared \S+ \S+ ([0-9.]+)') {
# The next hourly program is resident in the worker (ms from the prepare line to the answer)
$inst.preparedS = [double]$Matches[1] / 1000.0
} elseif ($l -match ' SEED CHANGE .*swapped with no pause') {
$took = if ($inst.preparedS) { ('{0:N1}' -f $inst.preparedS) } else { '?' }
Add-Event ("hourly program change, swapped with no pause (prepared in $took s) on $($v.card) miner $($inst.index)") 'ok'
} elseif ($l -match ' SEED CHANGE .*compiles inline') {
Add-Event ("hourly program change on $($v.card) miner $($inst.index): the worker was not prepared in time and compiled inline") 'info'
} elseif ($l -match ' worker exited .*restarting it in ([0-9]+) s') {
Add-Event ("$($v.card) worker $($inst.index) crashed; the miner restarts it in $($Matches[1]) s") 'error'
}
}
foreach ($l in (Read-NewLines $inst 'err')) {
@ -855,8 +894,8 @@ try {
# The whole vendor group restarts: the worker exe cannot be rebuilt while another identity still runs it
$v.rebuilds += 1
$v.building = $true
Log "$($v.name): the epoch or day seed changed (miner exit 42). Stopping its $($v.instances.Count) identities, re-exporting the pack, rebuilding the worker."
Add-Event "the hourly program changed, rebuilding the $($v.card) worker" 'build'
Log "$($v.name): the epoch or day seed changed (miner exit 42: fallback path, this worker has no prepare support). Stopping its $($v.instances.Count) identities, re-exporting the pack, rebuilding the worker."
Add-Event "the hourly program changed, rebuilding the $($v.card) worker (fallback: no prepare support)" 'build'
Draw-Dashboard # the build blocks this loop; show the state first
Stop-Vendor $v
foreach ($inst in $v.instances) { Update-Instance $v $inst } # the last lines of the old log segments
@ -879,9 +918,11 @@ try {
if ($inst.proc -and $inst.proc.HasExited -and -not $inst.restartAt) {
$inst.restarts += 1
$inst.exitCode = Get-ExitCode $inst
$inst.restartAt = (Get-Date).AddSeconds(10)
Log "$($inst.label): miner exited unexpectedly with code $($inst.exitCode); restarting in 10 s (restart $($inst.restarts))"
Add-Event "$($v.card) miner $($inst.index) stopped (code $($inst.exitCode)), restarting in 10 s" 'error'
# A random delay so a crash that hits every rig at once never restarts them at once
$delay = Get-Random -Minimum 5 -Maximum 61
$inst.restartAt = (Get-Date).AddSeconds($delay)
Log "$($inst.label): miner exited unexpectedly with code $($inst.exitCode); restarting in $delay s (restart $($inst.restarts))"
Add-Event "$($v.card) miner $($inst.index) stopped (code $($inst.exitCode)), restarting in $delay s" 'error'
}
if ($inst.restartAt -and (Get-Date) -ge $inst.restartAt) {
Update-Instance $v $inst

View file

@ -20,6 +20,11 @@
# connect in. The Mac node's inbound limit is the default 128.
$ProgressPreference = 'SilentlyContinue'
function Test-Port($h, $p) {
# Plain TCP probe. Test-NetConnection paints a blue progress banner in some consoles whatever $ProgressPreference says.
try { $c = New-Object Net.Sockets.TcpClient; $r = $c.BeginConnect($h, [int]$p, $null, $null); $ok = $r.AsyncWaitHandle.WaitOne(2000) -and $c.Connected; $c.Close(); return [bool]$ok } catch { return $false }
}
$ErrorActionPreference = 'Continue'
$root = Split-Path -Parent $MyInvocation.MyCommand.Path
Set-Location $root
@ -95,7 +100,7 @@ foreach ($port in @([int]$rpcPort, [int]$p2pPort)) {
} catch { }
}
try { $macUp = Test-NetConnection -ComputerName $macHost -Port ([int]$macPort) -WarningAction SilentlyContinue -InformationLevel Quiet } catch { $macUp = $false }
try { $macUp = Test-Port $macHost $macPort } catch { $macUp = $false }
if ($macUp) { 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)" }
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."