Operators
Spinning up the batcher

Spinning up the batcher

After you have spun up your sequencer, you need to configure a batcher to submit L2 transaction batches to L1. The batcher is a critical component that ensures L2 transaction data is available on L1 for data availability and enables users to reconstruct the L2 state.

This guide assumes you already have a functioning sequencer and the necessary L1 contracts deployed using op-deployer. If you haven't set up your sequencer yet, please refer to the [sequencer guide](add this later) first.

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:

  • Batch submission: Collecting L2 transactions and submitting them as batches to L1
  • Data availability: Ensuring L2 transaction data is available on L1 for verification
  • Cost optimization: Compressing and efficiently packing transaction data to minimize L1 costs
  • Channel management: Managing data channels for optimal batch submission timing

The batcher reads transaction data from your sequencer and submits compressed batches to the BatchInbox contract on L1.

Prerequisites

Before setting up your batcher, ensure you have:

Running infrastructure:

  • An operational sequencer node
  • Access to a L1 RPC endpoint

Network information:

  • Your L2 chain ID and network configuration
  • L1 network details (chain ID, RPC endpoints)
  • BatchInbox contract address from your deployment

Software installation

Finding the current stable releases

To ensure you're using the latest compatible versions of OP Stack components, always check the official releases page (opens in a new tab).

Look for the latest op-batcher/v* release that's compatible with your sequencer setup.

This guide uses op-batcher/v1.13.1 which is compatible with op-node/v1.13.3 and op-geth/v1.101511.0 from the sequencer setup. Always check the release notes (opens in a new tab) for compatibility information.

Build from source

Clone and build op-batcher:

# If you don't already have the optimism repository from the sequencer setup
git clone https://github.com/ethereum-optimism/optimism.git
cd optimism
 
# Checkout the latest release tag
git checkout op-batcher/v1.13.1
 
# Build op-batcher
cd op-batcher
just
 
# Binary will be available at ./bin/op-batcher

Verify installation

Run this command to verify the installation:

./bin/op-batcher --version

Docker alternative (For containerized environments)

If you prefer containerized deployment, you can use the official Docker images.

Complete Docker setup guide

Complete Docker setup guide

If you choose the Docker approach, you'll need to:

  1. Set up directory structure and copy configuration files:
# Create your batcher working directory
mkdir ~/batcher-node
cd ~/batcher-node
 
# Copy configuration files from op-deployer output
# Note: Adjust the path if your .deployer directory is located elsewhere
cp ~/.deployer/state.json .
 
# Extract the BatchInbox address
BATCH_INBOX_ADDRESS=$(cat state.json | jq -r '.opChainDeployments[0].systemConfigProxyAddress')
echo "BatchInbox Address: $BATCH_INBOX_ADDRESS"
  1. Create environment variables file:
# 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
 
# L2 Configuration - Should match your sequencer setup
L2_RPC_URL=http://sequencer-node:8545
ROLLUP_RPC_URL=http://sequencer-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=0xYOUR_ACTUAL_PRIVATE_KEY
 
# 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
 
# RPC configuration
BATCHER_RPC_PORT=8548
EOF

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

  1. Create docker-compose.yml:

This configuration assumes your sequencer is running in a Docker container named sequencer-node on the same op-stack network. Make sure your sequencer is running before starting the batcher.

version: '3.8'
 
services:
op-batcher:
  image: us-docker.pkg.dev/oplabs-tools-artifacts/images/op-batcher:v1.13.1
  volumes:
    - .:/workspace
  working_dir: /workspace
  ports:
    - "8548:8548"
  env_file:
    - .env
  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"
    - "--compress"
    - "--log.level=info"
  restart: unless-stopped
  1. Start the batcher service:
# Make sure your sequencer network exists
docker network create op-stack 2>/dev/null || true
 
# Start the batcher
docker-compose up -d
 
# View logs
docker-compose logs -f op-batcher
  1. Verify batcher is running:
# Check batcher RPC is responding
curl -X POST -H "Content-Type: application/json" \
  --data '{"jsonrpc":"2.0","method":"admin_startBatcher","params":[],"id":1}' \
  http://localhost:8548
 
# Check container status
docker-compose ps
  1. Final directory structure:
~/batcher-node/
├── state.json             # Copied from ~/.deployer/
├── .env                   # Environment variables
└── docker-compose.yml     # Docker configuration
⚠️

The rest of this guide assumes you're using the build-from-source approach. If you chose Docker, refer to the collapsible section.

Configuration setup

1. Organize your workspace

Create your batcher working directory:

# Create batcher directory at the same level as your sequencer
mkdir batcher-node
cd batcher-node
 
# Create scripts directory
mkdir scripts

Your final directory structure should look like:

~/
├── optimism/               # Contains op-batcher binary
├── sequencer-node/         # Your sequencer setup
├── proposer-node/          # Your proposer setup
├── .deployer/             # From op-deployer
   └── state.json
└── batcher-node/          # Your batcher working directory
    ├── state.json         # Copied from .deployer
    ├── .env
    └── scripts/
        └── start-batcher.sh

2. Extract BatchInbox address

Extract the BatchInbox contract address from your op-deployer output:

# Navigate to batcher directory
cd ~/batcher-node
 
# Copy the deployment state file from op-deployer
# Update the path if your .deployer directory is located elsewhere
cp ../.deployer/state.json .
 
# Extract the BatchInbox address
BATCH_INBOX_ADDRESS=$(cat state.json | jq -r '.opChainDeployments[0].systemConfigProxyAddress')
echo "BatchInbox Address: $BATCH_INBOX_ADDRESS"

The batcher submits transaction batches to the BatchInbox contract on L1. This contract is responsible for accepting and storing L2 transaction data.

3. Set up environment variables

Create your .env file with the actual values:

# Create .env file with your actual values
# L1 Configuration - Replace with your actual RPC URL
L1_RPC_URL=https://sepolia.infura.io/v3/YOUR_ACTUAL_INFURA_KEY
 
# L2 Configuration - Should match your sequencer setup
L2_RPC_URL=http://localhost:8545
ROLLUP_RPC_URL=http://localhost: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=0xYOUR_ACTUAL_PRIVATE_KEY
 
# 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
 
# RPC configuration
BATCHER_RPC_PORT=8548

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

4. Get your private key

Get a private key from your wallet that will be used for submitting batches to L1. This account needs sufficient ETH to pay for L1 gas costs.

⚠️

The batcher account needs to be funded with ETH on L1 to pay for batch submission transactions. Monitor this account's balance regularly as it will consume ETH for each batch submission.

Batcher configuration

Create scripts/start-batcher.sh:

#!/bin/bash
 
source .env
 
# Path to the op-batcher binary we built
../optimism/op-batcher/bin/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 \
  --compress \
  --log.level=info

Batcher parameters explained

  • --poll-interval: How frequently the batcher checks for new L2 blocks to batch
  • --sub-safety-margin: Number of confirmations to wait before considering L1 transactions safe
  • --max-channel-duration: Maximum time (in L1 blocks) to keep a channel open
  • --batch-type: Type of batch encoding (1 for span batches, 0 for singular batches)
  • --data-availability-type: Whether to use blobs or calldata for data availability
  • --compress: Enable compression to reduce L1 data costs

Starting the batcher

1. Verify prerequisites

Ensure your sequencer and rollup node are running:

Test L1 connectivity

# Note: Make sure you have exported these environment variables to your current shell session:
# export L1_RPC_URL="https://sepolia.infura.io/v3/YOUR_KEY"
# export L2_RPC_URL="http://localhost:8545"  
# export ROLLUP_RPC_URL="http://localhost:8547"
 
curl -X POST -H "Content-Type: application/json" \
  --data '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' \
  $L1_RPC_URL

Test L2 connectivity

curl -X POST -H "Content-Type: application/json" \
  --data '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' \
  $L2_RPC_URL

Test rollup node connectivity

curl -X POST -H "Content-Type: application/json" \
  --data '{"jsonrpc":"2.0","method":"optimism_syncStatus","params":[],"id":1}' \
  $ROLLUP_RPC_URL

2. Start the batcher

# Make the script executable
chmod +x scripts/start-batcher.sh
 
# Start the batcher
./scripts/start-batcher.sh

Verification

Verify your batcher is working correctly:

Check batcher status

# Check batcher RPC is responding
curl -X POST -H "Content-Type: application/json" \
  --data '{"jsonrpc":"2.0","method":"admin_startBatcher","params":[],"id":1}' \
  http://localhost:8548
 
# Monitor batch submission activity (check L1 for recent transactions from your batcher address)
# Replace with your actual batcher address
curl -X POST -H "Content-Type: application/json" \
  --data '{"jsonrpc":"2.0","method":"eth_getTransactionCount","params":["0xYOUR_BATCHER_ADDRESS","latest"],"id":1}' \
  $L1_RPC_URL
 
# Check if your batcher address has enough ETH for gas
curl -X POST -H "Content-Type: application/json" \
  --data '{"jsonrpc":"2.0","method":"eth_getBalance","params":["0xYOUR_BATCHER_ADDRESS","latest"],"id":1}' \
  $L1_RPC_URL

For detailed cost analysis and optimization strategies, refer to the Fee calculation tools.

Next steps

Your batcher is now operational and will continuously submit L2 transaction batches to L1!