-
Notifications
You must be signed in to change notification settings - Fork 617
feat: only verify new headers #25404
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
alexghr
wants to merge
1
commit into
stack/feat-checkpoint-reward-overrides
from
stack/feat-only-verify-new-headers
+151
−60
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
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
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -114,11 +114,17 @@ library EpochProofLib { | |
| STFLib.prune(); | ||
| } | ||
|
|
||
| Epoch endEpoch = assertAcceptable(_args.start, _args.end); | ||
| (Epoch endEpoch, uint256 provenBeforeSubmission) = assertAcceptable(_args.start, _args.end); | ||
| uint256 firstHeaderToVerify; | ||
| if (provenBeforeSubmission >= _args.start) { | ||
| uint256 provenPrefixLength = provenBeforeSubmission - _args.start + 1; | ||
| uint256 accountedPrefixLength = RewardLib.getLongestProvenLength(endEpoch); | ||
| firstHeaderToVerify = provenPrefixLength < accountedPrefixLength ? provenPrefixLength : accountedPrefixLength; | ||
| } | ||
|
|
||
| // Rehash the supplied headers against storage once, here: the public-input assembly below reads the fee | ||
| // recipient/value out of them and relies on this call having run. | ||
| verifyHeaders(_args.start, _args.end, _args.headers); | ||
| // The skipped calldata prefix is untrusted, but rewards have already consumed it and proof verification binds its | ||
| // fee data to the canonical checkpoint headers. We only verify new headers since the last proof | ||
| verifyHeaders(_args.start, _args.end, _args.headers, firstHeaderToVerify); | ||
|
|
||
| // Verify attestations for the last checkpoint in the epoch | ||
| // -> This serves as training wheels for the public part of the system (proving systems used in public and AVM) | ||
|
|
@@ -162,8 +168,8 @@ library EpochProofLib { | |
| * | ||
| * @dev The fee recipient/value public inputs are sourced from the supplied headers, so this entry point rehashes | ||
| * them against storage before assembling: an off-chain caller must not walk away with public inputs built from | ||
| * unverified fee fields and only discover the mismatch when the on-chain proof reverts. The submit path verifies | ||
| * the headers up front and assembles via computeEpochProofPublicInputs to avoid rehashing them twice. | ||
| * unverified fee fields and only discover the mismatch when the on-chain proof reverts. The submit path separately | ||
| * validates headers that have not already been proven and accounted for. | ||
| * | ||
| * @param _start - The start of the epoch (inclusive) | ||
| * @param _end - The end of the epoch (inclusive) | ||
|
|
@@ -178,7 +184,7 @@ library EpochProofLib { | |
| ProposedHeader[] calldata _headers, | ||
| bytes calldata _blobPublicInputs | ||
| ) internal view returns (bytes32[] memory) { | ||
| verifyHeaders(_start, _end, _headers); | ||
| verifyHeaders(_start, _end, _headers, 0); | ||
| return computeEpochProofPublicInputs(_start, _end, _args, _headers, _blobPublicInputs); | ||
| } | ||
|
|
||
|
|
@@ -396,19 +402,25 @@ library EpochProofLib { | |
| } | ||
|
|
||
| /** | ||
| * @notice Rehashes each provided checkpoint header and requires it to match the stored header hash | ||
| * @notice Rehashes a suffix of the provided checkpoint headers and requires it to match the stored header hashes | ||
| * | ||
| * @param _start The first checkpoint number in the epoch (inclusive) | ||
| * @param _end The last checkpoint number in the epoch (inclusive) | ||
| * @param _headers The proposed headers for each checkpoint in [_start, _end] | ||
| * @param _firstHeaderToVerify The index of the first header that has not already been proven and accounted for | ||
| */ | ||
| function verifyHeaders(uint256 _start, uint256 _end, ProposedHeader[] calldata _headers) private view { | ||
| function verifyHeaders( | ||
| uint256 _start, | ||
| uint256 _end, | ||
| ProposedHeader[] calldata _headers, | ||
| uint256 _firstHeaderToVerify | ||
| ) private view { | ||
| uint256 numCheckpoints = _end - _start + 1; | ||
| require( | ||
| _headers.length == numCheckpoints, Errors.Rollup__InvalidCheckpointHeaderCount(numCheckpoints, _headers.length) | ||
| ); | ||
|
|
||
| for (uint256 i = 0; i < numCheckpoints; i++) { | ||
| for (uint256 i = _firstHeaderToVerify; i < numCheckpoints; i++) { | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this is the whole patch. |
||
| bytes32 expectedHeaderHash = STFLib.getHeaderHash(_start + i); | ||
| bytes32 providedHeaderHash = ProposedHeaderLib.hash(_headers[i]); | ||
| require( | ||
|
|
@@ -439,8 +451,9 @@ library EpochProofLib { | |
| * @param _start The first checkpoint number in the epoch (inclusive) | ||
| * @param _end The last checkpoint number in the epoch (inclusive) | ||
| * @return The epoch number that the proof covers | ||
| * @return The proven checkpoint number observed while checking the submission | ||
| */ | ||
| function assertAcceptable(uint256 _start, uint256 _end) private view returns (Epoch) { | ||
| function assertAcceptable(uint256 _start, uint256 _end) private view returns (Epoch, uint256) { | ||
| RollupStore storage rollupStore = STFLib.getStorage(); | ||
|
|
||
| Epoch startEpoch = STFLib.getEpochForCheckpoint(_start); | ||
|
|
@@ -465,7 +478,8 @@ library EpochProofLib { | |
| bool isStartOfEpoch = _start == 1 || parentEpoch <= startEpoch - Epoch.wrap(1); | ||
| require(isStartOfEpoch, Errors.Rollup__StartIsNotFirstCheckpointOfEpoch()); | ||
|
|
||
| bool isStartBuildingOnProven = _start - 1 <= rollupStore.tips.getProven(); | ||
| uint256 provenBeforeSubmission = rollupStore.tips.getProven(); | ||
| bool isStartBuildingOnProven = _start - 1 <= provenBeforeSubmission; | ||
| require(isStartBuildingOnProven, Errors.Rollup__StartIsNotBuildingOnProven()); | ||
|
|
||
| bool claimedNumCheckpointsInEpoch = _end - _start + 1 <= Constants.MAX_CHECKPOINTS_PER_EPOCH; | ||
|
|
@@ -474,7 +488,7 @@ library EpochProofLib { | |
| Errors.Rollup__TooManyCheckpointsInEpoch(Constants.MAX_CHECKPOINTS_PER_EPOCH, _end - _start) | ||
| ); | ||
|
|
||
| return endEpoch; | ||
| return (endEpoch, provenBeforeSubmission); | ||
| } | ||
|
|
||
| /** | ||
|
|
@@ -485,8 +499,8 @@ library EpochProofLib { | |
| * 2. Assembling the public inputs for the root rollup circuit | ||
| * 3. Verifying the validity proof against the assembled public inputs using the configured verifier | ||
| * | ||
| * @dev Assumes the caller has already verified the supplied checkpoint headers against storage, so assembly skips | ||
| * rehashing them. | ||
| * @dev Assumes the caller has completed the submit path's required header checks, so assembly does not rehash | ||
| * headers. | ||
| * | ||
| * @dev Errors Thrown: | ||
| * - Rollup__InvalidBlobProof: Batched blob proof verification failed | ||
|
|
||
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
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
Oops, something went wrong.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When would these two differ?