chore(test-suite): sacrificial merge-queue validation for #2066 #6175
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 |