# Proving v1, the segment-aligned prover on PC 2 (6 October 2026, the project lead: "proving v1 is active but has proven zero # segments, and cannot with one prover; find a way to solve this"). A signed `run` job (shell powershell, not # elevated; the app keeps mining; the app's own prover is switched OFF for the run through /api/prove and ON again # at the end; the live /opt/igneum host is untouched: this build lands in /opt/igneum-segal). # # What it does, for RUN_MINUTES, exactly what the app's segment path (app/igneum-app/src/prover.rs, pick_segment and # prove_segment) does: # 1. the node's v1 status and the work list (igneum_getAssignedShards, lookback 600) grouped into whole untouched # segments (every block present, every shard open, unpaid, not in our pool); the newest one inside its deadline by # the margin (240 DAA, or 1.5x the last segment's time) is claimed; the app ranks by FNV of (first, key) for the # multi-prover spread, which with one prover changes nothing but the order # 2. the segment statement: executed, pending; fresh when the previous segment is not paid and no verified record of # it waits in the pool, else chained to the previous proof (--prev) when the pool holds it # 3. one export (igneum_exportSegments 0..last), one fixture per block, one host run (--mode chain --save-shards # [--prev]) with a 1-s nvidia-smi sampler underneath # 4. every shard record signed (igneum-miner.exe sign-record) and submitted (igneum_submitProofRecord), then the # segment record (sign-segment-record, igneum_submitSegmentRecord) # 5. the paid state of every submitted segment polled each pass (igneum_getSegmentRecords: carried, paid) # Every number is a RESULT line. The miner's hash rate comes from the app log's "status: ... MH/s" lines (every 30 s), # the 30 minutes before the job against the run. Card keys, when needed, come from settings.json, never /api/state # (that reply is "{}" on 0.3.11 once paid_wei passes u64::MAX; fixed in 6714a45). $ErrorActionPreference = 'Continue' $RunMinutes = 30 function Stamp { (Get-Date).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssZ') } $app = if ($env:IGNEUM_APP_DIR) { $env:IGNEUM_APP_DIR } else { Join-Path $env:LOCALAPPDATA 'igneum\app' } $urlFile = Join-Path $app 'app.url' $base = if (Test-Path $urlFile) { (Get-Content $urlFile -Raw).Trim().TrimEnd('/') } else { '' } function Post($path, $obj) { try { (Invoke-RestMethod -Method Post -Uri "$base$path" -ContentType 'application/json' -Body ($obj | ConvertTo-Json -Compress) -TimeoutSec 10) | ConvertTo-Json -Compress } catch { "error: $_" } } function Rpc($method, $params) { try { (Invoke-RestMethod -Method Post -Uri "http://127.0.0.1:$evmPort" -ContentType 'application/json' -Body (@{jsonrpc='2.0'; id=1; method=$method; params=$params} | ConvertTo-Json -Compress -Depth 8) -TimeoutSec 120).result } catch { $script:rpcErr = "$_"; $null } } function RpcRaw($method, $params) { try { Invoke-RestMethod -Method Post -Uri "http://127.0.0.1:$evmPort" -ContentType 'application/json' -Body (@{jsonrpc='2.0'; id=1; method=$method; params=$params} | ConvertTo-Json -Compress -Depth 8) -TimeoutSec 120 } catch { $script:rpcErr = "$_"; $null } } function Hex($v) { if ($null -eq $v) { return 0 }; if ($v -is [string] -and $v.StartsWith('0x')) { return [Convert]::ToInt64($v.Substring(2), 16) }; return [int64]$v } $job = $env:IGNEUM_JOB_DIR if (-not $job) { $job = Join-Path $env:TEMP 'igneum-segments' } New-Item -ItemType Directory -Force -Path $job | Out-Null $jobStart = Get-Date "RESULT start $(Stamp) app_dir=$app base_len=$($base.Length) job=$job run_minutes=$RunMinutes" $evmPort = $null foreach ($p in 26790, 26800, 26810) { $evmPort = $p; if (Rpc 'igneum_getProvingStatus' @()) { break }; $evmPort = $null } if (-not $evmPort) { "RESULT refused $(Stamp) no node EVM RPC on 26790/26800/26810: $script:rpcErr"; exit 1 } # the app's miner (the signer) and its label, the payout address $mp = Get-CimInstance Win32_Process | Where-Object { $_.Name -like 'igneum-miner*' -and $_.CommandLine -like '* mine *' } | Select-Object -First 1 $minerExe = if ($mp) { $mp.ExecutablePath } else { $null } if (-not $minerExe -or -not (Test-Path $minerExe)) { $cand = Get-ChildItem -Path (Split-Path $app -Parent) -Recurse -Filter 'igneum-miner.exe' -ErrorAction SilentlyContinue | Select-Object -First 1 if ($cand) { $minerExe = $cand.FullName } } if (-not $minerExe) { "RESULT refused $(Stamp) no igneum-miner.exe found (the signer)"; exit 1 } $settingsRaw = Get-Content (Join-Path $app 'settings.json') -Raw $payout = [regex]::Match($settingsRaw, '"address":\s*"(0x[0-9a-fA-F]{40})"').Groups[1].Value if ($payout.Length -ne 42) { "RESULT refused $(Stamp) no payout address in settings.json"; exit 1 } $identities = 1; $im = [regex]::Match($settingsRaw, '"nvidia:[^"]*":\s*\{[^}]*"identities":\s*(\d+)'); if ($im.Success) { $identities = [int]$im.Groups[1].Value } $machineId = ''; $mm = [regex]::Match($settingsRaw, '"machine_id":\s*"([0-9a-f]+)"'); if ($mm.Success) { $machineId = $mm.Groups[1].Value } if (-not $machineId) { $mf = Join-Path $app 'machine-id'; if (Test-Path $mf) { $machineId = (Get-Content $mf -Raw).Trim() } } if (-not $machineId -and $job -match '([0-9a-f]{8})') { $machineId = $Matches[1] } $id8 = if ($machineId.Length -ge 8) { $machineId.Substring(0, 8) } else { '1ccfe586' } $label = if ($identities -gt 1) { "win-$id8-1-1" } else { "win-$id8-1" } $chain = 'igneum-devnet' # the app's chain_name with no devnet suffix (IGNEUM_APP_DEVNET_SUFFIX unset on the fleet) $keyHash = (& $minerExe key-hash $label 2>$null | Select-Object -Last 1).Trim() if ($keyHash -and -not $keyHash.StartsWith('0x')) { $keyHash = "0x$keyHash" } "RESULT signer $(Stamp) miner=$minerExe label=$label key=$keyHash chain=$chain payout=$payout identities=$identities" if (-not $keyHash -or $keyHash.Length -lt 64) { "RESULT refused $(Stamp) key-hash gave nothing"; exit 1 } # the live prover off for the run: its sp1-gpu-server would be shared with ours (same socket, its environment) "RESULT prove_off $(Stamp) $(Post '/api/prove' @{on=$false})" Start-Sleep -Seconds 5 # --- WSL side: the package built into /opt/igneum-segal (root, the warm target of the live build), the segment runner $pkg = Join-Path $env:LOCALAPPDATA 'igneum\prove\igneum-prove-wsl2-segal\igneum-prove-wsl2' if (-not (Test-Path $pkg)) { $pkg = Join-Path $env:LOCALAPPDATA 'igneum\prove\igneum-prove-wsl2-segal' } "RESULT package $(Stamp) $pkg exists=$(Test-Path (Join-Path $pkg 'package'))" function WslPath($p) { $w = (& wsl.exe -d Ubuntu-24.04 -u root -- wslpath -a ($p -replace '\\', '/') 2>$null); if ($w) { ($w -replace "`0", '').Trim() } else { '/mnt/c' + ($p.Substring(2) -replace '\\', '/') } } $pkgW = WslPath $pkg; $jobW = WslPath $job $prep = @' set -uo pipefail export PATH="$HOME/.cargo/bin:$HOME/.sp1/bin:$PATH" CUDA_DIR="$(ls -d /usr/local/cuda-12.* 2>/dev/null | sort -V | tail -1 || true)"; [ -n "$CUDA_DIR" ] && export PATH="$CUDA_DIR/bin:$PATH" && export LD_LIBRARY_PATH="$CUDA_DIR/lib64:/usr/lib/wsl/lib:${LD_LIBRARY_PATH:-}" stamp() { date -u +%Y-%m-%dT%H:%M:%SZ; } PKG="$1" DEST="$HOME/igneum-prove-segal"; LIVE_TARGET="$HOME/igneum-prove/proving/igneum-prove/target" mkdir -p "$DEST" rsync -a --delete --exclude target "$PKG/package/" "$DEST/" find "$DEST" -name target -prune -o -type f -exec touch {} + 2>/dev/null grep -o '"program_id": "0x[0-9a-f]*"' "$DEST/proving/igneum-prove/elf/manifest.json" | sed 's/^/RESULT manifest /' cd "$DEST/proving/igneum-prove" t0=$(date +%s) if ! CARGO_TARGET_DIR="$LIVE_TARGET" cargo build --release -p igneum-prove-export -p igneum-prove-host --features igneum-prove-host/cuda 2>&1 | tail -3; then echo "RESULT build FAILED"; exit 1; fi echo "RESULT build $(stamp) exit 0 in $(( $(date +%s) - t0 )) s" mkdir -p /opt/igneum-segal && cp "$LIVE_TARGET/release/igneum-prove-host" "$LIVE_TARGET/release/igneum-prove-export" /opt/igneum-segal/ H=/opt/igneum-segal/igneum-prove-host; X=/opt/igneum-segal/igneum-prove-export echo "RESULT installed $(sha256sum $H | cut -c1-16) host, $(sha256sum $X | cut -c1-16) export; live /opt/igneum untouched: $(sha256sum /opt/igneum/igneum-prove-host | cut -c1-16)" $H --mode id | sed 's/^/RESULT segal-host /' echo "RESULT gpu_server_before $(stamp) running=$(pgrep -x sp1-gpu-server | wc -l) socket=$(ls -la /tmp/sp1-cuda-0.sock 2>/dev/null || echo none)" # the root-socket rule (tools/ci/prover-socket-check.sh): this run is root; the app's prover is off, so its server goes too pkill -x sp1-gpu-server; sleep 1; rm -f /tmp/sp1-cuda-*.sock echo "RESULT socket_start $(stamp) servers=$(pgrep -x sp1-gpu-server | wc -l) sockets=$(ls /tmp/sp1-cuda-*.sock 2>/dev/null | wc -l)" '@ # bash seg.sh [prev file]: unwrap the export, cut the blocks, run the chain with the sampler $seg = @' set -uo pipefail export PATH="$HOME/.cargo/bin:$HOME/.sp1/bin:$PATH" CUDA_DIR="$(ls -d /usr/local/cuda-12.* 2>/dev/null | sort -V | tail -1 || true)"; [ -n "$CUDA_DIR" ] && export PATH="$CUDA_DIR/bin:$PATH" && export LD_LIBRARY_PATH="$CUDA_DIR/lib64:/usr/lib/wsl/lib:${LD_LIBRARY_PATH:-}" stamp() { date -u +%Y-%m-%dT%H:%M:%SZ; } JOB="$1"; FIRST="$2"; LAST="$3"; PAYOUT="$4"; PREV="${5:-}" H=/opt/igneum-segal/igneum-prove-host; X=/opt/igneum-segal/igneum-prove-export D="$JOB/seg-$FIRST"; mkdir -p "$D" t0=$(date +%s.%N) python3 -c "import json; d=json.load(open('$D/seq.json')); json.dump(d['result'], open('$D/export.json','w'))" || { echo "RESULT seg $FIRST unwrap FAILED"; exit 1; } LIST="" for n in $(seq $FIRST $LAST); do if ! $X "$D/export.json" $n "$D/block-$n.json" --source "PC 2 live devnet, segment-aligned prover" >"$D/export-$n.log" 2>&1; then echo "RESULT seg $FIRST cut $n FAILED: $(tail -1 "$D/export-$n.log")"; exit 1; fi LIST="$LIST${LIST:+,}$D/block-$n.json" done CUT=$(python3 -c "import time; print(round(time.time() - $t0, 1))") echo "RESULT seg $FIRST cut $(stamp) $LAST blocks in $CUT s" nvidia-smi --query-gpu=timestamp,index,memory.used,utilization.gpu,power.draw --format=csv,noheader,nounits -l 1 > "$D/smi.csv" 2>/dev/null & SMI=$! t1=$(date +%s.%N) PREVARG=""; [ -n "$PREV" ] && PREVARG="--prev $PREV" SP1_PROVER=cuda RUST_LOG=off $H --mode chain --chain "$LIST" --prover "$PAYOUT" --save-shards $PREVARG --out "$D/chain-results.json" >"$D/chain.log" 2>"$D/chain.err" RC=$? WALL=$(python3 -c "import time; print(round(time.time() - $t1, 1))") kill $SMI 2>/dev/null; sleep 1 grep -E "^RESULT (chain block|chain:|chain prev|setup)" "$D/chain.log" | sed "s/^/seg $FIRST: /" awk -F', *' '{ if ($3+0 > max) max=$3+0; u+=$4; n++ } END { if (n) printf "RESULT seg FIRST gpu samples=%d memory_used_max_mib=%d util_mean_pct=%.1f\n", n, max, u/n }' "$D/smi.csv" | sed "s/FIRST/$FIRST/" echo "RESULT seg $FIRST chain $(stamp) exit $RC wall $WALL s" if [ $RC -ne 0 ]; then tail -4 "$D/chain.err" | sed "s/^/seg $FIRST stderr: /"; exit 1; fi # the submit bodies: one JSON-RPC request per shard record and one for the segment, the proof bytes as hex python3 - "$D" <<'PY' import json, sys, os d = sys.argv[1] r = json.load(open(os.path.join(d, 'chain-results.json'))) recs = [] for b in r['blocks']: for s in b.get('shard_records', []): recs.append(s) json.dump(recs, open(os.path.join(d, 'shard-records.json'), 'w')) print('RESULT seg %s records %d shard records, segment chain_len %s, proof %s bytes' % (r['first'], len(recs), r['segment_chain_len'], r['segment_proof_bytes'])) PY '@ # bash body.sh : the JSON-RPC body with the proof as hex $body = @' set -u python3 - "$1" "$2" "$3" "$4" <<'PY' import json, sys, binascii proof = '0x' + binascii.hexlify(open(sys.argv[1], 'rb').read()).decode() json.dump({'jsonrpc': '2.0', 'id': 1, 'method': sys.argv[3], 'params': [{'record': sys.argv[2], 'proof': proof}]}, open(sys.argv[4], 'w')) PY '@ # bash unhex.sh : a hex string (0x...) to bytes $unhex = @' set -u python3 -c "import sys,binascii; h=open(sys.argv[1]).read().strip(); h=h[2:] if h.startswith('0x') else h; open(sys.argv[2],'wb').write(binascii.unhexlify(h))" "$1" "$2" '@ foreach ($pair in @(@('prep.sh', $prep), @('seg.sh', $seg), @('body.sh', $body), @('unhex.sh', $unhex))) { [IO.File]::WriteAllText((Join-Path $job $pair[0]), ($pair[1] -replace "`r`n", "`n"), (New-Object System.Text.UTF8Encoding $false)) } function Wsl { param([string[]]$a) & wsl.exe -d Ubuntu-24.04 -u root -- bash @a 2>&1 | ForEach-Object { ($_ -replace "`0", '') } } Wsl @("$jobW/prep.sh", $pkgW) if (-not (Test-Path (Join-Path $job 'prep.sh'))) { "RESULT refused $(Stamp) prep.sh missing"; exit 1 } # --- the app log's miner rate before the run (baseline): "status: ... MH/s" every 30 s $logDir = Join-Path $app 'logs' function RateLines($since, $until) { $out = @() $files = @(Get-ChildItem -Path $logDir, (Join-Path (Split-Path $app -Parent) 'logs'), $app -Filter '*.log' -ErrorAction SilentlyContinue | Where-Object { $_.LastWriteTime -gt (Get-Date).AddHours(-3) } | Sort-Object LastWriteTime -Descending | Select-Object -First 4) if ($files.Count -eq 0) { "RESULT rate_files none under $logDir, $(Join-Path (Split-Path $app -Parent) 'logs'), $app" } foreach ($f in $files) { foreach ($l in (Get-Content $f.FullName -ErrorAction SilentlyContinue | Where-Object { $_ -match '^(\d{10}) status: .* ([\d.]+) MH/s' })) { $t = [int64]$Matches[1]; if ($t -ge $since -and $t -le $until) { $out += [double]$Matches[2] } } } return $out } function Epoch($d) { [int64](($d.ToUniversalTime()) - (Get-Date '1970-01-01')).TotalSeconds } $t0 = Epoch $jobStart $before = RateLines ($t0 - 1800) $t0 if ($before.Count) { $m = $before | Measure-Object -Average -Minimum -Maximum; "RESULT rate_before $(Stamp) n=$($before.Count) mean=$([math]::Round($m.Average,2)) min=$($m.Minimum) max=$($m.Maximum) MH/s (the app log's status lines, the 30 min before the job)" } else { "RESULT rate_before $(Stamp) no status lines found in $logDir" } # --- the loop $submittedSegments = @{} # first -> @{last; aggWei; at} $attempted = @{} $lastSegSecs = 0 $n = 1; $start = 0; $unproven = 600 $passes = 0; $claimed = 0; $submitted = 0; $shardsAccepted = 0; $shardsRefused = 0 $runStart = Get-Date function Candidates { $st = Rpc 'igneum_getProvingStatus' @() if (-not $st -or -not $st.v1 -or -not $st.v1.active -or -not $st.v1.start) { return @() } $script:start = Hex $st.v1.start; $script:n = [math]::Max(1, (Hex $st.v1.segmentBlocks)); $script:unproven = Hex $st.v1.unprovenDaa $tipDaa = Hex $st.tipDaa $work = Rpc 'igneum_getAssignedShards' @(@($keyHash), 600) if (-not $work) { return @() } $by = @{} foreach ($w in $work) { [int64]$num = Hex $w.number; if ($num -lt $script:start) { continue }; if (-not $by.ContainsKey($num)) { $by[$num] = @() }; $by[$num] += $w } "RESULT worklist $(Stamp) entries=$(@($work).Count) blocks=$($by.Count) start=$($script:start) n=$($script:n) tipDaa=$tipDaa" $need = [math]::Max(240, [math]::Ceiling($lastSegSecs * 1.5)) $segs = @() $seen = @{} foreach ($num in ($by.Keys | Sort-Object)) { # [int64] throughout: [math]::Floor gives a double, and a double never matches an int64 hashtable key (job b, # 07:20Z to 07:50Z: every segment "not whole", 88 passes, nothing claimed) [int64]$k = [math]::Floor(($num - $script:start) / $script:n); [int64]$first = $script:start + $k * $script:n; [int64]$last = $first + $script:n - 1 if ($seen.ContainsKey($first)) { continue }; $seen[$first] = $true if ($attempted.ContainsKey($first)) { continue } $whole = $true; $shards = @(); $lastDaa = 0; $wei = 0 for ([int64]$b = $first; $b -le $last; $b++) { if (-not $by.ContainsKey($b)) { $whole = $false; break } $es = $by[$b] | Sort-Object { $_.shard } -Unique foreach ($e in $es) { $inPool = ($e.pool -and (@($e.pool)).Count -gt 0) if (-not $e.open -or $null -ne $e.paid -or $inPool) { $whole = $false; break } $shards += @{ number = $b; hash = $e.hash; shard = [int]$e.shard } if ($b -eq $last) { $lastDaa = Hex $e.daaScore } } if (-not $whole) { break } } if ($whole -and $shards.Count -gt 0) { $deadline = $lastDaa + $script:unproven if ($deadline -ge ($tipDaa + 1 + $need)) { $segs += @{ first = $first; last = $last; lastDaa = $lastDaa; deadline = $deadline; shards = $shards; margin = [int64]($deadline - $tipDaa - 1) } } } } # newest first (the most time before the deadline); the app ranks by FNV(first, key) for the spread return @($segs | Sort-Object { $_.first } -Descending) } while (((Get-Date) - $runStart).TotalMinutes -lt $RunMinutes) { $passes++ # paid segments foreach ($f in @($submittedSegments.Keys)) { $rec = Rpc 'igneum_getSegmentRecords' @(('0x{0:x}' -f $f)) if ($rec) { $carried = (@($rec.carried)).Count if ($rec.paid) { "RESULT paid $(Stamp) segment $f..$($submittedSegments[$f].last) paid wei=$($rec.paid.wei) ($([math]::Round((Hex $rec.paid.wei) / 1e18, 4)) IGN) carrier=$(Hex $rec.paid.carrierNumber) payout=$($rec.paid.payout) after $([math]::Round(((Get-Date) - $submittedSegments[$f].at).TotalSeconds)) s"; $submittedSegments.Remove($f) } elseif ($carried -gt 0) { "RESULT carried $(Stamp) segment $f carried=$carried valid=$(@($rec.carried | ForEach-Object { $_.valid }) -join ',') rejected=$(@($rec.carried | ForEach-Object { $_.rejected }) -join ';')" } } } $cands = Candidates if (-not $cands -or $cands.Count -eq 0) { "RESULT pass $passes $(Stamp) no whole segment inside the margin (need=$([math]::Max(240, [math]::Ceiling($lastSegSecs * 1.5))) DAA); waiting 20 s"; Start-Sleep -Seconds 20; continue } $picked = $null; $prevFile = $null; $expected = '' $tries = 0 foreach ($c in $cands) { if ($tries -ge 3) { break }; $tries++ $stmt = Rpc 'igneum_getSegmentStatement' @(('0x{0:x}' -f $c.first)) if (-not $stmt -or -not $stmt.executed -or $stmt.status.status -ne 'pending') { $attempted[$c.first] = $true; "RESULT skip $(Stamp) segment $($c.first): executed=$($stmt.executed) status=$($stmt.status.status)"; continue } if ($null -eq $stmt.previous) { if ($c.first -ge ($start + $n)) { $pr = Rpc 'igneum_getSegmentRecords' @(('0x{0:x}' -f ($c.first - $n))) $waiting = $false if ($pr -and $pr.pool) { foreach ($e in @($pr.pool)) { if ($e.verified -eq $true -and $null -eq $e.includedIn) { $waiting = $true } } } if ($waiting -or ($pr -and $pr.paid)) { "RESULT skip $(Stamp) segment $($c.first): the previous segment has a record waiting or paid; a fresh chain would be refused"; continue } } $picked = $c; $expected = $stmt.publicValuesFresh; break } if ($stmt.previous.proofInPool -ne $true) { "RESULT skip $(Stamp) segment $($c.first): previous paid, its proof not in this pool"; continue } $got = Rpc 'igneum_getSegmentProofBytes' @($stmt.previous.first, $stmt.previous.keyHash) if (-not $got -or -not $got.proof) { continue } $hexFile = Join-Path $job "prev-$($c.first).hex"; $binFile = Join-Path $job "prev-$($c.first).bin" [IO.File]::WriteAllText($hexFile, $got.proof) Wsl @("$jobW/unhex.sh", (WslPath $hexFile), (WslPath $binFile)) if (-not (Test-Path $binFile)) { continue } $picked = $c; $prevFile = WslPath $binFile; $expected = $stmt.publicValuesContinuing; break } if (-not $picked) { "RESULT pass $passes $(Stamp) $($cands.Count) candidates, none usable this pass; waiting 20 s"; Start-Sleep -Seconds 20; continue } $first = $picked.first; $last = $picked.last $attempted[$first] = $true; $claimed++ $tipNow = Hex (Rpc 'eth_blockNumber' @()) "RESULT claim $(Stamp) segment $first..$last ($($picked.shards.Count) shards, $(if ($prevFile) { 'continuing' } else { 'fresh' })), margin=$($picked.margin) DAA, tip=$tipNow, candidates=$($cands.Count)" $segStart = Get-Date $d = Join-Path $job "seg-$first"; New-Item -ItemType Directory -Force -Path $d | Out-Null # 3. the export (curl.exe streams the reply to a file; Invoke-WebRequest's Content is a string there) $t = Get-Date $bodyTxt = (@{jsonrpc='2.0'; id=1; method='igneum_exportSegments'; params=@('0x0', ('0x{0:x}' -f $last))} | ConvertTo-Json -Compress) $bodyFile = Join-Path $d 'export-request.json'; $seqFile = Join-Path $d 'seq.json' [IO.File]::WriteAllText($bodyFile, $bodyTxt, (New-Object System.Text.UTF8Encoding $false)) & curl.exe -s -S -m 600 -X POST "http://127.0.0.1:$evmPort" -H 'Content-Type: application/json' --data-binary "@$bodyFile" -o $seqFile 2>&1 | ForEach-Object { "curl: $_" } if (-not (Test-Path $seqFile) -or (Get-Item $seqFile).Length -lt 1000) { "RESULT seg $first export FAILED"; continue } "RESULT seg $first export $(Stamp) $((Get-Item $seqFile).Length) bytes in $([math]::Round(((Get-Date) - $t).TotalSeconds,1)) s" $segArgs = @("$jobW/seg.sh", $jobW, "$first", "$last", $payout); if ($prevFile) { $segArgs += $prevFile } Wsl $segArgs Remove-Item $seqFile -ErrorAction SilentlyContinue $resFile = Join-Path $d 'chain-results.json' if (-not (Test-Path $resFile)) { "RESULT seg $first FAILED: no chain results"; continue } $res = Get-Content $resFile -Raw | ConvertFrom-Json $recs = Get-Content (Join-Path $d 'shard-records.json') -Raw | ConvertFrom-Json # 4. the shard records $okShards = 0 foreach ($r in $recs) { $sg = (& $minerExe sign-record $label $chain $r.block_hash "$($r.number)" "$($r.shard)" $payout $r.statement $r.proof_sha256 2>&1 | Select-Object -Last 1) $signed = $null; try { $signed = $sg | ConvertFrom-Json } catch {} if (-not $signed -or -not $signed.record) { "RESULT seg $first shard $($r.number)/$($r.shard) sign FAILED: $sg"; $shardsRefused++; continue } $proofWin = $r.proof_file -replace '^/mnt/c/', 'C:/' -replace '/', '\' $bf = Join-Path $d "body-$($r.number)-$($r.shard).json" Wsl @("$jobW/body.sh", $r.proof_file, $signed.record, 'igneum_submitProofRecord', (WslPath $bf)) $reply = (& curl.exe -s -S -m 120 -X POST "http://127.0.0.1:$evmPort" -H 'Content-Type: application/json' --data-binary "@$bf" 2>&1) $rr = $null; try { $rr = ($reply | ConvertFrom-Json).result } catch {} if ($rr -and $rr.accepted) { $okShards++; $shardsAccepted++ } else { $shardsRefused++; "RESULT seg $first shard $($r.number)/$($r.shard) refused: $(if ($rr) { $rr.reason } else { "$reply".Substring(0, [math]::Min(300, "$reply".Length)) })" } Remove-Item $bf -ErrorAction SilentlyContinue } "RESULT seg $first shards $(Stamp) accepted $okShards of $($recs.Count) (prove $([math]::Round($res.shard_prove_seconds_total,1)) s, aggregation $([math]::Round($res.aggregate_prove_seconds_total,1)) s, chain $([math]::Round($res.chain_seconds,1)) s)" if ($okShards -ne $recs.Count) { "RESULT seg $first FAILED: not every shard record accepted; the segment record is not submitted"; continue } # 5. the segment record: the statement against the node's (every field but provers, bytes 236..268 of the 340) $pv = $res.segment_public_values function Strip($h) { $h = $h -replace '^0x', ''; if ($h.Length -eq 680) { $h.Substring(0, 472) + $h.Substring(536) } else { $h } } if ((Strip $pv) -ne (Strip $expected)) { "RESULT seg $first FAILED: statement differs from the node's native one; ours $($pv.Substring(0,66)) node $($expected.Substring(0, [math]::Min(66, $expected.Length)))"; continue } $lastHash = ($picked.shards | Where-Object { $_.number -eq $last } | Select-Object -First 1).hash $sg = (& $minerExe sign-segment-record $label $chain "$first" "$last" $lastHash $payout $pv $res.segment_proof_sha256 2>&1 | Select-Object -Last 1) $signed = $null; try { $signed = $sg | ConvertFrom-Json } catch {} if (-not $signed -or -not $signed.record) { "RESULT seg $first segment sign FAILED: $sg"; continue } $bf = Join-Path $d 'body-segment.json' Wsl @("$jobW/body.sh", $res.segment_proof_file, $signed.record, 'igneum_submitSegmentRecord', (WslPath $bf)) $reply = (& curl.exe -s -S -m 120 -X POST "http://127.0.0.1:$evmPort" -H 'Content-Type: application/json' --data-binary "@$bf" 2>&1) $rr = $null; try { $rr = ($reply | ConvertFrom-Json).result } catch {} Remove-Item $bf -ErrorAction SilentlyContinue $segSecs = [math]::Round(((Get-Date) - $segStart).TotalSeconds, 1) if ($rr -and $rr.accepted) { $submitted++; $lastSegSecs = $segSecs $stmt2 = Rpc 'igneum_getSegmentStatement' @(('0x{0:x}' -f $first)) $aggWei = if ($stmt2) { Hex $stmt2.aggregatorWei } else { 0 } $submittedSegments[$first] = @{ last = $last; aggWei = $aggWei; at = (Get-Date) } "RESULT seg $first submitted $(Stamp) segment $first..$last record accepted (new=$($rr.new), chain_len $($res.segment_chain_len)), aggregator share $([math]::Round($aggWei / 1e18, 4)) IGN, end to end $segSecs s (export+cut+chain+sign+submit)" } else { "RESULT seg $first segment refused $(Stamp): $(if ($rr) { $rr.reason } else { "$reply".Substring(0, [math]::Min(300, "$reply".Length)) }); end to end $segSecs s" } foreach ($b in $first..$last) { Remove-Item (Join-Path $d "block-$b.json") -ErrorAction SilentlyContinue } Remove-Item (Join-Path $d 'export.json') -ErrorAction SilentlyContinue } # --- the end: paid state once more, the rate during the run, the sockets, the prover back on Start-Sleep -Seconds 30 $paidTotal = 0; $paidCount = 0 foreach ($f in @($submittedSegments.Keys)) { $rec = Rpc 'igneum_getSegmentRecords' @(('0x{0:x}' -f $f)) if ($rec -and $rec.paid) { $paidCount++; $paidTotal += (Hex $rec.paid.wei); "RESULT paid $(Stamp) segment $f..$($submittedSegments[$f].last) paid wei=$($rec.paid.wei) carrier=$(Hex $rec.paid.carrierNumber)"; $submittedSegments.Remove($f) } else { "RESULT unpaid $(Stamp) segment $f..$($submittedSegments[$f].last) carried=$(if ($rec) { (@($rec.carried)).Count } else { '?' }) pool=$(if ($rec) { (@($rec.pool)).Count } else { '?' }) $(if ($rec -and $rec.pool) { ($rec.pool | ForEach-Object { "verified=$($_.verified) included=$($_.includedIn) note=$($_.note)" }) -join '; ' })" } } $st = Rpc 'igneum_getProvingStatus' @() if ($st) { "RESULT node_v1 $(Stamp) paidSegments=$($st.v1.paidSegments) paidSegmentWei=$($st.v1.paidSegmentWei) window pending=$($st.v1.segmentsInWindow.pending) proven=$($st.v1.segmentsInWindow.proven) unproven=$($st.v1.segmentsInWindow.unproven) pool entries=$($st.v1.pool.entries) verified=$($st.v1.pool.verified) failed=$($st.v1.pool.failed)" } $t1 = Epoch (Get-Date) $during = RateLines (Epoch $runStart) $t1 if ($during.Count) { $m = $during | Measure-Object -Average -Minimum -Maximum; "RESULT rate_during $(Stamp) n=$($during.Count) mean=$([math]::Round($m.Average,2)) min=$($m.Minimum) max=$($m.Maximum) MH/s (the app log's status lines over the run)" } else { "RESULT rate_during $(Stamp) no status lines found" } "RESULT summary $(Stamp) passes=$passes claimed=$claimed submitted=$submitted paid=$paidCount paid_wei=$paidTotal shards_accepted=$shardsAccepted shards_refused=$shardsRefused last_segment_s=$lastSegSecs run_min=$([math]::Round(((Get-Date) - $runStart).TotalMinutes,1))" & wsl.exe -d Ubuntu-24.04 -u root -- bash -c 'pkill -x sp1-gpu-server; sleep 1; rm -f /tmp/sp1-cuda-*.sock; echo "RESULT socket_cleanup $(date -u +%Y-%m-%dT%H:%M:%SZ) servers=$(pgrep -x sp1-gpu-server | wc -l) sockets=$(ls /tmp/sp1-cuda-*.sock 2>/dev/null | wc -l)"' 2>&1 | ForEach-Object { ($_ -replace "`0", '') } "RESULT prove_on $(Stamp) $(Post '/api/prove' @{on=$true})" "RESULT end $(Stamp)"