63 lines
4.9 KiB
Bash
Executable file
63 lines
4.9 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
# Publishes the project's GPU prover server (prover floor, 6 October 2026): the binary CI built
|
|
# (.github/workflows/prover-server.yml, artifact `sp1-gpu-server-floor`) or a given build folder, its signed manifest
|
|
# prover-server.json (format app/igneum-app/src/proverserver.rs: the SP1 version and commit it patches, the patch's
|
|
# sha256, the CUDA targets, the binary's sha256 and size, the build) and prover-server.json.sig, the detached Ed25519
|
|
# signature made on this Mac with the OTA key the apps already trust, into the downloads folder (dl/<token>/), and
|
|
# deploys it. The Windows build (.github/workflows/windows.yml) and packaging/prover/fetch-server.sh fetch the three
|
|
# files from there and verify them before the payload carries them (wsl2\bin\sp1-gpu-server, wsl2\prover-server.json
|
|
# and .sig); the app verifies them again before use.
|
|
#
|
|
# packaging/prover/push-server.sh --run <ci run id> the CI artifact (gh run download; gh must be logged in as igneum-labs)
|
|
# packaging/prover/push-server.sh --dir <folder> a folder with sp1-gpu-server, sp1-gpu-server.sha256 and build.json
|
|
# [--no-deploy]
|
|
#
|
|
# Same secrets layout as push-inputs.sh: ~/.config/igneum/{dl-token, dlsite-dir, vercel, ota-signing-key(.pub)}.
|
|
set -euo pipefail
|
|
HERE="$(cd "$(dirname "$0")" && pwd)"; ROOT="$(cd "$HERE/../.." && pwd)"
|
|
RUN=""; DIR=""; DEPLOY=1
|
|
while [ $# -gt 0 ]; do case "$1" in --run) RUN="$2"; shift 2 ;; --dir) DIR="$2"; shift 2 ;; --no-deploy) DEPLOY=0; shift ;; *) echo "unknown argument $1" >&2; exit 2 ;; esac; done
|
|
[ -n "$RUN" ] || [ -n "$DIR" ] || { echo "usage: push-server.sh --run <ci run id> | --dir <folder> [--no-deploy]" >&2; exit 2; }
|
|
TOKEN="$(tr -d '[:space:]' < "$HOME/.config/igneum/dl-token")"
|
|
DLSITE="${IGNEUM_DLSITE:-}"; [ -n "$DLSITE" ] || DLSITE="$(tr -d '[:space:]' < "$HOME/.config/igneum/dlsite-dir")"
|
|
[ -d "$DLSITE/dl/$TOKEN" ] || { echo "no downloads folder at $DLSITE/dl/<token>" >&2; exit 1; }
|
|
KEY="$HOME/.config/igneum/ota-signing-key"; PUB="$HOME/.config/igneum/ota-signing-key.pub"
|
|
SIGNER="$ROOT/app/igneum-app/target/release/igneum-ota-sign"
|
|
if [ ! -x "$SIGNER" ]; then echo "building igneum-ota-sign"; (cd "$ROOT/app/igneum-app" && nice -n 19 cargo build --release -j 4 --bin igneum-ota-sign --quiet); fi
|
|
if [ -n "$RUN" ]; then
|
|
DIR="$(mktemp -d)/server"; mkdir -p "$DIR"
|
|
gh auth status 2>/dev/null | grep -q "igneum-labs" || echo "warning: gh's active account is not igneum-labs (gh auth switch --user igneum-labs)"
|
|
gh run download "$RUN" --repo igneum-network/igneum --name sp1-gpu-server-floor --dir "$DIR"
|
|
BUILT_BY="ci:$RUN"
|
|
else
|
|
BUILT_BY="dir:$(hostname -s)"
|
|
fi
|
|
BIN="$DIR/sp1-gpu-server"; [ -f "$BIN" ] || { echo "no sp1-gpu-server in $DIR" >&2; exit 1; }
|
|
[ -f "$DIR/build.json" ] || { echo "no build.json in $DIR (build-server.sh writes it)" >&2; exit 1; }
|
|
# the hash the builder recorded must be the file's hash now (a corrupt download is refused here)
|
|
SHA="$(shasum -a 256 "$BIN" | cut -c1-64)"; BYTES="$(stat -f %z "$BIN")"
|
|
REC="$(python3 -c 'import json,sys; print(json.load(open(sys.argv[1]))["sha256"])' "$DIR/build.json")"
|
|
[ "$SHA" = "$REC" ] || { echo "the binary's sha256 $SHA is not build.json's $REC" >&2; exit 1; }
|
|
[ -f "$DIR/sp1-gpu-server.sha256" ] && { grep -q "^$SHA " "$DIR/sp1-gpu-server.sha256" || { echo "sp1-gpu-server.sha256 disagrees" >&2; exit 1; }; }
|
|
DEST="$DLSITE/dl/$TOKEN"
|
|
python3 - "$DIR/build.json" "$DEST/prover-server.json" "$BUILT_BY" "$SHA" "$BYTES" <<'PY'
|
|
import json, sys, datetime
|
|
b = json.load(open(sys.argv[1]))
|
|
m = {"format": "igneum-prover-server/1", "sp1_version": b["sp1_version"], "sp1_commit": b["sp1_commit"], "patch_sha256": b["patch_sha256"],
|
|
"cuda_archs": b.get("elf_targets") or b["cuda_archs"], "built_at": b["built_at"], "built_by": sys.argv[3],
|
|
"published_at": datetime.datetime.now(datetime.timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ"),
|
|
"files": {"sp1-gpu-server": {"sha256": sys.argv[4], "bytes": int(sys.argv[5])}}}
|
|
open(sys.argv[2], "w").write(json.dumps(m, sort_keys=True, separators=(",", ":")) + "\n")
|
|
PY
|
|
"$SIGNER" sign-server "$KEY" "$DEST/prover-server.json" > "$DEST/prover-server.json.sig"
|
|
cp "$BIN" "$DEST/sp1-gpu-server"
|
|
"$SIGNER" verify-server "$PUB" "$DEST/prover-server.json" "$DEST/prover-server.json.sig" --binary "$DEST/sp1-gpu-server"
|
|
"$SIGNER" verify-server embedded "$DEST/prover-server.json" "$DEST/prover-server.json.sig" >/dev/null || { echo "the embedded key does not verify this signature: the OTA key on this Mac is not the one the apps carry" >&2; exit 1; }
|
|
cat "$DEST/prover-server.json"; echo "signature: $(cut -c1-16 "$DEST/prover-server.json.sig")..."
|
|
if [ "$DEPLOY" = 1 ]; then
|
|
echo "deploying $DLSITE"
|
|
(cd "$DLSITE" && npx vercel@latest --global-config "$HOME/.config/igneum/vercel" deploy --prod --yes 2>&1 | grep -v "$TOKEN" || true)
|
|
echo "published: https://dl.igneum.network/dl/<token>/{sp1-gpu-server,prover-server.json,prover-server.json.sig}"
|
|
else
|
|
echo "not deployed (--no-deploy); run the Vercel deploy from $DLSITE when ready"
|
|
fi
|