#!/usr/bin/env bash # Build the node once and install it on every node. # # ./provision.sh source tarball -> builder VM -> build/bin/{igneumd,igneum-miner} -> every node (systemd units) # ./provision.sh build only the build (creates the builder VM if build/builder.ip is missing, deletes it afterwards) # ./provision.sh install only the install on the nodes (needs build/bin/igneumd) # ./provision.sh install igneum-09 ... the install on the named nodes only (the mesh is still computed from all of nodes.tsv) # The binaries are copied only when the node's sha256 differs from build/bin (a re-install moves no 47 MB twice). # BIN_SOURCE=mac ./provision.sh [build|all] no builder VM: cross-compile on this Mac (infra/cross/build-linux.sh, # cargo-zigbuild, x86_64-unknown-linux-gnu glibc 2.36) and take build/bin from its output # # Two ways to get the binaries. BIN_SOURCE=builder (the default, 3 Oct 2026): a builder VM compiles the source # tarball (10 to 25 minutes on 8 vCPU, about EUR 0.05). BIN_SOURCE=mac (4 Oct 2026): cargo-zigbuild on this Mac # cross-compiles for x86_64 Linux glibc 2.36 (zig is the C/C++ toolchain and linker; rocksdb, blst, secp256k1 and the # execution layer link; infra/cross/build-linux.sh), no VM at all. The binaries are cached in build/bin; REBUILD=1 # forces a new build. # NET_MODE=private (4 Oct 2026): the builder has no public address either; it sits behind the zone gateway of # region 1 and lib's nssh/nscp jump through that gateway (create.sh builder does the uplink check). . "$(dirname "$0")/lib/common.sh" what="${1:-all}" mkdir -p "$BUILD_DIR" "$BIN_DIR" # ---- build --------------------------------------------------------------------------------------------------------- do_build() { if [ -x "$BIN_DIR/igneumd" ] && [ "${REBUILD:-0}" != 1 ]; then log "build/bin/igneumd exists ($(cat "$BIN_DIR/version.txt" 2>/dev/null | tr '\n' ' ')); REBUILD=1 to rebuild" return fi if [ "${BIN_SOURCE:-builder}" = mac ]; then log "BIN_SOURCE=mac: cross-compiling on this Mac (no builder VM) from $NODE_SRC" NODE_SRC="$NODE_SRC" OUT_DIR="$BIN_DIR" "$HERE/../cross/build-linux.sh" printf 'exported %s\nigneum-node (%s): HEAD %s (%s), cross-compiled on the Mac\n' "$(date -u +%Y-%m-%dT%H:%M:%SZ)" "$NODE_SRC" "$(git -C "$NODE_SRC" rev-parse --short HEAD)" "$(git -C "$NODE_SRC" rev-parse --abbrev-ref HEAD)" > "$BIN_DIR/src.stamp" log "binaries in $BIN_DIR: $(cat "$BIN_DIR/version.txt" | tr '\n' ' ')" return fi "$HERE/make-source.sh" if [ ! -s "$BUILD_DIR/builder.ip" ]; then YES="${YES:-0}" "$HERE/create.sh" builder fi bip=$(cat "$BUILD_DIR/builder.ip") log "builder at $bip; waiting for ssh" for try in $(seq 1 12); do nssh "$bip" true >/dev/null 2>&1 && break; sleep 10; done nssh "$bip" true || die "builder $bip not reachable over ssh" log "uploading source ($(du -h "$BUILD_DIR/src.tar.gz" | cut -f1)) and the build script" nscp "$BUILD_DIR/src.tar.gz" "$HERE/builder/build-on-builder.sh" "$SSH_USER@$bip:/root/" nssh "$bip" "bash /root/build-on-builder.sh" | tee "$BUILD_DIR/build.log" nscp "$SSH_USER@$bip:/root/out/igneumd" "$SSH_USER@$bip:/root/out/igneum-miner" "$SSH_USER@$bip:/root/out/version.txt" "$BIN_DIR/" chmod +x "$BIN_DIR/igneumd" "$BIN_DIR/igneum-miner" cp "$BUILD_DIR/src.stamp" "$BIN_DIR/src.stamp" log "binaries in $BIN_DIR: $(cat "$BIN_DIR/version.txt" | tr '\n' ' ')" if [ "${KEEP_BUILDER:-0}" = 1 ]; then log "KEEP_BUILDER=1: builder $bip stays up (it bills by the hour)" else log "deleting the builder VM" if [ "$PROVIDER" = digitalocean ]; then doctl compute droplet delete -f "$PREFIX-builder"; else hcloud server delete "$PREFIX-builder" >/dev/null; fi rm -f "$BUILD_DIR/builder.ip" fi } # ---- install ------------------------------------------------------------------------------------------------------ do_install() { # [node names] require_nodes [ -x "$BIN_DIR/igneumd" ] || die "no $BIN_DIR/igneumd: run ./provision.sh build" local n; n=$(node_count); local bits; bits=$(genesis_bits_decimal); local only="$*" local sha_d sha_m; sha_d=$(shasum -a 256 "$BIN_DIR/igneumd" | cut -c1-64); sha_m=$(shasum -a 256 "$BIN_DIR/igneum-miner" | cut -c1-64) log "installing on ${only:-all $n} nodes (devnet suffix $DEVNET_SUFFIX, genesis bits $GENESIS_BITS = $bits, $MESH_OUT outbound peers each, $MINER_THREADS miner thread)" while IFS=$'\t' read -r -u 3 name idx reg ip access pub port; do if [ -n "$only" ] && ! printf ' %s ' $only | grep -q " $name "; then continue; fi peers=$(peers_of "$idx") ( for try in 1 2 3; do nssh "$ip" "mkdir -p /opt/igneum/bin /etc/igneum" && break; sleep 10; done # the binaries only when they differ (sha256 on the node), the small files always have=$(nssh "$ip" "cd /opt/igneum/bin 2>/dev/null && sha256sum igneumd igneum-miner 2>/dev/null | cut -c1-64 | tr '\n' ' '" &1 | sed "s/^/[$name] /" ) & # at most 10 installs at once while [ "$(jobs -r | wc -l)" -ge 10 ]; do sleep 1; done done 3< "$NODES_FILE" wait log "installed. Peer map:" while IFS=$'\t' read -r -u 3 name idx reg ip access pub port; do printf ' %s (%s, %s, %s) -> %s\n' "$name" "$reg" "$ip" "$(external_addr "$idx")" "$(peers_of "$idx")"; done 3< "$NODES_FILE" log "next: ./start.sh" } case "$what" in all) do_build; do_install ;; build) do_build ;; install) shift; do_install "$@" ;; *) die "usage: provision.sh [all|build|install]" ;; esac