github.com/ethereum-optimism/optimism@v1.7.2/packages/contracts-bedrock/src/L1/SystemConfig.sol (about)

     1  // SPDX-License-Identifier: MIT
     2  pragma solidity 0.8.15;
     3  
     4  import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
     5  import { ISemver } from "src/universal/ISemver.sol";
     6  import { ResourceMetering } from "src/L1/ResourceMetering.sol";
     7  import { Storage } from "src/libraries/Storage.sol";
     8  import { Constants } from "src/libraries/Constants.sol";
     9  
    10  /// @title SystemConfig
    11  /// @notice The SystemConfig contract is used to manage configuration of an Optimism network.
    12  ///         All configuration is stored on L1 and picked up by L2 as part of the derviation of
    13  ///         the L2 chain.
    14  contract SystemConfig is OwnableUpgradeable, ISemver {
    15      /// @notice Enum representing different types of updates.
    16      /// @custom:value BATCHER              Represents an update to the batcher hash.
    17      /// @custom:value GAS_CONFIG           Represents an update to txn fee config on L2.
    18      /// @custom:value GAS_LIMIT            Represents an update to gas limit on L2.
    19      /// @custom:value UNSAFE_BLOCK_SIGNER  Represents an update to the signer key for unsafe
    20      ///                                    block distrubution.
    21      enum UpdateType {
    22          BATCHER,
    23          GAS_CONFIG,
    24          GAS_LIMIT,
    25          UNSAFE_BLOCK_SIGNER
    26      }
    27  
    28      /// @notice Struct representing the addresses of L1 system contracts. These should be the
    29      ///         proxies and are network specific.
    30      struct Addresses {
    31          address l1CrossDomainMessenger;
    32          address l1ERC721Bridge;
    33          address l1StandardBridge;
    34          address l2OutputOracle;
    35          address optimismPortal;
    36          address optimismMintableERC20Factory;
    37      }
    38  
    39      /// @notice Version identifier, used for upgrades.
    40      uint256 public constant VERSION = 0;
    41  
    42      /// @notice Storage slot that the unsafe block signer is stored at.
    43      ///         Storing it at this deterministic storage slot allows for decoupling the storage
    44      ///         layout from the way that `solc` lays out storage. The `op-node` uses a storage
    45      ///         proof to fetch this value.
    46      /// @dev    NOTE: this value will be migrated to another storage slot in a future version.
    47      ///         User input should not be placed in storage in this contract until this migration
    48      ///         happens. It is unlikely that keccak second preimage resistance will be broken,
    49      ///         but it is better to be safe than sorry.
    50      bytes32 public constant UNSAFE_BLOCK_SIGNER_SLOT = keccak256("systemconfig.unsafeblocksigner");
    51  
    52      /// @notice Storage slot that the L1CrossDomainMessenger address is stored at.
    53      bytes32 public constant L1_CROSS_DOMAIN_MESSENGER_SLOT =
    54          bytes32(uint256(keccak256("systemconfig.l1crossdomainmessenger")) - 1);
    55  
    56      /// @notice Storage slot that the L1ERC721Bridge address is stored at.
    57      bytes32 public constant L1_ERC_721_BRIDGE_SLOT = bytes32(uint256(keccak256("systemconfig.l1erc721bridge")) - 1);
    58  
    59      /// @notice Storage slot that the L1StandardBridge address is stored at.
    60      bytes32 public constant L1_STANDARD_BRIDGE_SLOT = bytes32(uint256(keccak256("systemconfig.l1standardbridge")) - 1);
    61  
    62      /// @notice Storage slot that the L2OutputOracle address is stored at.
    63      bytes32 public constant L2_OUTPUT_ORACLE_SLOT = bytes32(uint256(keccak256("systemconfig.l2outputoracle")) - 1);
    64  
    65      /// @notice Storage slot that the OptimismPortal address is stored at.
    66      bytes32 public constant OPTIMISM_PORTAL_SLOT = bytes32(uint256(keccak256("systemconfig.optimismportal")) - 1);
    67  
    68      /// @notice Storage slot that the OptimismMintableERC20Factory address is stored at.
    69      bytes32 public constant OPTIMISM_MINTABLE_ERC20_FACTORY_SLOT =
    70          bytes32(uint256(keccak256("systemconfig.optimismmintableerc20factory")) - 1);
    71  
    72      /// @notice Storage slot that the batch inbox address is stored at.
    73      bytes32 public constant BATCH_INBOX_SLOT = bytes32(uint256(keccak256("systemconfig.batchinbox")) - 1);
    74  
    75      /// @notice Storage slot for block at which the op-node can start searching for logs from.
    76      bytes32 public constant START_BLOCK_SLOT = bytes32(uint256(keccak256("systemconfig.startBlock")) - 1);
    77  
    78      /// @notice Fixed L2 gas overhead. Used as part of the L2 fee calculation.
    79      uint256 public overhead;
    80  
    81      /// @notice Dynamic L2 gas overhead. Used as part of the L2 fee calculation.
    82      uint256 public scalar;
    83  
    84      /// @notice Identifier for the batcher.
    85      ///         For version 1 of this configuration, this is represented as an address left-padded
    86      ///         with zeros to 32 bytes.
    87      bytes32 public batcherHash;
    88  
    89      /// @notice L2 block gas limit.
    90      uint64 public gasLimit;
    91  
    92      /// @notice The configuration for the deposit fee market.
    93      ///         Used by the OptimismPortal to meter the cost of buying L2 gas on L1.
    94      ///         Set as internal with a getter so that the struct is returned instead of a tuple.
    95      ResourceMetering.ResourceConfig internal _resourceConfig;
    96  
    97      /// @notice Emitted when configuration is updated.
    98      /// @param version    SystemConfig version.
    99      /// @param updateType Type of update.
   100      /// @param data       Encoded update data.
   101      event ConfigUpdate(uint256 indexed version, UpdateType indexed updateType, bytes data);
   102  
   103      /// @notice Semantic version.
   104      /// @custom:semver 1.12.0
   105      string public constant version = "1.12.0";
   106  
   107      /// @notice Constructs the SystemConfig contract. Cannot set
   108      ///         the owner to `address(0)` due to the Ownable contract's
   109      ///         implementation, so set it to `address(0xdEaD)`
   110      /// @dev    START_BLOCK_SLOT is set to type(uint256).max here so that it will be a dead value
   111      ///         in the singleton and is skipped by initialize when setting the start block.
   112      constructor() {
   113          Storage.setUint(START_BLOCK_SLOT, type(uint256).max);
   114          initialize({
   115              _owner: address(0xdEaD),
   116              _overhead: 0,
   117              _scalar: 0,
   118              _batcherHash: bytes32(0),
   119              _gasLimit: 1,
   120              _unsafeBlockSigner: address(0),
   121              _config: ResourceMetering.ResourceConfig({
   122                  maxResourceLimit: 1,
   123                  elasticityMultiplier: 1,
   124                  baseFeeMaxChangeDenominator: 2,
   125                  minimumBaseFee: 0,
   126                  systemTxMaxGas: 0,
   127                  maximumBaseFee: 0
   128              }),
   129              _batchInbox: address(0),
   130              _addresses: SystemConfig.Addresses({
   131                  l1CrossDomainMessenger: address(0),
   132                  l1ERC721Bridge: address(0),
   133                  l1StandardBridge: address(0),
   134                  l2OutputOracle: address(0),
   135                  optimismPortal: address(0),
   136                  optimismMintableERC20Factory: address(0)
   137              })
   138          });
   139      }
   140  
   141      /// @notice Initializer.
   142      ///         The resource config must be set before the require check.
   143      /// @param _owner             Initial owner of the contract.
   144      /// @param _overhead          Initial overhead value.
   145      /// @param _scalar            Initial scalar value.
   146      /// @param _batcherHash       Initial batcher hash.
   147      /// @param _gasLimit          Initial gas limit.
   148      /// @param _unsafeBlockSigner Initial unsafe block signer address.
   149      /// @param _config            Initial ResourceConfig.
   150      /// @param _batchInbox        Batch inbox address. An identifier for the op-node to find
   151      ///                           canonical data.
   152      /// @param _addresses         Set of L1 contract addresses. These should be the proxies.
   153      function initialize(
   154          address _owner,
   155          uint256 _overhead,
   156          uint256 _scalar,
   157          bytes32 _batcherHash,
   158          uint64 _gasLimit,
   159          address _unsafeBlockSigner,
   160          ResourceMetering.ResourceConfig memory _config,
   161          address _batchInbox,
   162          SystemConfig.Addresses memory _addresses
   163      )
   164          public
   165          initializer
   166      {
   167          __Ownable_init();
   168          transferOwnership(_owner);
   169  
   170          // These are set in ascending order of their UpdateTypes.
   171          _setBatcherHash(_batcherHash);
   172          _setGasConfig({ _overhead: _overhead, _scalar: _scalar });
   173          _setGasLimit(_gasLimit);
   174  
   175          Storage.setAddress(UNSAFE_BLOCK_SIGNER_SLOT, _unsafeBlockSigner);
   176          Storage.setAddress(BATCH_INBOX_SLOT, _batchInbox);
   177          Storage.setAddress(L1_CROSS_DOMAIN_MESSENGER_SLOT, _addresses.l1CrossDomainMessenger);
   178          Storage.setAddress(L1_ERC_721_BRIDGE_SLOT, _addresses.l1ERC721Bridge);
   179          Storage.setAddress(L1_STANDARD_BRIDGE_SLOT, _addresses.l1StandardBridge);
   180          Storage.setAddress(L2_OUTPUT_ORACLE_SLOT, _addresses.l2OutputOracle);
   181          Storage.setAddress(OPTIMISM_PORTAL_SLOT, _addresses.optimismPortal);
   182          Storage.setAddress(OPTIMISM_MINTABLE_ERC20_FACTORY_SLOT, _addresses.optimismMintableERC20Factory);
   183  
   184          _setStartBlock();
   185  
   186          _setResourceConfig(_config);
   187          require(_gasLimit >= minimumGasLimit(), "SystemConfig: gas limit too low");
   188      }
   189  
   190      /// @notice Returns the minimum L2 gas limit that can be safely set for the system to
   191      ///         operate. The L2 gas limit must be larger than or equal to the amount of
   192      ///         gas that is allocated for deposits per block plus the amount of gas that
   193      ///         is allocated for the system transaction.
   194      ///         This function is used to determine if changes to parameters are safe.
   195      /// @return uint64 Minimum gas limit.
   196      function minimumGasLimit() public view returns (uint64) {
   197          return uint64(_resourceConfig.maxResourceLimit) + uint64(_resourceConfig.systemTxMaxGas);
   198      }
   199  
   200      /// @notice High level getter for the unsafe block signer address.
   201      ///         Unsafe blocks can be propagated across the p2p network if they are signed by the
   202      ///         key corresponding to this address.
   203      /// @return addr_ Address of the unsafe block signer.
   204      function unsafeBlockSigner() public view returns (address addr_) {
   205          addr_ = Storage.getAddress(UNSAFE_BLOCK_SIGNER_SLOT);
   206      }
   207  
   208      /// @notice Getter for the L1CrossDomainMessenger address.
   209      function l1CrossDomainMessenger() external view returns (address addr_) {
   210          addr_ = Storage.getAddress(L1_CROSS_DOMAIN_MESSENGER_SLOT);
   211      }
   212  
   213      /// @notice Getter for the L1ERC721Bridge address.
   214      function l1ERC721Bridge() external view returns (address addr_) {
   215          addr_ = Storage.getAddress(L1_ERC_721_BRIDGE_SLOT);
   216      }
   217  
   218      /// @notice Getter for the L1StandardBridge address.
   219      function l1StandardBridge() external view returns (address addr_) {
   220          addr_ = Storage.getAddress(L1_STANDARD_BRIDGE_SLOT);
   221      }
   222  
   223      /// @notice Getter for the L2OutputOracle address.
   224      function l2OutputOracle() external view returns (address addr_) {
   225          addr_ = Storage.getAddress(L2_OUTPUT_ORACLE_SLOT);
   226      }
   227  
   228      /// @notice Getter for the OptimismPortal address.
   229      function optimismPortal() external view returns (address addr_) {
   230          addr_ = Storage.getAddress(OPTIMISM_PORTAL_SLOT);
   231      }
   232  
   233      /// @notice Getter for the OptimismMintableERC20Factory address.
   234      function optimismMintableERC20Factory() external view returns (address addr_) {
   235          addr_ = Storage.getAddress(OPTIMISM_MINTABLE_ERC20_FACTORY_SLOT);
   236      }
   237  
   238      /// @notice Getter for the BatchInbox address.
   239      function batchInbox() external view returns (address addr_) {
   240          addr_ = Storage.getAddress(BATCH_INBOX_SLOT);
   241      }
   242  
   243      /// @notice Getter for the StartBlock number.
   244      function startBlock() external view returns (uint256 startBlock_) {
   245          startBlock_ = Storage.getUint(START_BLOCK_SLOT);
   246      }
   247  
   248      /// @notice Updates the unsafe block signer address. Can only be called by the owner.
   249      /// @param _unsafeBlockSigner New unsafe block signer address.
   250      function setUnsafeBlockSigner(address _unsafeBlockSigner) external onlyOwner {
   251          _setUnsafeBlockSigner(_unsafeBlockSigner);
   252      }
   253  
   254      /// @notice Updates the unsafe block signer address.
   255      /// @param _unsafeBlockSigner New unsafe block signer address.
   256      function _setUnsafeBlockSigner(address _unsafeBlockSigner) internal {
   257          Storage.setAddress(UNSAFE_BLOCK_SIGNER_SLOT, _unsafeBlockSigner);
   258  
   259          bytes memory data = abi.encode(_unsafeBlockSigner);
   260          emit ConfigUpdate(VERSION, UpdateType.UNSAFE_BLOCK_SIGNER, data);
   261      }
   262  
   263      /// @notice Updates the batcher hash. Can only be called by the owner.
   264      /// @param _batcherHash New batcher hash.
   265      function setBatcherHash(bytes32 _batcherHash) external onlyOwner {
   266          _setBatcherHash(_batcherHash);
   267      }
   268  
   269      /// @notice Internal function for updating the batcher hash.
   270      /// @param _batcherHash New batcher hash.
   271      function _setBatcherHash(bytes32 _batcherHash) internal {
   272          batcherHash = _batcherHash;
   273  
   274          bytes memory data = abi.encode(_batcherHash);
   275          emit ConfigUpdate(VERSION, UpdateType.BATCHER, data);
   276      }
   277  
   278      /// @notice Updates gas config. Can only be called by the owner.
   279      /// @param _overhead New overhead value.
   280      /// @param _scalar   New scalar value.
   281      function setGasConfig(uint256 _overhead, uint256 _scalar) external onlyOwner {
   282          _setGasConfig(_overhead, _scalar);
   283      }
   284  
   285      /// @notice Internal function for updating the gas config.
   286      /// @param _overhead New overhead value.
   287      /// @param _scalar   New scalar value.
   288      function _setGasConfig(uint256 _overhead, uint256 _scalar) internal {
   289          overhead = _overhead;
   290          scalar = _scalar;
   291  
   292          bytes memory data = abi.encode(_overhead, _scalar);
   293          emit ConfigUpdate(VERSION, UpdateType.GAS_CONFIG, data);
   294      }
   295  
   296      /// @notice Updates the L2 gas limit. Can only be called by the owner.
   297      /// @param _gasLimit New gas limit.
   298      function setGasLimit(uint64 _gasLimit) external onlyOwner {
   299          _setGasLimit(_gasLimit);
   300      }
   301  
   302      /// @notice Internal function for updating the L2 gas limit.
   303      /// @param _gasLimit New gas limit.
   304      function _setGasLimit(uint64 _gasLimit) internal {
   305          require(_gasLimit >= minimumGasLimit(), "SystemConfig: gas limit too low");
   306          gasLimit = _gasLimit;
   307  
   308          bytes memory data = abi.encode(_gasLimit);
   309          emit ConfigUpdate(VERSION, UpdateType.GAS_LIMIT, data);
   310      }
   311  
   312      /// @notice Sets the start block in a backwards compatible way. Proxies
   313      ///         that were initialized before the startBlock existed in storage
   314      ///         can have their start block set by a user provided override.
   315      ///         A start block of 0 indicates that there is no override and the
   316      ///         start block will be set by `block.number`.
   317      /// @dev    This logic is used to patch legacy deployments with new storage values.
   318      ///         Use the override if it is provided as a non zero value and the value
   319      ///         has not already been set in storage. Use `block.number` if the value
   320      ///         has already been set in storage
   321      function _setStartBlock() internal {
   322          if (Storage.getUint(START_BLOCK_SLOT) == 0) {
   323              Storage.setUint(START_BLOCK_SLOT, block.number);
   324          }
   325      }
   326  
   327      /// @notice A getter for the resource config.
   328      ///         Ensures that the struct is returned instead of a tuple.
   329      /// @return ResourceConfig
   330      function resourceConfig() external view returns (ResourceMetering.ResourceConfig memory) {
   331          return _resourceConfig;
   332      }
   333  
   334      /// @notice An external setter for the resource config.
   335      ///         In the future, this method may emit an event that the `op-node` picks up
   336      ///         for when the resource config is changed.
   337      /// @param _config The new resource config values.
   338      function setResourceConfig(ResourceMetering.ResourceConfig memory _config) external onlyOwner {
   339          _setResourceConfig(_config);
   340      }
   341  
   342      /// @notice An internal setter for the resource config.
   343      ///         Ensures that the config is sane before storing it by checking for invariants.
   344      /// @param _config The new resource config.
   345      function _setResourceConfig(ResourceMetering.ResourceConfig memory _config) internal {
   346          // Min base fee must be less than or equal to max base fee.
   347          require(
   348              _config.minimumBaseFee <= _config.maximumBaseFee, "SystemConfig: min base fee must be less than max base"
   349          );
   350          // Base fee change denominator must be greater than 1.
   351          require(_config.baseFeeMaxChangeDenominator > 1, "SystemConfig: denominator must be larger than 1");
   352          // Max resource limit plus system tx gas must be less than or equal to the L2 gas limit.
   353          // The gas limit must be increased before these values can be increased.
   354          require(_config.maxResourceLimit + _config.systemTxMaxGas <= gasLimit, "SystemConfig: gas limit too low");
   355          // Elasticity multiplier must be greater than 0.
   356          require(_config.elasticityMultiplier > 0, "SystemConfig: elasticity multiplier cannot be 0");
   357          // No precision loss when computing target resource limit.
   358          require(
   359              ((_config.maxResourceLimit / _config.elasticityMultiplier) * _config.elasticityMultiplier)
   360                  == _config.maxResourceLimit,
   361              "SystemConfig: precision loss with target resource limit"
   362          );
   363  
   364          _resourceConfig = _config;
   365      }
   366  }