From 3f23df38b77ab9358098590715e50e9926ad6c29 Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Sun, 4 Oct 2026 14:36:59 +0000 Subject: [PATCH] Packaging for proving v0: the Mac DMG carries igneum-prove-host and igneum-prove-export, the Windows payload carries the Linux host and exporter under wsl2/bin with the WSL2 scripts and the fixtures; the prover probes the shipped WSL2 binaries first and runs helpers by absolute path; push-inputs takes IGNEUM_NODE_SRC; the test script's --network-only mode Co-Authored-By: Claude Fable 5.1 --- app/igneum-app/src/prover.rs | 13 ++++++++----- packaging/mac/build-dmg.sh | 8 ++++++++ packaging/windows/make-payload.sh | 18 ++++++++++++++++++ packaging/windows/push-inputs.sh | 3 ++- tools/proving-v0/run.mjs | 13 +++++++++++++ 5 files changed, 49 insertions(+), 6 deletions(-) diff --git a/app/igneum-app/src/prover.rs b/app/igneum-app/src/prover.rs index 2cd2e67b..148993bb 100644 --- a/app/igneum-app/src/prover.rs +++ b/app/igneum-app/src/prover.rs @@ -145,8 +145,11 @@ fn evm_rpc(shared: &Shared, method: &str, params: Value, timeout: Duration) -> R fn find_tools(bin_dir: &Path) -> Result { let miner = bin_dir.join(if cfg!(windows) { "igneum-miner.exe" } else { "igneum-miner" }); if cfg!(windows) { - // the SP1 host runs inside WSL2 (Ubuntu-24.04): built there by setup-wsl.sh, or shipped as a Linux binary - let probe = Command::new("wsl").args(["-d", "Ubuntu-24.04", "--", "bash", "-lc", "for f in ~/igneum-prove/target/release/igneum-prove-host /opt/igneum/igneum-prove-host; do [ -x \"$f\" ] && { echo \"$f\"; break; }; done; command -v nvidia-smi >/dev/null && echo cuda"]).output(); + // the SP1 host runs inside WSL2 (Ubuntu-24.04): the Linux binaries the payload ships under wsl2\bin\ (seen + // from Ubuntu as /mnt//.../wsl2/bin), else one built there by setup-wsl.sh + let shipped = wsl_path(&bin_dir.join("wsl2").join("bin").join("igneum-prove-host")); + let script = format!("for f in '{shipped}' ~/igneum-prove/target/release/igneum-prove-host /opt/igneum/igneum-prove-host; do [ -x \"$f\" ] && {{ echo \"$f\"; break; }}; done; command -v nvidia-smi >/dev/null && echo cuda"); + let probe = Command::new(crate::platform::tool("wsl")).args(["-d", "Ubuntu-24.04", "--", "bash", "-lc", &script]).output(); let text = probe.map(|o| String::from_utf8_lossy(&o.stdout).to_string()).unwrap_or_default(); let host = text.lines().find(|l| l.contains("igneum-prove-host")).map(|l| PathBuf::from(l.trim())); let setup = bin_dir.join("wsl2").join("setup-wsl.sh"); @@ -170,7 +173,7 @@ fn find_tools(bin_dir: &Path) -> Result { /// Runs the host or the exporter: directly, or through WSL on Windows. Returns (exit ok, output). fn run_tool(t: &Tools, exe: &Path, args: &[String], env: &[(&str, &str)], limit: Duration) -> (bool, String) { let mut cmd = if t.wsl { - let mut c = Command::new("wsl"); + let mut c = Command::new(crate::platform::tool("wsl")); let envs: String = env.iter().map(|(k, v)| format!("{k}={v} ")).collect(); let line = format!("{envs}{} {}", exe.display(), args.iter().map(|a| format!("'{a}'")).collect::>().join(" ")); c.args(["-d", "Ubuntu-24.04", "--", "bash", "-lc", &line]); @@ -417,8 +420,8 @@ pub fn setup(shared: &Shared) -> Result { return Err(format!("setup script missing: {}", script.display())); } let line = format!("bash {}", wsl_path(&script)); - let mut c = Command::new("cmd"); - c.args(["/c", "start", "", "wsl", "-d", "Ubuntu-24.04", "--", "bash", "-lc", &line]); + let mut c = Command::new(crate::platform::tool("cmd")); + c.args(["/c", "start", "", &crate::platform::tool("wsl").display().to_string(), "-d", "Ubuntu-24.04", "--", "bash", "-lc", &line]); c.spawn().map_err(|e| e.to_string())?; shared.event("proving", "WSL2 prover setup started in its own window"); Ok(json!({ "ok": true })) diff --git a/packaging/mac/build-dmg.sh b/packaging/mac/build-dmg.sh index 5217525a..4243ced0 100755 --- a/packaging/mac/build-dmg.sh +++ b/packaging/mac/build-dmg.sh @@ -28,6 +28,9 @@ NODE="${NODE:-$ROOT/vendor/igneum-node/target-integration/release/igneumd}" MINER="${MINER:-$ROOT/vendor/igneum-node/target-integration/release/igneum-miner}" WORKER="${WORKER:-}" ENGINE="${ENGINE:-}" +# proving v0: the SP1 host and the exporter next to the node (CPU proving on a Mac; app/igneum-app/src/prover.rs) +PROVE_HOST="${PROVE_HOST:-$ROOT/proving/igneum-prove/target/release/igneum-prove-host}" +PROVE_EXPORT="${PROVE_EXPORT:-$ROOT/proving/igneum-prove/target/release/igneum-prove-export}" REBUILD_WORKER="${REBUILD_WORKER:-1}" ICONS="$ROOT/brand/icons" BUILD="$HERE/build" @@ -96,6 +99,11 @@ cp "$ICONS/igneum.icns" "$APP/Contents/Resources/igneum.icns" cp "$NODE" "$APP/Contents/Resources/bin/igneumd" cp "$MINER" "$APP/Contents/Resources/bin/igneum-miner" cp "$WORKER" "$APP/Contents/Resources/bin/igneum-bench" +if [ -f "$PROVE_HOST" ] && [ -f "$PROVE_EXPORT" ]; then + cp "$PROVE_HOST" "$APP/Contents/Resources/bin/igneum-prove-host" + cp "$PROVE_EXPORT" "$APP/Contents/Resources/bin/igneum-prove-export" + echo "prover: igneum-prove-host and igneum-prove-export from $(dirname "$PROVE_HOST")" +else echo "warning: no $PROVE_HOST / $PROVE_EXPORT (cd proving/igneum-prove && cargo build --release -p igneum-prove-host -p igneum-prove-export); the Proving tile will say the prover is missing"; fi write_packaged_config "$APP/Contents/Resources/igneum-app.json" chmod 755 "$APP/Contents/MacOS/"* "$APP/Contents/Resources/bin/"* diff --git a/packaging/windows/make-payload.sh b/packaging/windows/make-payload.sh index 6b26ee93..53739b1f 100755 --- a/packaging/windows/make-payload.sh +++ b/packaging/windows/make-payload.sh @@ -76,6 +76,19 @@ mkdir -p "$STAGE/app/windows/art" && cp "$ROOT/brand/icons/igneum.ico" "$STAGE/a if [ -f "$ROOT/app/windows/dist/Igneum Miner.exe" ]; then cp "$ROOT/app/windows/dist/Igneum Miner.exe" "$STAGE/"; echo "window host: Igneum Miner.exe from app/windows/dist"; fi cp "$HERE/stop-igneum.ps1" "$STAGE/stop-igneum.ps1" +# proving v0 (spec 7.7, app/igneum-app/src/prover.rs): the SP1 host runs inside WSL2 on a PC, so the payload ships the +# Linux x86_64 host and exporter (proving/igneum-prove cross-built with cargo-zigbuild, glibc 2.36, sp1 cuda feature; +# IGNEUM_PROVE_LINUX overrides the folder) under wsl2\bin\, the WSL2 setup scripts and the fixtures. The engine runs +# them as /mnt//.../wsl2/bin/igneum-prove-host from Ubuntu-24.04; Set up runs wsl2\setup-wsl.sh. +PROVE_LINUX="${IGNEUM_PROVE_LINUX:-$ROOT/proving/igneum-prove/target-linux/x86_64-unknown-linux-gnu/release}" +mkdir -p "$STAGE/wsl2/bin" "$STAGE/wsl2/fixtures" +if [ -f "$PROVE_LINUX/igneum-prove-host" ] && [ -f "$PROVE_LINUX/igneum-prove-export" ]; then + cp "$PROVE_LINUX/igneum-prove-host" "$PROVE_LINUX/igneum-prove-export" "$STAGE/wsl2/bin/" + echo "prover (WSL2): igneum-prove-host $(stat -f %z "$PROVE_LINUX/igneum-prove-host") bytes, igneum-prove-export $(stat -f %z "$PROVE_LINUX/igneum-prove-export") bytes" +else echo "warning: no Linux igneum-prove-host/igneum-prove-export in $PROVE_LINUX (cargo zigbuild --target x86_64-unknown-linux-gnu.2.36 --features igneum-prove-host/cuda); the Proving tile will ask for the WSL2 setup, which builds them"; fi +cp "$ROOT"/proving/windows-wsl2/*.sh "$ROOT"/proving/windows-wsl2/*.ps1 "$ROOT"/proving/windows-wsl2/*.bat "$ROOT/proving/windows-wsl2/README.txt" "$STAGE/wsl2/" +cp "$ROOT"/proving/fixtures/*.json "$STAGE/wsl2/fixtures/" + # the packaged configuration: the download token stays out of the repo TOKEN="" [ -f "$TOKEN_FILE" ] && TOKEN="$(tr -d '[:space:]' < "$TOKEN_FILE")" @@ -83,8 +96,13 @@ MANIFEST="" [ -n "$TOKEN" ] && MANIFEST="https://dl.igneum.network/dl/$TOKEN/igneum-app-latest.json" [ -n "$MANIFEST" ] || echo "note: no $TOKEN_FILE; the update check is disabled in this build" LOG_KEY="$(sed -n 's/^LOG_KEY="\(.*\)"/\1/p' "$ROOT/packaging/mac/packaged-config.sh")" +# the pinned consensus parameters (packaged-config.sh NODE_OVERRIDE_PARAMS, e.g. the difficulty v2 activation height) +NODE_OVERRIDE_PARAMS="$(sed -n "s/^NODE_OVERRIDE_PARAMS='\(.*\)'/\1/p" "$ROOT/packaging/mac/packaged-config.sh")" +OVERRIDE_LINE="" +[ -n "$NODE_OVERRIDE_PARAMS" ] && OVERRIDE_LINE=" \"node_override_params\": $NODE_OVERRIDE_PARAMS," cat > "$STAGE/igneum-app.json" </dev/null || git -C "$ROOT/vendor/igneum-node" rev-parse --short HEAD 2>/dev/null || echo unknown)" +# IGNEUM_NODE_SRC names the worktree the exes were built from (default devnet-v4), for the manifest's commit field +NODE_COMMIT="$(git -C "${IGNEUM_NODE_SRC:-$ROOT/vendor/igneum-node-v4}" rev-parse --short HEAD 2>/dev/null || git -C "$ROOT/vendor/igneum-node" rev-parse --short HEAD 2>/dev/null || echo unknown)" REPO_COMMIT="$(git -C "$ROOT" rev-parse --short HEAD 2>/dev/null || echo unknown)" { echo '{' diff --git a/tools/proving-v0/run.mjs b/tools/proving-v0/run.mjs index 8c0f1ff1..d33c188d 100644 --- a/tools/proving-v0/run.mjs +++ b/tools/proving-v0/run.mjs @@ -12,6 +12,8 @@ // Never touches the live devnet (26610/26611, 26640/28640) or the fast-time simnet (29500+). // // node tools/proving-v0/run.mjs [--secs 1500] [--activation 60] [--empty] (--empty proves the newest empty segment instead) +// node tools/proving-v0/run.mjs --network-only --secs 3600 (just the 3 nodes and the voters, for the app's prover loop; node 1 +// p2p 127.0.0.1:29811 is the peer to give the app) import { spawn, spawnSync } from 'node:child_process'; import { mkdirSync, rmSync, writeFileSync, readFileSync, openSync, existsSync } from 'node:fs'; @@ -33,6 +35,7 @@ const flag = (name, dflt) => { const i = args.indexOf(name); return i >= 0 && ar const SECS = flag('--secs', 1500); const ACTIVATION = flag('--activation', 60); const EMPTY = args.includes('--empty'); +const NETWORK_ONLY = args.includes('--network-only'); const started = []; const t0 = Date.now(); const since = () => ((Date.now() - t0) / 1000).toFixed(1); @@ -119,6 +122,16 @@ try { const status0 = await n0.eth('igneum_getProvingStatus'); log(`proving status n0: ${JSON.stringify(status0)}`); step('status', { activationDaa: status0.activationDaa, verifier: status0.verifier }); + if (NETWORK_ONLY) { + log(`network only: 3 nodes up for ${SECS} s; peer for the app: 127.0.0.1:${n1.p2pPort}; EVM RPC n0 ${n0.evm}`); + while (Date.now() - t0 < SECS * 1000) { + await sleep(15000); + const s = await n0.eth('igneum_getProvingStatus').catch(() => null); + if (s) log(`daa ${parseInt(s.tipDaa, 16)} active=${s.active} pool=${JSON.stringify(s.pool)} paidShards=${s.paidShards}`); + } + report.ok = true; + throw new Error('network-only run finished'); + } // 1. wait for the activation DAA (plus a margin: the sortition window needs dust blocks per key) let daa = 0;