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

test: add e2e tests #357

Draft
wants to merge 14 commits into
base: taehoon/implement-challenger
Choose a base branch
from
Draft
987 changes: 794 additions & 193 deletions Cargo.lock

Large diffs are not rendered by default.

26 changes: 13 additions & 13 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
[workspace]
members = ["utils/*", "programs/*", "scripts/*", "proposer/succinct"]
members = ["utils/*", "programs/*", "scripts/*", "proposer/succinct", "fault_proof"]
resolver = "2"

[workspace.package]
license = "MIT"
edition = "2021"
authors = ["ratankaliani", "zachobront"]
authors = ["ratankaliani", "zachobront", "fakedev9999"]
homepage = "https://succinctlabs.github.io/op-succinct/"
repository = "https://github.com/succinctlabs/op-succinct"

Expand Down Expand Up @@ -43,19 +43,19 @@ tracing-subscriber = { version = "0.3.18", features = ["fmt"] }

# kona
# Switch back to main `kona` once the SingleChainHostCli is merged. https://github.com/op-rs/kona/issues/982
kona-mpt = { git = "https://github.com/succinctlabs/kona", rev = "b91da21b" }
kona-derive = { git = "https://github.com/succinctlabs/kona", rev = "b91da21b", default-features = false }
kona-driver = { git = "https://github.com/succinctlabs/kona", rev = "b91da21b" }
kona-preimage = { git = "https://github.com/succinctlabs/kona", rev = "b91da21b", features = [
kona-mpt = { git = "https://github.com/succinctlabs/kona", rev = "845c5c0" }
kona-derive = { git = "https://github.com/succinctlabs/kona", rev = "845c5c0", default-features = false }
kona-driver = { git = "https://github.com/succinctlabs/kona", rev = "845c5c0" }
kona-preimage = { git = "https://github.com/succinctlabs/kona", rev = "845c5c0", features = [
"rkyv",
"serde",
] }
kona-executor = { git = "https://github.com/succinctlabs/kona", rev = "b91da21b" }
kona-proof = { git = "https://github.com/succinctlabs/kona", rev = "b91da21b" }
kona-executor = { git = "https://github.com/succinctlabs/kona", rev = "845c5c0" }
kona-proof = { git = "https://github.com/succinctlabs/kona", rev = "845c5c0" }

kona-client = { git = "https://github.com/succinctlabs/kona", rev = "b91da21b" }
kona-host = { git = "https://github.com/succinctlabs/kona", rev = "b91da21b" }
kona-providers-alloy = { git = "https://github.com/succinctlabs/kona", rev = "b91da21b" }
kona-client = { git = "https://github.com/succinctlabs/kona", rev = "845c5c0" }
kona-host = { git = "https://github.com/succinctlabs/kona", rev = "845c5c0" }
kona-providers-alloy = { git = "https://github.com/succinctlabs/kona", rev = "845c5c0" }


# op-succinct
Expand Down Expand Up @@ -109,10 +109,10 @@ revm = { version = "19.4.0", default-features = false, features = ["kzg-rs"] }
sp1-lib = { version = "4.0.0", features = ["verify"] }
# sp1-sdk = { version = "4.0.0" }
# TODO: Switch back to version tag once the alloy bump is merged
sp1-sdk = { git = "https://github.com/succinctlabs/sp1", branch = "ratan/bump-alloy" }
sp1-sdk = { git = "https://github.com/succinctlabs/sp1", branch = "dev" }
sp1-zkvm = { version = "4.0.0", features = ["verify", "embedded"] }
# TODO: Switch back to version tag once the Docker workspace directory change is merged.
sp1-build = { git = "https://github.com/succinctlabs/sp1", branch = "ratan/bump-alloy" }
sp1-build = { git = "https://github.com/succinctlabs/sp1", branch = "dev" }

[profile.release-client-lto]
inherits = "release"
Expand Down
2 changes: 2 additions & 0 deletions book/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
- [Update Contract Parameters](./contracts/update-parameters.md)
- [Modifications to Original `L2OutputOracle`](./contracts/modifications.md)
- [Fault Proofs](./fault_proofs/fault_proof_architecture.md)
- [Deploy FP Contracts](./fault_proofs/deploy.md)
- [How to run the FP Proposer](./fault_proofs/proposer.md)
- [Experimental](./experimental/intro.md)
- [OptimismPortalV2](./experimental/optimism-portal-v2.md)
- [FAQ](./faq.md)
Expand Down
107 changes: 107 additions & 0 deletions book/fault_proofs/deploy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
# Deploying OP Succinct Fault Dispute Game

This guide explains how to deploy the OP Succinct Fault Dispute Game contracts using the `DeployOPSuccinctDG.s.sol` script.

## Overview

The deployment script performs the following actions:
1. Deploys the `DisputeGameFactory` implementation and proxy
2. Deploys a mock SP1 verifier for testing or use a SP1 Verifier Gateway set in the environment variable `SP1_VERIFIER_GATEWAY` for production
3. Deploys the `OPSuccinctFaultDisputeGame` implementation
4. Configures the factory with initial bond and game implementation

## Prerequisites

- [Foundry](https://book.getfoundry.sh/getting-started/installation) installed
- Access to an Ethereum node (local or network)
- Environment variables properly configured

## Configuration

Create a `.env` file in the contracts directory with the following variables:

```env
# Required Environment Variables for Game Configuration
GAME_TYPE=42 # Unique identifier for the game type (uint32)
MAX_CHALLENGE_DURATION=604800 # Maximum duration for challenges in seconds
MAX_PROVE_DURATION=86400 # Maximum duration for proving in seconds
# SP1 Verifier Configuration (choose one)
USE_SP1_MOCK_VERIFIER=true # Set to true to deploy a mock verifier for testing
# OR
SP1_VERIFIER_GATEWAY=0x... # Address of the SP1 verifier gateway for production
```

## Deployment

1. Install dependencies:
```bash
forge install
```

2. Change directory to contracts:
```bash
cd contracts
```

3. Build the contracts:
```bash
forge build
```

4. Run the deployment script:
```bash
forge script script/fp/DeployOPSuccinctDG.s.sol --broadcast --rpc-url <RPC_URL> --private-key <PRIVATE_KEY>
```

## Contract Parameters

The deployment script sets up the following parameters:

- **Initial Bond**: 0.01 ETH (configurable in the script)
- **Proof Reward**: 0.01 ETH (configurable in the script)
- **Genesis Parameters**:
- `rollupConfigHash`
- `aggregationVkey`
- `rangeVkeyCommitment`
- `genesisL2BlockNumber`
- `genesisL2OutputRoot`

## Post-Deployment

After deployment, the script will output the addresses of:
- Factory Proxy
- Game Implementation
- SP1 Verifier

Save these addresses for future reference and configuration of other components (proposer, challenger, etc.).

## Security Considerations

- The deployer address will be set as the factory owner
- Initial parameters are set for testing - adjust for production
- The mock SP1 verifier (SP1_MOCK_VERIFIER=true) should ONLY be used for testing
- For production deployments, always provide a valid SP1_VERIFIER_GATEWAY address. Contract addresses for SP1 Verifier Gateways can be found [here](https://docs.succinct.xyz/docs/verification/onchain/contract-addresses).
- Review and adjust the bond and reward values based on network economics

## Troubleshooting

Common issues and solutions:

1. **Compilation Errors**:
- Ensure Foundry is up to date
- Run `forge clean && forge build`

2. **Deployment Failures**:
- Check RPC connection
- Verify sufficient ETH balance
- Confirm gas settings

## Next Steps

After deployment:

1. Update the proposer configuration with the factory address
2. Configure the challenger with the game parameters
3. Test the deployment with a sample game
4. Monitor initial games for correct behavior
121 changes: 121 additions & 0 deletions book/fault_proofs/proposer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
# Fault Proof Proposer

The fault proof proposer is a component responsible for creating and managing op-succinct fault proof games on the L1 chain. It continuously monitors the L2 chain and creates new dispute games at regular intervals to ensure the validity of L2 state transitions.

## Prerequisites

Before running the proposer, ensure you have:

1. Rust toolchain installed (latest stable version)
2. Access to L1 and L2 network nodes
3. The DisputeGameFactory contract deployed (See [Deploy](./deploy.md))
4. Sufficient ETH balance for:
- Transaction fees
- Game bonds (configurable in the factory)
5. Required environment variables properly configured (see [Configuration](#configuration))

## Overview

The proposer performs several key functions:

1. **Game Creation**: Creates new dispute games for L2 blocks at configurable intervals
2. **Game Resolution**: Optionally resolves unchallenged games after their deadline passes
3. **Chain Monitoring**: Continuously monitors the L2 chain's safe head and creates proposals accordingly

## Configuration

The proposer is configured through various environment variables. Create a `.env` file in the root directory:

```env
# Required Configuration
L1_RPC= # L1 RPC endpoint URL
L2_RPC= # L2 RPC endpoint URL
FACTORY_ADDRESS= # Address of the DisputeGameFactory contract (obtained from deployment)
GAME_TYPE= # Type identifier for the dispute game (must match factory configuration)
PRIVATE_KEY= # Private key for transaction signing

# Optional Configuration
PROPOSAL_INTERVAL_IN_BLOCKS=1000 # Number of L2 blocks between proposals
FETCH_INTERVAL=30 # Polling interval in seconds
ENABLE_GAME_RESOLUTION=false # Whether to enable automatic game resolution
MAX_GAMES_TO_CHECK_FOR_RESOLUTION=100 # Maximum number of games to check for resolution
```

### Configuration Steps

1. Deploy the DisputeGameFactory contract following the [deployment guide](./deploy.md)
2. Copy the factory address from the deployment output
3. Create `.env` file with the above configuration
4. Ensure your account has sufficient ETH for bonds and gas

## Running

To run the proposer:
```bash
cd fault_proof
cargo run --bin proposer
```

The proposer will run indefinitely, creating new games and optionally resolving them based on the configuration.

## Features

### Game Creation
- Creates new dispute games at configurable block intervals
- Computes L2 output roots for game proposals
- Ensures proper game sequencing with parent-child relationships
- Handles bond requirements for game creation

### Game Resolution
When enabled (`ENABLE_GAME_RESOLUTION=true`), the proposer:
- Monitors unchallenged games
- Resolves games after their challenge period expires
- Respects parent-child game relationships in resolution
- Only resolves games whose parent games are already resolved

### Chain Monitoring
- Monitors the L2 chain's finalized (safe) head
- Creates proposals for new blocks as they become available
- Maintains proper spacing between proposals based on configuration

## Logging

The proposer uses the `tracing` crate for logging with a default level of INFO. You can adjust the log level by setting the `RUST_LOG` environment variable:

```bash
RUST_LOG=debug cargo run --bin proposer
```

## Error Handling

The proposer includes robust error handling for:
- RPC connection issues
- Transaction failures
- Contract interaction errors
- Invalid configurations

Errors are logged with appropriate context to aid in debugging.

## Architecture

The proposer is built around the `OPSuccinctProposer` struct which manages:
- Configuration state
- Wallet management for transactions
- Game creation and resolution logic
- Chain monitoring and interval management

Key components:
- `ProposerConfig`: Handles environment-based configuration
- `create_game`: Manages game creation with proper bonding
- `resolve_unchallenged_games`: Handles game resolution logic
- `should_attempt_resolution`: Determines if games can be resolved
- `run`: Main loop managing the proposer's operation

## Development

When developing or modifying the proposer:
1. Ensure all environment variables are properly set
2. Test with a local L1/L2 setup first
3. Monitor logs for proper operation
4. Test game creation and resolution separately
5. Verify proper handling of edge cases (network issues, invalid responses, etc.)
21 changes: 21 additions & 0 deletions challenger/fp/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
[package]
name = "op-fp-challenger"
version = "0.1.0"
edition = "2021"

[dependencies]
# alloy
alloy = { version = "0.9" , features = ["full"]}

# op-alloy
op-alloy-network = { version = "0.9", default-features = false }
op-alloy-rpc-types = { version = "0.9", default-features = false }

# general
anyhow.workspace = true
dotenv.workspace = true
log.workspace = true
tokio.workspace = true
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
serde_json.workspace = true
tracing.workspace = true
80 changes: 80 additions & 0 deletions contracts/script/fp/DeployOPSuccinctDG.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;

import {Script} from "forge-std/Script.sol";
import {console} from "forge-std/console.sol";
import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
import {DisputeGameFactory} from "src/dispute/DisputeGameFactory.sol";
import {OPSuccinctFaultDisputeGame} from "src/fp/OPSuccinctFaultDisputeGame.sol";
import {SP1MockVerifier} from "@sp1-contracts/src/SP1MockVerifier.sol";
import {Claim, GameType, Hash, OutputRoot, Duration} from "src/dispute/lib/Types.sol";
import {IDisputeGame} from "src/dispute/interfaces/IDisputeGame.sol";
import {IDisputeGameFactory} from "src/dispute/interfaces/IDisputeGameFactory.sol";
import {ISP1Verifier} from "@sp1-contracts/src/ISP1Verifier.sol";

contract DeployOPSuccinctDG is Script {
function run() public {
vm.startBroadcast();

// Deploy the factory implementation
DisputeGameFactory factoryImpl = new DisputeGameFactory();

// Deploy factory proxy
ERC1967Proxy factoryProxy = new ERC1967Proxy(
address(factoryImpl), abi.encodeWithSelector(DisputeGameFactory.initialize.selector, msg.sender)
);
DisputeGameFactory factory = DisputeGameFactory(address(factoryProxy));

// Setup starting anchor roots
GameType gameType = GameType.wrap(uint32(vm.envUint("GAME_TYPE")));

// Get or deploy SP1 verifier based on environment variable
address sp1VerifierAddress;
bool useMockVerifier = vm.envOr("USE_SP1_MOCK_VERIFIER", false);

if (useMockVerifier) {
// Deploy mock verifier for testing
SP1MockVerifier sp1Verifier = new SP1MockVerifier();
sp1VerifierAddress = address(sp1Verifier);
console.log("Using SP1 Mock Verifier:", address(sp1Verifier));
} else {
// Use provided verifier address for production
sp1VerifierAddress = vm.envAddress("SP1_VERIFIER_GATEWAY");
console.log("Using SP1 Verifier Gateway:", sp1VerifierAddress);
}

// Deploy game implementation
uint64 maxChallengeDuration = uint64(vm.envUint("MAX_CHALLENGE_DURATION"));
uint64 maxProveDuration = uint64(vm.envUint("MAX_PROVE_DURATION"));
bytes32 rollupConfigHash = bytes32(0);
bytes32 aggregationVkey = bytes32(0);
bytes32 rangeVkeyCommitment = bytes32(0);
uint256 genesisL2BlockNumber = uint256(vm.envUint("GENESIS_L2_BLOCK_NUMBER"));
bytes32 genesisL2OutputRoot = bytes32(vm.envBytes32("GENESIS_L2_OUTPUT_ROOT"));
uint256 proofReward = 0.01 ether;

OPSuccinctFaultDisputeGame gameImpl = new OPSuccinctFaultDisputeGame(
Duration.wrap(maxChallengeDuration),
Duration.wrap(maxProveDuration),
IDisputeGameFactory(address(factory)),
ISP1Verifier(sp1VerifierAddress),
rollupConfigHash,
aggregationVkey,
rangeVkeyCommitment,
genesisL2BlockNumber,
genesisL2OutputRoot,
proofReward
);

// Set initial bond and implementation in factory
factory.setInitBond(gameType, 0.01 ether);
factory.setImplementation(gameType, IDisputeGame(address(gameImpl)));

vm.stopBroadcast();

// Log deployed addresses
console.log("Factory Proxy:", address(factoryProxy));
console.log("Game Implementation:", address(gameImpl));
console.log("SP1 Verifier:", sp1VerifierAddress);
}
}
Loading