chore: v6 L1 updates integration branch - #25401
Merged
Merged
Conversation
spalladino
force-pushed
the
project/v6-l1-updates
branch
from
September 8, 2026 21:56
457cfb7 to
8af2277
Compare
spalladino
marked this pull request as ready for review
September 9, 2026 13:53
spalladino
requested review from
iAmMichaelConnor and
koenmtb1
as code owners
September 9, 2026 21:22
spalladino
force-pushed
the
project/v6-l1-updates
branch
from
September 10, 2026 16:36
cf0d363 to
af732b3
Compare
spalladino
approved these changes
Sep 10, 2026
spalladino
enabled auto-merge
September 10, 2026 16:54
spalladino
force-pushed
the
project/v6-l1-updates
branch
from
September 10, 2026 16:57
af732b3 to
c751592
Compare
## Summary - reuse the current epoch already computed during proof acceptance - cache the packed chain tips for full-proof detection and proven-tip advancement - read the known-existing next checkpoint slot directly instead of repeating checkpoint-number validation - update the gas benchmark results; this saves 1,053 gas per proof submission versus the parent PR implementation, leaving roughly 3,729 gas of net overhead versus the pre-PR baseline ## Tests - `forge fmt --check` - `forge test --offline --match-contract MultiProofTest` - `forge test --offline --match-contract HandleRewardsTest` - `python3 scripts/gas_benchmarks.py`
There was no on-chain record of who proved a given checkpoint. `L2ProofVerified` carries the prover, but there is nothing queryable, and the reward accounting only tracks per-epoch submissions. Adds a `firstProvenBy` mapping to `RollupStore`, written in `submitEpochRootProof` whenever a proof advances the proven tip. Only the checkpoint the proof ended at gets an entry, so entries are sparse: proofs of 1-10 and then 11-20 record entries at 10 and 20, with nothing in between. Because a proof of an already proven range cannot advance the tip, it never reaches the write and the original prover is preserved. `getFirstProvenBy(checkpointNumber)` resolves an arbitrary checkpoint by walking forward to the next entry. The first entry at or after the requested number belongs to the earliest proof that covered it, since the proven tip only ever advances; the walk is bounded by the epoch duration because a proof covers at most one epoch. The mapping stores the address in its lower 160 bits and sets bit 160 as a presence flag, so `address(0)` remains distinguishable from a sparse, unwritten entry. The getter reverts with `Rollup__CheckpointNotProven` for checkpoint 0 or a checkpoint ahead of the proven tip. The getter is routed through `RewardExtLib` (alongside the other STF getters) rather than inlined in `Rollup.sol` — the Rollup deployed bytecode is within 800 bytes of the size limit. New `IRollup.getFirstProvenBy(uint256) returns (address)` and `Errors.Rollup__CheckpointNotProven(uint256 proven, uint256 requested)`. Fixes A-1927
This PR changes the checkpoint header verification from always verifying from index 0 (in the epoch) up to the current proven tip to verifying from the last proven index to up the new proven tip. This reduces the gas cost for partial epoch proofs by about ~3-4k per previously verified checkpoint header. Fix A-1802
Further optimize the proof submission flow: 1. hash haeader from calldata instead of memory (avoids a copy) 2. read header hashes in bulk (avoid checks run on every iteration of a loop) 3. reuse already read header hashes Other than submitting a proof of the first checkpoint (which is +2k gas compared to next) every other scenario is cheaper than the code on next. | Scenario | Current gas | vs #25404 | vs origin/next | |------------------|-------------|--------------------|--------------------| | 1 fresh | 663,452 | −1,506 (−0.23%) | +2,243 (+0.34%) | | 8 fresh | 965,328 | −21,594 (−2.19%) | −14,985 (−1.53%) | | 8→16 extension | 930,160 | −28,490 (−2.97%) | −57,867 (−5.86%) | | 16 fresh | 1,256,565 | −44,700 (−3.44%) | −34,869 (−2.70%) | | 32 fresh | 1,729,965 | −91,388 (−5.02%) | −75,071 (−4.16%) |
This PR optimized the partial proof flow by enabling provers to only send the headers for new checkpoints that are proven by the proof. The provers can send smaller payloads (just fees + coinbase) for the already proven checkpoints (which also have their rewards accounted for). This PR slightly increases gas costs for full epoch proofs (because of all the new checks we have to run on the proven-prefix) but it reduces gas costs on partial epoch proofs that build on previously submitted proof by about ~3.5K/already proven checkpoint (so in the scneario where we prove 8 checkpoints and then another 8 checkpoints we save approx 27k on the second proof) This PR requires changes to be made to aztec-node to make it compatible with the new contracts.
spalladino
force-pushed
the
project/v6-l1-updates
branch
from
September 10, 2026 17:23
c751592 to
6dce8ee
Compare
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Rebuilds the v6 L1 integration branch on the latest
nextusing cherry-picked commits.This includes AZIPs 23, 24, 25 (all approved in last ACD), plus gas optimizations and refactors to work around the Rollup contract size limit.
Included PRs
Gas
The reports were regenerated after removing reward overrides. The
nextcomparison is unchanged because no L1 contract files changed onnextsince this branch point.Epoch benchmark
No validators
nextproposeavgsubmitEpochRootProofavgsubmitEpochRootProofmaxsubmitEpochRootProofcalldata bytessetupEpochavg100 validators
nextproposeavgsubmitEpochRootProofavgsubmitEpochRootProofmaxsubmitEpochRootProofcalldata bytesaggregate3avgsetupEpochavgPartial epoch proof benchmark
nextThe partial proof benchmark uses the mock epoch proof verifier; real ZK verification and top-level transaction calldata gas are excluded.
Tracked function gas report
The fixed
RollupTestreport now records a 41,936-byte preheated deployment, a 393,723-gas median forsubmitEpochRootProof(), and unchanged 283,135-gas median forpropose(). The owner-only setters pay one extra delegatecall after moving fee and reward admin paths intoRewardExtLib; hot proposal paths still callFeeLibdirectly.Contract size
Without the admin-path extraction, the reward-free integration stack still produces a 24,744-byte
Rollup, 168 bytes over EIP-170. Moving those paths intoRewardExtLibbrings runtime bytecode to 22,670 bytes, 1,906 under the 24,576-byte limit.CI checks this directly under both the default and production Foundry profiles via
scripts/check_contract_sizes.sh.