Batcher policy
The batcher policy defines high-level constraints and responsibilities regarding how L2 data is posted to L1. Below are the standard guidelines for configuring the batcher within the OP Stack.-
Data Availability Types:
- Calldata is generally simpler but can be more expensive on mainnet Ethereum, depending on gas prices.
- Blobs are typically lower cost when your chain has enough transaction volume to fill large chunks of data.
- The
op-batchercan toggle between these approaches by setting the--data-availability-type=<blobs|calldata|auto>flag or with theOP_BATCHER_DATA_AVAILABILITY_TYPEenv variable. Setting this flag toautowill allow the batcher to automatically switch betweencalldataandblobsbased on the current L1 gas price.
-
Batch Submission Frequency (
OP_BATCHER_MAX_CHANNEL_DURATIONand related flags):- Standard OP Chains frequently target a maximum channel duration between 1–6 hours.
- Your chain should never exceed your L2’s sequencing window (commonly 12 hours).
- If targeting a longer submission window (e.g., 5 or 6 hours), be aware that the safe head can stall up to that duration.
op-batcher configuration. See the batcher configuration reference, which explains each CLI flag and environment variable in depth.
Recommendations
Set your OP_BATCHER_MAX_CHANNEL_DURATION
The default value inside
op-batcher, if not specified, is still 0, which means channel duration tracking is disabled.
For very low throughput chains, this would mean to fill channels until close to the sequencing window and post the channel to L1 SUB_SAFETY_MARGIN L1 blocks before the sequencing window expires.OP_BATCHER_MAX_CHANNEL_DURATION to target 5 hours, with a value of 1500 L1 blocks. When non-zero, this parameter is the max time (in L1 blocks, which are 12 seconds each) between which batches will be submitted to the L1. If you have this set to 5 for example, then your batcher will send a batch to the L1 every 5*12=60 seconds. When using blobs, because 130kb blobs need to be purchased in full, if your chain doesn’t generate at least ~130kb of data in those 60 seconds, then you’ll be posting only partially full blobs and wasting storage.
- We do not recommend setting any values higher than targeting 5 hours, as batches have to be submitted within the sequencing window which defaults to 12 hours for OP chains, otherwise your chain may experience a 12 hour long chain reorg. 5 hours is the longest length of time we recommend that still sits snugly within that 12 hour window to avoid affecting stability.
- If your chain fills up full blobs of data before the
OP_BATCHER_MAX_CHANNEL_DURATIONelapses, a batch will be submitted anyways - (e.g. even if the OP Mainnet batcher sets anOP_BATCHER_MAX_CHANNEL_DURATIONof 5 hours, it will still be submitting batches every few minutes)
While setting an
OP_BATCHER_MAX_CHANNEL_DURATION of 1500 results in the cheapest fees, it also means that your safe head can stall for up to 5 hours.- This will negatively impact apps on your chain that rely on the safe head for operation. While many apps can likely operate simply by following the unsafe head, often Centralized Exchanges or third party bridges wait until transactions are marked safe before processing deposits and withdrawal.
- Thus a larger gap between posting batches can result in significant delays in the operation of certain types of high-security applications.
Configure your batcher to use multiple blobs
When there’s blob congestion, running with high blob counts can backfire, because you will have a harder time getting blobs included and then fees will bump, which always means a doubling of the priority fees.
op-batcher has the capabilities to send multiple blobs per single blob transaction. This is accomplished by the use of multi-frame channels, see the specs for more technical details on channels and frames.
A minimal batcher configuration (with env vars) to enable 6-blob batcher transactions is:
Set your --batch-type=1 to use span batches
Span batches reduce the overhead of OP Stack chains, introduced in the Delta network upgrade. This is beneficial for sparse and low-throughput OP Stack chains.
The overhead is reduced by representing a span of consecutive L2 blocks in a more efficient manner, while preserving the same consistency checks as regular batch data.
Batcher sequencer throttling
This feature is a batcher-driven sequencer-throttling control loop. This is to avoid sudden spikes in L1 DA-usage consuming too much available gas and causing a backlog in batcher transactions. The batcher can throttle the sequencer’s data throughput instantly when it sees too much batcher data built up. There are two throttling knobs:- Transaction throttling, which skips individual transactions whose estimated compressed L1 DA usage goes over a certain threshold, and
- Block throttling, which caps a block’s estimated total L1 DA usage and leads to not including transactions during block building that would move the block’s L1 DA usage past a certain threshold.
- This feature is enabled by default and requires the sequencer’s
op-rethnode to expose theminer_setMaxDASizeRPC (enable theminernamespace, below). It can be disabled by setting--throttle-thresholdto 0. The sequencer’sop-rethnode has to be updated first, before updating the batcher, so that the required RPC is available at the time of the batcher restart. - It is required to upgrade to
op-conductor/v0.2.0if you are using conductor’s leader-aware rpc proxy feature. This conductor release includes support for proxying theminer_setMaxDASizeRPC.
Note that this feature requires the batcher to correctly follow the sequencer at all times, or it would set throttling parameters on a non-sequencer EL client. That means, active sequencer follow mode has to be enabled correctly by listing all the possible sequencers in the L2 rollup and EL endpoint flags.
- Backlog of pending block bytes beyond which the batcher will enable throttling on the sequencer via
--throttle.unsafe-da-bytes-lower/upper-threshold(env varOP_BATCHER_THROTTLE_UNSAFE_DA_BYTES_LOWER/UPPER_THRESHOLD): 3_200_000 and 12_800_000 (batcher backlog of 3.2MB to 12.8MB of data to batch). Disable throttling by setting the lower threshold to0. The upper threshold sets the level where the maximum throttling intensity is reached. - Individual tx size throttling via
--throttle.tx-size-lower/upper-limit(env varOP_BATCHER_THROTTLE_TX_SIZE_LOWER/UPPER_LIMIT): 150 and 20_000. This is the limit on the estimated compressed size of a transaction when throttling is at maximum/minimum intensity respectively. - Block size throttling via
--throttle.block-size-lower/upper-limit(env varOP_BATCHER_THROTTLE_BLOCK_SIZE_LOWER/UPPER_LIMIT): 2_000 and 130_000. This is the limit on the estimated compressed size of a block when throttling is at maximum/minimum intensity respectively. - Throttler controller type via
--throttle.controller-type(env varOP_BATCHER_THROTTLE_CONTROLLER_TYPE):quadraticby default. This determines how transaction and block size limits are interpolated when throttling is at intermediate intensity.
op-reth node to which it’s talking doesn’t have the miner_setMaxDASize RPC enabled, it will fail with an error message like:
miner_setMaxDASize RPC has to be enabled by adding the miner namespace to op-reth’s API flags:
Example configuration
This is a basic example of a batcher configuration. Optimal batcher configuration is going to differ for each chain, however you can see some of the most important variables configured below:MAX_CHANNEL_DURATION is hit,
may save gas by increasing the MAX_CHANNEL_DURATION. See the recommendations section.