Skip to content

Conversation

wjmelements
Copy link
Contributor

@wjmelements wjmelements commented Oct 4, 2025

Reviewer @rvagg
Per a discussion with @jennijuju, we want to make the upgrade process more transparent.
This changes upgrades to a two step process.
First, we announce the planned upgrade.
Then, after the designated time, we can complete the upgrade.
The delay gives us time to check the pending implementation address. It also gives users notice even if we are not in communication with them.
I also fix #259 in this change, because I was already adding tests for upgradeToAndCall. I can fix it separately if this change is rejected.
After validating that this is a good design that the team likes, I can replicate it for the other proxies in separate PRs.

Test Plan

I tested the new deployment scripts by running them on calibnet.

Changes

  • announcePlannedUpgrade
  • update _authorizeUpgrade
  • new view method for pending upgrade
  • make gen
  • add and fix tests covering upgradeToAndCall with migrate
  • separate announce and upgrade scripts
  • update implementation-only script

@wjmelements wjmelements requested a review from rvagg October 4, 2025 05:10
@FilOzzy FilOzzy added this to FS Oct 4, 2025
@github-project-automation github-project-automation bot moved this to 📌 Triage in FS Oct 4, 2025
function _authorizeUpgrade(address newImplementation) internal override onlyOwner {}
function announcePlannedUpgrade(PlannedUpgrade calldata plannedUpgrade) external onlyOwner {
require(plannedUpgrade.nextImplementation.code.length > 3000);
require(plannedUpgrade.afterEpoch > block.number);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could also require a minimum delay, but in the event of an emergency we might want a shorter delay. I can add it if someone else wants it. Mainly if we discovered a problem right after a deployment a mandatory delay would become mandatory downtime.

Such a minimum delay would help facilitate security by allowing time to check, for example, that the bytecode matches the source code. It would enforce transparency by mandating a notice period for service providers, who can watch for the UpgradeAnnounced event log.

However such a delay could also just be enforced off-chain by best-practices. This is why I don't enforce it in the code.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sgtm

* @param _viewContract Address of the view contract (optional, can be address(0))
*/
function migrate(address _viewContract) public onlyProxy reinitializer(4) {
require(msg.sender == address(this), Errors.OnlySelf(address(this), msg.sender));
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the fix for #259

@wjmelements
Copy link
Contributor Author

After validating that this is a good design, I can replicate it for the other proxies in separate PRs.

}

// Event declaration for testing (must match the contract's event)
event ContractUpgraded(string version, address implementation);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is unused, and you can match the contract more easily by referring to the original, eg FilecoinWarmStorageService.ContractUpgraded.

export EXPECTED_IMPL=$(echo $NEW_WARM_STORAGE_IMPLEMENTATION_ADDRESS | tr '[:upper:]' '[:lower:]')

if [ "$NEW_IMPL" = "$EXPECTED_IMPL" ]; then
echo "✅ Upgrade successful! Proxy now points to: $NEW_WARM_STORAGE_IMPLEMENTATION_ADDRESS"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

output when I ran this locally:

Warning: NEW_WARM_STORAGE_VIEW_ADDRESS is not set. Keeping previous view contract.
Using owner address: 0x3B559cf662fdFe485eC216C036D4Cee91FBd1D39
Upgrade plan matches (0x9D4af62664A69db9c21eFCdf9fb43029D43A7f68)
Upgrade ready (3074256 > 3074254)
Keeping previous view contract address (0x85DB31F04dE9625b94b80bA20F1041f1A301D024)
Upgrading proxy and calling migrate...
Upgrade transaction sent: 0xbfb790ed434d1a1be7cc85fdab9cba40f00f1fbd9a4c0c10a39886cba74c70cc
Waiting for confirmation...
Verifying upgrade...
✅ Upgrade successful! Proxy now points to: 0x9D4af62664A69db9c21eFCdf9fb43029D43A7f68

echo "Error: Failed to send announcePlannedUpgrade transaction"
fi

echo "announcePlannedUpgrade transaction sent: $TX_HASH"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

successful output log

Announcing planned upgrade after 4 epochs
Sending announcement from owner address: 0x3B559cf662fdFe485eC216C036D4Cee91FBd1D39
announcePlannedUpgrade transaction sent: 0xee4f2cb731c4102454a57356d86df2cd4bc3ab3a8c8bc229d8126fdb279fe70c

@rjan90 rjan90 moved this from 📌 Triage to 🔎 Awaiting review in FS Oct 4, 2025
}

function _authorizeUpgrade(address newImplementation) internal override onlyOwner {
// zero address already checked by ERC1967Utils._setImplementation
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also test for this case in testUpgrade.

        (address nextImplementation, uint96 afterEpoch) = viewContract.nextUpgrade();
        assertEq(nextImplementation, address(0));
        assertEq(afterEpoch, uint96(0));

        // Do not allow upgrade to zero address even if it's the nextImplementation
        vm.expectRevert();
        service.upgradeToAndCall(nextImplementation, migrateData);

@wjmelements wjmelements changed the title announcePlannedUpgrade feat: announcePlannedUpgrade Oct 4, 2025
Copy link
Collaborator

@rvagg rvagg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

script names could be more consistent and have warm-storage in them, but that's a weakly held opinion and I hope that problem mostly goes away with #229

@github-project-automation github-project-automation bot moved this from 🔎 Awaiting review to ✔️ Approved by reviewer in FS Oct 7, 2025
@wjmelements
Copy link
Contributor Author

weird that 351cc6e caused the size check to fail

@wjmelements
Copy link
Contributor Author

weird that 351cc6e caused the size check to fail

I reproduce this after merging with the main branch but not on the tip commit. Maybe it was testing a merged PR?

I'll look for ways to cut codesize.

@wjmelements wjmelements merged commit 722943e into main Oct 7, 2025
5 checks passed
@wjmelements wjmelements deleted the announce-planned-upgrade branch October 7, 2025 04:35
@github-project-automation github-project-automation bot moved this from ✔️ Approved by reviewer to 🎉 Done in FS Oct 7, 2025
@wjmelements
Copy link
Contributor Author

Probably worth cutting codesize more than the minimum but will do it in a separate PR

rjan90 added a commit that referenced this pull request Oct 7, 2025
docs: add #260 to the changelog after rebase
DarkLord017 pushed a commit to DarkLord017/filecoin-services that referenced this pull request Oct 8, 2025
Reviewer @rvagg
Per a discussion with @jennijuju, we want to make the upgrade process
more transparent.
This changes upgrades to a two step process.
First, we announce the planned upgrade.
Then, after the designated time, we can complete the upgrade.
The delay gives us time to check the pending implementation address. It
also gives users notice even if we are not in communication with them.
I also fix FilOzone#259 in
this change, because I was already adding tests for `upgradeToAndCall`.
I can fix it separately if this change is rejected.
After validating that this is a good design that the team likes, I can
replicate it for the other proxies in separate PRs.
#### Test Plan
I tested the new deployment scripts by running them on calibnet.
*
[announcePlannedUpgrade](https://calibration.filfox.info/en/message/bafy2bzaceb6vpcsy563vhpwig5g6jy7gb6fr2ssxhjgwiagj7k3vbjrg3dg56?t=3)
*
[upgradeToAndCall](https://calibration.filfox.info/en/message/bafy2bzaceadjmlemjyrv7nmwh5lzavdbntjmywvblrzmtuh3wsyldqlvxbcyo?t=3)
#### Changes
* announcePlannedUpgrade
* update _authorizeUpgrade
* new view method for pending upgrade
* make gen
* add and fix tests covering upgradeToAndCall with migrate
* separate announce and upgrade scripts
* update implementation-only script

---------

Co-authored-by: Rod Vagg <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: 🎉 Done
Development

Successfully merging this pull request may close these issues.

FilecoinWarmStorageService.upgradeToAndCall migrate() reverts with Errors.OnlySelf
2 participants