Skip to content

Commit

Permalink
Merge pull request #7 from kroma-network/docs/fault-proof-system-v2
Browse files Browse the repository at this point in the history
docs: write specifications about Fault Proof System V2
  • Loading branch information
seolaoh authored Apr 30, 2024
2 parents a095c74 + 0d46407 commit 42cff00
Show file tree
Hide file tree
Showing 13 changed files with 1,211 additions and 9 deletions.
3 changes: 3 additions & 0 deletions .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Specs

/specs @kroma-network/l2-protocol
16 changes: 12 additions & 4 deletions specs/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,21 @@
- [Execution Engine](./protocol/exec-engine.md)
- [Rollup Node](./protocol/rollup-node.md)
- [Rollup Node P2P](./protocol/rollup-node-p2p.md)
- [L2 Chain Derivation](./protocol/derivation.md)
- [Derivation](./protocol/derivation.md)
- [Span Batches](./protocol/span-batches.md)
- [Batcher](./protocol/batcher.md)
- [Batch Submitter](./protocol/batcher.md)
- [Predeploys](./protocol/predeploys.md)
- [SystemConfig](./protocol/system-config.md)
- [Mint Manager](./protocol/mint-manager.md)
- [System Config](./protocol/system-config.md)
- [Fault Proof]()
- [Challenge](./fault-proof/challenge.md)
- [zkEVM Prover](./fault-proof/zkevm-prover.md)
- [Experimental]()
- [Mint Manager](./protocol/mint-manager.md)
- [Fault Proof System V2](./fault-proof-system-v2/overview.md)
- [Definitions](./fault-proof-system-v2/definitions.md)
- [Transaction Data Commitment](./fault-proof-system-v2/transaction-data-commitment.md)
- [Output Proposal](./fault-proof-system-v2/output-proposal.md)
- [Challenge](./fault-proof-system-v2/challenge.md)
- [Security Council Intervention](./fault-proof-system-v2/security-council-intervention.md)
- [Improvements](./fault-proof-system-v2/improvements.md)
- [Glossary](./glossary.md)
517 changes: 517 additions & 0 deletions specs/fault-proof-system-v2/challenge.md

Large diffs are not rendered by default.

123 changes: 123 additions & 0 deletions specs/fault-proof-system-v2/definitions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
# Definitions

<!-- All glossary references in this file. -->

[g-l2-output]: ../glossary.md#l2-output-root
[g-validator]: ../glossary.md#validator
[g-zk-fault-proof]: ../glossary.md#zk-fault-proof
[g-security-council]: ../glossary.md#security-council

<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
**Table of Contents**

- [Overview](#overview)
- [Participants](#participants)
- [Asserter](#asserter)
- [Challenger](#challenger)
- [History](#history)
- [Claim](#claim)
- [History Root](#history-root)
- [Edge](#edge)
- [Edge Dissection](#edge-dissection)
- [Edge Confirmation](#edge-confirmation)
- [Rival Edge](#rival-edge)
- [Presumptive Edge](#presumptive-edge)
- [Presumptive Timer](#presumptive-timer)
- [Edge Confirmation Condition](#edge-confirmation-condition)
- [Constants](#constants)

<!-- END doctoc generated TOC please keep comment here to allow auto update -->

## Overview

This document provides definitions of new terms introduced in Fault Proof System V2.

## Participants

### Asserter

An asserter refers to a validator who proposes the first output for a particular index or a validator proceeding a
challenge in the same party as the one proposing the first output.

### Challenger

A challenger refers to a validator who creates a challenge by proposing a different output when an output already exists
on a particular index, or a validator proceeding the challenge in the same party as the one creating the challenge.

## History

The history $H$ represents the sequence of [output roots][g-l2-output] $O$. The first output root in the sequence $O_0$
is the agreed-upon initial state. The height of the history $n$ can be at most `PROPOSAL_INTERVAL`.

```math
H_n = (O_0, O_1, ..., O_n) \ \ \ \ \ (n \leq \verb#PROPOSAL_INTERVAL#)
```

## Claim

A claim $C$ is a commitment to the entire sequence of the history, represented as a Merkle root of a Merkle tree with
all outputs in the history as leaf nodes. When a challenger creates a challenge and submits a claim of the history that
the challenger believes to be correct, any [validators][g-validator] who agree with the history can participate in the
challenge and take over the remaining challenge process on behalf of the challenger who initiated the challenge.
Likewise, after the asserter submits a claim to respond to a challenge, anyone who agrees with the asserter's claim can
continue the challenge on behalf of the asserter. This mechanism allows to turn the one-vs-one challenge of V1 into an
all-vs-all challenge.

### History Root

History root is essentially the same as claim, it denotes the Merkle root of historical outputs.

## Edge

An edge is consisted of two claims $(C_n, C_m) \ (n < m)$. The length of an edge is $m - n$, which can be at least 1 and
at most `PROPOSAL_INTERVAL`. The challenger must submit $(C_0, C_\verb#PROPOSAL_INTERVAL#)$ when creating a challenge,
where $C_\verb#PROPOSAL_INTERVAL#$ is the claim corresponding to the challenge target output and $C_0$ is the claim
corresponding to the previous output.

### Edge Dissection

Edges are dissected to find the first disagreement point between asserters and challengers. Each dissection deepens the
edge and necessitates the submission of intermediate claims, and these claims can also be represented as edges in pairs
of two. In other words, a challenge can be considered as a contest between edges. The depth of an edge indicates the
number of times that the edge has been dissected from the first edge submitted when creating the challenge. The number
of claims that should be submitted for each depth as a result of dissection is determined by a configuration.

### Edge Confirmation

Edge confirmation determines the challenge outcome. A valid edge can be confirmed, and the associated output is
considered to be valid.

### Rival Edge

A rival edge represents one of the conflicting edges with the same length and starting claim but different ending
claims. Only a pair of rival edges exists at each depth because the first claim must be the same and the last claim must
be different. The rival edge is dissected in the next dissection, narrowing down to an edge with a length of 1. As the
rival edges represent different histories, only one of them can be confirmed.

### Presumptive Edge

An edge without a rival. It can be confirmed after a set period if no rival edge submitted.

### Presumptive Timer

An edge's presumptive timer tracks the duration an edge and its parent edges have been in presumptive status. Edge
confirmation is possible once the presumptive timer passes a predefined deadline.

### Edge Confirmation Condition

Edge confirmation can be accomplished in three ways.

- If all child edges are confirmed, the parent edge can be confirmed.
- A presumptive edge can be confirmed after its presumptive timer expires.
- A rival edge of length 1 can be confirmed with [ZK fault proof][g-zk-fault-proof] verification.

If one of the first two conditions is met, only one of the rival edges can be confirmed on a first-come, first-served
basis. If the third condition is met, redundant confirmations are allowed in order to detect ZK soundness errors
on-chain. In this case, the [Security Council][g-security-council] must intervene to handle the redundant confirmations.

## Constants

| Name | Value | Unit |
|---------------------|--------|--------|
| `PROPOSAL_INTERVAL` | `1800` | blocks |
57 changes: 57 additions & 0 deletions specs/fault-proof-system-v2/improvements.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# Improvements

<!-- All glossary references in this file. -->

[g-checkpoint-output]: ../glossary.md#checkpoint-output
[g-validator]: ../glossary.md#validator
[g-l2-output]: ../glossary.md#l2-output-root

<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
**Table of Contents**

- [Overview](#overview)
- [Guaranteed Win of Valid Output](#guaranteed-win-of-valid-output)
- [Guaranteed Data Verifiability for ZK Proof Verification](#guaranteed-data-verifiability-for-zk-proof-verification)
- [Robust to Delay Attacks](#robust-to-delay-attacks)
- [Accurate Identification of First Disagreeing Block](#accurate-identification-of-first-disagreeing-block)

<!-- END doctoc generated TOC please keep comment here to allow auto update -->

## Overview

Fault Proof System V2 has been designed to address the key limitations identified in
[Fault Proof System V1](../fault-proof/challenge.md), as outlined in the [Background](./overview.md#background). This
document details how each of the four main limitations of V1 has been effectively resolved in V2.

## Guaranteed Win of Valid Output

In V2, the [output branching model](./output-proposal.md#output-branching-model) has been introduced. This model allows
[validators][g-validator] to follow and propose [outputs][g-checkpoint-output] along the branch they believe to be
correct, thereby eliminating the need to delete outputs deemed invalid as a result of a challenge. This directly
addresses a critical V1 issue where a challenger could always win if the previous output was deleted, as it was
impossible to verify the last point of agreement between the asserter and challenger on-chain. Now, the previous output
remains intact, and validators can branch out from the first output they dispute.

Also, in V2, challenge creation and dissection are based on [historical commitments](./definitions.md#claim) of outputs,
unlike V1, which was based on individual outputs. This change allows any validators who concur with the entire
[history](./definitions.md#history) to participate in an ongoing challenge, ensuring that they don't lose due to
timeouts.

## Guaranteed Data Verifiability for ZK Proof Verification

[Transaction Data Commitment](./transaction-data-commitment.md) in V2 ensures that the transaction data required for ZK
proof verification is verifiable on-chain. Validators can now conclusively prove on-chain that they have executed the
correct transactions in the target block to compute the state transition and claimed the correct post-state.

## Robust to Delay Attacks

In V1, delay attacks were possible through successive malicious challenges and deletions of outputs in the case where a
previous output was deleted. V2's output branching model solves this effectively.

## Accurate Identification of First Disagreeing Block

Because [transaction data is verifiable on-chain](./transaction-data-commitment.md), the
[version 1 output root payload](./output-proposal.md#output-root-payload-version-1) no longer relies on the information
from the next block, which leads to the elimination of `next_block_hash` from [output root][g-l2-output] payload. This
allows accurate identification of the first disagreeing block after dissection.
183 changes: 183 additions & 0 deletions specs/fault-proof-system-v2/output-proposal.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
# Output Proposal

<!-- All glossary references in this file. -->

[g-checkpoint-output]: ../glossary.md#checkpoint-output
[g-state]: ../glossary.md#state
[g-validator]: ../glossary.md#validator

<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
**Table of Contents**

- [Overview](#overview)
- [Output Branching Model](#output-branching-model)
- [L2 Output Commitment Construction](#l2-output-commitment-construction)
- [Output Root Payload (Version 1)](#output-root-payload-version-1)
- [`L2OutputOracle` Interface](#l2outputoracle-interface)
- [Output Proposal](#output-proposal)
- [Output Finalization](#output-finalization)

<!-- END doctoc generated TOC please keep comment here to allow auto update -->

## Overview

This document addresses one of the limitations of
[the previous output proposal process](../protocol/validator.md#submitting-l2-output-commitments) in Fault Proof System
V1. When consecutive invalid [outputs][g-checkpoint-output] are proposed, the previous system's sequential
[challenge](../fault-proof/challenge.md) and deletion mechanism for the first invalid output could lead to insufficient
time to [prove fault](../fault-proof/challenge.md#proving-fault) in subsequent challenges before finalization.
Additionally, the limited participation in each challenge (only designated asserters and challengers) increased the risk
of losing challenges due to timeouts, even for honest parties.

To address these limitations, we introduce **output branching model** which allows the proposal of a new branch of
output when disagreeing with the proposed output. Through the output branching model, it is possible to safely handle
all invalid outputs even in the worst-case where consecutive outputs are invalid.

## Output Branching Model

Outputs are proposed at intervals of L2 blocks defined by `PROPOSAL_INTERVAL`. Each output serves as a
[checkpoint][g-checkpoint-output] for the L2 [state][g-state]. Unlike the previous system where outputs were independent
and restricted to one per index, the output branching model links outputs sequentially.

- **Output Linkage**: The $i^{th}$ output links to the $(i-1)^{th}$ output, allowing multiple _output candidates_ at
index $i$.
- **Branch Creation**: Each output candidate represents a _branch_. A [validator][g-validator] can propose the
$(i+1)^{th}$ output candidate following the $i^{th}$ output which it agrees with, so multiple branches can emerge at
each index.
- **Output Finalization**: A [challenge](./challenge.md) determines which output candidate becomes the finalized
$i^{th}$ output. The winner of the challenge will be the one. All other branches except the branch of the finalized
output are deemed invalid, as are their subsequent output candidates, such as the $(i+1)^{th}$, $(i+2)^{th}$, ... etc.

![output-branching-model](../static/assets/output-branching-model.svg)

## L2 Output Commitment Construction

### Output Root Payload (Version 1)

The version 1 payload is defined as:

```pseudocode
payload = state_root || withdrawal_storage_root || block_hash
```

This version removes the `next_block_hash`, which was added as a means to ensure that the asserter and challenger
executed the same transactions in the target block in the
[previous ZK proof verification process](../fault-proof/challenge.md#proving-fault). The elimination of
`next_block_hash` is feasible now that [transaction data is verifiable on-chain](./transaction-data-commitment.md). This
change addresses the incorrect identification of the first disagreeing block in dissection, as noted in the
[Background](./overview.md#background).

## `L2OutputOracle` Interface

<!-- markdownlint-disable-next-line MD024 -->
### Output Proposal

For the output branching model, there are a few changes to the previous `L2OutputOracle` contract interface as shown
below.

```solidity
/**
* @notice OutputStatus represents the current status of output.
*
* @custom:value NO_OUTPUT No output is proposed.
* @custom:value PENDING Output is not finalized yet.
* @custom:value FINALIZED Output is finalized.
*/
enum OutputStatus {
NO_OUTPUT,
PENDING,
FINALIZED
}
/**
* @notice CheckpointOutput represents a commitment to the state of L2 checkpoint.
*
* @custom:field proposer Address of the output proposer.
* @custom:field prevOutputRoot Hash of the previous L2 output directly linked to this output.
* @custom:field l2BlockNumber L2 block number that the output corresponds to.
* @custom:field createdAtBlock L1 block number when this output was created.
* @custom:field status Status of the output.
*/
struct CheckpointOutput {
address proposer;
bytes32 prevOutputRoot;
uint128 l2BlockNumber;
uint64 createdAtBlock;
OutputStatus status;
}
/**
* @notice Mapping of output root to checkpoint output.
*/
mapping(bytes32 => CheckpointOutput) internal l2Outputs;
/**
* @notice Accepts an output root and the corresponding L2 block number. The block number must be
* `PROPOSAL_INTERVAL + prevOutputRoot.l2BlockNumber` in order to be accepted. This function may only
* be called by the validator.
*
* @param prevOutputRoot The previous L2 output root directly linked to output root.
* @param outputRoot The L2 output root of the checkpoint block.
* @param l2BlockNumber The L2 block number that resulted in output root.
* @param l1BlockHash The L1 block hash which must be included in the current chain.
* @param l1BlockNumber The L1 block number with the specified L1 block hash.
*/
function proposeL2Output(
bytes32 prevOutputRoot,
bytes32 outputRoot,
uint256 l2BlockNumber,
bytes32 l1BlockHash,
uint256 l1BlockNumber
) external payable onlyValidator {
// 1. Check if prevOutputRoot exists in l2Outputs
// 2. Ensure that outputRoot does not already exist in l2Outputs
// 3. Check if (L2 block number of the checkpoint output queried with prevOutputRoot + PROPOSAL_INTERVAL)
// is equal to l2BlockNumber
// 4. Check if the timestamp corresponding to l2BlockNumber is earlier than the current time
// 5. Ensure that outputRoot is not bytes(0)
// 6. Verify if the block hash of l1BlockNumber is the same as l1BlockHash (sanity check for reorg)
// 7. Construct the checkpoint output with outputRoot, including prevOutputRoot information, and store it
// in l2Outputs
// 8. Set the status of the checkpoint output to PENDING
}
/**
* @notice Get the checkpoint output for the given output root. The output may not exist.
*
* @param outputRoot The output root of the checkpoint output to return.
*
* @return The checkpoint output struct.
*/
function getL2Output(bytes32 outputRoot) public view returns (CheckpointOutput memory);
```

### Output Finalization

In the output branching model, where multiple outputs at a single index are possible, an additional process to finalize
only one output is required. If a single output is proposed, it can be finalized after `finalizationPeriodBlocks`. In
cases with multiple outputs at an index, a [challenge process](./challenge.md) determines the valid output. Only the
valid output can be finalized. The `finalizationPeriodBlocks` should exceed the
[`challengePeriodBlocks`](./challenge.md#confirm-by-time), the time required before challenge resolution.

```solidity
/**
* @notice An output can be finalized after finalizationPeriodBlocks has elapsed.
*/
uint64 public finalizationPeriodBlocks;
/**
* @notice Finalize a pending output.
*
* @param outputRoot The output root of the checkpoint output to finalize.
* @param winningEdgeId The winning edge id if a challenge is created.
*/
function finalizeOutput(bytes32 outputRoot, bytes32 winningEdgeId) external onlyValidator {
// 1. Ensure that the output corresponding to outputRoot exists in l2Outputs and is in the PENDING status
// 2. Check if finalizationPeriodBlocks has elapsed since the proposal of the output
// 3. Ensure that the previous output connected to the output is the most recently finalized output
// 4. If there is another output connected to the same previous output, ensure that an edge corresponding
// to winningEdgeId exists, is associated with outputRoot, and has the status of CONFIRMED
// 5. Change the status of the output to FINALIZED
}
```
Loading

0 comments on commit 42cff00

Please sign in to comment.