# Transaction Flow

### [#](#introduction) Introduction <a href="#introduction" id="introduction"></a>

The process for a rollup transaction has two requirements.

* The transaction needs to be written to L1 (Ethereum). This is typically performed by `pt-batcher`, but any user can send an L1 transaction to submit an L2 transaction, in which case pt`-batcher` is bypassed.
* The transaction needs to be executed to modify the state (by pt`-geth`). Afterwards, pt`-proposer` writes a [commitment (opens new window)](https://en.wikipedia.org/wiki/Commitment_scheme) to the post-transaction state to L1. Note that pt`-proposer` does not need to write a commitment after each transaction to L1, it is OK to commit to the state after a block of transactions.

### [#](#writing-the-transaction-to-l1) Writing the transaction to L1 <a href="#writing-the-transaction-to-l1" id="writing-the-transaction-to-l1"></a>

[`pt-batcher` (opens new window)](https://github.com/patex-ecosystem/patex-network/tree/main/pt-batcher) has two main jobs:

* Compress transactions into batches.
* Post those batches to L1 to ensure availability and integrity.

#### Compression <a href="#compression" id="compression"></a>

The batcher aggregates [sequencer batches (opens new window)](https://github.com/patex-ecosystem/patex-network/blob/main/specs/glossary.md#sequencer-batch) into [channels (opens new window)](https://github.com/patex-ecosystem/patex-network/blob/main/specs/glossary.md#channel). This allows for more data per compression frame, and therefore a better compression ratio. You can read more about this process [in the specs (opens new window)](https://github.com/patex-ecosystem/patex-network/blob/main/specs/glossary.md#batch-submission).

When a channel is full or times out it is compressed and written.

The maximum time that a channel can be open, from the first transaction to the last, is specified in units of L1 block time (so a value of 5 means 5\*12=60 seconds). You can specify it either as an environment variable (`OP_BATCHER_MAX_CHANNEL_DURATION`) or a command line parameters (`--max-channel-duration`). Alternatively, you can set it to zero (the default) to avoid posting smaller, less cost efficient, transactions.

A channel is full when the anticipated compressed size is the target L1 transaction size. This is controlled by two parameters:

1. The target L1 transaction size, which you can specify in bytes on the command line (`--target-l1-tx-size-bytes`) or as an environment variable (`OP_BATCHER_TARGET_L1_TX_SIZE_BYTES`)
2. The expected compression ratio, which you can specify as a decimal value, again either on the command line (`--approx-compr-ratio`) or as an environment variable (`OP_BATCHER_APPROX_COMPR_RATIO`).

You can see the code that implements this process in [`channel_manager.go` (opens new window)](https://github.com/patex-ecosystem/patex-network/blob/main/pt-batcher/batcher/channel_manager.go) and [`channel_builder.go` (opens new window)](https://github.com/patex-ecosystem/patex-network/blob/main/pt-batcher/batcher/channel_builder.go).

#### Posting to L1 <a href="#posting-to-l1" id="posting-to-l1"></a>

When a channel is full it is posted, either as a single transaction or as multiple transactions (depending on data size) to L1.

Processed L2 transactions exist in one of three states:

* **unsafe** transactions are already processed, but not written to L1 yet. A batcher fault might cause these transactions to be dropped.
* **safe** transactions are already processed and written to L1. However, they might be dropped due to a reorganization at the L1 level.
* **finalized** transactions are written to L1 in an L1 block that is old enough to be [finalized (opens new window)](https://www.alchemy.com/overviews/ethereum-commitment-levels).

When are transactions irrevocable?

Once a transaction is finalized, you can rely that it has "happened". While the state after the transaction is subject to fault challenges, the transaction itself is fix and immutable.

You can see the code that builds the channels to be written to L1 in [`channel_out.go` (opens new window)](https://github.com/patex-ecosystem/patex-network/blob/main/pt-node/rollup/derive/channel_out.go) and [`channel_builder.go` (opens new window)](https://github.com/patex-ecosystem/patex-network/blob/main/pt-batcher/batcher/channel_builder.go). The transactions themselves are sent in [`op-batcher`'s main loop (opens new window)](https://github.com/patex-ecosystem/patex-network/blob/main/pt-batcher/batcher/driver.go#L286), which calls [`publishStateToL1` (opens new window)](https://github.com/patex-ecosystem/patex-network/blob/main/pt-batcher/batcher/driver.go#L323)

#### **Determining the status of a transaction**

This is the procedure to see a transaction's status. The directions here are for [Foundry (opens new window)](https://book.getfoundry.sh/), but the concept is the same regardless of the method you use.

1. Get the number of the L2 block in which the transaction is recorded.

   ```
   export ETH_RPC_URL=<URL to Patex network>
   cast tx <transaction hash> blockNumber
   ```
2. Get the number of the latest finalized block. If the result is greater than the block number of the transaction, or equal, the transaction is finalized.

   ```
   cast block finalized --field number
   ```
3. Get the number of the latest safe block. If the result is greater than the block number of the transaction, or equal, the transaction is safe.

   ```
   cast block safe --field number
   ```
4. If the transaction isn't finalized or safe, it's unsafe.

### [#](#state-processing) State processing <a href="#state-processing" id="state-processing"></a>

State processing can be divided into two steps:

1. Applying the transaction to the old state to produce the new state, which is performed by [`pt-geth (opens new window)`](https://github.com/patex-ecosystem/patex-chain).
2. Proposing the new [Merkle root (opens new window)](https://en.wikipedia.org/wiki/Merkle_tree) of the state. Merkle roots are used because the actual state is long and would cost too much to write to L1. This step is performed by `pt-proposer`.

#### State changes <a href="#state-changes" id="state-changes"></a>

The state is stored and modified by [`pt-geth (opens new window)`](https://github.com/patex-ecosystem/patex-chain). It is a slightly modified version of the standard [geth (opens new window)](https://geth.ethereum.org/).

#### State root proposals <a href="#state-root-proposals" id="state-root-proposals"></a>

The state root proposals are posted by [`pt-proposer (opens new window)`](https://github.com/patex-ecosystem/patex-network/tree/main/pt-proposer) to [`L2OutputOracle` (opens new window)](https://github.com/patex-ecosystem/contracts-bedrock/blob/main/contracts/L1/L2OutputOracle.sol) on L1.

Output proposals are *not* immediately valid. They can only be considered authoritative once the fault challenge period (7 days on the production network, less on test networks) has passed.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.patex.io/tech/patex-network/transaction-flow.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
