Spin up challenger

After you have spun up your sequencer, batcher, and proposer, the final step is to configure a challenger to monitor and respond to disputes. The challenger is the security component that ensures the integrity of your rollup by monitoring dispute games and responding to invalid claims.

Step 5 of 5: This tutorial is designed to be followed step-by-step. Each step builds on the previous one, and this is the last part of the tutorial.

This guide provides step-by-step instructions for setting up the configuration and monitoring options for op-challenger. The challenger is a critical fault proofs component that monitors dispute games and challenges invalid claims to protect your OP Stack chain.

See the OP-Challenger explainer for a general overview of this fault proofs feature.

The challenger is responsible for:

  • Monitoring dispute games created by the fault proof system
  • Challenging invalid claims in dispute games
  • Defending valid state transitions
  • Resolving games when possible

Prerequisites

Essential requirements

Before configuring your challenger, complete the following steps:

Deploy OP Stack chain with fault proofs enabled

Generate absolute prestate (Required)

The challenger needs the absolute prestate to participate in dispute games. Here's how to generate it:

  1. Clone and checkout the correct version:

    git clone https://github.com/ethereum-optimism/optimism.git
    cd optimism
    git checkout op-program/v1.6.1  # Use the latest stable version
    git submodule update --init --recursive
  2. Copy your chain configuration:

    # Assuming you're in rollup/challenger/optimism directory
    # Replace <YOUR-CHAIN-ID> with your actual L2 chain ID
    cp ../deployer/.deployer/rollup.json op-program/chainconfig/configs/<YOUR-CHAIN-ID>-rollup.json
    cp ../deployer/.deployer/genesis.json op-program/chainconfig/configs/<YOUR-CHAIN-ID>-genesis.json
     
    # Your directory structure should look like:
    # rollup/
    # ├── deployer/
    # │   └── .deployer/
    # │       ├── rollup.json    # Source file
    # │       └── genesis.json   # Source file
    # └── optimism/             # You are here
    #     └── op-program/
    #         └── chainconfig/
    #             └── configs/
    #                 ├── <YOUR-CHAIN-ID>-rollup.json   # Destination
    #                 └── <YOUR-CHAIN-ID>-genesis.json  # Destination
  3. Generate the prestate:

    make reproducible-prestate

    You'll see output like:

    -------------------- Production Prestates --------------------
    Cannon64 Absolute prestate hash: 
    0x03eb07101fbdeaf3f04d9fb76526362c1eea2824e4c6e970bdb19675b72e4fc8
  4. Prepare the preimage file:

    cd op-program/bin
    mv prestate-mt64.bin.gz 0x[CANNON64_PRESTATE_HASH].bin.gz

    Replace [CANNON64_PRESTATE_HASH] with the actual hash from step 3.

  • Use the Cannon64 hash for production
  • Keep this file accessible - you'll need it for the challenger setup
  • For Superchain registry chains, you can find official prestates in the registry (opens in a new tab)

Set up required infrastructure access

  • L1 RPC endpoint (Ethereum, Sepolia, etc.)
  • L1 Beacon node endpoint (for blob access)

Prepare configuration files

  • prestate.json - The absolute prestate file generated in step 1
  • rollup.json - Rollup configuration file from the op-deployer guide

Software installation

For challenger deployment, we recommend using Docker as it provides a consistent and isolated environment. Building from source is also available for more advanced users.

Docker Setup

The Docker setup provides a containerized environment for running the challenger. This method uses the official Docker image that includes embedded op-program server and Cannon executable.

Create challenger directory

# Create your challenger directory inside rollup
cd ../    # Go back to rollup directory if you're in proposer
mkdir challenger
cd challenger

Create environment file

First, create a .env file with your configuration values. This file will be used by Docker Compose to set up the environment variables:

# Create .env file with your actual values
cat > .env << 'EOF'
# L1 Configuration - Replace with your actual RPC URLs
L1_RPC_URL=https://sepolia.infura.io/v3/YOUR_ACTUAL_INFURA_KEY
L1_BEACON=https://ethereum-sepolia-beacon-api.publicnode.com
 
# L2 Configuration - Replace with your actual node endpoints  
L2_RPC_URL=http://op-geth:8545
ROLLUP_RPC_URL=http://op-node:8547
 
# Private key - Replace with your actual private key
PRIVATE_KEY=YOUR_ACTUAL_PRIVATE_KEY
 
# Network configuration
NETWORK=op-sepolia
GAME_FACTORY_ADDRESS=YOUR_GAME_FACTORY_ADDRESS
 
# Prestate configuration - Replace with the hash from 'make reproducible-prestate'
PRESTATE_HASH=YOUR_PRESTATE_HASH
EOF

Important: Replace ALL placeholder values (YOUR_ACTUAL_*) with your real configuration values.

Set up Docker Compose

Create a docker-compose.yml file that defines the challenger service. The file mounts several important files:

  • prestate-proof-mt64.json and ${PRESTATE_HASH}.bin.gz: Prestate files required for dispute games (the PRESTATE_HASH comes from running make reproducible-prestate), replace PRESTATE_HASH with the actual hash
 
services:
  challenger:
    image: us-docker.pkg.dev/oplabs-tools-artifacts/images/op-challenger:v1.5.0
    user: "1000"
    volumes:
      - ./challenger-data:/data
      - ./rollup.json:/workspace/rollup.json:ro
      - ./genesis-l2.json:/workspace/genesis-l2.json:ro
      - ./prestate-proof-mt64.json:/workspace/prestate-proof.json:ro
      - ./${PRESTATE_HASH}.bin.gz:/workspace/${PRESTATE_HASH}.bin.gz:ro
    environment:
      - L1_RPC_URL=${L1_RPC_URL}
      - L1_BEACON=${L1_BEACON}
      - L2_RPC_URL=${L2_RPC_URL}
      - ROLLUP_RPC_URL=${ROLLUP_RPC_URL}
      - PRIVATE_KEY=${PRIVATE_KEY}
      - NETWORK=${NETWORK}
      - GAME_FACTORY_ADDRESS=${GAME_FACTORY_ADDRESS}
    command:
      - "op-challenger"
      - "--trace-type=cannon,asterisc-kona"
      - "--l1-eth-rpc=${L1_RPC_URL}"
      - "--l1-beacon=${L1_BEACON}"
      - "--l2-eth-rpc=${L2_RPC_URL}"
      - "--rollup-rpc=${ROLLUP_RPC_URL}"
      - "--selective-claim-resolution"
      - "--private-key=${PRIVATE_KEY}"
      - "--game-factory-address=${GAME_FACTORY_ADDRESS}"
      - "--datadir=/data"
      - "--cannon-prestate=/workspace/prestate-proof.json"
      - "--cannon-bin=/workspace/${PRESTATE_HASH}.bin.gz"
      - "--asterisc-kona-prestate=/workspace/prestate-proof.json"
    restart: unless-stopped
    networks:
      - sequencer-node_default
 
networks:
  sequencer-node_default:
    external: false
 
 

Launch the challenger

Start the challenger service and monitor its logs:

# Start the challenger service
docker-compose up -d
 
# View logs
docker-compose logs -f challenger

Monitoring with op-dispute-mon

Consider running op-dispute-mon for enhanced security monitoring:

  • Provides visibility into all game statuses for the last 28 days
  • Essential for production challenger deployments
  • Create Grafana dashboards using: Download the Dispute Monitor JSON

Congratulations

You've successfully completed the entire L2 rollup testnet tutorial! Your rollup is now fully operational with all components running:

  • op-deployer - L1 contracts deployed
  • Sequencer - Processing transactions
  • Batcher - Publishing data to L1
  • Proposer - Submitting state roots
  • Challenger - Monitoring disputes

Connect your wallet to your chain

You now have a fully functioning OP Stack Rollup with a Sequencer node running on http://localhost:8545. You can connect your wallet to this chain the same way you'd connect your wallet to any other EVM chain.

Get ETH on your chain

Once you've connected your wallet, you'll probably notice that you don't have any ETH to pay for gas on your chain.

The easiest way to deposit Sepolia ETH into your chain is to send ETH directly to the L1StandardBridge contract.

Get the L1StandardBridge address

The L1StandardBridge proxy address can be found in your deployment state file. To get it, run:

# From your project root
jq -r .l1StandardBridgeProxyAddress <PATH_TO_YOUR_OP_DEPLOYER_FOLDER>/.deployer/state.json

This will output the L1StandardBridge proxy address that you should use for deposits. Make sure to use the proxy address, not the implementation address.

Deposit ETH to your L2

Once you have the L1StandardBridge address, send a small amount of Sepolia ETH (0.1 or less) to that address from the wallet you want to use on L2. This will trigger a deposit that will mint ETH into your wallet on L2.

It may take up to 5 minutes for the ETH to appear in your wallet on L2. This delay is due to the time needed for the deposit transaction to be processed and finalized.

See your rollup in action

You can interact with your Rollup the same way you'd interact with any other EVM chain. Send some transactions, deploy some contracts, and see what happens!

Need Help?