diff --git a/create-l2-rollup-example/.example.env b/create-l2-rollup-example/.example.env new file mode 100644 index 000000000..75a31144b --- /dev/null +++ b/create-l2-rollup-example/.example.env @@ -0,0 +1,62 @@ +# OP Stack L2 Rollup Environment Configuration +# Copy this file to .env and fill in your actual values +# This uses direnv for automatic environment loading + +# ========================================== +# REQUIRED: L1 Configuration (Sepolia testnet) +# ========================================== +# Option 1: Public endpoint (no API key required - recommended for testing) +L1_RPC_URL="https://ethereum-sepolia-rpc.publicnode.com" +L1_BEACON_URL="https://ethereum-sepolia-beacon-api.publicnode.com" + +# Option 2: Private endpoint (requires API key from Infura/Alchemy) +# L1_RPC_URL="https://eth-sepolia.g.alchemy.com/v2/YOUR_API_KEY" +# L1_BEACON_URL="https://ethereum-sepolia-beacon-api.publicnode.com" + +# ========================================== +# REQUIRED: Private Key for Deployment & Operations +# ========================================== +# IMPORTANT: Never commit this to version control! +# Get this from your MetaMask or other self-custody wallet +# Remove the 0x prefix if present +PRIVATE_KEY="YOUR_PRIVATE_KEY_WITHOUT_0X_PREFIX" + +# ========================================== +# OPTIONAL: Public IP for P2P Networking +# ========================================== +# For local testing, defaults to 127.0.0.1 +# For production/testnet, run `curl ifconfig.me` to get your public IP +P2P_ADVERTISE_IP="127.0.0.1" + +# ========================================== +# OPTIONAL: Custom Configuration +# ========================================== +# Default L2 Chain ID (can be any number between 10000-99999 for testing) +L2_CHAIN_ID="16584" + +# L1 Beacon API URL for op-node (usually same provider as L1_RPC_URL) +L1_BEACON_URL="https://ethereum-sepolia-beacon-api.publicnode.com" + +# ========================================== +# ADVANCED: Component Environment Variables +# ========================================== +# These follow OP Stack conventions and can be overridden in the main .env file +# The setup script creates service-specific .env files with these OP_* prefixed variables + +# Batcher Environment Variables +OP_BATCHER_POLL_INTERVAL="1s" +OP_BATCHER_SUB_SAFETY_MARGIN="6" +OP_BATCHER_NUM_CONFIRMATIONS="1" +OP_BATCHER_SAFE_ABORT_NONCE_TOO_LOW_COUNT="3" + +# Proposer Environment Variables +OP_PROPOSER_PROPOSAL_INTERVAL="3600s" +OP_PROPOSER_GAME_TYPE="0" +OP_PROPOSER_POLL_INTERVAL="20s" + +# ========================================== +# DEVELOPMENT: Local Network (Alternative to Sepolia) +# ========================================== +# Uncomment these for local development with a local L1 network +# L1_RPC_URL="http://host.docker.internal:8545" +# L1_BEACON_URL="http://host.docker.internal:5052" \ No newline at end of file diff --git a/create-l2-rollup-example/.gitignore b/create-l2-rollup-example/.gitignore new file mode 100644 index 000000000..b82e9ff7a --- /dev/null +++ b/create-l2-rollup-example/.gitignore @@ -0,0 +1,45 @@ +# Environment files +.env +.env.local +**/.env + +# Deployment artifacts +deployer/ + +# Generated service directories +sequencer/ +batcher/ +proposer/ +challenger/ + +# Optimism monorepo +optimism/ + +# Downloaded binaries +op-deployer + +# Logs +*.log +logs/ + +# OS generated files +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +ehthumbs.db +Thumbs.db + +# IDE files +.vscode/ +.idea/ +*.swp +*.swo + +# Node modules (if any) +node_modules/ + +# Temporary files +tmp/ +temp/ diff --git a/create-l2-rollup-example/Makefile b/create-l2-rollup-example/Makefile new file mode 100644 index 000000000..c74670370 --- /dev/null +++ b/create-l2-rollup-example/Makefile @@ -0,0 +1,89 @@ +# OP Stack L2 Rollup Makefile + +.PHONY: help setup up down logs clean reset + +# Default target +help: ## Show this help message + @echo "OP Stack L2 Rollup Management Commands:" + @grep -E '^[a-zA-Z0-9_-]+:.*?## .*' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}' + +setup: ## Deploy L1 contracts and configure rollup components + mkdir -p deployer + @if [ ! -f op-deployer ]; then \ + echo "❌ Error: op-deployer not found. Run 'make download' first."; \ + exit 1; \ + fi + @if [ ! -f .env ]; then \ + echo "❌ Error: .env file not found. Copy .example.env to .env and configure it."; \ + exit 1; \ + fi + @echo "Running setup script..." + @./scripts/setup-rollup.sh + +up: ## Start all services + docker-compose up -d --wait + @make test-l2 + +down: ## Stop all services + docker-compose down + +logs: ## View logs from all services + docker-compose logs -f + +logs-%: ## View logs from a specific service (e.g., make logs-sequencer) + docker-compose logs -f $* + +status: ## Show status of all services + docker-compose ps + +restart: ## Restart all services + docker-compose restart + +restart-%: ## Restart a specific service (e.g., make restart-batcher) + docker-compose restart $* + +clean: ## Remove all containers and volumes + @# Create minimal env files if they don't exist to avoid docker-compose errors + @mkdir -p batcher proposer challenger sequencer + @echo "# Minimal env for cleanup" > batcher/.env 2>/dev/null || true + @echo "# Minimal env for cleanup" > proposer/.env 2>/dev/null || true + @echo "# Minimal env for cleanup" > challenger/.env 2>/dev/null || true + docker-compose down -v --remove-orphans 2>/dev/null || true + +reset: ## Complete reset - removes all data and redeploys + @echo "This will completely reset your L2 rollup deployment!" + @read -p "Are you sure? (y/N) " confirm && [ "$$confirm" = "y" ] || exit 1 + make clean + rm -rf deployer sequencer batcher proposer challenger + @echo "Reset complete. Run 'make setup' to redeploy." + +test-l2: ## Test L2 connectivity + @echo "Testing L2 RPC connection..." + @curl -s -X POST -H "Content-Type: application/json" \ + --data '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' \ + http://localhost:8545 | jq -r '.result' 2>/dev/null && echo "✅ L2 connection successful" || echo "❌ L2 connection failed" + +test-l1: ## Test L1 connectivity + @echo "Testing L1 RPC connection..." + @if [ -f .env ]; then \ + set -a; source .env; set +a; \ + fi; \ + curl -s -X POST -H "Content-Type: application/json" \ + --data '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' \ + "$$L1_RPC_URL" | jq -r '.result' 2>/dev/null && echo "✅ L1 connection successful" || echo "❌ L1 connection failed" + +deps: ## Install development dependencies with mise (optional) + mise install + +download: ## Download op-deployer binary + ./scripts/download-op-deployer.sh + +init: ## Initialize the project + ./scripts/download-op-deployer.sh + @if [ ! -f .env ]; then \ + cp .example.env .env; \ + echo "Please edit .env with your actual configuration values"; \ + else \ + echo ".env already exists, skipping copy"; \ + fi + @echo "Then run: make setup" diff --git a/create-l2-rollup-example/README.md b/create-l2-rollup-example/README.md new file mode 100644 index 000000000..5d3c60f84 --- /dev/null +++ b/create-l2-rollup-example/README.md @@ -0,0 +1,215 @@ +# Create L2 Rollup - Code Example + +This directory contains the complete working implementation that accompanies the [Create L2 Rollup tutorial](/operators/chain-operators/tutorials/create-l2-rollup). It provides automated deployment of an OP Stack L2 rollup testnet using official published Docker images. + +## Overview + +This implementation deploys a fully functional OP Stack L2 rollup testnet, including: + +- **L1 Smart Contracts** deployed on Sepolia testnet (via op-deployer) +- **Execution Client** (op-geth) processing transactions +- **Consensus Client** (op-node) managing rollup consensus +- **Batcher** (op-batcher) publishing transaction data to L1 +- **Proposer** (op-proposer) submitting state root proposals +- **Challenger** (op-challenger) monitoring for disputes + +## Prerequisites + +### Software Dependencies + +| Dependency | Version | Install Command | Purpose | +|------------|---------|-----------------|---------| +| [Docker](https://docs.docker.com/get-docker/) | ^24 | Follow Docker installation guide | Container runtime for OP Stack services | +| [Docker Compose](https://docs.docker.com/compose/install/) | latest | Usually included with Docker Desktop | Multi-container orchestration | +| [jq](https://github.com/jqlang/jq) | latest | `brew install jq` (macOS) / `apt install jq` (Ubuntu) | JSON processing for deployment data | +| [git](https://git-scm.com/) | latest | Usually pre-installed | Cloning repositories for prestate generation | + +### Recommended: Tool Management + +For the best experience with correct tool versions, we recommend installing [mise](https://mise.jdx.dev/): + +```bash +# Install mise (manages all tool versions automatically) +curl https://mise.jdx.dev/install.sh | bash + +# Install all required tools with correct versions +cd docs/create-l2-rollup-example +mise install +``` + +**Why mise?** It automatically handles tool installation and version management, preventing compatibility issues. + +### Network Access + +- **Sepolia RPC URL**: Get from [Infura](https://infura.io), [Alchemy](https://alchemy.com), or another provider +- **Sepolia ETH**: At least 2-3 ETH for contract deployment and operations +- **Public IP**: For P2P networking (use `curl ifconfig.me` to find your public IP) + +## Quick Start + +1. **Navigate to this code directory**: + ```bash + cd docs/pages/operators/chain-operators/tutorials/create-l2-rollup/code + ``` + +2. **Configure environment variables**: + ```bash + cp .example.env .env + # Edit .env with your actual values (L1_RPC_URL, PRIVATE_KEY, L2_CHAIN_ID) + ``` + +3. **Download op-deployer**: + ```bash + make init # Download op-deployer + ``` + +4. **Deploy and start everything**: + ```bash + make setup # Deploy contracts and configure all services + make up # Start all services + ``` + +5. **Verify deployment**: + ```bash + make status # Check service health + make test-l1 # Verify L1 connectivity + make test-l2 # Verify L2 functionality + + # Or manually check: + docker-compose ps + docker-compose logs -f op-node + ``` + +## Environment Configuration + +Copy `.example.env` to `.env` and configure the following variables: + +```bash +# L1 Configuration (Sepolia testnet) +# Option 1: Public endpoint (no API key required) +L1_RPC_URL="https://ethereum-sepolia-rpc.publicnode.com" +L1_BEACON_URL="https://ethereum-sepolia-beacon-api.publicnode.com" + +# Option 2: Private endpoint (requires API key) +# L1_RPC_URL="https://eth-sepolia.g.alchemy.com/v2/YOUR_API_KEY" +# L1_BEACON_URL="https://ethereum-sepolia-beacon-api.publicnode.com" + +# Private key for deployment and operations +# IMPORTANT: Never commit this to version control +PRIVATE_KEY="YOUR_PRIVATE_KEY_WITHOUT_0x_PREFIX" + +# Optional: Public IP for P2P networking (defaults to 127.0.0.1 for local testing) +P2P_ADVERTISE_IP="127.0.0.1" + +# Optional: Custom L2 Chain ID (default: 16584) +L2_CHAIN_ID="16584" +``` + +The `.env` file will be automatically loaded by Docker Compose. + +## Manual Setup (Alternative) + +For detailed manual setup instructions, see the [Create L2 Rollup tutorial](/operators/chain-operators/tutorials/create-l2-rollup). The tutorial provides step-by-step guidance for setting up each component individually if you prefer not to use the automated approach. + +## Directory Structure + +``` +code/ +├── .example.env # Environment variables template +├── docker-compose.yml # Service orchestration +├── Makefile # Automation commands +├── scripts/ +│ ├── setup-rollup.sh # Automated deployment script +│ └── download-op-deployer.sh # op-deployer downloader +└── README.md # This file +``` + +**Generated directories** (created during deployment): +``` +deployer/ # op-deployer configuration and outputs +├── .deployer/ # Deployment artifacts (genesis.json, rollup.json, etc.) +├── addresses/ # Generated wallet addresses +└── .env # Environment variables +batcher/ # op-batcher configuration +├── .env # Batcher-specific environment variables +proposer/ # op-proposer configuration +├── .env # Proposer-specific environment variables +challenger/ # op-challenger configuration +├── .env # Challenger-specific environment variables +└── data/ # Challenger data directory +``` + +## Service Ports + +| Service | Port | Description | +|---------|------|-------------| +| op-geth | 8545 | HTTP RPC endpoint | +| op-geth | 8546 | WebSocket RPC endpoint | +| op-geth | 8551 | Auth RPC for op-node | +| op-node | 8547 | op-node RPC endpoint | +| op-node | 9222 | P2P networking | + +## Monitoring and Logs + +```bash +# View all service logs +make logs + +# View specific service logs +docker-compose logs -f op-node +docker-compose logs -f op-geth + +# Check service health +make status + +# Restart all services +make restart + +# Restart a specific service +docker-compose restart op-batcher +``` + +## Troubleshooting + +### Common Issues + +1. **Port conflicts**: Ensure ports 8545-8551 and 9222 are available +2. **Insufficient ETH**: Make sure your deployment wallet has enough Sepolia ETH +3. **Network timeouts**: Check your L1 RPC URL and network connectivity +4. **Docker issues**: Ensure Docker daemon is running and you have sufficient resources + +### Reset Deployment + +To reset and redeploy: + +```bash +# Stop all services and clean up +make clean + +# Re-run setup +make setup +make up +``` + +## Security Notes + +- **Never commit private keys** to version control +- **Use hardware security modules (HSMs)** for production deployments +- **Monitor gas costs** on Sepolia testnet +- **Backup wallet addresses** and deployment artifacts + +## About This Code + +This code example accompanies the [Create L2 Rollup tutorial](/operators/chain-operators/tutorials/create-l2-rollup) in the Optimism documentation. It provides a complete, working implementation that demonstrates the concepts covered in the tutorial. + +## Contributing + +This code is part of the Optimism documentation. For issues or contributions: + +- **Documentation issues**: Report on the main [Optimism repository](https://github.com/ethereum-optimism/optimism) +- **Code improvements**: Submit pull requests to the Optimism monorepo +- **Tutorial feedback**: Use the documentation feedback mechanisms + +## License + +This code is provided as-is for educational and testing purposes. See the Optimism monorepo for licensing information. diff --git a/create-l2-rollup-example/docker-compose.yml b/create-l2-rollup-example/docker-compose.yml new file mode 100644 index 000000000..edb43c96a --- /dev/null +++ b/create-l2-rollup-example/docker-compose.yml @@ -0,0 +1,153 @@ +services: + # Sequencer (op-geth + op-node) + op-node: + image: us-docker.pkg.dev/oplabs-tools-artifacts/images/op-node:v1.13.5 + container_name: op-node + volumes: + - ./sequencer:/workspace + - op_geth_data:/workspace/op-geth-data + working_dir: /workspace + env_file: + - .env + ports: + - "8547:8547" + - "9222:9222" + command: > + op-node + --l1=${L1_RPC_URL} + --l1.beacon=${L1_BEACON_URL} + --l2=http://op-geth:8551 + --l2.jwt-secret=/workspace/jwt.txt + --rollup.config=/workspace/rollup.json + --sequencer.enabled=true + --sequencer.stopped=false + --sequencer.max-safe-lag=3600 + --verifier.l1-confs=4 + --p2p.listen.ip=0.0.0.0 + --p2p.listen.tcp=9222 + --p2p.listen.udp=9222 + --p2p.advertise.ip=${P2P_ADVERTISE_IP} + --p2p.advertise.tcp=9222 + --p2p.advertise.udp=9222 + --p2p.sequencer.key=${PRIVATE_KEY} + --rpc.addr=0.0.0.0 + --rpc.port=8547 + --rpc.enable-admin + --log.level=info + --log.format=json + depends_on: + - op-geth + healthcheck: + test: ["CMD", "wget", "--post-data={\"jsonrpc\":\"2.0\",\"method\":\"opp2p_self\",\"params\":[],\"id\":1}", "--header=Content-Type: application/json", "--quiet", "--tries=1", "--timeout=10", "--output-document=-", "http://localhost:8547"] + interval: 30s + timeout: 10s + retries: 5 + start_period: 10s + + op-geth: + image: us-docker.pkg.dev/oplabs-tools-artifacts/images/op-geth:v1.101511.1 + container_name: op-geth + volumes: + - ./sequencer:/workspace + - op_geth_data:/workspace/op-geth-data + working_dir: /workspace + env_file: + - .env + ports: + - "8545:8545" + - "8546:8546" + - "8551:8551" + entrypoint: ["/bin/sh", "-c"] + command: + - | + set -e + if [ ! -d /workspace/op-geth-data/geth/chaindata ]; then + echo "Initializing geth datadir..." + geth init --datadir=/workspace/op-geth-data --state.scheme=hash /workspace/genesis.json + fi + echo "Starting geth..." + exec geth --datadir=/workspace/op-geth-data --http --http.addr=0.0.0.0 --http.port=8545 --ws --ws.addr=0.0.0.0 --ws.port=8546 --authrpc.addr=0.0.0.0 --authrpc.port=8551 --authrpc.jwtsecret=/workspace/jwt.txt --syncmode=full --gcmode=archive --rollup.disabletxpoolgossip=true --rollup.sequencerhttp=http://op-node:8547 --http.vhosts=* --http.corsdomain=* --http.api=eth,net,web3,debug,txpool,admin --ws.origins=* --ws.api=eth,net,web3,debug,txpool,admin --authrpc.vhosts=* + + + # Batcher + batcher: + image: us-docker.pkg.dev/oplabs-tools-artifacts/images/op-batcher:v1.14.0 + container_name: op-batcher + volumes: + - ./batcher:/workspace + working_dir: /workspace + env_file: + - ./batcher/.env + - .env + environment: + - OP_BATCHER_L1_ETH_RPC=${L1_RPC_URL} + - OP_BATCHER_PRIVATE_KEY=${PRIVATE_KEY} + command: > + op-batcher + --rpc.addr=0.0.0.0 + --rpc.port=8548 + --rpc.enable-admin + --max-channel-duration=1 + --data-availability-type=calldata + --resubmission-timeout=30s + --log.level=info + --log.format=json + depends_on: + op-node: + condition: service_healthy + + # Proposer + proposer: + image: us-docker.pkg.dev/oplabs-tools-artifacts/images/op-proposer:v1.10.0 + container_name: op-proposer + volumes: + - ./proposer:/workspace + working_dir: /workspace + env_file: + - ./proposer/.env + - .env + environment: + - OP_PROPOSER_L1_ETH_RPC=${L1_RPC_URL} + - OP_PROPOSER_PRIVATE_KEY=${PRIVATE_KEY} + command: > + op-proposer + --rpc.port=8560 + --rollup-rpc=http://op-node:8547 + --allow-non-finalized=true + --wait-node-sync=true + --log.level=info + --log.format=json + depends_on: + op-node: + condition: service_healthy + + # Challenger + challenger: + image: us-docker.pkg.dev/oplabs-tools-artifacts/images/op-challenger:v1.5.1 + container_name: op-challenger + volumes: + - ./challenger:/workspace + working_dir: /workspace + env_file: + - ./challenger/.env + - .env + environment: + - OP_CHALLENGER_L1_ETH_RPC=${L1_RPC_URL} + - OP_CHALLENGER_L1_BEACON=${L1_BEACON_URL} + - OP_CHALLENGER_PRIVATE_KEY=${PRIVATE_KEY} + command: > + op-challenger run-trace + --trace-type=cannon + --cannon-l2-genesis=/workspace/genesis.json + --cannon-rollup-config=/workspace/rollup.json + --l2-eth-rpc=http://op-geth:8545 + --rollup-rpc=http://op-node:8547 + --datadir=/workspace/data + --log.level=info + --log.format=json + depends_on: + op-node: + condition: service_healthy + +volumes: + op_geth_data: diff --git a/create-l2-rollup-example/mise.toml b/create-l2-rollup-example/mise.toml new file mode 100644 index 000000000..d22bdca6e --- /dev/null +++ b/create-l2-rollup-example/mise.toml @@ -0,0 +1,8 @@ +[tools] +"jq" = "latest" +"git" = "latest" +"docker" = "latest" +"foundry" = "latest" + +[settings] +experimental = true diff --git a/create-l2-rollup-example/scripts/download-op-deployer.sh b/create-l2-rollup-example/scripts/download-op-deployer.sh new file mode 100755 index 000000000..c49a7540c --- /dev/null +++ b/create-l2-rollup-example/scripts/download-op-deployer.sh @@ -0,0 +1,251 @@ +#!/bin/bash + +# Download op-deployer pre-built binary +# Based on the tutorial instructions + +set -e + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +log_info() { + echo -e "${BLUE}[INFO]${NC} $1" +} + +log_success() { + echo -e "${GREEN}[SUCCESS]${NC} $1" +} + +log_warning() { + echo -e "${YELLOW}[WARNING]${NC} $1" +} + +log_error() { + echo -e "${RED}[ERROR]${NC} $1" +} + +# Detect platform +detect_platform() { + case "$(uname -s)" in + Darwin) + case "$(uname -m)" in + arm64) + echo "darwin-arm64" + ;; + x86_64) + echo "darwin-amd64" + ;; + *) + log_error "Unsupported macOS architecture: $(uname -m)" + exit 1 + ;; + esac + ;; + Linux) + echo "linux-amd64" + ;; + *) + log_error "Unsupported platform: $(uname -s)" + exit 1 + ;; + esac +} + +# Download op-deployer +download_op_deployer() { + # Detect host platform + local os + local arch + case "$(uname -s)" in + Darwin) + os="darwin" + ;; + Linux) + os="linux" + ;; + *) + log_error "Unsupported OS: $(uname -s)" + exit 1 + ;; + esac + + case "$(uname -m)" in + aarch64|arm64) + arch="arm64" + ;; + x86_64|amd64) + arch="amd64" + ;; + *) + log_error "Unsupported architecture: $(uname -m)" + exit 1 + ;; + esac + local platform="$os-$arch" + local releases_url="https://api.github.com/repos/ethereum-optimism/optimism/releases" + + log_info "Detecting platform: $platform" + + # Find the latest op-deployer release + log_info "Finding latest op-deployer release..." + + # Get all releases and find the latest one with op-deployer assets + local latest_deployer_release + latest_deployer_release=$(curl -s "$releases_url?per_page=50" | jq -r '.[] | select(.tag_name | startswith("op-deployer/")) | .tag_name' | sort -V | tail -1) + + if [ -z "$latest_deployer_release" ]; then + log_error "Could not find any op-deployer releases" + exit 1 + fi + + local tag_name="$latest_deployer_release" + log_info "Found latest op-deployer release: $tag_name" + + # Get the release info + local release_info + release_info=$(curl -s "$releases_url/tags/$tag_name") + + if [ -z "$release_info" ] || [ "$release_info" = "null" ] || echo "$release_info" | jq -e '.message' >/dev/null 2>&1; then + log_error "Could not fetch release information for $tag_name" + exit 1 + fi + + local has_deployer_assets + has_deployer_assets=$(echo "$release_info" | jq -r '.assets[] | select(.name | contains("op-deployer")) | .name' | wc -l) + + if [ "$has_deployer_assets" -eq 0 ]; then + log_error "Release $tag_name does not have op-deployer assets" + exit 1 + fi + + log_info "Release $tag_name has op-deployer assets" + + # Check if this release has op-deployer assets for our platform + local asset_name + asset_name=$(echo "$release_info" | jq -r ".assets[] | select(.name | contains(\"op-deployer\") and contains(\"$platform\")) | .name") + + # If arm64 is not available, fall back to amd64 (Rosetta compatibility) + if [ -z "$asset_name" ] && [ "$platform" = "linux-arm64" ]; then + log_info "linux-arm64 not available, trying linux-amd64 (Rosetta compatible)" + platform="linux-amd64" + asset_name=$(echo "$release_info" | jq -r ".assets[] | select(.name | contains(\"op-deployer\") and contains(\"$platform\")) | .name") + fi + + if [ -z "$asset_name" ]; then + log_error "Could not find op-deployer asset for platform $platform in release $tag_name" + log_info "Available op-deployer assets in this release:" + echo "$release_info" | jq -r '.assets[] | select(.name | contains("op-deployer")) | .name' + log_info "Please check: https://github.com/ethereum-optimism/optimism/releases/tag/$tag_name" + exit 1 + fi + + local download_url="https://github.com/ethereum-optimism/optimism/releases/download/$tag_name/$asset_name" + + log_info "Downloading op-deployer $tag_name for $platform..." + log_info "From: $download_url" + + # Download the asset + if ! curl -L -o "op-deployer.tar.gz" "$download_url"; then + log_error "Failed to download op-deployer" + exit 1 + fi + + # Extract (assuming it's a tar.gz) + log_info "Extracting op-deployer..." + tar -xzf op-deployer.tar.gz + + # Find the binary (it might be in a subdirectory) + local binary_path + + # Look for the extracted directory first + local extracted_dir + extracted_dir=$(find . -name "op-deployer-*" -type d | head -1) + + if [ -n "$extracted_dir" ] && [ -f "$extracted_dir/op-deployer" ]; then + binary_path="$extracted_dir/op-deployer" + elif [ -f "op-deployer" ]; then + binary_path="op-deployer" + elif [ -f "op-deployer-$platform" ]; then + binary_path="op-deployer-$platform" + else + # Look for it anywhere (macOS compatible) + binary_path=$(find . -name "op-deployer*" -type f -perm +111 | head -1) + fi + + if [ -z "$binary_path" ]; then + log_error "Could not find op-deployer binary in extracted files" + ls -la + exit 1 + fi + + # Make executable and move to current directory + chmod +x "$binary_path" + mv "$binary_path" ./op-deployer + + # Cleanup + rm -f op-deployer.tar.gz + rm -rf "${binary_path%/*}" 2>/dev/null || true + + # Test the binary (only if we're downloading for the same platform) + local current_platform=$(detect_platform) + if [ "$platform" = "$current_platform" ]; then + if ! ./op-deployer --version >/dev/null 2>&1; then + log_error "Downloaded op-deployer binary appears to be invalid" + exit 1 + fi + log_success "op-deployer downloaded and ready: $(./op-deployer --version)" + else + # Cross-platform download - just verify the file exists and is executable + if [ ! -x "./op-deployer" ]; then + log_error "Downloaded op-deployer binary is not executable" + exit 1 + fi + log_success "op-deployer downloaded for $platform platform (cannot test on $current_platform host)" + fi +} + +# Alternative: Manual download instructions +show_manual_instructions() { + log_warning "Automatic download failed. Please download manually:" + echo "" + echo "1. Go to: https://github.com/ethereum-optimism/optimism/releases" + echo "2. Find the latest release that includes op-deployer" + echo "3. Download the appropriate binary for your system:" + echo " - Linux: op-deployer-linux-amd64" + echo " - macOS Intel: op-deployer-darwin-amd64" + echo " - macOS Apple Silicon: op-deployer-darwin-arm64" + echo "4. Extract and place the binary as './op-deployer'" + echo "5. Run: chmod +x ./op-deployer" + echo "" + exit 1 +} + +# Main execution +main() { + log_info "Downloading op-deployer..." + + if ! command -v curl &> /dev/null; then + log_error "curl is required but not installed" + exit 1 + fi + + if ! command -v jq &> /dev/null; then + log_error "jq is required but not installed" + exit 1 + fi + + # Try automatic download + if download_op_deployer; then + log_success "op-deployer setup complete!" + exit 0 + else + show_manual_instructions + fi +} + +# Run main function +main "$@" diff --git a/create-l2-rollup-example/scripts/setup-rollup.sh b/create-l2-rollup-example/scripts/setup-rollup.sh new file mode 100755 index 000000000..efca586f2 --- /dev/null +++ b/create-l2-rollup-example/scripts/setup-rollup.sh @@ -0,0 +1,488 @@ +#!/bin/bash + +# OP Stack L2 Rollup Setup Script +# This script automates the deployment of a complete L2 rollup testnet + +set -e + +# Check if running in Docker +if [ -f "/.dockerenv" ]; then + log_error "This script should not be run inside Docker. Run it on the host system." + exit 1 +fi + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# Configuration +L1_CHAIN_ID=11155111 # Sepolia +L2_CHAIN_ID_DECIMAL=${L2_CHAIN_ID:-16584} # Default test chain ID (decimal) +L2_CHAIN_ID=$(printf "0x%064x" "$L2_CHAIN_ID_DECIMAL") # Convert to full 64-char hex format for TOML +P2P_ADVERTISE_IP=${P2P_ADVERTISE_IP:-127.0.0.1} # Default to localhost for local testing +WORKSPACE_DIR="$(pwd)" +ROLLUP_DIR="$WORKSPACE_DIR" +DEPLOYER_DIR="$ROLLUP_DIR/deployer" +SEQUENCER_DIR="$ROLLUP_DIR/sequencer" +BATCHER_DIR="$ROLLUP_DIR/batcher" +PROPOSER_DIR="$ROLLUP_DIR/proposer" +CHALLENGER_DIR="$ROLLUP_DIR/challenger" + +# Logging functions +log_info() { + echo -e "${BLUE}[INFO]${NC} $1" +} + +log_success() { + echo -e "${GREEN}[SUCCESS]${NC} $1" +} + +log_warning() { + echo -e "${YELLOW}[WARNING]${NC} $1" +} + +log_error() { + echo -e "${RED}[ERROR]${NC} $1" +} + +# Check prerequisites +check_prerequisites() { + log_info "Checking prerequisites..." + + if ! command -v op-deployer &> /dev/null; then + log_error "op-deployer not found. Please ensure it's downloaded" + log_info "Run: make download" + exit 1 + fi + + log_success "Prerequisites check passed" +} + +# Generate wallet addresses +generate_addresses() { + log_info "Generating wallet addresses..." + + mkdir -p "$DEPLOYER_DIR/addresses" + log_info "Created addresses directory: $DEPLOYER_DIR/addresses" + + cd "$DEPLOYER_DIR/addresses" + log_info "Changed to directory: $(pwd)" + + # Generate addresses for different roles using openssl + for role in admin base_fee_vault_recipient l1_fee_vault_recipient sequencer_fee_vault_recipient system_config unsafe_block_signer batcher proposer challenger; do + # Generate a random 32-byte private key, ensuring it's not zero + private_key="" + while [ -z "$private_key" ] || [ "$private_key" = "0000000000000000000000000000000000000000000000000000000000000000" ]; do + private_key=$(openssl rand -hex 32) + done + + # For this demo, we'll create a fake but valid Ethereum address + # In a real scenario, you'd derive the actual Ethereum address from the private key + # Create a 40-character hex address (20 bytes) + address="0x$(echo "$private_key" | head -c 40)" + echo "$address" > "${role}_address.txt" + log_info "Created wallet for $role: $address" + done + + log_success "Wallet addresses generated" + log_info "Addresses generated successfully, continuing to init..." +} + +# Initialize op-deployer +init_deployer() { + log_info "Initializing op-deployer..." + + cd "$DEPLOYER_DIR" + + # Create .env file + cat > .env << EOF +L1_RPC_URL=$L1_RPC_URL +PRIVATE_KEY=$PRIVATE_KEY +EOF + + # Remove any existing .deployer directory for clean state + rm -rf .deployer + + # Initialize intent + op-deployer init \ + --l1-chain-id $L1_CHAIN_ID \ + --l2-chain-ids "$L2_CHAIN_ID_DECIMAL" \ + --workdir .deployer \ + --intent-type standard-overrides + + log_success "op-deployer initialized" +} + +# Update intent configuration +update_intent() { + log_info "Updating intent configuration..." + + # Read generated addresses + BASE_FEE_VAULT_ADDR=$(cat addresses/base_fee_vault_recipient_address.txt) + L1_FEE_VAULT_ADDR=$(cat addresses/l1_fee_vault_recipient_address.txt) + SEQUENCER_FEE_VAULT_ADDR=$(cat addresses/sequencer_fee_vault_recipient_address.txt) + SYSTEM_CONFIG_ADDR=$(cat addresses/system_config_address.txt) + UNSAFE_BLOCK_SIGNER_ADDR=$(cat addresses/unsafe_block_signer_address.txt) + BATCHER_ADDR=$(cat addresses/batcher_address.txt) + PROPOSER_ADDR=$(cat addresses/proposer_address.txt) + CHALLENGER_ADDR=$(cat addresses/challenger_address.txt) + + # Keep the default contract locators and opcmAddress from op-deployer init + + # Update only the chain-specific fields in the existing intent.toml + L2_CHAIN_ID_HEX=$(printf "0x%064x" "$L2_CHAIN_ID") + sed -i.bak "s|id = .*|id = \"$L2_CHAIN_ID_HEX\"|" .deployer/intent.toml + sed -i.bak "s|baseFeeVaultRecipient = .*|baseFeeVaultRecipient = \"$BASE_FEE_VAULT_ADDR\"|" .deployer/intent.toml + sed -i.bak "s|l1FeeVaultRecipient = .*|l1FeeVaultRecipient = \"$L1_FEE_VAULT_ADDR\"|" .deployer/intent.toml + sed -i.bak "s|sequencerFeeVaultRecipient = .*|sequencerFeeVaultRecipient = \"$SEQUENCER_FEE_VAULT_ADDR\"|" .deployer/intent.toml + sed -i.bak "s|systemConfigOwner = .*|systemConfigOwner = \"$SYSTEM_CONFIG_ADDR\"|" .deployer/intent.toml + sed -i.bak "s|unsafeBlockSigner = .*|unsafeBlockSigner = \"$UNSAFE_BLOCK_SIGNER_ADDR\"|" .deployer/intent.toml + sed -i.bak "s|batcher = .*|batcher = \"$BATCHER_ADDR\"|" .deployer/intent.toml + sed -i.bak "s|proposer = .*|proposer = \"$PROPOSER_ADDR\"|" .deployer/intent.toml + sed -i.bak "s|challenger = .*|challenger = \"$CHALLENGER_ADDR\"|" .deployer/intent.toml + + log_success "Intent configuration updated" +} + +# Deploy L1 contracts +deploy_contracts() { + log_info "Deploying L1 contracts..." + + cd "$DEPLOYER_DIR" + + op-deployer apply \ + --workdir .deployer \ + --l1-rpc-url "$L1_RPC_URL" \ + --private-key "$PRIVATE_KEY" + + log_success "L1 contracts deployed" +} + +# Generate chain configuration +generate_config() { + log_info "Generating chain configuration..." + + cd "$DEPLOYER_DIR" + + op-deployer inspect genesis --workdir .deployer "$L2_CHAIN_ID" > .deployer/genesis.json + op-deployer inspect rollup --workdir .deployer "$L2_CHAIN_ID" > .deployer/rollup.json + + log_success "Chain configuration generated" +} + +# Setup sequencer +setup_sequencer() { + log_info "Setting up sequencer..." + + mkdir -p "$SEQUENCER_DIR" + cd "$SEQUENCER_DIR" + + # Copy configuration files + cp "$DEPLOYER_DIR/.deployer/genesis.json" . + cp "$DEPLOYER_DIR/.deployer/rollup.json" . + + # Generate JWT secret + openssl rand -hex 32 > jwt.txt + chmod 600 jwt.txt + + # Create .env file + cat > .env << EOF +L1_RPC_URL=$L1_RPC_URL +L1_BEACON_URL=$L1_BEACON_URL +PRIVATE_KEY=$PRIVATE_KEY +P2P_ADVERTISE_IP=$P2P_ADVERTISE_IP +L2_CHAIN_ID=$L2_CHAIN_ID +EOF + + log_success "Sequencer setup complete" +} + +# Setup batcher +setup_batcher() { + log_info "Setting up batcher..." + + mkdir -p "$BATCHER_DIR" + cd "$BATCHER_DIR" + + # Copy state file + cp "$DEPLOYER_DIR/.deployer/state.json" . + INBOX_ADDRESS=$(cat state.json | jq -r '.opChainDeployments[0].SystemConfigProxy') + + # Create .env file with OP_BATCHER prefixed variables + cat > .env << EOF +OP_BATCHER_L2_ETH_RPC=http://op-geth:8545 +OP_BATCHER_ROLLUP_RPC=http://op-node:8547 +OP_BATCHER_PRIVATE_KEY=$PRIVATE_KEY +OP_BATCHER_POLL_INTERVAL=1s +OP_BATCHER_SUB_SAFETY_MARGIN=6 +OP_BATCHER_NUM_CONFIRMATIONS=1 +OP_BATCHER_SAFE_ABORT_NONCE_TOO_LOW_COUNT=3 +OP_BATCHER_INBOX_ADDRESS=$INBOX_ADDRESS +EOF + + log_success "Batcher setup complete" +} + +# Setup proposer +setup_proposer() { + log_info "Setting up proposer..." + + mkdir -p "$PROPOSER_DIR" + cd "$PROPOSER_DIR" + + # Copy state file + cp "$DEPLOYER_DIR/.deployer/state.json" . + + # Extract dispute game factory address + GAME_FACTORY_ADDR=$(cat state.json | jq -r '.opChainDeployments[0].DisputeGameFactoryProxy') + + # Create .env file with OP_PROPOSER prefixed variables + cat > .env << EOF +OP_PROPOSER_GAME_FACTORY_ADDRESS=$GAME_FACTORY_ADDR +OP_PROPOSER_PRIVATE_KEY=$PRIVATE_KEY +OP_PROPOSER_POLL_INTERVAL=20s +OP_PROPOSER_GAME_TYPE=0 +OP_PROPOSER_PROPOSAL_INTERVAL=3600s +EOF + + log_success "Proposer setup complete" +} + +# Setup challenger +setup_challenger() { + log_info "Setting up challenger..." + + mkdir -p "$CHALLENGER_DIR" + cd "$CHALLENGER_DIR" + + # Copy configuration files + cp "$DEPLOYER_DIR/.deployer/genesis.json" . + cp "$DEPLOYER_DIR/.deployer/rollup.json" . + + # Extract dispute game factory address + GAME_FACTORY_ADDR=$(cat ../deployer/.deployer/state.json | jq -r '.opChainDeployments[0].DisputeGameFactoryProxy') + + # Check for existing prestate file + CHALLENGER_PRESTATE_FILE="" + if [ -d "$CHALLENGER_DIR" ]; then + # Look for any .bin.gz file in the challenger directory + EXISTING_PRESTATE=$(find "$CHALLENGER_DIR" -maxdepth 1 -name "*.bin.gz" -print -quit 2>/dev/null) + if [ -n "$EXISTING_PRESTATE" ]; then + CHALLENGER_PRESTATE_FILE=$(basename "$EXISTING_PRESTATE") + log_info "Found existing prestate file: $CHALLENGER_PRESTATE_FILE" + fi + fi + + # Ensure prestate file exists + if [ -z "$CHALLENGER_PRESTATE_FILE" ] || [ ! -f "$CHALLENGER_DIR/$CHALLENGER_PRESTATE_FILE" ]; then + log_error "Challenger prestate file not found in $CHALLENGER_DIR/" + log_error "Make sure generate_challenger_prestate runs before setup_challenger" + return 1 + fi + + # Create .env file with OP_CHALLENGER prefixed variables + cat > .env << EOF +OP_CHALLENGER_GAME_FACTORY_ADDRESS=$GAME_FACTORY_ADDR +OP_CHALLENGER_PRIVATE_KEY=$PRIVATE_KEY +OP_CHALLENGER_CANNON_PRESTATE=/workspace/$CHALLENGER_PRESTATE_FILE +EOF + + log_success "Challenger setup complete" +} + +# Validate main .env file for docker-compose +validate_main_env() { + log_info "Validating .env file..." + + # Load user-provided .env file + USER_ENV_FILE="$(dirname "$0")/../.env" + if [ ! -f "$USER_ENV_FILE" ]; then + log_error ".env file not found. Please run 'make init' first." + log_info "Run: make init" + return 1 + fi + + log_info "Loading .env file..." + set -a # automatically export all variables + source "$USER_ENV_FILE" + set +a + + # Validate required environment variables + if [ -z "$L1_RPC_URL" ]; then + log_error "L1_RPC_URL is not set. Please set it in your .env file." + log_info "Example: L1_RPC_URL=https://ethereum-sepolia-rpc.publicnode.com" + return 1 + fi + + if [ -z "$L1_BEACON_URL" ]; then + log_error "L1_BEACON_URL is not set. Please set it in your .env file." + log_info "Example: L1_BEACON_URL=https://ethereum-sepolia-beacon-api.publicnode.com" + return 1 + fi + + if [ -z "$PRIVATE_KEY" ]; then + log_error "PRIVATE_KEY is not set. Please set it in your .env file." + log_info "Example: PRIVATE_KEY=0x..." + return 1 + fi + + if [ -z "$L2_CHAIN_ID" ]; then + log_error "L2_CHAIN_ID is not set. Please set it in your .env file." + log_info "Example: L2_CHAIN_ID=16584" + return 1 + fi + + # Set defaults for optional values + P2P_ADVERTISE_IP=${P2P_ADVERTISE_IP:-127.0.0.1} + + log_success ".env file validated" +} + +# Generate challenger prestate +generate_challenger_prestate() { + log_info "Generating challenger prestate..." + + # Get the chain ID from the rollup config + if [ -f "$DEPLOYER_DIR/.deployer/rollup.json" ]; then + CHAIN_ID=$(jq -r '.l2_chain_id' "$DEPLOYER_DIR/.deployer/rollup.json") + else + log_error "Could not find rollup.json to determine chain ID" + return 1 + fi + + log_info "Chain ID for prestate generation: $CHAIN_ID" + + # Create optimism directory for prestate generation + OPTIMISM_DIR="$ROLLUP_DIR/optimism" + if [ ! -d "$OPTIMISM_DIR" ]; then + log_info "Cloning Optimism repository..." + git clone https://github.com/ethereum-optimism/optimism.git "$OPTIMISM_DIR" + cd "$OPTIMISM_DIR" + + # Find the latest op-program tag + log_info "Finding latest op-program version..." + OP_PROGRAM_TAG=$(git tag --list "op-program/v*" | sort -V | tail -1) + if [ -z "$OP_PROGRAM_TAG" ]; then + log_error "Could not find any op-program tags" + return 1 + fi + log_info "Using op-program version: $OP_PROGRAM_TAG" + + git checkout "$OP_PROGRAM_TAG" + git submodule update --init --recursive + else + log_info "Optimism repository already exists, checking configuration..." + cd "$OPTIMISM_DIR" + + # Check if we're on the correct op-program tag + CURRENT_TAG=$(git describe --tags --exact-match 2>/dev/null || echo "") + LATEST_TAG=$(git tag --list "op-program/v*" | sort -V | tail -1) + + if [ "$CURRENT_TAG" != "$LATEST_TAG" ]; then + log_info "Updating to latest op-program version: $LATEST_TAG" + git checkout "$LATEST_TAG" + git submodule update --init --recursive + else + log_info "Already on correct op-program version: $CURRENT_TAG" + fi + fi + + # Copy configuration files + log_info "Copying chain configuration files..." + mkdir -p op-program/chainconfig/configs + cp "$DEPLOYER_DIR/.deployer/rollup.json" "op-program/chainconfig/configs/${CHAIN_ID}-rollup.json" + cp "$DEPLOYER_DIR/.deployer/genesis.json" "op-program/chainconfig/configs/${CHAIN_ID}-genesis.json" + + # Generate prestate + log_info "Generating reproducible prestate..." + make reproducible-prestate + + # Extract the prestate hash from the JSON file + PRESTATE_HASH=$(jq -r '.pre' op-program/bin/prestate-proof-mt64.json) + if [ -z "$PRESTATE_HASH" ] || [ "$PRESTATE_HASH" = "null" ]; then + log_error "Could not extract prestate hash from prestate-proof-mt64.json" + return 1 + fi + + log_info "Prestate hash: $PRESTATE_HASH" + + # Move the prestate file + log_info "Moving prestate file to challenger directory..." + mkdir -p "$ROLLUP_DIR/challenger" + mv "op-program/bin/prestate-mt64.bin.gz" "$ROLLUP_DIR/challenger/${PRESTATE_HASH}.bin.gz" + + # Verify the prestate file was created successfully + if [ ! -f "$ROLLUP_DIR/challenger/${PRESTATE_HASH}.bin.gz" ]; then + log_error "Failed to create prestate file: $ROLLUP_DIR/challenger/${PRESTATE_HASH}.bin.gz" + return 1 + fi + + # Clean up + cd "$ROLLUP_DIR" + # rm -rf "$OPTIMISM_DIR" # Uncomment to clean up after successful generation + + log_success "Challenger prestate generation complete: $ROLLUP_DIR/challenger/${PRESTATE_HASH}.bin.gz" +} + +# Add op-deployer to PATH if it exists in the workspace +if [ -f "$(dirname "$0")/../op-deployer" ]; then + OP_DEPLOYER_PATH="$(cd "$(dirname "$0")/.." && pwd)/op-deployer" + export PATH="$(dirname "$OP_DEPLOYER_PATH"):$PATH" + log_info "Added op-deployer to PATH: $OP_DEPLOYER_PATH" +fi + +# Main execution +main() { + log_info "Starting OP Stack L2 Rollup deployment..." + log_info "L2 Chain ID: $L2_CHAIN_ID" + log_info "L1 Chain ID: $L1_CHAIN_ID" + + # Clean start - remove any existing deployer directory + log_info "Cleaning up any existing deployment..." + rm -rf "$DEPLOYER_DIR" + mkdir -p "$DEPLOYER_DIR" + + validate_main_env + check_prerequisites + generate_addresses + init_deployer + update_intent + deploy_contracts + generate_config + setup_sequencer + setup_batcher + setup_proposer + generate_challenger_prestate + setup_challenger + + log_success "OP Stack L2 Rollup deployment complete!" + log_info "Run 'docker-compose up -d' to start all services" +} + +# Handle command line arguments for standalone function calls +if [ $# -gt 0 ]; then + case "$1" in + "prestate"|"generate-prestate") + log_info "Running standalone prestate generation..." + + # Set up required variables for standalone execution + SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + ROLLUP_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" + DEPLOYER_DIR="$ROLLUP_DIR/deployer" + + generate_challenger_prestate + exit $? + ;; + *) + log_error "Unknown command: $1" + log_info "Available commands: prestate" + exit 1 + ;; + esac +fi + +# Run main function if no arguments provided +main "$@" diff --git a/pages/operators/chain-operators/tutorials/create-l2-rollup.mdx b/pages/operators/chain-operators/tutorials/create-l2-rollup.mdx index a840a2819..8d11c432f 100644 --- a/pages/operators/chain-operators/tutorials/create-l2-rollup.mdx +++ b/pages/operators/chain-operators/tutorials/create-l2-rollup.mdx @@ -25,8 +25,8 @@ import { Callout, Card, Steps } from 'nextra/components' Welcome to the complete guide for deploying your own OP Stack L2 rollup testnet. This multi-part tutorial will walk you through each component step-by-step, from initial setup to a fully functioning rollup. - This tutorial requires **intermediate-level experience working with EVM chains**. - You should be comfortable with concepts like smart contracts, private keys, RPC endpoints, gas fees, and command-line operations. + This tutorial requires **intermediate-level experience working with EVM chains**. + You should be comfortable with concepts like smart contracts, private keys, RPC endpoints, gas fees, and command-line operations. Basic familiarity with Docker is also recommended. @@ -41,6 +41,51 @@ By the end of this tutorial, you'll have a complete OP Stack testnet with: * **Proposer** (op-proposer) submitting state root proposals * **Challenger** (op-challenger) monitoring for disputes +## Quick setup (Recommended) + +If you want to get started quickly, you can use the complete working implementation provided in this repository. This automated setup handles all the configuration and deployment steps for you. + + + **Complete working example** + + A complete, working implementation is available in the [`create-l2-rollup-example/`](https://github.com/ethereum-optimism/docs/tree/main/create-l2-rollup-example/) directory. This includes all necessary scripts, Docker Compose configuration, and example environment files. + + +### Automated setup steps + +1. **Clone and navigate to the code directory:** + ```bash + git clone https://github.com/ethereum-optimism/docs.git + cd docs/create-l2-rollup-example/ + ``` + +2. **Configure your environment:** + ```bash + cp .example.env .env + # Edit .env with your L1_RPC_URL, PRIVATE_KEY, and other settings + ``` + +3. **Run the automated setup:** + ```bash + make init # Download op-deployer + make setup # Deploy contracts and generate configs + make up # Start all services + make test-l1 # Verify L1 connectivity + make test-l2 # Verify L2 functionality + ``` + +4. **Monitor your rollup:** + ```bash + make logs # View all service logs + make status # Check service health + ``` + +The automated setup uses the standard OP Stack environment variable conventions (prefixed with `OP_*`) and handles all the complex configuration automatically. + +## Manual setup (Step-by-Step) + +If you prefer to understand each component in detail or need custom configurations, follow the step-by-step guide below. + ## Before you start ### Software dependencies @@ -153,9 +198,9 @@ Each component's documentation will show you how the directory structure evolves Throughout this tutorial, all file paths will be relative to this `rollup` directory structure. Make sure to adjust any commands if you use different directory names. -## Tutorial overview +## Manual Tutorial Overview -This tutorial is organized into sequential steps that build upon each other: +If you're following the manual setup path, this tutorial is organized into sequential steps that build upon each other: ### **[Spin up op-deployer](/operators/chain-operators/tutorials/create-l2-rollup/op-deployer-setup)** diff --git a/pages/operators/chain-operators/tutorials/create-l2-rollup/_meta.json b/pages/operators/chain-operators/tutorials/create-l2-rollup/_meta.json index 43db0cad0..7d618b2b5 100644 --- a/pages/operators/chain-operators/tutorials/create-l2-rollup/_meta.json +++ b/pages/operators/chain-operators/tutorials/create-l2-rollup/_meta.json @@ -4,5 +4,6 @@ "op-geth-setup": "Spin up sequencer", "op-batcher-setup": "Spin up batcher", "op-proposer-setup": "Spin up proposer", - "op-challenger-setup": "Spin up challenger" + "op-challenger-setup": "Spin up challenger", + "code-setup": "Code examples" } diff --git a/pages/operators/chain-operators/tutorials/create-l2-rollup/code-setup.mdx b/pages/operators/chain-operators/tutorials/create-l2-rollup/code-setup.mdx new file mode 100644 index 000000000..39067ef2f --- /dev/null +++ b/pages/operators/chain-operators/tutorials/create-l2-rollup/code-setup.mdx @@ -0,0 +1,70 @@ +--- +title: L2 Rollup Code Examples +description: Complete working code examples for the Create L2 Rollup tutorial +lang: en-US +content_type: reference +topic: create-l2-rollup-code +personas: + - chain-operator +categories: + - testnet + - mainnet + - op-stack + - code-examples +is_imported_content: 'false' +--- + +import { useEffect } from 'react' +import { Callout } from 'nextra/components' + +# L2 Rollup Code Examples + +export default function Page() { + useEffect(() => { + if (typeof window !== 'undefined') { + window.location.replace('https://github.com/ethereum-optimism/docs/tree/main/create-l2-rollup-example/') + } + }, []) + return ( + <> + + Redirecting to the code on GitHub… If you are not redirected automatically, use this link:{' '} + Create L2 Rollup code on GitHub. + + + ) +} + +{/* Fallback content only if client-side redirect fails; keep minimal */} + +## Quick Start + +```bash +# Copy and configure environment +cp .example.env .env +# Edit .env with your values + +# Run the automated setup +make init # Download tools +make setup # Deploy and configure +make up # Start services +``` + +## Files + +* `.example.env` - Environment configuration template +* `docker-compose.yml` - Service orchestration +* `Makefile` - Automation commands +* `scripts/` - Setup and utility scripts +* `README.md` - Detailed documentation + +## About This Code + +This implementation provides: + +* Automated deployment of OP Stack L2 contracts +* Complete Docker-based service orchestration +* Working examples of all OP Stack components +* Production-ready configuration patterns + +For detailed setup instructions, see the [Create L2 Rollup tutorial](/operators/chain-operators/tutorials/create-l2-rollup). diff --git a/pages/operators/chain-operators/tutorials/create-l2-rollup/op-batcher-setup.mdx b/pages/operators/chain-operators/tutorials/create-l2-rollup/op-batcher-setup.mdx index c3015cd20..b4a00ec09 100644 --- a/pages/operators/chain-operators/tutorials/create-l2-rollup/op-batcher-setup.mdx +++ b/pages/operators/chain-operators/tutorials/create-l2-rollup/op-batcher-setup.mdx @@ -26,6 +26,12 @@ After you have spun up your sequencer, you need to configure a batcher to submit **Step 3 of 5**: This tutorial is designed to be followed step-by-step. Each step builds on the [previous one](/operators/chain-operators/tutorials/create-l2-rollup/op-geth-setup). + + **Automated Setup Available** + + For a complete working setup with all components, check out the [automated approach](https://github.com/ethereum-optimism/docs/tree/main/create-l2-rollup-example/) in the code directory. + + ## Understanding the batcher's role The batcher (`op-batcher`) serves as a crucial component that bridges your L2 chain data to L1. Its primary responsibilities include: @@ -77,32 +83,37 @@ For setting up the batcher, we recommend using Docker as it provides a consisten ### Create environment variables file + + **OP Stack Standard Variables** + + The batcher uses OP Stack standard environment variables following the OP Stack conventions. These are prefixed with `OP_BATCHER_` for batcher-specific settings. + + ```bash # 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 + OP_BATCHER_L1_RPC_URL=https://sepolia.infura.io/v3/YOUR_ACTUAL_INFURA_KEY + # Private key - Replace with your actual private key + OP_BATCHER_PRIVATE_KEY=YOUR_ACTUAL_PRIVATE_KEY # L2 Configuration - Should match your sequencer setup - L2_RPC_URL=http://op-geth:8545 - ROLLUP_RPC_URL=http://op-node:8547 + OP_BATCHER_L2_ETH_RPC=http://op-geth:8545 + OP_BATCHER_ROLLUP_RPC=http://op-node:8547 # Contract addresses - Extract from your op-deployer output - BATCH_INBOX_ADDRESS=YOUR_ACTUAL_BATCH_INBOX_ADDRESS - - # Private key - Replace with your actual private key - BATCHER_PRIVATE_KEY=YOUR_ACTUAL_PRIVATE_KEY + OP_BATCHER_BATCH_INBOX_ADDR=YOUR_ACTUAL_BATCH_INBOX_ADDRESS # Batcher configuration - POLL_INTERVAL=1s - SUB_SAFETY_MARGIN=6 - NUM_CONFIRMATIONS=1 - SAFE_ABORT_NONCE_TOO_LOW_COUNT=3 - RESUBMISSION_TIMEOUT=30s - MAX_CHANNEL_DURATION=25 + OP_BATCHER_POLL_INTERVAL=1s + OP_BATCHER_SUB_SAFETY_MARGIN=6 + OP_BATCHER_NUM_CONFIRMATIONS=1 + OP_BATCHER_SAFE_ABORT_NONCE_TOO_LOW_COUNT=3 + OP_BATCHER_MAX_CHANNEL_DURATION=1 + OP_BATCHER_DATA_AVAILABILITY_TYPE=calldata # RPC configuration - BATCHER_RPC_PORT=8548 + OP_BATCHER_RPC_PORT=8548 EOF ``` @@ -129,25 +140,13 @@ For setting up the batcher, we recommend using Docker as it provides a consisten - .env networks: - sequencer-node_default - command: - - "op-batcher" - - "--l2-eth-rpc=${L2_RPC_URL}" - - "--rollup-rpc=${ROLLUP_RPC_URL}" - - "--poll-interval=${POLL_INTERVAL}" - - "--sub-safety-margin=${SUB_SAFETY_MARGIN}" - - "--num-confirmations=${NUM_CONFIRMATIONS}" - - "--safe-abort-nonce-too-low-count=${SAFE_ABORT_NONCE_TOO_LOW_COUNT}" - - "--resubmission-timeout=${RESUBMISSION_TIMEOUT}" - - "--rpc.addr=0.0.0.0" - - "--rpc.port=${BATCHER_RPC_PORT}" - - "--rpc.enable-admin" - - "--max-channel-duration=${MAX_CHANNEL_DURATION}" - - "--l1-eth-rpc=${L1_RPC_URL}" - - "--private-key=${BATCHER_PRIVATE_KEY}" - - "--batch-type=1" - - "--data-availability-type=blobs" - - "--log.level=info" - - "--max-pending-tx=0" + command: > + op-batcher + --rpc.addr=0.0.0.0 + --rpc.enable-admin + --resubmission-timeout=30s + --log.level=info + --log.format=json restart: unless-stopped networks: diff --git a/pages/operators/chain-operators/tutorials/create-l2-rollup/op-challenger-setup.mdx b/pages/operators/chain-operators/tutorials/create-l2-rollup/op-challenger-setup.mdx index 312ad4c33..e66bd32c2 100644 --- a/pages/operators/chain-operators/tutorials/create-l2-rollup/op-challenger-setup.mdx +++ b/pages/operators/chain-operators/tutorials/create-l2-rollup/op-challenger-setup.mdx @@ -26,6 +26,12 @@ After you have spun up your sequencer, batcher, and proposer, the final step is Each step builds on the previous one, and this is the last part of the tutorial. + + **Automated Setup Available** + + For a complete working setup with all components including automated prestate generation, check out the [automated approach](https://github.com/ethereum-optimism/docs/tree/main/create-l2-rollup-example/) in the code directory. + + 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](/stack/fault-proofs/challenger) for a general overview of this fault proofs feature. @@ -138,28 +144,32 @@ For challenger deployment, we recommend using Docker as it provides a consistent ### 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: + + **OP Stack Standard Variables** + + The challenger uses OP Stack standard environment variables following the OP Stack conventions. These are prefixed with `OP_CHALLENGER_` for challenger-specific settings. + ```bash # 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 - + # Core configuration (required) + OP_CHALLENGER_L1_RPC_URL=https://sepolia.infura.io/v3/YOUR_ACTUAL_INFURA_KEY + OP_CHALLENGER_L1_BEACON_URL=https://ethereum-sepolia-beacon-api.publicnode.com + OP_CHALLENGER_PRIVATE_KEY=YOUR_ACTUAL_PRIVATE_KEY + # L2 Configuration - Replace with your actual node endpoints - L2_RPC_URL=http://op-geth:8545 - ROLLUP_RPC_URL=http://op-node:8547 + OP_CHALLENGER_L2_ETH_RPC=http://op-geth:8545 + OP_CHALLENGER_ROLLUP_RPC=http://op-node:8547 - # Private key - Replace with your actual private key - PRIVATE_KEY=YOUR_ACTUAL_PRIVATE_KEY + # OP Stack challenger configuration (optional - defaults provided) + OP_CHALLENGER_GAME_FACTORY_ADDRESS=YOUR_GAME_FACTORY_ADDRESS + OP_CHALLENGER_CANNON_L2_GENESIS=/workspace/genesis.json + OP_CHALLENGER_CANNON_ROLLUP_CONFIG=/workspace/rollup.json - # 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 + # Prestate configuration - Replace with the file from 'make reproducible-prestate' + OP_CHALLENGER_CANNON_PRESTATE=/workspace/${PRESTATE_HASH}.bin.gz EOF ``` @@ -174,7 +184,7 @@ For challenger deployment, we recommend using Docker as it provides a consistent services: challenger: - image: us-docker.pkg.dev/oplabs-tools-artifacts/images/op-challenger:v1.5.0 + image: us-docker.pkg.dev/oplabs-tools-artifacts/images/op-challenger:v1.5.1 user: "1000" volumes: - ./challenger-data:/data @@ -182,28 +192,12 @@ For challenger deployment, we recommend using Docker as it provides a consistent - ./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" + command: > + op-challenger run-trace + --trace-type=cannon + --datadir=/data + --log.level=info + --log.format=json restart: unless-stopped networks: - sequencer-node_default diff --git a/pages/operators/chain-operators/tutorials/create-l2-rollup/op-deployer-setup.mdx b/pages/operators/chain-operators/tutorials/create-l2-rollup/op-deployer-setup.mdx index 24798f405..96a46e117 100644 --- a/pages/operators/chain-operators/tutorials/create-l2-rollup/op-deployer-setup.mdx +++ b/pages/operators/chain-operators/tutorials/create-l2-rollup/op-deployer-setup.mdx @@ -23,6 +23,12 @@ Welcome to the first step of creating your own L2 rollup testnet! In this sectio **Step 1 of 5**: This tutorial is designed to be followed step-by-step. Each step builds on the previous one. + + **Quick Setup Available** + + For a complete automated setup that includes op-deployer deployment, check out the [`code/`](https://github.com/ethereum-optimism/docs/tree/main/create-l2-rollup-example/) directory. The automated setup handles all contract deployment and configuration automatically. + + ## About op-deployer `op-deployer` simplifies the process of deploying the OP Stack. You define a declarative config file called an "**intent**," then run a command to apply it. `op-deployer` compares your chain's current state against the intent and makes the necessary changes to match. @@ -35,11 +41,17 @@ There are a couple of ways to install `op-deployer`: The recommended way to install `op-deployer` is to download the latest release from the monorepo's [release page](https://github.com/ethereum-optimism/optimism/releases). + + **Quick Setup Available** + + For automated installation, you can use the download script from the [code directory](https://github.com/ethereum-optimism/docs/tree/main/create-l2-rollup-example/). This script automatically downloads the latest version for your system. + + ### Download the correct binary 1. Go to the [release page](https://github.com/ethereum-optimism/optimism/releases) - 2. Use the search bar to find the latest release that includes `op-deployer`. + 2. Find the **latest** release that includes `op-deployer` (look for releases tagged with `op-deployer/v*`) 3. Under **assets**, download the binary that matches your system: * For Linux: `op-deployer-linux-amd64` @@ -48,6 +60,10 @@ There are a couple of ways to install `op-deployer`: * Intel processors: `op-deployer-darwin-amd64` * For Windows: `op-deployer-windows-amd64.exe` + + **Always download the latest version** to ensure you have the most recent features and bug fixes. + + Not sure which macOS version to use? @@ -84,25 +100,30 @@ There are a couple of ways to install `op-deployer`: ```bash - # Step 1: Extract the tar.gz archive in the deployer directory - # Replace USERNAME with your username and adjust the version/arch if needed - tar -xvzf /Users/USERNAME/Downloads/op-deployer-0.2.6-darwin-arm64.tar.gz + # Step 1: Extract the downloaded archive in the deployer directory + # Replace FILENAME with the actual downloaded file name (includes version and arch) + tar -xvzf /Users/USERNAME/Downloads/FILENAME.tar.gz # Step 2: Make the binary executable - chmod +x op-deployer-0.2.6-darwin-arm64 + # Replace FILENAME with the extracted binary name + chmod +x FILENAME # Step 3: Remove macOS quarantine attribute (fixes "can't be opened" warning) - sudo xattr -dr com.apple.quarantine op-deployer-0.2.6-darwin-arm64 + sudo xattr -dr com.apple.quarantine FILENAME # Step 4: Move the binary to your PATH # For Intel Macs: - sudo mv op-deployer-0.2.6-darwin-arm64 /usr/local/bin/ + sudo mv FILENAME /usr/local/bin/op-deployer # For Apple Silicon Macs: - sudo mv op-deployer-0.2.6-darwin-arm64 /opt/homebrew/bin/ + sudo mv FILENAME /opt/homebrew/bin/op-deployer - # Step 7: Verify installation (should print version info) + # Step 5: Verify installation (should print version info) op-deployer --version ``` + + + **Pro Tip**: Use the automated download script from the [code directory](https://github.com/ethereum-optimism/docs/tree/main/create-l2-rollup-example/) to avoid manual version management. It automatically detects your platform and downloads the latest version. + @@ -206,6 +227,12 @@ The intent file defines your chain's configuration. --intent-type standard-overrides ``` + + **Version Compatibility** + + Each `op-deployer` version is bound to specific `op-contracts` versions. The `l1ContractsLocator` and `l2ContractsLocator` values in your intent file must be compatible with your `op-deployer` version. Check the [op-deployer release notes](https://github.com/ethereum-optimism/optimism/releases) for version compatibility information. + +
Understanding intent types @@ -220,20 +247,25 @@ The intent file defines your chain's configuration. ### Update the intent file - Edit `.deployer/intent.toml` with your generated addresses: + Edit `.deployer/intent.toml` with your generated addresses. The example below shows the typical configuration for a standard OP Stack deployment, with advanced options commented out: ```toml configType = "standard-overrides" l1ChainID = 11155111 # Sepolia fundDevAccounts = false # Set to false for production/testnet useInterop = false - l1ContractsLocator = "tag://op-contracts/v2.0.0" - l2ContractsLocator = "tag://op-contracts/v1.7.0-beta.1+l2-contracts" - [superchainRoles] - proxyAdminOwner = "0x..." # admin address - protocolVersionsOwner = "0x..." # admin address - guardian = "0x..." # admin address + # Contract locators are automatically determined by your op-deployer version + # Only uncomment and modify if you need specific contract versions (advanced users only) + # l1ContractsLocator = "tag://op-contracts/v2.0.0" + # l2ContractsLocator = "tag://op-contracts/v1.7.0-beta.1+l2-contracts" + + # Superchain roles - only define if creating a standalone chain not part of OP Stack superchain + # For standard OP Stack deployments, these are predefined and should not be set + # [superchainRoles] + # proxyAdminOwner = "0x..." # admin address + # protocolVersionsOwner = "0x..." # admin address + # guardian = "0x..." # admin address [[chains]] id = "0x000000000000000000000000000000000000000000000000000000000016de8d" @@ -245,7 +277,7 @@ The intent file defines your chain's configuration. eip1559Elasticity = 6 [chains.roles] l1ProxyAdminOwner = "0x1eb2ffc903729a0f03966b917003800b145f56e2" - l2ProxyAdminOwner = "0x2fc3ffc903729a0f03966b917003800b145f67f3" + l2ProxyAdminOwner = "0x2fc3ffc903729a0f03966b917003800b145f67f3" systemConfigOwner = "0x..." # system_config address unsafeBlockSigner = "0x..." # unsafe_block_signer address batcher = "0x..." # batcher address @@ -259,32 +291,32 @@ The intent file defines your chain's configuration. **Global Settings:** * `l1ChainID`: The L1 network ID (11155111 for Sepolia) - * `fundDevAccounts`: Creates test accounts with ETH if true - * `useInterop`: Enable interoperability features - * `l1ContractsLocator`: Version of L1 contracts to deploy - * `l2ContractsLocator`: Version of L2 contracts to deploy + * `fundDevAccounts`: Creates test accounts with ETH if true (set to false for production) + * `useInterop`: Enable interoperability features (false for standard deployments) + + **Contract Locators (Advanced):** + + These are commented out because `op-deployer` automatically determines compatible contract versions. Only uncomment and modify if you need to pin to specific contract versions for advanced use cases. - **Superchain Roles:** + **Superchain Roles (Advanced):** - * `proxyAdminOwner`: Can upgrade Superchain-wide contracts - * `protocolVersionsOwner`: Can update protocol versions - * `guardian`: Can pause withdrawals and manage disputes + These are commented out because for standard OP Stack deployments, superchain roles are predefined by the protocol. Only uncomment and define custom roles if you're creating a standalone chain not part of the OP Stack superchain. **Chain Configuration:** * `id`: Unique identifier for your chain - * `*FeeVaultRecipient`: Addresses receiving various fees - * `eip1559*`: Parameters for gas price calculation + * `*FeeVaultRecipient`: Addresses receiving various protocol fees + * `eip1559*`: Parameters for dynamic gas price calculation **Chain Roles:** - * `l1ProxyAdminOwner`: Updates L1 contract implementations - * `l2ProxyAdminOwner`: Updates L2 contract implementations - * `systemConfigOwner`: Manages system configuration - * `unsafeBlockSigner`: Signs pre-confirmation blocks - * `batcher`: Submits L2 transactions to L1 - * `proposer`: Submits L2 state roots to L1 - * `challenger`: Monitors and challenges invalid states + * `l1ProxyAdminOwner`: Can upgrade L1 contract implementations (usually same as superchain proxyAdminOwner) + * `l2ProxyAdminOwner`: Can upgrade L2 contract implementations + * `systemConfigOwner`: Manages system configuration parameters + * `unsafeBlockSigner`: Signs pre-confirmation blocks (can be same as batcher) + * `batcher`: Submits L2 transaction batches to L1 + * `proposer`: Submits L2 state roots to L1 for verification + * `challenger`: Monitors dispute games and defends valid states
diff --git a/pages/operators/chain-operators/tutorials/create-l2-rollup/op-proposer-setup.mdx b/pages/operators/chain-operators/tutorials/create-l2-rollup/op-proposer-setup.mdx index 23b0bdd08..172aa01eb 100644 --- a/pages/operators/chain-operators/tutorials/create-l2-rollup/op-proposer-setup.mdx +++ b/pages/operators/chain-operators/tutorials/create-l2-rollup/op-proposer-setup.mdx @@ -26,6 +26,12 @@ After you have spun up your sequencer and batcher, you need to attach a proposer **Step 4 of 5**: This tutorial is designed to be followed step-by-step. Each step builds on the previous one. + + **Automated Setup Available** + + For a complete working setup with all components, check out the [automated approach](https://github.com/ethereum-optimism/docs/tree/main/create-l2-rollup-example/) in the code directory. + + This guide assumes you already have a functioning sequencer, batcher, and the necessary L1 contracts deployed using [`op-deployer`](./op-deployer-setup). If you haven't set up your sequencer and batcher yet, please refer to the [sequencer guide](./op-geth-setup) and [batcher guide](./op-batcher-setup) first. To see configuration info for the proposer, check out the [configuration page](/operators/chain-operators/configuration/proposer). @@ -78,29 +84,33 @@ For setting up the proposer, we recommend using Docker as it provides a consiste ### Create environment variables file + + **OP Stack Standard Variables** + + The proposer uses OP Stack standard environment variables following the OP Stack conventions. These are prefixed with `OP_PROPOSER_` for proposer-specific settings. + + ```bash # 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 Configuration - Replace with your actual RPC URLs + OP_PROPOSER_L1_RPC_URL=https://sepolia.infura.io/v3/YOUR_ACTUAL_INFURA_KEY # L2 Configuration - Should match your sequencer setup - L2_RPC_URL=http://op-geth:8545 - ROLLUP_RPC_URL=http://op-node:8547 + OP_PROPOSER_ROLLUP_RPC=http://op-node:8547 # Contract addresses - Extract from your op-deployer output - GAME_FACTORY_ADDRESS=YOUR_ACTUAL_GAME_FACTORY_ADDRESS + OP_PROPOSER_GAME_FACTORY_ADDRESS=YOUR_ACTUAL_GAME_FACTORY_ADDRESS # Private key - Replace with your actual private key - PRIVATE_KEY=YOUR_ACTUAL_PRIVATE_KEY - - # Proposer configuration - PROPOSAL_INTERVAL=3600s - GAME_TYPE=0 - POLL_INTERVAL=20s - - # RPC configuration - PROPOSER_RPC_PORT=8560 + OP_PROPOSER_PRIVATE_KEY=YOUR_ACTUAL_PRIVATE_KEY + + # OP Stack proposer configuration (optional - defaults provided) + OP_PROPOSER_PROPOSAL_INTERVAL=3600s + OP_PROPOSER_GAME_TYPE=0 + OP_PROPOSER_POLL_INTERVAL=20s + OP_PROPOSER_ALLOW_NON_FINALIZED=true + OP_PROPOSER_WAIT_NODE_SYNC=true EOF ``` @@ -130,21 +140,11 @@ For setting up the proposer, we recommend using Docker as it provides a consiste - "8560:8560" env_file: - .env - command: - - "op-proposer" - - "--poll-interval=${POLL_INTERVAL}" - - "--rpc.port=${PROPOSER_RPC_PORT}" - - "--rpc.enable-admin" - - "--rollup-rpc=${ROLLUP_RPC_URL}" - - "--l1-eth-rpc=${L1_RPC_URL}" - - "--private-key=${PRIVATE_KEY}" - - "--game-factory-address=${GAME_FACTORY_ADDRESS}" - - "--game-type=${GAME_TYPE}" - - "--proposal-interval=${PROPOSAL_INTERVAL}" - - "--num-confirmations=1" - - "--resubmission-timeout=30s" - - "--wait-node-sync=true" - - "--log.level=info" + command: > + op-proposer + --rpc.port=8560 + --log.level=info + --log.format=json restart: unless-stopped networks: - sequencer-node_default