Skip to content

feat(test-suite): replace fhevm bash cli with Bun runtime #6176

feat(test-suite): replace fhevm bash cli with Bun runtime

feat(test-suite): replace fhevm bash cli with Bun runtime #6176

name: gateway-contracts-upgrade-tests
permissions: {}
on:
pull_request:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
# Define common environment variables here:
# - DOTENV_CONFIG_PATH: The path to the environment file, used for loading variables used for upgrades
# - HARDHAT_NETWORK: Should match the network from the docker-compose.yml's services
# - CHAIN_ID_GATEWAY: Should match the chain ID used in the anvil node in the docker-compose.yml file
# - RPC_URL: The port should match the one used in the anvil node in the docker-compose.yml file
env:
# Bump this tag each release cycle to test upgrades from the previous version
UPGRADE_FROM_TAG: v0.11.0
DOTENV_CONFIG_PATH: .env.example
HARDHAT_NETWORK: staging
CHAIN_ID_GATEWAY: 54321
RPC_URL: http://localhost:8546
jobs:
check-changes:
name: gateway-contracts-upgrade-tests/check-changes
permissions:
actions: 'read' # Required to read workflow run information
contents: 'read' # Required to checkout repository code
pull-requests: 'read' # Required to read pull request information
runs-on: ubuntu-latest
outputs:
changes-gw-contracts: ${{ steps.filter.outputs.gw-contracts }}
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
persist-credentials: 'false'
- uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
id: filter
with:
filters: |
gw-contracts:
- .github/workflows/gateway-contracts-upgrade-tests.yml
- gateway-contracts/**
sc-upgrade:
name: gateway-contracts-upgrade-tests/sc-upgrade (bpr)
needs: check-changes
if: ${{ needs.check-changes.outputs.changes-gw-contracts == 'true' }}
permissions:
contents: 'read' # Required to checkout repository code
checks: 'write' # Required to create GitHub checks for test results
packages: 'read' # Required to read GitHub packages/container registry
runs-on: ubuntu-latest
steps:
- name: Checkout previous release code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
ref: ${{ env.UPGRADE_FROM_TAG }}
path: previous-fhevm
persist-credentials: 'false'
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@d70bba72b1f3fd22344832f00baa16ece964efeb # v3.3.0
- name: Login to Docker Registry
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and start Docker services from previous release
working-directory: previous-fhevm/gateway-contracts
run: |
make docker-compose-build
make docker-compose-up
- name: Check smart contract deployment from previous release
working-directory: previous-fhevm/gateway-contracts
run: |
timeout 300s bash -c 'while docker ps --filter "name=deploy-gateway-contracts" --format "{{.Status}}" | grep -q "Up"; do sleep 5; done'
docker compose logs deploy-gateway-contracts > deployment_logs.txt
cat deployment_logs.txt
EXIT_CODE=$(docker inspect --format='{{.State.ExitCode}}' deploy-gateway-contracts)
if [ "$EXIT_CODE" -ne 0 ]; then
echo "Deployment failed with exit code $EXIT_CODE"
exit 1
elif ! grep -q "Contract deployment done!" deployment_logs.txt; then
echo "Deployment did not complete successfully - 'Contract deployment done!' message not found in logs"
exit 1
fi
- name: Checkout current code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
persist-credentials: 'false'
path: current-fhevm
- name: Install Foundry
uses: foundry-rs/foundry-toolchain@82dee4ba654bd2146511f85f0d013af94670c4de # v1.4.0
- name: Install dependencies
working-directory: current-fhevm/gateway-contracts
run: npm ci
# This step prepares the directory for upgrading contracts:
# 1) Copy contracts from previous version to directory `./previous-contracts`: upgrade tasks
# require access to the previous implementations
# 2) Copy addresses from previous version to root directory: the upgrade tasks need to use the
# internal addresses that have been deployed (ie, the previous version's addresses)
- name: Prepare contracts for upgrades
working-directory: current-fhevm/gateway-contracts
run: |
cp -r ../../previous-fhevm/gateway-contracts/contracts ./previous-contracts
docker cp deploy-gateway-contracts:/app/addresses ./
- name: Run contract upgrades
working-directory: current-fhevm/gateway-contracts
run: |
set -euo pipefail
UPGRADED=0
SKIPPED=0
# Iterate over contracts listed in the upgrade manifest
for name in $(jq -r '.[]' upgrade-manifest.json); do
# Fail fast if the contract is missing from current code (manifest out of sync)
if [ ! -f "contracts/${name}.sol" ]; then
echo "::error::$name listed in upgrade-manifest.json but contracts/${name}.sol not found"
exit 1
fi
# Skip contracts not present in the previous release (e.g. newly added)
if [ ! -f "previous-contracts/${name}.sol" ]; then
echo "Skipping $name (not present in previous release)"
SKIPPED=$((SKIPPED + 1))
continue
fi
# Extract REINITIALIZER_VERSION from both versions
old_ver=$(sed -n 's/.*REINITIALIZER_VERSION[[:space:]]*=[[:space:]]*\([0-9]*\).*/\1/p' \
"previous-contracts/${name}.sol")
new_ver=$(sed -n 's/.*REINITIALIZER_VERSION[[:space:]]*=[[:space:]]*\([0-9]*\).*/\1/p' \
"contracts/${name}.sol")
if [ -z "$old_ver" ]; then
echo "::error::Failed to parse REINITIALIZER_VERSION from previous-contracts/${name}.sol"
exit 1
fi
if [ -z "$new_ver" ]; then
echo "::error::Failed to parse REINITIALIZER_VERSION from contracts/${name}.sol"
exit 1
fi
# Upgrade only if reinitializer version changed
if [ "$old_ver" != "$new_ver" ]; then
echo "::group::Upgrading $name (reinitializer $old_ver → $new_ver)"
npx hardhat "task:upgrade${name}" \
--current-implementation "previous-contracts/${name}.sol:${name}" \
--new-implementation "contracts/${name}.sol:${name}" \
--use-internal-proxy-address true \
--verify-contract false
# OZ upgradeProxy does not wait for the upgradeToAndCall tx to be mined.
# With Anvil's interval mining (--block-time), flush it before moving on.
cast rpc evm_mine --rpc-url "$RPC_URL" > /dev/null
echo "::endgroup::"
UPGRADED=$((UPGRADED + 1))
else
echo "Skipping $name (reinitializer unchanged: $old_ver)"
SKIPPED=$((SKIPPED + 1))
fi
done
echo "::notice::Upgrade summary: $UPGRADED upgraded, $SKIPPED skipped"
if [ "$UPGRADED" -eq 0 ]; then
echo "::warning::No contracts needed upgrading — consider bumping UPGRADE_FROM_TAG"
fi
- name: Verify contract versions
working-directory: current-fhevm/gateway-contracts
run: |
source addresses/.env.gateway
# shellcheck disable=SC2034 # variables used via indirect expansion ${!addr_var}
GatewayConfigAddress=$GATEWAY_CONFIG_ADDRESS
# shellcheck disable=SC2034
DecryptionAddress=$DECRYPTION_ADDRESS
# shellcheck disable=SC2034
CiphertextCommitsAddress=$CIPHERTEXT_COMMITS_ADDRESS
# shellcheck disable=SC2034
InputVerificationAddress=$INPUT_VERIFICATION_ADDRESS
# shellcheck disable=SC2034
MultichainACLAddress=$MULTICHAIN_ACL_ADDRESS
# shellcheck disable=SC2034
KMSGenerationAddress=$KMS_GENERATION_ADDRESS
for name in $(jq -r '.[]' upgrade-manifest.json); do
addr_var="${name}Address"
addr="${!addr_var:-}"
if [ -z "$addr" ]; then
# New contract (not in previous release) — no deployment to verify
if [ ! -f "previous-contracts/${name}.sol" ]; then
echo "Skipping $name version check (new contract, not previously deployed)"
continue
fi
echo "::error::$name existed in previous release but ${addr_var} is not set — check address mapping"
exit 1
fi
# Build expected version from source constants: "<Name> v<MAJOR>.<MINOR>.<PATCH>"
sol="contracts/${name}.sol"
major=$(sed -n 's/.*MAJOR_VERSION[[:space:]]*=[[:space:]]*\([0-9]*\).*/\1/p' "$sol")
minor=$(sed -n 's/.*MINOR_VERSION[[:space:]]*=[[:space:]]*\([0-9]*\).*/\1/p' "$sol")
patch=$(sed -n 's/.*PATCH_VERSION[[:space:]]*=[[:space:]]*\([0-9]*\).*/\1/p' "$sol")
expected="${name} v${major}.${minor}.${patch}"
actual=$(cast call "$addr" "getVersion()(string)" --rpc-url "$RPC_URL" | tr -d '"')
if [ "$actual" != "$expected" ]; then
echo "::error::$name version mismatch: expected '$expected', got '$actual'"
exit 1
fi
echo "$name: $actual"
done
- name: Clean up
working-directory: previous-fhevm/gateway-contracts
if: always()
run: |
make docker-compose-down