AnchorStateRegistry
Table of Contents
- Overview
- Definitions
- Assumptions
- Invariants
- Function Specification
- constructor
- initialize
- paused
- respectedGameType
- retirementTimestamp
- disputeGameFinalityDelaySeconds
- setRespectedGameType
- updateRetirementTimestamp
- blacklistDisputeGame
- isGameRegistered
- isGameRespected
- isGameBlacklisted
- isGameRetired
- isGameProper
- isGameResolved
- isGameFinalized
- isGameClaimValid
- getAnchorRoot
- anchors
- setAnchorState
Overview
The AnchorStateRegistry
was designed as a registry where DisputeGame
contracts could store and
register their results so that these results could be used as the starting states for new
DisputeGame
instances. These starting states, called "anchor states", allow new DisputeGame
contracts to use a newer starting state to bound the size of the execution trace for any given
game.
We are generally aiming to shift the AnchorStateRegistry
to act as a unified source of truth for
the validity of DisputeGame
contracts and their corresponding root claims. This specification
corresponds to the first iteration of the AnchorStateRegistry
that will move us in this
direction.
Definitions
Dispute Game
A Dispute Game is a smart contract that makes a determination about the validity of some claim. In the context of the OP Stack, the claim is generally assumed to be a claim about the value of an output root at a given L2 block height. We assume that all Dispute Game contracts using the same AnchorStateRegistry contract are arguing over the same underlying state/claim structure.
Respected Game Type
The AnchorStateRegistry
contract defines a Respected Game Type which is the Dispute Game type
that is considered to be the correct by the AnchorStateRegistry
and, by extension, other
contracts that may rely on the assertions made within the AnchorStateRegistry
. The Respected Game
Type is, in a more general sense, a game type that the system believes will resolve correctly. For
now, the AnchorStateRegistry
only allows a single Respected Game Type.
Dispute Game Finality Delay (Airgap)
The Dispute Game Finality Delay or Airgap is the amount of time that must elapse after a game resolves before the game's result is considered "final".
Registered Game
A Dispute Game is considered to be a Registered Game if the game contract was created by the
system's DisputeGameFactory
contract.
Respected Game
A Dispute Game is considered to be a Respected Game if the game contract's game type was
the Respected Game Type defined by the AnchorStateRegistry
contract at the time of the game's
creation. Games that are not Respected Games cannot be used as an Anchor Game. See
Respected Game Type for more information.
Blacklisted Game
A Dispute Game is considered to be a Blacklisted Game if the game contract's address is marked
as blacklisted inside of the AnchorStateRegistry
contract.
Retirement Timestamp
The Retirement Timestamp is a timestamp value maintained within the AnchorStateRegistry
that
can be used to invalidate games. Games with a creation timestamp less than or equal to the
Retirement Timestamp are automatically considered to be invalid.
The RetirementTimestamp has the effect of retiring all games created before the specific transaction in which the retirement timestamp was set. This includes all games created in the same block as the transaction that set the Retirement Timestamp. We acknowledge the edge-case that games created in the same block after the Retirement Timestamp was set will be considered Retired Games even though they were technically created "after" the Retirement Timestamp was set.
Retired Game
A Dispute Game is considered to be a Retired Game if the game contract was created with a timestamp less than or equal to the Retirement Timestamp.
Proper Game
A Dispute Game is considered to be a Proper Game if it has not been invalidated through any of
the mechanisms defined by the AnchorStateRegistry
contract. A Proper Game is, in a sense, a
"clean" game that exists in the set of games that are playing out correctly in a bug-free manner. A
Dispute Game can be a Proper Game even if it has not yet resolved or resolves in favor of the
Challenger.
A Dispute Game that is NOT a Proper Game can also be referred to as an Improper Game for brevity. A Dispute Game can go from being a Proper Game to later not being an Improper Game if it is invalidated by being blacklisted or retired.
ALL Dispute Games TEMPORARILY become Improper Games while the Superchain-wide pause
mechanism is active. However, this is a temporary condition such that Registered Games that are
not invalidated by blacklisting or retirement will become
Proper Games again once the pause is lifted. The Superchain-wide pause is therefore a way to
temporarily prevent Dispute Games from being used by consumers like the OptimismPortal
while
relevant parties coordinate the use of some other invalidation mechanism.
A Game is considered to be a Proper Game if all of the following are true:
- The game is a Registered Game
- The game is NOT a Blacklisted Game
- The game is NOT a Retired Game
- The Superchain-wide pause is not active
Resolved Game
A Dispute Game is considered to be a Resolved Game if the game has resolved a result in favor of either the Challenger or the Defender.
Finalized Game
A Dispute Game is considered to be a Finalized Game if all of the following are true:
- The game is a Resolved Game
- The game resolved a result more than
Dispute Game Finality Delay seconds ago as defined by the
disputeGameFinalityDelaySeconds
variable in theAnchorStateRegistry
contract.
Valid Claim
A Dispute Game is considered to have a Valid Claim if all of the following are true:
- The game is a Proper Game
- The game is a Respected Game
- The game is a Finalized Game
- The game resolved in favor of the root claim (i.e., in favor of the Defender)
Truly Valid Claim
A Truly Valid Claim is a claim that accurately represents the correct root for the L2 block height on the L2 system as would be reported by a perfect oracle for the L2 system state.
Starting Anchor State
The Starting Anchor State is the anchor state (root and L2 block height) that is used as the
starting state for new Dispute Game instances when there is no current Anchor Game. The Starting
Anchor State is set during the initialization of the AnchorStateRegistry
contract.
Anchor Game
The Anchor Game is a game whose claim is used as the starting state for new Dispute Game instances. A Game can become the Anchor Game if it has a Valid Claim and the claim's L2 block height is greater than the claim of the current Anchor Game. If there is no current Anchor Game, a Game can become the Anchor Game if it has a Valid Claim and the claim's L2 block height is greater than the current Starting Anchor State's L2 block height.
After a Game becomes the Anchor Game, it will remain the Anchor Game until it is replaced by some other Game. A Game that is retired after becoming the Anchor Game will remain the Anchor Game.
Anchor Root
The Anchor Root is the root and L2 block height that is used as the starting state for new Dispute Game instances. The value of the Anchor Root is the Starting Anchor State if no Anchor Game has been set. Otherwise, the value of the Anchor Root is the root and L2 block height of the current Anchor Game.
Assumptions
NOTE: Assumptions are utilized by specific invariants and do not apply globally. Invariants typically only rely on a subset of the following assumptions. Different invariants may rely on different assumptions. Refer to individual invariants for their dependencies.
aASR-001: Dispute Game contracts properly report important properties
We assume that the FaultDisputeGame
and PermissionedDisputeGame
contracts properly and
faithfully report the following properties:
- Game type
- L2 block number
- Root claim value
- Game extra data
- Creation timestamp
- Resolution timestamp
- Resolution result
- Whether the game was the respected game type at creation
We also specifically assume that the game creation timestamp and the resolution timestamp are not set to values in the future.
Mitigations
- Existing audit on the
FaultDisputeGame
contract - Integration testing
aASR-002: DisputeGameFactory properly reports its created games
We assume that the DisputeGameFactory
contract properly and faithfully reports the games it has
created.
Mitigations
- Existing audit on the
DisputeGameFactory
contract - Integration testing
aASR-003: Incorrectly resolving games will be invalidated before they have Valid Claims
We assume that any games that are resolved incorrectly will be invalidated either by blacklisting or by retirement BEFORE they are considered to have Valid Claims.
Proper Games that resolve in favor the Defender will be considered to have Valid Claims after the Dispute Game Finality Delay has elapsed UNLESS the Superchain-wide pause mechanism is active. Therefore, in the absence of the Superchain-wide pause mechanism, parties responsible for game invalidation have exactly the Dispute Game Finality Delay to invalidate a withdrawal after it resolves incorrectly. If the Superchain-wide pause is active, then any incorrectly resolving games must be invalidated before the pause is deactivated.
Mitigations
- Stakeholder incentives / processes
- Incident response plan
- Monitoring
Invariants
iASR-001: Games are represented as Proper Games accurately
When asked if a game is a Proper Game, the AnchorStateRegistry
must serve a response that is
identical to the response that would be given by a perfect oracle for this query.
Impact
Severity: High
If this invariant is broken, the Anchor Game could be set to an incorrect value, which would cause
future Dispute Game instances to use an incorrect starting state. This would lead games to resolve
incorrectly. Additionally, this could cause a FaultDisputeGame
to incorrectly choose the wrong
bond refunding mode.
Dependencies
iASR-002: All Valid Claims are Truly Valid Claims
When asked if a game has a Valid Claim, the AnchorStateRegistry
must serve a response that is
identical to the response that would be given by a perfect oracle for this query. However, it is
important to note that we do NOT say that all Truly Valid Claims are Valid Claims. It is possible
that a game has a Truly Valid Claim but the AnchorStateRegistry
reports that the claim is not
a Valid Claim. This permits the AnchorStateRegistry
and system-wide safety net actions to err on
the side of caution.
In a nutshell, the set of Valid Claims is a subset of the set of Truly Valid Claims.
Impact
Severity: Critical
If this invariant is broken, then any component that relies on the correctness of this function may allow actions to occur based on invalid dispute games.
Some examples of strong negative impact are:
- Invalid Dispute Game could be used as the Anchor Game, which would cause future Dispute Game instances to use an incorrect starting state. This would lead these games to resolve incorrectly. (HIGH)
- Invalid Dispute Game could be used to prove or finalize withdrawals within the
OptimismPortal
contract. This would lead to a critical vulnerability in the bridging system. (CRITICAL)
Dependencies
iASR-003: The Anchor Game is a Truly Valid Claim
We require that the Anchor Game is a Truly Valid Claim. This makes it possible to use the Anchor Game as the starting state for new Dispute Game instances. Notably, given the allowance that not all Truly Valid Claims are Valid Claims, this invariant does not imply that the Anchor Game is a Valid Claim.
We allow retired games to be used as the Anchor Game because the retirement mechanism is broad in a way that commonly causes Truly Valid Claims to no longer be considered Valid Claims. However, we explicitly disallow blacklisted games from being used as the Anchor Game. If a game is blacklisted, it should no longer be used as the Anchor Game.
Impact
Severity: High
If this invariant is broken, an invalid Anchor Game could be used as the starting state for new Dispute Game instances. This would lead games to resolve incorrectly.
Dependencies
iASR-004: Invalidation functions operate correctly
We require that the blacklisting and retirement functions operate correctly. Games that are blacklisted must not be used as the Anchor Game, must not be considered Valid Games, and must not be usable to prove or finalize withdrawals. Any game created before a transaction that updates the retirement timestamp must not be set as the Anchor Game, must not be considered Valid Games, and must not be usable to prove or finalize withdrawals.
Impact
Severity: High/Critical
If this invariant is broken, the Anchor Game could be set to an incorrect value, which would cause future Dispute Game instances to use an incorrect starting state. This would lead games to resolve incorrectly and would be considered a High Severity issue. Issues that would allow users to finalize withdrawals with invalidated games would be considered Critical Severity.
Dependencies
Function Specification
constructor
- MUST set the value of the Dispute Game Finality Delay.
initialize
- MUST only be triggerable once.
- MUST set the value of the
SuperchainConfig
contract that stores the address of the Guardian. - MUST set the value of the
DisputeGameFactory
contract that creates Dispute Game instances. - MUST set the value of the Starting Anchor State.
- MUST set the value of the initial Respected Game Type.
- MUST set the value of the Retirement Timestamp to the current block
timestamp. NOTE that this is a safety mechanism that invalidates all existing Dispute Game
contracts to support the safe transition away from the
OptimismPortal
as the source of truth for game validity. In this way, theAnchorStateRegistry
does not need to consider the state of the legacy blacklisting/retirement mechanisms within theOptimismPortal
and starts from a clean slate.
paused
Returns the value of the Superchain-wide paused()
flag in the SuperchainConfig
contract.
respectedGameType
Returns the value of the currently Respected Game Type.
retirementTimestamp
Returns the value of the current Retirement Timestamp.
disputeGameFinalityDelaySeconds
Returns the value of the Dispute Game Finality Delay.
setRespectedGameType
Permits the Guardian role to set the Respected Game Type.
- MUST revert if called by any address other than the Guardian.
- MUST update the respected game type with the provided type.
- MUST emit an event showing that the game type was updated.
updateRetirementTimestamp
Permits the Guardian role to update the Retirement Timestamp.
- MUST revert if called by any address other than the Guardian.
- MUST set the retirement timestamp to the current block timestamp.
- MUST emit an event showing that the retirement timestamp was updated.
blacklistDisputeGame
Permits the Guardian role to blacklist a Dispute Game.
- MUST revert if called by any address other than the Guardian.
- MUST mark the game as blacklisted.
- MUST emit an event showing that the game was blacklisted.
isGameRegistered
Determines if a game is a Registered Game.
- MUST return
true
if and only if the game was created by the system'sDisputeGameFactory
contract.
isGameRespected
Determines if a game is a Respected Game.
- MUST return
true
if and only if the game's game type was the respected game type defined by theAnchorStateRegistry
contract at the time of the game's creation as per a call toAnchorStateRegistry.respectedGameType()
. - MUST return
false
if the call toFaultDisputeGame.wasRespectedGameTypeWhenCreated
reverts.
isGameBlacklisted
Determines if a game is a Blacklisted Game.
- MUST return
true
if and only if the game's address is marked as blacklisted inside of theAnchorStateRegistry
contract.
isGameRetired
Determines if a game is a Retired Game.
- MUST return
true
if and only if the game was created before the retirement timestamp defined by theAnchorStateRegistry
contract as per a call toAnchorStateRegistry.retirementTimestamp()
. Check should be a strict comparison that the creation is less than the retirement timestamp.
isGameProper
Determines if a game is a Proper Game.
- MUST return
true
if and only ifisGameRegistered(game)
istrue
,isGameBlacklisted(game)
andisGameRetired(game)
are bothfalse
, andpaused()
isfalse
.
isGameResolved
Determines if a game is a Resolved Game.
- MUST return
true
if and only if the game has resolved a result in favor of either the Challenger or the Defender as determined by theFaultDisputeGame.status()
function.
isGameFinalized
Determines if a game is a Finalized Game.
- MUST return
true
if and only ifisGameResolved(game)
and the game has resolved a result more than the airgap delay seconds ago as defined by thedisputeGameFinalityDelaySeconds
variable in theAnchorStateRegistry
contract.
isGameClaimValid
Determines if a game has a Valid Claim.
- MUST return
true
if and only ifisGameProper(game)
istrue
,isGameRespected(game)
istrue
,isGameFinalized(game)
istrue
, and the game resolved in favor of the root claim (i.e., in favor of the Defender).
getAnchorRoot
Retrieves the current anchor root.
- MUST return the root hash and L2 block height of the current anchor state.
anchors
Legacy function. Accepts a game type as a parameter but does not use it.
- MUST return the current value of
getAnchorRoot()
.
setAnchorState
Allows any address to attempt to update the Anchor Game with a new Game as input.
- MUST revert if the provided game does not have a Valid Claim for any reason.
- MUST revert if the provided game corresponds to an L2 block height that is less than or equal to the current anchor state's L2 block height.
- MUST otherwise update the anchor state to match the game's result.