Lagoon L2 Chain Derivation Changes

Table of Contents

Span Batch Updates

Span batches encode a span of consecutive L2 blocks for submission to the data availability layer.

The Lagoon network upgrade introduces the post-execution transaction, an [EIP-2718] typed transaction with type byte 0x7D. Unlike a deposited transaction, which is derived from L1 and is never present in batch data, a post-exec transaction is produced by the sequencer and travels to verifiers inside the L2 block body — through the L1 batch as well as the unsafe p2p payload. A span batch covering a block that contains a post-exec transaction therefore has to transpose that transaction into the span batch txs structure like any other.

A post-exec transaction is unlike every previously batched type: it carries only an opaque post-exec payload, with no nonce, gas limit, recipient or signature. Most of the slots the span batch format reserves per transaction have no natural value for it. This section specifies all of them.

Nothing outside the txs structure changes. In particular, a post-exec transaction is an ordinary member of its block's transaction list, so it is counted in that block's block_tx_counts entry and in the MAX_SPAN_BATCH_ELEMENT_COUNT total, exactly like a user transaction. Because a post-exec transaction is the final transaction of its block, it occupies the last index of that block's slice of the span.

The span batch format transposes and reconstructs a transaction list and has no notion of block validity, so it can faithfully encode a block that violates the block-level structural rules — one carrying two 0x7D transactions, say, or one where the 0x7D transaction is not last. Such a batch is well formed as a batch; the violation is caught where the rules are stated, when the derived block is validated, and under Steady Block Derivation the invalid payload is then replaced by a deposit-only one and the remaining span batch and its channel are dropped.

A decoder MUST NOT reject a span batch on account of these rules, and that prohibition carries as much weight as the rules themselves. The two paths do not converge. A block-validity failure produces a deposit-only block at that height and then discards the rest of the span batch and its channel; a decode-time rejection produces no block at that height at all, leaving it to be filled by a later batch. From the same L1 data they derive different chains, so a decoder that checked these rules early would diverge from one that left them alone.

This is the line the slot rules below sit on the other side of. A value that cannot reach the derived block is checked by nothing downstream, so the decoder MUST check it; a property of the block itself is already checked downstream, so the decoder MUST NOT.

Transaction Data

This corresponds with a new encoding of the tx_datas list as specified in the Delta span batch spec, adding a new transaction type:

Transaction type 0x7D (post-exec): 0x7D ++ rlp_encoded_payload

where rlp_encoded_payload is the RLP encoding of the post-exec payload as a list, exactly as defined by the transaction's EIP-2718 encoding. As for every other tx_datas element, the bytes following the type byte MUST be a single RLP list.

A decoder MUST NOT inspect the payload's version byte or validate it against a schema while decoding a batch: below the outer RLP list the element is opaque bytes, reproduced verbatim into the reconstructed transaction. Payload validity is a block-level concern and is settled when the derived block is validated.

For every other transaction type the tx_datas element is a reduced encoding: fields the span batch format stores in dedicated slots (nonce, gasLimit, to, and the signature), along with the chain ID, which is recovered from the rollup config rather than stored at all, are omitted from the element, and the remaining fields are re-encoded as a shorter RLP list. A post-exec transaction has none of those fields, so nothing is omitted and nothing is re-encoded: its tx_datas element is byte for byte the transaction's EIP-2718 encoding as it appears in the block body.

Transposed Envelope Fields

A post-exec transaction has no envelope fields to transpose. Its slots in the span batch txs structure take the following values:

SlotValue for a 0x7D transaction
zero_to_bits1
tx_tosno entry — the transaction consumes none
y_parity_bits0
tx_sigsr = 0, s = 0
tx_nonces0
tx_gases0
protected_bitsno entry — the bitlist covers legacy transactions only

zero_to_bits

The bit for a post-exec transaction MUST be 1: the transaction has no to field, so it consumes no entry from tx_tos.

A decoder MUST reject the span batch if the bit is 0 for a post-exec transaction, exactly as it rejects one whose tx_datas element carries an unusable transaction type.

Unused signature and gas accounting slots

y_parity_bits, tx_sigs, tx_nonces and tx_gases are positional: every transaction in the span occupies one slot in each, whether or not the corresponding field exists. A post-exec transaction has no signature, nonce or gas limit, so:

  • A batcher MUST write zero into each of these slots for a post-exec transaction, as given in the table above.
  • A decoder MUST verify that each of them is zero, and MUST reject the span batch if any of them is not.

The rejection is at span batch granularity: these slots are positional across the whole span, so a violation invalidates the span batch rather than the single block whose transaction carries it. How far that invalidity then propagates — whether the remaining channel is discarded with it — is a property of malformed span batches in general, not something particular to post-exec transactions, and is not settled here.

Decoding is deliberately no more permissive than encoding. The values in these slots cannot reach the reconstructed transaction, so tolerating them would cost nothing in the short term — but it would make a span batch's encoding malleable: the same sequence of L2 blocks would have unboundedly many valid encodings, differing in bytes that a batcher chooses freely. tx_sigs alone reserves 64 bytes per transaction that no post-exec transaction uses. A strict decoder keeps the encoding canonical, denies a batcher that space as a channel for arbitrary data, and leaves nothing that a later upgrade would have to tighten retroactively.

This strictness is available precisely because 0x7D is new. A block before the Lagoon activation timestamp MUST NOT contain a 0x7D transaction, so no batch already posted carries one, and no rule stated here reinterprets any of them.

Reconstruction

When a span batch is decoded, the full transaction reconstructed for a post-exec element is its tx_datas element verbatim:

0x7D ++ rlp_encoded_payload

A decoder MUST NOT fold tx_nonces, tx_gases, tx_tos or tx_sigs into the reconstructed transaction; there are no fields for them to occupy. The tx_tos cursor is not advanced, because the transaction's zero_to_bits bit is 1.

The reconstructed bytes are therefore identical to the transaction's encoding in the block body. This is what makes the overlap check between a batch and an already-safe block — comparing the batch's reconstructed transactions against the safe block's transactions — well defined for blocks containing a post-exec transaction: the comparison turns on the tx_datas element alone, and every other slot is both fixed by the rules above and discarded here.

Batch Acceptance

This document specifies only how a post-exec transaction is encoded within a span batch, because that is the only batch format for which the question arises. A singular batch needs no Lagoon amendment: its transaction_list holds each transaction's EIP-2718 encoding verbatim, so a post-exec transaction appears there as 0x7D ++ rlp_encoded_payload like any other typed transaction, with nothing transposed and no slots to fill. Only the span batch format, which splits each transaction across per-field slots, needed the rules above.

Whether a batch is permitted to contain a post-exec transaction at all is a separate, batch-level question, and one that applies to both batch formats. It is governed by the batch.transactions drop rules in Batch Queue.

Singular batches with transactions of type 0x7D must only be accepted if Lagoon is active at the timestamp of the batch. If a singular batch contains a transaction of type 0x7D before Lagoon is active, this batch must be dropped. This check must happen at the level of individual batches that are derived from span batches, not to span batches as a whole. In particular, it is allowed for a span batch to span the Lagoon activation timestamp and contain an 0x7D transaction in singular batches that have a timestamp at or after the Lagoon activation time, even if the timestamp of the span batch itself is before the Lagoon activation time.