Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fp updates #1257

Draft
wants to merge 5 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 28 additions & 22 deletions pages/stack/fault-proofs/cannon.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,11 @@ dispute game.
### OP-Program \<> Cannon

Once the execution trace bisection begins and Cannon is run, an Executable and Linkable Format (ELF) binary will be loaded and run within Cannon.
Within Cannon is the `mipsevm` that is built to handle the MIPS R3000, 32-bit Instruction Set Architecture (ISA). The ELF file contains MIPS instructions,
where the code that has been compiled into MIPS instructions is OP-Program.
Within Cannon is the `mipsevm` that is built to handle the MIPS R4000, 64-bit Instruction Set Architecture (ISA). The ELF file contains MIPS instructions, where the code that has been compiled into MIPS instructions is OP-Program.

OP-Program is golang code that will be compiled into MIPS instructions and run within the Cannon FPVM. OP-Program, whether run as standalone
golang code or in Cannon, fetches all necessary data used for deriving the state of the L2. It is built such that the
same inputs will produce not only the same outputs, but the same execution trace. This allows all participants in a fault dispute game to run
OP-Program such that, given the same L2 output root state transition, they can generate the same execution traces. This in turn generates the same
witness proof for the exact same MIPS instruction that will be run onchain.
OP-Program is golang code that will be compiled into MIPS64 instructions and run within the Cannon FPVM. As mentioned previously, the `mipsevm` is 64-bit, which means the full addressable address range is `[0, 2^64-1]`. The memory layout uses the typical monolithic memory structure, and the VM operates as though it were interacting directly with physical memory.

OP-Program, whether run as standalone golang code or in Cannon, fetches all necessary data used for deriving the state of the L2. It is built such that the same inputs will produce not only the same outputs, but the same execution trace. This allows all participants in a fault dispute game to run OP-Program such that, given the same L2 output root state transition, can generate the same execution traces. This in turn generates the same witness proof for the exact same MIPS instruction that will be run onchain.

## Overview of offchain Cannon components

Expand All @@ -65,17 +62,14 @@ most important features / considerations highlighted.

### `mipsevm` state and memory

As mentioned previously, the `mipsevm` is 32-bit, which means the full addressable address range is `[0, 2^32-1]`. The memory layout
uses the typical monolithic memory structure, and the VM operates as though it were interacting directly with physical memory.
For the mipsevm, how memory is stored isn't important, as it can hold the entire monolithic memory within the Go runtime. The addressable memory range is \[0, 2^64-1], as the VM implements a 64-bit address space. The memory layout uses the typical monolithic memory structure, and the VM operates as though it were interacting directly with physical memory.

For the `mipsevm`, how memory is stored isn't important, as it can hold the entire monolithic memory within the Go runtime.
In this way, how memory is represented is abstracted away from the VM itself. However, it is important for memory to be represented
such that only small portions are needed in order to run a MIPS instruction onchain. This is because it is infeasible to represent the
entire 32-bit memory space onchain due to cost. Therefore, memory is stored in a binary Merkle tree data structure, with the implementation
In this way, how memory is represented is abstracted away from the VM itself. However, it is important for memory to be represented such that only small portions are needed in order to run a MIPS instruction onchain. This is because it is infeasible to represent the entire 64-bit memory space onchain due to cost.
Therefore, memory is stored in a binary Merkle tree data structure, with the implementation
spread across [`memory.go`](https://github.com/ethereum-optimism/optimism/blob/develop/cannon/mipsevm/memory/memory.go) and
[`page.go`](https://github.com/ethereum-optimism/optimism/blob/develop/cannon/mipsevm/memory/page.go).
The tree has a fixed-depth of 27 levels, with leaf values of 32 bytes each. This spans the full 32-bit address space: `2**27 * 32 = 2**32`.
Each leaf contains the memory for that part of the tree.

The tree has a fixed-depth of 28 levels, with leaf values of 32 bytes each. This spans the full 64-bit address space: 2**28 \* 32 = 2**64. Each leaf contains the memory for that part of the tree.

`memory.go` defines the data structure, `Memory`, which holds pointers to `nodes` and `pages`. A memory `node` holds the calculated Merkle
root of its parent node within the memory binary Merkle tree, where the 'location' of the node is determined by its generalized index.
Expand Down Expand Up @@ -111,7 +105,7 @@ The last major component is located in [`state.go`](https://github.com/ethereum-
The `State` struct in `state.go` holds all the execution state that is required for the `mipsevm`.
The information stored is largely identical to the [VM execution state](mips#packed-vm-execution-state) for `MIPS.sol`. The key differences are:

* Instead of storing just the memory Merkle root, there is a `Memory` Struct pointer for the binary Merkle tree representation of the entire 32-bit memory space.
* Instead of storing just the memory Merkle root, there is aMemoryStruct pointer for the binary Merkle tree representation of the entire 64-bit memory space.
* There is an optional `LastHint` bytes variable, which can be used to communicate a Pre-image hint to avoid having to load in multiple prior Pre-images.

#### Generating the witness proof
Expand Down Expand Up @@ -188,13 +182,13 @@ certain syscalls. The full list of instructions supported can be found [here](mi

#### `mips.go` vs. `MIPS.sol`

The offchain `mips.go` and the onchain Cannon `MIPS.sol` behave similarly when it comes to executing 32-bit, MIPS III instructions.
The offchain `mips.go` and the onchain Cannon `MIPS.sol` behave similarly when it comes to executing 64-bit, MIPS III instructions.
In fact, they must produce **exactly the same results** given the same instruction, memory, and register state.
Consequently, the [witness data](#witness-data) is essential to reproduce the same instruction onchain and offchain.
However, there are differences between the two:
However, there are differences between the onchain and offchain implementations:

1. A single instruction will be run onchain in `MIPS.sol`, whereas the offchain `mips.go` will run all MIPS instructions for all state transitions in the disputed L2 state.
2. The `mipsevm` contains the entire 32-bit monolithic memory space, is responsible for maintaining the memory state based on the results of MIPS instructions, and generates the memory binary Merkle tree, Merkle root, and memory Merkle proofs. `MIPS.sol` is mostly stateless, and does not maintain the full memory space. Instead, it only requires the memory Merkle root, and up to two memory Merkle proofs: 1 for the instruction and 1 for potential load, store, or certain syscall instructions.
2. The mipsevm contains the entire 64-bit monolithic memory space, is responsible for maintaining the memory state based on the results of MIPS instructions, and generates the memory binary Merkle tree, Merkle root, and memory Merkle proofs. MIPS.sol is mostly stateless, and does not maintain the full memory space. Instead, it only requires the memory Merkle root, and up to two memory Merkle proofs: 1 for the instruction and 1 for potential load, store, or certain syscall instructions.
3. Unlike `MIPS.sol`, `mips.go` is responsible for writing Pre-images to the PreimageOracle Server, and optionally writing hints to the Server.

### PreimageOracle interaction
Expand All @@ -212,10 +206,22 @@ define the ABI for communicating pre-images.

This ABI is implemented by the VM by intercepting the `read`/`write` syscalls to specific file descriptors. See [Cannon VM Specs](https://specs.optimism.io/experimental/fault-proof/cannon-fault-proof-vm.html#io) for more details.

Note that although the oracle provides up to 32 bytes of the pre-image,
Cannon only supports reading at most 4 bytes at a time, to unify the memory operations with 32-bit load/stores.
<Callout>
Although the oracle provides up to 32 bytes of the pre-image, Cannon supports reading up to 8 bytes at a time in its 64-bit implementation, unifying memory operations with 64-bit load/stores. This enhancement from the previous 32-bit implementation allows for more efficient memory handling and improved performance.
</Callout>

### Multi-threading support

A significant enhancement to Cannon is the introduction of multi-threading capabilities. This upgrade enables:

* Concurrent execution of MIPS instructions across multiple threads
cpengilly marked this conversation as resolved.
Show resolved Hide resolved
* Deterministic thread scheduling and state management
* Asynchronous garbage collection through Go runtime
* Improved performance through parallel processing

The multi-threaded implementation maintains deterministic execution by carefully managing thread states and context switching, ensuring that the same execution trace can be reproduced both onchain and offchain.

## Further Reading
## Next steps

* [Cannon FPVM Specification](https://specs.optimism.io/experimental/fault-proof/cannon-fault-proof-vm.html)
* [Merkle Proofs Specification](https://github.com/ethereum/consensus-specs/blob/dev/ssz/merkle-proofs.md)
Expand Down
18 changes: 14 additions & 4 deletions pages/stack/fault-proofs/challenger.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ import Image from 'next/image'

# OP-Challenger explainer

The `op-challenger` operates as the *honest actor* in the fault dispute system and defends the chain by securing the `OptimismPortal` and ensuring the game always resolves to the correct state of the chain. For verifying the legitimacy of claims, `op-challenger` relies on a synced, trusted rollup node as well as a trace provider (e.g., [Cannon](/stack/fault-proofs/cannon)).
The `op-challenger` operates as the *honest actor* in the fault dispute system and defends the chain by securing the `OptimismPortal` and ensuring the game always resolves to the correct state of the chain. For verifying the legitimacy of claims, `op-challenger` relies on a synced, trusted rollup node as well as a trace provider (e.g., [Cannon](/stack/fault-proofs/cannon)) that now supports 64-bit MIPS emulation.

The updated 64-bit architecture allows for a significantly larger address space compared to the previous 32-bit implementation, enabling the system to handle more complex state transitions and larger memory requirements. This upgrade to 64-bit addressing provides access to a theoretical 16 exabytes of virtual memory space, though practical limitations and system configurations will typically restrict this to a more manageable size.

Specifically, `op-challenger` performs the following actions:

Expand All @@ -20,7 +22,7 @@ Specifically, `op-challenger` performs the following actions:
* claims paid out bonds for both the challenger and proposer

## Architecture
This diagram illustrates how `op-challenger` monitors dispute games, defends valid proposals, and challenges invalid ones. It also shows its interaction with the `op-proposer` in resolving claims.
This diagram illustrates how `op-challenger` monitors dispute games, defends valid proposals, and challenges invalid ones. It also shows its interaction with the `op-proposer` in resolving claims. OP-Challenger now leverages a 64-bit MIPS VM with multithreaded capabilities, enabling features like asynchronous garbage collection and deterministic thread management through context switching.

```mermaid
graph TD;
Expand All @@ -30,12 +32,20 @@ graph TD;
OP -->|Assists| OPP[OP-Proposer]
OPP -->|Resolves Claims| DG
DG -->|Claims Paid| Bonds[Bonds for Challenger and Proposer]

subgraph VM[64-bit MIPS VM]
MT[Multithreaded Execution] -->|Manages| TS[Thread States]
MT -->|Enables| GC[Asynchronous GC]
MT -->|Controls| CS[Context Switching]
end

OP -->|Uses| VM

classDef default fill:#00,stroke:#FF0420,stroke-width:2px;
```

<Callout>
The `cannon` and `op-program` executables are run in the `op-challenger` docker container as sub-processes when required to generate game trace data.
The `cannon` and `op-program` executables are run in the `op-challenger` docker container as sub-processes, leveraging 64-bit MIPS emulation and multithreaded capabilities to efficiently generate game trace data.
</Callout>

## Fault detection responses
Expand Down Expand Up @@ -97,7 +107,7 @@ Note: An actor would only be pushed down to the bottom half of the game if the b

### How many CPUs should I run for challenger to work efficiently?

The default `--max-concurrency` setting suits most operators. Increase it if the challenger lags, or decrease it if it overloads with requests.
The default `--max-concurrency` setting is optimized for the 64-bit MIPS emulation with multithreaded Cannon. The system automatically balances thread allocation, but you can adjust this value if needed - increase it to utilize more parallel processing power, or decrease it if system resources are constrained.

### How much ETH do you need to challenge in a game?

Expand Down
Loading