igneum/tools/fleet/box-node-swap.sh

45 lines
4.8 KiB
Bash
Executable file

#!/usr/bin/env bash
# The 0.3.13 node swap for a phase-2 box (6 October 2026, the coordinator's procedure): the fixed Linux igneumd (pushed
# to /root/fleet/in/igneumd-0313, sha256 in NODE_SHA256) replaces the running one over the observer's full-history
# datadir (pulled from the hub unless already in place), with the hub and the seed as peers and the proof verifier;
# then the exec follower's replay is timed as box-datadir.sh does: eth_blockNumber every 15 s until it reaches the tip.
set -uo pipefail
F=/root/fleet; OUT=$F/out; B=/opt/igneum/pkg/bin; FLOOR=/opt/igneum-floor; HOST=$FLOOR/bin/igneum-prove-host
HUB_SSH="${HUB_SSH:-213.173.107.74}"; HUB_PORT="${HUB_PORT:-16515}"; HUB_PEER="${HUB_PEER:-213.173.107.74:16516}"
NODE_SHA256="${NODE_SHA256:?the fixed igneumd's sha256}"
STEP="${STEP:-binary}" # binary = publish 1 (the new igneumd, the ten-field file kept, digest 7bd98cc4); file = publish 2 (ov13.json becomes the override, digest b18ed271)
EXPECT_DIGEST="${EXPECT_DIGEST:-7bd98cc4118616455709d5e32a30b799e6e67caa42d2b5d09875cd49848a7ed7}"
mkdir -p $OUT; exec >> $OUT/node-swap.log 2>&1
stamp() { date -u +%Y-%m-%dT%H:%M:%SZ; }
echo "RESULT swap_start $(stamp)"
echo "$NODE_SHA256 $F/in/igneumd-0313" | sha256sum -c - >/dev/null || { echo "RESULT swap_failed sha256 mismatch: $(sha256sum $F/in/igneumd-0313 | cut -c1-16)"; exit 2; }
chmod +x $F/in/igneumd-0313
t0=$(date +%s)
if [ ! -d $F/node/igneum-devnet ] || [ ! -f $F/node/.full-history ]; then
[ -s $F/observer-datadir.tgz ] || scp -i $F/in/fleet-internal -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -P "$HUB_PORT" "root@$HUB_SSH:/root/fleet/share/observer-datadir.tgz" $F/observer-datadir.tgz || { echo "RESULT swap_failed pull"; exit 2; }
bash $F/in/box-kill.sh >/dev/null 2>&1; pkill -x igneumd; sleep 4; pkill -9 -x igneumd 2>/dev/null
rm -rf $F/node.proof && mv $F/node $F/node.proof && mkdir -p $F/node && tar -C $F/node -xzf $F/observer-datadir.tgz 2>/dev/null && touch $F/node/.full-history || { echo "RESULT swap_failed untar"; exit 2; }
echo "RESULT datadir_in_place $(stamp) s=$(( $(date +%s) - t0 ))"
else
bash $F/in/box-kill.sh >/dev/null 2>&1; pkill -x igneumd; sleep 4; pkill -9 -x igneumd 2>/dev/null
fi
if [ "$STEP" = file ]; then cp $F/override.json $F/override-10.json; cp $F/in/ov13.json $F/override.json; echo "RESULT override_swapped $(stamp) fields=$(python3 -c 'import json,sys; print(len(json.load(open(sys.argv[1]))))' $F/override.json)"; fi
cp $F/in/igneumd-0313 $B/igneumd-0313
IGNEUM_PROOF_VERIFIER=$HOST nohup $B/igneumd-0313 --devnet --appdir=$F/node --rpclisten=127.0.0.1:26610 --evm-rpclisten=127.0.0.1:26790 --listen=0.0.0.0:26611 \
--addpeer=$HUB_PEER --addpeer=188.245.5.161:26611 --override-params-file=$F/override.json --nodnsseed --disable-upnp --nologfiles --yes ${NODE_EXTRA:-} >> $F/node.log 2>&1 &
t1=$(date +%s); sleep 10
d="$(grep -o 'digest: [0-9a-f]*' $F/node.log | tail -1 | awk '{print $2}')"
echo "RESULT node_started $(stamp) step=$STEP pid=$(pgrep -f igneumd-0313 | head -1) version=$($B/igneumd-0313 --version 2>&1 | head -1) digest=${d:0:16} expected=${EXPECT_DIGEST:0:16} $( [ "$d" = "$EXPECT_DIGEST" ] && echo digest_ok || echo DIGEST_MISMATCH ) exec_restart=\"$(grep -o 'Exec restart from the override file.*' $F/node.log | tail -1 | cut -c1-120)\""
[ "$d" = "$EXPECT_DIGEST" ] || { echo "RESULT swap_failed digest mismatch"; exit 2; }
bn() { curl -s -m 8 -X POST -H 'Content-Type: application/json' --data '{"jsonrpc":"2.0","id":1,"method":"eth_blockNumber","params":[]}' http://127.0.0.1:26790/ | grep -o '"result":"[^"]*"' | cut -d'"' -f4; }
for i in $(seq 1 240); do
sleep 15; h="$(bn)"; n=$(( ${h:-0x0} )); w="$($B/igneum-miner watch 1 grpc://127.0.0.1:26610 2>/dev/null | grep -o 'blocks=[0-9]*.*synced=[a-z]*' | tail -1)"
echo "RESULT replay $(stamp) s=$(( $(date +%s) - t1 )) evm_block=$n $w"
if [ "$n" -gt 0 ] && [[ "$w" == *synced=true* ]]; then
st="$(curl -s -m 8 -X POST -H 'Content-Type: application/json' --data '{"jsonrpc":"2.0","id":1,"method":"igneum_getProvingStatus","params":[]}' http://127.0.0.1:26790/ | python3 -c 'import sys,json; d=json.load(sys.stdin).get("result",{}); print("tipDaa", int(d.get("tipDaa","0x0"),16), "active", d.get("v1",{}).get("active"), "fresh", d.get("v1",{}).get("freshRuleActive"))' 2>/dev/null)"
ex="$(curl -s -m 8 -X POST -H 'Content-Type: application/json' --data '{"jsonrpc":"2.0","id":1,"method":"igneum_getExecStatus","params":[]}' http://127.0.0.1:26790/ | cut -c1-200)"; echo "RESULT exec_status $ex"
daa=$(printf '%s' "$w" | grep -o 'daa=[0-9]*' | cut -d= -f2); tip=$(printf '%s' "$st" | awk '{print $2}')
[ -n "$tip" ] && [ "$tip" -ge $(( ${daa:-0} - 20 )) ] && { echo "RESULT swap_done $(stamp) replay_s=$(( $(date +%s) - t1 )) $st"; exit 0; }
fi
done
echo "RESULT swap_failed replay did not reach the tip in 60 min"