Skip to content

Checkpoint Update

Checkpoint Update #185

# Automated checkpoint updates.
#
# Triggered whenever the integration tests complete; requires both checkpoint artifacts.
# Downloads checkpoint artifacts produced by generate-checkpoints-* jobs,
# appends new entries to the checkpoint files, validates them, and opens a PR.
#
# The PR requires human review before merge; checkpoints are consensus-critical.
name: Checkpoint Update
on:
# zizmor: ignore[dangerous-triggers] -- triggers only on internal CI workflow completion,
# processes deterministic checkpoint data from artifacts, no untrusted user input
workflow_run:
workflows: ["Integration Tests on GCP"]
types: [completed]
branches: [main]
# Manual trigger for testing; resolves the latest completed integration test run automatically
workflow_dispatch:
permissions: {}
jobs:
update-checkpoints:
name: Update checkpoint files
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
env:
MAINNET_CHECKPOINTS: zebra-chain/src/parameters/checkpoint/main-checkpoints.txt
TESTNET_CHECKPOINTS: zebra-chain/src/parameters/checkpoint/test-checkpoints.txt
steps:
- name: Generate release app token
id: app-token
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 #v3.2.0
with:
app-id: ${{ vars.RELEASE_APP_ID }}
private-key: ${{ secrets.RELEASE_APP_PRIVATE_KEY }}
permission-contents: write
permission-pull-requests: write
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd #v6.0.2
with:
persist-credentials: false
ref: main
token: ${{ steps.app-token.outputs.token }}
# Resolve the integration test run ID.
# For workflow_run: use the triggering run directly.
# For workflow_dispatch: find the latest completed run via the API.
- name: Resolve integration test run ID
id: resolve-run
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
EVENT_NAME: ${{ github.event_name }}
WF_RUN_ID: ${{ github.event.workflow_run.id }}
WF_RUN_URL: ${{ github.event.workflow_run.html_url }}
REPO: ${{ github.repository }}
run: |
if [ "$EVENT_NAME" = "workflow_run" ]; then
RUN_ID="$WF_RUN_ID"
RUN_URL="$WF_RUN_URL"
else
RUN_ID=$(gh run list \
--workflow "Integration Tests on GCP" \
--branch main \
--status completed \
--limit 1 \
--json databaseId \
--jq '.[0].databaseId')
RUN_URL="https://github.com/${REPO}/actions/runs/${RUN_ID}"
fi
if [ -z "$RUN_ID" ]; then
echo "No completed integration test run found"
exit 1
fi
echo "run_id=${RUN_ID}" >> "$GITHUB_OUTPUT"
echo "run_url=${RUN_URL}" >> "$GITHUB_OUTPUT"
echo "Using integration test run: ${RUN_URL}"
# Download checkpoint artifacts from the integration test run.
- name: Download mainnet checkpoint artifact
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c #v8.0.1
with:
name: generate-checkpoints-mainnet-checkpoints
run-id: ${{ steps.resolve-run.outputs.run_id }}
github-token: ${{ secrets.GITHUB_TOKEN }}
- name: Download testnet checkpoint artifact
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c #v8.0.1
with:
name: generate-checkpoints-testnet-checkpoints
run-id: ${{ steps.resolve-run.outputs.run_id }}
github-token: ${{ secrets.GITHUB_TOKEN }}
- name: Verify required checkpoint artifacts
run: |
for artifact in main-checkpoints.txt test-checkpoints.txt; do
if [ ! -f "$artifact" ]; then
echo "::error::Required checkpoint artifact file is missing: ${artifact}"
exit 1
fi
LINES=$(wc -l < "$artifact" | tr -d ' ')
echo "${artifact}: ${LINES} checkpoint lines"
done
# Append new mainnet checkpoints (entries with heights higher than current last)
- name: Append new mainnet checkpoints
run: |
CURRENT_LAST=$(tail -1 "${MAINNET_CHECKPOINTS}" | awk '{print $1}')
echo "Current last mainnet checkpoint: ${CURRENT_LAST}"
# Extract only new entries (height > current last)
NEW_COUNT=$(awk -v last="$CURRENT_LAST" '$1 > last' main-checkpoints.txt | wc -l | tr -d ' ')
echo "New mainnet checkpoints to append: ${NEW_COUNT}"
if [ "$NEW_COUNT" -gt 0 ]; then
awk -v last="$CURRENT_LAST" '$1 > last' main-checkpoints.txt >> "${MAINNET_CHECKPOINTS}"
NEW_LAST=$(tail -1 "${MAINNET_CHECKPOINTS}" | awk '{print $1}')
echo "Updated last mainnet checkpoint: ${NEW_LAST}"
fi
# Append new testnet checkpoints
- name: Append new testnet checkpoints
run: |
CURRENT_LAST=$(tail -1 "${TESTNET_CHECKPOINTS}" | awk '{print $1}')
echo "Current last testnet checkpoint: ${CURRENT_LAST}"
NEW_COUNT=$(awk -v last="$CURRENT_LAST" '$1 > last' test-checkpoints.txt | wc -l | tr -d ' ')
echo "New testnet checkpoints to append: ${NEW_COUNT}"
if [ "$NEW_COUNT" -gt 0 ]; then
awk -v last="$CURRENT_LAST" '$1 > last' test-checkpoints.txt >> "${TESTNET_CHECKPOINTS}"
NEW_LAST=$(tail -1 "${TESTNET_CHECKPOINTS}" | awk '{print $1}')
echo "Updated last testnet checkpoint: ${NEW_LAST}"
fi
# Validate the updated checkpoint files
- name: Validate checkpoint files
run: |
.github/scripts/validate-checkpoints.sh "${MAINNET_CHECKPOINTS}"
.github/scripts/validate-checkpoints.sh "${TESTNET_CHECKPOINTS}"
# Check if there are actual changes to commit
- name: Check for changes
id: changes
run: |
if git diff --quiet; then
echo "No changes to commit"
echo "has_changes=false" >> "$GITHUB_OUTPUT"
else
echo "Changes detected:"
git diff --stat
echo "has_changes=true" >> "$GITHUB_OUTPUT"
fi
# Open or update a PR with the checkpoint changes
- name: Create checkpoint update PR
if: steps.changes.outputs.has_changes == 'true'
uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 #v8.1.1
with:
token: ${{ steps.app-token.outputs.token }}
branch: chore/update-checkpoints
add-paths: |
zebra-chain/src/parameters/checkpoint/main-checkpoints.txt
zebra-chain/src/parameters/checkpoint/test-checkpoints.txt
title: "chore(chain): update checkpoints"
body: |
Automated checkpoint update from the integration test run.
**Source:** [Integration test run #${{ steps.resolve-run.outputs.run_id }}](${{ steps.resolve-run.outputs.run_url }})
Checkpoints are consensus-critical. Verify the new hashes against the source run before merging.
labels: A-release,C-enhancement
commit-message: "chore(chain): update checkpoints"
delete-branch: true