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:
| Slot | Value for a 0x7D transaction |
|---|---|
zero_to_bits | 1 |
tx_tos | no entry — the transaction consumes none |
y_parity_bits | 0 |
tx_sigs | r = 0, s = 0 |
tx_nonces | 0 |
tx_gases | 0 |
protected_bits | no 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.