-
Notifications
You must be signed in to change notification settings - Fork 18
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
feat: sgx verifier #58
base: main
Are you sure you want to change the base?
Conversation
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.
How will we deal with protocol upgrades (multiple batch versions)?
Will we deploy multiple instances of SGXVerifier
with different attestationVerifier
contracts? Or will they reuse the same attestationVerifier
?
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.
We will have a MultipleVersionRollupVerifier
contract deployed only for SGXVerifier
and the version managed in this contract. So each time we upgrade batch version, both MultipleVersionRollupVerifier
for zkp and tee should be updated.
For different SGXVerifier
, I believe we can share the same attestationVerifier
.
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.
For different SGXVerifier, I believe we can share the same attestationVerifier.
I'm not sure. Basically we'd need batchVersion ==> mrEnclave
mapping implemented by MultipleVersionRollupVerifier
. (In practice it's batchVersion ==> sgxVerifier ==> attestationVerifier
.)
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.
(In practice it's
batchVersion
==>sgxVerifier
==>attestationVerifier
.)
true, we can decide it later. It is only related to deployment.
src/L1/rollup/ScrollChain.sol
Outdated
// Pop finalized and non-skipped message from L1MessageQueue. | ||
_finalizePoppedL1Messages(_totalL1MessagesPoppedOverall); | ||
|
||
emit VerifyBatchWithTee(_batchIndex); | ||
emit FinalizeBatch(_batchIndex, _batchHash, _postStateRoot, _withdrawRoot); |
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.
Just a note to self (and to @colinlyguo): This will keep the semantics of FinalizeBatch
as before, but indexers might still need to be updated if they want to decode the transaction calldata. (Maybe only relevant for commit, not finalize.)
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.
chain-monitor (does not monitor batch finalize events, only monitors finalize deposit/withdraw events), bridge-history (withdraw proof), and l2geth-verifier (finalize batch verification) are compatible. I believe sync-from-DA feature is also compatible.
We can keep a close eye on monitoring these components after the upgrade as well.
src/L1/rollup/ScrollChain.sol
Outdated
finalizedStateRoots[_batchIndex] = _postStateRoot; | ||
withdrawRoots[_batchIndex] = _withdrawRoot; |
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.
These are not finalized at this point. Is there a risk that clients will incorrectly rely on unfinalized roots?
The question is: Should we prevent this programmatically / through renaming? Or should we just use documentation to communicate that clients must use lastFinalizedBatchIndex
or isBatchFinalized
before reading from finalizedStateRoots
.
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.
We can override the function of finalizedStateRoots
and withdrawRoots
, to make it return bytes(0)
for all indices after lastFinalizedBatchIndex
.
src/L1/rollup/ScrollChain.sol
Outdated
emit ResolveState(state.batchIndex, state.stateRoot, state.withdrawRoot); | ||
|
||
// reset zkp verified batch index, zk prover need to reprove everything after this batch | ||
lastZkpVerifiedBatchIndex = state.batchIndex; |
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.
@colinlyguo any thoughts what we'd need to add to be able to recover from this relatively painlessly? Maybe just listen to ResolveState
events in rollup-relayer
and update db accordingly? (Though in this case most likely we'll need to fix either zk or sgx prover.)
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.
Maybe just listen to ResolveState events in rollup-relayer and update db accordingly
agree.
Though in this case most likely we'll need to fix either zk or sgx prover.
BeforeResolveState
- if no need to fix zk prover or it has been fixed, then can rely on auto-recover of rollup-relayer.
- if we just ResolveState first then fix zk prover, then add a flag to halt finalization.
point me out if missing any corner cases pls.
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.
So with MockFinalize
mode we'd still need to run an SGX prover?
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.
Yeah, running a SGX prover is cheap. I think it is ok to run it in sepolia.
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.
Since the verifier is set as address(0)
, does that mean that we just need someone to call finalizeBundleWithTeeProof
(e.g. in rollup-relayer
, when fake finalize mode is enabled), and the verifyBundleProof
call will be a no-op?
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.
seems that I forget to change the constructor. The verifier
should not be set as address(0)
. I did change ScrollChainMockBlob
since it is used in unit tests. I'm thinking we should also add unit tests for ScrollChainMockFinalize
.
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.
I see two options two make ScrollChainMockFinalize
useful:
- Use
address(0)
as verifier so that we bypass the whole verification step. Then,rollup-relayer
can callfinalizeBundleWithTeeProof
when fake finalization is enabled. - Keep the verifier, but somehow bypass
verifyAttestation
, so that we can run the "SGX" prover on normal hardware. (Setting up SGX hardware is too complex for a devnet.)
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.
For option 2, we need test the feature in sepolia first before goes to mainnet. After test we can do anything we like, like bypass verifyAttestation
or fake finalization on tee proof.
import {BytesUtils} from "./utils/BytesUtils.sol"; | ||
|
||
/// @dev This contract is modified from https://github.com/automata-network/scroll-prover/blob/demo/contracts/src/core/AttestationVerifier.sol | ||
contract AttestationVerifier is Ownable, IAttestationVerifier { |
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.
any doc about this verifier?
src/L1/rollup/ScrollChain.sol
Outdated
function initializeV2() external reinitializer(2) { | ||
uint256 cachedIndex = lastZkpVerifiedBatchIndex; | ||
lastTeeVerifiedBatchIndex = cachedIndex; | ||
emit VerifyBatchWithTee(cachedIndex); |
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.
Would another event name to differentiate from real tee verify a better choice?
); | ||
|
||
/// @notice Emitted when a batch is verified by tee proof | ||
/// @dev Tee proof always comes after zk proof. If they match, the state root and withdraw root are the same. |
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.
/// @dev Tee proof always comes after zk proof. If they match, the state root and withdraw root are the same. |
/************************* | ||
* Public View Functions * | ||
*************************/ | ||
|
||
/// @return The latest finalized batch index. | ||
/// @return The latest finalized batch index (both zkp and tee verified). |
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.
(both zkp and tee verified)
This is not always true, right?
|
||
/// @notice The timestamp to delay proof when we only has one proof type. | ||
/// @dev This is enabled after Euclid upgrade. | ||
uint256 public proofDelayTimestamp; |
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.
uint256 public proofDelayTimestamp; | |
uint256 public emergencyFinalizationDelay; |
The word "timestamp" is usually used for instants, not durations
/********************** | ||
* Internal Functions * | ||
**********************/ | ||
|
||
/// @dev Internal function to enable proof types. | ||
/// @param mask The mask for new enabled proof types. | ||
function _enableProofTypes(uint256 mask) internal { |
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.
Should require that mask <= 3
@@ -172,6 +260,14 @@ contract ScrollChain is OwnableUpgradeable, PausableUpgradeable, IScrollChain { | |||
_; | |||
} | |||
|
|||
modifier whenFinalizeNotPaused(ProofType proofType) { |
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.
We should also consider paused
here (operator pause) as a 3rd case
/// @notice Update the bundle size | ||
/// @param size The new bundle size. | ||
/// @param batchIndex The start batch index for new bundle size. | ||
function updateBundleSize(uint128 size, uint128 batchIndex) external onlyOwner { |
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.
Is there a risk that we (accidentally) set a very large index, and then we have no way to change this?
); | ||
|
||
// initialize the first element in the array | ||
bundleSize.push(BundleSizeStruct(_bundleSize, uint128(cachedIndex))); |
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.
How will the upgrade happen? Basically right after executing the upgrade we'll need to reset all pending bundles in the rollup-relayer, right?
No description provided.