Skip to content

Syncoor - Devnet 1

Syncoor - Devnet 1 #2

name: Syncoor - Devnet 1
on:
#schedule:
#- cron: '30 10 1-31/2 * *' # Every odd day at 10h 30m (Fullnode runs)
#- cron: '30 10 2-30/2 * *' # Every even day at 10h 30m (Supernode runs)
workflow_dispatch:
inputs:
el-client:
description: 'Comma-separated list of execution layer clients (geth,besu,nethermind,erigon,reth)'
required: false
default: '"geth","reth","nethermind","besu","erigon"'
type: string
cl-client:
description: 'Comma-separated list of consensus layer clients (lighthouse,teku,prysm,nimbus,lodestar,grandine)'
required: false
default: '"lighthouse","teku","prysm","nimbus","lodestar","grandine"'
type: string
runconfig:
description: >
Run configuration as JSON.
run-timeout: timeout in minutes.
cl-synctype: "checkpoint" (sync from checkpoint) or "genesis" (sync from genesis).
cl-nodetype: "fullnode" (normal node) or "supernode" (subscribes to all custody groups).
runs-on: GitHub runner label (ccx13: 2c/8GB RAM/80GB disk, ccx23: 4c/16GB RAM/160GB disk, ccx33: 8c/32GB RAM/240GB disk, ccx43: 16c/64GB RAM/360GB disk).
Example: {"run-timeout": "1800", "cl-synctype": ["checkpoint"], "cl-nodetype": ["fullnode"]}
required: false
default: >-
{
"run-timeout": "1800",
"cl-synctype": ["checkpoint"],
"cl-nodetype": ["fullnode"],
"runs-on": "self-hosted-ghr-size-ccx33-x64"
}
type: string
checkpoint-sync-url:
description: 'Checkpoint sync URL. Will be auto generated if not provided. (Example: https://checkpoint-sync.$NETWORK.ethpandaops.io)'
required: false
default: ''
type: string
image:
description: 'Syncoor Docker image'
required: false
default: 'docker.ethquokkaops.io/dh/ethpandaops/syncoor:master'
type: string
git-ref:
description: 'Git reference (branch, tag, or commit) to checkout'
required: false
default: ''
type: string
el-image:
description: 'Execution layer client images as JSON (e.g., {"geth": "ethereum/client-go:latest", "besu": "hyperledger/besu:latest"})'
required: false
default: >-
{
"besu": "hyperledger/besu:latest",
"geth": "ethereum/client-go:stable",
"erigon": "erigontech/erigon:latest",
"nethermind": "nethermind/nethermind:latest",
"reth": "ghcr.io/paradigmxyz/reth",
"nimbusel": "ethpandaops/nimbus-eth1:master"
}
type: string
cl-image:
description: 'Consensus layer client images as JSON (e.g., {"lighthouse": "sigp/lighthouse:latest", "teku": "consensys/teku:latest"})'
required: false
default: >-
{
"lighthouse": "sigp/lighthouse:latest",
"teku": "consensys/teku:latest",
"prysm": "offchainlabs/prysm-beacon-chain:stable",
"nimbus": "statusim/nimbus-eth2:amd64-latest",
"lodestar": "chainsafe/lodestar:latest",
"grandine": "sifrai/grandine:stable"
}
type: string
env:
INSTALL_RCLONE_VERSION: v1.68.2
S3_BUCKET: ethpandaops-syncoor-data
jobs:
sync:
# Timeouts from h to minutes:
# - 4h -> 240m
# - 6h -> 360m
# - 8h -> 480m
# - 12h -> 720m
# - 24h -> 1440m
# - 48h -> 2880m
# - 72h -> 4320m
timeout-minutes: ${{ github.event_name == 'schedule' && 500 || fromJSON(fromJSON(inputs.runconfig || '{}')['run-timeout'] || '1800') }}
runs-on: ${{ fromJSON(inputs.runconfig || '{}')['runs-on'] || 'self-hosted-ghr-size-ccx33-x64' }}
concurrency:
group: >-
${{ github.event_name }}-${{ matrix.network }}-${{ matrix.el-client }}-${{ matrix.cl-client }}-${{ matrix.cl-nodetype }}-${{ matrix.cl-synctype }}
strategy:
fail-fast: false
matrix:
network: ["bal-devnet-1"]
el-client: >-
${{
fromJSON(format('[{0}]', inputs.el-client || '
"besu",
"erigon",
"geth",
"nethermind",
"reth"
'))}}
cl-client: >-
${{
fromJSON(format('[{0}]', inputs.cl-client || '
"lighthouse",
"teku",
"prysm",
"nimbus",
"lodestar",
"grandine"
'))}}
cl-nodetype: >-
${{
github.event_name == 'schedule' &&
(github.event.schedule == '30 10 1-31/2 * *' && fromJSON('["fullnode"]') ||
github.event.schedule == '30 10 2-30/2 * *' && fromJSON('["supernode"]') ||
fromJSON('["fullnode","supernode"]')) ||
fromJSON(inputs.runconfig || '{}')['cl-nodetype'] || fromJSON('["fullnode","supernode"]')
}}
cl-synctype: >-
${{
github.event_name == 'schedule' && fromJSON('["checkpoint"]') ||
fromJSON(inputs.runconfig || '{}')['cl-synctype'] || fromJSON('["checkpoint","genesis"]')
}}
steps:
- name: Set default images for scheduled runs
id: default-images
if: github.event_name == 'schedule'
run: |
cat > /tmp/default-el-images.json <<'EOF'
{
"besu": "hyperledger/besu:latest",
"geth": "ethereum/client-go:stable",
"erigon": "erigontech/erigon:latest",
"nethermind": "nethermind/nethermind:latest",
"reth": "ghcr.io/paradigmxyz/reth",
"nimbusel": "ethpandaops/nimbus-eth1:master"
}
EOF
echo "el-images=$(cat /tmp/default-el-images.json | jq -c .)" >> $GITHUB_OUTPUT
cat > /tmp/default-cl-images.json <<'EOF'
{
"lighthouse": "sigp/lighthouse:latest",
"teku": "consensys/teku:latest",
"prysm": "offchainlabs/prysm-beacon-chain:stable",
"nimbus": "statusim/nimbus-eth2:amd64-latest",
"lodestar": "chainsafe/lodestar:latest",
"grandine": "sifrai/grandine:stable"
}
EOF
echo "cl-images=$(cat /tmp/default-cl-images.json | jq -c .)" >> $GITHUB_OUTPUT
- name: Prepare inputs
id: prepare
env:
EL_IMAGES: ${{ github.event_name == 'schedule' && steps.default-images.outputs.el-images || inputs.el-image }}
CL_IMAGES: ${{ github.event_name == 'schedule' && steps.default-images.outputs.cl-images || inputs.cl-image }}
run: |
set -x
# Parse EL image for current client
if [ "$EL_IMAGES" != '{}' ] && [ -n "$EL_IMAGES" ]; then
EL_IMAGE=$(echo "$EL_IMAGES" | jq -r --arg client "${{ matrix.el-client }}" '.[$client] // ""')
echo "el-image=$EL_IMAGE" >> $GITHUB_OUTPUT
else
echo "el-image=" >> $GITHUB_OUTPUT
fi
# Parse CL image for current client
if [ "$CL_IMAGES" != '{}' ] && [ -n "$CL_IMAGES" ]; then
CL_IMAGE=$(echo "$CL_IMAGES" | jq -r --arg client "${{ matrix.cl-client }}" '.[$client] // ""')
echo "cl-image=$CL_IMAGE" >> $GITHUB_OUTPUT
else
echo "cl-image=" >> $GITHUB_OUTPUT
fi
# Generate checkpoint sync URL based on network
CHECKPOINT_SYNC_URL="https://checkpoint-sync.${{ matrix.network }}.ethpandaops.io"
echo "checkpoint-sync-url=$CHECKPOINT_SYNC_URL" >> $GITHUB_OUTPUT
# Set checkpoint sync enabled based on cl-synctype
if [ "${{ matrix.cl-synctype }}" = "checkpoint" ]; then
CHECKPOINT_SYNC_ENABLED="true"
else
CHECKPOINT_SYNC_ENABLED="false"
fi
echo "checkpoint-sync-enabled=$CHECKPOINT_SYNC_ENABLED" >> $GITHUB_OUTPUT
# Generate syncoor server address based on network
SERVER_URL="https://syncoor-api.${{ matrix.network }}.ethpandaops.io"
echo "syncoor-server-url=$SERVER_URL" >> $GITHUB_OUTPUT
# Generate S3 path based on network, cl-nodetype, and checkpoint sync
S3_PATH="devnets/${{ matrix.network }}"
if [ "${{ matrix.cl-nodetype }}" = "supernode" ]; then
S3_PATH="${S3_PATH}-clsupernode"
fi
if [ "$CHECKPOINT_SYNC_ENABLED" = "false" ]; then
S3_PATH="${S3_PATH}-clcheckpointsyncdisabled"
fi
echo "s3-path=$S3_PATH" >> $GITHUB_OUTPUT
# Calculate timeout (subtract 10 minutes)
TIMEOUT=$(( ${{ github.event_name == 'schedule' && 500 || fromJSON(fromJSON(inputs.runconfig || '{}')['run-timeout'] || '1800') }} - 10 ))
echo "run-timeout=$TIMEOUT" >> $GITHUB_OUTPUT
- name: Run Syncoor Test
uses: ethpandaops/syncoor@master
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
server: ${{ steps.prepare.outputs.syncoor-server-url }}
server-auth: ${{ secrets.SYNCOOR_SERVER_AUTH }}
log-force-colors: true
client-logs: true
public: true
network: ${{ matrix.network }}
el-client: ${{ matrix.el-client }}
cl-client: ${{ matrix.cl-client }}
el-image: ${{ steps.prepare.outputs.el-image }}
cl-image: ${{ steps.prepare.outputs.cl-image }}
el-extra-args: >-
${{
(matrix.el-client == 'reth') && '["--full"]' ||
(matrix.el-client == 'erigon') && '["--prune.mode=full"]' ||
'[]'
}}
check-interval: 30s
run-timeout: ${{ steps.prepare.outputs.run-timeout }}m
log-level: info
s3-upload: true
s3-bucket: ${{ env.S3_BUCKET }}
s3-path: ${{ steps.prepare.outputs.s3-path }}
rclone-config: ${{ secrets.SYNCOOR_RCLONE_CONFIG }}
rclone-version: ${{ env.INSTALL_RCLONE_VERSION }}
checkpoint-sync-enabled: ${{ steps.prepare.outputs.checkpoint-sync-enabled }}
checkpoint-sync-url: ${{ inputs.checkpoint-sync-url || steps.prepare.outputs.checkpoint-sync-url }}
supernode: ${{ matrix.cl-nodetype == 'supernode' }}
image: ${{ inputs.image || 'docker.ethquokkaops.io/dh/ethpandaops/syncoor:master' }}
git-ref: ${{ inputs.git-ref }}
- name: Update test results index
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
await github.rest.actions.createWorkflowDispatch({
owner: context.repo.owner,
repo: context.repo.repo,
workflow_id: 'syncoor-generate-index.yaml',
ref: context.ref,
inputs: {
's3-path': '${{ steps.prepare.outputs.s3-path }}'
}
});