forked from ethereum-optimism/optimism
-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'develop' into fpvm-status
- Loading branch information
Showing
84 changed files
with
1,841 additions
and
1,464 deletions.
There are no files selected for viewing
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
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
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
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
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,16 @@ | ||
## Fault Proofs Alpha | ||
|
||
The fault proof alpha is a pre-release version of the OP Stack fault proof system. | ||
This documentation provides an overview of the system and instructions on how to help | ||
test the fault proof system. | ||
|
||
The overall design of this system along with the APIs and interfaces it exposes are not | ||
finalized and may change without notice. | ||
|
||
### Contents | ||
|
||
* Overview | ||
* [Deployment Details](./deployments.md) | ||
* [Manual Usage](./manual.md) | ||
* [Creating Traces with Cannon](./cannon.md) | ||
* [Automation with `op-challenger`](./run-challenger.md) |
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,92 @@ | ||
## Generate Traces with `cannon` and `op-program` | ||
|
||
Normally, `op-challenger` handles creating the required traces as part of responding to games. However, for manual | ||
testing it may be useful to manually generate the trace. This can be done by running `cannon` directly. | ||
|
||
### Prerequisites | ||
|
||
- The cannon pre-state downloaded from [Goerli deployment](./deployments.md#goerli). | ||
- A Goerli L1 node. | ||
- An archive node is not required. | ||
- Public RPC providers can be used, however a significant number of requests will need to be made which may exceed | ||
rate limits for free plans. | ||
- An OP-Goerli L2 archive node with `debug` APIs enabled. | ||
- An archive node is required to ensure world-state pre-images remain available. | ||
- Public RPC providers are generally not usable as they don’t support the `debug_dbGet` RPC method. | ||
|
||
### Compilation | ||
|
||
To compile the required programs, in the top level of the monorepo run: | ||
|
||
```bash | ||
make cannon-prestate | ||
``` | ||
|
||
This will compile the `cannon` executable to `cannon/bin/cannon` as well as the `op-program` executable used to fetch | ||
pre-image data to `op-program/bin/op-program`. | ||
|
||
### Run Cannon | ||
|
||
To run cannon to generate a proof use: | ||
|
||
```bash | ||
mkdir -p temp/cannon/proofs temp/cannon/snapshots temp/cannon/preimages | ||
|
||
./cannon/bin/cannon run \ | ||
--pprof.cpu \ | ||
--info-at '%10000000' \ | ||
--proof-at '=<TRACE_INDEX>' \ | ||
--stop-at '=<STOP_INDEX>' \ | ||
--proof-fmt 'temp/cannon/proofs/%d.json' \ | ||
--snapshot-at '%1000000000' \ | ||
--snapshot-fmt 'temp/cannon/snapshots/%d.json.gz' \ | ||
--input <PRESTATE> \ | ||
--output temp/cannon/stop-state.json \ | ||
-- \ | ||
./op-program/bin/op-program \ | ||
--network goerli \ | ||
--l1 <L1_URL> \ | ||
--l2 <L2_URL> \ | ||
--l1.head <L1_HEAD> \ | ||
--l2.claim <L2_CLAIM> \ | ||
--l2.head <L2_HEAD> \ | ||
--l2.blocknumber <L2_BLOCK_NUMBER> \ | ||
--datadir temp/cannon/preimages \ | ||
--log.format terminal \ | ||
--server | ||
``` | ||
|
||
The placeholders are: | ||
|
||
- `<TRACE_INDEX>` the index in the trace to generate a proof for | ||
- `<STOP_INDEX>` the index to stop execution at. Typically this is one instruction after `<TRACE_INDEX>` to stop as soon | ||
as the required proof has been generated. | ||
- `<PRESTATE>` the prestate.json downloaded above. Note that this needs to precisely match the prestate used on-chain so | ||
must be the downloaded version and not a version built locally. | ||
- `<L1_URL>` the Goerli L1 JSON RPC endpoint | ||
- `<L2_URL>` the OP-Goerli L2 archive node JSON RPC endpoint | ||
- `<L1_HEAD>` the hash of the L1 head block used for the dispute game | ||
- `<L2_CLAIM>` the output root immediately prior to the disputed root in the L2 output oracle | ||
- `<L2_HEAD>` the hash of the L2 block that `<L2_CLAIM>`is from | ||
- `<L2_BLOCK_NUMBER>` the block number that `<L2_CLAIM>` is from | ||
|
||
The generated proof will be stored in the `temp/cannon/proofs/` directory. The hash to use as the claim value is | ||
the `post` field of the generated proof which provides the hash of the cannon state witness after execution of the step. | ||
|
||
Since cannon can be very slow to execute, the above command uses the `--snapshot-at` option to generate a snapshot of | ||
the cannon state every 1000000000 instructions. Once generated, these snapshots can be used as the `--input` to begin | ||
execution at that step rather than from the very beginning. Generated snapshots are stored in | ||
the `temp/cannon/snapshots` directory. | ||
|
||
See `./cannon/bin/cannon --help` for further information on the options available. | ||
|
||
### Trace Extension | ||
|
||
Fault dispute games always use a trace with a fixed length of `2 ^ MAX_GAME_DEPTH`. The trace generated by `cannon` | ||
stops when the client program exits, so this trace must be extended by repeating the hash of the final state in the | ||
actual trace for all remaining steps. Cannon does not perform this trace extension automatically. | ||
|
||
If cannon stops execution before the trace index you requested a proof at, it simply will not generate a proof. When it | ||
stops executing, it will write its final state to `temp/cannon/stop-state.json` (controlled by the `--output` option). | ||
The `step` field of this state contains the last step cannon executed. Once the final step is known, rerun cannon to | ||
generate the proof at that final step and use the `post` hash as the claim value for all later trace indices. |
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,24 @@ | ||
## Fault Proof Alpha Deployment Information | ||
|
||
### Goerli | ||
|
||
Information on the fault proofs alpha deployment to Goerli is not yet available. | ||
|
||
### Local Devnet | ||
|
||
The local devnet includes a deployment of the fault proof alpha. To start the devnet, in the top level of this repo, | ||
run: | ||
|
||
```bash | ||
make devnet-up | ||
``` | ||
|
||
| Input | Value | | ||
|----------------------|-------------------------------------------------------------| | ||
| Dispute Game Factory | Run `jq -r .DisputeGameFactoryProxy .devnet/addresses.json` | | ||
| Absolute Prestate | `op-program/bin/prestate.json` | | ||
| Max Depth | 30 | | ||
| Max Game Duration | 1200 (20 minutes) | | ||
|
||
See the [op-challenger README](../../op-challenger#running-with-cannon-on-local-devnet) for information on | ||
running `op-challenger` against the local devnet. |
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,111 @@ | ||
## Manual Fault Proof Interactions | ||
|
||
### Creating a Game | ||
|
||
The process of disputing an output root starts by creating a new dispute game. There are conceptually three key inputs | ||
required for a dispute game: | ||
|
||
- The output root being disputed | ||
- The agreed output root the derivation process will start from | ||
- The L1 head block that defines the canonical L1 chain containing all required batch data to perform the derivation | ||
|
||
The creator of the game selects the output root to dispute. It is identified by its L2 block number which can be used to | ||
look up the full details in the L2 output oracle. | ||
|
||
The agreed output root is defined as the output root immediately prior to the disputed output root in the L2 output | ||
oracle. Therefore, a dispute game should only be created for the first invalid output root. If it is successfully | ||
disputed, all output roots after it are considered invalid by inference. | ||
|
||
The L1 head block can be any L1 block where the disputed output root is present in the L2 output oracle. Proposers | ||
should therefore ensure that all batch data has been submitted to L1 before submitting a proposal. The L1 head block is | ||
recorded in the `BlockOracle` and then referenced by its block number. | ||
|
||
Creating a game requires two separate transactions. First the L1 head block is recorded in the `BlockOracle` by calling | ||
its `checkpoint` function. This records the parent of the block the transaction is included in. The `BlockOracle` emits | ||
a log `Checkpoint(blockNumber, blockHash, childTimestamp)`. | ||
|
||
Now, using the L1 head along with output root info available in the L2 output oracle, cannon can be executed to | ||
determine the root claim to use when creating the game. In simple cases, where the claim is expected to be incorrect, an | ||
arbitrary hash can be used for claim values. For more advanced cases [cannon can be used](./cannon.md) to generate a | ||
trace, including the claim values to use at specific steps. Note that it is not valid to create a game that disputes an | ||
output root, using the final hash from a trace that confirms the output root is valid. To dispute an output root | ||
successfully, the trace must resolve that the disputed output root is invalid. | ||
|
||
The game can then be created by calling the `create` method on the `DisputeGameFactory` contract. This requires three | ||
parameters: | ||
|
||
- `gameType` - a `uint8` representing the type of game to create. For fault dispute games using cannon and op-program | ||
traces, the game type is 0. | ||
- `rootClaim` - a `bytes32` hash of the final state from the trace. | ||
- `extraData` - arbitrary bytes which are used as the initial inputs for the game. For fault dispute games using cannon | ||
and op-program traces, this is the abi encoding of `(uint256(l2_block_number), uint256(l1_checkpoint))`. | ||
- `l2_block_number` is the L2 block number from the output root being disputed | ||
- `l1_checkpoint` is the L1 block number recorded by the `BlockOracle` checkpoint | ||
|
||
This emits a log event `DisputeGameCreated(gameAddress, gameType, rootClaim)` where `gameAddress` is the address of the | ||
newly created dispute game. | ||
|
||
The helper script, [create_game.sh](../../op-challenger#create_gamesh) can be used to easily create a new dispute | ||
game and also acts as an example of using `cast` to manually create a game. | ||
|
||
### Performing Moves | ||
|
||
The dispute game progresses by actors countering existing claims via either the `attack` or `defend` methods in | ||
the `FaultDisputeGame` contract. Note that only `attack` can be used to counter the root claim. In both cases, there are | ||
two inputs required: | ||
|
||
- `parentIndex` - the index in the claims array of the parent claim that is being countered. | ||
- `claim` - a `bytes32` hash of the state at the trace index corresponding to the new claim’s position. | ||
|
||
The helper script, [move.sh](../../op-challenger#movesh), can be used to easily perform moves and also | ||
acts as an example of using `cast` to manually call `attack` and `defend`. | ||
|
||
### Performing Steps | ||
|
||
Attacking or defending are teh only available actions before the maximum depth of the game is reached. To counter claims | ||
at the maximum depth, a step must be performed instead. Calling the `step` method in the `FaultDisputeGame` contract | ||
counters a claim at the maximum depth by running a single step of the cannon VM on chain. The `step` method will revert | ||
unless the cannon execution confirms the claim being countered is invalid. Note, if an actor's clock runs out at any | ||
point, the game can be [resolved](#resolving-a-game). | ||
|
||
The inputs for step are: | ||
|
||
- `claimIndex` - the index in the claims array of the claim that is being countered | ||
- `isAttack` - Similar to regular moves, steps can either be attacking or defending | ||
- `stateData` - the full cannon state witness to use as the starting state for execution | ||
- `proof` - the additional proof data for the state witness required by cannon to perform the step | ||
|
||
When a step is attacking, the caller is asserting that the claim at `claimIndex` is incorrect, and the claim for | ||
the previous trace index (made at a previous level in the game) was correct. The `stateData` must be the pre-image for | ||
the agreed correct hash at the previous trace index. The call to `step` will revert if the post-state from cannon | ||
matches the claim at `claimIndex` since the on-chain execution has proven the claim correct and it should not be | ||
countered. | ||
|
||
When a step is defending, the caller is asserting that the claim at `claimIndex` is correct, and the claim for | ||
the next trace index (made at a previous level in the game) is incorrect. The `stateData` must be the pre-image for the | ||
hash in the claim at `claimIndex`. | ||
|
||
The `step` function will revert with `ValidStep()` if the cannon execution proves that the claim attempting to be | ||
countered is correct. As a result, claims at the maximum game depth can only be countered by a valid execution of the | ||
single instruction in cannon running on-chain. | ||
|
||
#### Populating the Pre-image Oracle | ||
|
||
When the instruction to be executed as part of a `step` call reads from some pre-image data, that data must be loaded | ||
into the pre-image oracle prior to calling `step`. | ||
For [local pre-image keys](../../specs/fault-proof.md#type-1-local-key), the pre-image must be populated via | ||
the `FaultDisputeGame` contract by calling the `addLocalData` function. | ||
For [global keccak256 keys](../../specs/fault-proof.md#type-2-global-keccak256-key), the data should be added directly | ||
to the pre-image oracle contract. | ||
|
||
### Resolving a Game | ||
|
||
The final action required for a game is to resolve it by calling the `resolve` method in the `FaultDisputeGame` | ||
contract. This can only be done once the clock of the left-most uncontested claim’s parent has expired. A game can only | ||
be resolved once. | ||
|
||
There are no inputs required for the `resolve` method. When successful, a log event is emitted with the game’s final | ||
status. | ||
|
||
The helper script, [resolve.sh](../../op-challenger#resolvesh), can be used to easily resolve a game and also acts as an | ||
example of using `cast` to manually call `resolve` and understand the result. |
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,65 @@ | ||
## Running op-challenger | ||
|
||
`op-challenger` is a program that implements the honest actor algorithm to automatically “play” the dispute games. | ||
|
||
### Prerequisites | ||
|
||
- The cannon pre-state downloaded from [Goerli deployment](./deployments.md#goerli). | ||
- An account on the Goerli testnet with funds available. The amount of GöETH required depends on the number of claims | ||
the challenger needs to post, but 0.01 ETH should be plenty to start. | ||
- A Goerli L1 node. | ||
- An archive node is not required. | ||
- Public RPC providers can be used, however a significant number of requests will need to be made which may exceed | ||
rate limits for free plans. | ||
- An OP-Goerli L2 archive node with `debug` APIs enabled. | ||
- An archive node is required to ensure world-state pre-images remain available. | ||
- Public RPC providers are generally not usable as they don’t support the `debug_dbGet` RPC method. | ||
- Approximately 3.5Gb of disk space for each game being played. | ||
|
||
### Starting op-challenger | ||
|
||
When executing `op-challenger`, there are a few placeholders that need to be set to concreate values: | ||
|
||
- `<L1_URL>` the Goerli L1 JSON RPC endpoint | ||
- `<DISPUTE_GAME_FACTORY_ADDRESS>` the address of the dispute game factory contract (see | ||
the [Goerli deployment details](./deployments.md#goerli)) | ||
- `<PRESTATE>` the prestate.json downloaded above. Note that this needs to precisely match the prestate used on-chain so | ||
must be the downloaded version and not a version built locally (see the [Goerli deployment details](./deployments.md#goerli)) | ||
- `<L2_URL>` the OP-Goerli L2 archive node JSON RPC endpoint | ||
- `<PRIVATE_KEY>` the private key for a funded Goerli account. For other ways to specify the account to use | ||
see `./op-challenger/bin/op-challenger --help` | ||
|
||
From inside the monorepo directory, run the challenger with these placeholders set. | ||
|
||
```bash | ||
# Build the required components | ||
make op-challenger op-program cannon | ||
|
||
# Run op-challenger | ||
./op-challenger/bin/op-challenger \ | ||
--trace-type cannon \ | ||
--l1-eth-rpc <L1_URL> \ | ||
--game-factory-address <DISPUTE_GAME_FACTORY_ADDRESS> \ | ||
--agree-with-proposed-output=true \ | ||
--datadir temp/challenger-goerli \ | ||
--cannon-network goerli \ | ||
--cannon-bin ./cannon/bin/cannon \ | ||
--cannon-server ./op-program/bin/op-program \ | ||
--cannon-prestate <PRESTATE> \ | ||
--cannon-l2 <L2_URL> \ | ||
--private-key <PRIVATE_KEY> | ||
``` | ||
|
||
|
||
### Restricting Games to Play | ||
|
||
By default `op-challenger` will generate traces and respond to any game created by the dispute game factory contract. On | ||
a public testnet like Goerli, that could be a large number of games, requiring significant CPU and disk resources. To | ||
avoid this, `op-challenger` supports specifying an allowlist of games for it to respond to with the `--game-allowlist` | ||
option. | ||
|
||
```bash | ||
./op-challenger/bin/op-challenger \ | ||
... \ | ||
--game-allowlist <GAME_ADDR> <GAME_ADDR> <GAME_ADDR>... | ||
``` |
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
Oops, something went wrong.