-
Notifications
You must be signed in to change notification settings - Fork 2.2k
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(protocol): Separate proof verification to a standalone, deployed contract #13794
Conversation
function verifyProof( | ||
bytes32 instance, | ||
TaikoData.TypedProof[] calldata blockProofs, | ||
AddressResolver resolver |
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 not pass in the resolver as this contract shall be a resolver itself.
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.
Well, yes, so I did it on purpose (until there is no setter for AddressManager and wanted to use the 'common' one). Will change tomorrow when addressing the PR findings.
*/ | ||
function verifyProof( | ||
bytes32 instance, | ||
TaikoData.TypedProof[] calldata blockProofs, |
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.
What if you change calldata
to memory
? Will the cost be lower?
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.
No, calldata is much cheaper.
function verifyProof( | ||
bytes32 instance, | ||
TaikoData.TypedProof[] calldata blockProofs, | ||
AddressResolver resolver |
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 remove resolver
as it is implementation specific.
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.
Referred to this in the prev. point.
import {TaikoData} from "./TaikoData.sol"; | ||
import {AddressResolver} from "../common/AddressResolver.sol"; | ||
|
||
interface IProofVerifier { |
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.
rename the file to IProofVerifier.sol
} | ||
|
||
/// @custom:security-contact [email protected] | ||
contract TaikoProofVerifier is TaikoErrors { |
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.
Rename to ProofVerifier
? (and the filename)
@@ -13,6 +13,7 @@ import {TaikoToken} from "../contracts/L1/TaikoToken.sol"; | |||
import {SignalService} from "../contracts/signal/SignalService.sol"; | |||
import {Strings} from "@openzeppelin/contracts/utils/Strings.sol"; | |||
import {TaikoL1TestBase} from "./TaikoL1TestBase.t.sol"; | |||
import {TaikoProofToggleMask, TaikoProofVerifier} from "../contracts/L1/TaikoProofVerifier.sol"; |
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.
TaikoProofToggleMask not used at all.
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.
Indeed, here not, but we need to have it for toggle mask setter during upgrades. If you referred to this line exaclty then sure, i'll delete it, thanks!
import {LibVerifyTrusted} from "./libs/proofTypes/LibVerifyTrusted.sol"; | ||
import {LibVerifyZKP} from "./libs/proofTypes/LibVerifyZKP.sol"; | ||
|
||
library TaikoProofToggleMask { |
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.
Why do we need the code in a library?
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.
Not necessary, just given the fact it's 3 lines and highly related to the ProofVerifier code (so during uprages, this is how we can manage setting the mask) i thought fine setting here. Let me know and i can put it to a different file.
* @param blockProofs Proof array | ||
* @param resolver Current (up-to-date) address resolver | ||
*/ | ||
function verifyProof( |
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.
rename to verifyProofs
?
} | ||
|
||
if(mask != 0) { | ||
revert L1_NOT_ALL_REQ_PROOF_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.
@adaki2004 Lets talk about it tomorrow. But i feel like this current code can only express AND logic, not the OR logic.
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.
This is true however:
-
- This scenario is covered by an option to (over)write the correct fork choice so a 'SuperProver' is still available.
-
- Is somewhat Brecht's answer here answering your question ?
-
- If you mean 'in general' I'd say - the current implementation of this is indeed does not implement an OR relationship, but this is the beauty of this separation. We do not need to handle things just now, it lives as a standalone deployment and in case we need to OR / AND, we can very easily adjust it.
function verifyProofs( | ||
bytes32 instance, | ||
TaikoData.TypedProof[] calldata blockProofs, | ||
AddressResolver resolver | ||
) external; |
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.
function verifyProofs( | |
bytes32 instance, | |
TaikoData.TypedProof[] calldata blockProofs, | |
AddressResolver resolver | |
) external; | |
function verifyProof(bytes32 instance, bytes calldata proof) external; |
What do you think of this API? This way we don't have any dependencies and the proof can really be whatever, and proofs don't have to confirm to TypedProof
which may not always fit.
EDIT: Updated to still have the instance separate. I would say not to pass in the AddressResolver, I think addresses accessed by the verifier should not be set on the protocol AddressResolver, they should store their own data.
external | ||
view | ||
{ | ||
uint16 mask = getToggleMask(); |
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 we should simply remove the mask? A verifier just always hard-codes the logic that needs to be followed. If this logic changes, a different verifier contract should be deployed.
Well, it is maybe useful for testing still, so this could be the testnet verifier contract or something like that. But on mainnet, probably just want to keep it as simple as possible.
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.
Well, makes things more difficult with testing (multi prover vs. exisitng ZK only proofs).
So, i'd just leave it for now - we shall keep it in mind - but since harmless even on mainnet i'd just handle it with low prio - and change it close to mainnet. (?)
@adaki2004 , as mentioned #13791 (comment), I now perfer not splitting verification logics into their own contracts. |
Yes, i got it. |
Closing for now! |
Base branch of this introduced multi-prover possibilities.
This one outsourced proof verification into a separate, deployed contract.
Gas comparison:
Base: (42.074 gwei)
This one (47.418 gwei)
IMPORTANT NOTE
Code to calculate the public
instance
below stayed in LibProving.I decided to leave it there, because:
Evidence
towards the verifier contract and calculate it there, but it adds additional data (overhead) which costs roughly +1K gas.Evidence
we need to upgrade this new Verifier anyways as well..Only issue I see with this is: there will be a completely new proof method which will require only some portion of the
Evidence
so would be useful having that extra data at the verifier contract.With current plans (ZK, SGX and Failsafe signature overwrite) i see it a no issue, but who knows, maybe worth to pass the whole
Evidence
data ?Please let me know what you think @dantaik @Brechtpd