In the event of a sequencer failure, a user or entity must be able to 1) verifiably reconstruct the L2 state from the last finalized checkpoint and 2) continue to sequence incoming transactions. This provides stronger availability guarantees for the ecosystem and removes a point of failure for enabling unstoppable dapps. A state reconstruction software shall be provided to allow anyone to validate the proposed state roots against published data independently, minimizing the trust placed on the current Linea L2 operator.
Linea Data Submission and Finalization Flow
The Linea operator submits blobs periodically to L1. The smart contract performs some validations and keeps track of the blobs already submitted and accepted on L1. These blobs will represent the L2 transactions execution order and state when the operator submits the corresponding final aggregated proof, which proves the correct transaction execution, data compression, and order. The final aggregation proof finalizes multiple blobs previously submitted and the smart contract ensures that all the data was previously submitted to L1 in the correct order. Blobs are linked together through what we call blob shnarf
, which references parent blob’s shnarf and is verified on by the smart contract when the operator submits blobs.
To maximize the number of L2 transactions in an L1 blob, Linea removes fields that are not necessary to rebuild the state during data compression. For example, a transaction’s signature is replaced by the sender’s address.
Block data sent to L1 in the compressed blob.
BlockInfo {
blockHash: byte[]
blockTimestamp: int
transactions: TxInfo[]
}
TxInfo {
type uint8
nonce uint64
maxPriorityFeePerGas int (aka gasTipCap)
maxFeePerGas int (aka gasFeeCap)
gasLimit int
from [20]byte
to [20]byte
value int
data byte[]
accessList AccessTuple[]
}
AccessTuple {
address: [20]bytes
storageKeys: byte[][]
}
Smart contract events
Blob Data sumission
This event shall be emitted when the Linea operator submits blobs to the smart contract. Multiple blobs can be sent in a single transaction. See bellow event example for a transaction with 3 blobs: [blob_100, blob_101, blo_102]
event DataSubmittedV3(bytes32 parentShnarf, bytes32 indexed shnarf, bytes32 finalStateRootHash)
// event emitted for transaction with 3 blobs: [blob_100, blob_101, blo_102]
DataSubmittedV3(
parentShnarf = blob_99.shnarf,
shnarf = blob_102.shnarf,
finalStateRootHash = blob_102.finalStateRootHash
)
Final Proof Sumission
When the operator submits the final proof that aggregates multiple blobs, if the proof is valid it shall emit the following event
event DataFinalizedV3(
uint256 indexed startBlockNumber,
uint256 indexed endBlockNumber,
bytes32 indexed shnarf,
bytes32 parentStateRootHash,
bytes32 finalStateRootHash
)
Blob submission and finalization can be interleaved, for example, the Operator can send following transactions in order
- data submission:
[blob_100, blob_101, blo_102]
- data submission:
[blob_103, blob_104, blo_105, blob_106, blob_107, blo_108]
- data submission:
[blob_109, blob_110]
- data submission:
[blob_111, blob_112]
- data submission:
[blob_113, blob_114, blob_115]
- final aggregation proof submission that aggregates blobs
[100..110]
that shall emit the following event
DataFinalizedV3(
startBlockNumber = blob_100.startBlockNumber,
endBlockNumber = blob_110.endBlockNumber,
shnarf = blob_110.shnarf,
parentStateRootHash = blob_99.finalStateRootHash,
finalStateRootHash = blob_110.finalStateRootHash
)
State Reconstruction App
To fetch blobs from L1 and replay the transaction’s in the execution client a dedicated software component shall be created, let’s call it the “state recover app”. This app is responsible for fetching Linea blobs data from mainnet, decompressing them, replaying the decompressed blocks in the execution client, and assert that yielded stateRootHash
matches the one finalized on L1. Note, Linea is a type 2 zkEVM with a zk freindly state represetation, so we are refering here to the type2 stateRootHash which is computed by Linea’s state manager, we call it Shomei.
To achieve this, the execution layer needs to be adapted to import and execute block’s transactions without verifying the signature and block header. We will adapt Linea Besu to support this state recovery mode. As besu executes the imported block from L1, Shomei rebuilds its state representation as well.
The initial version of the state recover app will focus on verifying that published data on L1 allows to rebuild the state yielding the same stateRootHash as proven on L1. Also, it only fetches blob data that has been proven and finalized to avoid importing data that can could be reverted. Reverts are not supported in the Shomei state manager and if such case happens it would require reverting Besu and Shomei to a snapshot before the revert.
The state recover app will run inside Besu as a plugin and expose an API to enable state recover mode. Besu shall be running in full sync to mode to execute every block and send the sate diffs to the Shomei. Besu will sync it’s state from the Liena P2P network as regular node until the “stare recover” is enabled. Once the state recovery is enabled, besu will stop synching from P2P network and resume from Blobs sent on L1. The sync from L1 data will continue as long as stateRootHash matches. In case of a stateRootHash discrepancy is found, the application shall stop syching and log an error with identifying which blob yields a different state than expected.
Once state recover is enabled in Besu, the state recover app shall perform the following steps:
- get local chain head block
- find
DataFinalizedV3(startBlockNumber, endBlockNumber, shnarf, ... , finalStateRootHash)
event that contains the head block - the finalized
shnarf
will allow to fetch the canonical list of blobs finalized by that final aggregated proof by followingparentShnarf
field inDataFinalizedV3
events until we reachDataFinalized3.shnarf == DataFinalizedV3.parentShnarf
- decompress the blob data
- call
linea_engine_importBlocksFromBlobs(blocks: BlockInfo[])
method to import the blocks - assert that
stateRootHash
in Shomei state manager matchesDataFinalized.finalStateRootHash
- repeat steps 2…6 for the next
DataFinalizedV3
event
Besu execution client shall implement a new method linea_engine_importBlocksFromBlobs(blocks: BlockInfo[])
for state recover mode to execute transactions and rebuild the state without verifying signatures.
Known Limitations & Requirements
- Some eth_ API methods won’t have the standard behavior for blocks/transactions. For example,
eth_getTransactionByHash
won’t because we can’t calculate the transaction hash without it’s signature. - This initial version requires Linea Smart Contract V6 upgrade, with new DataSubmission events to allow deterministic blob fetching with
parentShnarf
.