feat: add mainnet deployment script with session key injection

Automates: stop nodes, archive old chain data, deploy binaries,
inject session keys from MAINNET_WALLETS.json, start nodes sequentially.
This commit is contained in:
2026-02-14 23:43:57 +03:00
parent 3fa2fe3ea6
commit fdf72b4055
+536
View File
@@ -0,0 +1,536 @@
#!/bin/bash
# =============================================================================
# PEZKUWICHAIN MAINNET DEPLOYMENT SCRIPT
# =============================================================================
# Bu script yeni mainnet'i sıfırdan deploy eder:
# 1. Tüm node'ları durdurur (silmez)
# 2. Eski chain dizinini rename eder (veri korunur)
# 3. Yeni binary + chain spec dağıtır
# 4. Session key'leri inject eder
# 5. Node'ları sıralı başlatır
#
# Kullanım:
# bash tools/deploy-mainnet.sh [faz]
#
# Fazlar:
# check - Ön kontroller (binary, spec, wallet dosyaları var mı)
# stop - Tüm node'ları durdur
# archive - Eski chain dizinlerini rename et
# deploy - Binary + chain spec dağıt
# inject - Session key'leri inject et
# start - Node'ları sıralı başlat
# verify - Sağlık kontrolü
# all - Hepsini sırayla çalıştır
# =============================================================================
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
SDK_ROOT="$(dirname "$SCRIPT_DIR")"
# Dosya yolları
VPS_JSON="/home/mamostehp/claude/vps.json"
WALLETS_JSON="/home/mamostehp/res/MAINNET_WALLETS_20260128_235407.json"
PEZKUWI_BIN="$SDK_ROOT/target/release/pezkuwi"
TEYRCHAIN_BIN="$SDK_ROOT/target/release/pezkuwi-teyrchain"
CHAINSPEC_DIR="$SDK_ROOT/chainspecs"
# Uzak makine yolları
REMOTE_BIN_DIR="/usr/local/bin"
REMOTE_SPEC_DIR="/root/chainspec"
REMOTE_DATA_DIR="/root/.local/share/pezkuwi/chains"
OLD_CHAIN_ID="pezkuwichain_mainnet"
ARCHIVE_SUFFIX="zagros_archive_$(date +%Y%m%d)"
# Renkler
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
NC='\033[0m'
# ===== VPS Bilgileri (vps.json'dan) =====
# Bootnode IP
BOOTNODE_IP="217.77.6.126"
# Tüm VPS IP'leri (validator çalıştıranlar)
declare -A VPS_VALIDATORS
VPS_VALIDATORS=(
["62.146.235.186"]="5 6 7 21"
["217.77.6.126"]="1 2 3 4"
["217.77.15.51"]="14"
["161.97.183.44"]="13"
["161.97.185.100"]="12"
["109.123.229.159"]="16"
["161.97.116.241"]="17"
["46.250.241.121"]="18"
["164.68.121.181"]="19"
["158.220.93.23"]="20"
["207.180.194.103"]="11"
["167.86.70.241"]="10"
["167.86.108.190"]="9"
["207.180.233.147"]="8"
["178.18.252.120"]="15"
)
# Collator VPS'leri
declare -A VPS_COLLATORS
VPS_COLLATORS=(
["217.77.6.126"]="azad erin"
["173.249.57.228"]="beritan firaz"
)
ALL_VALIDATOR_IPS=(${!VPS_VALIDATORS[@]})
ALL_COLLATOR_IPS=(${!VPS_COLLATORS[@]})
# Tüm unique IP'ler
ALL_IPS=($(echo "${ALL_VALIDATOR_IPS[@]} ${ALL_COLLATOR_IPS[@]}" | tr ' ' '\n' | sort -u))
# ===== Yardımcı Fonksiyonlar =====
log_info() { echo -e "${GREEN}[INFO]${NC} $1"; }
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
log_step() { echo -e "${CYAN}[STEP]${NC} $1"; }
ssh_cmd() {
local ip=$1
shift
ssh -o ConnectTimeout=10 -o StrictHostKeyChecking=no "root@$ip" "$@"
}
scp_file() {
local src=$1
local ip=$2
local dst=$3
scp -o ConnectTimeout=10 -o StrictHostKeyChecking=no "$src" "root@$ip:$dst"
}
# ===== FAZ: CHECK =====
do_check() {
log_step "=== ÖN KONTROLLER ==="
local ok=true
# Binary kontrolleri
if [ -f "$PEZKUWI_BIN" ]; then
log_info "pezkuwi binary: OK ($(du -h "$PEZKUWI_BIN" | cut -f1))"
else
log_error "pezkuwi binary bulunamadı: $PEZKUWI_BIN"
ok=false
fi
if [ -f "$TEYRCHAIN_BIN" ]; then
log_info "pezkuwi-teyrchain binary: OK ($(du -h "$TEYRCHAIN_BIN" | cut -f1))"
else
log_error "pezkuwi-teyrchain binary bulunamadı: $TEYRCHAIN_BIN"
ok=false
fi
# Chain spec kontrolleri
for spec in relay-raw.json asset-hub-raw.json people-raw.json; do
if [ -f "$CHAINSPEC_DIR/$spec" ]; then
log_info "Chain spec $spec: OK ($(du -h "$CHAINSPEC_DIR/$spec" | cut -f1))"
else
log_error "Chain spec bulunamadı: $CHAINSPEC_DIR/$spec"
ok=false
fi
done
# Wallet dosyası
if [ -f "$WALLETS_JSON" ]; then
local wallet_count
wallet_count=$(python3 -c "import json; print(len(json.load(open('$WALLETS_JSON'))['wallets']))")
log_info "Wallet dosyası: OK ($wallet_count wallet)"
else
log_error "Wallet dosyası bulunamadı: $WALLETS_JSON"
ok=false
fi
# VPS erişim kontrolü
log_step "VPS erişim kontrolü (SSH)..."
for ip in "${ALL_IPS[@]}"; do
if ssh_cmd "$ip" "echo ok" >/dev/null 2>&1; then
log_info " $ip: erişilebilir"
else
log_error " $ip: ERİŞİLEMİYOR"
ok=false
fi
done
if $ok; then
log_info "Tüm kontroller başarılı!"
else
log_error "Bazı kontroller başarısız. Düzelttikten sonra tekrar deneyin."
return 1
fi
}
# ===== FAZ: STOP =====
do_stop() {
log_step "=== TÜM NODE'LARI DURDUR ==="
log_warn "Mevcut chain durdurulacak (veri silinmeyecek)"
for ip in "${ALL_IPS[@]}"; do
log_info "Durduruluyor: $ip"
ssh_cmd "$ip" '
# Validator servislerini durdur
systemctl list-units --type=service --state=running | grep -i pezkuwi | awk "{print \$1}" | xargs -r systemctl stop 2>/dev/null || true
# Collator servislerini durdur
systemctl list-units --type=service --state=running | grep -i "asset-hub\|people-chain" | awk "{print \$1}" | xargs -r systemctl stop 2>/dev/null || true
# Doğrula
sleep 2
remaining=$(systemctl list-units --type=service --state=running | grep -ci "pezkuwi\|asset-hub\|people-chain" || true)
echo "Kalan çalışan servis: $remaining"
' 2>/dev/null || log_warn " $ip: bağlantı sorunu (atlanıyor)"
done
log_info "Tüm node'lar durduruldu"
}
# ===== FAZ: ARCHIVE =====
do_archive() {
log_step "=== ESKİ CHAIN DİZİNLERİNİ ARCHIVE ET ==="
for ip in "${ALL_IPS[@]}"; do
log_info "Archive: $ip"
ssh_cmd "$ip" "
CHAIN_DIR='$REMOTE_DATA_DIR/$OLD_CHAIN_ID'
ARCHIVE_DIR='$REMOTE_DATA_DIR/${ARCHIVE_SUFFIX}'
if [ -d \"\$CHAIN_DIR\" ]; then
mv \"\$CHAIN_DIR\" \"\$ARCHIVE_DIR\"
echo ' Moved: $OLD_CHAIN_ID -> ${ARCHIVE_SUFFIX}'
else
echo ' Chain dizini bulunamadı (ilk kurulum olabilir)'
fi
# Teyrchain dizinlerini de archive et
for tc_dir in asset-hub-pezkuwichain people-pezkuwichain; do
TC_PATH='$REMOTE_DATA_DIR/'\$tc_dir
if [ -d \"\$TC_PATH\" ]; then
mv \"\$TC_PATH\" \"\${TC_PATH}_${ARCHIVE_SUFFIX}\"
echo \" Moved teyrchain: \$tc_dir\"
fi
done
" 2>/dev/null || log_warn " $ip: bağlantı sorunu"
done
log_info "Eski chain verileri archive edildi"
}
# ===== FAZ: DEPLOY =====
do_deploy() {
log_step "=== BINARY + CHAIN SPEC DAĞIT ==="
# Tüm VPS'lere relay binary + relay chain spec
for ip in "${ALL_IPS[@]}"; do
log_info "Deploy: $ip"
# Binary
scp_file "$PEZKUWI_BIN" "$ip" "$REMOTE_BIN_DIR/pezkuwi"
ssh_cmd "$ip" "chmod +x $REMOTE_BIN_DIR/pezkuwi"
# Relay chain spec
ssh_cmd "$ip" "mkdir -p $REMOTE_SPEC_DIR"
scp_file "$CHAINSPEC_DIR/relay-raw.json" "$ip" "$REMOTE_SPEC_DIR/relay-raw.json"
echo " Binary + relay spec OK"
done
# Collator VPS'lere teyrchain binary + chain spec'leri
for ip in "${ALL_COLLATOR_IPS[@]}"; do
log_info "Deploy teyrchain: $ip"
scp_file "$TEYRCHAIN_BIN" "$ip" "$REMOTE_BIN_DIR/pezkuwi-teyrchain"
ssh_cmd "$ip" "chmod +x $REMOTE_BIN_DIR/pezkuwi-teyrchain"
scp_file "$CHAINSPEC_DIR/asset-hub-raw.json" "$ip" "$REMOTE_SPEC_DIR/asset-hub-raw.json"
scp_file "$CHAINSPEC_DIR/people-raw.json" "$ip" "$REMOTE_SPEC_DIR/people-raw.json"
echo " Teyrchain binary + specs OK"
done
log_info "Deploy tamamlandı"
}
# ===== FAZ: INJECT =====
do_inject() {
log_step "=== SESSION KEY'LERİ INJECT ET ==="
# Python ile wallet JSON'dan key injection komutları oluştur ve çalıştır
python3 << 'PYEOF'
import json
import subprocess
import sys
import time
WALLETS_FILE = "/home/mamostehp/res/MAINNET_WALLETS_20260128_235407.json"
# VPS -> Validator mapping (validator numarası -> VPS IP)
# Her VPS'te validator'lar farklı RPC portlarında çalışır
# İlk validator 9944, ikincisi 9945, üçüncüsü 9946, dördüncüsü 9947
VPS_VALIDATOR_MAP = {
"62.146.235.186": [5, 6, 7, 21],
"217.77.6.126": [1, 2, 3, 4],
"217.77.15.51": [14],
"161.97.183.44": [13],
"161.97.185.100": [12],
"109.123.229.159": [16],
"161.97.116.241": [17],
"46.250.241.121": [18],
"164.68.121.181": [19],
"158.220.93.23": [20],
"207.180.194.103": [11],
"167.86.70.241": [10],
"167.86.108.190": [9],
"207.180.233.147": [8],
"178.18.252.120": [15],
}
# Collator mapping: (IP, port) -> collator name
COLLATOR_MAP = {
("217.77.6.126", 40944): "Asset_Hub_Collator_Azad",
("217.77.6.126", 41944): "People_Chain_Collator_Erin",
("173.249.57.228", 40944): "Asset_Hub_Collator_Beritan",
("173.249.57.228", 41944): "People_Chain_Collator_Firaz",
}
# Key type mapping (substrate key_type_id)
KEY_TYPES = {
"babe": "babe",
"grandpa": "gran",
"para_validator": "para",
"para_assignment": "asgn",
"authority_discovery": "audi",
"beefy": "beef",
}
with open(WALLETS_FILE) as f:
data = json.load(f)
wallets = {w["name"]: w for w in data["wallets"]}
def inject_key(ip, port, key_type_id, seed, public_key):
"""Inject a single key via RPC"""
payload = json.dumps({
"jsonrpc": "2.0",
"id": 1,
"method": "author_insertKey",
"params": [key_type_id, seed, public_key]
})
cmd = [
"ssh", "-o", "ConnectTimeout=10", "-o", "StrictHostKeyChecking=no",
f"root@{ip}",
f"curl -sH 'Content-Type: application/json' -d '{payload}' http://localhost:{port}"
]
try:
result = subprocess.run(cmd, capture_output=True, text=True, timeout=15)
if '"result"' in result.stdout:
return True
else:
print(f" WARN: {result.stdout.strip()}", file=sys.stderr)
return False
except Exception as e:
print(f" ERROR: {e}", file=sys.stderr)
return False
def inject_validator_keys(ip, port, validator_num):
"""Inject all 6 session keys for a validator"""
session_name = f"Validator_{validator_num:02d}_Session"
session = wallets.get(session_name)
if not session:
print(f" ERROR: {session_name} bulunamadı!")
return False
seed = session["master_seed"]
keys = session["keys"]
success = True
for key_name, key_type_id in KEY_TYPES.items():
public_key = keys[key_name]["public_key"]
ok = inject_key(ip, port, key_type_id, seed, public_key)
status = "OK" if ok else "FAIL"
print(f" {key_type_id}: {status}")
if not ok:
success = False
return success
def inject_collator_key(ip, port, collator_name):
"""Inject aura key for a collator"""
collator = wallets.get(collator_name)
if not collator:
print(f" ERROR: {collator_name} bulunamadı!")
return False
seed = collator["seed_phrase"]
public_key = collator["public_key"]
ok = inject_key(ip, port, "aura", seed, public_key)
status = "OK" if ok else "FAIL"
print(f" aura: {status}")
return ok
# === Validator key injection ===
print("=== VALIDATOR SESSION KEY INJECTION ===")
total_ok = 0
total_fail = 0
for ip, validators in sorted(VPS_VALIDATOR_MAP.items()):
for idx, val_num in enumerate(validators):
port = 9944 + idx # Her validator farklı RPC portu
print(f"\n Validator {val_num:02d} @ {ip}:{port}")
if inject_validator_keys(ip, port, val_num):
total_ok += 1
else:
total_fail += 1
print(f"\nValidator sonuç: {total_ok} OK, {total_fail} FAIL")
# === Collator key injection ===
print("\n=== COLLATOR KEY INJECTION ===")
for (ip, port), collator_name in sorted(COLLATOR_MAP.items()):
print(f"\n {collator_name} @ {ip}:{port}")
inject_collator_key(ip, port, collator_name)
print("\nKey injection tamamlandı!")
PYEOF
log_info "Session key injection tamamlandı"
}
# ===== FAZ: START =====
do_start() {
log_step "=== NODE'LARI SIRALI BAŞLAT ==="
# 1. Bootnode (VPS3 - Validator 1)
log_info "1/4: Bootnode başlatılıyor (VPS3 - $BOOTNODE_IP)"
ssh_cmd "$BOOTNODE_IP" '
systemctl start pezkuwi-validator-1.service
sleep 5
systemctl start pezkuwi-validator-2.service
systemctl start pezkuwi-validator-3.service
systemctl start pezkuwi-validator-4.service
' 2>/dev/null
log_info " VPS3 validator'ları başlatıldı, 30 saniye bekleniyor..."
sleep 30
# 2. VPS2 validator'ları
log_info "2/4: VPS2 validator'ları başlatılıyor (62.146.235.186)"
ssh_cmd "62.146.235.186" '
systemctl start pezkuwi-validator-5.service
systemctl start pezkuwi-validator-6.service
systemctl start pezkuwi-validator-7.service
systemctl start pezkuwi-validator-21.service
' 2>/dev/null
log_info " VPS2 başlatıldı, 15 saniye bekleniyor..."
sleep 15
# 3. Kalan validator VPS'leri
log_info "3/4: Kalan validator'lar başlatılıyor..."
for ip in "${ALL_VALIDATOR_IPS[@]}"; do
# VPS3 ve VPS2 zaten başlatıldı
if [ "$ip" = "$BOOTNODE_IP" ] || [ "$ip" = "62.146.235.186" ]; then
continue
fi
ssh_cmd "$ip" '
for svc in $(systemctl list-unit-files | grep pezkuwi-validator | awk "{print \$1}"); do
systemctl start "$svc" 2>/dev/null || true
done
' 2>/dev/null &
done
wait
log_info " Tüm validator'lar başlatıldı"
# 4. Relay chain'in finalize etmesini bekle
log_info "4/4: Relay chain finalizasyon bekleniyor (60 saniye)..."
sleep 60
# Sağlık kontrolü
local health
health=$(ssh_cmd "$BOOTNODE_IP" "curl -sH 'Content-Type: application/json' -d '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"system_health\",\"params\":[]}' http://localhost:9944" 2>/dev/null)
echo " Relay health: $health"
log_info "Relay chain başlatıldı!"
log_warn "Collator'ları başlatmadan önce relay chain'in finalize ettiğini doğrulayın."
echo ""
echo "Collator'ları başlatmak için:"
echo " ssh root@$BOOTNODE_IP 'systemctl start asset-hub-azad.service && systemctl start people-chain-erin.service'"
echo " ssh root@173.249.57.228 'systemctl start asset-hub-beritan.service && systemctl start people-chain-firaz.service'"
}
# ===== FAZ: VERIFY =====
do_verify() {
log_step "=== SAĞLIK KONTROLÜ ==="
echo ""
log_info "Relay Chain:"
ssh_cmd "$BOOTNODE_IP" "
echo ' Health:'
curl -sH 'Content-Type: application/json' -d '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"system_health\",\"params\":[]}' http://localhost:9944
echo ''
echo ' Version:'
curl -sH 'Content-Type: application/json' -d '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"state_getRuntimeVersion\",\"params\":[]}' http://localhost:9944 | python3 -c 'import json,sys; d=json.load(sys.stdin); print(\" specVersion:\", d[\"result\"][\"specVersion\"])'
echo ' Header:'
curl -sH 'Content-Type: application/json' -d '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"chain_getHeader\",\"params\":[]}' http://localhost:9944 | python3 -c 'import json,sys; d=json.load(sys.stdin); print(\" Block #\", int(d[\"result\"][\"number\"], 16))'
" 2>/dev/null
echo ""
log_info "Asset Hub:"
ssh_cmd "$BOOTNODE_IP" "
curl -sH 'Content-Type: application/json' -d '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"system_health\",\"params\":[]}' http://localhost:40944
echo ''
curl -sH 'Content-Type: application/json' -d '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"chain_getHeader\",\"params\":[]}' http://localhost:40944 | python3 -c 'import json,sys; d=json.load(sys.stdin); print(\" Block #\", int(d[\"result\"][\"number\"], 16))' 2>/dev/null || echo ' (henüz blok yok)'
" 2>/dev/null
echo ""
log_info "People Chain:"
ssh_cmd "$BOOTNODE_IP" "
curl -sH 'Content-Type: application/json' -d '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"system_health\",\"params\":[]}' http://localhost:41944
echo ''
curl -sH 'Content-Type: application/json' -d '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"chain_getHeader\",\"params\":[]}' http://localhost:41944 | python3 -c 'import json,sys; d=json.load(sys.stdin); print(\" Block #\", int(d[\"result\"][\"number\"], 16))' 2>/dev/null || echo ' (henüz blok yok)'
" 2>/dev/null
echo ""
log_info "Doğrulama tamamlandı"
}
# ===== MAIN =====
PHASE="${1:-help}"
case "$PHASE" in
check) do_check ;;
stop) do_stop ;;
archive) do_archive ;;
deploy) do_deploy ;;
inject) do_inject ;;
start) do_start ;;
verify) do_verify ;;
all)
do_check
echo ""
read -p "Devam etmek istiyor musunuz? (y/N) " confirm
[ "$confirm" = "y" ] || exit 0
do_stop
do_archive
do_deploy
echo ""
log_warn "Node'ları başlatıp key inject etmeniz gerekiyor."
log_warn "Önce: bash tools/deploy-mainnet.sh start"
log_warn "Node'lar ayağa kalkınca: bash tools/deploy-mainnet.sh inject"
log_warn "Sonra: bash tools/deploy-mainnet.sh verify"
;;
*)
echo "Kullanım: $0 {check|stop|archive|deploy|inject|start|verify|all}"
echo ""
echo "Fazlar:"
echo " check - Ön kontroller"
echo " stop - Tüm node'ları durdur"
echo " archive - Eski chain verilerini yedekle"
echo " deploy - Binary + chain spec dağıt"
echo " inject - Session key inject (node'lar çalışırken)"
echo " start - Node'ları sıralı başlat"
echo " verify - Sağlık kontrolü"
echo " all - check + stop + archive + deploy"
;;
esac