@@ -15,6 +15,8 @@ concurrency:
1515# - CHAIN_ID_GATEWAY: Should match the chain ID used in the anvil node in the docker-compose.yml file
1616# - RPC_URL: The port should match the one used in the anvil node in the docker-compose.yml file
1717env :
18+ # Bump this tag each release cycle to test upgrades from the previous version
19+ UPGRADE_FROM_TAG : v0.11.0
1820 DOTENV_CONFIG_PATH : .env.example
1921 HARDHAT_NETWORK : staging
2022 CHAIN_ID_GATEWAY : 54321
5456 - name : Checkout previous release code
5557 uses : actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
5658 with :
57- # This version should be updated whenever we release new contract versions or
58- # touch a contract upgrade path.
59- ref : v0.10.0
59+ ref : ${{ env.UPGRADE_FROM_TAG }}
6060 path : previous-fhevm
6161 persist-credentials : ' false'
6262
@@ -79,21 +79,17 @@ jobs:
7979 - name : Check smart contract deployment from previous release
8080 working-directory : previous-fhevm/gateway-contracts
8181 run : |
82-
83- ## Check Contracts Deployment
8482 timeout 300s bash -c 'while docker ps --filter "name=deploy-gateway-contracts" --format "{{.Status}}" | grep -q "Up"; do sleep 5; done'
8583 docker compose logs deploy-gateway-contracts > deployment_logs.txt
86- EXIT_CODE_SC=$(docker inspect --format='{{.State.ExitCode}}' deploy-gateway-contracts)
87- # display logs for debugging
88- # cat deployment_logs.txt
89- if [ "$EXIT_CODE_SC " -ne 0 ]; then
90- echo "Deployment failed with exit code $EXIT_CODE_SC "
84+ cat deployment_logs.txt
85+ EXIT_CODE=$(docker inspect --format='{{.State.ExitCode}}' deploy-gateway-contracts)
86+
87+ if [ "$EXIT_CODE " -ne 0 ]; then
88+ echo "Deployment failed with exit code $EXIT_CODE "
9189 exit 1
9290 elif ! grep -q "Contract deployment done!" deployment_logs.txt; then
9391 echo "Deployment did not complete successfully - 'Contract deployment done!' message not found in logs"
9492 exit 1
95- else
96- echo "Deployment completed successfully with expected completion message"
9793 fi
9894
9995 - name : Checkout current code
10298 persist-credentials : ' false'
10399 path : current-fhevm
104100
101+ - name : Install Foundry
102+ uses : foundry-rs/foundry-toolchain@82dee4ba654bd2146511f85f0d013af94670c4de # v1.4.0
103+
105104 - name : Install dependencies
106105 working-directory : current-fhevm/gateway-contracts
107106 run : npm ci
@@ -117,89 +116,114 @@ jobs:
117116 cp -r ../../previous-fhevm/gateway-contracts/contracts ./previous-contracts
118117 docker cp deploy-gateway-contracts:/app/addresses ./
119118
120- # TODO: We should instead automatically detect if the contract needs to be upgraded
121- # See https://github.com/zama-ai/fhevm-internal/issues/379
122- - name : Upgrade GatewayConfig contract
123- working-directory : current-fhevm/gateway-contracts
124- if : false
125- run : |
126- npx hardhat task:upgradeGatewayConfig \
127- --current-implementation previous-contracts/GatewayConfig.sol:GatewayConfig \
128- --new-implementation contracts/GatewayConfig.sol:GatewayConfig \
129- --use-internal-proxy-address true \
130- --verify-contract false
131-
132- # TODO: We should instead automatically detect if the contract needs to be upgraded
133- # See https://github.com/zama-ai/fhevm-internal/issues/379
134- - name : Upgrade Decryption contract
135- working-directory : current-fhevm/gateway-contracts
136- if : false
137- run : |
138- npx hardhat task:upgradeDecryption \
139- --current-implementation previous-contracts/Decryption.sol:Decryption \
140- --new-implementation contracts/Decryption.sol:Decryption \
141- --use-internal-proxy-address true \
142- --verify-contract false
143-
144- # TODO: We should instead automatically detect if the contract needs to be upgraded
145- # See https://github.com/zama-ai/fhevm-internal/issues/379
146- - name : Upgrade CiphertextCommits contract
119+ - name : Run contract upgrades
147120 working-directory : current-fhevm/gateway-contracts
148- if : false
149121 run : |
150- npx hardhat task:upgradeCiphertextCommits \
151- --current-implementation previous-contracts/CiphertextCommits.sol:CiphertextCommits \
152- --new-implementation contracts/CiphertextCommits.sol:CiphertextCommits \
153- --use-internal-proxy-address true \
154- --verify-contract false
155-
156- # TODO: We should instead automatically detect if the contract needs to be upgraded
157- # See https://github.com/zama-ai/fhevm-internal/issues/379
158- - name : Upgrade InputVerification contract
159- working-directory : current-fhevm/gateway-contracts
160- if : false
161- run : |
162- npx hardhat task:upgradeInputVerification \
163- --current-implementation previous-contracts/InputVerification.sol:InputVerification \
164- --new-implementation contracts/InputVerification.sol:InputVerification \
165- --use-internal-proxy-address true \
166- --verify-contract false
167-
168- # TODO: We should instead automatically detect if the contract needs to be upgraded
169- # See https://github.com/zama-ai/fhevm-internal/issues/379
170- - name : Upgrade MultichainACL contract
171- working-directory : current-fhevm/gateway-contracts
172- if : false
173- run : |
174- npx hardhat task:upgradeMultichainACL \
175- --current-implementation previous-contracts/MultichainACL.sol:MultichainACL \
176- --new-implementation contracts/MultichainACL.sol:MultichainACL \
177- --use-internal-proxy-address true \
178- --verify-contract false
179-
180- # TODO: We should instead automatically detect if the contract needs to be upgraded
181- # See https://github.com/zama-ai/fhevm-internal/issues/379
182- - name : Upgrade KMSGeneration contract
183- working-directory : current-fhevm/gateway-contracts
184- if : false
185- run : |
186- npx hardhat task:upgradeKMSGeneration \
187- --current-implementation previous-contracts/KMSGeneration.sol:KMSGeneration \
188- --new-implementation contracts/KMSGeneration.sol:KMSGeneration \
189- --use-internal-proxy-address true \
190- --verify-contract false
191-
192- # TODO: We should instead automatically detect if the contract needs to be upgraded
193- # See https://github.com/zama-ai/fhevm-internal/issues/379
194- - name : Upgrade ProtocolPayment contract
122+ set -euo pipefail
123+ UPGRADED=0
124+ SKIPPED=0
125+
126+ # Iterate over contracts listed in the upgrade manifest
127+ for name in $(jq -r '.[]' upgrade-manifest.json); do
128+ # Fail fast if the contract is missing from current code (manifest out of sync)
129+ if [ ! -f "contracts/${name}.sol" ]; then
130+ echo "::error::$name listed in upgrade-manifest.json but contracts/${name}.sol not found"
131+ exit 1
132+ fi
133+
134+ # Skip contracts not present in the previous release (e.g. newly added)
135+ if [ ! -f "previous-contracts/${name}.sol" ]; then
136+ echo "Skipping $name (not present in previous release)"
137+ SKIPPED=$((SKIPPED + 1))
138+ continue
139+ fi
140+
141+ # Extract REINITIALIZER_VERSION from both versions
142+ old_ver=$(sed -n 's/.*REINITIALIZER_VERSION[[:space:]]*=[[:space:]]*\([0-9]*\).*/\1/p' \
143+ "previous-contracts/${name}.sol")
144+ new_ver=$(sed -n 's/.*REINITIALIZER_VERSION[[:space:]]*=[[:space:]]*\([0-9]*\).*/\1/p' \
145+ "contracts/${name}.sol")
146+ if [ -z "$old_ver" ]; then
147+ echo "::error::Failed to parse REINITIALIZER_VERSION from previous-contracts/${name}.sol"
148+ exit 1
149+ fi
150+ if [ -z "$new_ver" ]; then
151+ echo "::error::Failed to parse REINITIALIZER_VERSION from contracts/${name}.sol"
152+ exit 1
153+ fi
154+
155+ # Upgrade only if reinitializer version changed
156+ if [ "$old_ver" != "$new_ver" ]; then
157+ echo "::group::Upgrading $name (reinitializer $old_ver → $new_ver)"
158+
159+ npx hardhat "task:upgrade${name}" \
160+ --current-implementation "previous-contracts/${name}.sol:${name}" \
161+ --new-implementation "contracts/${name}.sol:${name}" \
162+ --use-internal-proxy-address true \
163+ --verify-contract false
164+
165+ # OZ upgradeProxy does not wait for the upgradeToAndCall tx to be mined.
166+ # With Anvil's interval mining (--block-time), flush it before moving on.
167+ cast rpc evm_mine --rpc-url "$RPC_URL" > /dev/null
168+
169+ echo "::endgroup::"
170+ UPGRADED=$((UPGRADED + 1))
171+ else
172+ echo "Skipping $name (reinitializer unchanged: $old_ver)"
173+ SKIPPED=$((SKIPPED + 1))
174+ fi
175+ done
176+
177+ echo "::notice::Upgrade summary: $UPGRADED upgraded, $SKIPPED skipped"
178+ if [ "$UPGRADED" -eq 0 ]; then
179+ echo "::warning::No contracts needed upgrading — consider bumping UPGRADE_FROM_TAG"
180+ fi
181+
182+ - name : Verify contract versions
195183 working-directory : current-fhevm/gateway-contracts
196- if : false
197184 run : |
198- npx hardhat task:upgradeProtocolPayment \
199- --current-implementation previous-contracts/ProtocolPayment.sol:ProtocolPayment \
200- --new-implementation contracts/ProtocolPayment.sol:ProtocolPayment \
201- --use-internal-proxy-address true \
202- --verify-contract false
185+ source addresses/.env.gateway
186+ # shellcheck disable=SC2034 # variables used via indirect expansion ${!addr_var}
187+ GatewayConfigAddress=$GATEWAY_CONFIG_ADDRESS
188+ # shellcheck disable=SC2034
189+ DecryptionAddress=$DECRYPTION_ADDRESS
190+ # shellcheck disable=SC2034
191+ CiphertextCommitsAddress=$CIPHERTEXT_COMMITS_ADDRESS
192+ # shellcheck disable=SC2034
193+ InputVerificationAddress=$INPUT_VERIFICATION_ADDRESS
194+ # shellcheck disable=SC2034
195+ MultichainACLAddress=$MULTICHAIN_ACL_ADDRESS
196+ # shellcheck disable=SC2034
197+ KMSGenerationAddress=$KMS_GENERATION_ADDRESS
198+
199+ for name in $(jq -r '.[]' upgrade-manifest.json); do
200+ addr_var="${name}Address"
201+ addr="${!addr_var:-}"
202+ if [ -z "$addr" ]; then
203+ # New contract (not in previous release) — no deployment to verify
204+ if [ ! -f "previous-contracts/${name}.sol" ]; then
205+ echo "Skipping $name version check (new contract, not previously deployed)"
206+ continue
207+ fi
208+ echo "::error::$name existed in previous release but ${addr_var} is not set — check address mapping"
209+ exit 1
210+ fi
211+
212+ # Build expected version from source constants: "<Name> v<MAJOR>.<MINOR>.<PATCH>"
213+ sol="contracts/${name}.sol"
214+ major=$(sed -n 's/.*MAJOR_VERSION[[:space:]]*=[[:space:]]*\([0-9]*\).*/\1/p' "$sol")
215+ minor=$(sed -n 's/.*MINOR_VERSION[[:space:]]*=[[:space:]]*\([0-9]*\).*/\1/p' "$sol")
216+ patch=$(sed -n 's/.*PATCH_VERSION[[:space:]]*=[[:space:]]*\([0-9]*\).*/\1/p' "$sol")
217+ expected="${name} v${major}.${minor}.${patch}"
218+
219+ actual=$(cast call "$addr" "getVersion()(string)" --rpc-url "$RPC_URL" | tr -d '"')
220+
221+ if [ "$actual" != "$expected" ]; then
222+ echo "::error::$name version mismatch: expected '$expected', got '$actual'"
223+ exit 1
224+ fi
225+ echo "$name: $actual"
226+ done
203227
204228 - name : Clean up
205229 working-directory : previous-fhevm/gateway-contracts
0 commit comments