-
Notifications
You must be signed in to change notification settings - Fork 3.4k
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
OPCM Upgrade implementations only #13574
base: opcm-up/add-deployImpls-to-fork-live
Are you sure you want to change the base?
Changes from all commits
cd6c12d
a1ef982
fab598b
083ad1e
371d001
3417eaa
7340890
6b907ac
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||
---|---|---|---|---|---|---|---|---|
|
@@ -114,8 +114,8 @@ contract OPContractsManager is ISemver { | |||||||
|
||||||||
// -------- Constants and Variables -------- | ||||||||
|
||||||||
/// @custom:semver 1.0.0-beta.27 | ||||||||
string public constant version = "1.0.0-beta.27"; | ||||||||
/// @custom:semver 1.0.0-beta.28 | ||||||||
string public constant version = "1.0.0-beta.28"; | ||||||||
|
||||||||
/// @notice Represents the interface version so consumers know how to decode the DeployOutput struct | ||||||||
/// that's emitted in the `Deployed` event. Whenever that struct changes, a new version should be used. | ||||||||
|
@@ -139,6 +139,10 @@ contract OPContractsManager is ISemver { | |||||||
/// @notice Addresses of the latest implementation contracts. | ||||||||
Implementations internal implementation; | ||||||||
|
||||||||
/// @notice The OPContractsManager contract that is currently being used. This is needed in the upgrade function | ||||||||
/// which is intended to be DELEGATECALLed. | ||||||||
OPContractsManager internal immutable thisOPCM; | ||||||||
|
||||||||
// -------- Events -------- | ||||||||
|
||||||||
/// @notice Emitted when a new OP Stack chain is deployed. | ||||||||
|
@@ -150,6 +154,12 @@ contract OPContractsManager is ISemver { | |||||||
uint256 indexed outputVersion, uint256 indexed l2ChainId, address indexed deployer, bytes deployOutput | ||||||||
); | ||||||||
|
||||||||
/// @notice Emitted when a chain is upgraded | ||||||||
/// @param l2ChainId Chain ID of the upgraded chain | ||||||||
/// @param systemConfig Address of the chain's SystemConfig contract | ||||||||
/// @param upgrader Address that initiated the upgrade | ||||||||
event Upgraded(uint256 indexed l2ChainId, ISystemConfig indexed systemConfig, address indexed upgrader); | ||||||||
|
||||||||
// -------- Errors -------- | ||||||||
|
||||||||
/// @notice Thrown when an address is the zero address. | ||||||||
|
@@ -190,6 +200,7 @@ contract OPContractsManager is ISemver { | |||||||
|
||||||||
blueprint = _blueprints; | ||||||||
implementation = _implementations; | ||||||||
thisOPCM = this; | ||||||||
} | ||||||||
|
||||||||
function deploy(DeployInput calldata _input) external returns (DeployOutput memory) { | ||||||||
|
@@ -363,6 +374,38 @@ contract OPContractsManager is ISemver { | |||||||
return output; | ||||||||
} | ||||||||
|
||||||||
/// @notice Upgrades a set of chains to the latest implementation contracts | ||||||||
/// @param _systemConfigs Array of SystemConfig contracts, one per chain to upgrade | ||||||||
/// @param _proxyAdmins Array of ProxyAdmin contracts, one per chain to upgrade | ||||||||
/// @dev This function is intended to be called via DELEGATECALL from the Upgrade Controller Safe | ||||||||
function upgrade(ISystemConfig[] calldata _systemConfigs, IProxyAdmin[] calldata _proxyAdmins) external { | ||||||||
Implementations memory impls = thisOPCM.implementations(); | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can enforce a delegatecallhere
Suggested change
|
||||||||
|
||||||||
for (uint256 i = 0; i < _systemConfigs.length; i++) { | ||||||||
ISystemConfig systemConfig = _systemConfigs[i]; | ||||||||
ISystemConfig.Addresses memory opChainAddrs = ISystemConfig.Addresses({ | ||||||||
l1CrossDomainMessenger: systemConfig.l1CrossDomainMessenger(), | ||||||||
l1ERC721Bridge: systemConfig.l1ERC721Bridge(), | ||||||||
l1StandardBridge: systemConfig.l1StandardBridge(), | ||||||||
disputeGameFactory: systemConfig.disputeGameFactory(), | ||||||||
optimismPortal: systemConfig.optimismPortal(), | ||||||||
optimismMintableERC20Factory: systemConfig.optimismMintableERC20Factory(), | ||||||||
gasPayingToken: address(0) | ||||||||
}); | ||||||||
|
||||||||
IProxyAdmin proxyAdmin = _proxyAdmins[i]; | ||||||||
proxyAdmin.upgrade(payable(address(systemConfig)), impls.systemConfigImpl); | ||||||||
proxyAdmin.upgrade(payable(opChainAddrs.l1CrossDomainMessenger), impls.l1CrossDomainMessengerImpl); | ||||||||
proxyAdmin.upgrade(payable(opChainAddrs.l1ERC721Bridge), impls.l1ERC721BridgeImpl); | ||||||||
proxyAdmin.upgrade(payable(opChainAddrs.l1StandardBridge), impls.l1StandardBridgeImpl); | ||||||||
proxyAdmin.upgrade(payable(opChainAddrs.disputeGameFactory), impls.disputeGameFactoryImpl); | ||||||||
proxyAdmin.upgrade(payable(opChainAddrs.optimismPortal), impls.optimismPortalImpl); | ||||||||
proxyAdmin.upgrade( | ||||||||
payable(opChainAddrs.optimismMintableERC20Factory), impls.optimismMintableERC20FactoryImpl | ||||||||
); | ||||||||
} | ||||||||
} | ||||||||
|
||||||||
// -------- Utilities -------- | ||||||||
|
||||||||
/// @notice Verifies that all inputs are valid and reverts if any are invalid. | ||||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -91,3 +91,10 @@ contract Reverter { | |
revert(); | ||
} | ||
} | ||
|
||
contract DelegateCaller { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we add natspec explaining why we have this contract? |
||
function dcForward(address _target, bytes calldata _data) external { | ||
(bool success,) = _target.delegatecall(_data); | ||
require(success, "DelegateCaller: Delegatecall failed"); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,6 +3,7 @@ pragma solidity ^0.8.0; | |
|
||
// Testing | ||
import { stdJson } from "forge-std/StdJson.sol"; | ||
import { DelegateCaller } from "test/mocks/Callers.sol"; | ||
|
||
// Scripts | ||
import { Deployer } from "scripts/deploy/Deployer.sol"; | ||
|
@@ -16,6 +17,9 @@ import { EIP1967Helper } from "test/mocks/EIP1967Helper.sol"; | |
import { IFaultDisputeGame } from "interfaces/dispute/IFaultDisputeGame.sol"; | ||
import { IDisputeGameFactory } from "interfaces/dispute/IDisputeGameFactory.sol"; | ||
import { IAddressManager } from "interfaces/legacy/IAddressManager.sol"; | ||
import { ISystemConfig } from "interfaces/L1/ISystemConfig.sol"; | ||
import { IProxyAdmin } from "interfaces/universal/IProxyAdmin.sol"; | ||
import { OPContractsManager } from "src/L1/OPContractsManager.sol"; | ||
|
||
/// @title ForkLive | ||
/// @notice This script is called by Setup.sol as a preparation step for the foundry test suite, and is run as an | ||
|
@@ -96,20 +100,53 @@ contract ForkLive is Deployer { | |
|
||
// Now deploy the updated OPCM and implementations of the contracts | ||
_deployNewImplementations(); | ||
|
||
// Now upgrade the contracts | ||
_upgrade(); | ||
} | ||
|
||
/// @notice Etches a new Deploy.s.sol contract at a deterministic address, sets up the environment, | ||
/// and deploys new implementations with a "_NextVersion" suffix. This suffix is necessary to avoid | ||
/// naming collisions with the implementations saved above. | ||
function _deployNewImplementations() internal { | ||
// Etch a copy of the Deploy.s.sol contract so that we can use its deployImplementations() function | ||
Deploy deployNew = Deploy(address(uint160(uint256(keccak256(abi.encode("optimism.deploy.new")))))); | ||
vm.etch(address(deployNew), vm.getDeployedCode("Deploy.s.sol:Deploy")); | ||
vm.label(address(deployNew), "DeployNew"); | ||
vm.allowCheatcodes(address(deployNew)); | ||
vm.setEnv("CONTRACT_ADDRESSES_PATH", string.concat(vm.projectRoot(), "/deployments/1-deploy.json")); | ||
|
||
// Set the CONTRACT_ADDRESSES_PATH environment variable | ||
// This is used in Deploy.setUp() to read and save the addresses it needs (SuperchainConfigProxy, | ||
// ProtocolVersionsProxy) | ||
string memory jsonPath = string.concat(vm.projectRoot(), "/deployments/1-deploy.json"); | ||
vm.setEnv("CONTRACT_ADDRESSES_PATH", jsonPath); | ||
deployNew.setUp(); | ||
deployNew.deployImplementations({ _isInterop: false, _suffix: "_NextVersion" }); | ||
|
||
// deployNew.deployImplementations() saves the addresses to its own storage as well as to the json file at | ||
// CONTRACT_ADDRESSES_PATH. In order to use the addresses in the json file, we now need to load them into | ||
// local storage. | ||
loadAddresses(jsonPath); | ||
} | ||
|
||
function _upgrade() internal { | ||
OPContractsManager opcm = OPContractsManager(mustGetAddress("OPContractsManager_NextVersion")); | ||
|
||
ISystemConfig systemConfig = ISystemConfig(mustGetAddress("SystemConfigProxy")); | ||
IProxyAdmin proxyAdmin = IProxyAdmin(EIP1967Helper.getAdmin(address(systemConfig))); | ||
|
||
address upgrader = proxyAdmin.owner(); | ||
vm.label(upgrader, "ProxyAdmin Owner"); | ||
|
||
ISystemConfig[] memory systemConfigs = new ISystemConfig[](1); | ||
systemConfigs[0] = systemConfig; | ||
IProxyAdmin[] memory proxyAdmins = new IProxyAdmin[](1); | ||
proxyAdmins[0] = proxyAdmin; | ||
Comment on lines
+141
to
+144
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Consider adding helpers for this to our vendored |
||
|
||
vm.etch(upgrader, vm.getDeployedCode("test/mocks/Callers.sol:DelegateCaller")); | ||
DelegateCaller(upgrader).dcForward( | ||
address(opcm), abi.encodeCall(OPContractsManager.upgrade, (systemConfigs, proxyAdmins)) | ||
); | ||
} | ||
|
||
/// @notice Saves the proxy and implementation addresses for a contract name | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like we are not emitting (or testing for) the
Upgraded
event