github.com/ethereum-optimism/optimism@v1.7.2/packages/contracts-bedrock/test/L1/SystemConfig.t.sol (about) 1 // SPDX-License-Identifier: MIT 2 pragma solidity 0.8.15; 3 4 // Testing utilities 5 import { CommonTest } from "test/setup/CommonTest.sol"; 6 7 // Libraries 8 import { Constants } from "src/libraries/Constants.sol"; 9 import { EIP1967Helper } from "test/mocks/EIP1967Helper.sol"; 10 11 // Target contract dependencies 12 import { ResourceMetering } from "src/L1/ResourceMetering.sol"; 13 import { Proxy } from "src/universal/Proxy.sol"; 14 15 // Target contract 16 import { SystemConfig } from "src/L1/SystemConfig.sol"; 17 18 contract SystemConfig_Init is CommonTest { 19 event ConfigUpdate(uint256 indexed version, SystemConfig.UpdateType indexed updateType, bytes data); 20 } 21 22 contract SystemConfig_Initialize_Test is SystemConfig_Init { 23 address batchInbox; 24 address owner; 25 uint256 overhead; 26 uint256 scalar; 27 bytes32 batcherHash; 28 uint64 gasLimit; 29 address unsafeBlockSigner; 30 address systemConfigImpl; 31 address optimismMintableERC20Factory; 32 33 function setUp() public virtual override { 34 super.setUp(); 35 batchInbox = deploy.cfg().batchInboxAddress(); 36 owner = deploy.cfg().finalSystemOwner(); 37 overhead = deploy.cfg().gasPriceOracleOverhead(); 38 scalar = deploy.cfg().gasPriceOracleScalar(); 39 batcherHash = bytes32(uint256(uint160(deploy.cfg().batchSenderAddress()))); 40 gasLimit = uint64(deploy.cfg().l2GenesisBlockGasLimit()); 41 unsafeBlockSigner = deploy.cfg().p2pSequencerAddress(); 42 systemConfigImpl = deploy.mustGetAddress("SystemConfig"); 43 optimismMintableERC20Factory = deploy.mustGetAddress("OptimismMintableERC20FactoryProxy"); 44 } 45 46 /// @dev Tests that constructor sets the correct values. 47 function test_constructor_succeeds() external { 48 SystemConfig impl = SystemConfig(systemConfigImpl); 49 assertEq(impl.owner(), address(0xdEaD)); 50 assertEq(impl.overhead(), 0); 51 assertEq(impl.scalar(), 0); 52 assertEq(impl.batcherHash(), bytes32(0)); 53 assertEq(impl.gasLimit(), 1); 54 assertEq(impl.unsafeBlockSigner(), address(0)); 55 ResourceMetering.ResourceConfig memory actual = impl.resourceConfig(); 56 assertEq(actual.maxResourceLimit, 1); 57 assertEq(actual.elasticityMultiplier, 1); 58 assertEq(actual.baseFeeMaxChangeDenominator, 2); 59 assertEq(actual.minimumBaseFee, 0); 60 assertEq(actual.systemTxMaxGas, 0); 61 assertEq(actual.maximumBaseFee, 0); 62 assertEq(impl.startBlock(), type(uint256).max); 63 assertEq(address(impl.batchInbox()), address(0)); 64 // Check addresses 65 assertEq(address(impl.l1CrossDomainMessenger()), address(0)); 66 assertEq(address(impl.l1ERC721Bridge()), address(0)); 67 assertEq(address(impl.l1StandardBridge()), address(0)); 68 assertEq(address(impl.l2OutputOracle()), address(0)); 69 assertEq(address(impl.optimismPortal()), address(0)); 70 assertEq(address(impl.optimismMintableERC20Factory()), address(0)); 71 } 72 73 /// @dev Tests that initailization sets the correct values. 74 function test_initialize_succeeds() external { 75 assertEq(systemConfig.owner(), owner); 76 assertEq(systemConfig.overhead(), overhead); 77 assertEq(systemConfig.scalar(), scalar); 78 assertEq(systemConfig.batcherHash(), batcherHash); 79 assertEq(systemConfig.gasLimit(), gasLimit); 80 assertEq(systemConfig.unsafeBlockSigner(), unsafeBlockSigner); 81 // Depends on `initialize` being called with defaults 82 ResourceMetering.ResourceConfig memory rcfg = Constants.DEFAULT_RESOURCE_CONFIG(); 83 ResourceMetering.ResourceConfig memory actual = systemConfig.resourceConfig(); 84 assertEq(actual.maxResourceLimit, rcfg.maxResourceLimit); 85 assertEq(actual.elasticityMultiplier, rcfg.elasticityMultiplier); 86 assertEq(actual.baseFeeMaxChangeDenominator, rcfg.baseFeeMaxChangeDenominator); 87 assertEq(actual.minimumBaseFee, rcfg.minimumBaseFee); 88 assertEq(actual.systemTxMaxGas, rcfg.systemTxMaxGas); 89 assertEq(actual.maximumBaseFee, rcfg.maximumBaseFee); 90 // Depends on start block being set to 0 in `initialize` 91 uint256 cfgStartBlock = deploy.cfg().systemConfigStartBlock(); 92 assertEq(systemConfig.startBlock(), (cfgStartBlock == 0 ? block.number : cfgStartBlock)); 93 assertEq(address(systemConfig.batchInbox()), address(batchInbox)); 94 // Check addresses 95 assertEq(address(systemConfig.l1CrossDomainMessenger()), address(l1CrossDomainMessenger)); 96 assertEq(address(systemConfig.l1ERC721Bridge()), address(l1ERC721Bridge)); 97 assertEq(address(systemConfig.l1StandardBridge()), address(l1StandardBridge)); 98 assertEq(address(systemConfig.l2OutputOracle()), address(l2OutputOracle)); 99 assertEq(address(systemConfig.optimismPortal()), address(optimismPortal)); 100 assertEq(address(systemConfig.optimismMintableERC20Factory()), address(optimismMintableERC20Factory)); 101 } 102 } 103 104 contract SystemConfig_Initialize_TestFail is SystemConfig_Initialize_Test { 105 /// @dev Tests that initialization reverts if the gas limit is too low. 106 function test_initialize_lowGasLimit_reverts() external { 107 uint64 minimumGasLimit = systemConfig.minimumGasLimit(); 108 109 // Wipe out the initialized slot so the proxy can be initialized again 110 vm.store(address(systemConfig), bytes32(0), bytes32(0)); 111 112 address admin = address(uint160(uint256(vm.load(address(systemConfig), Constants.PROXY_OWNER_ADDRESS)))); 113 vm.prank(admin); 114 115 vm.expectRevert("SystemConfig: gas limit too low"); 116 systemConfig.initialize({ 117 _owner: alice, 118 _overhead: 2100, 119 _scalar: 1000000, 120 _batcherHash: bytes32(hex"abcd"), 121 _gasLimit: minimumGasLimit - 1, 122 _unsafeBlockSigner: address(1), 123 _config: Constants.DEFAULT_RESOURCE_CONFIG(), 124 _batchInbox: address(0), 125 _addresses: SystemConfig.Addresses({ 126 l1CrossDomainMessenger: address(0), 127 l1ERC721Bridge: address(0), 128 l1StandardBridge: address(0), 129 l2OutputOracle: address(0), 130 optimismPortal: address(0), 131 optimismMintableERC20Factory: address(0) 132 }) 133 }); 134 } 135 136 /// @dev Tests that startBlock is updated correctly when it's zero. 137 function test_startBlock_update_succeeds() external { 138 // Wipe out the initialized slot so the proxy can be initialized again 139 vm.store(address(systemConfig), bytes32(0), bytes32(0)); 140 // Set slot startBlock to zero 141 vm.store(address(systemConfig), systemConfig.START_BLOCK_SLOT(), bytes32(uint256(0))); 142 143 // Initialize and check that StartBlock updates to current block number 144 vm.prank(systemConfig.owner()); 145 systemConfig.initialize({ 146 _owner: alice, 147 _overhead: 2100, 148 _scalar: 1000000, 149 _batcherHash: bytes32(hex"abcd"), 150 _gasLimit: gasLimit, 151 _unsafeBlockSigner: address(1), 152 _config: Constants.DEFAULT_RESOURCE_CONFIG(), 153 _batchInbox: address(0), 154 _addresses: SystemConfig.Addresses({ 155 l1CrossDomainMessenger: address(0), 156 l1ERC721Bridge: address(0), 157 l1StandardBridge: address(0), 158 l2OutputOracle: address(0), 159 optimismPortal: address(0), 160 optimismMintableERC20Factory: address(0) 161 }) 162 }); 163 assertEq(systemConfig.startBlock(), block.number); 164 } 165 166 /// @dev Tests that startBlock is not updated when it's not zero. 167 function test_startBlock_update_fails() external { 168 // Wipe out the initialized slot so the proxy can be initialized again 169 vm.store(address(systemConfig), bytes32(0), bytes32(0)); 170 // Set slot startBlock to non-zero value 1 171 vm.store(address(systemConfig), systemConfig.START_BLOCK_SLOT(), bytes32(uint256(1))); 172 173 // Initialize and check that StartBlock doesn't update 174 vm.prank(systemConfig.owner()); 175 systemConfig.initialize({ 176 _owner: alice, 177 _overhead: 2100, 178 _scalar: 1000000, 179 _batcherHash: bytes32(hex"abcd"), 180 _gasLimit: gasLimit, 181 _unsafeBlockSigner: address(1), 182 _config: Constants.DEFAULT_RESOURCE_CONFIG(), 183 _batchInbox: address(0), 184 _addresses: SystemConfig.Addresses({ 185 l1CrossDomainMessenger: address(0), 186 l1ERC721Bridge: address(0), 187 l1StandardBridge: address(0), 188 l2OutputOracle: address(0), 189 optimismPortal: address(0), 190 optimismMintableERC20Factory: address(0) 191 }) 192 }); 193 assertEq(systemConfig.startBlock(), 1); 194 } 195 } 196 197 contract SystemConfig_Setters_TestFail is SystemConfig_Init { 198 /// @dev Tests that `setBatcherHash` reverts if the caller is not the owner. 199 function test_setBatcherHash_notOwner_reverts() external { 200 vm.expectRevert("Ownable: caller is not the owner"); 201 systemConfig.setBatcherHash(bytes32(hex"")); 202 } 203 204 /// @dev Tests that `setGasConfig` reverts if the caller is not the owner. 205 function test_setGasConfig_notOwner_reverts() external { 206 vm.expectRevert("Ownable: caller is not the owner"); 207 systemConfig.setGasConfig(0, 0); 208 } 209 210 /// @dev Tests that `setGasLimit` reverts if the caller is not the owner. 211 function test_setGasLimit_notOwner_reverts() external { 212 vm.expectRevert("Ownable: caller is not the owner"); 213 systemConfig.setGasLimit(0); 214 } 215 216 /// @dev Tests that `setUnsafeBlockSigner` reverts if the caller is not the owner. 217 function test_setUnsafeBlockSigner_notOwner_reverts() external { 218 vm.expectRevert("Ownable: caller is not the owner"); 219 systemConfig.setUnsafeBlockSigner(address(0x20)); 220 } 221 222 /// @dev Tests that `setResourceConfig` reverts if the caller is not the owner. 223 function test_setResourceConfig_notOwner_reverts() external { 224 ResourceMetering.ResourceConfig memory config = Constants.DEFAULT_RESOURCE_CONFIG(); 225 vm.expectRevert("Ownable: caller is not the owner"); 226 systemConfig.setResourceConfig(config); 227 } 228 229 /// @dev Tests that `setResourceConfig` reverts if the min base fee 230 /// is greater than the maximum allowed base fee. 231 function test_setResourceConfig_badMinMax_reverts() external { 232 ResourceMetering.ResourceConfig memory config = ResourceMetering.ResourceConfig({ 233 maxResourceLimit: 20_000_000, 234 elasticityMultiplier: 10, 235 baseFeeMaxChangeDenominator: 8, 236 systemTxMaxGas: 1_000_000, 237 minimumBaseFee: 2 gwei, 238 maximumBaseFee: 1 gwei 239 }); 240 vm.prank(systemConfig.owner()); 241 vm.expectRevert("SystemConfig: min base fee must be less than max base"); 242 systemConfig.setResourceConfig(config); 243 } 244 245 /// @dev Tests that `setResourceConfig` reverts if the baseFeeMaxChangeDenominator 246 /// is zero. 247 function test_setResourceConfig_zeroDenominator_reverts() external { 248 ResourceMetering.ResourceConfig memory config = ResourceMetering.ResourceConfig({ 249 maxResourceLimit: 20_000_000, 250 elasticityMultiplier: 10, 251 baseFeeMaxChangeDenominator: 0, 252 systemTxMaxGas: 1_000_000, 253 minimumBaseFee: 1 gwei, 254 maximumBaseFee: 2 gwei 255 }); 256 vm.prank(systemConfig.owner()); 257 vm.expectRevert("SystemConfig: denominator must be larger than 1"); 258 systemConfig.setResourceConfig(config); 259 } 260 261 /// @dev Tests that `setResourceConfig` reverts if the gas limit is too low. 262 function test_setResourceConfig_lowGasLimit_reverts() external { 263 uint64 gasLimit = systemConfig.gasLimit(); 264 265 ResourceMetering.ResourceConfig memory config = ResourceMetering.ResourceConfig({ 266 maxResourceLimit: uint32(gasLimit), 267 elasticityMultiplier: 10, 268 baseFeeMaxChangeDenominator: 8, 269 systemTxMaxGas: uint32(gasLimit), 270 minimumBaseFee: 1 gwei, 271 maximumBaseFee: 2 gwei 272 }); 273 vm.prank(systemConfig.owner()); 274 vm.expectRevert("SystemConfig: gas limit too low"); 275 systemConfig.setResourceConfig(config); 276 } 277 278 /// @dev Tests that `setResourceConfig` reverts if the elasticity multiplier 279 /// and max resource limit are configured such that there is a loss of precision. 280 function test_setResourceConfig_badPrecision_reverts() external { 281 ResourceMetering.ResourceConfig memory config = ResourceMetering.ResourceConfig({ 282 maxResourceLimit: 20_000_000, 283 elasticityMultiplier: 11, 284 baseFeeMaxChangeDenominator: 8, 285 systemTxMaxGas: 1_000_000, 286 minimumBaseFee: 1 gwei, 287 maximumBaseFee: 2 gwei 288 }); 289 vm.prank(systemConfig.owner()); 290 vm.expectRevert("SystemConfig: precision loss with target resource limit"); 291 systemConfig.setResourceConfig(config); 292 } 293 } 294 295 contract SystemConfig_Setters_Test is SystemConfig_Init { 296 /// @dev Tests that `setBatcherHash` updates the batcher hash successfully. 297 function testFuzz_setBatcherHash_succeeds(bytes32 newBatcherHash) external { 298 vm.expectEmit(true, true, true, true); 299 emit ConfigUpdate(0, SystemConfig.UpdateType.BATCHER, abi.encode(newBatcherHash)); 300 301 vm.prank(systemConfig.owner()); 302 systemConfig.setBatcherHash(newBatcherHash); 303 assertEq(systemConfig.batcherHash(), newBatcherHash); 304 } 305 306 /// @dev Tests that `setGasConfig` updates the overhead and scalar successfully. 307 function testFuzz_setGasConfig_succeeds(uint256 newOverhead, uint256 newScalar) external { 308 vm.expectEmit(true, true, true, true); 309 emit ConfigUpdate(0, SystemConfig.UpdateType.GAS_CONFIG, abi.encode(newOverhead, newScalar)); 310 311 vm.prank(systemConfig.owner()); 312 systemConfig.setGasConfig(newOverhead, newScalar); 313 assertEq(systemConfig.overhead(), newOverhead); 314 assertEq(systemConfig.scalar(), newScalar); 315 } 316 317 /// @dev Tests that `setGasLimit` updates the gas limit successfully. 318 function testFuzz_setGasLimit_succeeds(uint64 newGasLimit) external { 319 uint64 minimumGasLimit = systemConfig.minimumGasLimit(); 320 newGasLimit = uint64(bound(uint256(newGasLimit), uint256(minimumGasLimit), uint256(type(uint64).max))); 321 322 vm.expectEmit(true, true, true, true); 323 emit ConfigUpdate(0, SystemConfig.UpdateType.GAS_LIMIT, abi.encode(newGasLimit)); 324 325 vm.prank(systemConfig.owner()); 326 systemConfig.setGasLimit(newGasLimit); 327 assertEq(systemConfig.gasLimit(), newGasLimit); 328 } 329 330 /// @dev Tests that `setUnsafeBlockSigner` updates the block signer successfully. 331 function testFuzz_setUnsafeBlockSigner_succeeds(address newUnsafeSigner) external { 332 vm.expectEmit(true, true, true, true); 333 emit ConfigUpdate(0, SystemConfig.UpdateType.UNSAFE_BLOCK_SIGNER, abi.encode(newUnsafeSigner)); 334 335 vm.prank(systemConfig.owner()); 336 systemConfig.setUnsafeBlockSigner(newUnsafeSigner); 337 assertEq(systemConfig.unsafeBlockSigner(), newUnsafeSigner); 338 } 339 }