From aa62eacae1a333cb4708c9414b04c75553551c3f Mon Sep 17 00:00:00 2001 From: Marios Christou Date: Tue, 9 Dec 2025 16:16:53 +0200 Subject: [PATCH 1/6] Add integration CI workflow: bite, spawn, and block production checks --- .github/workflows/integration.yml | 179 ++++++++++++++++++++++++++++++ 1 file changed, 179 insertions(+) create mode 100644 .github/workflows/integration.yml diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml new file mode 100644 index 0000000..416aaac --- /dev/null +++ b/.github/workflows/integration.yml @@ -0,0 +1,179 @@ +name: Zombie Bite CI Integration + +on: + push: + branches: [main] + pull_request: + branches: [main] + +jobs: + zombie-bite-test: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + + - name: Install Rust + uses: dtolnay/rust-toolchain@stable + + - name: Install protobuf compiler + run: | + sudo apt-get update + sudo apt-get install -y protobuf-compiler + + - name: Download doppelganger binaries + run: | + VERSION_TO_DOWNLOAD=$(curl -s https://api.github.com/repos/paritytech/doppelganger-wrapper/releases/latest | jq -r .tag_name) + echo "Downloading doppelganger binaries version: $VERSION_TO_DOWNLOAD" + + mkdir -p ${{ github.workspace }}/bins + + for bin in doppelganger doppelganger-parachain polkadot-execute-worker polkadot-prepare-worker; do + echo "Downloading $bin..." + curl -L -o ${{ github.workspace }}/bins/$bin \ + https://github.com/paritytech/doppelganger-wrapper/releases/download/$VERSION_TO_DOWNLOAD/$bin + chmod +x ${{ github.workspace }}/bins/$bin + done + + echo "${{ github.workspace }}/bins" >> $GITHUB_PATH + ls -lh ${{ github.workspace }}/bins + + - name: Build zombie-bite + run: cargo build --release + + # TODO: change people to AH. + - name: Run bite (polkadot/AH/coretime) + run: | + target/release/zombie-bite bite \ + --rc polkadot \ + --parachains asset-hub,coretime \ + --base-path ${{ github.workspace }}/zombie-bite-output + + - name: Run spawn in background + run: | + target/release/zombie-bite spawn \ + --base-path ${{ github.workspace }}/zombie-bite-output & + echo $! > spawn.pid + sleep 60 + + - name: Check spawn process + run: | + if [ ! -f spawn.pid ]; then + echo "Spawn process not found!" + exit 1 + fi + + if ! ps -p $(cat spawn.pid) > /dev/null; then + echo "Spawn process died!" + exit 1 + fi + echo "Spawn process is alive (PID: $(cat spawn.pid))" + + - name: Ensure block production + run: | + ZOMBIE_JSON="${{ github.workspace }}/zombie-bite-output/spawn/zombie.json" + + if [ ! -f "$ZOMBIE_JSON" ]; then + echo "zombie.json not found!" + exit 1 + fi + + echo "Monitoring block production (checking every 15s for up to 5 minutes)..." + + # Extract node names and prometheus ports from zombie.json + VALIDATORS=$(jq -r '.relay_chain[].validators[] | "\(.name):\(.prometheus_port[0])"' "$ZOMBIE_JSON") + COLLATORS=$(jq -r '.parachains[].collators[] | "\(.name):\(.prometheus_port[0])"' "$ZOMBIE_JSON") + + MAX_ATTEMPTS=20 + ATTEMPT=0 + declare -A INITIAL_BLOCKS + + while [ $ATTEMPT -lt $MAX_ATTEMPTS ]; do + ATTEMPT=$((ATTEMPT + 1)) + echo "" + echo "Check $ATTEMPT/$MAX_ATTEMPTS..." + + ALL_OK=true + + # Check validators + for node in $VALIDATORS; do + NAME=$(echo $node | cut -d: -f1) + PORT=$(echo $node | cut -d: -f2) + BLOCK=$(curl -s "http://127.0.0.1:${PORT}/metrics" | grep '^block_height{status="best"}' | awk '{print $2}' || echo "0") + + if [ $ATTEMPT -eq 1 ]; then + INITIAL_BLOCKS[$NAME]=$BLOCK + echo "$NAME: initial block height $BLOCK" + elif [ "$BLOCK" -gt "${INITIAL_BLOCKS[$NAME]}" ]; then + echo "$NAME: producing blocks (height: $BLOCK)" + else + echo "$NAME: waiting... (height: $BLOCK)" + ALL_OK=false + fi + done + + # Check collators + for node in $COLLATORS; do + NAME=$(echo $node | cut -d: -f1) + PORT=$(echo $node | cut -d: -f2) + BLOCK=$(curl -s "http://127.0.0.1:${PORT}/metrics" | grep '^block_height{status="best"}' | awk '{print $2}' || echo "0") + + if [ $ATTEMPT -eq 1 ]; then + INITIAL_BLOCKS[$NAME]=$BLOCK + echo "$NAME: initial block height $BLOCK" + elif [ "$BLOCK" -gt "${INITIAL_BLOCKS[$NAME]}" ] && [ "$BLOCK" -gt "0" ]; then + echo "$NAME: producing blocks (height: $BLOCK)" + else + echo "$NAME: waiting... (height: $BLOCK)" + ALL_OK=false + fi + done + + if [ "$ALL_OK" = true ] && [ $ATTEMPT -gt 1 ]; then + echo "" + echo "All nodes are producing blocks!" + exit 0 + fi + + if [ $ATTEMPT -lt $MAX_ATTEMPTS ]; then + sleep 15 + fi + done + + echo "" + echo "Block production timeout after 5 minutes!" + exit 1 + + - name: Cleanup + if: always() + run: | + if [ ! -f spawn.pid ]; then + echo "No spawn process to cleanup" + exit 0 + fi + + PID=$(cat spawn.pid) + echo "Creating stop file for shutdown..." + touch ${{ github.workspace }}/zombie-bite-output/spawn/stop.txt + + echo "Waiting for process $PID to stop (max 30s)..." + for i in {1..30}; do + if ! ps -p $PID > /dev/null 2>&1; then + echo "Process stopped after ${i}s" + rm -f spawn.pid + exit 0 + fi + sleep 1 + done + + echo "Process did not stop gracefully, sending SIGTERM..." + kill $PID 2>/dev/null || true + sleep 5 + + if ps -p $PID > /dev/null 2>&1; then + echo "Failed to stop process $PID" + exit 1 + else + echo "Process stopped" + rm -f spawn.pid + fi From 594c1de5bb3bf3d8b367167dd9aedd271ca2140c Mon Sep 17 00:00:00 2001 From: Marios Christou Date: Thu, 11 Dec 2025 10:07:14 +0200 Subject: [PATCH 2/6] Change back to people to verify if there is problem with space --- .github/workflows/integration.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index 416aaac..0f69eb9 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -46,7 +46,7 @@ jobs: run: | target/release/zombie-bite bite \ --rc polkadot \ - --parachains asset-hub,coretime \ + --parachains people,coretime \ --base-path ${{ github.workspace }}/zombie-bite-output - name: Run spawn in background From 0232335c046f93608864eef7003aee3f53fb0623 Mon Sep 17 00:00:00 2001 From: Marios Christou Date: Thu, 11 Dec 2025 10:35:46 +0200 Subject: [PATCH 3/6] Fix jq query for validators and collators --- .github/workflows/integration.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index 0f69eb9..ab49344 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -80,9 +80,9 @@ jobs: echo "Monitoring block production (checking every 15s for up to 5 minutes)..." - # Extract node names and prometheus ports from zombie.json - VALIDATORS=$(jq -r '.relay_chain[].validators[] | "\(.name):\(.prometheus_port[0])"' "$ZOMBIE_JSON") - COLLATORS=$(jq -r '.parachains[].collators[] | "\(.name):\(.prometheus_port[0])"' "$ZOMBIE_JSON") + # Extract node names and prometheus URIs from zombie.json + VALIDATORS=$(jq -r '.relay.nodes[]? | "\(.name):\(.prometheus_uri)"' "$ZOMBIE_JSON") + COLLATORS=$(jq -r '.parachains[]?[]?.collators[]? | "\(.name):\(.prometheus_uri)"' "$ZOMBIE_JSON") MAX_ATTEMPTS=20 ATTEMPT=0 @@ -98,8 +98,8 @@ jobs: # Check validators for node in $VALIDATORS; do NAME=$(echo $node | cut -d: -f1) - PORT=$(echo $node | cut -d: -f2) - BLOCK=$(curl -s "http://127.0.0.1:${PORT}/metrics" | grep '^block_height{status="best"}' | awk '{print $2}' || echo "0") + METRICS_URL=$(echo $node | cut -d: -f2-) + BLOCK=$(curl -s "${METRICS_URL}" | grep '^block_height{status="best"}' | awk '{print $2}' || echo "0") if [ $ATTEMPT -eq 1 ]; then INITIAL_BLOCKS[$NAME]=$BLOCK @@ -115,8 +115,8 @@ jobs: # Check collators for node in $COLLATORS; do NAME=$(echo $node | cut -d: -f1) - PORT=$(echo $node | cut -d: -f2) - BLOCK=$(curl -s "http://127.0.0.1:${PORT}/metrics" | grep '^block_height{status="best"}' | awk '{print $2}' || echo "0") + METRICS_URL=$(echo $node | cut -d: -f2-) + BLOCK=$(curl -s "${METRICS_URL}" | grep '^block_height{status="best"}' | awk '{print $2}' || echo "0") if [ $ATTEMPT -eq 1 ]; then INITIAL_BLOCKS[$NAME]=$BLOCK From 1380509dbdc3fb7ca8df3543d19af1747d734b21 Mon Sep 17 00:00:00 2001 From: Marios Christou Date: Thu, 11 Dec 2025 11:05:42 +0200 Subject: [PATCH 4/6] Fix initial block number --- .github/workflows/integration.yml | 39 ++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index ab49344..bff4788 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -84,6 +84,9 @@ jobs: VALIDATORS=$(jq -r '.relay.nodes[]? | "\(.name):\(.prometheus_uri)"' "$ZOMBIE_JSON") COLLATORS=$(jq -r '.parachains[]?[]?.collators[]? | "\(.name):\(.prometheus_uri)"' "$ZOMBIE_JSON") + echo "Validators: $VALIDATORS" + echo "Collators: $COLLATORS" + MAX_ATTEMPTS=20 ATTEMPT=0 declare -A INITIAL_BLOCKS @@ -99,12 +102,19 @@ jobs: for node in $VALIDATORS; do NAME=$(echo $node | cut -d: -f1) METRICS_URL=$(echo $node | cut -d: -f2-) - BLOCK=$(curl -s "${METRICS_URL}" | grep '^block_height{status="best"}' | awk '{print $2}' || echo "0") + BLOCK=$(curl -s "${METRICS_URL}" | grep '^block_height{status="best"}' | awk '{print $2}') + BLOCK=${BLOCK:-0} - if [ $ATTEMPT -eq 1 ]; then - INITIAL_BLOCKS[$NAME]=$BLOCK - echo "$NAME: initial block height $BLOCK" - elif [ "$BLOCK" -gt "${INITIAL_BLOCKS[$NAME]}" ]; then + # If we haven't set initial block yet, or it was 0, set it now if we have a valid reading + if [ -z "${INITIAL_BLOCKS[$NAME]}" ] || [ "${INITIAL_BLOCKS[$NAME]}" -eq 0 ]; then + if [ "$BLOCK" -gt 0 ] 2>/dev/null; then + INITIAL_BLOCKS[$NAME]=$BLOCK + echo "$NAME: initial block height $BLOCK" + else + echo "$NAME: waiting for metrics... (height: $BLOCK)" + ALL_OK=false + fi + elif [ "$BLOCK" -gt "${INITIAL_BLOCKS[$NAME]}" ] 2>/dev/null; then echo "$NAME: producing blocks (height: $BLOCK)" else echo "$NAME: waiting... (height: $BLOCK)" @@ -116,12 +126,19 @@ jobs: for node in $COLLATORS; do NAME=$(echo $node | cut -d: -f1) METRICS_URL=$(echo $node | cut -d: -f2-) - BLOCK=$(curl -s "${METRICS_URL}" | grep '^block_height{status="best"}' | awk '{print $2}' || echo "0") + BLOCK=$(curl -s "${METRICS_URL}" | grep '^block_height{status="best"}' | awk '{print $2}') + BLOCK=${BLOCK:-0} - if [ $ATTEMPT -eq 1 ]; then - INITIAL_BLOCKS[$NAME]=$BLOCK - echo "$NAME: initial block height $BLOCK" - elif [ "$BLOCK" -gt "${INITIAL_BLOCKS[$NAME]}" ] && [ "$BLOCK" -gt "0" ]; then + # If we haven't set initial block yet, or it was 0, set it now if we have a valid reading + if [ -z "${INITIAL_BLOCKS[$NAME]}" ] || [ "${INITIAL_BLOCKS[$NAME]}" -eq 0 ]; then + if [ "$BLOCK" -gt 0 ] 2>/dev/null; then + INITIAL_BLOCKS[$NAME]=$BLOCK + echo "$NAME: initial block height $BLOCK" + else + echo "$NAME: waiting for metrics... (height: $BLOCK)" + ALL_OK=false + fi + elif [ "$BLOCK" -gt "${INITIAL_BLOCKS[$NAME]}" ] 2>/dev/null; then echo "$NAME: producing blocks (height: $BLOCK)" else echo "$NAME: waiting... (height: $BLOCK)" @@ -129,7 +146,7 @@ jobs: fi done - if [ "$ALL_OK" = true ] && [ $ATTEMPT -gt 1 ]; then + if [ "$ALL_OK" = true ]; then echo "" echo "All nodes are producing blocks!" exit 0 From 5af8632938d3aa2ef917bfddb85c00e1f7206c0a Mon Sep 17 00:00:00 2001 From: Marios Christou Date: Thu, 11 Dec 2025 11:26:05 +0200 Subject: [PATCH 5/6] Add debug prints --- .github/workflows/integration.yml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index bff4788..630ac80 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -54,7 +54,8 @@ jobs: target/release/zombie-bite spawn \ --base-path ${{ github.workspace }}/zombie-bite-output & echo $! > spawn.pid - sleep 60 + echo "Waiting for network and Prometheus metrics to be ready..." + sleep 90 - name: Check spawn process run: | @@ -87,6 +88,12 @@ jobs: echo "Validators: $VALIDATORS" echo "Collators: $COLLATORS" + # Debug: Check what Prometheus returns for alice + ALICE_URL=$(echo "$VALIDATORS" | head -1 | cut -d: -f2-) + echo "Checking Prometheus for alice at: $ALICE_URL" + echo "Sample metrics output:" + curl -s "$ALICE_URL" | grep "block_height" | head -5 + MAX_ATTEMPTS=20 ATTEMPT=0 declare -A INITIAL_BLOCKS From 7199b65addc27b123f92dff90195c05674981d44 Mon Sep 17 00:00:00 2001 From: Marios Christou Date: Thu, 11 Dec 2025 11:54:29 +0200 Subject: [PATCH 6/6] Fix metric name --- .github/workflows/integration.yml | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index 630ac80..80b6e19 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -41,7 +41,6 @@ jobs: - name: Build zombie-bite run: cargo build --release - # TODO: change people to AH. - name: Run bite (polkadot/AH/coretime) run: | target/release/zombie-bite bite \ @@ -88,12 +87,6 @@ jobs: echo "Validators: $VALIDATORS" echo "Collators: $COLLATORS" - # Debug: Check what Prometheus returns for alice - ALICE_URL=$(echo "$VALIDATORS" | head -1 | cut -d: -f2-) - echo "Checking Prometheus for alice at: $ALICE_URL" - echo "Sample metrics output:" - curl -s "$ALICE_URL" | grep "block_height" | head -5 - MAX_ATTEMPTS=20 ATTEMPT=0 declare -A INITIAL_BLOCKS @@ -109,7 +102,7 @@ jobs: for node in $VALIDATORS; do NAME=$(echo $node | cut -d: -f1) METRICS_URL=$(echo $node | cut -d: -f2-) - BLOCK=$(curl -s "${METRICS_URL}" | grep '^block_height{status="best"}' | awk '{print $2}') + BLOCK=$(curl -s "${METRICS_URL}" | grep 'block_height.*status="best"' | awk '{print $2}') BLOCK=${BLOCK:-0} # If we haven't set initial block yet, or it was 0, set it now if we have a valid reading @@ -117,6 +110,7 @@ jobs: if [ "$BLOCK" -gt 0 ] 2>/dev/null; then INITIAL_BLOCKS[$NAME]=$BLOCK echo "$NAME: initial block height $BLOCK" + ALL_OK=false else echo "$NAME: waiting for metrics... (height: $BLOCK)" ALL_OK=false @@ -133,7 +127,7 @@ jobs: for node in $COLLATORS; do NAME=$(echo $node | cut -d: -f1) METRICS_URL=$(echo $node | cut -d: -f2-) - BLOCK=$(curl -s "${METRICS_URL}" | grep '^block_height{status="best"}' | awk '{print $2}') + BLOCK=$(curl -s "${METRICS_URL}" | grep 'block_height.*status="best"' | awk '{print $2}') BLOCK=${BLOCK:-0} # If we haven't set initial block yet, or it was 0, set it now if we have a valid reading @@ -141,6 +135,7 @@ jobs: if [ "$BLOCK" -gt 0 ] 2>/dev/null; then INITIAL_BLOCKS[$NAME]=$BLOCK echo "$NAME: initial block height $BLOCK" + ALL_OK=false else echo "$NAME: waiting for metrics... (height: $BLOCK)" ALL_OK=false