-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #7 from kroma-network/docs/fault-proof-system-v2
docs: write specifications about Fault Proof System V2
- Loading branch information
Showing
13 changed files
with
1,211 additions
and
9 deletions.
There are no files selected for viewing
Validating CODEOWNERS rules …
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# Specs | ||
|
||
/specs @kroma-network/l2-protocol |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} | ||
``` |
Oops, something went wrong.