A word of caution here. Practical L2 designs have several features that don’t seem compatible with the design described here.
L2s have functionalities for things like trustless cross-chain deposits and withdrawals, which need to be supported in the L2 state transition function.
L2s use transaction types not supported by Ethereum, such as types that can be sent by L1 contracts. (This requires a different transaction type because, for example, such transactions don’t carry a signature.)
L2s do gas accounting differently than L1 does, for example by adding a surcharge to pay for data availability; or if the L2 has variable block time for efficiency, then adjusting gas prices based on timestamp rather than block number. Doing this trustlessly requires changes to the state transition function.
L2s support precompiles that do not exist on L1, for example to get information about the current data availability gas price, or to get information about the L1 state. These precompiles aren’t just invoked as “top-level” transactions but are invoked within the execution of other transactions.