scripts/sepolia/airlock.sh100 lines · 5433 bytes
| 1 | #!/usr/bin/env bash |
| 2 | # The airlock listener: runs the CRE workflow's log trigger (handler 0) in listen mode. Every AirlockAdmin.Proposed |
| 3 | # event is judged as it arrives and answered on chain: a pass becomes a Clear report, a failed check a Veto report. |
| 4 | # |
| 5 | # scripts/sepolia/airlock.sh # live Sepolia (target "sepolia", cre/veto/config.sepolia.json) |
| 6 | # FORK=19631 scripts/sepolia/airlock.sh # local fork (target "sepolia-fork", a generated config in the state dir) |
| 7 | # scripts/sepolia/airlock.sh stop # stops a background airlock.sh started with the same FORK setting |
| 8 | # |
| 9 | # It runs: (cd cre && $CRE_SIM workflow simulate ./veto -T <target> --non-interactive --trigger-index 0 --listen --broadcast) |
| 10 | # with the attester key (the EIP-712 verdict secret, env name from cre/secrets.yaml) and CRE_ETH_PRIVATE_KEY from |
| 11 | # sender.key (pays the writeReport transaction to the MockKeystoneForwarder). The workflow is compiled once per |
| 12 | # source version into the state dir and shared with sweep.sh (WASM_CACHE=0 compiles inside the simulator instead). |
| 13 | # Proposals it misses (the listener was down, the log was too big to deliver) are picked up by sweep.sh. |
| 14 | # Env: CRE_SIM (default `cre`, the official CLI, which needs a logged-in session; a login-free build of the same |
| 15 | # CLI also works), KEY_DIR, SEPOLIA_RPC (only for the pre-flight reads here; the workflow itself uses the RPCs |
| 16 | # in cre/project.yaml and in the config), AIRLOCK_STATE, WORKFLOW_CONFIG (live: another config file). |
| 17 | # Output: the simulator's output on stdout and in <state dir>/airlock-<time>.log (airlock.log points to the latest). |
| 18 | # Runs in the foreground (systemd/airlock-listener.service runs it like this); stop it with Ctrl-C or `airlock.sh stop`. |
| 19 | # When the simulator exits (it ends listen mode on any failed run), it is started again after 5 s. |
| 20 | source "$(dirname "$0")/lib.sh" |
| 21 | PIDF=$STATE/airlock.pid |
| 22 | |
| 23 | if [ "${1:-}" = stop ]; then |
| 24 | if [ -f "$PIDF" ] && kill -0 "$(cat "$PIDF")" 2>/dev/null; then |
| 25 | kill "$(cat "$PIDF")" && say "stopped airlock (pid $(cat "$PIDF"))" |
| 26 | else |
| 27 | say "no airlock running for $NET" |
| 28 | fi |
| 29 | rm -f "$PIDF" |
| 30 | exit 0 |
| 31 | fi |
| 32 | [ $# = 0 ] || die "usage: [FORK=<port>] $0 [stop]" |
| 33 | if [ -f "$PIDF" ] && kill -0 "$(cat "$PIDF")" 2>/dev/null; then |
| 34 | die "an airlock listener is already running for $NET (pid $(cat "$PIDF")); stop it first: ${FORK:+FORK=$FORK }$0 stop" |
| 35 | fi |
| 36 | |
| 37 | sim_bin |
| 38 | check_rpc |
| 39 | GA=$(dep airlockAdmin) |
| 40 | RX=$(dep receiver) |
| 41 | workflow_config |
| 42 | CONFIG_ARGS=(--config "$CONFIG") |
| 43 | |
| 44 | ATTESTER_PK=$(read_key attester) |
| 45 | SENDER_PK=$(read_key sender) |
| 46 | ATTESTER=$(cast wallet address --private-key "$ATTESTER_PK") |
| 47 | SENDER=$(cast wallet address --private-key "$SENDER_PK") |
| 48 | ONCHAIN_ATTESTER=$(cast call "$RX" 'attester()(address)' --rpc-url "$RPC") |
| 49 | [ "$ONCHAIN_ATTESTER" = "$ATTESTER" ] || die "attester.key is $ATTESTER but AirlockReceiver.attester() is $ONCHAIN_ATTESTER" |
| 50 | [ "$(lc "$(cast call "$GA" 'clearanceOracle()(address)' --rpc-url "$RPC")")" = "$(lc "$RX")" ] \ |
| 51 | || die "the deployment's receiver is not AirlockAdmin's clearance oracle" |
| 52 | SBAL=$(cast balance "$SENDER" --rpc-url "$RPC") |
| 53 | GP=$(cast gas-price --rpc-url "$RPC") |
| 54 | GL=$(jq -r .gasLimit "$CONFIG") |
| 55 | PER_REPORT=$(bc <<<"$GL * $GP * 2") |
| 56 | [ "$SBAL" != 0 ] || die "sender $SENDER has no ETH on $NET (run fund-sender.sh)" |
| 57 | [ "$(bc <<<"$SBAL < $PER_REPORT")" = 0 ] || say "warning: sender balance $(cast from-wei "$SBAL") ETH may not cover a report ($GL gas at 2x $GP wei)" |
| 58 | |
| 59 | STAMP=$(date +%Y%m%d-%H%M%S) |
| 60 | LOG=$STATE/airlock-$STAMP.log |
| 61 | ln -sf "$(basename "$LOG")" "$STATE/airlock.log" |
| 62 | { |
| 63 | say "== Upgrade Airlock listener: CRE log trigger, $NET, started $(date -u +%Y-%m-%dT%H:%M:%SZ) at block $(block_now)" |
| 64 | say " AirlockAdmin $GA receiver $RX" |
| 65 | say " attester $ATTESTER report sender $SENDER ($(cast from-wei "$SBAL") ETH)" |
| 66 | say " providers $(jq -r '[.rpcs[].label]|join(", ")' "$CONFIG"), quorum $(jq -r .minAgree "$CONFIG"); target $TARGET; simulator $(basename "$SIM")" |
| 67 | } | tee "$LOG" |
| 68 | wasm_build |
| 69 | [ ${#WASM_ARGS[@]} = 0 ] || say " workflow binary $(basename "${WASM_ARGS[1]}")" | tee -a "$LOG" |
| 70 | |
| 71 | cleanup() { |
| 72 | if [ -n "${SPID:-}" ]; then kill "$SPID" 2>/dev/null || true; fi |
| 73 | rm -f "$PIDF" |
| 74 | } |
| 75 | trap cleanup EXIT |
| 76 | trap 'exit 130' INT TERM |
| 77 | cd "$ROOT/cre" |
| 78 | echo $$ >"$PIDF" |
| 79 | # The simulator in listen mode ends when one workflow run fails (an RPC timeout, a revert). Start it again after |
| 80 | # RESTART_SECS (default 5); a proposal that arrives in the gap stays Pending without a clearance until sweep.sh |
| 81 | # judges it. AIRLOCK_RESTART=0 exits instead (with the simulator's exit status). |
| 82 | while :; do |
| 83 | # The keys go to the simulator's environment only (never to any process's arguments, or to the log): the subshell |
| 84 | # exports them with the shell builtin, then becomes the simulator (exec), so $! is the simulator's pid. |
| 85 | ( |
| 86 | export "$(attester_env)=$ATTESTER_PK" CRE_ETH_PRIVATE_KEY="$SENDER_PK" |
| 87 | exec "$SIM" workflow simulate ./veto -T "$TARGET" "${CONFIG_ARGS[@]}" ${WASM_ARGS[@]+"${WASM_ARGS[@]}"} \ |
| 88 | --non-interactive --trigger-index 0 --listen --broadcast |
| 89 | ) > >(tee -a "$LOG") 2>&1 & |
| 90 | SPID=$! |
| 91 | say "airlock listening (simulator pid $SPID); log $LOG" |
| 92 | set +e |
| 93 | wait "$SPID" |
| 94 | RC=$? |
| 95 | set -e |
| 96 | SPID= |
| 97 | [ "${AIRLOCK_RESTART:-1}" = 1 ] || exit "$RC" |
| 98 | say "== simulator exited ($RC) at block $(block_now 2>/dev/null || echo '?'); restarting in ${RESTART_SECS:-5} s (sweep.sh judges what arrives meanwhile)" | tee -a "$LOG" |
| 99 | sleep "${RESTART_SECS:-5}" |
| 100 | done |