#!/bin/bash # # Verify that Dashboard, Miner and Signet node are aligned on the same chain # (expected height ~11535). Run on the bitcoin machine (192.168.1.105). # # Usage: ./verify-chain-alignment.sh # # Author: 4NK Team # Date: 2026-02-02 set -e CONTAINER_NAME="bitcoin-signet-instance" DASHBOARD_URL="${DASHBOARD_URL:-http://localhost:3020}" EXPECTED_HEIGHT_MIN="${EXPECTED_HEIGHT_MIN:-11000}" EXPECTED_HEIGHT_MAX="${EXPECTED_HEIGHT_MAX:-12000}" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" cd "$SCRIPT_DIR" DASHBOARD_TMP="$SCRIPT_DIR/.verify-chain-dashboard-$$.json" trap 'rm -f "$DASHBOARD_TMP"' EXIT echo "=== Chain alignment check (Dashboard / Miner / Signet) ===" echo "" # 1. Node: getblockchaininfo (datadir = BITCOIN_DIR from container, default /root/.bitcoin) if ! docker ps --format "{{.Names}}" | grep -q "^${CONTAINER_NAME}$"; then echo "FAIL: Container $CONTAINER_NAME is not running." exit 1 fi BITCOIN_DATADIR=$(docker exec "$CONTAINER_NAME" printenv BITCOIN_DIR 2>/dev/null || echo "/root/.bitcoin") NODE_JSON=$(sudo docker exec "$CONTAINER_NAME" bitcoin-cli -datadir="$BITCOIN_DATADIR" getblockchaininfo 2>/dev/null || true) if [ -z "$NODE_JSON" ]; then echo "FAIL: Could not get getblockchaininfo from node." exit 1 fi NODE_CHAIN=$(echo "$NODE_JSON" | grep -o '"chain"[[:space:]]*:[[:space:]]*"[^"]*"' | sed 's/.*:[[:space:]]*"\([^"]*\)".*/\1/') NODE_BLOCKS=$(echo "$NODE_JSON" | grep -o '"blocks"[[:space:]]*:[[:space:]]*[0-9]*' | grep -o '[0-9]*$') if [ -z "$NODE_BLOCKS" ]; then echo "FAIL: Could not parse blocks from node getblockchaininfo." exit 1 fi echo "Node (signet): chain=$NODE_CHAIN blocks=$NODE_BLOCKS" if [ "$NODE_CHAIN" != "signet" ]; then echo "WARN: Node chain is not 'signet' (got '$NODE_CHAIN')." fi # 2. Dashboard: /api/blockchain/info DASHBOARD_HTTP_CODE=$(curl -s -o "$DASHBOARD_TMP" -w "%{http_code}" "$DASHBOARD_URL/api/blockchain/info" 2>/dev/null || echo "000") DASHBOARD_JSON="" if [ -f "$DASHBOARD_TMP" ]; then DASHBOARD_JSON=$(cat "$DASHBOARD_TMP") fi if [ "$DASHBOARD_HTTP_CODE" = "403" ]; then echo "Dashboard: (403 Forbidden - if ALLOWED_SOURCE_IP is set, use DASHBOARD_URL from proxy or allowed host)" elif [ -n "$DASHBOARD_JSON" ] && [ "$DASHBOARD_HTTP_CODE" = "200" ]; then DASHBOARD_BLOCKS=$(echo "$DASHBOARD_JSON" | grep -o '"blocks"[[:space:]]*:[[:space:]]*[0-9]*' | grep -o '[0-9]*$') if [ -n "$DASHBOARD_BLOCKS" ]; then echo "Dashboard: blocks=$DASHBOARD_BLOCKS" if [ "$DASHBOARD_BLOCKS" != "$NODE_BLOCKS" ]; then echo "WARN: Dashboard blocks ($DASHBOARD_BLOCKS) != Node blocks ($NODE_BLOCKS)." else echo "OK: Dashboard and Node show same height." fi else echo "Dashboard: (could not parse blocks)" fi else if [ "$DASHBOARD_HTTP_CODE" != "000" ]; then echo "Dashboard: (HTTP $DASHBOARD_HTTP_CODE at $DASHBOARD_URL)" else echo "Dashboard: (not reachable at $DASHBOARD_URL)" fi fi # 3. Expected height range (~11535) echo "" if [ -n "$NODE_BLOCKS" ] && [ "$NODE_BLOCKS" -eq "$NODE_BLOCKS" ] 2>/dev/null; then if [ "$NODE_BLOCKS" -ge "$EXPECTED_HEIGHT_MIN" ] && [ "$NODE_BLOCKS" -le "$EXPECTED_HEIGHT_MAX" ]; then echo "OK: Node height $NODE_BLOCKS is in expected range [$EXPECTED_HEIGHT_MIN..$EXPECTED_HEIGHT_MAX]." else echo "WARN: Node height $NODE_BLOCKS is outside expected range [$EXPECTED_HEIGHT_MIN..$EXPECTED_HEIGHT_MAX]." echo " If the chain was lost (e.g. container recreated without persistent volume), see:" echo " fixKnowledge/signet-chain-lost-volume-persistent.md" echo " restore-signet-from-backup.sh" fi else echo "WARN: Could not validate node height (got '$NODE_BLOCKS')." fi echo "" echo "Done."