@@ -137,6 +137,8 @@ contract AnchorStateRegistry is Initializable, ISemver {
137137 /// @param _game The game to check.
138138 /// @return Whether the game is retired.
139139 function isGameRetired (IDisputeGame _game ) public view returns (bool ) {
140+ // Must be created at or after the respectedGameTypeUpdatedAt timestamp. Note that the
141+ // strict inequality exactly mirrors the logic in the OptimismPortal contract.
140142 return _game.createdAt ().raw () < portal.respectedGameTypeUpdatedAt ();
141143 }
142144
@@ -145,6 +147,13 @@ contract AnchorStateRegistry is Initializable, ISemver {
145147 /// invalidation conditions. The root claim of a proper game IS NOT guaranteed to be
146148 /// valid. The root claim of a proper game CAN BE incorrect and still be a proper game.
147149 /// DO NOT USE THIS FUNCTION ALONE TO DETERMINE IF A ROOT CLAIM IS VALID.
150+ /// @dev Note that it is possible for games to be created when their game type is not the
151+ /// respected game type. We do not consider these games to be Proper Games. isGameProper()
152+ /// can currently guarantee this because the OptimismPortal contract will always set the
153+ /// retirement timestamp whenever the respected game type is updated such that any games
154+ /// created before any update of the respected game type are automatically retired. If
155+ /// this coupling is broken, then we must instead check that the game type *was* the
156+ /// respected game type at the time of the game's creation.
148157 /// @param _game The game to check.
149158 /// @return Whether the game is a proper game.
150159 function isGameProper (IDisputeGame _game ) public view returns (bool ) {
@@ -171,9 +180,9 @@ contract AnchorStateRegistry is Initializable, ISemver {
171180 return true ;
172181 }
173182
174- /// @notice Callable by FaultDisputeGame contracts to update the anchor state. Pulls the anchor state directly from
175- /// the FaultDisputeGame contract and stores it in the registry if the new anchor state is valid and the
176- /// state is newer than the current anchor state .
183+ /// @notice Allows FaultDisputeGame contracts to attempt to become the new anchor game. A game
184+ /// can only become the new anchor game if it is not invalid (it is a Proper Game), it
185+ /// resolved in favor of the root claim, and it is newer than the current anchor game .
177186 function tryUpdateAnchorState () external {
178187 // Grab the game.
179188 IFaultDisputeGame game = IFaultDisputeGame (msg .sender );
@@ -190,7 +199,7 @@ contract AnchorStateRegistry is Initializable, ISemver {
190199 return ;
191200 }
192201
193- // No need to update anything if the anchor state is already newer .
202+ // Must be newer than the current anchor game .
194203 (, uint256 anchorL2BlockNumber ) = getAnchorRoot ();
195204 if (game.l2BlockNumber () <= anchorL2BlockNumber) {
196205 emit AnchorNotUpdated (game);
@@ -202,7 +211,10 @@ contract AnchorStateRegistry is Initializable, ISemver {
202211 emit AnchorUpdated (game);
203212 }
204213
205- /// @notice Sets the anchor state given the game.
214+ /// @notice Sets the anchor state given the game. Can only be triggered by the Guardian
215+ /// address. Unlike tryUpdateAnchorState(), this function does not check if the
216+ /// provided is newer than the existing anchor game. This allows the Guardian to
217+ /// recover from situations in which the current anchor game is invalid.
206218 /// @param _game The game to set the anchor state for.
207219 function setAnchorState (IFaultDisputeGame _game ) external {
208220 // Function can only be triggered by the guardian.
0 commit comments