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  }