Dispute Games & On‑Chain Resolution on OP Mainnet
In Part 1 – “Fault Proofs 101” we mapped the why: Optimism’s June 2024 hard-fork switched on permissionless fault proofs, letting anyone roll back a malicious output root and moving OP Mainnet’s trust model closer to Ethereum.
Part 2 – “FPP, FPVM & the Pre-image Oracle” broke down the what: the stateless program, the deterministic VM and the immutable data feed that together recreate L2 state with byte-for-byte fidelity.
Part 3 (this post) tackles the how. We zoom in on the FaultDisputeGame protocol — the core interactive mechanism used to resolve disputes over L2 outputs. Our goal is to build intuition about how the game operates, without diving into low-level implementation details.
The FaultDisputeGame Protocol
The FaultDisputeGame is a stage-one interactive verification protocol designed to resolve disputes over the correctness of a claimed L2 output root. It is implemented as an on-chain game, where participants submit claims about VM execution states and use a bisection strategy to isolate a single execution step for deterministic verification.
Each game begins with:
- A root claim, which commits to the post-state of a proposed L2 execution trace.
- A game type, which defines the dispute mechanism (e.g., single-step VM execution).
- An anchor state, which serves as the trusted pre-state. This anchor is retrieved from the AnchorStateRegistry.
The goal of the game is to either confirm or refute the root claim. The claim itself represents a commitment to a full VM execution trace—from the anchor state to a proposed final state. It is important to note that the FaultDisputeGame is agnostic to the specific operations performed by the VM. This generality allows it to support various execution environments, not just a specific fault-proof VM (FPVM). The only strict requirement is that all participants operate under the same VM configuration and semantics.
The dispute is structured as a binary tree of trace positions, commonly referred to as the Game Tree. Each leaf node corresponds to a single execution step (i.e., a trace index), and each internal node represents a commitment to a range of the execution trace. Bisection reduces the disputed range by introducing intermediate claims, gradually narrowing the disagreement until it reaches an individual instruction.
The illustration below shows a simplified Game Tree, assuming a trace length of 8 steps.
The root claim is represented by Node 0 in the Game Tree. This position corresponds to a claim over the entire execution trace—it commits to the result of executing all steps from index 0 to T, where T is the trace length (e.g., 0..7 in a simplified trace of 8 steps).
To determine the range of execution covered by any node in the tree, you can conceptually trace a path from that node down the right edge of the tree to the leaf. Each step to the right halves the trace range, starting from the root. For example:
- Node 0 represents the range 0..7
- Node 2 represents the range 0..3
- Node 4 and Node 10 represent the range 0..1
This structure ensures that each internal node represents a claim over a subrange of the execution trace, and the tree progresses toward individual execution steps at the leaves, where disputes are resolved by concrete on-chain verification.
To build some intuition, let’s walk through a simplified example of a game involving an execution trace with 8 steps. The game begins with a challenge against the root claim (Node 0), which represents a commitment to the entire trace range 0..7.
The first challenge is always made by disputing the entire trace, which corresponds to moving to the left child of Node 0 in the Game Tree. This move introduces a new claim — a commitment (typically a hash of the post-state) for the left half of the trace, in this case the subrange 0..3.
Now that the game has progressed to Node 2, representing the trace range 0..3, it can be either defended or challenged by participants. Let’s consider the case where it is challenged. A challenge move at this point will bisect the current range and produce a new claim at Node 4, which corresponds to the left half of the trace — specifically, the subrange 0..1.
Now let’s consider a situation where Node 4 is defended by a participant. To make a defense move for any node, the player must traverse up to the parent, then right, then left — effectively selecting the sibling subrange that maintains the defender’s position. In this case, defending Node 4 leads to a new claim at Node 11, which corresponds to the trace range 0..2.
This move implies that the trace range 0..1 is no longer in dispute, as both parties agree on the execution result up to that point. It also indicates agreement on the broader range 0..2.
It’s important to note that while we visualize the game as a binary tree for clarity, the actual implementation of FaultDisputeGame uses a directed acyclic graph (DAG) to store claims. In this structure, each claim points to its parent claim — the one it directly challenges — but there are no explicit edges between claims like Node 4 and Node 11, since they are not in a strict parent-child relationship.
In our example, moving from Node 4 to Node 11 represents a change in position within the logical game, not a traversal along a single tree edge. The DAG structure allows the protocol to maintain a flexible and efficient record of all claims, challenges, and responses, while still enforcing the rules of turn-taking and trace indexing.
While in a real-world scenario this process may involve many alternating challenge and defense moves, in our simplified example the game has already narrowed the disagreement to a single execution step — specifically, the transition from trace index 2 to trace index 3.
At this point, the FaultDisputeGame has isolated the disagreement to a single execution step — specifically, the transition from trace index 2 to trace index 3. No further bisection is possible. The game now transitions to its final phase, where the correctness of the disputed step is determined via on-chain execution.
To resolve the dispute, the game invokes a fault-proof virtual machine, implemented in contracts such as MIPS.sol. This verifier deterministically re-executes the disputed instruction on-chain. The execution uses:
- The pre-state at trace index 2, as committed by the defending party,
- The claimed post-state at trace index 3,
- And the required execution context (e.g., memory, calldata, etc.), typically fetched via preimage oracles.
The VM executes the instruction starting from the pre-state. If the result matches the claimed post-state, the claim is validated and the defender wins. If the result differs, the claim is proven incorrect, and the challenger prevails.
This on-chain execution is fully deterministic, requires no further interaction, and ensures that disputes can be resolved objectively. While MIPS.sol is the currently deployed implementation, the FaultDisputeGame protocol is designed to support multiple VMs via the modular game type system.
As the game progresses, participants submit claims to the DAG — each representing a state commitment at a specific trace index. By default, a newly added claim is considered uncountered, meaning no one has challenged it yet.
Once a claim is directly targeted by another claim (i.e., someone makes a valid move that challenges it), the original claim becomes countered. However, the status of a claim being countered depends on the status of its children:
- A claim is considered countered only if at least one of its children is uncountered.
- Conversely, if all of a claim’s children are themselves countered, then the claim is not countered — it successfully defended itself at that level.
This rule allows the game to determine correctness by propagating claim statuses upward in the DAG:
- Starting from the leaves, the game evaluates which claims are uncountered.
- Any parent of an uncontested claim becomes countered.
- This process continues upward toward the root.
- If the root claim becomes countered (i.e., some branch led to an uncountered challenge), the original claim is considered invalid and the challengers win.
- If the root is not countered, the claim stands, and the defenders win.
This approach ensures that only a single path — the one ending in an uncountered leaf — is needed to overturn the root claim, making the protocol efficient and decisive.
The FaultDisputeGame represents a core building block in the OP Stack’s fault-proof system. By combining interactive bisection with deterministic, on-chain execution, it enables a permissionless and trust-minimized method for verifying L2 outputs. Its modular design allows for extensibility across different VMs and proof mechanisms, laying the groundwork for scalable and decentralized L2 security.
Smart Contracts Enabling Dispute Games
To support the FaultDisputeGame protocol, the OP Stack relies on a coordinated set of smart contracts deployed on L1. These contracts manage key responsibilities like anchoring L2 state commitments, tracking trusted state references, and deploying new dispute game instances. Together, they form the on-chain infrastructure that enables permissionless, verifiable dispute resolution.
OptimismPortal2.sol
The OptimismPortal2 contract plays a foundational role in the OP Stack’s bridging and dispute infrastructure. It is the main entry point for cross-chain interactions between Ethereum (L1) and the OP Stack L2 chain.
Specifically, OptimismPortal2 is where:
- Deposit transactions are submitted by users and later picked up for execution on L2.
- Withdrawal-proof transactions are submitted to complete asset exits from L2 to L1.
- The system used to keep track of validity-related state for dispute games — such as whether a game was blacklisted or considered final.
While OptimismPortal2 initially served as the central source of truth for dispute game status, this responsibility has since shifted toward the AnchorStateRegistry contract. This change reflects a broader architectural evolution intended to support future interoperability between OP Stack chains.
A full deep dive into these changes is outside the scope of this article — it would be more appropriate in the context of reviewing the Interop upgrade — but here are the main points:
- AnchorStateRegistry has taken over responsibility for game validity tracking. It now independently tracks whether a game is blacklisted, finalized, or retired — eliminating the need to query OptimismPortal2 for this information.
- A new ETHLockbox contract was introduced to hold ETH previously managed by OptimismPortal2, enabling ETH custody to be cleanly shared across multiple systems.
- These shared components — AnchorStateRegistry and ETHLockbox — can now be reused by multiple fault-proof systems, including those with different dispute game implementations.
- The protocol introduced super root semantics, which aggregate commitments from multiple L2 chains into a single verifiable structure, enabling unified dispute resolution across systems.
- This led to the development of SuperFaultDisputeGame.sol, an extended version of FaultDisputeGame that supports disputes over the state of two separate L2 chains.
These changes reflect a significant step toward a more modular and interoperable OP Stack, setting the stage for more complex, cross-chain dispute resolution systems in the future.
AnchorStateRegistry.sol
The AnchorStateRegistry contract serves as a coordination point for dispute games operating over a shared set of assumptions about the L2 state. It acts as a registry where DisputeGame contracts can record their finalized outcomes — known as anchor states. These anchor states are then reused as trusted starting points for new dispute games, effectively narrowing the execution trace that needs to be replayed or verified in future disputes. This design significantly improves scalability and allows different dispute games to build on a common state lineage.
All games referencing the same AnchorStateRegistry are implicitly assumed to be operating over the same underlying state model and claim structure. This provides consistency across disputes and enables more efficient validation paths. In the long term, this registry will serve as the canonical source of truth for identifying which DisputeGame contracts are valid and final.
The registry also defines key parameters for managing the lifecycle of disputes, including:
- Dispute Game Finality Delay (Airgap): A buffer period before a game result is considered final.
- Retirement Timestamp: A configurable time after which a given anchor state is no longer used for new games.
Additionally, the registry enforces a Respected Game Type, which helps ensure only properly configured dispute games can contribute anchor states.
Although the dispute system is permissionless by default, the OP Stack includes a safety mechanism via the Guardian role, currently held by the Optimism Security Council. The Guardian acts as a fail-safe, providing emergency powers in case the fault proof system misbehaves or breaks down.
During the finality delay (airgap), the Guardian can:
- Pause withdrawals to prevent the exit of funds based on disputed outputs.
- Blacklist specific dispute games that are deemed invalid or malicious.
- Switch to a permissioned dispute system, where only designated proposers and challengers can participate.
These powers are intended as last-resort measures, and the trust assumption is minimal: as long as the Guardian does not intervene, the system functions permissionlessly. This aligns with Stage 1 decentralization goals while offering practical safety guarantees during early deployments.
The AnchorStateRegistry exposes key functions for governance and lifecycle management, including:
- setRespectedGameType() – configures the valid game type ID.
- updateRetirementTimestamp() – adjusts anchor state expiry.
- blacklistDisputeGame() – invalidates specific dispute game contracts.
DisputeGameFactory.sol
The DisputeGameFactory contract is responsible for deploying new instances of DisputeGame contracts. When a dispute is initiated, the factory receives a GameType and a root Claim, and creates a new DisputeGame instance based on the specified type.
Each GameType is represented as a 32-byte identifier (a bytes32 value) that maps to a specific dispute game implementation contract. These implementations must be registered ahead of time within the factory. Once registered, they serve as immutable blueprints for spawning new game instances of that type.
To deploy these instances efficiently, the factory uses the clones-with-immutable-args pattern — an optimized minimal proxy cloning method that allows parameters to be embedded directly into the bytecode of each clone. This makes deployments gas-efficient while ensuring critical inputs remain immutable.
The registration process is permissioned: only authorized governance (or an admin contract) can register or update a GameType. This ensures that only dispute mechanisms explicitly approved by governance are available through the factory.
When a new dispute game is created, the factory emits a DisputeGameCreated event containing the address of the new game, the root claim, and the GameType. Off-chain agents — particularly challengers — listen for these events to discover and respond to new disputes in real time.
This design enables a modular and extensible dispute system, where multiple kinds of proof games (e.g., MIPS-based, RISC-V-based, or even custom implementations) can coexist and be deployed on demand, all under a unified factory interface.
Conclusion
FaultDisputeGame takes optimistic L2 output roots and subjects them to a permissionless, on-chain “chess match.” Through iterative bisection and a single-step VM, any challenger can isolate one faulty instruction, roll back an invalid root, and anchor a new, verified state—all while AnchorStateRegistry trims future gas costs and the system stays modular for future upgrades.
In the upcoming post, “Real-World Vulnerabilities in OP Fault Proofs,” we’ll dissect the high-severity timing flaws flagged by Offchain Labs and the medium-severity issues surfaced in Sherlock’s audit contest, showing how they were fixed and what they teach us about building safer dispute games. Stay tuned.
Subscribe
to our
newsletter
Be the first to receive our latest company updates, Web3 security insights, and exclusive content curated for the blockchain enthusiasts.

Read next:
More related- FP System Components: FPP, FPVM & the Pre-image Oracle
13 min read
Discover
- Fault Proofs 101: The Backbone of OP Stack Security
15 min read
Discover
- Optimism Blockchain 101: Unlocking The Potential Of Layer 2 Scaling
11 min read
Discover