Transaction finality
A Linea transaction moves through two finality states before it is permanently settled on Ethereum.
Transaction lifecycle
When you submit a transaction on Linea, it follows this path: the sequencerSequencer The component of the Lineth execution client responsible for ordering, building, and executing blocks in a way that allows the subsequent ZK proof to be made. It's implemented as a set of plugins extending Linea Besu, including the tracer. There's typically one sequencer per network. validates and includes it in an L2 block, reaching soft finalitySoft finality The point at which a block is confirmed and committed on the L2 itself, before its state is committed on the finalization layer. On Linea Mainnet, soft finality is reached in about 1 second. in approximately 1 second. The coordinatorCoordinator Lineth's coordination module for batching, proof generation, and finality submission. The coordinator monitors block production, manages conflation deadlines, batches blocks, combines batches into blobs, orchestrates execution, compression, and aggregation proofs, and submits proofs and data to the finalization layer. then groups blocks into a batch and submits it to Ethereum. The proverProver The Lineth component that generates ZK proofs of state transitions, handling proof-generation requests from the coordinator and Linea Besu. The prover produces three types of proofs (execution, compression, and aggregation) and combines them into a zk-SNARK that the finalization layer verifies. Provers may be scaled horizontally to meet throughput requirements. generates a ZK proofZero-knowledge proof A cryptographic method that allows an individual to prove that a statement is true without conveying any additional information. This is useful for scaling blockchain networks through rollups, because it reduces the amount of information you have to provide to lower layers. for the batch, which is verified by the Linea rollup contract on L1. Once the L1 block containing the proof is finalized by Ethereum's consensus, the transaction reaches hard finalityHard finality The point at which the L2 state containing a transaction is confirmed and committed on the selected finalization layer, after the corresponding zk-SNARK proof is verified. Hard finality is irreversible..
For the full protocol-level breakdown, see Architecture: Transaction lifecycle.
Soft finality
When the sequencer orders, executes, and seals your transaction into an L2 block, it has reached soft finality. This happens within approximately 1 second, which is Linea's block time.
At soft finality:
- The transaction is confirmed on Linea and visible in your wallet
- Once a transaction reaches soft finality on Linea, it will not be removed or reordered by Linea
- Ethereum (L1) may still reorg, but this does not affect Linea's confirmed state
For most application use cases, including swaps, transfers, and in-app interactions, soft finality is sufficient.
Hard finality
Hard finality is reached when the ZK proof covering your transaction's batch has been verified by the Linea rollup contract on Ethereum, and the L1 block containing that verification transaction is itself finalized by Ethereum's consensus (two epochs / ~12.8 minutes).
At hard finality:
- The transaction is cryptographically proven on Ethereum and inherits its security guarantees
- It is anchored to Ethereum's security guarantees
- The current median time to hard finality is approximately 2 hours. Planned finality improvements are expected to reduce hard finality to under 30 minutes.
- Hard finality should never exceed 16 hours under normal operating conditions
Hard finality is required for cross-layer withdrawals, CEX deposit confirmations, and any use case where Ethereum-level security guarantees are needed.
What you should care about
| Use case | Finality needed | Why |
|---|---|---|
| In-app transactions, swaps | Soft | Once confirmed on Linea, the transaction is in the canonical chain and will not be reversed by the L2 |
| Bridge withdrawals to L1 | Hard | Funds must be provably settled on Ethereum |
| CEX deposits | Hard | Exchanges require irreversibility |
| Onchain gaming, NFT mints | Soft | Speed matters, because Linea does not reorg after soft finality |
How to check finality
Use the finalized tag
Use the finalized tag in JSON-RPC calls to target the latest hard-finalized block:
curl https://rpc.linea.build \
-X POST \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"eth_getBlockByNumber","params":["finalized",false],"id":1}'
The finalized tag is supported by applicable JSON-RPC methods on Linea Mainnet and Linea Sepolia.
Query the rollup contract
As an alternative to the finalized tag, you can query the
Linea L1 rollup contract
to retrieve the value of the current finalized L2 block number stored in the currentL2BlockNumber
variable.
Etherscan reads contract state from the latest L1 block, not the finalized one. The value
shown may therefore be slightly ahead of the actual hard-finalized L2 block number. For exact
finalized state, use the finalized JSON-RPC tag described above.
Prerequisites: Node.js installed.
-
Initialize the project and install the
web3package:npm init -y && npm install web3 -
Create a JavaScript file (for example
index.js) and copy the following code:infoReplace the Infura endpoint with your preferred Ethereum L1 RPC provider. You can use any L1 endpoint, including Infura, Alchemy, or a self-hosted node.
index.jsconst { Web3 } = require("web3")const web3 = new Web3(new Web3.providers.HttpProvider(`https://mainnet.infura.io/v3/<YOUR-API-KEY>`))const lineaRollupAbi = [{"constant":true,"inputs":[],"name":"currentL2BlockNumber","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"}];const lineaRollupAddress = '0xd19d4b5d358258f05d7b411e21a1460d11b0876f';const lineaRollupContract = new web3.eth.Contract(lineaRollupAbi, lineaRollupAddress);async function getFinalizedL2BlockNumber() {try {const currentL2BlockNumber = await lineaRollupContract.methods.currentL2BlockNumber().call();const blockNumberHex = '0x' + BigInt(currentL2BlockNumber).toString(16);console.log('Finalized L2 Block Number:', currentL2BlockNumber.toString());console.log('Finalized L2 Block Number (Hex):', blockNumberHex);return { blockNumber: currentL2BlockNumber, blockNumberHex };} catch (error) {console.error('Error fetching L2 block number:', error);}}getFinalizedL2BlockNumber(); -
Run the script:
node index.js
Next steps
- Understand how the protocol architecture supports finality, including the full transaction lifecycle
- Learn about predictable pricing on Linea
- Run a node to query finality state yourself
- Learn how to submit forced transactions directly to L1