From 39619b220bbb6520056042ae38f150e7dce7a054 Mon Sep 17 00:00:00 2001 From: Phi Date: Mon, 12 Jan 2026 09:43:49 +0100 Subject: [PATCH 01/32] feat: document FWSS upgrade process feat: document FWSS upgrade process --- .github/workflows/upgrade-announcement.yml | 177 +++++++++++++ service_contracts/tools/README.md | 49 ++-- service_contracts/tools/UPGRADE-PROCESS.md | 291 +++++++++++++++++++++ 3 files changed, 495 insertions(+), 22 deletions(-) create mode 100644 .github/workflows/upgrade-announcement.yml create mode 100644 service_contracts/tools/UPGRADE-PROCESS.md diff --git a/.github/workflows/upgrade-announcement.yml b/.github/workflows/upgrade-announcement.yml new file mode 100644 index 00000000..100dc874 --- /dev/null +++ b/.github/workflows/upgrade-announcement.yml @@ -0,0 +1,177 @@ +name: Create Upgrade Announcement + +on: + workflow_dispatch: + inputs: + network: + description: 'Target network' + required: true + type: choice + options: + - Calibnet + - Mainnet + upgrade_type: + description: 'Type of upgrade' + required: true + type: choice + options: + - Routine + - Breaking Change + contract: + description: 'Contract being upgraded' + required: true + type: choice + options: + - FilecoinWarmStorageService + - ServiceProviderRegistry + - PDPVerifier + after_epoch: + description: 'AFTER_EPOCH (block number after which upgrade can execute)' + required: true + type: string + new_implementation_address: + description: 'New implementation contract address' + required: true + type: string + changes_summary: + description: 'Summary of changes (use | for multiple lines)' + required: true + type: string + release_tag: + description: 'Release tag if already created (usually added after upgrade completes)' + required: false + type: string + action_required: + description: 'Action required by integrators (leave empty if none)' + required: false + type: string + +jobs: + create-announcement: + runs-on: ubuntu-latest + permissions: + issues: write + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Calculate estimated execution time + id: calc_time + run: | + # Filecoin has ~30 second block times + # Get current epoch from RPC (approximate) + if [ "${{ inputs.network }}" = "Mainnet" ]; then + RPC_URL="https://api.node.glif.io/rpc/v1" + else + RPC_URL="https://api.calibration.node.glif.io/rpc/v1" + fi + + CURRENT_EPOCH=$(curl -s -X POST "$RPC_URL" \ + -H "Content-Type: application/json" \ + -d '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' \ + | jq -r '.result' | xargs printf "%d") + + AFTER_EPOCH=${{ inputs.after_epoch }} + EPOCHS_REMAINING=$((AFTER_EPOCH - CURRENT_EPOCH)) + + if [ $EPOCHS_REMAINING -lt 0 ]; then + echo "estimate=Immediately (epoch already passed)" >> $GITHUB_OUTPUT + else + SECONDS_REMAINING=$((EPOCHS_REMAINING * 30)) + HOURS=$((SECONDS_REMAINING / 3600)) + MINUTES=$(((SECONDS_REMAINING % 3600) / 60)) + + FUTURE_DATE=$(date -u -d "+${SECONDS_REMAINING} seconds" "+%Y-%m-%d %H:%M UTC" 2>/dev/null || \ + date -u -v+${SECONDS_REMAINING}S "+%Y-%m-%d %H:%M UTC" 2>/dev/null || \ + echo "~${HOURS}h ${MINUTES}m from now") + + echo "estimate=~${FUTURE_DATE} (~${HOURS}h ${MINUTES}m from current epoch ${CURRENT_EPOCH})" >> $GITHUB_OUTPUT + fi + + - name: Format changes summary + id: format_changes + run: | + # Convert pipe-separated changes to bullet points + CHANGES=$(echo "${{ inputs.changes_summary }}" | sed 's/|/\n/g' | sed 's/^/- /' | sed '/^- $/d') + echo "changes<> $GITHUB_OUTPUT + echo "$CHANGES" >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT + + - name: Create announcement issue + uses: actions/github-script@v7 + with: + script: | + const network = '${{ inputs.network }}'; + const upgradeType = '${{ inputs.upgrade_type }}'; + const contract = '${{ inputs.contract }}'; + const afterEpoch = '${{ inputs.after_epoch }}'; + const implAddress = '${{ inputs.new_implementation_address }}'; + const releaseTag = '${{ inputs.release_tag }}'; + const actionRequired = '${{ inputs.action_required }}' || 'None'; + const timeEstimate = `${{ steps.calc_time.outputs.estimate }}`; + const changes = `${{ steps.format_changes.outputs.changes }}`; + + const releaseLink = releaseTag + ? `https://github.com/${context.repo.owner}/${context.repo.repo}/releases/tag/${releaseTag}` + : null; + + const changelogLink = `https://github.com/${context.repo.owner}/${context.repo.repo}/blob/main/CHANGELOG.md`; + + const body = `## ${contract} Upgrade Announcement + + **Network**: ${network} + **Upgrade Type**: ${upgradeType} + **Scheduled Execution**: After epoch ${afterEpoch} (${timeEstimate}) + + ### Changes + ${changes} + + ### New Implementation Address + \`${implAddress}\` + + ### Action Required + ${actionRequired} + + ### Resources + ${releaseLink ? `- Release: ${releaseLink}` : ''} + - Changelog: ${changelogLink} + - Upgrade Process: [UPGRADE-PROCESS.md](https://github.com/${context.repo.owner}/${context.repo.repo}/blob/main/service_contracts/tools/UPGRADE-PROCESS.md) + + --- + + ### Checklist + - [ ] New implementation deployed (address above) + - [ ] Upgrade announced on-chain via \`announce-planned-upgrade.sh\` + - [ ] Stakeholders notified + - [ ] Upgrade executed after AFTER_EPOCH + - [ ] Upgrade verified on block explorer + - [ ] \`deployments.json\` updated and committed + - [ ] Release tagged (post-upgrade) + `.split('\n').map(line => line.trim()).join('\n'); + + const labels = ['upgrade']; + if (upgradeType === 'Breaking Change') { + labels.push('breaking-change'); + } + + const issue = await github.rest.issues.create({ + owner: context.repo.owner, + repo: context.repo.repo, + title: `[Upgrade] ${contract} - ${network} - Epoch ${afterEpoch}`, + body: body, + labels: labels + }); + + console.log(`Created issue #${issue.data.number}: ${issue.data.html_url}`); + core.setOutput('issue_number', issue.data.number); + core.setOutput('issue_url', issue.data.html_url); + + - name: Summary + run: | + echo "## Upgrade Announcement Created" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "**Contract**: ${{ inputs.contract }}" >> $GITHUB_STEP_SUMMARY + echo "**Network**: ${{ inputs.network }}" >> $GITHUB_STEP_SUMMARY + echo "**After Epoch**: ${{ inputs.after_epoch }}" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "See the created issue for full details." >> $GITHUB_STEP_SUMMARY diff --git a/service_contracts/tools/README.md b/service_contracts/tools/README.md index 9ad4a0dd..1aab5440 100644 --- a/service_contracts/tools/README.md +++ b/service_contracts/tools/README.md @@ -2,13 +2,21 @@ This directory contains scripts for deploying and upgrading the FilecoinWarmStorageService contract on Calibration testnet and Mainnet. +> **For detailed upgrade procedures**, see [UPGRADE-PROCESS.md](./UPGRADE-PROCESS.md). + ## Scripts Overview -### Available Scripts +### Deployment Scripts - `deploy-warm-storage-calibnet.sh` - Deploy FilecoinWarmStorageService only (requires existing PDPVerifier and FilecoinPayV1 contracts) - `deploy-all-warm-storage.sh` - Deploy all contracts to either Calibnet or Mainnet -- `upgrade-warm-storage-calibnet.sh` - Upgrade existing FilecoinWarmStorageService contract with new proving period parameters + +### Upgrade Scripts + +- `announce-planned-upgrade.sh` - Announce a planned FWSS upgrade (two-step process) +- `upgrade.sh` - Execute a previously announced FWSS upgrade +- `announce-planned-upgrade-registry.sh` - Announce a planned ServiceProviderRegistry upgrade +- `upgrade-registry.sh` - Execute a previously announced registry upgrade ### Usage @@ -19,8 +27,9 @@ This directory contains scripts for deploying and upgrading the FilecoinWarmStor # Deploy all contracts ./tools/deploy-all-warm-storage.sh -# Upgrade existing deployment -./tools/upgrade-warm-storage-calibnet.sh +# Upgrade existing deployment (see UPGRADE-PROCESS.md for details) +./tools/announce-planned-upgrade.sh # Step 1: Announce +./tools/upgrade.sh # Step 2: Execute (after AFTER_EPOCH) ``` ## Deployment Parameters @@ -116,16 +125,13 @@ These scripts now follow forge/cast's environment variable conventions. Set the ### Required for specific scripts: - `deploy-warm-storage-calibnet.sh` requires: - - `PDP_VERIFIER_PROXY_ADDRESS` - Address of deployed PDPVerifier contract - `FILECOIN_PAY_ADDRESS` - Address of deployed FilecoinPayV1 contract - - `deploy-all-warm-storage.sh` requires: - `CHALLENGE_FINALITY` - Challenge finality parameter for PDPVerifier -- `upgrade-warm-storage-calibnet.sh` requires: - - `WARM_STORAGE_SERVICE_PROXY_ADDRESS` - Address of existing FilecoinWarmStorageService proxy to upgrade +- Upgrade scripts - see [UPGRADE-PROCESS.md](./UPGRADE-PROCESS.md) for complete environment variable reference ## Usage Examples @@ -160,25 +166,24 @@ export FILECOIN_PAY_ADDRESS="0x456..." ### Upgrade Existing Contract -```bash -export ETH_KEYSTORE="/path/to/keystore.json" -export PASSWORD="your-password" -export ETH_RPC_URL="https://api.calibration.node.glif.io/rpc/v1" -export WARM_STORAGE_SERVICE_PROXY_ADDRESS="0x789..." +See [UPGRADE-PROCESS.md](./UPGRADE-PROCESS.md) for the complete two-step upgrade workflow. -# Optional: Custom proving periods -export MAX_PROVING_PERIOD="240" # 240 epochs for calibnet, 2880 for mainnet -export CHALLENGE_WINDOW_SIZE="20" # 20 epochs for calibnet, 60 for mainnet +## Contract Upgrade Process -./upgrade-warm-storage-calibnet.sh -``` +The FilecoinWarmStorageService and ServiceProviderRegistry contracts use a **two-step upgrade process** for security: -## Contract Upgrade Process +1. **Announce**: Call `announcePlannedUpgrade()` with the new implementation address and a future epoch +2. **Execute**: After the announced epoch, call `upgradeToAndCall()` to complete the upgrade + +This gives stakeholders time to review changes before execution. -The FilecoinWarmStorageService contract uses OpenZeppelin's upgradeable pattern. When upgrading: +**For complete upgrade documentation**, including: +- Step-by-step upgrade workflows +- Environment variable reference +- Immutable dependency handling +- Verification procedures -1. **Deploy new implementation**: The script deploys a new implementation contract -2. **Upgrade proxy**: Uses `upgradeToAndCall` to point the proxy to the new implementation +See [UPGRADE-PROCESS.md](./UPGRADE-PROCESS.md). ## Testing diff --git a/service_contracts/tools/UPGRADE-PROCESS.md b/service_contracts/tools/UPGRADE-PROCESS.md new file mode 100644 index 00000000..ba076fa8 --- /dev/null +++ b/service_contracts/tools/UPGRADE-PROCESS.md @@ -0,0 +1,291 @@ +# FWSS Contract Upgrade Process + +This document describes the upgrade process for FilecoinWarmStorageService (FWSS) and related contracts. + +## Contract Upgradeability Overview + +| Contract | Proxy Pattern | Upgrade Method | +|----------|---------------|----------------| +| FilecoinWarmStorageService | UUPS Proxy (two-step) | `announce-planned-upgrade.sh` + `upgrade.sh` | +| ServiceProviderRegistry | UUPS Proxy (two-step) | `announce-planned-upgrade-registry.sh` + `upgrade-registry.sh` | +| PDPVerifier | ERC1967 Proxy | Via [pdp repo](https://github.com/FilOzone/pdp) scripts | +| FilecoinPayV1 | None (immutable) | Not expected to be redeployed | +| SessionKeyRegistry | None (immutable) | Not expected to be redeployed | +| FilecoinWarmStorageServiceStateView | None (helper) | Redeployable via `deploy-warm-storage-view.sh` | + +## Immutable Dependencies + +FWSS stores several dependencies as `immutable` constructor parameters: + +```solidity +IPDPVerifier public immutable pdpVerifier; +FilecoinPayV1 public immutable paymentsContract; +IERC20Metadata public immutable usdfcTokenAddress; +address public immutable filBeamBeneficiaryAddress; +ServiceProviderRegistry public immutable serviceProviderRegistry; +SessionKeyRegistry public immutable sessionKeyRegistry; +``` + +### Operational Expectations + +These immutable contracts are **not expected to be redeployed** under normal operations. Redeploying any of these would require upgrading FWSS to a new implementation with updated constructor arguments, which could break existing functionality and integrations. + +**If redeployment becomes necessary:** +- It will be announced **well ahead of time** to all stakeholders +- A migration plan will be communicated +- The change will go through the standard two-step upgrade process with an extended notice period + +## Two-Step Upgrade Process + +Both FWSS and ServiceProviderRegistry use a security-focused two-step upgrade mechanism: + +1. **Announce** - Call `announcePlannedUpgrade()` with the new implementation address and `AFTER_EPOCH` +2. **Execute** - After `AFTER_EPOCH` has passed, call `upgradeToAndCall()` to complete the upgrade + +This gives stakeholders time to review changes before execution. + +## Stakeholder Communication + + + +> **Tip**: Use the [Create Upgrade Announcement](../../.github/workflows/upgrade-announcement.yml) GitHub Action to automatically generate an announcement issue. Go to **Actions → Create Upgrade Announcement → Run workflow**. + +### Before Announcing an Upgrade + +Before running `announce-planned-upgrade.sh`, notify stakeholders through: + +- [ ] **Slack**: Post in `#` with upgrade details +- [ ] **GitHub**: Create a tracking issue or discussion for the upgrade +- [ ] **Documentation**: Update changelog with upcoming changes + +### Upgrade Announcement Template + +> **Automated**: The [Create Upgrade Announcement](https://github.com/FilOzone/filecoin-services/actions/workflows/upgrade-announcement.yml) GitHub Action generates this template as an issue automatically. + +When communicating an upgrade, include: + +``` +## FWSS Contract Upgrade Announcement + +**Network**: [Mainnet/Calibnet] +**Upgrade Type**: [Routine/Breaking Change] +**Scheduled Execution**: After epoch [AFTER_EPOCH] (~[estimated date/time]) + +### Changes +- [Summary of changes] +- [Link to PR/release notes] + +### New Implementation Address +`0x...` + +### Action Required +[None / Describe any required actions for integrators] + +### Resources +- Release: [link] (if applicable) +- Changelog: [link] +``` + +### After Upgrade Execution + +- [ ] **Verify**: Confirm upgrade success on block explorer +- [ ] **Notify**: Post confirmation in communication channels +- [ ] **Update**: Update `deployments.json` (automatic) and any external documentation +- [ ] **Release**: Tag a new release in GitHub with updated addresses + +### Breaking Changes Communication + +For upgrades involving immutable dependency changes or breaking API changes: + +- Provide **extended notice period** (minimum recommended: ) +- Create detailed **migration guide** for affected integrators +- Offer **support channel** for questions during migration +- Consider **phased rollout**: Calibnet first, then Mainnet after validation + +## FWSS Upgrade Workflow + +### Step 1: Deploy New Implementation + +Deploy the new implementation contract with the same immutable dependencies: + +```bash +export ETH_KEYSTORE="/path/to/keystore.json" +export PASSWORD="your-password" +export ETH_RPC_URL="https://api.calibration.node.glif.io/rpc/v1" + +# Deploy new implementation (uses existing immutable addresses from deployments.json) +forge create --password "$PASSWORD" --broadcast \ + --libraries "src/lib/SignatureVerificationLib.sol:SignatureVerificationLib:$SIGNATURE_VERIFICATION_LIB_ADDRESS" \ + src/FilecoinWarmStorageService.sol:FilecoinWarmStorageService \ + --constructor-args \ + "$PDP_VERIFIER_ADDRESS" \ + "$PAYMENTS_CONTRACT_ADDRESS" \ + "$USDFC_TOKEN_ADDRESS" \ + "$FILBEAM_BENEFICIARY_ADDRESS" \ + "$SERVICE_PROVIDER_REGISTRY_PROXY_ADDRESS" \ + "$SESSION_KEY_REGISTRY_ADDRESS" +``` + +### Step 2: Optionally Deploy New StateView + +If the StateView contract needs updating: + +```bash +source ./deploy-warm-storage-view.sh +``` + +### Step 3: Announce the Upgrade + +```bash +export ETH_RPC_URL="https://api.calibration.node.glif.io/rpc/v1" +export ETH_KEYSTORE="/path/to/keystore.json" +export PASSWORD="your-password" +export WARM_STORAGE_PROXY_ADDRESS="0x..." +export NEW_WARM_STORAGE_IMPLEMENTATION_ADDRESS="0x..." # From step 1 +export AFTER_EPOCH="123456" # Block number after which upgrade can execute + +./announce-planned-upgrade.sh +``` + +### Step 4: Wait for AFTER_EPOCH + +The upgrade cannot be executed until the current block number exceeds `AFTER_EPOCH`. + +### Step 5: Execute the Upgrade + +```bash +export ETH_RPC_URL="https://api.calibration.node.glif.io/rpc/v1" +export ETH_KEYSTORE="/path/to/keystore.json" +export PASSWORD="your-password" +export WARM_STORAGE_PROXY_ADDRESS="0x..." +export NEW_WARM_STORAGE_IMPLEMENTATION_ADDRESS="0x..." +# Optional: NEW_WARM_STORAGE_VIEW_ADDRESS if deploying new view contract + +./upgrade.sh +``` + +### Step 6: Verify + +The script automatically: +- Verifies the upgrade by checking the implementation storage slot +- Updates `deployments.json` with the new implementation address + +## ServiceProviderRegistry Upgrade Workflow + +Similar to FWSS, but uses dedicated scripts: + +### Announce + +```bash +export ETH_RPC_URL="https://api.calibration.node.glif.io/rpc/v1" +export ETH_KEYSTORE="/path/to/keystore.json" +export PASSWORD="your-password" +export REGISTRY_PROXY_ADDRESS="0x..." +export NEW_REGISTRY_IMPLEMENTATION_ADDRESS="0x..." +export AFTER_EPOCH="123456" + +./announce-planned-upgrade-registry.sh +``` + +### Execute + +```bash +export ETH_RPC_URL="https://api.calibration.node.glif.io/rpc/v1" +export ETH_KEYSTORE="/path/to/keystore.json" +export PASSWORD="your-password" +export SERVICE_PROVIDER_REGISTRY_PROXY_ADDRESS="0x..." +export NEW_REGISTRY_IMPLEMENTATION_ADDRESS="0x..." +export NEW_VERSION="v1.1.0" # Optional version string for migrate() + +./upgrade-registry.sh +``` + +## StateView Contract Updates + +The `FilecoinWarmStorageServiceStateView` is a helper contract that can be redeployed independently without going through the two-step announcement process: + +1. Deploy new StateView: + ```bash + source ./deploy-warm-storage-view.sh + ``` + +2. Set the new view address on FWSS proxy: + ```bash + source ./set-warm-storage-view.sh + ``` + +This is an owner-only operation and does not require an upgrade announcement. + +## Environment Variables Reference + +### Common Variables + +| Variable | Description | +|----------|-------------| +| `ETH_RPC_URL` | RPC endpoint (e.g., `https://api.calibration.node.glif.io/rpc/v1`) | +| `ETH_KEYSTORE` | Path to Ethereum keystore file | +| `PASSWORD` | Keystore password | +| `CHAIN` | Chain ID (auto-detected if not set) | + +### FWSS Upgrade Variables + +| Variable | Description | +|----------|-------------| +| `WARM_STORAGE_PROXY_ADDRESS` | Address of FWSS proxy contract | +| `NEW_WARM_STORAGE_IMPLEMENTATION_ADDRESS` | Address of new implementation | +| `AFTER_EPOCH` | Block number after which upgrade can execute | +| `NEW_WARM_STORAGE_VIEW_ADDRESS` | (Optional) New StateView address | + +### Registry Upgrade Variables + +| Variable | Description | +|----------|-------------| +| `SERVICE_PROVIDER_REGISTRY_PROXY_ADDRESS` | Address of registry proxy | +| `REGISTRY_PROXY_ADDRESS` | Same as above (used by announce script) | +| `NEW_REGISTRY_IMPLEMENTATION_ADDRESS` | Address of new implementation | +| `AFTER_EPOCH` | Block number after which upgrade can execute | +| `NEW_VERSION` | (Optional) Version string for migrate() | + +## Verification and Testing + +### Always Test on Calibnet First + +Before upgrading on mainnet, always test the upgrade on Calibnet: + +```bash +export ETH_RPC_URL="https://api.calibration.node.glif.io/rpc/v1" +# ... run upgrade scripts +``` + +### Storage Layout Verification + +Before deploying a new implementation, verify storage layout compatibility: + +```bash +forge inspect src/FilecoinWarmStorageService.sol:FilecoinWarmStorageService storageLayout +``` + +Compare with the previous version to ensure no storage slot collisions. + +### Upgrade Verification + +The upgrade scripts automatically verify success by checking the ERC1967 implementation slot: + +```bash +cast rpc eth_getStorageAt "$PROXY_ADDRESS" \ + 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc latest +``` + +### Run Upgrade Tests + +```bash +forge test --match-contract FilecoinWarmStorageServiceUpgradeTest +``` + +## Deployment Address Management + +All deployment scripts automatically load and update addresses in `deployments.json`. See the main [README.md](./README.md) for details on: + +- How addresses are loaded by chain ID +- Environment variable overrides +- Control flags (`SKIP_LOAD_DEPLOYMENTS`, `SKIP_UPDATE_DEPLOYMENTS`) From 5f6154ec0169fb52b0c4abbaaafe16a27a2f4711 Mon Sep 17 00:00:00 2001 From: Phi Date: Thu, 15 Jan 2026 12:34:52 +0100 Subject: [PATCH 02/32] docs: enhance UPGRADE-PROCESS.md with detailed AFTER_EPOCH guidelines and release workflow steps --- service_contracts/tools/UPGRADE-PROCESS.md | 66 ++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/service_contracts/tools/UPGRADE-PROCESS.md b/service_contracts/tools/UPGRADE-PROCESS.md index ba076fa8..536ccfc9 100644 --- a/service_contracts/tools/UPGRADE-PROCESS.md +++ b/service_contracts/tools/UPGRADE-PROCESS.md @@ -44,6 +44,72 @@ Both FWSS and ServiceProviderRegistry use a security-focused two-step upgrade me This gives stakeholders time to review changes before execution. +## Choosing AFTER_EPOCH + +When announcing an upgrade, choose `AFTER_EPOCH` to give stakeholders adequate notice: + +| Upgrade Type | Minimum Notice | Recommended | +|--------------|----------------|-------------| +| Routine (bug fixes, minor features) | ~24 hours (~2,880 epochs) | 1-2 days | +| Breaking changes | ~1 week (~20,160 epochs) | 1-2 weeks | +| Immutable dependency changes | ~2 weeks (~40,320 epochs) | 2-4 weeks | + +**To calculate:** + +```bash +# Get current epoch +CURRENT_EPOCH=$(cast block-number --rpc-url $ETH_RPC_URL) + +# Add desired notice period (e.g., 2 days = ~5760 epochs) +AFTER_EPOCH=$((CURRENT_EPOCH + 5760)) + +echo "Current: $CURRENT_EPOCH, Upgrade after: $AFTER_EPOCH" +``` + +**Considerations:** +- Allow time for stakeholder review +- Avoid weekends/holidays for mainnet upgrades +- Calibnet can use shorter notice periods for testing + +## Release Workflow + +### Before the Upgrade + +1. **Prepare changelog entry** in `CHANGELOG.md`: + - Document all changes since last release + - Mark breaking changes clearly + - Include migration notes if needed + +2. **Create PR** with changelog updates + +3. **Deploy new implementation** contract: + - Run the deployment script (see [FWSS Upgrade Workflow](#fwss-upgrade-workflow)) + - `deployments.json` is automatically updated by the script + - **Document the new implementation address in PR comments** for traceability + - Commit the updated `deployments.json` to the PR + +4. **Run upgrade announcement** on-chain via `announce-planned-upgrade.sh` + +5. **Create tracking issue** using the [Create Upgrade Announcement](https://github.com/FilOzone/filecoin-services/actions/workflows/upgrade-announcement.yml) GitHub Action + +### After Successful Upgrade + +1. **Verify** the upgrade on block explorer (Blockscout) + +2. **Confirm** `deployments.json` was updated (automatic via script) + +3. **Merge** the changelog PR + +4. **Tag release** in GitHub (post-upgrade): + ```bash + git tag v1.X.0 + git push origin v1.X.0 + ``` + +5. **Create GitHub Release** pointing to: + - Changelog entry + - `deployments.json` for current addresses + ## Stakeholder Communication From a79de374e79f3b70fed8ce445da65f0c2d6eabca Mon Sep 17 00:00:00 2001 From: Phi Date: Thu, 15 Jan 2026 16:45:06 +0100 Subject: [PATCH 03/32] fix: wording in two-step upgrade fix: wording in two-step upgrade --- service_contracts/tools/UPGRADE-PROCESS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/service_contracts/tools/UPGRADE-PROCESS.md b/service_contracts/tools/UPGRADE-PROCESS.md index 536ccfc9..f05a6239 100644 --- a/service_contracts/tools/UPGRADE-PROCESS.md +++ b/service_contracts/tools/UPGRADE-PROCESS.md @@ -37,7 +37,7 @@ These immutable contracts are **not expected to be redeployed** under normal ope ## Two-Step Upgrade Process -Both FWSS and ServiceProviderRegistry use a security-focused two-step upgrade mechanism: +Both FWSS and ServiceProviderRegistry use a two-step upgrade mechanism: 1. **Announce** - Call `announcePlannedUpgrade()` with the new implementation address and `AFTER_EPOCH` 2. **Execute** - After `AFTER_EPOCH` has passed, call `upgradeToAndCall()` to complete the upgrade From 608d91e6df4740dbcbe729112b4d903c317a842c Mon Sep 17 00:00:00 2001 From: Phi Date: Fri, 16 Jan 2026 09:10:34 +0100 Subject: [PATCH 04/32] chore: remove thousands seperator --- service_contracts/tools/UPGRADE-PROCESS.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/service_contracts/tools/UPGRADE-PROCESS.md b/service_contracts/tools/UPGRADE-PROCESS.md index f05a6239..1b9c31b9 100644 --- a/service_contracts/tools/UPGRADE-PROCESS.md +++ b/service_contracts/tools/UPGRADE-PROCESS.md @@ -50,9 +50,9 @@ When announcing an upgrade, choose `AFTER_EPOCH` to give stakeholders adequate n | Upgrade Type | Minimum Notice | Recommended | |--------------|----------------|-------------| -| Routine (bug fixes, minor features) | ~24 hours (~2,880 epochs) | 1-2 days | -| Breaking changes | ~1 week (~20,160 epochs) | 1-2 weeks | -| Immutable dependency changes | ~2 weeks (~40,320 epochs) | 2-4 weeks | +| Routine (bug fixes, minor features) | ~24 hours (~2880 epochs) | 1-2 days | +| Breaking changes | ~1 week (~20160 epochs) | 1-2 weeks | +| Immutable dependency changes | ~2 weeks (~40320 epochs) | 2-4 weeks | **To calculate:** From cbc7641cb2d8f88b1d7a02fbd7f7e623a99b5a7e Mon Sep 17 00:00:00 2001 From: Phi Date: Fri, 16 Jan 2026 09:46:43 +0100 Subject: [PATCH 05/32] chore: re-ordering upgrade processa chore: re-ordering upgrade processa --- service_contracts/tools/UPGRADE-PROCESS.md | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/service_contracts/tools/UPGRADE-PROCESS.md b/service_contracts/tools/UPGRADE-PROCESS.md index 1b9c31b9..469c5e18 100644 --- a/service_contracts/tools/UPGRADE-PROCESS.md +++ b/service_contracts/tools/UPGRADE-PROCESS.md @@ -57,13 +57,7 @@ When announcing an upgrade, choose `AFTER_EPOCH` to give stakeholders adequate n **To calculate:** ```bash -# Get current epoch -CURRENT_EPOCH=$(cast block-number --rpc-url $ETH_RPC_URL) - -# Add desired notice period (e.g., 2 days = ~5760 epochs) -AFTER_EPOCH=$((CURRENT_EPOCH + 5760)) - -echo "Current: $CURRENT_EPOCH, Upgrade after: $AFTER_EPOCH" +CURRENT_EPOCH=$(cast block-number --rpc-url "$ETH_RPC_URL"); AFTER_EPOCH=$((CURRENT_EPOCH + 5760)); echo "Current: $CURRENT_EPOCH, Upgrade after: $AFTER_EPOCH" ``` **Considerations:** @@ -71,26 +65,26 @@ echo "Current: $CURRENT_EPOCH, Upgrade after: $AFTER_EPOCH" - Avoid weekends/holidays for mainnet upgrades - Calibnet can use shorter notice periods for testing -## Release Workflow +## Pre-Upgrade Checklist ### Before the Upgrade 1. **Prepare changelog entry** in `CHANGELOG.md`: - - Document all changes since last release + - Document all changes since last release (https://github.com/FilOzone/filecoin-services/releases) - Mark breaking changes clearly - Include migration notes if needed 2. **Create PR** with changelog updates -3. **Deploy new implementation** contract: +3. **Create tracking issue** using the [Create Upgrade Announcement](https://github.com/FilOzone/filecoin-services/actions/workflows/upgrade-announcement.yml) GitHub Action + +4. **Deploy new implementation** contract: - Run the deployment script (see [FWSS Upgrade Workflow](#fwss-upgrade-workflow)) - `deployments.json` is automatically updated by the script - **Document the new implementation address in PR comments** for traceability - Commit the updated `deployments.json` to the PR -4. **Run upgrade announcement** on-chain via `announce-planned-upgrade.sh` - -5. **Create tracking issue** using the [Create Upgrade Announcement](https://github.com/FilOzone/filecoin-services/actions/workflows/upgrade-announcement.yml) GitHub Action +5. **Run upgrade announcement** on-chain via `announce-planned-upgrade.sh` ### After Successful Upgrade From 33f824f958cfc5caf8e58c01c716762ee47f942d Mon Sep 17 00:00:00 2001 From: Phi Date: Fri, 16 Jan 2026 09:55:31 +0100 Subject: [PATCH 06/32] chore: bump FWSS-version and ServiceProviderRegistry chore: bump FWSS-version and ServiceProviderRegistry --- service_contracts/src/FilecoinWarmStorageService.sol | 2 +- service_contracts/src/ServiceProviderRegistry.sol | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/service_contracts/src/FilecoinWarmStorageService.sol b/service_contracts/src/FilecoinWarmStorageService.sol index 947aac14..f9340ecb 100644 --- a/service_contracts/src/FilecoinWarmStorageService.sol +++ b/service_contracts/src/FilecoinWarmStorageService.sol @@ -60,7 +60,7 @@ contract FilecoinWarmStorageService is EIP712Upgradeable { // Version tracking - string public constant VERSION = "1.0.0"; + string public constant VERSION = "1.1.0"; // ========================================================================= // Events diff --git a/service_contracts/src/ServiceProviderRegistry.sol b/service_contracts/src/ServiceProviderRegistry.sol index b0cc214c..c658e71c 100644 --- a/service_contracts/src/ServiceProviderRegistry.sol +++ b/service_contracts/src/ServiceProviderRegistry.sol @@ -43,7 +43,7 @@ contract ServiceProviderRegistry is } /// @notice Version of the contract implementation - string public constant VERSION = "1.0.0"; + string public constant VERSION = "1.1.0"; /// @notice Maximum length for service URL uint256 private constant MAX_SERVICE_URL_LENGTH = 256; From 20a168de9541d0b2ee4db132ced1a8ac49656070 Mon Sep 17 00:00:00 2001 From: Phi Date: Fri, 16 Jan 2026 10:08:33 +0100 Subject: [PATCH 07/32] chore: update upgrade announcement workflow to include changelog PR input --- .github/workflows/upgrade-announcement.yml | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/.github/workflows/upgrade-announcement.yml b/.github/workflows/upgrade-announcement.yml index 100dc874..521a5b8c 100644 --- a/.github/workflows/upgrade-announcement.yml +++ b/.github/workflows/upgrade-announcement.yml @@ -29,8 +29,8 @@ on: description: 'AFTER_EPOCH (block number after which upgrade can execute)' required: true type: string - new_implementation_address: - description: 'New implementation contract address' + changelog_pr: + description: 'PR number with changelog updates' required: true type: string changes_summary: @@ -105,7 +105,7 @@ jobs: const upgradeType = '${{ inputs.upgrade_type }}'; const contract = '${{ inputs.contract }}'; const afterEpoch = '${{ inputs.after_epoch }}'; - const implAddress = '${{ inputs.new_implementation_address }}'; + const changelogPr = '${{ inputs.changelog_pr }}'; const releaseTag = '${{ inputs.release_tag }}'; const actionRequired = '${{ inputs.action_required }}' || 'None'; const timeEstimate = `${{ steps.calc_time.outputs.estimate }}`; @@ -116,6 +116,7 @@ jobs: : null; const changelogLink = `https://github.com/${context.repo.owner}/${context.repo.repo}/blob/main/CHANGELOG.md`; + const changelogPrLink = `https://github.com/${context.repo.owner}/${context.repo.repo}/pull/${changelogPr}`; const body = `## ${contract} Upgrade Announcement @@ -124,11 +125,9 @@ jobs: **Scheduled Execution**: After epoch ${afterEpoch} (${timeEstimate}) ### Changes + - Changelog PR: ${changelogPrLink} ${changes} - ### New Implementation Address - \`${implAddress}\` - ### Action Required ${actionRequired} @@ -140,7 +139,7 @@ jobs: --- ### Checklist - - [ ] New implementation deployed (address above) + - [ ] New implementation deployed (address shared) - [ ] Upgrade announced on-chain via \`announce-planned-upgrade.sh\` - [ ] Stakeholders notified - [ ] Upgrade executed after AFTER_EPOCH From f15a275ceb24c03eb6f6ef74c4028d9b046fb074 Mon Sep 17 00:00:00 2001 From: Phi Date: Fri, 16 Jan 2026 10:18:56 +0100 Subject: [PATCH 08/32] chore: remove action required input and changelog link from upgrade announcement workflow --- .github/workflows/upgrade-announcement.yml | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/.github/workflows/upgrade-announcement.yml b/.github/workflows/upgrade-announcement.yml index 521a5b8c..631a6052 100644 --- a/.github/workflows/upgrade-announcement.yml +++ b/.github/workflows/upgrade-announcement.yml @@ -41,10 +41,6 @@ on: description: 'Release tag if already created (usually added after upgrade completes)' required: false type: string - action_required: - description: 'Action required by integrators (leave empty if none)' - required: false - type: string jobs: create-announcement: @@ -107,7 +103,6 @@ jobs: const afterEpoch = '${{ inputs.after_epoch }}'; const changelogPr = '${{ inputs.changelog_pr }}'; const releaseTag = '${{ inputs.release_tag }}'; - const actionRequired = '${{ inputs.action_required }}' || 'None'; const timeEstimate = `${{ steps.calc_time.outputs.estimate }}`; const changes = `${{ steps.format_changes.outputs.changes }}`; @@ -115,7 +110,6 @@ jobs: ? `https://github.com/${context.repo.owner}/${context.repo.repo}/releases/tag/${releaseTag}` : null; - const changelogLink = `https://github.com/${context.repo.owner}/${context.repo.repo}/blob/main/CHANGELOG.md`; const changelogPrLink = `https://github.com/${context.repo.owner}/${context.repo.repo}/pull/${changelogPr}`; const body = `## ${contract} Upgrade Announcement @@ -128,12 +122,8 @@ jobs: - Changelog PR: ${changelogPrLink} ${changes} - ### Action Required - ${actionRequired} - ### Resources ${releaseLink ? `- Release: ${releaseLink}` : ''} - - Changelog: ${changelogLink} - Upgrade Process: [UPGRADE-PROCESS.md](https://github.com/${context.repo.owner}/${context.repo.repo}/blob/main/service_contracts/tools/UPGRADE-PROCESS.md) --- From 4b0253f1abaaefacaf093167c60d9637ae4e6f7e Mon Sep 17 00:00:00 2001 From: Phi Date: Fri, 16 Jan 2026 15:39:47 +0100 Subject: [PATCH 09/32] feat: enhance deploy-registry-calibnet.sh with proxy deployment option --- service_contracts/tools/UPGRADE-PROCESS.md | 18 +- .../tools/deploy-registry-calibnet.sh | 172 +++++++++++------- 2 files changed, 121 insertions(+), 69 deletions(-) diff --git a/service_contracts/tools/UPGRADE-PROCESS.md b/service_contracts/tools/UPGRADE-PROCESS.md index 469c5e18..c8b5ee64 100644 --- a/service_contracts/tools/UPGRADE-PROCESS.md +++ b/service_contracts/tools/UPGRADE-PROCESS.md @@ -114,9 +114,9 @@ CURRENT_EPOCH=$(cast block-number --rpc-url "$ETH_RPC_URL"); AFTER_EPOCH=$((CURR Before running `announce-planned-upgrade.sh`, notify stakeholders through: -- [ ] **Slack**: Post in `#` with upgrade details +- [ ] **Documentation**: Update changelog with upcoming changes in a PR - [ ] **GitHub**: Create a tracking issue or discussion for the upgrade -- [ ] **Documentation**: Update changelog with upcoming changes +- [ ] **Slack**: Post in `#` with upgrade details ### Upgrade Announcement Template @@ -234,6 +234,20 @@ The script automatically: Similar to FWSS, but uses dedicated scripts: +### Deploy New Registry Implementation (Calibnet) + +Use the deploy script in upgrade-first mode (implementation-only). This is the default: + +```bash +./deploy-registry-calibnet.sh +``` + +To deploy a new proxy as well (fresh deployment), pass the flag: + +```bash +./deploy-registry-calibnet.sh --with-proxy +``` + ### Announce ```bash diff --git a/service_contracts/tools/deploy-registry-calibnet.sh b/service_contracts/tools/deploy-registry-calibnet.sh index a48868cd..23aef26d 100755 --- a/service_contracts/tools/deploy-registry-calibnet.sh +++ b/service_contracts/tools/deploy-registry-calibnet.sh @@ -14,6 +14,33 @@ echo "Deploying Service Provider Registry Contract" export CHAIN=314159 +WITH_PROXY=false +for arg in "$@"; do + case "$arg" in + --with-proxy) + WITH_PROXY=true + ;; + -h|--help) + echo "Usage: $(basename "$0") [--with-proxy]" + echo "" + echo "Default: deploy implementation only (upgrade-first)." + echo " --with-proxy Also deploy a new proxy and initialize it." + exit 0 + ;; + *) + echo "Error: Unknown option '$arg'" + echo "Run with --help for usage." + exit 1 + ;; + esac +done + +if [ "$WITH_PROXY" = "true" ]; then + echo "Mode: implementation + proxy deployment" +else + echo "Mode: implementation-only deployment (upgrade-first)" +fi + # Load deployment addresses from deployments.json load_deployment_addresses "$CHAIN" @@ -54,60 +81,62 @@ fi echo "✓ ServiceProviderRegistry implementation deployed at: $SERVICE_PROVIDER_REGISTRY_IMPLEMENTATION_ADDRESS" NONCE=$(expr $NONCE + "1") -# Deploy ServiceProviderRegistry proxy -echo "" -echo "=== STEP 2: Deploying ServiceProviderRegistry Proxy ===" -# Initialize with no parameters for basic initialization -INIT_DATA=$(cast calldata "initialize()") -echo "Initialization calldata: $INIT_DATA" - -REGISTRY_PROXY_ADDRESS=$(forge create --password "$PASSWORD" --broadcast --nonce $NONCE lib/pdp/src/ERC1967Proxy.sol:MyERC1967Proxy --constructor-args $SERVICE_PROVIDER_REGISTRY_IMPLEMENTATION_ADDRESS $INIT_DATA --optimizer-runs 1 --via-ir | grep "Deployed to" | awk '{print $3}') -if [ -z "$REGISTRY_PROXY_ADDRESS" ]; then - echo "Error: Failed to extract ServiceProviderRegistry proxy address" - exit 1 -fi -echo "✓ ServiceProviderRegistry proxy deployed at: $REGISTRY_PROXY_ADDRESS" - -# Verify deployment by calling version() on the proxy -echo "" -echo "=== STEP 3: Verifying Deployment ===" -VERSION=$(cast call $REGISTRY_PROXY_ADDRESS "version()(string)") -if [ -z "$VERSION" ]; then - echo "Warning: Could not verify contract version" -else - echo "✓ Contract version: $VERSION" -fi - -# Get registration fee -FEE=$(cast call $REGISTRY_PROXY_ADDRESS "REGISTRATION_FEE()(uint256)") -if [ -z "$FEE" ]; then - echo "Warning: Could not retrieve registration fee" - FEE_IN_FIL="unknown" +if [ "$WITH_PROXY" = "true" ]; then + # Deploy ServiceProviderRegistry proxy + echo "" + echo "=== STEP 2: Deploying ServiceProviderRegistry Proxy ===" + # Initialize with no parameters for basic initialization + INIT_DATA=$(cast calldata "initialize()") + echo "Initialization calldata: $INIT_DATA" + + REGISTRY_PROXY_ADDRESS=$(forge create --password "$PASSWORD" --broadcast --nonce $NONCE lib/pdp/src/ERC1967Proxy.sol:MyERC1967Proxy --constructor-args $SERVICE_PROVIDER_REGISTRY_IMPLEMENTATION_ADDRESS $INIT_DATA --optimizer-runs 1 --via-ir | grep "Deployed to" | awk '{print $3}') + if [ -z "$REGISTRY_PROXY_ADDRESS" ]; then + echo "Error: Failed to extract ServiceProviderRegistry proxy address" + exit 1 + fi + echo "✓ ServiceProviderRegistry proxy deployed at: $REGISTRY_PROXY_ADDRESS" + + # Verify deployment by calling version() on the proxy + echo "" + echo "=== STEP 3: Verifying Deployment ===" + VERSION=$(cast call $REGISTRY_PROXY_ADDRESS "version()(string)") + if [ -z "$VERSION" ]; then + echo "Warning: Could not verify contract version" + else + echo "✓ Contract version: $VERSION" + fi + + # Get registration fee + FEE=$(cast call $REGISTRY_PROXY_ADDRESS "REGISTRATION_FEE()(uint256)") + if [ -z "$FEE" ]; then + echo "Warning: Could not retrieve registration fee" + FEE_IN_FIL="unknown" + else + echo "✓ Registration fee: $FEE attoFIL" + FEE_IN_FIL="$FEE attoFIL" + fi + + # Get burn actor address + BURN_ACTOR=$(cast call $REGISTRY_PROXY_ADDRESS "BURN_ACTOR()(address)") + if [ -z "$BURN_ACTOR" ]; then + echo "Warning: Could not retrieve burn actor address" + else + echo "✓ Burn actor address: $BURN_ACTOR" + fi + + # Get contract version (this should be used instead of hardcoded version) + CONTRACT_VERSION=$(cast call $REGISTRY_PROXY_ADDRESS "VERSION()(string)") + if [ -z "$CONTRACT_VERSION" ]; then + echo "Warning: Could not retrieve contract version" + CONTRACT_VERSION="Unknown" + fi else - echo "✓ Registration fee: $FEE attoFIL" - FEE_IN_FIL="$FEE attoFIL" -fi - -# Get burn actor address -BURN_ACTOR=$(cast call $REGISTRY_PROXY_ADDRESS "BURN_ACTOR()(address)") -if [ -z "$BURN_ACTOR" ]; then - echo "Warning: Could not retrieve burn actor address" -else - echo "✓ Burn actor address: $BURN_ACTOR" -fi - -# Get contract version (this should be used instead of hardcoded version) -CONTRACT_VERSION=$(cast call $REGISTRY_PROXY_ADDRESS "VERSION()(string)") -if [ -z "$CONTRACT_VERSION" ]; then - echo "Warning: Could not retrieve contract version" - CONTRACT_VERSION="Unknown" -fi - -# Get contract version (this should be used instead of hardcoded version) -CONTRACT_VERSION=$(cast call $REGISTRY_PROXY_ADDRESS "VERSION()(string)") -if [ -z "$CONTRACT_VERSION" ]; then - echo "Warning: Could not retrieve contract version" - CONTRACT_VERSION="Unknown" + echo "" + echo "=== STEP 2: Skipping Proxy Deployment ===" + echo "Use --with-proxy to deploy and initialize a new proxy." + CONTRACT_VERSION="n/a" + FEE_IN_FIL="n/a" + BURN_ACTOR="n/a" fi # Summary of deployed contracts @@ -116,14 +145,16 @@ echo "==========================================" echo "=== DEPLOYMENT SUMMARY ===" echo "==========================================" echo "ServiceProviderRegistry Implementation: $SERVICE_PROVIDER_REGISTRY_IMPLEMENTATION_ADDRESS" -echo "ServiceProviderRegistry Proxy: $REGISTRY_PROXY_ADDRESS" +if [ "$WITH_PROXY" = "true" ]; then + echo "ServiceProviderRegistry Proxy: $REGISTRY_PROXY_ADDRESS" +fi echo "==========================================" # Update deployments.json if [ -n "$SERVICE_PROVIDER_REGISTRY_IMPLEMENTATION_ADDRESS" ]; then update_deployment_address "$CHAIN" "SERVICE_PROVIDER_REGISTRY_IMPLEMENTATION_ADDRESS" "$SERVICE_PROVIDER_REGISTRY_IMPLEMENTATION_ADDRESS" fi -if [ -n "$REGISTRY_PROXY_ADDRESS" ]; then +if [ "$WITH_PROXY" = "true" ] && [ -n "$REGISTRY_PROXY_ADDRESS" ]; then update_deployment_address "$CHAIN" "SERVICE_PROVIDER_REGISTRY_PROXY_ADDRESS" "$REGISTRY_PROXY_ADDRESS" fi if [ -n "$SERVICE_PROVIDER_REGISTRY_IMPLEMENTATION_ADDRESS" ] || [ -n "$REGISTRY_PROXY_ADDRESS" ]; then @@ -137,19 +168,26 @@ echo " - Burn Actor: $BURN_ACTOR" echo " - Chain: Calibration testnet (314159)" echo "" echo "Next steps:" -echo "1. Save the proxy address: export REGISTRY_ADDRESS=$REGISTRY_PROXY_ADDRESS" -echo "2. Verify the deployment by calling getProviderCount() - should return 0" -echo "3. Test registration with: cast send --value attoFIL ..." -echo "4. Transfer ownership if needed using transferOwnership()" -echo "5. The registry is ready for provider registrations" -echo "" -echo "To interact with the registry:" -echo " View functions:" -echo " cast call $REGISTRY_PROXY_ADDRESS \"getProviderCount()(uint256)\"" -echo " cast call $REGISTRY_PROXY_ADDRESS \"getAllActiveProviders()(uint256[])\"" -echo " State changes (requires registration fee):" -echo " Register as provider (requires proper encoding of PDPData)" +if [ "$WITH_PROXY" = "true" ]; then + echo "1. Save the proxy address: export REGISTRY_ADDRESS=$REGISTRY_PROXY_ADDRESS" + echo "2. Verify the deployment by calling getProviderCount() - should return 0" + echo "3. Test registration with: cast send --value attoFIL ..." + echo "4. Transfer ownership if needed using transferOwnership()" + echo "5. The registry is ready for provider registrations" +else + echo "1. Save the implementation address for upgrade announcement" + echo "2. Proceed with announce-planned-upgrade-registry.sh" +fi echo "" +if [ "$WITH_PROXY" = "true" ]; then + echo "To interact with the registry:" + echo " View functions:" + echo " cast call $REGISTRY_PROXY_ADDRESS \"getProviderCount()(uint256)\"" + echo " cast call $REGISTRY_PROXY_ADDRESS \"getAllActiveProviders()(uint256[])\"" + echo " State changes (requires registration fee):" + echo " Register as provider (requires proper encoding of PDPData)" + echo "" +fi # Automatic contract verification if [ "${AUTO_VERIFY:-true}" = "true" ]; then From 25ec0bfe87de9d16514b17bbecd4bfc21b5f15e7 Mon Sep 17 00:00:00 2001 From: Phi Date: Tue, 20 Jan 2026 08:40:15 +0100 Subject: [PATCH 10/32] feat: enhance deploy-warm-storage-implementation-only.sh to load defaults and persist deployment metadata --- service_contracts/tools/README.md | 1 + .../deploy-warm-storage-implementation-only.sh | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/service_contracts/tools/README.md b/service_contracts/tools/README.md index 1aab5440..7bcb685b 100644 --- a/service_contracts/tools/README.md +++ b/service_contracts/tools/README.md @@ -9,6 +9,7 @@ This directory contains scripts for deploying and upgrading the FilecoinWarmStor ### Deployment Scripts - `deploy-warm-storage-calibnet.sh` - Deploy FilecoinWarmStorageService only (requires existing PDPVerifier and FilecoinPayV1 contracts) +- `deploy-warm-storage-implementation-only.sh` - Deploy FWSS implementation only; loads defaults from `deployments.json` and writes back new implementation + metadata (reuses existing signature lib unless redeployed) - `deploy-all-warm-storage.sh` - Deploy all contracts to either Calibnet or Mainnet ### Upgrade Scripts diff --git a/service_contracts/tools/deploy-warm-storage-implementation-only.sh b/service_contracts/tools/deploy-warm-storage-implementation-only.sh index 27df2a3b..551fa8e2 100755 --- a/service_contracts/tools/deploy-warm-storage-implementation-only.sh +++ b/service_contracts/tools/deploy-warm-storage-implementation-only.sh @@ -24,6 +24,10 @@ if [ -z "$CHAIN" ]; then fi fi +# Load deployments.json helpers and populate defaults if available +source "$(dirname "$0")/deployments.sh" +load_deployment_addresses "$CHAIN" + if [ -z "$ETH_KEYSTORE" ]; then echo "Error: ETH_KEYSTORE is not set" @@ -67,6 +71,7 @@ fi USDFC_TOKEN_ADDRESS="0xb3042734b608a1B16e9e86B374A3f3e389B4cDf0" # USDFC token address on calibnet +SIGNATURE_LIB_DEPLOYED=false if [ -z "$SIGNATURE_VERIFICATION_LIB_ADDRESS" ]; then # Deploy SignatureVerificationLib first so we can link it into the implementation echo "Deploying SignatureVerificationLib..." @@ -77,6 +82,7 @@ if [ -z "$SIGNATURE_VERIFICATION_LIB_ADDRESS" ]; then exit 1 fi echo "SignatureVerificationLib deployed at: $SIGNATURE_VERIFICATION_LIB_ADDRESS" + SIGNATURE_LIB_DEPLOYED=true # Increment nonce for the next deployment NONCE=$((NONCE + 1)) else @@ -112,6 +118,13 @@ echo "SignatureVerificationLib deployed at: $SIGNATURE_VERIFICATION_LIB_ADDRESS" echo "FilecoinWarmStorageService Implementation deployed at: $FWSS_IMPLEMENTATION_ADDRESS" echo "" +# Persist deployment addresses + metadata +update_deployment_address "$CHAIN" "FWSS_IMPLEMENTATION_ADDRESS" "$FWSS_IMPLEMENTATION_ADDRESS" +if [ "$SIGNATURE_LIB_DEPLOYED" = "true" ]; then + update_deployment_address "$CHAIN" "SIGNATURE_VERIFICATION_LIB_ADDRESS" "$SIGNATURE_VERIFICATION_LIB_ADDRESS" +fi +update_deployment_metadata "$CHAIN" + # Automatic contract verification if [ "${AUTO_VERIFY:-true}" = "true" ]; then echo From d49a18a560a2445ff6ca2e02eefc9e2848a6db97 Mon Sep 17 00:00:00 2001 From: Phi Date: Wed, 21 Jan 2026 08:39:27 +0100 Subject: [PATCH 11/32] feat: enhance warm storage view scripts to load deployment defaults and persist metadata --- service_contracts/tools/deploy-warm-storage-view.sh | 9 +++++++++ service_contracts/tools/set-warm-storage-view.sh | 7 +++++++ 2 files changed, 16 insertions(+) diff --git a/service_contracts/tools/deploy-warm-storage-view.sh b/service_contracts/tools/deploy-warm-storage-view.sh index 5db5b7ef..f25abb6a 100755 --- a/service_contracts/tools/deploy-warm-storage-view.sh +++ b/service_contracts/tools/deploy-warm-storage-view.sh @@ -24,6 +24,11 @@ if [ -z "$CHAIN" ]; then fi fi +# Load deployments.json helpers and populate defaults if available +SCRIPT_DIR="$(dirname "${BASH_SOURCE[0]}")" +source "$SCRIPT_DIR/deployments.sh" +load_deployment_addresses "$CHAIN" + if [ -z "$FWSS_PROXY_ADDRESS" ]; then echo "Error: FWSS_PROXY_ADDRESS is not set" exit 1 @@ -47,6 +52,10 @@ export FWSS_VIEW_ADDRESS=$(forge create --password "$PASSWORD" --broadcast --non echo FilecoinWarmStorageServiceStateView deployed at $FWSS_VIEW_ADDRESS +# Persist deployment address + metadata +update_deployment_address "$CHAIN" "FWSS_VIEW_ADDRESS" "$FWSS_VIEW_ADDRESS" +update_deployment_metadata "$CHAIN" + # Automatic contract verification if [ "${AUTO_VERIFY:-true}" = "true" ]; then echo diff --git a/service_contracts/tools/set-warm-storage-view.sh b/service_contracts/tools/set-warm-storage-view.sh index 01c6efdf..35484d88 100755 --- a/service_contracts/tools/set-warm-storage-view.sh +++ b/service_contracts/tools/set-warm-storage-view.sh @@ -25,6 +25,11 @@ if [ -z "$CHAIN" ]; then fi fi +# Load deployments.json helpers and populate defaults if available +SCRIPT_DIR="$(dirname "${BASH_SOURCE[0]}")" +source "$SCRIPT_DIR/deployments.sh" +load_deployment_addresses "$CHAIN" + if [ -z "$FWSS_PROXY_ADDRESS" ]; then echo "Error: FWSS_PROXY_ADDRESS is not set" exit 1 @@ -55,6 +60,8 @@ TX_OUTPUT=$(cast send --password "$PASSWORD" --nonce $NONCE $FWSS_PROXY_ADDRESS if [ $? -eq 0 ]; then echo "View contract address set successfully" + update_deployment_address "$CHAIN" "FWSS_VIEW_ADDRESS" "$FWSS_VIEW_ADDRESS" + update_deployment_metadata "$CHAIN" else echo "Error: Failed to set view contract address" echo "$TX_OUTPUT" From d8b9b6dc78016412ad9488a8f1d51f4f61764cf7 Mon Sep 17 00:00:00 2001 From: Phi Date: Wed, 21 Jan 2026 11:00:10 +0100 Subject: [PATCH 12/32] refactor: enhance deploy-registry-calibnet.sh for better network compatibility and chain ID handling refactor: enhance deploy-registry-calibnet.sh for better network compatibility and chain ID handling --- service_contracts/tools/UPGRADE-PROCESS.md | 4 +- .../tools/deploy-registry-calibnet.sh | 31 ++- service_contracts/tools/deploy-registry.sh | 219 ++++++++++++++++++ 3 files changed, 244 insertions(+), 10 deletions(-) mode change 100755 => 100644 service_contracts/tools/deploy-registry-calibnet.sh create mode 100755 service_contracts/tools/deploy-registry.sh diff --git a/service_contracts/tools/UPGRADE-PROCESS.md b/service_contracts/tools/UPGRADE-PROCESS.md index c8b5ee64..a75e6ed3 100644 --- a/service_contracts/tools/UPGRADE-PROCESS.md +++ b/service_contracts/tools/UPGRADE-PROCESS.md @@ -239,13 +239,13 @@ Similar to FWSS, but uses dedicated scripts: Use the deploy script in upgrade-first mode (implementation-only). This is the default: ```bash -./deploy-registry-calibnet.sh +./deploy-registry.sh ``` To deploy a new proxy as well (fresh deployment), pass the flag: ```bash -./deploy-registry-calibnet.sh --with-proxy +./deploy-registry.sh --with-proxy ``` ### Announce diff --git a/service_contracts/tools/deploy-registry-calibnet.sh b/service_contracts/tools/deploy-registry-calibnet.sh old mode 100755 new mode 100644 index 23aef26d..f9cc5171 --- a/service_contracts/tools/deploy-registry-calibnet.sh +++ b/service_contracts/tools/deploy-registry-calibnet.sh @@ -1,7 +1,7 @@ #!/bin/bash -# deploy-registry-calibnet deploys the Service Provider Registry contract to calibration net +# deploy-registry-calibnet deploys the Service Provider Registry contract to a target network # Assumption: ETH_KEYSTORE, PASSWORD, ETH_RPC_URL env vars are set to an appropriate eth keystore path and password -# and to a valid ETH_RPC_URL for the calibnet. +# and to a valid ETH_RPC_URL for the target network. # Assumption: forge, cast, jq are in the PATH # Assumption: called from contracts directory so forge paths work out # @@ -12,8 +12,6 @@ source "$SCRIPT_DIR/deployments.sh" echo "Deploying Service Provider Registry Contract" -export CHAIN=314159 - WITH_PROXY=false for arg in "$@"; do case "$arg" in @@ -41,14 +39,23 @@ else echo "Mode: implementation-only deployment (upgrade-first)" fi -# Load deployment addresses from deployments.json -load_deployment_addresses "$CHAIN" - if [ -z "$ETH_RPC_URL" ]; then echo "Error: ETH_RPC_URL is not set" exit 1 fi +# Auto-detect chain ID from RPC if not already set +if [ -z "$CHAIN" ]; then + export CHAIN=$(cast chain-id) + if [ -z "$CHAIN" ]; then + echo "Error: Failed to detect chain ID from RPC" + exit 1 + fi +fi + +# Load deployment addresses from deployments.json +load_deployment_addresses "$CHAIN" + if [ -z "$ETH_KEYSTORE" ]; then echo "Error: ETH_KEYSTORE is not set" exit 1 @@ -165,7 +172,15 @@ echo "Contract Details:" echo " - Version: $CONTRACT_VERSION" echo " - Registration Fee: $FEE_IN_FIL (burned)" echo " - Burn Actor: $BURN_ACTOR" -echo " - Chain: Calibration testnet (314159)" +CHAIN_LABEL="unknown" +if [ "$CHAIN" = "314159" ]; then + CHAIN_LABEL="Calibration testnet (314159)" +elif [ "$CHAIN" = "314" ]; then + CHAIN_LABEL="Filecoin mainnet (314)" +else + CHAIN_LABEL="Chain ID $CHAIN" +fi +echo " - Chain: $CHAIN_LABEL" echo "" echo "Next steps:" if [ "$WITH_PROXY" = "true" ]; then diff --git a/service_contracts/tools/deploy-registry.sh b/service_contracts/tools/deploy-registry.sh new file mode 100755 index 00000000..259a45cc --- /dev/null +++ b/service_contracts/tools/deploy-registry.sh @@ -0,0 +1,219 @@ +#!/bin/bash +# deploy-registry deploys the Service Provider Registry contract to a target network +# Assumption: ETH_KEYSTORE, PASSWORD, ETH_RPC_URL env vars are set to an appropriate eth keystore path and password +# and to a valid ETH_RPC_URL for the target network. +# Assumption: forge, cast, jq are in the PATH +# Assumption: called from contracts directory so forge paths work out +# + +# Get script directory and source deployments.sh +SCRIPT_DIR="$(dirname "${BASH_SOURCE[0]}")" +source "$SCRIPT_DIR/deployments.sh" + +echo "Deploying Service Provider Registry Contract" + +WITH_PROXY=false +for arg in "$@"; do + case "$arg" in + --with-proxy) + WITH_PROXY=true + ;; + -h|--help) + echo "Usage: $(basename "$0") [--with-proxy]" + echo "" + echo "Default: deploy implementation only (upgrade-first)." + echo " --with-proxy Also deploy a new proxy and initialize it." + exit 0 + ;; + *) + echo "Error: Unknown option '$arg'" + echo "Run with --help for usage." + exit 1 + ;; + esac +done + +if [ "$WITH_PROXY" = "true" ]; then + echo "Mode: implementation + proxy deployment" +else + echo "Mode: implementation-only deployment (upgrade-first)" +fi + +if [ -z "$ETH_RPC_URL" ]; then + echo "Error: ETH_RPC_URL is not set" + exit 1 +fi + +# Auto-detect chain ID from RPC if not already set +if [ -z "$CHAIN" ]; then + export CHAIN=$(cast chain-id) + if [ -z "$CHAIN" ]; then + echo "Error: Failed to detect chain ID from RPC" + exit 1 + fi +fi + +# Load deployment addresses from deployments.json +load_deployment_addresses "$CHAIN" + +if [ -z "$ETH_KEYSTORE" ]; then + echo "Error: ETH_KEYSTORE is not set" + exit 1 +fi + +# Optional: Check if PASSWORD is set (some users might use empty password) +if [ -z "$PASSWORD" ]; then + echo "Warning: PASSWORD is not set, using empty password" +fi + +ADDR=$(cast wallet address --password "$PASSWORD") +echo "Deploying contracts from address $ADDR" + +# Get current balance and nonce (cast will use ETH_RPC_URL) +BALANCE=$(cast balance "$ADDR") +echo "Deployer balance: $BALANCE" + +NONCE="$(cast nonce "$ADDR")" +echo "Starting nonce: $NONCE" + +# Deploy ServiceProviderRegistry implementation +echo "" +echo "=== STEP 1: Deploying ServiceProviderRegistry Implementation ===" +SERVICE_PROVIDER_REGISTRY_IMPLEMENTATION_ADDRESS=$(forge create --password "$PASSWORD" --broadcast --nonce $NONCE src/ServiceProviderRegistry.sol:ServiceProviderRegistry --optimizer-runs 1 --via-ir | grep "Deployed to" | awk '{print $3}') +if [ -z "$SERVICE_PROVIDER_REGISTRY_IMPLEMENTATION_ADDRESS" ]; then + echo "Error: Failed to extract ServiceProviderRegistry implementation address" + exit 1 +fi +echo "✓ ServiceProviderRegistry implementation deployed at: $SERVICE_PROVIDER_REGISTRY_IMPLEMENTATION_ADDRESS" +NONCE=$(expr $NONCE + "1") + +if [ "$WITH_PROXY" = "true" ]; then + # Deploy ServiceProviderRegistry proxy + echo "" + echo "=== STEP 2: Deploying ServiceProviderRegistry Proxy ===" + # Initialize with no parameters for basic initialization + INIT_DATA=$(cast calldata "initialize()") + echo "Initialization calldata: $INIT_DATA" + + REGISTRY_PROXY_ADDRESS=$(forge create --password "$PASSWORD" --broadcast --nonce $NONCE lib/pdp/src/ERC1967Proxy.sol:MyERC1967Proxy --constructor-args $SERVICE_PROVIDER_REGISTRY_IMPLEMENTATION_ADDRESS $INIT_DATA --optimizer-runs 1 --via-ir | grep "Deployed to" | awk '{print $3}') + if [ -z "$REGISTRY_PROXY_ADDRESS" ]; then + echo "Error: Failed to extract ServiceProviderRegistry proxy address" + exit 1 + fi + echo "✓ ServiceProviderRegistry proxy deployed at: $REGISTRY_PROXY_ADDRESS" + + # Verify deployment by calling version() on the proxy + echo "" + echo "=== STEP 3: Verifying Deployment ===" + VERSION=$(cast call $REGISTRY_PROXY_ADDRESS "version()(string)") + if [ -z "$VERSION" ]; then + echo "Warning: Could not verify contract version" + else + echo "✓ Contract version: $VERSION" + fi + + # Get registration fee + FEE=$(cast call $REGISTRY_PROXY_ADDRESS "REGISTRATION_FEE()(uint256)") + if [ -z "$FEE" ]; then + echo "Warning: Could not retrieve registration fee" + FEE_IN_FIL="unknown" + else + echo "✓ Registration fee: $FEE attoFIL" + FEE_IN_FIL="$FEE attoFIL" + fi + + # Get burn actor address + BURN_ACTOR=$(cast call $REGISTRY_PROXY_ADDRESS "BURN_ACTOR()(address)") + if [ -z "$BURN_ACTOR" ]; then + echo "Warning: Could not retrieve burn actor address" + else + echo "✓ Burn actor address: $BURN_ACTOR" + fi + + # Get contract version (this should be used instead of hardcoded version) + CONTRACT_VERSION=$(cast call $REGISTRY_PROXY_ADDRESS "VERSION()(string)") + if [ -z "$CONTRACT_VERSION" ]; then + echo "Warning: Could not retrieve contract version" + CONTRACT_VERSION="Unknown" + fi +else + echo "" + echo "=== STEP 2: Skipping Proxy Deployment ===" + echo "Use --with-proxy to deploy and initialize a new proxy." + CONTRACT_VERSION="n/a" + FEE_IN_FIL="n/a" + BURN_ACTOR="n/a" +fi + +# Summary of deployed contracts +echo "" +echo "==========================================" +echo "=== DEPLOYMENT SUMMARY ===" +echo "==========================================" +echo "ServiceProviderRegistry Implementation: $SERVICE_PROVIDER_REGISTRY_IMPLEMENTATION_ADDRESS" +if [ "$WITH_PROXY" = "true" ]; then + echo "ServiceProviderRegistry Proxy: $REGISTRY_PROXY_ADDRESS" +fi +echo "==========================================" + +# Update deployments.json +if [ -n "$SERVICE_PROVIDER_REGISTRY_IMPLEMENTATION_ADDRESS" ]; then + update_deployment_address "$CHAIN" "SERVICE_PROVIDER_REGISTRY_IMPLEMENTATION_ADDRESS" "$SERVICE_PROVIDER_REGISTRY_IMPLEMENTATION_ADDRESS" +fi +if [ "$WITH_PROXY" = "true" ] && [ -n "$REGISTRY_PROXY_ADDRESS" ]; then + update_deployment_address "$CHAIN" "SERVICE_PROVIDER_REGISTRY_PROXY_ADDRESS" "$REGISTRY_PROXY_ADDRESS" +fi +if [ -n "$SERVICE_PROVIDER_REGISTRY_IMPLEMENTATION_ADDRESS" ] || [ -n "$REGISTRY_PROXY_ADDRESS" ]; then + update_deployment_metadata "$CHAIN" +fi +echo "" +echo "Contract Details:" +echo " - Version: $CONTRACT_VERSION" +echo " - Registration Fee: $FEE_IN_FIL (burned)" +echo " - Burn Actor: $BURN_ACTOR" +CHAIN_LABEL="unknown" +if [ "$CHAIN" = "314159" ]; then + CHAIN_LABEL="Calibration testnet (314159)" +elif [ "$CHAIN" = "314" ]; then + CHAIN_LABEL="Filecoin mainnet (314)" +else + CHAIN_LABEL="Chain ID $CHAIN" +fi +echo " - Chain: $CHAIN_LABEL" +echo "" +echo "Next steps:" +if [ "$WITH_PROXY" = "true" ]; then + echo "1. Save the proxy address: export REGISTRY_ADDRESS=$REGISTRY_PROXY_ADDRESS" + echo "2. Verify the deployment by calling getProviderCount() - should return 0" + echo "3. Test registration with: cast send --value attoFIL ..." + echo "4. Transfer ownership if needed using transferOwnership()" + echo "5. The registry is ready for provider registrations" +else + echo "1. Save the implementation address for upgrade announcement" + echo "2. Proceed with announce-planned-upgrade-registry.sh" +fi +echo "" +if [ "$WITH_PROXY" = "true" ]; then + echo "To interact with the registry:" + echo " View functions:" + echo " cast call $REGISTRY_PROXY_ADDRESS \"getProviderCount()(uint256)\"" + echo " cast call $REGISTRY_PROXY_ADDRESS \"getAllActiveProviders()(uint256[])\"" + echo " State changes (requires registration fee):" + echo " Register as provider (requires proper encoding of PDPData)" + echo "" +fi + +# Automatic contract verification +if [ "${AUTO_VERIFY:-true}" = "true" ]; then + echo + echo "🔍 Starting automatic contract verification..." + + pushd "$(dirname $0)/.." >/dev/null + source tools/verify-contracts.sh + verify_contracts_batch "$SERVICE_PROVIDER_REGISTRY_IMPLEMENTATION_ADDRESS,src/ServiceProviderRegistry.sol:ServiceProviderRegistry" + popd >/dev/null +else + echo + echo "⏭️ Skipping automatic verification (export AUTO_VERIFY=true to enable)" +fi +echo "==========================================" From 6a774b851929315ac76c5f7ee692b897fbd6b0a8 Mon Sep 17 00:00:00 2001 From: Phi Date: Wed, 21 Jan 2026 13:06:59 +0100 Subject: [PATCH 13/32] feat: add network-specific USDFC token address handling in deploy-warm-storage-implementation-only.sh --- ...deploy-warm-storage-implementation-only.sh | 27 ++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/service_contracts/tools/deploy-warm-storage-implementation-only.sh b/service_contracts/tools/deploy-warm-storage-implementation-only.sh index 551fa8e2..39596438 100755 --- a/service_contracts/tools/deploy-warm-storage-implementation-only.sh +++ b/service_contracts/tools/deploy-warm-storage-implementation-only.sh @@ -69,7 +69,32 @@ if [ -z "$SESSION_KEY_REGISTRY_ADDRESS" ]; then exit 1 fi -USDFC_TOKEN_ADDRESS="0xb3042734b608a1B16e9e86B374A3f3e389B4cDf0" # USDFC token address on calibnet +# Set network-specific USDFC token address based on chain ID +case "$CHAIN" in + "31415926") + # Devnet requires explicit USDFC_TOKEN_ADDRESS (mock token) + if [ -z "$USDFC_TOKEN_ADDRESS" ]; then + echo "Error: USDFC_TOKEN_ADDRESS is not set (required for devnet)" + echo "Please set USDFC_TOKEN_ADDRESS to your deployed MockUSDFC address" + exit 1 + fi + ;; + "314159") + USDFC_TOKEN_ADDRESS="${USDFC_TOKEN_ADDRESS:-0xb3042734b608a1B16e9e86B374A3f3e389B4cDf0}" # calibnet + ;; + "314") + USDFC_TOKEN_ADDRESS="${USDFC_TOKEN_ADDRESS:-0x80B98d3aa09ffff255c3ba4A241111Ff1262F045}" # mainnet + ;; + *) + echo "Error: Unsupported network" + echo " Supported networks:" + echo " 31415926 - Filecoin local development network" + echo " 314159 - Filecoin Calibration testnet" + echo " 314 - Filecoin mainnet" + echo " Detected chain ID: $CHAIN" + exit 1 + ;; +esac SIGNATURE_LIB_DEPLOYED=false if [ -z "$SIGNATURE_VERIFICATION_LIB_ADDRESS" ]; then From 79055ef651c5fb6116fa5a4bff2c51f173766407 Mon Sep 17 00:00:00 2001 From: Phi Date: Wed, 21 Jan 2026 14:07:51 +0100 Subject: [PATCH 14/32] chore: update version to 1.1.0 in ServiceProviderRegistry and FilecoinWarmStorageService tests --- service_contracts/test/FilecoinWarmStorageService.t.sol | 2 +- service_contracts/test/ServiceProviderRegistry.t.sol | 2 +- service_contracts/test/ServiceProviderRegistryFull.t.sol | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/service_contracts/test/FilecoinWarmStorageService.t.sol b/service_contracts/test/FilecoinWarmStorageService.t.sol index dca54a07..5df116de 100644 --- a/service_contracts/test/FilecoinWarmStorageService.t.sol +++ b/service_contracts/test/FilecoinWarmStorageService.t.sol @@ -5387,7 +5387,7 @@ contract FilecoinWarmStorageServiceUpgradeTest is Test { if (logs[i].topics[0] == expectedTopic) { // Decode and verify the event data (string memory version, address implementation) = abi.decode(logs[i].data, (string, address)); - assertEq(version, "1.0.0", "Version should be 1.0.0"); + assertEq(version, "1.1.0", "Version should be 1.1.0"); assertTrue(implementation != address(0), "Implementation address should not be zero"); foundEvent = true; break; diff --git a/service_contracts/test/ServiceProviderRegistry.t.sol b/service_contracts/test/ServiceProviderRegistry.t.sol index ae4315a1..f69aeaa7 100644 --- a/service_contracts/test/ServiceProviderRegistry.t.sol +++ b/service_contracts/test/ServiceProviderRegistry.t.sol @@ -38,7 +38,7 @@ contract ServiceProviderRegistryTest is MockFVMTest { function testInitialState() public view { // Check version - assertEq(registry.VERSION(), "1.0.0", "Version should be 1.0.0"); + assertEq(registry.VERSION(), "1.1.0", "Version should be 1.1.0"); // Check owner assertEq(registry.owner(), owner, "Service provider should be deployer"); diff --git a/service_contracts/test/ServiceProviderRegistryFull.t.sol b/service_contracts/test/ServiceProviderRegistryFull.t.sol index 5211ff56..9fe0c9d8 100644 --- a/service_contracts/test/ServiceProviderRegistryFull.t.sol +++ b/service_contracts/test/ServiceProviderRegistryFull.t.sol @@ -85,7 +85,7 @@ contract ServiceProviderRegistryFullTest is MockFVMTest { // ========== Initial State Tests ========== function testInitialState() public view { - assertEq(registry.VERSION(), "1.0.0", "Version should be 1.0.0"); + assertEq(registry.VERSION(), "1.1.0", "Version should be 1.1.0"); assertEq(registry.owner(), owner, "Service provider should be deployer"); assertEq(registry.getNextProviderId(), 1, "Next provider ID should start at 1"); assertEq(registry.REGISTRATION_FEE(), 5 ether, "Registration fee should be 5 FIL"); From 3f41420e9c3b2865533240db1210f38bbbe73652 Mon Sep 17 00:00:00 2001 From: Phi Date: Wed, 21 Jan 2026 14:59:47 +0100 Subject: [PATCH 15/32] docs: update upgrade-process document docs: update upgrade-process document --- service_contracts/tools/UPGRADE-PROCESS.md | 324 +++++++-------------- 1 file changed, 108 insertions(+), 216 deletions(-) diff --git a/service_contracts/tools/UPGRADE-PROCESS.md b/service_contracts/tools/UPGRADE-PROCESS.md index a75e6ed3..d27e05e8 100644 --- a/service_contracts/tools/UPGRADE-PROCESS.md +++ b/service_contracts/tools/UPGRADE-PROCESS.md @@ -1,6 +1,6 @@ # FWSS Contract Upgrade Process -This document describes the upgrade process for FilecoinWarmStorageService (FWSS) and related contracts. +This document describes the upgrade process for FilecoinWarmStorageService (FWSS) and related contracts, organized as a phase-based runbook. ## Contract Upgradeability Overview @@ -26,14 +26,7 @@ ServiceProviderRegistry public immutable serviceProviderRegistry; SessionKeyRegistry public immutable sessionKeyRegistry; ``` -### Operational Expectations - -These immutable contracts are **not expected to be redeployed** under normal operations. Redeploying any of these would require upgrading FWSS to a new implementation with updated constructor arguments, which could break existing functionality and integrations. - -**If redeployment becomes necessary:** -- It will be announced **well ahead of time** to all stakeholders -- A migration plan will be communicated -- The change will go through the standard two-step upgrade process with an extended notice period +These immutable contracts are **not expected to be redeployed** under normal operations. If redeployment becomes necessary, announce it well ahead of time and follow the standard two-step upgrade process with an extended notice period. ## Two-Step Upgrade Process @@ -42,253 +35,188 @@ Both FWSS and ServiceProviderRegistry use a two-step upgrade mechanism: 1. **Announce** - Call `announcePlannedUpgrade()` with the new implementation address and `AFTER_EPOCH` 2. **Execute** - After `AFTER_EPOCH` has passed, call `upgradeToAndCall()` to complete the upgrade -This gives stakeholders time to review changes before execution. - ## Choosing AFTER_EPOCH When announcing an upgrade, choose `AFTER_EPOCH` to give stakeholders adequate notice: | Upgrade Type | Minimum Notice | Recommended | |--------------|----------------|-------------| -| Routine (bug fixes, minor features) | ~24 hours (~2880 epochs) | 1-2 days | +| Routine (bug fixes, minor features) | ~24 hours (~5760 epochs) | 1-2 days | | Breaking changes | ~1 week (~20160 epochs) | 1-2 weeks | | Immutable dependency changes | ~2 weeks (~40320 epochs) | 2-4 weeks | -**To calculate:** - ```bash CURRENT_EPOCH=$(cast block-number --rpc-url "$ETH_RPC_URL"); AFTER_EPOCH=$((CURRENT_EPOCH + 5760)); echo "Current: $CURRENT_EPOCH, Upgrade after: $AFTER_EPOCH" ``` -**Considerations:** +Considerations: - Allow time for stakeholder review - Avoid weekends/holidays for mainnet upgrades - Calibnet can use shorter notice periods for testing -## Pre-Upgrade Checklist +## Phase 0: Decide Scope + +1. Identify which contracts are changing: + - FWSS implementation + - ServiceProviderRegistry implementation + - StateView contract (typically for breaking changes in the view) +2. If the change is breaking or touches immutable dependencies, plan for longer notice and a migration guide. -### Before the Upgrade +## Phase 1: Prepare 1. **Prepare changelog entry** in `CHANGELOG.md`: - Document all changes since last release (https://github.com/FilOzone/filecoin-services/releases) - Mark breaking changes clearly - Include migration notes if needed - 2. **Create PR** with changelog updates +3. **Update the version** string in the contracts if applicable. +4. **Create tracking issue** using the [Create Upgrade Announcement](https://github.com/FilOzone/filecoin-services/actions/workflows/upgrade-announcement.yml) GitHub Action -3. **Create tracking issue** using the [Create Upgrade Announcement](https://github.com/FilOzone/filecoin-services/actions/workflows/upgrade-announcement.yml) GitHub Action - -4. **Deploy new implementation** contract: - - Run the deployment script (see [FWSS Upgrade Workflow](#fwss-upgrade-workflow)) - - `deployments.json` is automatically updated by the script - - **Document the new implementation address in PR comments** for traceability - - Commit the updated `deployments.json` to the PR - -5. **Run upgrade announcement** on-chain via `announce-planned-upgrade.sh` - -### After Successful Upgrade - -1. **Verify** the upgrade on block explorer (Blockscout) - -2. **Confirm** `deployments.json` was updated (automatic via script) - -3. **Merge** the changelog PR - -4. **Tag release** in GitHub (post-upgrade): - ```bash - git tag v1.X.0 - git push origin v1.X.0 - ``` - -5. **Create GitHub Release** pointing to: - - Changelog entry - - `deployments.json` for current addresses - -## Stakeholder Communication - - - -> **Tip**: Use the [Create Upgrade Announcement](../../.github/workflows/upgrade-announcement.yml) GitHub Action to automatically generate an announcement issue. Go to **Actions → Create Upgrade Announcement → Run workflow**. - -### Before Announcing an Upgrade - -Before running `announce-planned-upgrade.sh`, notify stakeholders through: - -- [ ] **Documentation**: Update changelog with upcoming changes in a PR -- [ ] **GitHub**: Create a tracking issue or discussion for the upgrade -- [ ] **Slack**: Post in `#` with upgrade details +## Phase 2: Calibnet Rehearsal -### Upgrade Announcement Template - -> **Automated**: The [Create Upgrade Announcement](https://github.com/FilOzone/filecoin-services/actions/workflows/upgrade-announcement.yml) GitHub Action generates this template as an issue automatically. +Always test the upgrade on Calibnet before mainnet. -When communicating an upgrade, include: +### Deploy Implementations (Calibnet) +FWSS implementation: +```bash +./deploy-warm-storage-implementation-only.sh ``` -## FWSS Contract Upgrade Announcement -**Network**: [Mainnet/Calibnet] -**Upgrade Type**: [Routine/Breaking Change] -**Scheduled Execution**: After epoch [AFTER_EPOCH] (~[estimated date/time]) +Other contracts you might deploy during a upgrade can be: -### Changes -- [Summary of changes] -- [Link to PR/release notes] - -### New Implementation Address -`0x...` - -### Action Required -[None / Describe any required actions for integrators] - -### Resources -- Release: [link] (if applicable) -- Changelog: [link] +ServiceProviderRegistry implementation (if needed): +```bash +./deploy-registry-calibnet.sh ``` -### After Upgrade Execution - -- [ ] **Verify**: Confirm upgrade success on block explorer -- [ ] **Notify**: Post confirmation in communication channels -- [ ] **Update**: Update `deployments.json` (automatic) and any external documentation -- [ ] **Release**: Tag a new release in GitHub with updated addresses - -### Breaking Changes Communication - -For upgrades involving immutable dependency changes or breaking API changes: - -- Provide **extended notice period** (minimum recommended: ) -- Create detailed **migration guide** for affected integrators -- Offer **support channel** for questions during migration -- Consider **phased rollout**: Calibnet first, then Mainnet after validation - -## FWSS Upgrade Workflow - -### Step 1: Deploy New Implementation - -Deploy the new implementation contract with the same immutable dependencies: - +FilecoinWarmStorageStateView update (if needed): ```bash -export ETH_KEYSTORE="/path/to/keystore.json" -export PASSWORD="your-password" -export ETH_RPC_URL="https://api.calibration.node.glif.io/rpc/v1" - -# Deploy new implementation (uses existing immutable addresses from deployments.json) -forge create --password "$PASSWORD" --broadcast \ - --libraries "src/lib/SignatureVerificationLib.sol:SignatureVerificationLib:$SIGNATURE_VERIFICATION_LIB_ADDRESS" \ - src/FilecoinWarmStorageService.sol:FilecoinWarmStorageService \ - --constructor-args \ - "$PDP_VERIFIER_ADDRESS" \ - "$PAYMENTS_CONTRACT_ADDRESS" \ - "$USDFC_TOKEN_ADDRESS" \ - "$FILBEAM_BENEFICIARY_ADDRESS" \ - "$SERVICE_PROVIDER_REGISTRY_PROXY_ADDRESS" \ - "$SESSION_KEY_REGISTRY_ADDRESS" +./deploy-warm-storage-view.sh ``` -### Step 2: Optionally Deploy New StateView +`deployments.json` is updated automatically by the scripts. Commit the updated file in the upgrade PR and document the new addresses in PR comments for traceability. -If the StateView contract needs updating: -```bash -source ./deploy-warm-storage-view.sh -``` - -### Step 3: Announce the Upgrade +### Announce and Execute (Calibnet) ```bash export ETH_RPC_URL="https://api.calibration.node.glif.io/rpc/v1" -export ETH_KEYSTORE="/path/to/keystore.json" -export PASSWORD="your-password" export WARM_STORAGE_PROXY_ADDRESS="0x..." -export NEW_WARM_STORAGE_IMPLEMENTATION_ADDRESS="0x..." # From step 1 -export AFTER_EPOCH="123456" # Block number after which upgrade can execute +export NEW_WARM_STORAGE_IMPLEMENTATION_ADDRESS="0x..." +export AFTER_EPOCH="123456" ./announce-planned-upgrade.sh ``` -### Step 4: Wait for AFTER_EPOCH - -The upgrade cannot be executed until the current block number exceeds `AFTER_EPOCH`. - -### Step 5: Execute the Upgrade - +After `AFTER_EPOCH`, execute: ```bash export ETH_RPC_URL="https://api.calibration.node.glif.io/rpc/v1" -export ETH_KEYSTORE="/path/to/keystore.json" -export PASSWORD="your-password" export WARM_STORAGE_PROXY_ADDRESS="0x..." export NEW_WARM_STORAGE_IMPLEMENTATION_ADDRESS="0x..." -# Optional: NEW_WARM_STORAGE_VIEW_ADDRESS if deploying new view contract ./upgrade.sh ``` -### Step 6: Verify +## Phase 3: Mainnet Deployment -The script automatically: -- Verifies the upgrade by checking the implementation storage slot -- Updates `deployments.json` with the new implementation address +1. Deploy registry implementation (if needed): + ```bash + ./deploy-registry.sh + ``` +2. Deploy FWSS implementation: + ```bash + ./deploy-warm-storage-implementation-only.sh + ``` +3. Deploy StateView (if needed): + ```bash + ./deploy-warm-storage-view.sh + ``` -## ServiceProviderRegistry Upgrade Workflow +`deployments.json` is updated automatically by the scripts. Commit the updated file in the upgrade PR and document the new addresses in PR comments for traceability. -Similar to FWSS, but uses dedicated scripts: +## Phase 4: Announce the Mainnet Upgrade -### Deploy New Registry Implementation (Calibnet) +1. Choose `AFTER_EPOCH` based on the upgrade type. +2. Announce on-chain: + ```bash + export ETH_RPC_URL="https://api.node.glif.io/rpc/v1" + export WARM_STORAGE_PROXY_ADDRESS="0x..." + export NEW_WARM_STORAGE_IMPLEMENTATION_ADDRESS="0x..." + export AFTER_EPOCH="123456" -Use the deploy script in upgrade-first mode (implementation-only). This is the default: + ./announce-planned-upgrade.s + ``` +4. Notify stakeholders (see template below). Use the GitHub Action to create the announcement issue. -```bash -./deploy-registry.sh -``` +## Phase 5: Execute the Mainnet Upgrade -To deploy a new proxy as well (fresh deployment), pass the flag: +After `AFTER_EPOCH`, execute: ```bash -./deploy-registry.sh --with-proxy +export ETH_RPC_URL="https://api.node.glif.io/rpc/v1" +export WARM_STORAGE_PROXY_ADDRESS="0x..." +export NEW_WARM_STORAGE_IMPLEMENTATION_ADDRESS="0x..." +export NEW_WARM_STORAGE_VIEW_ADDRESS="0x..." # Optional + +./upgrade.sh ``` -### Announce +## Phase 6: Verify and Release -```bash -export ETH_RPC_URL="https://api.calibration.node.glif.io/rpc/v1" -export ETH_KEYSTORE="/path/to/keystore.json" -export PASSWORD="your-password" -export REGISTRY_PROXY_ADDRESS="0x..." -export NEW_REGISTRY_IMPLEMENTATION_ADDRESS="0x..." -export AFTER_EPOCH="123456" +1. **Verify** upgrades on Blockscout. +2. **Confirm** `deployments.json` was updated (automatic via script). +3. **Merge** the changelog PR. +4. **Tag release** in GitHub (post-upgrade): + ```bash + git tag v1.X.0 + git push origin v1.X.0 + ``` +5. **Create GitHub Release** with the changelog, ensure to point to the `deployments.json` for current addresses. +6. **Notify stakeholders** that the upgrade is complete. -./announce-planned-upgrade-registry.sh -``` +## Stakeholder Communication -### Execute +> **Tip**: Use the [Create Upgrade Announcement](../../.github/workflows/upgrade-announcement.yml) GitHub Action to automatically generate an announcement issue. Go to **Actions → Create Upgrade Announcement → Run workflow**. -```bash -export ETH_RPC_URL="https://api.calibration.node.glif.io/rpc/v1" -export ETH_KEYSTORE="/path/to/keystore.json" -export PASSWORD="your-password" -export SERVICE_PROVIDER_REGISTRY_PROXY_ADDRESS="0x..." -export NEW_REGISTRY_IMPLEMENTATION_ADDRESS="0x..." -export NEW_VERSION="v1.1.0" # Optional version string for migrate() +### Upgrade Announcement Template + +> **Automated**: The GitHub Action generates this template as an issue automatically. + +When communicating an upgrade, include: -./upgrade-registry.sh ``` +## FWSS Contract Upgrade Announcement -## StateView Contract Updates +**Network**: [Mainnet/Calibnet] +**Upgrade Type**: [Routine/Breaking Change] +**Scheduled Execution**: After epoch [AFTER_EPOCH] (~[estimated date/time]) -The `FilecoinWarmStorageServiceStateView` is a helper contract that can be redeployed independently without going through the two-step announcement process: +### Changes +- [Summary of changes] +- [Link to PR/release notes] -1. Deploy new StateView: - ```bash - source ./deploy-warm-storage-view.sh - ``` +### Contracts Planned Upgraded +- FilecoinWarmStorageService +- ServiceProviderRegistry (if applicable) +- FilecoinWarmStorageServiceStateView (if applicable) -2. Set the new view address on FWSS proxy: - ```bash - source ./set-warm-storage-view.sh - ``` +### Action Required +[None / Describe any required actions for integrators] + +### Resources +- Release: [link] (if applicable) +- Changelog: [link] +- Upgrade Process: [link to this document] +``` -This is an owner-only operation and does not require an upgrade announcement. +### Breaking Changes Communication + +For upgrades involving immutable dependency changes or breaking API changes: +- Provide extended notice period +- Create a migration guide for affected integrators +- Offer a support channel for questions during migration +- Consider phased rollout: Calibnet first, then Mainnet after validation ## Environment Variables Reference @@ -320,42 +248,6 @@ This is an owner-only operation and does not require an upgrade announcement. | `AFTER_EPOCH` | Block number after which upgrade can execute | | `NEW_VERSION` | (Optional) Version string for migrate() | -## Verification and Testing - -### Always Test on Calibnet First - -Before upgrading on mainnet, always test the upgrade on Calibnet: - -```bash -export ETH_RPC_URL="https://api.calibration.node.glif.io/rpc/v1" -# ... run upgrade scripts -``` - -### Storage Layout Verification - -Before deploying a new implementation, verify storage layout compatibility: - -```bash -forge inspect src/FilecoinWarmStorageService.sol:FilecoinWarmStorageService storageLayout -``` - -Compare with the previous version to ensure no storage slot collisions. - -### Upgrade Verification - -The upgrade scripts automatically verify success by checking the ERC1967 implementation slot: - -```bash -cast rpc eth_getStorageAt "$PROXY_ADDRESS" \ - 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc latest -``` - -### Run Upgrade Tests - -```bash -forge test --match-contract FilecoinWarmStorageServiceUpgradeTest -``` - ## Deployment Address Management All deployment scripts automatically load and update addresses in `deployments.json`. See the main [README.md](./README.md) for details on: From 38a0cafe263b74770e4021fe24a320f67b8b6ca9 Mon Sep 17 00:00:00 2001 From: Phi Date: Wed, 21 Jan 2026 15:13:22 +0100 Subject: [PATCH 16/32] feat: enhance upgrade announcement workflow with new upgrade options and action requirements --- .github/workflows/upgrade-announcement.yml | 92 ++++++++++++++-------- 1 file changed, 60 insertions(+), 32 deletions(-) diff --git a/.github/workflows/upgrade-announcement.yml b/.github/workflows/upgrade-announcement.yml index 631a6052..0ad13233 100644 --- a/.github/workflows/upgrade-announcement.yml +++ b/.github/workflows/upgrade-announcement.yml @@ -17,14 +17,21 @@ on: options: - Routine - Breaking Change - contract: - description: 'Contract being upgraded' - required: true - type: choice - options: - - FilecoinWarmStorageService - - ServiceProviderRegistry - - PDPVerifier + upgrade_fwss: + description: 'Upgrading FilecoinWarmStorageService?' + required: false + type: boolean + default: true + upgrade_registry: + description: 'Upgrading ServiceProviderRegistry?' + required: false + type: boolean + default: false + upgrade_state_view: + description: 'Upgrading FilecoinWarmStorageServiceStateView?' + required: false + type: boolean + default: false after_epoch: description: 'AFTER_EPOCH (block number after which upgrade can execute)' required: true @@ -37,6 +44,11 @@ on: description: 'Summary of changes (use | for multiple lines)' required: true type: string + action_required: + description: 'Action required for integrators (or "None" if no action needed)' + required: true + type: string + default: 'None' release_tag: description: 'Release tag if already created (usually added after upgrade completes)' required: false @@ -99,44 +111,61 @@ jobs: script: | const network = '${{ inputs.network }}'; const upgradeType = '${{ inputs.upgrade_type }}'; - const contract = '${{ inputs.contract }}'; const afterEpoch = '${{ inputs.after_epoch }}'; const changelogPr = '${{ inputs.changelog_pr }}'; const releaseTag = '${{ inputs.release_tag }}'; + const actionRequired = '${{ inputs.action_required }}'; const timeEstimate = `${{ steps.calc_time.outputs.estimate }}`; const changes = `${{ steps.format_changes.outputs.changes }}`; + const upgradeFwss = '${{ inputs.upgrade_fwss }}' === 'true'; + const upgradeRegistry = '${{ inputs.upgrade_registry }}' === 'true'; + const upgradeStateView = '${{ inputs.upgrade_state_view }}' === 'true'; const releaseLink = releaseTag ? `https://github.com/${context.repo.owner}/${context.repo.repo}/releases/tag/${releaseTag}` : null; const changelogPrLink = `https://github.com/${context.repo.owner}/${context.repo.repo}/pull/${changelogPr}`; + const changelogLink = `https://github.com/${context.repo.owner}/${context.repo.repo}/blob/main/CHANGELOG.md`; + const upgradeProcessLink = `https://github.com/${context.repo.owner}/${context.repo.repo}/blob/main/service_contracts/tools/UPGRADE-PROCESS.md`; - const body = `## ${contract} Upgrade Announcement + // Build contracts list + const contracts = []; + if (upgradeFwss) { + contracts.push('- FilecoinWarmStorageService'); + } + if (upgradeRegistry) { + contracts.push('- ServiceProviderRegistry'); + } + if (upgradeStateView) { + contracts.push('- FilecoinWarmStorageServiceStateView'); + } + // If none selected, default to FilecoinWarmStorageService + if (contracts.length === 0) { + contracts.push('- FilecoinWarmStorageService'); + } + + const body = `## FWSS Contract Upgrade Announcement - **Network**: ${network} - **Upgrade Type**: ${upgradeType} - **Scheduled Execution**: After epoch ${afterEpoch} (${timeEstimate}) +**Network**: ${network} +**Upgrade Type**: ${upgradeType} +**Scheduled Execution**: After epoch ${afterEpoch} (${timeEstimate}) - ### Changes - - Changelog PR: ${changelogPrLink} - ${changes} +### Changes +${changes} +- [Link to PR/release notes](${changelogPrLink}) - ### Resources - ${releaseLink ? `- Release: ${releaseLink}` : ''} - - Upgrade Process: [UPGRADE-PROCESS.md](https://github.com/${context.repo.owner}/${context.repo.repo}/blob/main/service_contracts/tools/UPGRADE-PROCESS.md) +### Contracts Planned Upgraded +${contracts.join('\n')} - --- - - ### Checklist - - [ ] New implementation deployed (address shared) - - [ ] Upgrade announced on-chain via \`announce-planned-upgrade.sh\` - - [ ] Stakeholders notified - - [ ] Upgrade executed after AFTER_EPOCH - - [ ] Upgrade verified on block explorer - - [ ] \`deployments.json\` updated and committed - - [ ] Release tagged (post-upgrade) - `.split('\n').map(line => line.trim()).join('\n'); +### Action Required +${actionRequired} + +### Resources +${releaseLink ? `- Release: ${releaseLink}` : '- Release: [link] (if applicable)'} +- Changelog: ${changelogLink} +- Upgrade Process: ${upgradeProcessLink} +`.split('\n').map(line => line.trim()).join('\n'); const labels = ['upgrade']; if (upgradeType === 'Breaking Change') { @@ -146,7 +175,7 @@ jobs: const issue = await github.rest.issues.create({ owner: context.repo.owner, repo: context.repo.repo, - title: `[Upgrade] ${contract} - ${network} - Epoch ${afterEpoch}`, + title: `[Upgrade] FWSS Contract - ${network} - Epoch ${afterEpoch}`, body: body, labels: labels }); @@ -159,7 +188,6 @@ jobs: run: | echo "## Upgrade Announcement Created" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY - echo "**Contract**: ${{ inputs.contract }}" >> $GITHUB_STEP_SUMMARY echo "**Network**: ${{ inputs.network }}" >> $GITHUB_STEP_SUMMARY echo "**After Epoch**: ${{ inputs.after_epoch }}" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY From 77bf6dd3511ec610291c4623be9e644d646b2245 Mon Sep 17 00:00:00 2001 From: Phi-rjan Date: Thu, 22 Jan 2026 07:42:45 +0100 Subject: [PATCH 17/32] Update service_contracts/tools/UPGRADE-PROCESS.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- service_contracts/tools/UPGRADE-PROCESS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/service_contracts/tools/UPGRADE-PROCESS.md b/service_contracts/tools/UPGRADE-PROCESS.md index d27e05e8..55c45216 100644 --- a/service_contracts/tools/UPGRADE-PROCESS.md +++ b/service_contracts/tools/UPGRADE-PROCESS.md @@ -145,7 +145,7 @@ export NEW_WARM_STORAGE_IMPLEMENTATION_ADDRESS="0x..." export NEW_WARM_STORAGE_IMPLEMENTATION_ADDRESS="0x..." export AFTER_EPOCH="123456" - ./announce-planned-upgrade.s + ./announce-planned-upgrade.sh ``` 4. Notify stakeholders (see template below). Use the GitHub Action to create the announcement issue. From 41ee70df0a89636f2e249e69784a99e8957518b9 Mon Sep 17 00:00:00 2001 From: Phi-rjan Date: Thu, 22 Jan 2026 07:42:59 +0100 Subject: [PATCH 18/32] Update service_contracts/tools/UPGRADE-PROCESS.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- service_contracts/tools/UPGRADE-PROCESS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/service_contracts/tools/UPGRADE-PROCESS.md b/service_contracts/tools/UPGRADE-PROCESS.md index 55c45216..56cbdd0d 100644 --- a/service_contracts/tools/UPGRADE-PROCESS.md +++ b/service_contracts/tools/UPGRADE-PROCESS.md @@ -196,7 +196,7 @@ When communicating an upgrade, include: - [Summary of changes] - [Link to PR/release notes] -### Contracts Planned Upgraded +### Contracts Planned for Upgrade - FilecoinWarmStorageService - ServiceProviderRegistry (if applicable) - FilecoinWarmStorageServiceStateView (if applicable) From 9d05a18b63d3a3edc5b5fe3c82e5cf329bf70e5b Mon Sep 17 00:00:00 2001 From: Phi-rjan Date: Thu, 22 Jan 2026 07:43:11 +0100 Subject: [PATCH 19/32] Update .github/workflows/upgrade-announcement.yml Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .github/workflows/upgrade-announcement.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/upgrade-announcement.yml b/.github/workflows/upgrade-announcement.yml index 0ad13233..bed699a9 100644 --- a/.github/workflows/upgrade-announcement.yml +++ b/.github/workflows/upgrade-announcement.yml @@ -155,7 +155,7 @@ jobs: ${changes} - [Link to PR/release notes](${changelogPrLink}) -### Contracts Planned Upgraded +### Contracts Planned for Upgrade ${contracts.join('\n')} ### Action Required From 2141519d01602777380a80155265e44076805b48 Mon Sep 17 00:00:00 2001 From: Phi Date: Mon, 26 Jan 2026 09:05:15 +0100 Subject: [PATCH 20/32] chore: remove deploy-registry-calibnet script Integrated into deploy-registry.sh which is network agnositc --- .../tools/deploy-registry-calibnet.sh | 220 ------------------ 1 file changed, 220 deletions(-) delete mode 100644 service_contracts/tools/deploy-registry-calibnet.sh diff --git a/service_contracts/tools/deploy-registry-calibnet.sh b/service_contracts/tools/deploy-registry-calibnet.sh deleted file mode 100644 index f9cc5171..00000000 --- a/service_contracts/tools/deploy-registry-calibnet.sh +++ /dev/null @@ -1,220 +0,0 @@ -#!/bin/bash -# deploy-registry-calibnet deploys the Service Provider Registry contract to a target network -# Assumption: ETH_KEYSTORE, PASSWORD, ETH_RPC_URL env vars are set to an appropriate eth keystore path and password -# and to a valid ETH_RPC_URL for the target network. -# Assumption: forge, cast, jq are in the PATH -# Assumption: called from contracts directory so forge paths work out -# - -# Get script directory and source deployments.sh -SCRIPT_DIR="$(dirname "${BASH_SOURCE[0]}")" -source "$SCRIPT_DIR/deployments.sh" - -echo "Deploying Service Provider Registry Contract" - -WITH_PROXY=false -for arg in "$@"; do - case "$arg" in - --with-proxy) - WITH_PROXY=true - ;; - -h|--help) - echo "Usage: $(basename "$0") [--with-proxy]" - echo "" - echo "Default: deploy implementation only (upgrade-first)." - echo " --with-proxy Also deploy a new proxy and initialize it." - exit 0 - ;; - *) - echo "Error: Unknown option '$arg'" - echo "Run with --help for usage." - exit 1 - ;; - esac -done - -if [ "$WITH_PROXY" = "true" ]; then - echo "Mode: implementation + proxy deployment" -else - echo "Mode: implementation-only deployment (upgrade-first)" -fi - -if [ -z "$ETH_RPC_URL" ]; then - echo "Error: ETH_RPC_URL is not set" - exit 1 -fi - -# Auto-detect chain ID from RPC if not already set -if [ -z "$CHAIN" ]; then - export CHAIN=$(cast chain-id) - if [ -z "$CHAIN" ]; then - echo "Error: Failed to detect chain ID from RPC" - exit 1 - fi -fi - -# Load deployment addresses from deployments.json -load_deployment_addresses "$CHAIN" - -if [ -z "$ETH_KEYSTORE" ]; then - echo "Error: ETH_KEYSTORE is not set" - exit 1 -fi - -# Optional: Check if PASSWORD is set (some users might use empty password) -if [ -z "$PASSWORD" ]; then - echo "Warning: PASSWORD is not set, using empty password" -fi - -ADDR=$(cast wallet address --password "$PASSWORD") -echo "Deploying contracts from address $ADDR" - -# Get current balance and nonce (cast will use ETH_RPC_URL) -BALANCE=$(cast balance "$ADDR") -echo "Deployer balance: $BALANCE" - -NONCE="$(cast nonce "$ADDR")" -echo "Starting nonce: $NONCE" - -# Deploy ServiceProviderRegistry implementation -SPR_INIT_COUNTER=1 -echo "" -echo "=== STEP 1: Deploying ServiceProviderRegistry Implementation ===" -SERVICE_PROVIDER_REGISTRY_IMPLEMENTATION_ADDRESS=$(forge create --password "$PASSWORD" --broadcast --nonce $NONCE src/ServiceProviderRegistry.sol:ServiceProviderRegistry --optimizer-runs 1 --via-ir --constructor-args $SPR_INIT_COUNTER | grep "Deployed to" | awk '{print $3}') -if [ -z "$SERVICE_PROVIDER_REGISTRY_IMPLEMENTATION_ADDRESS" ]; then - echo "Error: Failed to extract ServiceProviderRegistry implementation address" - exit 1 -fi -echo "✓ ServiceProviderRegistry implementation deployed at: $SERVICE_PROVIDER_REGISTRY_IMPLEMENTATION_ADDRESS" -NONCE=$(expr $NONCE + "1") - -if [ "$WITH_PROXY" = "true" ]; then - # Deploy ServiceProviderRegistry proxy - echo "" - echo "=== STEP 2: Deploying ServiceProviderRegistry Proxy ===" - # Initialize with no parameters for basic initialization - INIT_DATA=$(cast calldata "initialize()") - echo "Initialization calldata: $INIT_DATA" - - REGISTRY_PROXY_ADDRESS=$(forge create --password "$PASSWORD" --broadcast --nonce $NONCE lib/pdp/src/ERC1967Proxy.sol:MyERC1967Proxy --constructor-args $SERVICE_PROVIDER_REGISTRY_IMPLEMENTATION_ADDRESS $INIT_DATA --optimizer-runs 1 --via-ir | grep "Deployed to" | awk '{print $3}') - if [ -z "$REGISTRY_PROXY_ADDRESS" ]; then - echo "Error: Failed to extract ServiceProviderRegistry proxy address" - exit 1 - fi - echo "✓ ServiceProviderRegistry proxy deployed at: $REGISTRY_PROXY_ADDRESS" - - # Verify deployment by calling version() on the proxy - echo "" - echo "=== STEP 3: Verifying Deployment ===" - VERSION=$(cast call $REGISTRY_PROXY_ADDRESS "version()(string)") - if [ -z "$VERSION" ]; then - echo "Warning: Could not verify contract version" - else - echo "✓ Contract version: $VERSION" - fi - - # Get registration fee - FEE=$(cast call $REGISTRY_PROXY_ADDRESS "REGISTRATION_FEE()(uint256)") - if [ -z "$FEE" ]; then - echo "Warning: Could not retrieve registration fee" - FEE_IN_FIL="unknown" - else - echo "✓ Registration fee: $FEE attoFIL" - FEE_IN_FIL="$FEE attoFIL" - fi - - # Get burn actor address - BURN_ACTOR=$(cast call $REGISTRY_PROXY_ADDRESS "BURN_ACTOR()(address)") - if [ -z "$BURN_ACTOR" ]; then - echo "Warning: Could not retrieve burn actor address" - else - echo "✓ Burn actor address: $BURN_ACTOR" - fi - - # Get contract version (this should be used instead of hardcoded version) - CONTRACT_VERSION=$(cast call $REGISTRY_PROXY_ADDRESS "VERSION()(string)") - if [ -z "$CONTRACT_VERSION" ]; then - echo "Warning: Could not retrieve contract version" - CONTRACT_VERSION="Unknown" - fi -else - echo "" - echo "=== STEP 2: Skipping Proxy Deployment ===" - echo "Use --with-proxy to deploy and initialize a new proxy." - CONTRACT_VERSION="n/a" - FEE_IN_FIL="n/a" - BURN_ACTOR="n/a" -fi - -# Summary of deployed contracts -echo "" -echo "==========================================" -echo "=== DEPLOYMENT SUMMARY ===" -echo "==========================================" -echo "ServiceProviderRegistry Implementation: $SERVICE_PROVIDER_REGISTRY_IMPLEMENTATION_ADDRESS" -if [ "$WITH_PROXY" = "true" ]; then - echo "ServiceProviderRegistry Proxy: $REGISTRY_PROXY_ADDRESS" -fi -echo "==========================================" - -# Update deployments.json -if [ -n "$SERVICE_PROVIDER_REGISTRY_IMPLEMENTATION_ADDRESS" ]; then - update_deployment_address "$CHAIN" "SERVICE_PROVIDER_REGISTRY_IMPLEMENTATION_ADDRESS" "$SERVICE_PROVIDER_REGISTRY_IMPLEMENTATION_ADDRESS" -fi -if [ "$WITH_PROXY" = "true" ] && [ -n "$REGISTRY_PROXY_ADDRESS" ]; then - update_deployment_address "$CHAIN" "SERVICE_PROVIDER_REGISTRY_PROXY_ADDRESS" "$REGISTRY_PROXY_ADDRESS" -fi -if [ -n "$SERVICE_PROVIDER_REGISTRY_IMPLEMENTATION_ADDRESS" ] || [ -n "$REGISTRY_PROXY_ADDRESS" ]; then - update_deployment_metadata "$CHAIN" -fi -echo "" -echo "Contract Details:" -echo " - Version: $CONTRACT_VERSION" -echo " - Registration Fee: $FEE_IN_FIL (burned)" -echo " - Burn Actor: $BURN_ACTOR" -CHAIN_LABEL="unknown" -if [ "$CHAIN" = "314159" ]; then - CHAIN_LABEL="Calibration testnet (314159)" -elif [ "$CHAIN" = "314" ]; then - CHAIN_LABEL="Filecoin mainnet (314)" -else - CHAIN_LABEL="Chain ID $CHAIN" -fi -echo " - Chain: $CHAIN_LABEL" -echo "" -echo "Next steps:" -if [ "$WITH_PROXY" = "true" ]; then - echo "1. Save the proxy address: export REGISTRY_ADDRESS=$REGISTRY_PROXY_ADDRESS" - echo "2. Verify the deployment by calling getProviderCount() - should return 0" - echo "3. Test registration with: cast send --value attoFIL ..." - echo "4. Transfer ownership if needed using transferOwnership()" - echo "5. The registry is ready for provider registrations" -else - echo "1. Save the implementation address for upgrade announcement" - echo "2. Proceed with announce-planned-upgrade-registry.sh" -fi -echo "" -if [ "$WITH_PROXY" = "true" ]; then - echo "To interact with the registry:" - echo " View functions:" - echo " cast call $REGISTRY_PROXY_ADDRESS \"getProviderCount()(uint256)\"" - echo " cast call $REGISTRY_PROXY_ADDRESS \"getAllActiveProviders()(uint256[])\"" - echo " State changes (requires registration fee):" - echo " Register as provider (requires proper encoding of PDPData)" - echo "" -fi - -# Automatic contract verification -if [ "${AUTO_VERIFY:-true}" = "true" ]; then - echo - echo "🔍 Starting automatic contract verification..." - - pushd "$(dirname $0)/.." >/dev/null - source tools/verify-contracts.sh - verify_contracts_batch "$SERVICE_PROVIDER_REGISTRY_IMPLEMENTATION_ADDRESS,src/ServiceProviderRegistry.sol:ServiceProviderRegistry" - popd >/dev/null -else - echo - echo "⏭️ Skipping automatic verification (export AUTO_VERIFY=true to enable)" -fi -echo "==========================================" From 18086d724f46d41e3b5910953ad1e86e3cf2345c Mon Sep 17 00:00:00 2001 From: Phi Date: Mon, 26 Jan 2026 09:08:24 +0100 Subject: [PATCH 21/32] chore: make implementation "mode" wording clearer chore: make implementation "mode" wording clearer --- service_contracts/tools/deploy-registry.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/service_contracts/tools/deploy-registry.sh b/service_contracts/tools/deploy-registry.sh index 259a45cc..1e05702a 100755 --- a/service_contracts/tools/deploy-registry.sh +++ b/service_contracts/tools/deploy-registry.sh @@ -21,7 +21,7 @@ for arg in "$@"; do -h|--help) echo "Usage: $(basename "$0") [--with-proxy]" echo "" - echo "Default: deploy implementation only (upgrade-first)." + echo "Default: deploy implementation only (upgrade)." echo " --with-proxy Also deploy a new proxy and initialize it." exit 0 ;; @@ -36,7 +36,7 @@ done if [ "$WITH_PROXY" = "true" ]; then echo "Mode: implementation + proxy deployment" else - echo "Mode: implementation-only deployment (upgrade-first)" + echo "Mode: implementation-only deployment with no new proxy and no proxy changes" fi if [ -z "$ETH_RPC_URL" ]; then From 52d19475bc742a6f983553378eb3dfba944473ab Mon Sep 17 00:00:00 2001 From: Phi Date: Mon, 26 Jan 2026 09:13:22 +0100 Subject: [PATCH 22/32] chore: rename workflow to `create-upgrade-announcement-issue.yml` chore: rename workflow to `create-upgrade-announcement-issue.yml` --- ...ade-announcement.yml => create-upgrade-announcement-issue.yml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/workflows/{upgrade-announcement.yml => create-upgrade-announcement-issue.yml} (100%) diff --git a/.github/workflows/upgrade-announcement.yml b/.github/workflows/create-upgrade-announcement-issue.yml similarity index 100% rename from .github/workflows/upgrade-announcement.yml rename to .github/workflows/create-upgrade-announcement-issue.yml From 982732288348d665f7ecbb41e66a8052b63bb041 Mon Sep 17 00:00:00 2001 From: Phi Date: Mon, 26 Jan 2026 09:22:24 +0100 Subject: [PATCH 23/32] fix: address `UPGRADE-PROCESS` comments fix: address `UPGRADE-PROCESS` comments --- service_contracts/tools/UPGRADE-PROCESS.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/service_contracts/tools/UPGRADE-PROCESS.md b/service_contracts/tools/UPGRADE-PROCESS.md index 56cbdd0d..f8a55698 100644 --- a/service_contracts/tools/UPGRADE-PROCESS.md +++ b/service_contracts/tools/UPGRADE-PROCESS.md @@ -6,7 +6,7 @@ This document describes the upgrade process for FilecoinWarmStorageService (FWSS | Contract | Proxy Pattern | Upgrade Method | |----------|---------------|----------------| -| FilecoinWarmStorageService | UUPS Proxy (two-step) | `announce-planned-upgrade.sh` + `upgrade.sh` | +| FilecoinWarmStorageService (FWSS) | UUPS Proxy (two-step) | `announce-planned-upgrade.sh` + `upgrade.sh` | | ServiceProviderRegistry | UUPS Proxy (two-step) | `announce-planned-upgrade-registry.sh` + `upgrade-registry.sh` | | PDPVerifier | ERC1967 Proxy | Via [pdp repo](https://github.com/FilOzone/pdp) scripts | | FilecoinPayV1 | None (immutable) | Not expected to be redeployed | @@ -60,11 +60,11 @@ Considerations: - FWSS implementation - ServiceProviderRegistry implementation - StateView contract (typically for breaking changes in the view) -2. If the change is breaking or touches immutable dependencies, plan for longer notice and a migration guide. +2. If the change is breaking (including breaking changes to dependencies) , plan for longer notice and a migration guide. ## Phase 1: Prepare -1. **Prepare changelog entry** in `CHANGELOG.md`: +1. **Prepare changelog entry** in [`CHANGELOG.md`](../../CHANGELOG.md): - Document all changes since last release (https://github.com/FilOzone/filecoin-services/releases) - Mark breaking changes clearly - Include migration notes if needed From 041c9ae3338be6d485e5fc3287937ca315631219 Mon Sep 17 00:00:00 2001 From: Phi-rjan Date: Mon, 26 Jan 2026 09:15:16 +0100 Subject: [PATCH 24/32] Update service_contracts/tools/UPGRADE-PROCESS.md Co-authored-by: Steve Loeppky --- service_contracts/tools/UPGRADE-PROCESS.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/service_contracts/tools/UPGRADE-PROCESS.md b/service_contracts/tools/UPGRADE-PROCESS.md index f8a55698..d3b4acab 100644 --- a/service_contracts/tools/UPGRADE-PROCESS.md +++ b/service_contracts/tools/UPGRADE-PROCESS.md @@ -45,9 +45,13 @@ When announcing an upgrade, choose `AFTER_EPOCH` to give stakeholders adequate n | Breaking changes | ~1 week (~20160 epochs) | 1-2 weeks | | Immutable dependency changes | ~2 weeks (~40320 epochs) | 2-4 weeks | +For quickly calculating an `AFTER_EPOCH`, one can use the following snippet: + ```bash -CURRENT_EPOCH=$(cast block-number --rpc-url "$ETH_RPC_URL"); AFTER_EPOCH=$((CURRENT_EPOCH + 5760)); echo "Current: $CURRENT_EPOCH, Upgrade after: $AFTER_EPOCH" -``` +UPGRADE_WAIT_DURATION_EPOCHS=5760 +CURRENT_EPOCH=$(cast block-number --rpc-url "$ETH_RPC_URL") +AFTER_EPOCH=$((CURRENT_EPOCH + $UPGRADE_WAIT_DURATION_EPOCHS)) +echo "Current: $CURRENT_EPOCH, Upgrade after: $AFTER_EPOCH" Considerations: - Allow time for stakeholder review From a899196771d5680a689922606491ca81114682fc Mon Sep 17 00:00:00 2001 From: Phi-rjan Date: Mon, 26 Jan 2026 09:15:42 +0100 Subject: [PATCH 25/32] Update service_contracts/tools/README.md Co-authored-by: Steve Loeppky --- service_contracts/tools/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/service_contracts/tools/README.md b/service_contracts/tools/README.md index 7bcb685b..3a9e847e 100644 --- a/service_contracts/tools/README.md +++ b/service_contracts/tools/README.md @@ -14,6 +14,7 @@ This directory contains scripts for deploying and upgrading the FilecoinWarmStor ### Upgrade Scripts +For the [two step upgrade process](#contract-upgrade-process): - `announce-planned-upgrade.sh` - Announce a planned FWSS upgrade (two-step process) - `upgrade.sh` - Execute a previously announced FWSS upgrade - `announce-planned-upgrade-registry.sh` - Announce a planned ServiceProviderRegistry upgrade From 2fc6bd33ea0b7b6d6fa6be45c5eceeea1a19f132 Mon Sep 17 00:00:00 2001 From: Phi Date: Wed, 28 Jan 2026 07:50:07 +0100 Subject: [PATCH 26/32] fix: update migrate data handling in upgrade script fix: update migrate data handling in upgrade script --- service_contracts/tools/upgrade.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/service_contracts/tools/upgrade.sh b/service_contracts/tools/upgrade.sh index bb8ea307..df67830e 100755 --- a/service_contracts/tools/upgrade.sh +++ b/service_contracts/tools/upgrade.sh @@ -87,7 +87,7 @@ if [ -n "$NEW_FWSS_VIEW_ADDRESS" ]; then MIGRATE_DATA=$(cast calldata "migrate(address)" "$NEW_FWSS_VIEW_ADDRESS") else echo "Keeping previous view contract address ($FWSS_VIEW_ADDRESS)" - MIGRATE_DATA=$(cast calldata "migrate(address)" "0x0000000000000000000000000000000000000000") + MIGRATE_DATA="0x" fi # Call upgradeToAndCall on the proxy with migrate function From 67f2c33814f69e3bbbf9d46b00ad645036d3ec52 Mon Sep 17 00:00:00 2001 From: Phi Date: Fri, 30 Jan 2026 02:38:42 -0800 Subject: [PATCH 27/32] Revert "fix: update migrate data handling in upgrade script" This reverts commit 85ee423913ec26f6b0666d44ab6919614429c508. --- service_contracts/tools/upgrade.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/service_contracts/tools/upgrade.sh b/service_contracts/tools/upgrade.sh index df67830e..bb8ea307 100755 --- a/service_contracts/tools/upgrade.sh +++ b/service_contracts/tools/upgrade.sh @@ -87,7 +87,7 @@ if [ -n "$NEW_FWSS_VIEW_ADDRESS" ]; then MIGRATE_DATA=$(cast calldata "migrate(address)" "$NEW_FWSS_VIEW_ADDRESS") else echo "Keeping previous view contract address ($FWSS_VIEW_ADDRESS)" - MIGRATE_DATA="0x" + MIGRATE_DATA=$(cast calldata "migrate(address)" "0x0000000000000000000000000000000000000000") fi # Call upgradeToAndCall on the proxy with migrate function From 203e00d0253ed198b84b467b07f737928a5609c7 Mon Sep 17 00:00:00 2001 From: Phi Date: Fri, 30 Jan 2026 03:02:53 -0800 Subject: [PATCH 28/32] fix: incorporate PR feedback in UPGRADE-PROCESS.md fix: incorporate PR feedback in UPGRADE-PROCESS.md --- service_contracts/tools/UPGRADE-PROCESS.md | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/service_contracts/tools/UPGRADE-PROCESS.md b/service_contracts/tools/UPGRADE-PROCESS.md index d3b4acab..324569eb 100644 --- a/service_contracts/tools/UPGRADE-PROCESS.md +++ b/service_contracts/tools/UPGRADE-PROCESS.md @@ -72,8 +72,9 @@ Considerations: - Document all changes since last release (https://github.com/FilOzone/filecoin-services/releases) - Mark breaking changes clearly - Include migration notes if needed -2. **Create PR** with changelog updates -3. **Update the version** string in the contracts if applicable. +2. **Update the version** string in the contracts if applicable. +3. **Create an "upgrade PR"** with your changelog updates. + - Name the pull request clearly, e.g. `feat: FWSS v1.2.0 upgrade (mainnet)` or `feat: ServiceProviderRegistry patch`. 4. **Create tracking issue** using the [Create Upgrade Announcement](https://github.com/FilOzone/filecoin-services/actions/workflows/upgrade-announcement.yml) GitHub Action ## Phase 2: Calibnet Rehearsal @@ -89,15 +90,8 @@ FWSS implementation: Other contracts you might deploy during a upgrade can be: -ServiceProviderRegistry implementation (if needed): -```bash -./deploy-registry-calibnet.sh -``` - -FilecoinWarmStorageStateView update (if needed): -```bash -./deploy-warm-storage-view.sh -``` +- ServiceProviderRegistry: `./deploy-registry.sh` +- FilecoinWarmStorageStateView: `./deploy-warm-storage-view.sh` `deployments.json` is updated automatically by the scripts. Commit the updated file in the upgrade PR and document the new addresses in PR comments for traceability. @@ -151,7 +145,7 @@ export NEW_WARM_STORAGE_IMPLEMENTATION_ADDRESS="0x..." ./announce-planned-upgrade.sh ``` -4. Notify stakeholders (see template below). Use the GitHub Action to create the announcement issue. +4. Notify stakeholders per [Stakeholder Communication](#stakeholder-communication). ## Phase 5: Execute the Mainnet Upgrade From 4191992e88a9513da963f296431ffdb2e061d357 Mon Sep 17 00:00:00 2001 From: Phi Date: Fri, 30 Jan 2026 03:05:27 -0800 Subject: [PATCH 29/32] fix: notify stakeholders fix: notify stakeholders --- service_contracts/tools/UPGRADE-PROCESS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/service_contracts/tools/UPGRADE-PROCESS.md b/service_contracts/tools/UPGRADE-PROCESS.md index 324569eb..9b2719e7 100644 --- a/service_contracts/tools/UPGRADE-PROCESS.md +++ b/service_contracts/tools/UPGRADE-PROCESS.md @@ -171,7 +171,7 @@ export NEW_WARM_STORAGE_VIEW_ADDRESS="0x..." # Optional git push origin v1.X.0 ``` 5. **Create GitHub Release** with the changelog, ensure to point to the `deployments.json` for current addresses. -6. **Notify stakeholders** that the upgrade is complete. +6. **Notify stakeholders** that the upgrade is complete by updating the release issue and then resolve it. ## Stakeholder Communication From ea506df6970e6813b47ae51baa48e6a79a0db472 Mon Sep 17 00:00:00 2001 From: Phi Date: Sun, 1 Feb 2026 16:31:35 -0800 Subject: [PATCH 30/32] refactor: extract upgrade announcement logic into standalone script Move the issue creation logic from inline workflow JavaScript to a separate script at .github/scripts/create-upgrade-announcement.js. --- .../scripts/create-upgrade-announcement.js | 358 ++++++++++++++++++ .../create-upgrade-announcement-issue.yml | 153 ++------ 2 files changed, 392 insertions(+), 119 deletions(-) create mode 100644 .github/scripts/create-upgrade-announcement.js diff --git a/.github/scripts/create-upgrade-announcement.js b/.github/scripts/create-upgrade-announcement.js new file mode 100644 index 00000000..87e6d6b4 --- /dev/null +++ b/.github/scripts/create-upgrade-announcement.js @@ -0,0 +1,358 @@ +#!/usr/bin/env node +/** + * Create FWSS Contract Upgrade Announcement Issue + * + * Usage: + * node create-upgrade-announcement.js [options] + * + * Options: + * --dry-run Output issue text without creating an issue + * --help Show this help message + * + * Environment variables (required unless --dry-run with minimal output): + * NETWORK Target network (Calibnet or Mainnet) + * UPGRADE_TYPE Type of upgrade (Routine or Breaking Change) + * AFTER_EPOCH Block number after which upgrade can execute + * CHANGELOG_PR PR number with changelog updates + * CHANGES_SUMMARY Summary of changes (use | for multiple lines) + * ACTION_REQUIRED Action required for integrators (default: None) + * UPGRADE_FWSS Upgrading FilecoinWarmStorageService? (true/false) + * UPGRADE_REGISTRY Upgrading ServiceProviderRegistry? (true/false) + * UPGRADE_STATE_VIEW Upgrading FilecoinWarmStorageServiceStateView? (true/false) + * RELEASE_TAG Release tag if already created (optional) + * + * GitHub-specific environment variables (required when not using --dry-run): + * GITHUB_TOKEN GitHub token with issues:write permission + * GITHUB_REPOSITORY Repository in format owner/repo + */ + +const https = require("https"); + +// Parse command line arguments +const args = process.argv.slice(2); +const dryRun = args.includes("--dry-run"); +const showHelp = args.includes("--help") || args.includes("-h"); + +if (showHelp) { + console.log(` +Create FWSS Contract Upgrade Announcement Issue + +Usage: + node create-upgrade-announcement.js [options] + +Options: + --dry-run Output issue text without creating an issue + --help Show this help message + +Environment variables: + NETWORK Target network (Calibnet or Mainnet) + UPGRADE_TYPE Type of upgrade (Routine or Breaking Change) + AFTER_EPOCH Block number after which upgrade can execute + CHANGELOG_PR PR number with changelog updates + CHANGES_SUMMARY Summary of changes (use | for multiple lines) + ACTION_REQUIRED Action required for integrators (default: None) + UPGRADE_FWSS Upgrading FilecoinWarmStorageService? (true/false, default: true) + UPGRADE_REGISTRY Upgrading ServiceProviderRegistry? (true/false, default: false) + UPGRADE_STATE_VIEW Upgrading FilecoinWarmStorageServiceStateView? (true/false, default: false) + RELEASE_TAG Release tag if already created (optional) + GITHUB_TOKEN GitHub token (required when not using --dry-run) + GITHUB_REPOSITORY Repository in format owner/repo (required when not using --dry-run) + +Example: + NETWORK=Calibnet UPGRADE_TYPE=Routine AFTER_EPOCH=12345 \\ + CHANGELOG_PR=100 CHANGES_SUMMARY="Fix bug|Add feature" \\ + node create-upgrade-announcement.js --dry-run +`); + process.exit(0); +} + +// Get configuration from environment +const config = { + network: process.env.NETWORK, + upgradeType: process.env.UPGRADE_TYPE, + afterEpoch: process.env.AFTER_EPOCH, + changelogPr: process.env.CHANGELOG_PR, + changesSummary: process.env.CHANGES_SUMMARY, + actionRequired: process.env.ACTION_REQUIRED || "None", + upgradeFwss: process.env.UPGRADE_FWSS !== "false", + upgradeRegistry: process.env.UPGRADE_REGISTRY === "true", + upgradeStateView: process.env.UPGRADE_STATE_VIEW === "true", + releaseTag: process.env.RELEASE_TAG || "", + githubToken: process.env.GITHUB_TOKEN, + githubRepository: process.env.GITHUB_REPOSITORY, + // Optional: pre-computed time estimate (from workflow) + timeEstimate: process.env.TIME_ESTIMATE, +}; + +// Validate required fields +function validateConfig() { + const required = ["network", "upgradeType", "afterEpoch", "changelogPr", "changesSummary"]; + const missing = required.filter((key) => !config[key]); + + if (missing.length > 0) { + console.error(`Error: Missing required environment variables: ${missing.join(", ")}`); + console.error("Run with --help for usage information."); + process.exit(1); + } + + if (!dryRun) { + if (!config.githubToken) { + console.error("Error: GITHUB_TOKEN is required when not using --dry-run"); + process.exit(1); + } + if (!config.githubRepository) { + console.error("Error: GITHUB_REPOSITORY is required when not using --dry-run"); + process.exit(1); + } + } +} + +// Fetch current epoch from Filecoin RPC +async function getCurrentEpoch(network) { + const rpcUrl = + network === "Mainnet" + ? "https://api.node.glif.io/rpc/v1" + : "https://api.calibration.node.glif.io/rpc/v1"; + + return new Promise((resolve, reject) => { + const url = new URL(rpcUrl); + const postData = JSON.stringify({ + jsonrpc: "2.0", + method: "eth_blockNumber", + params: [], + id: 1, + }); + + const options = { + hostname: url.hostname, + path: url.pathname, + method: "POST", + headers: { + "Content-Type": "application/json", + "Content-Length": Buffer.byteLength(postData), + }, + }; + + const req = https.request(options, (res) => { + let data = ""; + res.on("data", (chunk) => (data += chunk)); + res.on("end", () => { + try { + const result = JSON.parse(data); + if (result.result) { + resolve(parseInt(result.result, 16)); + } else { + reject(new Error("Invalid RPC response")); + } + } catch (e) { + reject(e); + } + }); + }); + + req.on("error", reject); + req.write(postData); + req.end(); + }); +} + +// Calculate estimated execution time +async function calculateTimeEstimate(network, afterEpoch) { + // If pre-computed estimate is provided, use it + if (config.timeEstimate) { + return config.timeEstimate; + } + + try { + const currentEpoch = await getCurrentEpoch(network); + const epochsRemaining = afterEpoch - currentEpoch; + + if (epochsRemaining < 0) { + return "Immediately (epoch already passed)"; + } + + // Filecoin has ~30 second block times + const secondsRemaining = epochsRemaining * 30; + const hours = Math.floor(secondsRemaining / 3600); + const minutes = Math.floor((secondsRemaining % 3600) / 60); + + const futureDate = new Date(Date.now() + secondsRemaining * 1000); + const dateStr = futureDate.toISOString().replace("T", " ").substring(0, 16) + " UTC"; + + return `~${dateStr} (~${hours}h ${minutes}m from current epoch ${currentEpoch})`; + } catch (error) { + console.error("Warning: Could not fetch current epoch:", error.message); + return "Unknown (could not fetch current epoch)"; + } +} + +// Format changes summary from pipe-separated to bullet points +function formatChanges(changesSummary) { + return changesSummary + .split("|") + .map((line) => line.trim()) + .filter((line) => line.length > 0) + .map((line) => `- ${line}`) + .join("\n"); +} + +// Build the list of contracts being upgraded +function buildContractsList() { + const contracts = []; + + if (config.upgradeFwss) { + contracts.push("- FilecoinWarmStorageService"); + } + if (config.upgradeRegistry) { + contracts.push("- ServiceProviderRegistry"); + } + if (config.upgradeStateView) { + contracts.push("- FilecoinWarmStorageServiceStateView"); + } + + // Default to FilecoinWarmStorageService if none selected + if (contracts.length === 0) { + contracts.push("- FilecoinWarmStorageService"); + } + + return contracts.join("\n"); +} + +// Generate issue title +function generateTitle() { + return `[Upgrade] FWSS Contract - ${config.network} - Epoch ${config.afterEpoch}`; +} + +// Generate issue body +function generateBody(timeEstimate) { + const [owner, repo] = (config.githubRepository || "OWNER/REPO").split("/"); + const baseUrl = `https://github.com/${owner}/${repo}`; + + const changelogPrLink = `${baseUrl}/pull/${config.changelogPr}`; + const changelogLink = `${baseUrl}/blob/main/CHANGELOG.md`; + const upgradeProcessLink = `${baseUrl}/blob/main/service_contracts/tools/UPGRADE-PROCESS.md`; + const releaseLink = config.releaseTag ? `${baseUrl}/releases/tag/${config.releaseTag}` : null; + + const changes = formatChanges(config.changesSummary); + const contracts = buildContractsList(); + + return `## FWSS Contract Upgrade Announcement + +**Network**: ${config.network} +**Upgrade Type**: ${config.upgradeType} +**Scheduled Execution**: After epoch ${config.afterEpoch} (${timeEstimate}) + +### Changes +${changes} +- [Link to PR/release notes](${changelogPrLink}) + +### Contracts Planned for Upgrade +${contracts} + +### Action Required +${config.actionRequired} + +### Resources +${releaseLink ? `- Release: ${releaseLink}` : "- Release: [link] (if applicable)"} +- Changelog: ${changelogLink} +- Upgrade Process: ${upgradeProcessLink}`; +} + +// Generate labels for the issue +function generateLabels() { + const labels = ["upgrade"]; + if (config.upgradeType === "Breaking Change") { + labels.push("breaking-change"); + } + return labels; +} + +// Create GitHub issue +async function createGitHubIssue(title, body, labels) { + const [owner, repo] = config.githubRepository.split("/"); + + return new Promise((resolve, reject) => { + const postData = JSON.stringify({ title, body, labels }); + + const options = { + hostname: "api.github.com", + path: `/repos/${owner}/${repo}/issues`, + method: "POST", + headers: { + Authorization: `Bearer ${config.githubToken}`, + Accept: "application/vnd.github+json", + "Content-Type": "application/json", + "Content-Length": Buffer.byteLength(postData), + "User-Agent": "create-upgrade-announcement-script", + "X-GitHub-Api-Version": "2022-11-28", + }, + }; + + const req = https.request(options, (res) => { + let data = ""; + res.on("data", (chunk) => (data += chunk)); + res.on("end", () => { + try { + const result = JSON.parse(data); + if (res.statusCode === 201) { + resolve(result); + } else { + reject(new Error(`GitHub API error: ${res.statusCode} - ${result.message || data}`)); + } + } catch (e) { + reject(e); + } + }); + }); + + req.on("error", reject); + req.write(postData); + req.end(); + }); +} + +// Main execution +async function main() { + validateConfig(); + + const timeEstimate = await calculateTimeEstimate(config.network, parseInt(config.afterEpoch)); + const title = generateTitle(); + const body = generateBody(timeEstimate); + const labels = generateLabels(); + + if (dryRun) { + console.log("=== DRY RUN - Issue Preview ===\n"); + console.log(`Title: ${title}\n`); + console.log(`Labels: ${labels.join(", ")}\n`); + console.log("--- Body ---"); + console.log(body); + console.log("\n=== End of Preview ==="); + + // Output in GitHub Actions format if running in that context + if (process.env.GITHUB_OUTPUT) { + const fs = require("fs"); + fs.appendFileSync(process.env.GITHUB_OUTPUT, `title=${title}\n`); + fs.appendFileSync(process.env.GITHUB_OUTPUT, `labels=${labels.join(",")}\n`); + // For multiline body, use delimiter syntax + fs.appendFileSync(process.env.GITHUB_OUTPUT, `body<> $GITHUB_OUTPUT - else - SECONDS_REMAINING=$((EPOCHS_REMAINING * 30)) - HOURS=$((SECONDS_REMAINING / 3600)) - MINUTES=$(((SECONDS_REMAINING % 3600) / 60)) - - FUTURE_DATE=$(date -u -d "+${SECONDS_REMAINING} seconds" "+%Y-%m-%d %H:%M UTC" 2>/dev/null || \ - date -u -v+${SECONDS_REMAINING}S "+%Y-%m-%d %H:%M UTC" 2>/dev/null || \ - echo "~${HOURS}h ${MINUTES}m from now") - - echo "estimate=~${FUTURE_DATE} (~${HOURS}h ${MINUTES}m from current epoch ${CURRENT_EPOCH})" >> $GITHUB_OUTPUT + node .github/scripts/create-upgrade-announcement.js fi - - name: Format changes summary - id: format_changes - run: | - # Convert pipe-separated changes to bullet points - CHANGES=$(echo "${{ inputs.changes_summary }}" | sed 's/|/\n/g' | sed 's/^/- /' | sed '/^- $/d') - echo "changes<> $GITHUB_OUTPUT - echo "$CHANGES" >> $GITHUB_OUTPUT - echo "EOF" >> $GITHUB_OUTPUT - - - name: Create announcement issue - uses: actions/github-script@v7 - with: - script: | - const network = '${{ inputs.network }}'; - const upgradeType = '${{ inputs.upgrade_type }}'; - const afterEpoch = '${{ inputs.after_epoch }}'; - const changelogPr = '${{ inputs.changelog_pr }}'; - const releaseTag = '${{ inputs.release_tag }}'; - const actionRequired = '${{ inputs.action_required }}'; - const timeEstimate = `${{ steps.calc_time.outputs.estimate }}`; - const changes = `${{ steps.format_changes.outputs.changes }}`; - const upgradeFwss = '${{ inputs.upgrade_fwss }}' === 'true'; - const upgradeRegistry = '${{ inputs.upgrade_registry }}' === 'true'; - const upgradeStateView = '${{ inputs.upgrade_state_view }}' === 'true'; - - const releaseLink = releaseTag - ? `https://github.com/${context.repo.owner}/${context.repo.repo}/releases/tag/${releaseTag}` - : null; - - const changelogPrLink = `https://github.com/${context.repo.owner}/${context.repo.repo}/pull/${changelogPr}`; - const changelogLink = `https://github.com/${context.repo.owner}/${context.repo.repo}/blob/main/CHANGELOG.md`; - const upgradeProcessLink = `https://github.com/${context.repo.owner}/${context.repo.repo}/blob/main/service_contracts/tools/UPGRADE-PROCESS.md`; - - // Build contracts list - const contracts = []; - if (upgradeFwss) { - contracts.push('- FilecoinWarmStorageService'); - } - if (upgradeRegistry) { - contracts.push('- ServiceProviderRegistry'); - } - if (upgradeStateView) { - contracts.push('- FilecoinWarmStorageServiceStateView'); - } - // If none selected, default to FilecoinWarmStorageService - if (contracts.length === 0) { - contracts.push('- FilecoinWarmStorageService'); - } - - const body = `## FWSS Contract Upgrade Announcement - -**Network**: ${network} -**Upgrade Type**: ${upgradeType} -**Scheduled Execution**: After epoch ${afterEpoch} (${timeEstimate}) - -### Changes -${changes} -- [Link to PR/release notes](${changelogPrLink}) - -### Contracts Planned for Upgrade -${contracts.join('\n')} - -### Action Required -${actionRequired} - -### Resources -${releaseLink ? `- Release: ${releaseLink}` : '- Release: [link] (if applicable)'} -- Changelog: ${changelogLink} -- Upgrade Process: ${upgradeProcessLink} -`.split('\n').map(line => line.trim()).join('\n'); - - const labels = ['upgrade']; - if (upgradeType === 'Breaking Change') { - labels.push('breaking-change'); - } - - const issue = await github.rest.issues.create({ - owner: context.repo.owner, - repo: context.repo.repo, - title: `[Upgrade] FWSS Contract - ${network} - Epoch ${afterEpoch}`, - body: body, - labels: labels - }); - - console.log(`Created issue #${issue.data.number}: ${issue.data.html_url}`); - core.setOutput('issue_number', issue.data.number); - core.setOutput('issue_url', issue.data.html_url); - - name: Summary run: | - echo "## Upgrade Announcement Created" >> $GITHUB_STEP_SUMMARY + echo "## Upgrade Announcement ${{ inputs.dry_run == true && '(Dry Run)' || 'Created' }}" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "**Network**: ${{ inputs.network }}" >> $GITHUB_STEP_SUMMARY echo "**After Epoch**: ${{ inputs.after_epoch }}" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY - echo "See the created issue for full details." >> $GITHUB_STEP_SUMMARY + if [ "${{ inputs.dry_run }}" = "true" ]; then + echo "This was a dry run. No issue was created." >> $GITHUB_STEP_SUMMARY + else + echo "See the created issue for full details." >> $GITHUB_STEP_SUMMARY + fi From 08942c1e29173775440807727f4d461276c25b7c Mon Sep 17 00:00:00 2001 From: Phi Date: Wed, 4 Feb 2026 08:31:05 +0100 Subject: [PATCH 31/32] refactor: consolidate upgrade announcement into release issue format - Update script to generate combined release issue with user-facing info at top and release engineer checklist below (Lotus-style) - Simplify UPGRADE-PROCESS.md to focus on FWSS as the primary path - Move ServiceProviderRegistry and StateView to separate "Upgrading Other Contracts" section since they are rarely upgraded - Remove upgrade_fwss workflow input (FWSS always included) - Mark Registry/StateView inputs as "(Rare)" in workflow - Align script section headers with UPGRADE-PROCESS.md Co-Authored-By: Claude Opus 4.5 --- .../scripts/create-upgrade-announcement.js | 174 ++++++++--- .../create-upgrade-announcement-issue.yml | 14 +- service_contracts/tools/UPGRADE-PROCESS.md | 283 +++++++++--------- 3 files changed, 290 insertions(+), 181 deletions(-) diff --git a/.github/scripts/create-upgrade-announcement.js b/.github/scripts/create-upgrade-announcement.js index 87e6d6b4..93615736 100644 --- a/.github/scripts/create-upgrade-announcement.js +++ b/.github/scripts/create-upgrade-announcement.js @@ -1,6 +1,9 @@ #!/usr/bin/env node /** - * Create FWSS Contract Upgrade Announcement Issue + * Create FWSS Contract Upgrade Release Issue + * + * Generates a release issue that combines user-facing upgrade information + * with a release engineer checklist (similar to Lotus release issues). * * Usage: * node create-upgrade-announcement.js [options] @@ -16,9 +19,8 @@ * CHANGELOG_PR PR number with changelog updates * CHANGES_SUMMARY Summary of changes (use | for multiple lines) * ACTION_REQUIRED Action required for integrators (default: None) - * UPGRADE_FWSS Upgrading FilecoinWarmStorageService? (true/false) - * UPGRADE_REGISTRY Upgrading ServiceProviderRegistry? (true/false) - * UPGRADE_STATE_VIEW Upgrading FilecoinWarmStorageServiceStateView? (true/false) + * UPGRADE_REGISTRY Also upgrading ServiceProviderRegistry? (true/false, rare) + * UPGRADE_STATE_VIEW Also redeploying FilecoinWarmStorageServiceStateView? (true/false, rare) * RELEASE_TAG Release tag if already created (optional) * * GitHub-specific environment variables (required when not using --dry-run): @@ -35,7 +37,7 @@ const showHelp = args.includes("--help") || args.includes("-h"); if (showHelp) { console.log(` -Create FWSS Contract Upgrade Announcement Issue +Create FWSS Contract Upgrade Release Issue Usage: node create-upgrade-announcement.js [options] @@ -51,10 +53,9 @@ Environment variables: CHANGELOG_PR PR number with changelog updates CHANGES_SUMMARY Summary of changes (use | for multiple lines) ACTION_REQUIRED Action required for integrators (default: None) - UPGRADE_FWSS Upgrading FilecoinWarmStorageService? (true/false, default: true) - UPGRADE_REGISTRY Upgrading ServiceProviderRegistry? (true/false, default: false) - UPGRADE_STATE_VIEW Upgrading FilecoinWarmStorageServiceStateView? (true/false, default: false) - RELEASE_TAG Release tag if already created (optional) + UPGRADE_REGISTRY Also upgrading ServiceProviderRegistry? (true/false, default: false, rare) + UPGRADE_STATE_VIEW Also redeploying StateView? (true/false, default: false, rare) + RELEASE_TAG Release tag (optional, usually added after upgrade completes) GITHUB_TOKEN GitHub token (required when not using --dry-run) GITHUB_REPOSITORY Repository in format owner/repo (required when not using --dry-run) @@ -74,7 +75,6 @@ const config = { changelogPr: process.env.CHANGELOG_PR, changesSummary: process.env.CHANGES_SUMMARY, actionRequired: process.env.ACTION_REQUIRED || "None", - upgradeFwss: process.env.UPGRADE_FWSS !== "false", upgradeRegistry: process.env.UPGRADE_REGISTRY === "true", upgradeStateView: process.env.UPGRADE_STATE_VIEW === "true", releaseTag: process.env.RELEASE_TAG || "", @@ -196,31 +196,23 @@ function formatChanges(changesSummary) { .join("\n"); } -// Build the list of contracts being upgraded +// Build the list of contracts being upgraded (FWSS is always included) function buildContractsList() { - const contracts = []; + const contracts = ["FilecoinWarmStorageService"]; - if (config.upgradeFwss) { - contracts.push("- FilecoinWarmStorageService"); - } if (config.upgradeRegistry) { - contracts.push("- ServiceProviderRegistry"); + contracts.push("ServiceProviderRegistry"); } if (config.upgradeStateView) { - contracts.push("- FilecoinWarmStorageServiceStateView"); - } - - // Default to FilecoinWarmStorageService if none selected - if (contracts.length === 0) { - contracts.push("- FilecoinWarmStorageService"); + contracts.push("FilecoinWarmStorageServiceStateView"); } - return contracts.join("\n"); + return contracts; } // Generate issue title function generateTitle() { - return `[Upgrade] FWSS Contract - ${config.network} - Epoch ${config.afterEpoch}`; + return `[Release] FWSS ${config.network} Upgrade - Epoch ${config.afterEpoch}`; } // Generate issue body @@ -235,32 +227,140 @@ function generateBody(timeEstimate) { const changes = formatChanges(config.changesSummary); const contracts = buildContractsList(); + const isMainnet = config.network === "Mainnet"; + const isBreaking = config.upgradeType === "Breaking Change"; + + // Build contracts checklist for the release checklist section + const deployChecklist = contracts + .map((c) => { + if (c === "FilecoinWarmStorageService") { + return "- [ ] Deploy FWSS implementation: `./deploy-warm-storage-implementation-only.sh`"; + } else if (c === "ServiceProviderRegistry") { + return "- [ ] Deploy Registry implementation: `./deploy-registry.sh`"; + } else if (c === "FilecoinWarmStorageServiceStateView") { + return "- [ ] Deploy StateView: `./deploy-warm-storage-view.sh`"; + } + return `- [ ] Deploy ${c}`; + }) + .join("\n"); + + const announceChecklist = contracts + .map((c) => { + if (c === "FilecoinWarmStorageService") { + return "- [ ] Announce FWSS upgrade: `./announce-planned-upgrade.sh`"; + } else if (c === "ServiceProviderRegistry") { + return "- [ ] Announce Registry upgrade: `./announce-planned-upgrade-registry.sh`"; + } + return null; + }) + .filter(Boolean) + .join("\n"); - return `## FWSS Contract Upgrade Announcement + const executeChecklist = contracts + .map((c) => { + if (c === "FilecoinWarmStorageService") { + return "- [ ] Execute FWSS upgrade: `./upgrade.sh`"; + } else if (c === "ServiceProviderRegistry") { + return "- [ ] Execute Registry upgrade: `./upgrade-registry.sh`"; + } + return null; + }) + .filter(Boolean) + .join("\n"); -**Network**: ${config.network} -**Upgrade Type**: ${config.upgradeType} -**Scheduled Execution**: After epoch ${config.afterEpoch} (${timeEstimate}) + return `## Overview + +| Field | Value | +|-------|-------| +| **Network** | ${config.network} | +| **Upgrade Type** | ${config.upgradeType} | +| **Target Epoch** | ${config.afterEpoch} | +| **Estimated Execution** | ${timeEstimate} | +| **Changelog PR** | ${changelogPrLink} | +${releaseLink ? `| **Release** | ${releaseLink} |` : ""} + +### Contracts in Scope +${contracts.map((c) => `- ${c}`).join("\n")} ### Changes ${changes} -- [Link to PR/release notes](${changelogPrLink}) - -### Contracts Planned for Upgrade -${contracts} -### Action Required +### Action Required for Integrators ${config.actionRequired} +--- + +## Release Checklist + +> Full process details: [UPGRADE-PROCESS.md](${upgradeProcessLink}) + +### Phase 1: Prepare +- [ ] Changelog entry prepared in [CHANGELOG.md](${changelogLink}) +- [ ] Version string updated in contracts (if applicable) +- [ ] Upgrade PR created: #${config.changelogPr} +${isBreaking ? "- [ ] Migration guide prepared for breaking changes" : ""} + +### Phase 2: Calibnet Rehearsal +${isMainnet ? `
+Calibnet steps (expand) + +` : ""}**Deploy Implementation** +${deployChecklist} +- [ ] Commit updated \`deployments.json\` + +**Announce Upgrade** +${announceChecklist} + +**Execute Upgrade** +${executeChecklist} +- [ ] Verify on Blockscout +${isMainnet ? ` +
+` : ""} +${ + isMainnet + ? `### Phase 3: Mainnet Deployment +${deployChecklist} +- [ ] Commit updated \`deployments.json\` + +### Phase 4: Announce Mainnet Upgrade +${announceChecklist} +- [ ] Notify stakeholders (post in relevant channels) + +### Phase 5: Execute Mainnet Upgrade +> ⏳ Wait until after epoch ${config.afterEpoch} + +${executeChecklist} +- [ ] Verify on Blockscout +` + : "" +} +### Phase ${isMainnet ? "6" : "3"}: Verify and Release +- [ ] Verify upgrade on Blockscout +- [ ] Confirm \`deployments.json\` is up to date +- [ ] Merge changelog PR: #${config.changelogPr} +- [ ] Tag release: \`git tag vX.Y.Z && git push origin vX.Y.Z\` +- [ ] Create GitHub Release with changelog +- [ ] Update this issue with release link +- [ ] Close this issue + +--- + ### Resources -${releaseLink ? `- Release: ${releaseLink}` : "- Release: [link] (if applicable)"} -- Changelog: ${changelogLink} -- Upgrade Process: ${upgradeProcessLink}`; +- [Changelog](${changelogLink}) +- [Upgrade Process Documentation](${upgradeProcessLink}) +${releaseLink ? `- [Release](${releaseLink})` : ""} + +### Deployed Addresses + +| Contract | Network | Address | +|----------|---------|---------| +| | | |`; } // Generate labels for the issue function generateLabels() { - const labels = ["upgrade"]; + const labels = ["release"]; if (config.upgradeType === "Breaking Change") { labels.push("breaking-change"); } diff --git a/.github/workflows/create-upgrade-announcement-issue.yml b/.github/workflows/create-upgrade-announcement-issue.yml index 31c54cb8..bf3ede2e 100644 --- a/.github/workflows/create-upgrade-announcement-issue.yml +++ b/.github/workflows/create-upgrade-announcement-issue.yml @@ -1,4 +1,4 @@ -name: Create Upgrade Announcement +name: Create Release Issue on: workflow_dispatch: @@ -17,18 +17,13 @@ on: options: - Routine - Breaking Change - upgrade_fwss: - description: 'Upgrading FilecoinWarmStorageService?' - required: false - type: boolean - default: true upgrade_registry: - description: 'Upgrading ServiceProviderRegistry?' + description: '(Rare) Also upgrading ServiceProviderRegistry?' required: false type: boolean default: false upgrade_state_view: - description: 'Upgrading FilecoinWarmStorageServiceStateView?' + description: '(Rare) Also redeploying FilecoinWarmStorageServiceStateView?' required: false type: boolean default: false @@ -78,7 +73,6 @@ jobs: env: NETWORK: ${{ inputs.network }} UPGRADE_TYPE: ${{ inputs.upgrade_type }} - UPGRADE_FWSS: ${{ inputs.upgrade_fwss }} UPGRADE_REGISTRY: ${{ inputs.upgrade_registry }} UPGRADE_STATE_VIEW: ${{ inputs.upgrade_state_view }} AFTER_EPOCH: ${{ inputs.after_epoch }} @@ -97,7 +91,7 @@ jobs: - name: Summary run: | - echo "## Upgrade Announcement ${{ inputs.dry_run == true && '(Dry Run)' || 'Created' }}" >> $GITHUB_STEP_SUMMARY + echo "## Release Issue ${{ inputs.dry_run == true && '(Dry Run)' || 'Created' }}" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "**Network**: ${{ inputs.network }}" >> $GITHUB_STEP_SUMMARY echo "**After Epoch**: ${{ inputs.after_epoch }}" >> $GITHUB_STEP_SUMMARY diff --git a/service_contracts/tools/UPGRADE-PROCESS.md b/service_contracts/tools/UPGRADE-PROCESS.md index 9b2719e7..db6292e9 100644 --- a/service_contracts/tools/UPGRADE-PROCESS.md +++ b/service_contracts/tools/UPGRADE-PROCESS.md @@ -1,105 +1,81 @@ # FWSS Contract Upgrade Process -This document describes the upgrade process for FilecoinWarmStorageService (FWSS) and related contracts, organized as a phase-based runbook. +This document describes the upgrade process for FilecoinWarmStorageService (FWSS), organized as a phase-based runbook. Most upgrades only involve the FWSS implementation contract. -## Contract Upgradeability Overview +## Contract Overview -| Contract | Proxy Pattern | Upgrade Method | -|----------|---------------|----------------| -| FilecoinWarmStorageService (FWSS) | UUPS Proxy (two-step) | `announce-planned-upgrade.sh` + `upgrade.sh` | -| ServiceProviderRegistry | UUPS Proxy (two-step) | `announce-planned-upgrade-registry.sh` + `upgrade-registry.sh` | -| PDPVerifier | ERC1967 Proxy | Via [pdp repo](https://github.com/FilOzone/pdp) scripts | -| FilecoinPayV1 | None (immutable) | Not expected to be redeployed | -| SessionKeyRegistry | None (immutable) | Not expected to be redeployed | -| FilecoinWarmStorageServiceStateView | None (helper) | Redeployable via `deploy-warm-storage-view.sh` | +| Contract | Upgradeable? | Notes | +|----------|--------------|-------| +| **FilecoinWarmStorageService (FWSS)** | Yes (UUPS, two-step) | Primary contract, most upgrades are here | +| ServiceProviderRegistry | Yes (UUPS, two-step) | Rarely upgraded separately | +| FilecoinWarmStorageServiceStateView | No (redeploy) | Helper contract, redeploy if view logic changes | +| PDPVerifier | Yes (ERC1967) | Via [pdp repo](https://github.com/FilOzone/pdp) | +| FilecoinPayV1, SessionKeyRegistry | No (immutable) | Not expected to change | -## Immutable Dependencies +> For upgrading ServiceProviderRegistry or redeploying StateView, see [Upgrading Other Contracts](#upgrading-other-contracts). -FWSS stores several dependencies as `immutable` constructor parameters: +## Two-Step Upgrade Mechanism -```solidity -IPDPVerifier public immutable pdpVerifier; -FilecoinPayV1 public immutable paymentsContract; -IERC20Metadata public immutable usdfcTokenAddress; -address public immutable filBeamBeneficiaryAddress; -ServiceProviderRegistry public immutable serviceProviderRegistry; -SessionKeyRegistry public immutable sessionKeyRegistry; -``` - -These immutable contracts are **not expected to be redeployed** under normal operations. If redeployment becomes necessary, announce it well ahead of time and follow the standard two-step upgrade process with an extended notice period. - -## Two-Step Upgrade Process - -Both FWSS and ServiceProviderRegistry use a two-step upgrade mechanism: +FWSS uses a two-step upgrade to give stakeholders notice: 1. **Announce** - Call `announcePlannedUpgrade()` with the new implementation address and `AFTER_EPOCH` -2. **Execute** - After `AFTER_EPOCH` has passed, call `upgradeToAndCall()` to complete the upgrade +2. **Execute** - After `AFTER_EPOCH` passes, call `upgradeToAndCall()` to complete the upgrade ## Choosing AFTER_EPOCH -When announcing an upgrade, choose `AFTER_EPOCH` to give stakeholders adequate notice: - | Upgrade Type | Minimum Notice | Recommended | |--------------|----------------|-------------| -| Routine (bug fixes, minor features) | ~24 hours (~5760 epochs) | 1-2 days | +| Routine (bug fixes, minor features) | ~24 hours (~2880 epochs) | 1-2 days | | Breaking changes | ~1 week (~20160 epochs) | 1-2 weeks | -| Immutable dependency changes | ~2 weeks (~40320 epochs) | 2-4 weeks | - -For quickly calculating an `AFTER_EPOCH`, one can use the following snippet: +Calculate an `AFTER_EPOCH`: ```bash -UPGRADE_WAIT_DURATION_EPOCHS=5760 +UPGRADE_WAIT_DURATION_EPOCHS=2880 # ~24 hours CURRENT_EPOCH=$(cast block-number --rpc-url "$ETH_RPC_URL") -AFTER_EPOCH=$((CURRENT_EPOCH + $UPGRADE_WAIT_DURATION_EPOCHS)) +AFTER_EPOCH=$((CURRENT_EPOCH + UPGRADE_WAIT_DURATION_EPOCHS)) echo "Current: $CURRENT_EPOCH, Upgrade after: $AFTER_EPOCH" +``` -Considerations: +**Considerations:** - Allow time for stakeholder review - Avoid weekends/holidays for mainnet upgrades - Calibnet can use shorter notice periods for testing -## Phase 0: Decide Scope - -1. Identify which contracts are changing: - - FWSS implementation - - ServiceProviderRegistry implementation - - StateView contract (typically for breaking changes in the view) -2. If the change is breaking (including breaking changes to dependencies) , plan for longer notice and a migration guide. +--- ## Phase 1: Prepare 1. **Prepare changelog entry** in [`CHANGELOG.md`](../../CHANGELOG.md): - - Document all changes since last release (https://github.com/FilOzone/filecoin-services/releases) + - Document all changes since [last release](https://github.com/FilOzone/filecoin-services/releases) - Mark breaking changes clearly - Include migration notes if needed -2. **Update the version** string in the contracts if applicable. -3. **Create an "upgrade PR"** with your changelog updates. - - Name the pull request clearly, e.g. `feat: FWSS v1.2.0 upgrade (mainnet)` or `feat: ServiceProviderRegistry patch`. -4. **Create tracking issue** using the [Create Upgrade Announcement](https://github.com/FilOzone/filecoin-services/actions/workflows/upgrade-announcement.yml) GitHub Action + +2. **Update the version** string in the contract if applicable. + +3. **Create an upgrade PR** with your changelog updates. + - Example title: `feat: FWSS v1.2.0 upgrade` + +4. **Create release issue** using the [Create Release Issue](https://github.com/FilOzone/filecoin-services/actions/workflows/create-upgrade-announcement-issue.yml) GitHub Action. + - Or preview locally: `node .github/scripts/create-upgrade-announcement.js --dry-run` ## Phase 2: Calibnet Rehearsal Always test the upgrade on Calibnet before mainnet. -### Deploy Implementations (Calibnet) +### Deploy Implementation -FWSS implementation: ```bash +cd service_contracts/tools +export ETH_RPC_URL="https://api.calibration.node.glif.io/rpc/v1" + ./deploy-warm-storage-implementation-only.sh ``` -Other contracts you might deploy during a upgrade can be: - -- ServiceProviderRegistry: `./deploy-registry.sh` -- FilecoinWarmStorageStateView: `./deploy-warm-storage-view.sh` +The script updates `deployments.json` automatically. Commit the changes. -`deployments.json` is updated automatically by the scripts. Commit the updated file in the upgrade PR and document the new addresses in PR comments for traceability. - - -### Announce and Execute (Calibnet) +### Announce Upgrade ```bash -export ETH_RPC_URL="https://api.calibration.node.glif.io/rpc/v1" export WARM_STORAGE_PROXY_ADDRESS="0x..." export NEW_WARM_STORAGE_IMPLEMENTATION_ADDRESS="0x..." export AFTER_EPOCH="123456" @@ -107,114 +83,163 @@ export AFTER_EPOCH="123456" ./announce-planned-upgrade.sh ``` -After `AFTER_EPOCH`, execute: +### Execute Upgrade + +After `AFTER_EPOCH` passes: + ```bash -export ETH_RPC_URL="https://api.calibration.node.glif.io/rpc/v1" export WARM_STORAGE_PROXY_ADDRESS="0x..." export NEW_WARM_STORAGE_IMPLEMENTATION_ADDRESS="0x..." ./upgrade.sh ``` +Verify the upgrade on [Calibnet Blockscout](https://calibration.filfox.info/). + ## Phase 3: Mainnet Deployment -1. Deploy registry implementation (if needed): - ```bash - ./deploy-registry.sh - ``` -2. Deploy FWSS implementation: - ```bash - ./deploy-warm-storage-implementation-only.sh - ``` -3. Deploy StateView (if needed): - ```bash - ./deploy-warm-storage-view.sh - ``` +```bash +cd service_contracts/tools +export ETH_RPC_URL="https://api.node.glif.io/rpc/v1" -`deployments.json` is updated automatically by the scripts. Commit the updated file in the upgrade PR and document the new addresses in PR comments for traceability. +./deploy-warm-storage-implementation-only.sh +``` -## Phase 4: Announce the Mainnet Upgrade +Commit the updated `deployments.json`. -1. Choose `AFTER_EPOCH` based on the upgrade type. -2. Announce on-chain: - ```bash - export ETH_RPC_URL="https://api.node.glif.io/rpc/v1" - export WARM_STORAGE_PROXY_ADDRESS="0x..." - export NEW_WARM_STORAGE_IMPLEMENTATION_ADDRESS="0x..." - export AFTER_EPOCH="123456" +## Phase 4: Announce Mainnet Upgrade - ./announce-planned-upgrade.sh - ``` -4. Notify stakeholders per [Stakeholder Communication](#stakeholder-communication). +```bash +export ETH_RPC_URL="https://api.node.glif.io/rpc/v1" +export WARM_STORAGE_PROXY_ADDRESS="0x..." +export NEW_WARM_STORAGE_IMPLEMENTATION_ADDRESS="0x..." +export AFTER_EPOCH="123456" + +./announce-planned-upgrade.sh +``` -## Phase 5: Execute the Mainnet Upgrade +Notify stakeholders (see [Stakeholder Communication](#stakeholder-communication)). -After `AFTER_EPOCH`, execute: +## Phase 5: Execute Mainnet Upgrade + +After `AFTER_EPOCH` passes: ```bash export ETH_RPC_URL="https://api.node.glif.io/rpc/v1" export WARM_STORAGE_PROXY_ADDRESS="0x..." export NEW_WARM_STORAGE_IMPLEMENTATION_ADDRESS="0x..." -export NEW_WARM_STORAGE_VIEW_ADDRESS="0x..." # Optional ./upgrade.sh ``` ## Phase 6: Verify and Release -1. **Verify** upgrades on Blockscout. -2. **Confirm** `deployments.json` was updated (automatic via script). +1. **Verify** the upgrade on [Mainnet Blockscout](https://filfox.info/). +2. **Confirm** `deployments.json` is up to date. 3. **Merge** the changelog PR. -4. **Tag release** in GitHub (post-upgrade): +4. **Tag release**: ```bash git tag v1.X.0 git push origin v1.X.0 ``` -5. **Create GitHub Release** with the changelog, ensure to point to the `deployments.json` for current addresses. -6. **Notify stakeholders** that the upgrade is complete by updating the release issue and then resolve it. +5. **Create GitHub Release** with the changelog. +6. **Close the release issue** after updating it with the release link. + +--- ## Stakeholder Communication -> **Tip**: Use the [Create Upgrade Announcement](../../.github/workflows/upgrade-announcement.yml) GitHub Action to automatically generate an announcement issue. Go to **Actions → Create Upgrade Announcement → Run workflow**. +> **Tip**: Use the [Create Release Issue](https://github.com/FilOzone/filecoin-services/actions/workflows/create-upgrade-announcement-issue.yml) GitHub Action to generate a release issue. Go to **Actions → Create Release Issue → Run workflow**. + +The release issue serves as both the public announcement and the release engineer's checklist. It includes: +- Overview with network, epoch, estimated time, and changelog link +- Summary of changes and action required for integrators +- Full release checklist with all phases +- Deployed addresses table (filled in during the process) + +### Breaking Changes + +For breaking API changes: +- Provide extended notice period (1-2 weeks recommended) +- Create a migration guide for affected integrators +- Consider phased rollout: Calibnet first, then Mainnet after validation + +--- + +## Upgrading Other Contracts + +Most upgrades only involve FWSS. This section covers the rare cases where you need to upgrade other contracts. + +### ServiceProviderRegistry + +The registry uses the same two-step upgrade mechanism as FWSS. Only upgrade it when: +- There are changes to provider registration logic +- Storage or validation rules need updating -### Upgrade Announcement Template +**Deploy new implementation:** +```bash +./deploy-registry.sh +``` + +**Announce upgrade:** +```bash +export REGISTRY_PROXY_ADDRESS="0x..." +export NEW_REGISTRY_IMPLEMENTATION_ADDRESS="0x..." +export AFTER_EPOCH="123456" -> **Automated**: The GitHub Action generates this template as an issue automatically. +./announce-planned-upgrade-registry.sh +``` -When communicating an upgrade, include: +**Execute upgrade (after AFTER_EPOCH):** +```bash +export SERVICE_PROVIDER_REGISTRY_PROXY_ADDRESS="0x..." +export NEW_REGISTRY_IMPLEMENTATION_ADDRESS="0x..." +./upgrade-registry.sh ``` -## FWSS Contract Upgrade Announcement -**Network**: [Mainnet/Calibnet] -**Upgrade Type**: [Routine/Breaking Change] -**Scheduled Execution**: After epoch [AFTER_EPOCH] (~[estimated date/time]) +**Environment variables:** -### Changes -- [Summary of changes] -- [Link to PR/release notes] +| Variable | Description | +|----------|-------------| +| `REGISTRY_PROXY_ADDRESS` | Address of registry proxy (for announce script) | +| `SERVICE_PROVIDER_REGISTRY_PROXY_ADDRESS` | Address of registry proxy (for upgrade script) | +| `NEW_REGISTRY_IMPLEMENTATION_ADDRESS` | Address of new implementation | +| `AFTER_EPOCH` | Block number after which upgrade can execute | -### Contracts Planned for Upgrade -- FilecoinWarmStorageService -- ServiceProviderRegistry (if applicable) -- FilecoinWarmStorageServiceStateView (if applicable) +### FilecoinWarmStorageServiceStateView -### Action Required -[None / Describe any required actions for integrators] +StateView is a helper contract (not upgradeable). Redeploy it when: +- The view logic changes +- FWSS changes require updated read functions -### Resources -- Release: [link] (if applicable) -- Changelog: [link] -- Upgrade Process: [link to this document] +**Deploy new StateView:** +```bash +./deploy-warm-storage-view.sh ``` -### Breaking Changes Communication +**Update FWSS to use new StateView (during upgrade):** +```bash +export NEW_WARM_STORAGE_VIEW_ADDRESS="0x..." +./upgrade.sh +``` -For upgrades involving immutable dependency changes or breaking API changes: -- Provide extended notice period -- Create a migration guide for affected integrators -- Offer a support channel for questions during migration -- Consider phased rollout: Calibnet first, then Mainnet after validation +### Immutable Dependencies + +FWSS has these immutable dependencies that are **not expected to change**: + +```solidity +IPDPVerifier public immutable pdpVerifier; +FilecoinPayV1 public immutable paymentsContract; +IERC20Metadata public immutable usdfcTokenAddress; +address public immutable filBeamBeneficiaryAddress; +ServiceProviderRegistry public immutable serviceProviderRegistry; +SessionKeyRegistry public immutable sessionKeyRegistry; +``` + +If any of these need to change, it requires redeploying FWSS entirely. This should be announced well in advance (~2-4 weeks) with a migration plan. + +--- ## Environment Variables Reference @@ -222,33 +247,23 @@ For upgrades involving immutable dependency changes or breaking API changes: | Variable | Description | |----------|-------------| -| `ETH_RPC_URL` | RPC endpoint (e.g., `https://api.calibration.node.glif.io/rpc/v1`) | +| `ETH_RPC_URL` | RPC endpoint | | `ETH_KEYSTORE` | Path to Ethereum keystore file | | `PASSWORD` | Keystore password | | `CHAIN` | Chain ID (auto-detected if not set) | -### FWSS Upgrade Variables +### FWSS Variables | Variable | Description | |----------|-------------| | `WARM_STORAGE_PROXY_ADDRESS` | Address of FWSS proxy contract | | `NEW_WARM_STORAGE_IMPLEMENTATION_ADDRESS` | Address of new implementation | | `AFTER_EPOCH` | Block number after which upgrade can execute | -| `NEW_WARM_STORAGE_VIEW_ADDRESS` | (Optional) New StateView address | - -### Registry Upgrade Variables - -| Variable | Description | -|----------|-------------| -| `SERVICE_PROVIDER_REGISTRY_PROXY_ADDRESS` | Address of registry proxy | -| `REGISTRY_PROXY_ADDRESS` | Same as above (used by announce script) | -| `NEW_REGISTRY_IMPLEMENTATION_ADDRESS` | Address of new implementation | -| `AFTER_EPOCH` | Block number after which upgrade can execute | -| `NEW_VERSION` | (Optional) Version string for migrate() | +| `NEW_WARM_STORAGE_VIEW_ADDRESS` | (Optional) New StateView address to set during upgrade | ## Deployment Address Management -All deployment scripts automatically load and update addresses in `deployments.json`. See the main [README.md](./README.md) for details on: +All deployment scripts automatically load and update addresses in `deployments.json`. See [README.md](./README.md) for details on: - How addresses are loaded by chain ID - Environment variable overrides From f8ffc6aba9bd6ba01bb65bca1bef0dabb1dbe7e9 Mon Sep 17 00:00:00 2001 From: Phi Date: Fri, 6 Feb 2026 12:16:22 +0100 Subject: [PATCH 32/32] chore: address PR review comments chore: address PR review comments --- .../scripts/create-upgrade-announcement.js | 24 +++---------------- service_contracts/tools/README.md | 2 +- service_contracts/tools/UPGRADE-PROCESS.md | 8 ++++--- 3 files changed, 9 insertions(+), 25 deletions(-) diff --git a/.github/scripts/create-upgrade-announcement.js b/.github/scripts/create-upgrade-announcement.js index 93615736..12bdb98d 100644 --- a/.github/scripts/create-upgrade-announcement.js +++ b/.github/scripts/create-upgrade-announcement.js @@ -5,27 +5,7 @@ * Generates a release issue that combines user-facing upgrade information * with a release engineer checklist (similar to Lotus release issues). * - * Usage: - * node create-upgrade-announcement.js [options] - * - * Options: - * --dry-run Output issue text without creating an issue - * --help Show this help message - * - * Environment variables (required unless --dry-run with minimal output): - * NETWORK Target network (Calibnet or Mainnet) - * UPGRADE_TYPE Type of upgrade (Routine or Breaking Change) - * AFTER_EPOCH Block number after which upgrade can execute - * CHANGELOG_PR PR number with changelog updates - * CHANGES_SUMMARY Summary of changes (use | for multiple lines) - * ACTION_REQUIRED Action required for integrators (default: None) - * UPGRADE_REGISTRY Also upgrading ServiceProviderRegistry? (true/false, rare) - * UPGRADE_STATE_VIEW Also redeploying FilecoinWarmStorageServiceStateView? (true/false, rare) - * RELEASE_TAG Release tag if already created (optional) - * - * GitHub-specific environment variables (required when not using --dry-run): - * GITHUB_TOKEN GitHub token with issues:write permission - * GITHUB_REPOSITORY Repository in format owner/repo + * See help text below for more info. */ const https = require("https"); @@ -341,6 +321,8 @@ ${executeChecklist} - [ ] Merge changelog PR: #${config.changelogPr} - [ ] Tag release: \`git tag vX.Y.Z && git push origin vX.Y.Z\` - [ ] Create GitHub Release with changelog +- [ ] Merge auto-generated PRs in [filecoin-cloud](https://github.com/FilOzone/filecoin-cloud/pulls) so docs.filecoin.cloud and filecoin.cloud reflect new contract versions +- [ ] Create "Upgrade Synapse to use newest contracts" issue - [ ] Update this issue with release link - [ ] Close this issue diff --git a/service_contracts/tools/README.md b/service_contracts/tools/README.md index 3a9e847e..04cbb0ae 100644 --- a/service_contracts/tools/README.md +++ b/service_contracts/tools/README.md @@ -8,7 +8,7 @@ This directory contains scripts for deploying and upgrading the FilecoinWarmStor ### Deployment Scripts -- `deploy-warm-storage-calibnet.sh` - Deploy FilecoinWarmStorageService only (requires existing PDPVerifier and FilecoinPayV1 contracts) +- `deploy-warm-storage-calibnet.sh` - Deploy FilecoinWarmStorageService to **Calibnet only** (deploys both the ERC1967 proxy and implementation, plus the SignatureVerificationLib library; requires existing PDPVerifier, FilecoinPayV1, FilBeam, SessionKeyRegistry, and ServiceProviderRegistry contracts) - `deploy-warm-storage-implementation-only.sh` - Deploy FWSS implementation only; loads defaults from `deployments.json` and writes back new implementation + metadata (reuses existing signature lib unless redeployed) - `deploy-all-warm-storage.sh` - Deploy all contracts to either Calibnet or Mainnet diff --git a/service_contracts/tools/UPGRADE-PROCESS.md b/service_contracts/tools/UPGRADE-PROCESS.md index db6292e9..be19b33b 100644 --- a/service_contracts/tools/UPGRADE-PROCESS.md +++ b/service_contracts/tools/UPGRADE-PROCESS.md @@ -12,6 +12,8 @@ This document describes the upgrade process for FilecoinWarmStorageService (FWSS | PDPVerifier | Yes (ERC1967) | Via [pdp repo](https://github.com/FilOzone/pdp) | | FilecoinPayV1, SessionKeyRegistry | No (immutable) | Not expected to change | +**UUPS, two-step** — These contracts use the [UUPS (ERC-1822)](https://eips.ethereum.org/EIPS/eip-1822) proxy pattern via OpenZeppelin's `UUPSUpgradeable`, where the upgrade authorization logic lives in the *implementation* contract rather than the proxy. On top of standard UUPS, we add a **two-step upgrade mechanism**: the owner must first call `announcePlannedUpgrade()` to record the new implementation address and a future epoch, then wait for that epoch to pass before `upgradeToAndCall()` will succeed. + > For upgrading ServiceProviderRegistry or redeploying StateView, see [Upgrading Other Contracts](#upgrading-other-contracts). ## Two-Step Upgrade Mechanism @@ -50,7 +52,7 @@ echo "Current: $CURRENT_EPOCH, Upgrade after: $AFTER_EPOCH" - Mark breaking changes clearly - Include migration notes if needed -2. **Update the version** string in the contract if applicable. +2. **Update the [version](https://github.com/FilOzone/filecoin-services/blob/main/service_contracts/src/FilecoinWarmStorageService.sol#L63)** string in the contract. 3. **Create an upgrade PR** with your changelog updates. - Example title: `feat: FWSS v1.2.0 upgrade` @@ -71,7 +73,7 @@ export ETH_RPC_URL="https://api.calibration.node.glif.io/rpc/v1" ./deploy-warm-storage-implementation-only.sh ``` -The script updates `deployments.json` automatically. Commit the changes. +The script updates `deployments.json` automatically. Commit the changes in the branch of the "upgrade PR" above. ### Announce Upgrade @@ -105,7 +107,7 @@ export ETH_RPC_URL="https://api.node.glif.io/rpc/v1" ./deploy-warm-storage-implementation-only.sh ``` -Commit the updated `deployments.json`. +Commit the updated `deployments.json` in the branch of the "upgrade PR" above. ## Phase 4: Announce Mainnet Upgrade