-
Notifications
You must be signed in to change notification settings - Fork 29
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
Full Multi-query support onchain #321
base: master
Are you sure you want to change the base?
Conversation
Pull Request Test Coverage Report for Build 13087224067Details
💛 - Coveralls |
b70f050
to
a02592c
Compare
string[] _supportedCircuitIds; | ||
IState state; | ||
uint256[1] __gap; |
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.
Need a small comment why we put this __gap
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.
Validator will always work only with one State contract. Why do you need to pass it as a param to methods and removed it from here?
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.
Yes, that is what was true before we started transferring cross-chain timestamps of state and GIST.
But, as long as now Verifier should insert cross-chain messages into State contracts (Validator is not efficient to do the same instead), it would be a duplication of the link to the State contract in both Validator and Verifier. At least in terms of contract init, It's better only one component to keep the link.
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.
To me it looks strange and a place for a calling contract / EOA to make a mistake. The less possibilities to make a mistake - the better.
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 please revert this part and remove passing of state contract address from the verify function.
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.
Done
require(length > 0, "Length should be greater than 0"); | ||
require(length <= limit, "Length limit exceeded"); | ||
require(start < arrLength, "Start index out of bounds"); | ||
if (length == 0) { |
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.
require
allows passing error as a second param instead of a string. And I think require statements are much easier to read than ifs, especially in else-if cases. So unless there are side effects of doing so (e.g. much higher gas cost or unexpected behavior in specific cases like explained in the docs) I would use require
.
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.
Custom errors save more gas than using strings in require error messages. This is because the error message in custom errors is encoded into the bytecode of the contract, so it does not need to be stored on the blockchain.
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.
The gas cost is almost the same if message length < 32 bytes as far as I remember, however for custom errors logging is better as we can add params. So I would add params like "length", "limit" etc.
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.
Yes, I'll add some more params for the user to know this limits and have more deails about these errors.
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, I was proposing to use:
require(length > 0, LenghtShouldBeGreaterThanZero());
instead of:
if (length == 0) {
revert LenghtShouldBeGreaterThanZero();
}
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 this case we could even do this if it's question to compact it in 1 line
if (length == 0) revert LenghtShouldBeGreaterThanZero();
contracts/verifiers/Verifier.sol
Outdated
function _getRequestType(uint256 requestId) internal pure returns (uint8) { | ||
// 0x0000000000000000 - prefix for old uint64 requests | ||
// 0x0000000000000001 - prefix for keccak256 cut to fit in the remaining 192 bits | ||
return uint8(requestId >> 192); |
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 dedicated 64 bits to this, why return just 8? If all the other bits are for flags, then maybe we should move 01 to the beginning of the prefix, so it becomes 0x0100000000000000
and the rest of the bytes (7) would be for flags. @vmidyllic @demonsh what do you think?
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 my opinion it seems more natural like you propose. In fact it was the first approach and we changed it.
I have implemented it like this. First byte 0x00
for previous uint64
requestIds. 0x01
for new uint256
requestIds.
We will reserve the next 7 bytes for future potential updates and then the remaining 24 bytes (192 bits) are for requestId hash from request params.
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.
Thanks for quick change. But I just recalled why I though highest byte was not a good idea, because this byte is not fully usable, e.f. 0xFF would make number not fit into the field. Actually max byte there is ~0x29. So we might want to shift this type to second byte. So, let's do 0x0001000000000000
prefix for keccak. And do not use most significant byte there at all (keep first byte 0x00 always).
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.
Done
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.
Please make state contract preconfigured in validators. See rationale in the comments.
bytes calldata proof, | ||
bytes calldata params, | ||
address sender, | ||
IState state, |
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.
are we sure that we need state contract as an explicit parameter and not as a part of 'params' or other 'generic' platform?
What if state contract is not neede for some specific key validation / etc .
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.
as well as expectedNonce
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.
Changed as we agreed
contracts/interfaces/IVerifier.sol
Outdated
* @param proof proof to verify. | ||
*/ | ||
struct AuthResponse { | ||
string authType; //zkp-auth-v2, zkp-auth-v3, etc. |
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.
let's remove this comment until it is not yet decided how types will be named
* @param metadata Metadata for the multiRequest. Empty in first version. | ||
*/ | ||
struct MultiRequest { | ||
uint256 multiRequestId; |
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'm not sure what will be a protocol value for multiRequestId
super.__EmbeddedVerifier_init(initialOwner, state); | ||
} | ||
|
||
function _beforeProofSubmit( |
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.
beforeTransfer / afterTransfer are standard hooks for erc20, that is why we named ours accordingly!
uint256[10] circuitQueryHash; | ||
} | ||
|
||
string public constant VERSION = "1.0.0-beta"; |
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 guess right syntax is "1.0.0-beta.1"
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.
Fixed
settings: { | ||
optimizer: { | ||
enabled: true, | ||
runs: 200, |
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.
are we sure that current production version has '200' runs and not '1000' , won't it influence the upgrade
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.
Currently we were not working with optimizer in the deployments we have. We achieved max limit size of the contract bytecode and with this specific settings for every contract that is at maximum limit size it reduces in most of the cases to half of the size and we are able to deploy them.
contracts/verifiers/Verifier.sol
Outdated
); | ||
|
||
if ( | ||
keccak256(abi.encodePacked(authResponse.authMethod)) == | ||
keccak256(abi.encodePacked("authV2")) |
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 could have it precalculated as a constant.
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.
Done
keccak256(abi.encodePacked("challenge")) | ||
) { | ||
bytes32 expectedNonce = keccak256(abi.encode(sender, responses)) & | ||
0x0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; |
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 think it should be 0x00FFFF... if we want to zero out the first byte.
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.
Only with the first position as 0 that is 4 bits we have 252 bits remaining for the calculation that fits in a field number. But I could do it with 1 byte if you think it's better an we we'll use 248 bits then.
df615af
to
707a770
Compare
Implement multi-query support similar to existing requests now in Universal Verifier.
Query
) independently and in the same way we are managing Requests in ZKPVerifierBase now (setQuery, getQuery, …). Avoid ZKP and generalize methods in Requests. setRequest, getRequest, submitResponse, …address user
touint256 userID
to keep identifier of the user.userAddress
anduserID
. In this first version 1 userID will have only 1 address? Review best approach or if we have to keep an array of addresses.linkID
between the Requests and Auth of the sameQuery
.uint64
touint256
.Link to Tech Spec for changes: https://www.notion.so/privado-id/Multi-query-Tech-Spec-13d4f86a875180e68fc8e3fa5362805e