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

     1  // SPDX-License-Identifier: MIT
     2  pragma solidity 0.8.15;
     3  
     4  import { Initializable } from "@openzeppelin/contracts/proxy/utils/Initializable.sol";
     5  import { ISemver } from "src/universal/ISemver.sol";
     6  
     7  import { IAnchorStateRegistry } from "src/dispute/interfaces/IAnchorStateRegistry.sol";
     8  import { IFaultDisputeGame } from "src/dispute/interfaces/IFaultDisputeGame.sol";
     9  import { IDisputeGame } from "src/dispute/interfaces/IDisputeGame.sol";
    10  import { IDisputeGameFactory } from "src/dispute/interfaces/IDisputeGameFactory.sol";
    11  
    12  import "src/libraries/DisputeTypes.sol";
    13  
    14  /// @title AnchorStateRegistry
    15  /// @notice The AnchorStateRegistry is a contract that stores the latest "anchor" state for each available
    16  ///         FaultDisputeGame type. The anchor state is the latest state that has been proposed on L1 and was not
    17  ///         challenged within the challenge period. By using stored anchor states, new FaultDisputeGame instances can
    18  ///         be initialized with a more recent starting state which reduces the amount of required offchain computation.
    19  contract AnchorStateRegistry is Initializable, IAnchorStateRegistry, ISemver {
    20      /// @notice Describes an initial anchor state for a game type.
    21      struct StartingAnchorRoot {
    22          GameType gameType;
    23          OutputRoot outputRoot;
    24      }
    25  
    26      /// @notice Semantic version.
    27      /// @custom:semver 0.1.0
    28      string public constant version = "0.1.0";
    29  
    30      /// @notice DisputeGameFactory address.
    31      IDisputeGameFactory internal immutable DISPUTE_GAME_FACTORY;
    32  
    33      /// @inheritdoc IAnchorStateRegistry
    34      mapping(GameType => OutputRoot) public anchors;
    35  
    36      /// @param _disputeGameFactory DisputeGameFactory address.
    37      constructor(IDisputeGameFactory _disputeGameFactory) {
    38          DISPUTE_GAME_FACTORY = _disputeGameFactory;
    39  
    40          // Initialize the implementation with an empty array of starting anchor roots.
    41          initialize(new StartingAnchorRoot[](0));
    42      }
    43  
    44      /// @notice Initializes the contract.
    45      /// @param _startingAnchorRoots An array of starting anchor roots.
    46      function initialize(StartingAnchorRoot[] memory _startingAnchorRoots) public initializer {
    47          for (uint256 i = 0; i < _startingAnchorRoots.length; i++) {
    48              StartingAnchorRoot memory startingAnchorRoot = _startingAnchorRoots[i];
    49              anchors[startingAnchorRoot.gameType] = startingAnchorRoot.outputRoot;
    50          }
    51      }
    52  
    53      /// @inheritdoc IAnchorStateRegistry
    54      function disputeGameFactory() external view returns (IDisputeGameFactory) {
    55          return DISPUTE_GAME_FACTORY;
    56      }
    57  
    58      /// @inheritdoc IAnchorStateRegistry
    59      function tryUpdateAnchorState() external {
    60          // Grab the game and game data.
    61          IFaultDisputeGame game = IFaultDisputeGame(msg.sender);
    62          (GameType gameType, Claim rootClaim, bytes memory extraData) = game.gameData();
    63  
    64          // Grab the verified address of the game based on the game data.
    65          // slither-disable-next-line unused-return
    66          (IDisputeGame factoryRegisteredGame,) =
    67              DISPUTE_GAME_FACTORY.games({ _gameType: gameType, _rootClaim: rootClaim, _extraData: extraData });
    68  
    69          // Must be a valid game.
    70          require(
    71              address(factoryRegisteredGame) == address(game),
    72              "AnchorStateRegistry: fault dispute game not registered with factory"
    73          );
    74  
    75          // No need to update anything if the anchor state is already newer.
    76          if (game.l2BlockNumber() <= anchors[gameType].l2BlockNumber) {
    77              return;
    78          }
    79  
    80          // Must be a game that resolved in favor of the state.
    81          if (game.status() != GameStatus.DEFENDER_WINS) {
    82              return;
    83          }
    84  
    85          // Actually update the anchor state.
    86          anchors[gameType] = OutputRoot({ l2BlockNumber: game.l2BlockNumber(), root: Hash.wrap(game.rootClaim().raw()) });
    87      }
    88  }