Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
177d817
ci(host-contracts): add cross-version upgrade test workflow (#1097)
Eikix Mar 2, 2026
334539b
fix(ci): correct misleading CHAIN_ID_GATEWAY comment
Eikix Mar 2, 2026
7f099ff
ci(host-contracts): skip upgrades for contracts with unchanged reinit…
Eikix Mar 2, 2026
0747688
ci: add actionlint ignore for host-contracts-upgrade-tests
Eikix Mar 3, 2026
dfa2030
ci(host-contracts): auto-detect contract upgrades via REINITIALIZER_V…
Eikix Mar 4, 2026
5eda611
ci(gateway-contracts): auto-detect contract upgrades via REINITIALIZE…
Eikix Mar 4, 2026
dbac5da
fix(ci): skip upgrade for contracts not present in previous release
Eikix Mar 4, 2026
3b45350
ci: align deployment check steps between host and gateway workflows
Eikix Mar 4, 2026
cdc3f8b
ci: rename PREVIOUS_RELEASE_TAG to UPGRADE_FROM_TAG, bump gateway to …
Eikix Mar 4, 2026
22755c7
ci: add inline comments to upgrade loop for readability
Eikix Mar 4, 2026
599f4fc
ci: verify contract versions with cast call after upgrades
Eikix Mar 4, 2026
bd0eb80
ci: assert getVersion() matches expected version from source constants
Eikix Mar 4, 2026
1fbb9d9
ci: replace associative arrays with indirect expansion for bash 3 compat
Eikix Mar 4, 2026
2e1db54
ci: strip quotes from cast call output before version comparison
Eikix Mar 4, 2026
b76b94f
ci: suppress shellcheck SC2034 for indirect expansion address vars
Eikix Mar 4, 2026
245e375
fix(ci): add shellcheck disable SC2034 to each indirect-expansion var…
Eikix Mar 4, 2026
1e27101
fix(ci): address PR review feedback
Eikix Mar 4, 2026
7ff3c17
fix(ci): fail-fast on missing REINITIALIZER_VERSION, skip verify for …
Eikix Mar 4, 2026
5aebbc4
fix(ci): fail-hard when address mapping is missing for existing contr…
Eikix Mar 4, 2026
e49fbb1
fix(coprocessor): decompress all ciphertexts per operation
antoniupop Mar 2, 2026
a1cb0be
fix(coprocessor): sanity-check that only scalars are uncompressed
antoniupop Mar 2, 2026
77081d0
fix(coprocessor): add compressed ct type
antoniupop Mar 2, 2026
b018037
ci: trigger fresh workflow run
Eikix Mar 4, 2026
42a2e6f
fix(coprocessor): propagate DecompressionError
antoniupop Mar 4, 2026
7909f07
fix(ci): address PR review nits — consistent PascalCase naming, add c…
Eikix Mar 5, 2026
93f1c05
fix(ci): clean Hardhat cache and OZ manifest between sequential upgrades
Eikix Mar 5, 2026
847266f
fix: wait for upgradeToAndCall tx receipt before declaring upgrade su…
Eikix Mar 5, 2026
8b099f6
Revert "fix: wait for upgradeToAndCall tx receipt before declaring up…
Eikix Mar 5, 2026
db6d7d6
fix(ci): force-mine and verify on-chain state after each contract upg…
Eikix Mar 5, 2026
971a14a
fix(ci): simplify upgrade step — remove redundant per-upgrade verific…
Eikix Mar 5, 2026
ed7e2c0
fix(ci): remove unnecessary hardhat clean/OZ manifest wipe between up…
Eikix Mar 5, 2026
96a61c7
Merge of #2036
mergify[bot] Mar 5, 2026
15bdb80
Merge of #2037
mergify[bot] Mar 5, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions .github/actionlint.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,3 @@ paths:
ignore:
- SC2001 # https://www.shellcheck.net/wiki/SC2129
- 'property "result" is not defined in object type.*'
.github/workflows/gateway-contracts-upgrade-tests.yml:
ignore:
- 'constant expression "false" in condition' # https://github.com/zama-ai/fhevm-internal/issues/379
206 changes: 115 additions & 91 deletions .github/workflows/gateway-contracts-upgrade-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ concurrency:
# - 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
Expand Down Expand Up @@ -54,9 +56,7 @@ jobs:
- name: Checkout previous release code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
# This version should be updated whenever we release new contract versions or
# touch a contract upgrade path.
ref: v0.10.0
ref: ${{ env.UPGRADE_FROM_TAG }}
path: previous-fhevm
persist-credentials: 'false'

Expand All @@ -79,21 +79,17 @@ jobs:
- name: Check smart contract deployment from previous release
working-directory: previous-fhevm/gateway-contracts
run: |

## Check Contracts Deployment
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
EXIT_CODE_SC=$(docker inspect --format='{{.State.ExitCode}}' deploy-gateway-contracts)
# display logs for debugging
# cat deployment_logs.txt
if [ "$EXIT_CODE_SC" -ne 0 ]; then
echo "Deployment failed with exit code $EXIT_CODE_SC"
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
else
echo "Deployment completed successfully with expected completion message"
fi

- name: Checkout current code
Expand All @@ -102,6 +98,9 @@ jobs:
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
Expand All @@ -117,89 +116,114 @@ jobs:
cp -r ../../previous-fhevm/gateway-contracts/contracts ./previous-contracts
docker cp deploy-gateway-contracts:/app/addresses ./

# TODO: We should instead automatically detect if the contract needs to be upgraded
# See https://github.com/zama-ai/fhevm-internal/issues/379
- name: Upgrade GatewayConfig contract
working-directory: current-fhevm/gateway-contracts
if: false
run: |
npx hardhat task:upgradeGatewayConfig \
--current-implementation previous-contracts/GatewayConfig.sol:GatewayConfig \
--new-implementation contracts/GatewayConfig.sol:GatewayConfig \
--use-internal-proxy-address true \
--verify-contract false

# TODO: We should instead automatically detect if the contract needs to be upgraded
# See https://github.com/zama-ai/fhevm-internal/issues/379
- name: Upgrade Decryption contract
working-directory: current-fhevm/gateway-contracts
if: false
run: |
npx hardhat task:upgradeDecryption \
--current-implementation previous-contracts/Decryption.sol:Decryption \
--new-implementation contracts/Decryption.sol:Decryption \
--use-internal-proxy-address true \
--verify-contract false

# TODO: We should instead automatically detect if the contract needs to be upgraded
# See https://github.com/zama-ai/fhevm-internal/issues/379
- name: Upgrade CiphertextCommits contract
- name: Run contract upgrades
working-directory: current-fhevm/gateway-contracts
if: false
run: |
npx hardhat task:upgradeCiphertextCommits \
--current-implementation previous-contracts/CiphertextCommits.sol:CiphertextCommits \
--new-implementation contracts/CiphertextCommits.sol:CiphertextCommits \
--use-internal-proxy-address true \
--verify-contract false

# TODO: We should instead automatically detect if the contract needs to be upgraded
# See https://github.com/zama-ai/fhevm-internal/issues/379
- name: Upgrade InputVerification contract
working-directory: current-fhevm/gateway-contracts
if: false
run: |
npx hardhat task:upgradeInputVerification \
--current-implementation previous-contracts/InputVerification.sol:InputVerification \
--new-implementation contracts/InputVerification.sol:InputVerification \
--use-internal-proxy-address true \
--verify-contract false

# TODO: We should instead automatically detect if the contract needs to be upgraded
# See https://github.com/zama-ai/fhevm-internal/issues/379
- name: Upgrade MultichainACL contract
working-directory: current-fhevm/gateway-contracts
if: false
run: |
npx hardhat task:upgradeMultichainACL \
--current-implementation previous-contracts/MultichainACL.sol:MultichainACL \
--new-implementation contracts/MultichainACL.sol:MultichainACL \
--use-internal-proxy-address true \
--verify-contract false

# TODO: We should instead automatically detect if the contract needs to be upgraded
# See https://github.com/zama-ai/fhevm-internal/issues/379
- name: Upgrade KMSGeneration contract
working-directory: current-fhevm/gateway-contracts
if: false
run: |
npx hardhat task:upgradeKMSGeneration \
--current-implementation previous-contracts/KMSGeneration.sol:KMSGeneration \
--new-implementation contracts/KMSGeneration.sol:KMSGeneration \
--use-internal-proxy-address true \
--verify-contract false

# TODO: We should instead automatically detect if the contract needs to be upgraded
# See https://github.com/zama-ai/fhevm-internal/issues/379
- name: Upgrade ProtocolPayment contract
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
if: false
run: |
npx hardhat task:upgradeProtocolPayment \
--current-implementation previous-contracts/ProtocolPayment.sol:ProtocolPayment \
--new-implementation contracts/ProtocolPayment.sol:ProtocolPayment \
--use-internal-proxy-address true \
--verify-contract false
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
Expand Down
Loading
Loading