Commit c2cb2344 authored by clabby's avatar clabby Committed by GitHub

feat(specs): FDG spec updates (#8687)

* chore: fdg spec updates

* lint

* Update specs/fault-dispute-game.md
Co-authored-by: default avatarInphi <mlaw2501@gmail.com>

* Update specs/fault-dispute-game.md
Co-authored-by: default avatarInphi <mlaw2501@gmail.com>

* Update specs/fault-dispute-game.md
Co-authored-by: default avatarInphi <mlaw2501@gmail.com>

* @inphi review

* Update specs/fault-dispute-game.md
Co-authored-by: default avatarInphi <mlaw2501@gmail.com>

* toc

---------
Co-authored-by: default avatarInphi <mlaw2501@gmail.com>
parent 9230831a
...@@ -30,6 +30,9 @@ single dispute game will not result in the bug becoming consensus. ...@@ -30,6 +30,9 @@ single dispute game will not result in the bug becoming consensus.
For added context, we define a few types that are used in the following snippets. For added context, we define a few types that are used in the following snippets.
```solidity ```solidity
/// @notice A `Claim` type represents a 32 byte hash or other unique identifier for a claim about
/// a certain piece of information.
type Claim is bytes32;
/// @notice A custom type for a generic hash. /// @notice A custom type for a generic hash.
type Hash is bytes32; type Hash is bytes32;
...@@ -37,14 +40,25 @@ type Hash is bytes32; ...@@ -37,14 +40,25 @@ type Hash is bytes32;
/// @notice A dedicated timestamp type. /// @notice A dedicated timestamp type.
type Timestamp is uint64; type Timestamp is uint64;
/// @notice The type of proof system being used. /// @notice A `GameType` represents the type of game being played.
enum GameType { type GameType is uint8;
/// @dev The game will use a `IDisputeGame` implementation that utilizes fault proofs.
FAULT, /// @title GameTypes
/// @dev The game will use a `IDisputeGame` implementation that utilizes validity proofs. /// @notice A library that defines the IDs of games that can be played.
VALIDITY, library GameTypes {
/// @dev The game will use a `IDisputeGame` implementation that utilizes attestation proofs. /// @dev A dispute game type the uses the cannon vm.
ATTESTATION GameType internal constant CANNON = GameType.wrap(0);
/// @dev A dispute game type that performs output bisection and then uses the cannon vm.
GameType internal constant OUTPUT_CANNON = GameType.wrap(1);
/// @notice A dispute game type that performs output bisection and then uses an alphabet vm.
/// Not intended for production use.
GameType internal constant OUTPUT_ALPHABET = GameType.wrap(254);
/// @notice A dispute game type that uses an alphabet vm.
/// Not intended for production use.
GameType internal constant ALPHABET = GameType.wrap(255);
} }
/// @notice The current status of the dispute game. /// @notice The current status of the dispute game.
...@@ -56,13 +70,6 @@ enum GameStatus { ...@@ -56,13 +70,6 @@ enum GameStatus {
/// @dev The game has concluded, and the `rootClaim` could not be contested. /// @dev The game has concluded, and the `rootClaim` could not be contested.
DEFENDER_WINS DEFENDER_WINS
} }
/// @notice A `Claim` type represents a 32 byte hash or other unique identifier for a claim about
/// a certain piece of information.
/// @dev For the `FAULT` `GameType`, this will be a root of the merklized state of the fault proof
/// program at the end of the state transition.
/// For the `ATTESTATION` `GameType`, this will be an output root.
type Claim is bytes32;
``` ```
## `DisputeGameFactory` Interface ## `DisputeGameFactory` Interface
...@@ -112,7 +119,11 @@ interface IDisputeGameFactory { ...@@ -112,7 +119,11 @@ interface IDisputeGameFactory {
/// @return proxy_ The clone of the `DisputeGame` created with the given parameters. /// @return proxy_ The clone of the `DisputeGame` created with the given parameters.
/// Returns `address(0)` if nonexistent. /// Returns `address(0)` if nonexistent.
/// @return timestamp_ The timestamp of the creation of the dispute game. /// @return timestamp_ The timestamp of the creation of the dispute game.
function games(GameType _gameType, Claim _rootClaim, bytes calldata _extraData) function games(
GameType _gameType,
Claim _rootClaim,
bytes calldata _extraData
)
external external
view view
returns (IDisputeGame proxy_, Timestamp timestamp_); returns (IDisputeGame proxy_, Timestamp timestamp_);
...@@ -141,7 +152,11 @@ interface IDisputeGameFactory { ...@@ -141,7 +152,11 @@ interface IDisputeGameFactory {
/// @param _rootClaim The root claim of the DisputeGame. /// @param _rootClaim The root claim of the DisputeGame.
/// @param _extraData Any extra data that should be provided to the created dispute game. /// @param _extraData Any extra data that should be provided to the created dispute game.
/// @return proxy_ The address of the created DisputeGame proxy. /// @return proxy_ The address of the created DisputeGame proxy.
function create(GameType _gameType, Claim _rootClaim, bytes calldata _extraData) function create(
GameType _gameType,
Claim _rootClaim,
bytes calldata _extraData
)
external external
returns (IDisputeGame proxy_); returns (IDisputeGame proxy_);
...@@ -158,7 +173,11 @@ interface IDisputeGameFactory { ...@@ -158,7 +173,11 @@ interface IDisputeGameFactory {
/// @param _rootClaim The root claim of the DisputeGame. /// @param _rootClaim The root claim of the DisputeGame.
/// @param _extraData Any extra data that should be provided to the created dispute game. /// @param _extraData Any extra data that should be provided to the created dispute game.
/// @return uuid_ The unique identifier for the given dispute game parameters. /// @return uuid_ The unique identifier for the given dispute game parameters.
function getGameUUID(GameType _gameType, Claim _rootClaim, bytes memory _extraData) function getGameUUID(
GameType _gameType,
Claim _rootClaim,
bytes memory _extraData
)
external external
pure pure
returns (Hash uuid_); returns (Hash uuid_);
...@@ -175,46 +194,40 @@ the interface. ...@@ -175,46 +194,40 @@ the interface.
Clones of the `IDisputeGame`'s `initialize` functions will be called by the `DisputeGameFactory` upon creation. Clones of the `IDisputeGame`'s `initialize` functions will be called by the `DisputeGameFactory` upon creation.
```solidity ```solidity
////////////////////////////////////////////////////////////////
// GENERIC DISPUTE GAME //
////////////////////////////////////////////////////////////////
/// @title IDisputeGame /// @title IDisputeGame
/// @notice The generic interface for a DisputeGame contract. /// @notice The generic interface for a DisputeGame contract.
interface IDisputeGame { interface IDisputeGame is IInitializable {
/// @notice Initializes the DisputeGame contract.
/// @custom:invariant The `initialize` function may only be called once.
function initialize() external;
/// @notice Emitted when the game is resolved. /// @notice Emitted when the game is resolved.
/// @param status The status of the game after resolution. /// @param status The status of the game after resolution.
event Resolved(GameStatus indexed status); event Resolved(GameStatus indexed status);
/// @notice Returns the timestamp that the DisputeGame contract was created at. /// @notice Returns the timestamp that the DisputeGame contract was created at.
function createdAt() external pure returns (Timestamp createdAt_); /// @return createdAt_ The timestamp that the DisputeGame contract was created at.
function createdAt() external view returns (Timestamp createdAt_);
/// @notice Returns the current status of the game. /// @notice Returns the current status of the game.
/// @return status_ The current status of the game.
function status() external view returns (GameStatus status_); function status() external view returns (GameStatus status_);
/// @notice Getter for the game type. /// @notice Getter for the game type.
/// @dev `clones-with-immutable-args` argument #1
/// @dev The reference impl should be entirely different depending on the type (fault, validity) /// @dev The reference impl should be entirely different depending on the type (fault, validity)
/// i.e. The game type should indicate the security model. /// i.e. The game type should indicate the security model.
/// @return gameType_ The type of proof system being used. /// @return gameType_ The type of proof system being used.
function gameType() external view returns (GameType gameType_); function gameType() external view returns (GameType gameType_);
/// @notice Getter for the root claim. /// @notice Getter for the root claim.
/// @dev `clones-with-immutable-args` argument #1
/// @return rootClaim_ The root claim of the DisputeGame. /// @return rootClaim_ The root claim of the DisputeGame.
/// @dev `clones-with-immutable-args` argument #2 function rootClaim() external pure returns (Claim rootClaim_);
function rootClaim() external view returns (Claim rootClaim_);
/// @notice Getter for the extra data. /// @notice Getter for the extra data.
/// @dev `clones-with-immutable-args` argument #3 /// @dev `clones-with-immutable-args` argument #2
/// @return extraData_ Any extra data supplied to the dispute game contract by the creator. /// @return extraData_ Any extra data supplied to the dispute game contract by the creator.
function extraData() external view returns (bytes memory extraData_); function extraData() external pure returns (bytes memory extraData_);
/// @notice Returns the address of the `BondManager` used /// @notice Returns the address of the `BondManager` used.
function bondManager() public view returns (IBondManager bondManager_); /// @return bondManager_ The address of the `BondManager` used.
function bondManager() external view returns (IBondManager bondManager_);
/// @notice If all necessary information has been gathered, this function should mark the game /// @notice If all necessary information has been gathered, this function should mark the game
/// status as either `CHALLENGER_WINS` or `DEFENDER_WINS` and return the status of /// status as either `CHALLENGER_WINS` or `DEFENDER_WINS` and return the status of
...@@ -222,7 +235,7 @@ interface IDisputeGame { ...@@ -222,7 +235,7 @@ interface IDisputeGame {
/// necessary parties. /// necessary parties.
/// @dev May only be called if the `status` is `IN_PROGRESS`. /// @dev May only be called if the `status` is `IN_PROGRESS`.
/// @return status_ The status of the game after resolution. /// @return status_ The status of the game after resolution.
function resolve() public returns (GameStatus status_); function resolve() external returns (GameStatus status_);
/// @notice A compliant implementation of this interface should return the components of the /// @notice A compliant implementation of this interface should return the components of the
/// game UUID's preimage provided in the cwia payload. The preimage of the UUID is /// game UUID's preimage provided in the cwia payload. The preimage of the UUID is
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
- [Execution Trace](#execution-trace) - [Execution Trace](#execution-trace)
- [Claims](#claims) - [Claims](#claims)
- [DAG](#dag) - [DAG](#dag)
- [Subgame](#subgame)
- [Game Tree](#game-tree) - [Game Tree](#game-tree)
- [Position](#position) - [Position](#position)
- [GAME_DURATION](#game_duration) - [GAME_DURATION](#game_duration)
...@@ -28,18 +29,21 @@ ...@@ -28,18 +29,21 @@
<!-- END doctoc generated TOC please keep comment here to allow auto update --> <!-- END doctoc generated TOC please keep comment here to allow auto update -->
<!-- Glossary References -->
[g-output-root]: glossary.md#L2-output-root
## Overview ## Overview
The Fault Dispute Game (FDG) is a specific type of The Fault Dispute Game (FDG) is a specific type of
[dispute game](./dispute-game-interface.md) that verifies the validity of a [dispute game](./dispute-game-interface.md) that verifies the validity of a
root claim by iteratively bisecting an execution trace down to a single instruction step. root claim by iteratively bisecting over [output roots][g-output-root] and execution traces of single block state
It relies on a Virtual Machine (VM) to falsify invalid claims made transitions down to a single instruction step. It relies on a Virtual Machine (VM) to falsify invalid claims made at
at a single instruction step. a single instruction step.
Actors, i.e. Players, interact with the game by making claims that dispute other claims in the FDG. Actors, i.e. Players, interact with the game by making claims that dispute other claims in the FDG.
Each claim made narrows the execution trace until the source of dispute is a single state transition. Each claim made narrows the range over the entire historical state of L2, until the source of dispute is a single
Once a time limit is reached, the dispute game is _resolved_, based on state transition. Once a time limit is reached, the dispute game is _resolved_, based on claims made that are disputed
claims made that are disputed and which aren't, to determine the winners of the game. and which aren't, to determine the winners of the game.
## Definitions ## Definitions
...@@ -69,9 +73,12 @@ We refer to this state as the **ABSOLUTE\_PRESTATE**. ...@@ -69,9 +73,12 @@ We refer to this state as the **ABSOLUTE\_PRESTATE**.
### Claims ### Claims
Claims assert an execution trace. This is represented as `ClaimHash`, a `bytes32` commitment to Claims assert an [output root][g-output-root] or the state of the FPVM at a given instruction. This is represented as
the last VM state in a trace. A FDG is initialized with a root claim, which commits to the entire `ClaimHash`, a `bytes32` representing either an [output root][g-output-root] or a commitment to the last VM state in a
execution trace. As we'll see later, there can be multiple claims, committing to different states in the FDG. trace. A FDG is initialized with an output root that corresponds to the state of L2 at a given L2 block number, and
execution trace subgames at `SPLIT_DEPTH + 1` are initialized with a claim that commits to the entire execution trace
between two consecutive output roots (a block `n -> n+1` state transition). As we'll see later, there can be multiple
claims, committing to different output roots and FPVM states in the FDG.
### DAG ### DAG
...@@ -82,12 +89,33 @@ where $C_i$ is a claim. ...@@ -82,12 +89,33 @@ where $C_i$ is a claim.
- $E$ is the set of _directed_ edges. An edge $(C_i,C_j)$ exists if $C_j$ is a direct dispute - $E$ is the set of _directed_ edges. An edge $(C_i,C_j)$ exists if $C_j$ is a direct dispute
against $C_i$ through either an "Attack" or "Defend" [move](#moves). against $C_i$ through either an "Attack" or "Defend" [move](#moves).
### Subgame
A sub-game is a DAG of depth 1, where the root of the DAG is a `Claim` and the children are `Claim`s that counter the
root. A good mental model around this structure is that it is a fundamental dispute between two parties over a single
piece of information. These subgames are chained together such that a child within a subgame is the root of its own
subgame, which is visualized in the [resolution](#resolution) section. There are two types of sub-games in the fault
dispute game:
1. Output Roots
1. Execution Trace Commitments
At and above the split depth, all subgame roots correspond to [output roots][g-output-root], or commitments to the full
state of L2 at a given L2 block number. Below the split depth, subgame roots correspond to commitments to the fault
proof VM's state at a given instruction step.
### Game Tree ### Game Tree
The Game Tree is a binary tree of positions. Every claim in the DAG references a position in the Game Tree. The Game Tree is a binary tree of positions. Every claim in the DAG references a position in the Game Tree.
The Game Tree has a maximum depth, `MAX_GAME_DEPTH`, that's preset to an FDG implementation. The Game Tree has a split depth and maximum depth, `SPLIT_DEPTH` and `MAX_GAME_DEPTH` respectively, that are both
Thus, the Game Tree contains $2^{d-1}$ positions, where $d$ is the `MAX_GAME_DEPTH` preset to an FDG implementation. The split depth defines the maximum depth at which claims about
(unless $d=0$, in which case there's only 1 position). [output roots][g-output-root] can occur, and below it, execution trace bisection occurs. Thus, the Game Tree contains
$2^{d-1}$ positions, where $d$ is the `MAX_GAME_DEPTH` (unless $d=0$, in which case there's only 1 position).
The full game tree, with a layer of the tree allocated to output bisection, and sub-trees after an arbitrary split
depth, looks like:
![ob-tree](./assets/ob-tree.png)
### Position ### Position
...@@ -100,7 +128,8 @@ The **gindex** of a position $n$ can be calculated as $2^{d(n)} + idx(n)$, where ...@@ -100,7 +128,8 @@ The **gindex** of a position $n$ can be calculated as $2^{d(n)} + idx(n)$, where
- $d(n)$ is a function returning the depth of the position in the Game Tree - $d(n)$ is a function returning the depth of the position in the Game Tree
- $idx(n)$ is a function returning the index of the position at its depth (starting from the left). - $idx(n)$ is a function returning the index of the position at its depth (starting from the left).
Positions at the deepest level of the game tree correspond to indices in the execution trace. Positions at the deepest level of the game tree correspond to indices in the execution trace, whereas claims at the
split depth represent single L2 blocks' [output roots][g-output-root].
Positions higher up the game tree also cover the deepest, right-most positions relative to the current position. Positions higher up the game tree also cover the deepest, right-most positions relative to the current position.
We refer to this coverage as the **trace index** of a Position. We refer to this coverage as the **trace index** of a Position.
...@@ -119,14 +148,19 @@ This is an immutable, preset to a FDG implementation, representing the duration ...@@ -119,14 +148,19 @@ This is an immutable, preset to a FDG implementation, representing the duration
The game involves two types of participants (or Players): **Challengers** and **Defenders**. The game involves two types of participants (or Players): **Challengers** and **Defenders**.
These players are grouped into separate teams, each employing distinct strategies to interact with the game. These players are grouped into separate teams, each employing distinct strategies to interact with the game.
Team members share a common goal regarding the game's outcome. Players interact with the game primarily through _moves_. Team members share a common goal regarding the game's outcome. Players interact with the game primarily through
_moves_.
### Moves ### Moves
A Move is a challenge against a claim's execution trace and must include an alternate claim asserting a different trace. A Move is a challenge against an existing claim and must include an alternate claim asserting a different trace.
Moves can either be attacks or defenses and serve to update to DAG by adding nodes and edges targeting the disputed Moves can either be attacks or defenses and serve to update to DAG by adding nodes and edges targeting the disputed
claim. claim.
Moves within the fault dispute game can claim two separate values: [output roots][g-output-root] and execution trace
commitments. At and above the `SPLIT_DEPTH`, claims correspond to output roots, while below the split depth, they
correspond to execution trace commitments.
Initially, claims added to the DAG are _uncontesteed_ (i.e. not **countered**). Once a move targets a claim, that claim Initially, claims added to the DAG are _uncontesteed_ (i.e. not **countered**). Once a move targets a claim, that claim
is considered countered. is considered countered.
The status of a claim &mdash; whether it's countered or not &mdash; helps determine its validity and, ultimately, the The status of a claim &mdash; whether it's countered or not &mdash; helps determine its validity and, ultimately, the
...@@ -216,12 +250,17 @@ The FDG provides the following interface to manage data loaded to the `PreimageO ...@@ -216,12 +250,17 @@ The FDG provides the following interface to manage data loaded to the `PreimageO
```solidity ```solidity
/// @notice Posts the requested local data to the VM's `PreimageOralce`. /// @notice Posts the requested local data to the VM's `PreimageOralce`.
/// @param _ident The local identifier of the data to post. /// @param _ident The local identifier of the data to post.
/// @param _execLeafIdx The index of the leaf claim in an execution subgame that requires the local data for a step.
/// @param _partOffset The offset of the data to post. /// @param _partOffset The offset of the data to post.
function addLocalData(uint256 _ident, uint256 _partOffset) external; function addLocalData(uint256 _ident, uint256 _execLeafIdx, uint256 _partOffset) external;
``` ```
The `addLocalData` function loads parts of a pre-image to VM's `PreimageOracle`. The `addLocalData` function loads parts of a pre-image to VM's `PreimageOracle`. Players use this to ensure pre-image
Players use this to ensure pre-image parts are available to the VM during a step. parts are available to the VM during a step. Because there are multiple sets of local preimage keys that belong to the
`FaultDisputeGame` contract due to the ability for players to bisect to any block `n->n+1` state transition since the
configured genesis, the `_execLeafIdx` parameter enables a search for the starting / disputed outputs to be performed
such that the contract can write to and reference unique local keys in the `PreimageOracle` for each of these `n->n+1`
transitions.
### Team Dynamics ### Team Dynamics
...@@ -352,7 +391,7 @@ digraph G { ...@@ -352,7 +391,7 @@ digraph G {
</p> </p>
Given these rules, players are motivated to move quickly to challenge all dishonest claims. Given these rules, players are motivated to move quickly to challenge all dishonest claims.
Each move bisects the execution trace and eventually, `MAX_GAME_DEPTH` is reached where disputes Each move bisects the historical state of L2 and eventually, `MAX_GAME_DEPTH` is reached where disputes
can be settled conclusively. Dishonest players are disincentivized to participate, via backwards induction, can be settled conclusively. Dishonest players are disincentivized to participate, via backwards induction,
as an invalid claim won't remain uncontested. Further incentives can be added to the game by requiring as an invalid claim won't remain uncontested. Further incentives can be added to the game by requiring
claims to be bonded, while rewarding game winners using the bonds of dishonest claims. claims to be bonded, while rewarding game winners using the bonds of dishonest claims.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment