Skip to content

perf(params): validate ConsensusParams once per change set (CON-312) #16056

perf(params): validate ConsensusParams once per change set (CON-312)

perf(params): validate ConsensusParams once per change set (CON-312) #16056

# This workflow will build a golang project
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-go
name: Docker Integration Test
on:
push:
branches:
- main
- release/**
pull_request:
branches:
- main
- release/**
merge_group:
branches:
- main
- release/**
concurrency:
group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.event_name == 'push' && github.sha || github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
defaults:
run:
shell: bash
jobs:
# Generate the integration-test matrix from integration-test-matrix.json.
# Runs the full matrix on every event (pull_request, push, merge_group) — all
# Autobahn coverage runs on every PR. The matrix is built here, in a job
# output, because the `matrix` context is NOT available to a job-level `if:`.
set-matrix:
name: Resolve integration test matrix
runs-on: ubuntu-latest
timeout-minutes: 5
outputs:
tests: ${{ steps.build.outputs.tests }}
steps:
# See: https://github.com/actions/checkout/releases/tag/v7.0.0
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
- name: Build matrix
id: build
run: |
set -euo pipefail
matrix_file=.github/workflows/integration-test-matrix.json
tests=$(jq -c '.' "$matrix_file")
echo "tests=$tests" >> "$GITHUB_OUTPUT"
echo "Selected $(echo "$tests" | jq 'length') matrix entries."
# Build localnode/rpcnode images and seid once; matrix jobs pull the images
# from GHCR (tagged with the run id) and download seid as a small artifact.
prepare-cluster:
name: Prepare integration test cluster
runs-on: ubuntu-large
timeout-minutes: 45
# packages:write required to push images and buildx cache to GHCR. Fork PRs
# cannot publish org packages, so integration tests cannot run from forks; a
# maintainer must push external contributions to a branch on this repo.
# cache-to is restricted to push events to avoid cache thrashing on PRs.
permissions:
packages: write
contents: read
env:
GHCR_LOCALNODE: ghcr.io/sei-protocol/sei-chain-integration-test-localnode
GHCR_RPCNODE: ghcr.io/sei-protocol/sei-chain-integration-test-rpcnode
steps:
# See: https://github.com/actions/checkout/releases/tag/v7.0.0
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
# Reclaim disk and push Docker + Go caches onto /mnt before the
# image builds so the runner's small root filesystem does not fill up and
# crash the runner mid-job.
- name: Reclaim runner disk
run: bash .github/scripts/ci-free-disk.sh
- name: Relocate Docker data-root to /mnt
run: bash .github/scripts/ci-relocate-docker-data-root.sh
- name: Relocate Go caches to /mnt
run: bash .github/scripts/ci-relocate-go-cache.sh
- name: Login to Docker Hub
# See: https://github.com/docker/login-action/releases/tag/v4.2.0
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee
if: env.DOCKERHUB_USERNAME != ''
env:
DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Login to GitHub Container Registry
# See: https://github.com/docker/login-action/releases/tag/v4.2.0
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Docker Buildx
# See: https://github.com/docker/setup-buildx-action/releases/tag/v4.1.0
uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5
- name: Build localnode image (cached)
uses: docker/build-push-action@v6
with:
context: docker/localnode
file: docker/localnode/Dockerfile
platforms: linux/amd64
push: false
load: true
tags: sei-chain/localnode
# Run-id label makes each run's image digest unique (config-only
# change, layer cache unaffected) so old run tags can be pruned without
# touching digests other runs still reference.
labels: sei-chain.ci-run-id=${{ github.run_id }}
cache-from: type=registry,ref=${{ env.GHCR_LOCALNODE }}:cache
cache-to: ${{ github.event_name == 'push' && format('type=registry,ref={0}:cache,mode=max', env.GHCR_LOCALNODE) || '' }}
- name: Build rpcnode image (cached)
uses: docker/build-push-action@v6
with:
context: docker/rpcnode
file: docker/rpcnode/Dockerfile
platforms: linux/amd64
push: false
load: true
tags: sei-chain/rpcnode
labels: sei-chain.ci-run-id=${{ github.run_id }}
cache-from: type=registry,ref=${{ env.GHCR_RPCNODE }}:cache
cache-to: ${{ github.event_name == 'push' && format('type=registry,ref={0}:cache,mode=max', env.GHCR_RPCNODE) || '' }}
# rpcnode is independent of the seid build, so push it now: push failures
# (retried below) surface before the expensive seid build rather than after.
- name: Push rpcnode image to GHCR for test jobs
run: |
source .github/scripts/docker-registry-retry.sh
docker tag sei-chain/rpcnode "${GHCR_RPCNODE}:${{ github.run_id }}"
push_with_retry "${GHCR_RPCNODE}:${{ github.run_id }}"
- uses: actions/setup-go@v6
with:
go-version: '1.25.6'
- name: Build seid binary in localnode container
env:
DOCKER_PLATFORM: linux/amd64
run: make build-seid-in-localnode-ci
- name: Push localnode image to GHCR for test jobs
run: |
source .github/scripts/docker-registry-retry.sh
docker tag sei-chain/localnode "${GHCR_LOCALNODE}:${{ github.run_id }}"
push_with_retry "${GHCR_LOCALNODE}:${{ github.run_id }}"
- name: Package CI artifacts
run: tar -czf integration-build.tar.gz build/seid
- name: Upload integration CI artifacts
uses: actions/upload-artifact@v4
with:
name: integration-ci-artifacts
path: integration-build.tar.gz
retention-days: 1
integration-tests:
name: Integration Test (${{ matrix.test.name }})
needs: [ set-matrix, prepare-cluster ]
runs-on: ubuntu-large
timeout-minutes: 30
permissions:
packages: read
contents: read
env:
JOB_TIMEOUT: 28m
GHCR_LOCALNODE: ghcr.io/sei-protocol/sei-chain-integration-test-localnode
GHCR_RPCNODE: ghcr.io/sei-protocol/sei-chain-integration-test-rpcnode
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
DAPP_TESTS_MNEMONIC: ${{ secrets.DAPP_TESTS_MNEMONIC }}
strategy:
# other jobs should run even if one integration test fails
fail-fast: false
# Matrix is resolved by the set-matrix job from
# integration-test-matrix.json.
matrix:
test: ${{ fromJSON(needs.set-matrix.outputs.tests) }}
steps:
# See: https://github.com/actions/checkout/releases/tag/v7.0.0
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
- name: Reclaim runner disk
run: bash .github/scripts/ci-free-disk.sh
- name: Relocate Docker data-root to /mnt
run: bash .github/scripts/ci-relocate-docker-data-root.sh
- name: Relocate Go caches to /mnt
run: bash .github/scripts/ci-relocate-go-cache.sh
- uses: actions/setup-node@v4
with:
node-version: '22'
- name: Install jq
run: sudo apt-get install -y jq
- name: Set up Go
uses: actions/setup-go@v6
with:
go-version: '1.25.6'
- name: Login to Docker Hub
# See: https://github.com/docker/login-action/releases/tag/v4.2.0
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee
if: env.DOCKERHUB_USERNAME != ''
env:
DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Login to GitHub Container Registry
# See: https://github.com/docker/login-action/releases/tag/v4.2.0
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Download integration CI artifacts
uses: actions/download-artifact@v4
with:
name: integration-ci-artifacts
- name: Load prebuilt seid and pull Docker images
run: |
tar -xzf integration-build.tar.gz
# The seid binary is now extracted to build/seid; drop the
# tarball so its copy does not sit on disk for the rest of the job.
rm -f integration-build.tar.gz
source .github/scripts/docker-registry-retry.sh
pull_with_retry "${GHCR_LOCALNODE}:${{ github.run_id }}"
pull_with_retry "${GHCR_RPCNODE}:${{ github.run_id }}"
docker tag "${GHCR_LOCALNODE}:${{ github.run_id }}" sei-chain/localnode
docker tag "${GHCR_RPCNODE}:${{ github.run_id }}" sei-chain/rpcnode
# Drop the redundant run-id-tagged references now that the images are
# retagged as sei-chain/*; keeps a single tag per image.
docker image rm "${GHCR_LOCALNODE}:${{ github.run_id }}" "${GHCR_RPCNODE}:${{ github.run_id }}" || true
- name: Start 4 node docker cluster
run: DOCKER_DETACH=true INVARIANT_CHECK_INTERVAL=10 ${{matrix.test.env}} make docker-cluster-start-ci
- name: Wait for docker cluster to start
run: |
until [ $(cat build/generated/launch.complete |wc -l) = 4 ]
do
sleep 10
done
sleep 10
- name: Start rpc node
run: ${{matrix.test.env}} make run-rpc-node-integration-ci &
- name: Verify Sei Chain is running
run: go test -tags yaml_integration -v -timeout 5m ./integration_test/runner/... -run TestStartup
- name: ${{ matrix.test.name }}
run: |
scripts=$(echo '${{ toJson(matrix.test.scripts) }}' | jq -r '.[]')
IFS=$'\n' # change the internal field separator to newline
echo $scripts
for script in $scripts
do
bash -c "${script}"
done
unset IFS # revert the internal field separator back to default
- name: Print node logs on failure
if: ${{ failure() }}
run: |
set -euo pipefail
for c in sei-node-0 sei-node-1 sei-node-2 sei-node-3; do
echo "==================== ${c} (docker logs tail) ===================="
docker logs --tail 200 "${c}" || true
echo "==================== ${c} (seid log file tail) ===================="
# Logs are accessible on host since build/generated is mounted in containers
NODE_ID=${c#sei-node-}
if [ -f "build/generated/logs/seid-${NODE_ID}.log" ]; then
tail -200 "build/generated/logs/seid-${NODE_ID}.log" || true
fi
done
- name: Prepare log artifact name
if: ${{ always() }}
id: log_artifact_meta
run: |
raw="${{ matrix.test.name }}"
safe=$(echo "$raw" | tr '[:upper:]' '[:lower:]' | sed -E 's/[^a-z0-9]+/-/g' | sed -E 's/^-+|-+$//g')
if [ -z "$safe" ]; then
safe="logs"
fi
echo "artifact_name=$safe" >> $GITHUB_OUTPUT
- name: Collect logs directory
if: ${{ always() }}
run: |
LOG_ROOT="artifacts/sei-${{ steps.log_artifact_meta.outputs.artifact_name }}"
mkdir -p "$LOG_ROOT"
if [ -d build/generated/logs ]; then
cp -r build/generated/logs "$LOG_ROOT/"
else
echo "No logs directory found"
fi
- name: Upload logs directory
if: ${{ always() }}
uses: actions/upload-artifact@v4
with:
name: integration-logs-${{ steps.log_artifact_meta.outputs.artifact_name }}
path: artifacts/sei-${{ steps.log_artifact_meta.outputs.artifact_name }}
if-no-files-found: warn
- name: Upload RPC parity test report
if: ${{ always() }}
uses: actions/upload-artifact@v4
with:
name: rpc-parity-report-${{ steps.log_artifact_meta.outputs.artifact_name }}
path: integration_test/rpc_tests/reports/merged
if-no-files-found: ignore
- name: Upload precompile test report
if: ${{ always() }}
uses: actions/upload-artifact@v4
with:
name: precompile-report-${{ steps.log_artifact_meta.outputs.artifact_name }}
path: integration_test/precompile_tests/reports/merged
if-no-files-found: ignore
# Autobahn integration suite (Autobahn Basic) — boots its own cluster via
# TestMain (docker-cluster-start / -stop), so it runs in a separate job
# rather than as a matrix entry that would share the integration-tests
# cluster.
autobahn-integration-tests:
name: Integration Test (Autobahn Basic)
runs-on: ubuntu-large
timeout-minutes: 45
needs: prepare-cluster
permissions:
packages: read
contents: read
env:
GHCR_LOCALNODE: ghcr.io/sei-protocol/sei-chain-integration-test-localnode
GHCR_RPCNODE: ghcr.io/sei-protocol/sei-chain-integration-test-rpcnode
steps:
# See: https://github.com/actions/checkout/releases/tag/v7.0.0
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
- name: Reclaim runner disk
run: bash .github/scripts/ci-free-disk.sh
- name: Relocate Docker data-root to /mnt
run: bash .github/scripts/ci-relocate-docker-data-root.sh
- name: Relocate Go caches to /mnt
run: bash .github/scripts/ci-relocate-go-cache.sh
- uses: actions/setup-go@v6
with:
go-version: '1.25.6'
- name: Install jq
run: sudo apt-get install -y jq
- name: Login to Docker Hub
uses: docker/login-action@v3
if: env.DOCKERHUB_USERNAME != ''
env:
DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Download integration CI artifacts
uses: actions/download-artifact@v4
with:
name: integration-ci-artifacts
- name: Load prebuilt seid and pull Docker images
run: |
tar -xzf integration-build.tar.gz
# The seid binary is now extracted to build/seid; drop the
# tarball so its copy does not sit on disk for the rest of the job.
rm -f integration-build.tar.gz
source .github/scripts/docker-registry-retry.sh
pull_with_retry "${GHCR_LOCALNODE}:${{ github.run_id }}"
pull_with_retry "${GHCR_RPCNODE}:${{ github.run_id }}"
docker tag "${GHCR_LOCALNODE}:${{ github.run_id }}" sei-chain/localnode
docker tag "${GHCR_RPCNODE}:${{ github.run_id }}" sei-chain/rpcnode
# Drop the redundant run-id-tagged references now that the images are
# retagged as sei-chain/*; keeps a single tag per image.
docker image rm "${GHCR_LOCALNODE}:${{ github.run_id }}" "${GHCR_RPCNODE}:${{ github.run_id }}" || true
- name: Run autobahn integration tests
run: make autobahn-integration-test
- name: Print node logs on failure
if: ${{ failure() }}
run: |
set -euo pipefail
for c in sei-node-0 sei-node-1 sei-node-2 sei-node-3 sei-rpc-node; do
echo "==================== ${c} (docker logs tail) ===================="
docker logs --tail 200 "${c}" || true
done
- name: Collect logs directory
if: ${{ always() }}
run: |
mkdir -p artifacts/sei-autobahn-integration
if [ -d build/generated/logs ]; then
cp -r build/generated/logs artifacts/sei-autobahn-integration/
fi
- name: Upload logs directory
if: ${{ always() }}
uses: actions/upload-artifact@v4
with:
name: integration-logs-autobahn-integration
path: artifacts/sei-autobahn-integration
if-no-files-found: warn
integration-test-check:
name: Integration Test Check
runs-on: ubuntu-latest
needs: [ prepare-cluster, integration-tests, autobahn-integration-tests ]
if: always()
steps:
- name: Verify prepare and test jobs succeeded
run: |
if [[ "${{ needs.prepare-cluster.result }}" != "success" ]]; then
echo "prepare-cluster job did not succeed (${{ needs.prepare-cluster.result }})"
exit 1
fi
if [[ "${{ needs.integration-tests.result }}" != "success" ]]; then
echo "integration-tests job did not succeed (${{ needs.integration-tests.result }})"
exit 1
fi
if [[ "${{ needs.autobahn-integration-tests.result }}" != "success" ]]; then
echo "autobahn-integration-tests job did not succeed (${{ needs.autobahn-integration-tests.result }})"
exit 1
fi
echo "All integration test jobs passed."