You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
FullZKEVMWithSuite() is a utility function that creates a new *ZkEvm with a given compilation suite. However, it assigns its result to the package-level global fullZkEvm before returning (fullZkEvm = NewZkEVM(settings)). This silently overwrites the cached instance that FullZkEvm() guards with sync.Once.
During make setup (all circuits), execution-limitless calls NewLimitlessZkEVM() → FullZKEVMWithSuite(..., nil), which creates a ZkEvm with RecursionCompiledIOP = nil (because PostRecursionCompilationSuite is nil) and overwrites the global. When invalidity-precompile-logs runs next, FullZkEvm() returns the corrupted instance (the sync.Once already fired), and BadPrecompileCircuit.Allocate() panics on config.ZkEvmComp.NumRounds().
Changed FullZKEVMWithSuite() to return a local value (return NewZkEVM(settings)) instead of writing to the global. Only the sync.Once closures in FullZkEvm(), FullZkEvmLarge(), and FullZkEVMCheckOnly() should write to their respective globals.
Why this wasn't caught before
The bug existed since FullZKEVMWithSuite was extracted into its own function — the global assignment came along as a copy-paste artifact. It was hidden because nothing reused FullZkEvm() during setup until the invalidity circuits were added. The invalidity-precompile circuits are the first to call FullZkEvm() after the corrupted write, which exposed the nil pointer.
Checklist
I wrote new tests for my new core changes.
I have successfully ran tests, style checker and build against my new changes locally.
If this change is deployed to any environment (including Devnet), E2E test coverage exists or is included in this
PR.
I have informed the team of any breaking changes if there are any.
Note
Medium Risk
Touches zkEVM construction/memoization logic used across prover setups; a mistake here could change which compiled instance is reused and lead to hard-to-debug runtime panics. Change is small and covered by a targeted regression test.
Overview
Stops FullZKEVMWithSuite from overwriting the package-level fullZkEvm cache by returning NewZkEVM(settings) directly instead of assigning to the global.
Adds a regression test (TestFullZKEVMWithSuiteNoGlobalOverwrite) to ensure calling FullZKEVMWithSuite does not mutate the memoized fullZkEvm instance.
Reviewed by Cursor Bugbot for commit 783eb17. Bugbot is set up for automated code reviews on this repo. Configure here.
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR fixes a critical caching bug in the prover’s zkEVM builder by removing an unintended package-global overwrite from FullZKEVMWithSuite(), ensuring only the sync.Once-guarded entrypoints populate their respective cached instances.
Changes:
Stop FullZKEVMWithSuite() from mutating the package-level fullZkEvm global.
Ensure FullZKEVMWithSuite() simply constructs and returns a fresh *ZkEvm, leaving memoization solely to FullZkEvm(), FullZkEvmLarge(), and FullZkEVMCheckOnly().
✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 77.24%. Comparing base (b56778e) to head (7dc0e58). ⚠️ Report is 337 commits behind head on main.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
FullZKEVMWithSuite() is a utility function that creates a new *ZkEvm with a given compilation suite. However, it assigns its result to the package-level global fullZkEvm before returning (fullZkEvm = NewZkEVM(settings)). This silently overwrites the cached instance that FullZkEvm() guards with sync.Once.
During make setup (all circuits), execution-limitless calls NewLimitlessZkEVM() → FullZKEVMWithSuite(..., nil), which creates a ZkEvm with RecursionCompiledIOP = nil (because PostRecursionCompilationSuite is nil) and overwrites the global. When invalidity-precompile-logs runs next, FullZkEvm() returns the corrupted instance (the sync.Once already fired), and BadPrecompileCircuit.Allocate() panics on config.ZkEvmComp.NumRounds().
Error
Fix
Changed FullZKEVMWithSuite() to return a local value (return NewZkEVM(settings)) instead of writing to the global. Only the sync.Once closures in FullZkEvm(), FullZkEvmLarge(), and FullZkEVMCheckOnly() should write to their respective globals.
Why this wasn't caught before
The bug existed since FullZKEVMWithSuite was extracted into its own function — the global assignment came along as a copy-paste artifact. It was hidden because nothing reused FullZkEvm() during setup until the invalidity circuits were added. The invalidity-precompile circuits are the first to call FullZkEvm() after the corrupted write, which exposed the nil pointer.
Checklist
PR.
Note
Medium Risk
Touches zkEVM construction/memoization logic used across prover setups; a mistake here could change which compiled instance is reused and lead to hard-to-debug runtime panics. Change is small and covered by a targeted regression test.
Overview
Stops
FullZKEVMWithSuitefrom overwriting the package-levelfullZkEvmcache by returningNewZkEVM(settings)directly instead of assigning to the global.Adds a regression test (
TestFullZKEVMWithSuiteNoGlobalOverwrite) to ensure callingFullZKEVMWithSuitedoes not mutate the memoizedfullZkEvminstance.Reviewed by Cursor Bugbot for commit 783eb17. Bugbot is set up for automated code reviews on this repo. Configure here.