Authors: The Scroll Security Council.
Overview
On 8th August 2025, the Scroll team received alerts of proving failure. The root cause turned out to be a guest program completeness bug in the EuclidV2 version of the prover. A fix was promptly implemented by the Scroll team and executed by the Scroll Security Council. The issue prolonged finality and delayed withdrawals, but no user funds were at risk.
Summary of the Bug
In previous versions of the Scroll protocol (pre-Euclid), state accounts used to store the bytecode size to make this value available to the halo2 provers in a cheap way.
This optimization was deprecated in Euclid, which meant that the prover guest program (revm) needed to manually initialize each instance of code_size
. This was missing in some 7702-related code paths (ref):
authority_acc.info.code_hash = hash;
authority_acc.info.code = Some(bytecode);
As a result, Scroll’s version of the extcodesize
opcode would return 0
instead of the actual code size.
This has led to divergence between the sequencer and the prover for some delegate-and-call transactions. For example, this transaction reverted on l2geth but did not revert in the prover, leading to diverging state roots. The prover failed with a state root mismatch error, and Scroll stopped finalizing blocks.
Fix Review
Based on the analysis above, this specific issue could have been solved by correctly setting the code size field:
+ authority_acc.info.code_size = bytecode.len();
authority_acc.info.code_hash = hash;
authority_acc.info.code = Some(bytecode);
However, we opted instead to directly upgrade to the Feynman version of the prover guest program (v0.5.2). This version deprecated most of our revm fork, using scroll-revm instead, which uses upstream revm as an SDK, ensuring a high level of spec compatibility with Ethereum. This version, while scheduled for Feynman, is also backward-compatible with EuclidV2.
Timeline
The below timestamps are in UTC.
-
8th August 9pm: The Scroll team received monitoring alerts about chunk proving failure.
-
8th August 10pm: It was confirmed that the latest circuit version v0.5.2 can prove the chunks with results identical to l2geth.
-
8th August 11pm: A new verifier contract was deployed, configured to use v0.5.2 with protocol version v7 (i.e. EuclidV2).
-
9th August 9am: All pending chunks/batches/bundles were re-proven using the updated prover versions. The resulting bundle proofs were manually tested against the new verifier.
-
9th August 11am: The verifier upgrade transaction was submitted to the Security Council.
-
9th August 5pm: The Security Council approved the transaction. The transaction was executed, and all pending proven bundles were finalized soon after.