In Scroll zkEVM Rollups, transaction execution occurs in two main steps:
Scroll follows a strict threat model for zkEVM provers: if transaction traces exceed row capacity, the zk provers may fail. An unprovable block prevents the entire chain from finalizing and wastes valuable computational resources. To mitigate this, Scroll employs the Circuit Capacity Checker (CCC) in l2-geth to validate transactions before they enter the zkEVM circuits.
The mining process for transactions follows these high-level steps:
A transaction enters the mempool and is then promoted to the worker.
Transactions are processed within the mainLoop()
function, as handled by the following code section:
The ProcessTxs()
function processes transactions one by one according to priority via ProcessTx()
.
Important factor: In scroll-geth, all incoming transactions are processed first, executing EVM operations and state transitions. The Circuit Capacity Checker (CCC) is then executed asynchronously just before block sealing.
Once the block is ready for sealing, the mainLoop()
function proceeds to this code section to commit the block.
NewMinedBlockEvent
.commit()
function, the CCC check is triggered asynchronously.
onBlockFailingCCC
callback.In the current design, the CCC functions primarily act as a post-sealing validation rather than a pre-sealing check. This approach enables faster block production while still enforcing circuit capacity constraints through the reorg mechanism.
The CCC verifies each transaction individually, accumulating row consumption within the Rust library. When the CCC limit is reached, it returns an error
, TxIdx
, and ShouldSkip
, then triggers the failingCallback()
function to initiate a reorg for the CCC case. Example of this code snippet:
https://github.com/scroll-tech/go-ethereum/blob/ac8164f5a4190ff9e536f296195013ea7a4e3e3d/rollup/ccc/async_checker.go#L179-L198
If a single transaction alone could exceed the CCC limit, Scroll removes it entirely from both the mempool and the mined block, as it would not be processed by the zkProvers anyway. If a single transaction is capable of exceeding the CCC limit, the ShouldSkip
flag is set to true
, and during chain reorganization, the transaction is removed from both the block and the mempool.