Commit ca604d59 authored by Mark Tyneway's avatar Mark Tyneway Committed by GitHub

contracts: update chain assertions (#12323)

* contracts: update chain assertions

Updates the assertion that the storage is either 1 or 0xff.
This enables the usage of `_disableInitializers` which is
required for the Standard L2 Genesis project, so that
the `SystemConfig` doesn't make external calls during its
deployment.

* lint: fix

* nit: address naming

* rebase and fix build

* build: fix

* build: fix
parent 035129de
...@@ -79,7 +79,7 @@ library ChainAssertions { ...@@ -79,7 +79,7 @@ library ChainAssertions {
); );
// Check that the contract is initialized // Check that the contract is initialized
assertSlotValueIsOne({ _contractAddress: address(config), _slot: 0, _offset: 0 }); assertInitializedSlotIsSet({ _contractAddress: address(config), _slot: 0, _offset: 0 });
IResourceMetering.ResourceConfig memory resourceConfig = config.resourceConfig(); IResourceMetering.ResourceConfig memory resourceConfig = config.resourceConfig();
...@@ -175,7 +175,7 @@ library ChainAssertions { ...@@ -175,7 +175,7 @@ library ChainAssertions {
require(address(messenger) != address(0), "CHECK-L1XDM-10"); require(address(messenger) != address(0), "CHECK-L1XDM-10");
// Check that the contract is initialized // Check that the contract is initialized
assertSlotValueIsOne({ _contractAddress: address(messenger), _slot: 0, _offset: 20 }); assertInitializedSlotIsSet({ _contractAddress: address(messenger), _slot: 0, _offset: 20 });
require(address(messenger.OTHER_MESSENGER()) == Predeploys.L2_CROSS_DOMAIN_MESSENGER, "CHECK-L1XDM-20"); require(address(messenger.OTHER_MESSENGER()) == Predeploys.L2_CROSS_DOMAIN_MESSENGER, "CHECK-L1XDM-20");
require(address(messenger.otherMessenger()) == Predeploys.L2_CROSS_DOMAIN_MESSENGER, "CHECK-L1XDM-30"); require(address(messenger.otherMessenger()) == Predeploys.L2_CROSS_DOMAIN_MESSENGER, "CHECK-L1XDM-30");
...@@ -204,7 +204,7 @@ library ChainAssertions { ...@@ -204,7 +204,7 @@ library ChainAssertions {
require(address(bridge) != address(0), "CHECK-L1SB-10"); require(address(bridge) != address(0), "CHECK-L1SB-10");
// Check that the contract is initialized // Check that the contract is initialized
assertSlotValueIsOne({ _contractAddress: address(bridge), _slot: 0, _offset: 0 }); assertInitializedSlotIsSet({ _contractAddress: address(bridge), _slot: 0, _offset: 0 });
if (_isProxy) { if (_isProxy) {
require(address(bridge.MESSENGER()) == _contracts.L1CrossDomainMessenger, "CHECK-L1SB-20"); require(address(bridge.MESSENGER()) == _contracts.L1CrossDomainMessenger, "CHECK-L1SB-20");
...@@ -239,7 +239,7 @@ library ChainAssertions { ...@@ -239,7 +239,7 @@ library ChainAssertions {
require(address(factory) != address(0), "CHECK-DG-10"); require(address(factory) != address(0), "CHECK-DG-10");
// Check that the contract is initialized // Check that the contract is initialized
assertSlotValueIsOne({ _contractAddress: address(factory), _slot: 0, _offset: 0 }); assertInitializedSlotIsSet({ _contractAddress: address(factory), _slot: 0, _offset: 0 });
// The same check is made for both proxy and implementation // The same check is made for both proxy and implementation
require(factory.owner() == _expectedOwner, "CHECK-DG-20"); require(factory.owner() == _expectedOwner, "CHECK-DG-20");
...@@ -279,7 +279,7 @@ library ChainAssertions { ...@@ -279,7 +279,7 @@ library ChainAssertions {
require(address(weth) != address(0), "CHECK-DWETH-10"); require(address(weth) != address(0), "CHECK-DWETH-10");
// Check that the contract is initialized // Check that the contract is initialized
assertSlotValueIsOne({ _contractAddress: address(weth), _slot: 0, _offset: 0 }); assertInitializedSlotIsSet({ _contractAddress: address(weth), _slot: 0, _offset: 0 });
if (_isProxy) { if (_isProxy) {
require(weth.owner() == _expectedOwner, "CHECK-DWETH-20"); require(weth.owner() == _expectedOwner, "CHECK-DWETH-20");
...@@ -310,7 +310,7 @@ library ChainAssertions { ...@@ -310,7 +310,7 @@ library ChainAssertions {
require(address(weth) != address(0), "CHECK-PDWETH-10"); require(address(weth) != address(0), "CHECK-PDWETH-10");
// Check that the contract is initialized // Check that the contract is initialized
assertSlotValueIsOne({ _contractAddress: address(weth), _slot: 0, _offset: 0 }); assertInitializedSlotIsSet({ _contractAddress: address(weth), _slot: 0, _offset: 0 });
if (_isProxy) { if (_isProxy) {
require(weth.owner() == _expectedOwner, "CHECK-PDWETH-20"); require(weth.owner() == _expectedOwner, "CHECK-PDWETH-20");
...@@ -341,7 +341,7 @@ library ChainAssertions { ...@@ -341,7 +341,7 @@ library ChainAssertions {
require(address(oracle) != address(0), "CHECK-L2OO-10"); require(address(oracle) != address(0), "CHECK-L2OO-10");
// Check that the contract is initialized // Check that the contract is initialized
assertSlotValueIsOne({ _contractAddress: address(oracle), _slot: 0, _offset: 0 }); assertInitializedSlotIsSet({ _contractAddress: address(oracle), _slot: 0, _offset: 0 });
if (_isProxy) { if (_isProxy) {
require(oracle.SUBMISSION_INTERVAL() == _cfg.l2OutputOracleSubmissionInterval(), "CHECK-L2OO-20"); require(oracle.SUBMISSION_INTERVAL() == _cfg.l2OutputOracleSubmissionInterval(), "CHECK-L2OO-20");
...@@ -383,7 +383,7 @@ library ChainAssertions { ...@@ -383,7 +383,7 @@ library ChainAssertions {
require(address(factory) != address(0), "CHECK-MERC20F-10"); require(address(factory) != address(0), "CHECK-MERC20F-10");
// Check that the contract is initialized // Check that the contract is initialized
assertSlotValueIsOne({ _contractAddress: address(factory), _slot: 0, _offset: 0 }); assertInitializedSlotIsSet({ _contractAddress: address(factory), _slot: 0, _offset: 0 });
if (_isProxy) { if (_isProxy) {
require(factory.BRIDGE() == _contracts.L1StandardBridge, "CHECK-MERC20F-10"); require(factory.BRIDGE() == _contracts.L1StandardBridge, "CHECK-MERC20F-10");
...@@ -406,7 +406,7 @@ library ChainAssertions { ...@@ -406,7 +406,7 @@ library ChainAssertions {
require(address(bridge) != address(0), "CHECK-L1ERC721B-10"); require(address(bridge) != address(0), "CHECK-L1ERC721B-10");
// Check that the contract is initialized // Check that the contract is initialized
assertSlotValueIsOne({ _contractAddress: address(bridge), _slot: 0, _offset: 0 }); assertInitializedSlotIsSet({ _contractAddress: address(bridge), _slot: 0, _offset: 0 });
require(address(bridge.OTHER_BRIDGE()) == Predeploys.L2_ERC721_BRIDGE, "CHECK-L1ERC721B-10"); require(address(bridge.OTHER_BRIDGE()) == Predeploys.L2_ERC721_BRIDGE, "CHECK-L1ERC721B-10");
require(address(bridge.otherBridge()) == Predeploys.L2_ERC721_BRIDGE, "CHECK-L1ERC721B-20"); require(address(bridge.otherBridge()) == Predeploys.L2_ERC721_BRIDGE, "CHECK-L1ERC721B-20");
...@@ -433,7 +433,7 @@ library ChainAssertions { ...@@ -433,7 +433,7 @@ library ChainAssertions {
require(address(portal) != address(0), "CHECK-OP-10"); require(address(portal) != address(0), "CHECK-OP-10");
// Check that the contract is initialized // Check that the contract is initialized
assertSlotValueIsOne({ _contractAddress: address(portal), _slot: 0, _offset: 0 }); assertInitializedSlotIsSet({ _contractAddress: address(portal), _slot: 0, _offset: 0 });
address guardian = _cfg.superchainConfigGuardian(); address guardian = _cfg.superchainConfigGuardian();
if (guardian.code.length == 0) { if (guardian.code.length == 0) {
...@@ -473,7 +473,7 @@ library ChainAssertions { ...@@ -473,7 +473,7 @@ library ChainAssertions {
require(address(portal) != address(0), "CHECK-OP2-10"); require(address(portal) != address(0), "CHECK-OP2-10");
// Check that the contract is initialized // Check that the contract is initialized
assertSlotValueIsOne({ _contractAddress: address(portal), _slot: 0, _offset: 0 }); assertInitializedSlotIsSet({ _contractAddress: address(portal), _slot: 0, _offset: 0 });
address guardian = _cfg.superchainConfigGuardian(); address guardian = _cfg.superchainConfigGuardian();
if (guardian.code.length == 0) { if (guardian.code.length == 0) {
...@@ -516,7 +516,7 @@ library ChainAssertions { ...@@ -516,7 +516,7 @@ library ChainAssertions {
require(address(versions) != address(0), "CHECK-PV-10"); require(address(versions) != address(0), "CHECK-PV-10");
// Check that the contract is initialized // Check that the contract is initialized
assertSlotValueIsOne({ _contractAddress: address(versions), _slot: 0, _offset: 0 }); assertInitializedSlotIsSet({ _contractAddress: address(versions), _slot: 0, _offset: 0 });
if (_isProxy) { if (_isProxy) {
require(versions.owner() == _cfg.finalSystemOwner(), "CHECK-PV-20"); require(versions.owner() == _cfg.finalSystemOwner(), "CHECK-PV-20");
...@@ -548,7 +548,7 @@ library ChainAssertions { ...@@ -548,7 +548,7 @@ library ChainAssertions {
require(address(superchainConfig) != address(0), "CHECK-SC-10"); require(address(superchainConfig) != address(0), "CHECK-SC-10");
// Check that the contract is initialized // Check that the contract is initialized
assertSlotValueIsOne({ _contractAddress: address(superchainConfig), _slot: 0, _offset: 0 }); assertInitializedSlotIsSet({ _contractAddress: address(superchainConfig), _slot: 0, _offset: 0 });
if (_isProxy) { if (_isProxy) {
require(superchainConfig.guardian() == _cfg.superchainConfigGuardian(), "CHECK-SC-20"); require(superchainConfig.guardian() == _cfg.superchainConfigGuardian(), "CHECK-SC-20");
...@@ -559,15 +559,6 @@ library ChainAssertions { ...@@ -559,15 +559,6 @@ library ChainAssertions {
} }
} }
/// @dev Asserts that for a given contract the value of a storage slot at an offset is 1.
function assertSlotValueIsOne(address _contractAddress, uint256 _slot, uint256 _offset) internal view {
bytes32 slotVal = vm.load(_contractAddress, bytes32(_slot));
require(
uint8((uint256(slotVal) >> (_offset * 8)) & 0xFF) == uint8(1),
"Storage value is not 1 at the given slot and offset"
);
}
/// @notice Asserts that the SuperchainConfig is setup correctly /// @notice Asserts that the SuperchainConfig is setup correctly
function checkOPContractsManager(Types.ContractSet memory _contracts, bool _isProxy) internal view { function checkOPContractsManager(Types.ContractSet memory _contracts, bool _isProxy) internal view {
OPContractsManager opcm = OPContractsManager(_contracts.OPContractsManager); OPContractsManager opcm = OPContractsManager(_contracts.OPContractsManager);
...@@ -579,7 +570,7 @@ library ChainAssertions { ...@@ -579,7 +570,7 @@ library ChainAssertions {
require(address(opcm) != address(0), "CHECK-OPCM-10"); require(address(opcm) != address(0), "CHECK-OPCM-10");
// Check that the contract is initialized // Check that the contract is initialized
assertSlotValueIsOne({ _contractAddress: address(opcm), _slot: 0, _offset: 0 }); assertInitializedSlotIsSet({ _contractAddress: address(opcm), _slot: 0, _offset: 0 });
// These values are immutable so are shared by the proxy and implementation // These values are immutable so are shared by the proxy and implementation
require(address(opcm.superchainConfig()) == address(_contracts.SuperchainConfig), "CHECK-OPCM-30"); require(address(opcm.superchainConfig()) == address(_contracts.SuperchainConfig), "CHECK-OPCM-30");
...@@ -587,4 +578,12 @@ library ChainAssertions { ...@@ -587,4 +578,12 @@ library ChainAssertions {
// TODO: Add assertions for blueprints and setters? // TODO: Add assertions for blueprints and setters?
} }
/// @dev Asserts that for a given contract the value of a storage slot at an offset is 1 or 0xff.
/// A call to `initialize` will set it to 1 and a call to _disableInitializers will set it to 0xff.
function assertInitializedSlotIsSet(address _contractAddress, uint256 _slot, uint256 _offset) internal view {
bytes32 slotVal = vm.load(_contractAddress, bytes32(_slot));
uint8 val = uint8((uint256(slotVal) >> (_offset * 8)) & 0xFF);
require(val == uint8(1) || val == uint8(0xff), "Storage value is not 1 or 0xff at the given slot and offset");
}
} }
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