diff --git a/.github/workflows/chainspec-sync-check.yml b/.github/workflows/chainspec-sync-check.yml new file mode 100644 index 00000000..74ec1632 --- /dev/null +++ b/.github/workflows/chainspec-sync-check.yml @@ -0,0 +1,118 @@ +name: Chainspec sync check + +on: + push: + branches: [main] + pull_request: + branches: [main] + paths: + - 'chainspecs/**' + - '.github/workflows/chainspec-sync-check.yml' + - '.github/env' + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + set-image: + uses: ./.github/workflows/set-image.yml + + # Pre-warm the binary cache once so matrix legs hit the cache instead of + # each one source-building polkadot-omni-node independently. + setup: + needs: [set-image] + name: Setup + runs-on: parity-large + container: + image: ${{ needs.set-image.outputs.CI_IMAGE }} + steps: + - name: Checkout sources + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + + - name: Load common environment variables via env file + run: cat .github/env >> $GITHUB_ENV + + - uses: ./.github/actions/install-just + + - name: Cache polkadot-node binaries + id: cache-binaries + uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5 + with: + path: ${{ env.POLKADOT_BINARIES_DIR }}/polkadot-node + key: polkadot-node-${{ runner.os }}-${{ env.POLKADOT_NODE_VERSION }} + + - name: Populate cache + if: steps.cache-binaries.outputs.cache-hit != 'true' + run: just binaries-polkadot + + sync-check: + needs: [set-image, setup] + name: Sync (${{ matrix.name }}) + runs-on: parity-large + container: + image: ${{ needs.set-image.outputs.CI_IMAGE }} + timeout-minutes: 30 + strategy: + fail-fast: false + matrix: + include: + - name: polkadot + chainspec: chainspecs/polkadot-chainspec.json + relay_rpc: wss://rpc.polkadot.io + - name: westend + chainspec: chainspecs/westend-chainspec.json + relay_rpc: wss://westend-rpc.polkadot.io + - name: paseo-next + chainspec: chainspecs/paseo-next-chainspec.json + relay_rpc: wss://paseo.dotters.network + - name: paseo-next-v2 + chainspec: chainspecs/paseo-next-v2-chainspec.json + relay_rpc: wss://paseo.dotters.network + steps: + - name: Checkout sources + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + + - name: Load common environment variables via env file + run: cat .github/env >> $GITHUB_ENV + + - uses: ./.github/actions/install-just + + - name: Restore binary cache + uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5 + with: + path: ${{ env.POLKADOT_BINARIES_DIR }}/polkadot-node + key: polkadot-node-${{ runner.os }}-${{ env.POLKADOT_NODE_VERSION }} + fail-on-cache-miss: true + + - name: Resolve binary directory + run: | + POLKADOT_DIR="$(just binaries-polkadot)" + echo "$POLKADOT_DIR" >> "$GITHUB_PATH" + + - name: Sync a few blocks + run: ./scripts/chainspec_sync_check.sh "${{ matrix.chainspec }}" "${{ matrix.relay_rpc }}" + + - name: Upload omni-node log on failure + if: failure() + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: omni-node-${{ matrix.name }}.log + path: omni-node.log + retention-days: 7 + + sync-check-complete: + name: All chainspec sync checks passed + needs: [sync-check] + if: always() + runs-on: ubuntu-latest + steps: + - name: Decide outcome + if: contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') + run: | + echo "Chainspec sync check failed or was cancelled" + exit 1 diff --git a/scripts/chainspec_sync_check.sh b/scripts/chainspec_sync_check.sh new file mode 100755 index 00000000..9d181168 --- /dev/null +++ b/scripts/chainspec_sync_check.sh @@ -0,0 +1,69 @@ +#!/usr/bin/env bash +# Boot `polkadot-omni-node` against a chainspec and wait until the parachain +# imports a few blocks. +# +# Usage: chainspec_sync_check.sh +# +# Env overrides (with defaults): +# TARGET_BLOCKS=3 Best-block height the node must reach to pass. +# TIMEOUT_SECONDS=600 Hard cap on how long to wait for that height. +# RPC_PORT=9944 Local RPC port to bind for progress polling. +# LOG=omni-node.log File where the node's stdout/stderr is captured. + +set -euo pipefail + +CHAINSPEC="${1:-}" +RELAY_RPC="${2:-}" +TARGET_BLOCKS="${TARGET_BLOCKS:-3}" +TIMEOUT_SECONDS="${TIMEOUT_SECONDS:-600}" +RPC_PORT="${RPC_PORT:-9944}" +LOG="${LOG:-omni-node.log}" + +if [ -z "$CHAINSPEC" ] || [ -z "$RELAY_RPC" ]; then + echo "usage: $0 " >&2 + exit 2 +fi + +polkadot-omni-node \ + --chain "$CHAINSPEC" \ + --tmp \ + --no-hardware-benchmarks \ + --rpc-port "$RPC_PORT" \ + --relay-chain-rpc-urls "$RELAY_RPC" \ + --log info \ + > "$LOG" 2>&1 & +NODE_PID=$! + +cleanup() { + kill "$NODE_PID" 2>/dev/null || true + wait "$NODE_PID" 2>/dev/null || true +} +trap cleanup EXIT + +deadline=$(( $(date +%s) + TIMEOUT_SECONDS )) +best=0 +while [ "$(date +%s)" -lt "$deadline" ]; do + if ! kill -0 "$NODE_PID" 2>/dev/null; then + echo "polkadot-omni-node exited before reaching block $TARGET_BLOCKS" + tail -n 200 "$LOG" + exit 1 + fi + + response=$(curl -fs -m 5 -H "Content-Type: application/json" \ + -d '{"jsonrpc":"2.0","method":"chain_getHeader","params":[],"id":1}' \ + "http://127.0.0.1:${RPC_PORT}" || true) + hex=$(echo "$response" | jq -r '.result.number // "0x0"' 2>/dev/null || echo "0x0") + best=$(( hex )) + echo "best block: $best" + + if [ "$best" -ge "$TARGET_BLOCKS" ]; then + echo "imported $best blocks for $CHAINSPEC" + exit 0 + fi + + sleep 10 +done + +echo "did not import $TARGET_BLOCKS blocks within ${TIMEOUT_SECONDS}s (last best=$best)" +tail -n 200 "$LOG" +exit 1