Commit 716aa394 authored by Mark Tyneway's avatar Mark Tyneway

contracts-bedrock: migrate OptimismPortal single impl

Migrate the network specific config in the `OptimismPortal`
from being `immutable` values into storage. This allows for
a single implementation to be used for all proxies in the
network.

As seen in the storage layout, no storage values are modified.
Only new storage values are added. This is very important for
ensuring the integrity of storage in the contract.

The deployment complexity is reduced by removing all constructor
values and setting all config in the `initialize` function.
The sentinel contract should use all null values for its fields
so that it is not confused as the contract for an actual network.

The bindings are regnerated. A follow up commit will bump the
minor semver version in the `OptimismPortal`
parent 747876d0
This diff is collapsed.
This source diff could not be displayed because it is too large. You can view the blob instead.
This diff is collapsed.
This diff is collapsed.
...@@ -63,6 +63,9 @@ ...@@ -63,6 +63,9 @@
| finalizedWithdrawals | mapping(bytes32 => bool) | 51 | 0 | 32 | src/L1/OptimismPortal.sol:OptimismPortal | | finalizedWithdrawals | mapping(bytes32 => bool) | 51 | 0 | 32 | src/L1/OptimismPortal.sol:OptimismPortal |
| provenWithdrawals | mapping(bytes32 => struct OptimismPortal.ProvenWithdrawal) | 52 | 0 | 32 | src/L1/OptimismPortal.sol:OptimismPortal | | provenWithdrawals | mapping(bytes32 => struct OptimismPortal.ProvenWithdrawal) | 52 | 0 | 32 | src/L1/OptimismPortal.sol:OptimismPortal |
| paused | bool | 53 | 0 | 1 | src/L1/OptimismPortal.sol:OptimismPortal | | paused | bool | 53 | 0 | 1 | src/L1/OptimismPortal.sol:OptimismPortal |
| L2_ORACLE | contract L2OutputOracle | 53 | 1 | 20 | src/L1/OptimismPortal.sol:OptimismPortal |
| SYSTEM_CONFIG | contract SystemConfig | 54 | 0 | 20 | src/L1/OptimismPortal.sol:OptimismPortal |
| GUARDIAN | address | 55 | 0 | 20 | src/L1/OptimismPortal.sol:OptimismPortal |
======================= =======================
➡ src/L1/SystemConfig.sol:SystemConfig ➡ src/L1/SystemConfig.sol:SystemConfig
......
...@@ -292,24 +292,11 @@ contract Deploy is Deployer { ...@@ -292,24 +292,11 @@ contract Deploy is Deployer {
/// @notice Deploy the OptimismPortal /// @notice Deploy the OptimismPortal
function deployOptimismPortal() broadcast() public returns (address) { function deployOptimismPortal() broadcast() public returns (address) {
address l2OutputOracleProxy = mustGetAddress("L2OutputOracleProxy"); OptimismPortal portal = new OptimismPortal();
address systemConfigProxy = mustGetAddress("SystemConfigProxy");
address guardian = cfg.portalGuardian();
if (guardian.code.length == 0) {
console.log("Portal guardian has no code: %s", guardian);
}
OptimismPortal portal = new OptimismPortal({ require(address(portal.L2_ORACLE()) == address(0));
_l2Oracle: L2OutputOracle(l2OutputOracleProxy), require(portal.GUARDIAN() == address(0));
_guardian: guardian, require(address(portal.SYSTEM_CONFIG()) == address(0));
_paused: true,
_config: SystemConfig(systemConfigProxy)
});
require(address(portal.L2_ORACLE()) == l2OutputOracleProxy);
require(portal.GUARDIAN() == guardian);
require(address(portal.SYSTEM_CONFIG()) == systemConfigProxy);
require(portal.paused() == true); require(portal.paused() == true);
save("OptimismPortal", address(portal)); save("OptimismPortal", address(portal));
...@@ -681,10 +668,23 @@ contract Deploy is Deployer { ...@@ -681,10 +668,23 @@ contract Deploy is Deployer {
address l2OutputOracleProxy = mustGetAddress("L2OutputOracleProxy"); address l2OutputOracleProxy = mustGetAddress("L2OutputOracleProxy");
address systemConfigProxy = mustGetAddress("SystemConfigProxy"); address systemConfigProxy = mustGetAddress("SystemConfigProxy");
address guardian = cfg.portalGuardian();
if (guardian.code.length == 0) {
console.log("Portal guardian has no code: %s", guardian);
}
proxyAdmin.upgradeAndCall({ proxyAdmin.upgradeAndCall({
_proxy: payable(optimismPortalProxy), _proxy: payable(optimismPortalProxy),
_implementation: optimismPortal, _implementation: optimismPortal,
_data: abi.encodeCall(OptimismPortal.initialize, (false)) _data: abi.encodeCall(
OptimismPortal.initialize,
(
L2OutputOracle(l2OutputOracleProxy),
guardian,
SystemConfig(systemConfigProxy),
false
)
)
}); });
OptimismPortal portal = OptimismPortal(payable(optimismPortalProxy)); OptimismPortal portal = OptimismPortal(payable(optimismPortalProxy));
......
...@@ -35,15 +35,6 @@ contract OptimismPortal is Initializable, ResourceMetering, Semver { ...@@ -35,15 +35,6 @@ contract OptimismPortal is Initializable, ResourceMetering, Semver {
/// @notice The L2 gas limit set when eth is deposited using the receive() function. /// @notice The L2 gas limit set when eth is deposited using the receive() function.
uint64 internal constant RECEIVE_DEFAULT_GAS_LIMIT = 100_000; uint64 internal constant RECEIVE_DEFAULT_GAS_LIMIT = 100_000;
/// @notice Address of the L2OutputOracle contract.
L2OutputOracle public immutable L2_ORACLE;
/// @notice Address of the SystemConfig contract.
SystemConfig public immutable SYSTEM_CONFIG;
/// @notice Address that has the ability to pause and unpause withdrawals.
address public immutable GUARDIAN;
/// @notice Address of the L2 account which initiated a withdrawal in this transaction. /// @notice Address of the L2 account which initiated a withdrawal in this transaction.
/// If the of this variable is the default L2 sender address, then we are NOT inside of /// If the of this variable is the default L2 sender address, then we are NOT inside of
/// a call to finalizeWithdrawalTransaction. /// a call to finalizeWithdrawalTransaction.
...@@ -60,6 +51,15 @@ contract OptimismPortal is Initializable, ResourceMetering, Semver { ...@@ -60,6 +51,15 @@ contract OptimismPortal is Initializable, ResourceMetering, Semver {
/// This may be removed in the future. /// This may be removed in the future.
bool public paused; bool public paused;
/// @notice Address of the L2OutputOracle contract.
L2OutputOracle public L2_ORACLE;
/// @notice Address of the SystemConfig contract.
SystemConfig public SYSTEM_CONFIG;
/// @notice Address that has the ability to pause and unpause withdrawals.
address public GUARDIAN;
/// @notice Emitted when a transaction is deposited from L1 to L2. /// @notice Emitted when a transaction is deposited from L1 to L2.
/// The parameters of this event are read by the rollup node and used to derive deposit /// The parameters of this event are read by the rollup node and used to derive deposit
/// transactions on L2. /// transactions on L2.
...@@ -105,25 +105,25 @@ contract OptimismPortal is Initializable, ResourceMetering, Semver { ...@@ -105,25 +105,25 @@ contract OptimismPortal is Initializable, ResourceMetering, Semver {
/// @custom:semver 1.7.2 /// @custom:semver 1.7.2
/// @notice Constructs the OptimismPortal contract. /// @notice Constructs the OptimismPortal contract.
constructor() Semver(1, 7, 2) {
initialize({
_l2Oracle: L2OutputOracle(address(0)),
_guardian: address(0),
_systemConfig: SystemConfig(address(0)),
_paused: true
});
}
/// @notice Initializer.
/// @param _l2Oracle Address of the L2OutputOracle contract. /// @param _l2Oracle Address of the L2OutputOracle contract.
/// @param _guardian Address that can pause withdrawals. /// @param _guardian Address that can pause withdrawals.
/// @param _paused Sets the contract's pausability state. /// @param _paused Sets the contract's pausability state.
/// @param _config Address of the SystemConfig contract. /// @param _systemConfig Address of the SystemConfig contract.
constructor( function initialize(L2OutputOracle _l2Oracle, address _guardian, SystemConfig _systemConfig, bool _paused) public reinitializer(2) {
L2OutputOracle _l2Oracle, l2Sender = Constants.DEFAULT_L2_SENDER;
address _guardian,
bool _paused,
SystemConfig _config
) Semver(1, 7, 2) {
L2_ORACLE = _l2Oracle; L2_ORACLE = _l2Oracle;
SYSTEM_CONFIG = _systemConfig;
GUARDIAN = _guardian; GUARDIAN = _guardian;
SYSTEM_CONFIG = _config;
initialize(_paused);
}
/// @notice Initializer.
function initialize(bool _paused) public initializer {
l2Sender = Constants.DEFAULT_L2_SENDER;
paused = _paused; paused = _paused;
__ResourceMetering_init(); __ResourceMetering_init();
} }
......
...@@ -207,18 +207,16 @@ contract Portal_Initializer is L2OutputOracle_Initializer { ...@@ -207,18 +207,16 @@ contract Portal_Initializer is L2OutputOracle_Initializer {
_config: config _config: config
}); });
opImpl = new OptimismPortal({ opImpl = new OptimismPortal();
_l2Oracle: oracle,
_guardian: guardian,
_paused: true,
_config: systemConfig
});
Proxy proxy = new Proxy(multisig); Proxy proxy = new Proxy(multisig);
vm.prank(multisig); vm.prank(multisig);
proxy.upgradeToAndCall( proxy.upgradeToAndCall(
address(opImpl), address(opImpl),
abi.encodeWithSelector(OptimismPortal.initialize.selector, false) abi.encodeCall(
OptimismPortal.initialize,
(oracle, guardian, systemConfig, false)
)
); );
op = OptimismPortal(payable(address(proxy))); op = OptimismPortal(payable(address(proxy)));
vm.label(address(op), "OptimismPortal"); vm.label(address(op), "OptimismPortal");
...@@ -726,7 +724,7 @@ contract NextImpl is Initializable { ...@@ -726,7 +724,7 @@ contract NextImpl is Initializable {
bytes32 slot21; bytes32 slot21;
bytes32 public constant slot21Init = bytes32(hex"1337"); bytes32 public constant slot21Init = bytes32(hex"1337");
function initialize() public reinitializer(2) { function initialize(uint8 _init) public reinitializer(_init) {
// Slot21 is unused by an of our upgradeable contracts. // Slot21 is unused by an of our upgradeable contracts.
// This is used to verify that we can access this value after an upgrade. // This is used to verify that we can access this value after an upgrade.
slot21 = slot21Init; slot21 = slot21Init;
......
...@@ -454,7 +454,7 @@ contract L2OutputOracleUpgradeable_Test is L2OutputOracle_Initializer { ...@@ -454,7 +454,7 @@ contract L2OutputOracleUpgradeable_Test is L2OutputOracle_Initializer {
vm.startPrank(multisig); vm.startPrank(multisig);
proxy.upgradeToAndCall( proxy.upgradeToAndCall(
address(nextImpl), address(nextImpl),
abi.encodeWithSelector(NextImpl.initialize.selector) abi.encodeWithSelector(NextImpl.initialize.selector, 2)
); );
assertEq(proxy.implementation(), address(nextImpl)); assertEq(proxy.implementation(), address(nextImpl));
......
...@@ -14,6 +14,7 @@ import { Proxy } from "../src/universal/Proxy.sol"; ...@@ -14,6 +14,7 @@ import { Proxy } from "../src/universal/Proxy.sol";
import { ResourceMetering } from "../src/L1/ResourceMetering.sol"; import { ResourceMetering } from "../src/L1/ResourceMetering.sol";
import { AddressAliasHelper } from "../src/vendor/AddressAliasHelper.sol"; import { AddressAliasHelper } from "../src/vendor/AddressAliasHelper.sol";
import { L2OutputOracle } from "../src/L1/L2OutputOracle.sol"; import { L2OutputOracle } from "../src/L1/L2OutputOracle.sol";
import { SystemConfig } from "../src/L1/SystemConfig.sol";
// Target contract // Target contract
import { OptimismPortal } from "../src/L1/OptimismPortal.sol"; import { OptimismPortal } from "../src/L1/OptimismPortal.sol";
...@@ -1121,13 +1122,23 @@ contract OptimismPortalUpgradeable_Test is Portal_Initializer { ...@@ -1121,13 +1122,23 @@ contract OptimismPortalUpgradeable_Test is Portal_Initializer {
/// @dev Tests that the proxy cannot be initialized twice. /// @dev Tests that the proxy cannot be initialized twice.
function test_initialize_cannotInitProxy_reverts() external { function test_initialize_cannotInitProxy_reverts() external {
vm.expectRevert("Initializable: contract is already initialized"); vm.expectRevert("Initializable: contract is already initialized");
OptimismPortal(payable(proxy)).initialize(false); OptimismPortal(payable(proxy)).initialize({
_l2Oracle: L2OutputOracle(address(0)),
_systemConfig: SystemConfig(address(0)),
_guardian: address(0),
_paused: false
});
} }
/// @dev Tests that the implementation cannot be initialized twice. /// @dev Tests that the implementation cannot be initialized twice.
function test_initialize_cannotInitImpl_reverts() external { function test_initialize_cannotInitImpl_reverts() external {
vm.expectRevert("Initializable: contract is already initialized"); vm.expectRevert("Initializable: contract is already initialized");
OptimismPortal(opImpl).initialize(false); OptimismPortal(opImpl).initialize({
_l2Oracle: L2OutputOracle(address(0)),
_systemConfig: SystemConfig(address(0)),
_guardian: address(0),
_paused: false
});
} }
/// @dev Tests that the proxy can be upgraded. /// @dev Tests that the proxy can be upgraded.
...@@ -1138,9 +1149,11 @@ contract OptimismPortalUpgradeable_Test is Portal_Initializer { ...@@ -1138,9 +1149,11 @@ contract OptimismPortalUpgradeable_Test is Portal_Initializer {
NextImpl nextImpl = new NextImpl(); NextImpl nextImpl = new NextImpl();
vm.startPrank(multisig); vm.startPrank(multisig);
// The value passed to the initialize must be larger than the last value
// that initialize was called with.
proxy.upgradeToAndCall( proxy.upgradeToAndCall(
address(nextImpl), address(nextImpl),
abi.encodeWithSelector(NextImpl.initialize.selector) abi.encodeWithSelector(NextImpl.initialize.selector, 3)
); );
assertEq(proxy.implementation(), address(nextImpl)); assertEq(proxy.implementation(), address(nextImpl));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment