Skip to content

Commit

Permalink
fault-proof: Specify bond incentives (#21)
Browse files Browse the repository at this point in the history
Update the Fault Proof specification to include bonds.
  • Loading branch information
Inphi authored Feb 5, 2024
1 parent 598745d commit cd7ccb3
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 11 deletions.
1 change: 1 addition & 0 deletions specs/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
- [Dispute Game Interface](./experimental/fault-proof/dispute-game-interface.md)
- [Fault Dispute Game](./experimental/fault-proof/fault-dispute-game.md)
- [Honest Challenger](./experimental/fault-proof/honest-challenger-fdg.md)
- [Bond Incentives](./experimental/fault-proof/bond-incentives.md)
- [Glossary](./glossary.md)
- [Meta](./meta/index.md)
- [Linting](./meta/linting.md)
Expand Down
47 changes: 47 additions & 0 deletions specs/experimental/fault-proof/bond-incentives.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Bond Incentives

Bonds is an add-on to the core [Fault Dispute Game](./fault-dispute-game.md). The core game mechanics are
designed to ensure honesty as the best response to winning subgames. By introducing financial incentives,
Bonds makes it worthwhile for honest challengers to participate.
Without the bond reward incentive, the FDG will be too costly for honest players to participate in given the
cost of verifying and making claims.

Implementations may allow the FDG to directly receive bonds, or delegate this responsibility to another entity.
Regardless, there must be a way for the FDG to query and distribute bonds linked to a claim.

Bonds are integrated into the FDG in two areas:

- Moves
- Subgame Resolution

## Moves

Moves must be adequately bonded to be added to the FDG. This document does not specify a
scheme for determining the minimum bond requirement. FDG implementations should define a function
computing the minimum bond requirement with the following signature:

```solidity
function getRequiredBond(Position _movePosition) public pure returns (uint256 requiredBond_)
```

As such, attacking or defending requires a check for the `getRequiredBond()` amount against the bond
attached to the move. To incentivize participation, the minimum bond should cover the cost of a possible
counter to the move being added. Thus, the minimum bond depends only on the position of the move that's added.

## Subgame Resolution

If a subgame root resolves incorrectly, then its bond is distributed to the **leftmost claimant** that countered
it. This creates an incentive to identify the earliest point of disagreement in an execution trace.
The subgame root claimant gets back its bond iff it resolves correctly.

At maximum game depths, where a claimant counters a bonded claim via `step`, the bond is instead distributed
to the account that successfully called `step`.

### Leftmost Claim Incentives

There exists defensive positions that cannot be countered, even if they hold invalid claims. These positions
are located on the same level as honest claims, but situated to its right (i.e. its gindex > honest claim's).

An honest challenger can always successfully dispute any sibling claims not positioned to the right of an honest claim.
The leftmost payoff rule encourages such disputes, ensuring only one claim is leftmost at correct depths.
This claim will be the honest one, and thus bond rewards will be directed exclusively to honest claims.
6 changes: 5 additions & 1 deletion specs/experimental/fault-proof/fault-dispute-game.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,11 @@ Note that there can be multiple positions covering the same _trace index_.
This is an immutable, preset to a FDG implementation, representing the duration of the game. Each top level team will
receive half of this duration on their initial chess clocks.

## Game Mechanics
## Core Game Mechanics

This section specifies the core game mechanics of the FDG. The full FDG mechanics includes a
[specification for Bonds](./bond-incentives.md). Readers should understand basic game mechanics before
reading up on the Bond specification.

### Actors

Expand Down
58 changes: 48 additions & 10 deletions specs/experimental/fault-proof/honest-challenger-fdg.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ to its root claim:
NOTE: The honest challenger will still track this game in order to defend any subsequent
claims made against the root claim - in effect, "playing the game".

### Counter Claims
### Countering Invalid Claims

For every claim made in a dispute game with a [game tree](fault-dispute-game.md#game-tree)
depth in the range of `[1, MAX_DEPTH]`, the honest challenger processes them and performs
Expand All @@ -62,7 +62,8 @@ This determines the set of claims it should respond to in the FDG.
If the agent determines itself to be a Defender, which aims to support the root claim,
then it must dispute claims positioned at odd depths in the game tree.
Otherwise, it disputes claims positioned at even depths in the game tree.
This means an honest challenger only responds to claims made by the opposing team.
This means an honest challenger will typically only respond to claims made by the opposing team.
(See [Countering Freeloaders](#countering-freeloaders) for exceptions to this).

The next step is to determine if the claim, now known to be for the opposing team,
disputes another claim the honest challenger _agrees_ with.
Expand All @@ -77,6 +78,23 @@ If the `ClaimHash` matches the honest challenger's at the same trace index, then
disagree with the claim's stance by moving to [defend](fault-dispute-game.md#defend).
Otherwise, the claim is [attacked](fault-dispute-game.md#attack).

### Countering Freeloaders

Freeloaders are claims that exist at the correct depth and on the same team as honest challengers
but are positioned incorrectly or commit to an invalid `ClaimHash`.
The honest challenger must dispute freeloaders to claim the bond of the subgame root.
If not disputed, the bond may be awarded to the freeloader, depending on their position.
See [Bond incentives for subgame Resolution](./bond-incentives.md) for details.

The honest challenger achieves this by disputing any freeloader claim that is not invalidly positioned
in a defensive position. This includes disputing the following types of claims:

- Claims at an invalid attack position
- Claims with an invalid `ClaimHash` at a valid attack position
- Claims with a valid `ClaimHash` at a valid defense position

Doing so ensures that the leftmost claim is the hoenst challenger's.

The following pseudocode illustrates the response logic.

```python
Expand All @@ -89,24 +107,44 @@ class Claim:
position: uint64
claim_hash: ClaimHash

class Response(Enum):
ATTACK = 0
DEFEND = 1
NOP = 2

MAX_TRACE = 2**MAX_GAME_DEPTH

def agree_with(claim: Claim, chal_trace: List[ClaimHash, MAX_TRACE]):
if chal_trace[claim.trace_index] != claim.claim_hash:
def agree_with(claim: Claim, chal_trace: List[ClaimHash, MAX_TRACE]) -> bool:
if chal_trace[trace_index(claim.position)] != claim.claim_hash:
return False
grand_parent = claim.parent.parent if claim.parent is not None else None
if grand_parent is not None:
return agree_with(grand_parent)
return True

def respond(claim: Claim, chal: Team, chal_trace: List[ClaimHash, MAX_TRACE]):
def is_attack(claim: Claim) -> bool:
return claim.position == claim.parent.position << 1

def respond_claim(claim: Claim, correct_trace: List[ClaimHash, MAX_TRACE]) -> Response:
if chal_trace[trace_index(claim.position)] == claim.claim_hash:
return Response.DEFEND
else:
return Response.ATTACK

def respond(claim: Claim, chal: Team, chal_trace: List[ClaimHash, MAX_TRACE]) -> Response:
if depth(claim.position) % 2 != chal.value:
if claim.parent is None or agree_with(claim.parent, chal_trace):
if chal_trace[trace_index(claim.position)] == claim.claim_hash:
defend()
else:
attack()
else: pass # avoid supporting invalid claims on the same team
return respond_claim(claim, chal_trace)
else:
return Response.NOP # avoid supporting invalid claims on the same team
else:
correct_response = respond(claim.parent, chal, chal_trace)
claim_response = Response.ATTACK if is_attack(claim) else Response.DEFEND
invalid_defense = claim_response == Response.DEFEND and correct_response == Respond.ATTACK
if not invalid_defense:
return respond_claim(claim, chal_trace)
else:
return Response.NOP
```

In attack or defense, the honest challenger submit a `ClaimHash` corresponding to the
Expand Down

0 comments on commit cd7ccb3

Please sign in to comment.