-
Notifications
You must be signed in to change notification settings - Fork 46
design doc for the ocpm superchain upgrade fix #310
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
AmadiMichael
wants to merge
17
commits into
main
Choose a base branch
from
opcm/opcm-superchain-upgrade-fix
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+134
−0
Open
Changes from all commits
Commits
Show all changes
17 commits
Select commit
Hold shift + click to select a range
057bd86
design doc for the ocpm superchain upgrade fix
AmadiMichael d4a34a3
add requirements and more FMAs
AmadiMichael 7497f11
Update protocol/opcm-superchain-upgrade-fix.md
AmadiMichael ad1ce6a
fixes
AmadiMichael e129c34
Update protocol/opcm-superchain-upgrade-fix.md
AmadiMichael e0c1348
Update protocol/opcm-superchain-upgrade-fix.md
AmadiMichael 1bfaadf
fix
AmadiMichael cb02adc
fix
AmadiMichael 76f1ff8
add table of expected behavior
AmadiMichael 0bffd00
remove section
AmadiMichael 5132be8
add notes
AmadiMichael feab12a
Update protocol/opcm-superchain-upgrade-fix.md
AmadiMichael 098862c
Update protocol/opcm-superchain-upgrade-fix.md
AmadiMichael b5a8d14
fixes
AmadiMichael 7f9e437
update and simplify design doc
AmadiMichael 3a6a01b
add requirement to make changes to opcm-upgrade-checks
AmadiMichael 14ea901
add extra variable to remove and add reasons to justify it
AmadiMichael File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
<!-- START doctoc generated TOC please keep comment here to allow auto update --> | ||
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --> | ||
**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* | ||
|
||
- [OPCM SuperchainConfig Upgrade Fix: Design Doc](#opcm-superchainconfig-upgrade-fix-design-doc) | ||
- [Summary](#summary) | ||
- [Problem Statement + Context](#problem-statement--context) | ||
- [Customer Requirements and Expected Behavior](#customer-requirements-and-expected-behavior) | ||
- [OPContractsManager upgradeSuperchainConfig function:](#opcontractsmanager-upgradesuperchainconfig-function) | ||
- [OPContractsManager upgrade function:](#opcontractsmanager-upgrade-function) | ||
- [Proposed Solution](#proposed-solution) | ||
- [Proposal 1: Move the SuperchainConfig upgrade functionality to it's own function:](#proposal-1-move-the-superchainconfig-upgrade-functionality-to-its-own-function) | ||
- [Proposal 2: SuperchainConfig Upgrade Check Fix](#proposal-2-superchainconfig-upgrade-check-fix) | ||
- [Proposal 3: Support for different superchainConfigs i.e different Superchains](#proposal-3-support-for-different-superchainconfigs-ie-different-superchains) | ||
- [Proposal 4: Remove redundant immutable variables from the OPCM](#proposal-4-remove-redundant-immutable-variables-from-the-opcm) | ||
- [Failure Mode Analysis](#failure-mode-analysis) | ||
|
||
<!-- END doctoc generated TOC please keep comment here to allow auto update --> | ||
|
||
# OPCM SuperchainConfig Upgrade Fix: Design Doc | ||
|
||
| | | | ||
| ------------------ | -------------------------------------------------- | | ||
| Author | Michael Amadi | | ||
| Created at | _2025-07-29_ | | ||
| Initial Reviewers | Matt Solomon, John Mardlin | | ||
| Need Approval From | _To be assigned_ | | ||
| Status | _Draft_ | | ||
|
||
## Summary | ||
|
||
Currently, the OPCM's `upgrade()` function optionally upgrades the superchainConfigProxy based on the following checks: | ||
|
||
For [op-contracts/v2.0.0](https://github.com/ethereum-optimism/optimism/blob/8d0dd96e494b2ba154587877351e87788336a4ec/packages/contracts-bedrock/src/L1/OPContractsManager.sol#L477) | ||
```solidity | ||
// If the SuperchainConfig is not already upgraded, upgrade it. | ||
if (superchainProxyAdmin.getProxyImplementation(address(superchainConfig)) != impls.superchainConfigImpl) { | ||
// Attempt to upgrade. If the ProxyAdmin is not the SuperchainConfig's admin, this will revert. | ||
upgradeTo(superchainProxyAdmin, address(superchainConfig), impls.superchainConfigImpl); | ||
} | ||
``` | ||
|
||
and [op-contracts/v4.0.0](https://github.com/ethereum-optimism/optimism/blob/54c19f6acb7a6d3505f884bae601733d3d54a3a6/packages/contracts-bedrock/src/L1/OPContractsManager.sol#L615) | ||
```solidity | ||
// If the SuperchainConfig is not already upgraded, upgrade it. NOTE that this type of | ||
// upgrade means that chains can ONLY be upgraded via this OPCM contract if they use the | ||
// same SuperchainConfig contract. We will assert this later. | ||
if (_superchainProxyAdmin.getProxyImplementation(address(_superchainConfig)) != impls.superchainConfigImpl) { | ||
// Attempt to upgrade. If the ProxyAdmin is not the SuperchainConfig's admin, this will revert. | ||
upgradeToAndCall( | ||
_superchainProxyAdmin, | ||
address(_superchainConfig), | ||
impls.superchainConfigImpl, | ||
abi.encodeCall(ISuperchainConfig.upgrade, ()) | ||
); | ||
``` | ||
|
||
The check basically says that, if the implementation of the superchainConfig is not the same as the implementation the OPCM has stored, then upgrade it. | ||
|
||
To upgrade the superchainConfig, the superchainProxyAdminOwner will need to call the OPCM's `upgrade()` function and optionally pass in values to upgrade any other chain's contracts as long as it controls that chain's proxyAdmin. | ||
|
||
## Problem Statement + Context | ||
|
||
This works for the most part but has a flaw. Assume the following: | ||
- There are 2 chains in the Superchain, ChainA and ChainB | ||
- ChainA's proxyAdmin is also the SuperchainConfig's ProxyAdmin | ||
- The SuperchainConfig's implementation is Impl0 | ||
- The OPCM has stored Impl1 as the implementation to upgrade to | ||
|
||
If ChainA's proxyAdminOwner (also the SuperchainConfig's ProxyAdminOwner) calls the OPCM's `upgrade()` function, the check above (if (superchainProxyAdmin.getProxyImplementation(address(superchainConfig)) != impls.superchainConfigImpl)) will be true and it will upgrade the SuperchainConfig to Impl1 and also upgrade ChainA's L1 contracts. | ||
|
||
If ChainB's `proxyAdminOwner` calls the OPCM's `upgrade()` function, the check above (if (`superchainProxyAdmin.getProxyImplementation(address(superchainConfig)) != impls.superchainConfigImpl)`) will be false and so it will not enter the if block (if it did it will revert since ChainB's `proxyAdminOwner` is not the SuperchainConfig's `ProxyAdminOwner`). So it will skip this and go ahead to upgrade ChainB's L1 contracts. | ||
|
||
Now the a problem arises here: | ||
- The SuperchainConfig's implementation is Impl1 | ||
- A new OPCM is created with an expected implementation of Impl2 | ||
- The OPCM's `upgrade()` function is called and the SuperchainConfig's implementation is upgraded to Impl2 | ||
- A new chain, ChainC comes in or is behind and has to use the old OPCM first | ||
|
||
When it calls the OPCM's `upgrade()` function, the check above (if (`superchainProxyAdmin.getProxyImplementation(address(superchainConfig)) != impls.superchainConfigImpl)`) will be true and it will attempt to upgrade the SuperchainConfig which: | ||
- If the ProxyAdmin is not the SuperchainConfig's ProxyAdmin, it will revert. This essentially means that all upgrades from that OPCM is not possible any longer. Of course unless the SuperchainProxyAdminOwner calls upgrade which would upgrade the SuperchainConfig to Impl1 (effectively a downgrade) and make it possible for other chains to upgrade but for obvious reasons downgrading the SuperchainConfig is not the best course of action. | ||
- If however it's ProxyAdmin is the SuperchainConfig's ProxyAdmin, it will upgrade the SuperchainConfig to impl1 (old implementation) and then upgrade ChainC's L1 contracts. | ||
|
||
## Customer Requirements and Expected Behavior | ||
|
||
### OPContractsManager upgradeSuperchainConfig function: | ||
- The SuperchainConfig has not been upgraded by the OPCM being called. | ||
- The caller must be the SuperchainConfig's ProxyAdminOwner. | ||
|
||
### OPContractsManager upgrade function: | ||
- ChainA's SuperchainConfig has been upgraded by the OPCM being called. | ||
- The caller must be ChainA's ProxyAdminOwner. | ||
- ChainA has not already been upgraded by the OPCM being called. | ||
|
||
## Proposed Solution | ||
|
||
### Proposal 1: Move the SuperchainConfig upgrade functionality to it's own function: | ||
This will help simplify the `upgrade()` function and make the checks easier to reason about and implement. As part of this the `opcm-upgrade-checks` script will also need to be updated to support this too. | ||
|
||
|
||
### Proposal 2: SuperchainConfig Upgrade Check Fix | ||
A proposed solution for this is to change the check to version comparisons. We can hardcode an expected previous and target versions for the SuperchainConfig and compare it to the actual version when performing upgrades. E.g | ||
- For `The SuperchainConfig has not been upgraded by the OPCM being called` in `OPCM.upgradeSuperchainConfig()`, we check if the SuperchainConfig's actual version is equal to the expected previous version. If it is, we can upgrade the SuperchainConfig. Otherwise we revert. We do this strict check to ensure that SuperchainConfigs are upgraded only from a pre-approved version most likely to be the immediate previous version. | ||
- For `ChainA's SuperchainConfig has been upgraded by the OPCM being called` in `OPCM.upgrade()`, we check if the SuperchainConfig's actual version is greater than or equal to the expected target version. If it is, we can proceed to upgrade the OP Chains L1 contracts. Otherwise we revert. We do not make a strict check here so that OP Chains that are more than 2 SuperchainConfig versions behind can still be upgraded. | ||
- For `ChainA has not already been upgraded by the OPCM being called` in `OPCM.upgrade()`, we check if the version of one of the OP Chains L1 contracts intended to be upgraded by the upgrade function is equal to the expected previous version of the chosen contract. If it is, we can proceed to upgrade the OP Chains L1 contracts. Otherwise we revert. | ||
|
||
|
||
### Proposal 3: Support for different superchainConfigs i.e different Superchains | ||
While at it, it is proposed to also add support for different superchainConfigs i.e different Superchains. The proposed solution also allows for this. | ||
|
||
```solidity | ||
ISuperchainConfig _superchainConfig = _opChainInputs[0].systemConfig.optimismPortal().superchainConfig(); | ||
for (uint256 i = 0; i < _opChainInputs.length; i++) { | ||
if (_opChainInputs[i].systemConfig.optimismPortal().superchainConfig() != _superchainConfig) { | ||
revert SuperchainConfigInconsistent(); | ||
} | ||
} | ||
``` | ||
|
||
We should note that: | ||
- OP Chains of different superchains (even if they share the same ProxyAdminOwner)can not be upgraded in one call to upgrade(...) because of the check above. | ||
|
||
|
||
### Proposal 4: Remove redundant immutable variables from the OPCM | ||
Lastly, it is proposed to remove the following immutable variables from the OPCM contract as they are not used any longer: | ||
- `ProtocolVersions`: Not used anymore since OPCM v2.x.x | ||
- `SuperchainProxyAdminOwner`: Not used anymore since we now support multiple superchains. | ||
- `upgradeController`: Not used anymore since RC functionality was removed. | ||
- `SuperchainConfig`: Not used anymore except as an input to OPCMDeployer.deploy(...) which is called in the OPCM. A bypass this is to add the `SuperchainConfig` as one of the fields of the `Roles` struct which is an input to OPCM.deploy(...). This should now fully enable deploying OP chains from variable `SuperchainConfigs`. | ||
|
||
## Failure Mode Analysis | ||
|
||
- **A chain might be upgraded when it's superchainConfig is not upgraded:** | ||
- Mitigation: We can implement a simple loop to assert that all chains in the array are of the same superchain and have tests for this. |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.