igneum/infra/cloud-devnet/experiments/hop.sh
igneum-labs 8255839d9e Cloud devnet: two Singapore partitions and the hash-rate steps on the 12-node network, results and bench-log entry
partition.sh adapted to private-network mode: the cut sits on the region's gateway (INPUT, OUTPUT and FORWARD
against the far gateways' public IPs over 26611 and the DNAT ports 27001:27099), since a per-node port-26611 rule
leaves the DNAT links up. It now records the locks per side at cut, during, at heal and after convergence, the
first lock after the heal from the journals, and the heal time as each minority node's first chain removal of 5+
blocks (the sink-count criterion is tip churn on a healthy network). hop.sh and partition.sh hold the Mac awake
with caffeinate; analyze.py gains a 10-s hop series (difficulty, block count, 1- and 2-min rates, threads) and an
overshoot table; collect.sh writes hop-series.tsv and hop.md and gzips the journals.

Results 2026-10-04: partition 1 (window still filling) reorg 431/496 on the minority, 2 on the majority, healed in
10 and 14 s; partition 2 (locks active): minority locked nothing during the cut, majority locked every interval at
66.8% to 84.5% of total, 0 conflicting locks over 107 indices, healed in 11 and 15 s, first lock after heal 13 s.
Hash-rate steps x1.42, x0.70, x0.75, x1.32: difficulty overshoots x1.67, x0.66, x0.53, x1.60, settle 751 s,
never in 900 s, 241 s, 646 s. Failures stated in summary.md: the Mac hibernated during the hop (phase 2 ran 94
min), the first partition could not see locks, the script's heal and first-lock figures were artefacts (fixed),
and another agent's v2 rollout restarted every node during the second heal.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-04 14:39:54 +00:00

55 lines
2.8 KiB
Bash
Executable file

#!/usr/bin/env bash
# Experiment 1c: hash-rate steps for the difficulty controller (spec 02 section 2.3; the dual-lane rule is on the
# `difficulty` worktree, NODE_SRC=vendor/igneum-node-diff when building; on master it exercises Kaspa's sampled DAA).
# ./experiments/hop.sh "<schedule>"
# schedule = phases separated by ";", phase = <selector>:<threads>:<seconds>
# selector: all | half (odd indices) | odd | even | region:<name> | <from>-<to> (indices)
# threads: miner threads on the selected nodes (0 stops the miner); unselected nodes keep their setting
# Default schedule (about 75 min): steady, 4x step up on half the nodes, back down, one region off, back:
# all:1:900;half:4:900;all:1:900;region:hel1:0:600;all:1:900
# Every phase change is logged to results/<date>/hop.log (ts_ms, selector, threads); collect.sh and analyze.py hop
# line the difficulty samples up against it.
. "$(dirname "$0")/../lib/common.sh"
require_nodes
# A schedule of sleeps pauses when the Mac sleeps (4 Oct 2026: the hop's 15-min 4-thread phase ran 94 min because the
# laptop hibernated on a flat battery). On macOS re-run under caffeinate -i, which holds the machine awake while this runs.
if [ "$(uname)" = Darwin ] && [ -z "${IGNEUM_CAFFEINATED:-}" ] && command -v caffeinate >/dev/null 2>&1; then
IGNEUM_CAFFEINATED=1 exec caffeinate -i "$0" "$@"
fi
schedule="${1:-all:1:900;half:4:900;all:1:900;region:hel1:0:600;all:1:900}"
out="$(results_dir_for)"; logf="$out/hop.log"
select_nodes() {
case "$1" in
all) node_names ;;
half|odd) awk -F'\t' '$2 % 2 == 1 { print $1 }' "$NODES_FILE" ;;
even) awk -F'\t' '$2 % 2 == 0 { print $1 }' "$NODES_FILE" ;;
region:*) nodes_in_region "${1#region:}" ;;
*-*) awk -F'\t' -v a="${1%-*}" -v b="${1#*-}" '$2 >= a && $2 <= b { print $1 }' "$NODES_FILE" ;;
*) die "bad selector $1" ;;
esac
}
set_threads() { # node threads
local ip; ip=$(node_ip "$1")
if [ "$2" = 0 ]; then
nssh "$ip" "systemctl stop igneum-miner"
else
nssh "$ip" "sed -i 's/^MINER_THREADS=.*/MINER_THREADS=$2/' /etc/igneum/node.env && systemctl restart igneum-miner"
fi
}
log "schedule: $schedule"
IFS=';' read -r -a phases <<< "$schedule"
for ph in "${phases[@]}"; do
sel="${ph%%:*}"; rest="${ph#*:}"
if [ "$sel" = region ]; then sel="region:${rest%%:*}"; rest="${rest#*:}"; fi
threads="${rest%%:*}"; secs="${rest#*:}"
nodes=$(select_nodes "$sel")
log "phase: $sel -> $threads thread(s) for $secs s ($(printf '%s\n' "$nodes" | wc -l | tr -d ' ') nodes)"
for n in $nodes; do set_threads "$n" "$threads" & done; wait
printf '%s\t%s\t%s\t%s\n' "$(date +%s)000" "$sel" "$threads" "$secs" >> "$logf"
sleep "$secs"
done
printf '%s\tend\t-\t-\n' "$(date +%s)000" >> "$logf"
log "done; phases in $logf. Pull the samples with ./experiments/collect.sh and read results/<date>/hop.md"