- Institutional / JVMTM / reserve-provenance / GRU transport + standards JSON - Validation and verify scripts (Blockscout labels, x402, GRU preflight, P1 local path) - Wormhole wiring in AGENTS, MCP_SETUP, MASTER_INDEX, 04-configuration README - Meta docs, integration gaps, live verification log, architecture updates - CI validate-config workflow updates Operator/LAN items, submodule working trees, and public token-aggregation edge routes remain follow-up (see TODOS_CONSOLIDATED P1). Made-with: Cursor
137 lines
4.6 KiB
Bash
Executable File
137 lines
4.6 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Rotate the Chain 138 oracle publisher off the shared deployer key by provisioning
|
|
# a dedicated transmitter key, adding it to the oracle aggregator, updating CT 3500,
|
|
# and removing the legacy deployer transmitter after the new key confirms an update.
|
|
#
|
|
# Usage:
|
|
# bash scripts/deployment/rotate-oracle-publisher-transmitter.sh [--dry-run]
|
|
#
|
|
# Env overrides:
|
|
# PROXMOX_NODE_IP default 192.168.11.12
|
|
# ORACLE_VMID default 3500
|
|
# ORACLE_SECRET_FILE default ~/.secure-secrets/chain138-oracle-publisher.env
|
|
# ORACLE_AGGREGATOR_ADDRESS default 0x99b3511a2d315a497c8112c1fdd8d508d4b1e506
|
|
# ORACLE_FUND_WEI default 100000000000000000 (0.1 native token)
|
|
# NEW_ORACLE_PRIVATE_KEY optional pre-generated 0x-prefixed key
|
|
#
|
|
set -euo pipefail
|
|
|
|
DRY_RUN=0
|
|
if [[ "${1:-}" == "--dry-run" ]]; then
|
|
DRY_RUN=1
|
|
fi
|
|
|
|
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
|
cd "$ROOT"
|
|
had_nounset=0
|
|
if [[ $- == *u* ]]; then
|
|
had_nounset=1
|
|
set +u
|
|
fi
|
|
set -a
|
|
source scripts/lib/load-project-env.sh >/dev/null 2>&1
|
|
set +a
|
|
if [[ "$had_nounset" -eq 1 ]]; then
|
|
set -u
|
|
fi
|
|
|
|
RPC="${DEPLOY_RPC_URL_138:-${RPC_URL_138:-http://192.168.11.211:8545}}"
|
|
NODE_IP="${PROXMOX_NODE_IP:-192.168.11.12}"
|
|
ORACLE_VMID="${ORACLE_VMID:-3500}"
|
|
AGG="${ORACLE_AGGREGATOR_ADDRESS:-0x99b3511a2d315a497c8112c1fdd8d508d4b1e506}"
|
|
SECRET_FILE="${ORACLE_SECRET_FILE:-$HOME/.secure-secrets/chain138-oracle-publisher.env}"
|
|
DEPLOYER_ADDR="$(cast wallet address --private-key "$PRIVATE_KEY")"
|
|
NEW_KEY="${NEW_ORACLE_PRIVATE_KEY:-0x$(openssl rand -hex 32)}"
|
|
NEW_ADDR="$(cast wallet address --private-key "$NEW_KEY")"
|
|
ORACLE_FUND_WEI="${ORACLE_FUND_WEI:-100000000000000000}"
|
|
|
|
echo "Oracle transmitter rotation"
|
|
echo " node: $NODE_IP"
|
|
echo " vmid: $ORACLE_VMID"
|
|
echo " aggregator: $AGG"
|
|
echo " admin: $DEPLOYER_ADDR"
|
|
echo " new signer: $NEW_ADDR"
|
|
echo " secret file: $SECRET_FILE"
|
|
echo " fund wei: $ORACLE_FUND_WEI"
|
|
|
|
if [[ "$DRY_RUN" -eq 1 ]]; then
|
|
exit 0
|
|
fi
|
|
|
|
mkdir -p "$(dirname "$SECRET_FILE")"
|
|
umask 077
|
|
cat >"$SECRET_FILE" <<EOF
|
|
CHAIN138_ORACLE_PUBLISHER_PRIVATE_KEY=$NEW_KEY
|
|
CHAIN138_ORACLE_PUBLISHER_ADDRESS=$NEW_ADDR
|
|
CHAIN138_ORACLE_AGGREGATOR_ADDRESS=$AGG
|
|
CHAIN138_ORACLE_ROTATED_AT=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
EOF
|
|
|
|
if [[ "$(cast call "$AGG" 'isTransmitter(address)(bool)' "$NEW_ADDR" --rpc-url "$RPC")" != "true" ]]; then
|
|
cast send "$AGG" 'addTransmitter(address)' "$NEW_ADDR" \
|
|
--rpc-url "$RPC" \
|
|
--private-key "$PRIVATE_KEY" \
|
|
--legacy \
|
|
--gas-price 1000000000 \
|
|
>/dev/null
|
|
fi
|
|
|
|
new_balance="$(cast balance "$NEW_ADDR" --rpc-url "$RPC")"
|
|
if [[ "$new_balance" -lt "$ORACLE_FUND_WEI" ]]; then
|
|
cast send "$NEW_ADDR" \
|
|
--value "$ORACLE_FUND_WEI" \
|
|
--rpc-url "$RPC" \
|
|
--private-key "$PRIVATE_KEY" \
|
|
--legacy \
|
|
--gas-price 1000000000 \
|
|
>/dev/null
|
|
fi
|
|
|
|
ssh -o BatchMode=yes -o StrictHostKeyChecking=no "root@$NODE_IP" "\
|
|
pct exec $ORACLE_VMID -- bash -lc 'set -euo pipefail; \
|
|
ENV=/opt/oracle-publisher/.env; \
|
|
grep -q \"^PRIVATE_KEY=\" \$ENV && sed -i \"s|^PRIVATE_KEY=.*|PRIVATE_KEY=$NEW_KEY|\" \$ENV || echo \"PRIVATE_KEY=$NEW_KEY\" >> \$ENV; \
|
|
systemctl restart oracle-publisher.service; \
|
|
systemctl is-active oracle-publisher.service >/dev/null'"
|
|
|
|
echo "Waiting for new transmitter to confirm an oracle update..."
|
|
tx_hash=""
|
|
for _ in {1..24}; do
|
|
line="$(ssh -o BatchMode=yes -o StrictHostKeyChecking=no "root@$NODE_IP" "pct exec $ORACLE_VMID -- journalctl -u oracle-publisher.service -n 20 --no-pager | grep 'Transaction confirmed:' | tail -n 1" || true)"
|
|
if [[ -n "$line" ]]; then
|
|
tx_hash="$(printf '%s' "$line" | grep -oE '0x[a-fA-F0-9]{64}' | tail -n 1 || true)"
|
|
fi
|
|
if [[ -n "$tx_hash" ]]; then
|
|
tx_from="$(cast receipt "$tx_hash" --rpc-url "$RPC" | awk '/^from /{print $2}')"
|
|
if [[ "${tx_from,,}" == "${NEW_ADDR,,}" ]]; then
|
|
break
|
|
fi
|
|
fi
|
|
sleep 5
|
|
done
|
|
|
|
if [[ -z "$tx_hash" ]]; then
|
|
echo "ERROR: No confirmed oracle update observed from the new transmitter." >&2
|
|
exit 1
|
|
fi
|
|
|
|
tx_from="$(cast receipt "$tx_hash" --rpc-url "$RPC" | awk '/^from /{print $2}')"
|
|
if [[ "${tx_from,,}" != "${NEW_ADDR,,}" ]]; then
|
|
echo "ERROR: Latest confirmed oracle update was not sent by the new transmitter: $tx_from" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if [[ "$(cast call "$AGG" 'isTransmitter(address)(bool)' "$DEPLOYER_ADDR" --rpc-url "$RPC")" == "true" ]]; then
|
|
cast send "$AGG" 'removeTransmitter(address)' "$DEPLOYER_ADDR" \
|
|
--rpc-url "$RPC" \
|
|
--private-key "$PRIVATE_KEY" \
|
|
--legacy \
|
|
--gas-price 1000000000 \
|
|
>/dev/null
|
|
fi
|
|
|
|
echo "Rotation complete."
|
|
echo " new transmitter: $NEW_ADDR"
|
|
echo " confirmed tx: $tx_hash"
|
|
echo " deployer signer removed from transmitter set."
|