Skip to content

Conversation

pakim249CAL
Copy link
Contributor

@pakim249CAL pakim249CAL commented Apr 30, 2025

Why are these changes needed?

Closes DAINT-383.

Checks

  • I've made sure the tests are passing. Note that there might be a few flaky tests, in that case, please comment that they are not relevant.
  • I've checked the new test coverage and the coverage percentage didn't drop.
  • Testing Strategy
    • Unit tests
    • Integration tests
    • This PR is not tested :(

fix: remove operator state retriever change

fix: readd v1 test
@pakim249CAL pakim249CAL force-pushed the refactor/version-contract-types branch from 9b31539 to d93e21e Compare April 30, 2025 22:56
@pakim249CAL pakim249CAL force-pushed the feat/cert-verifier-v3 branch from 3ec0ab9 to 4d17389 Compare April 30, 2025 23:22
feat: remove old files

refactor: file layout
@pakim249CAL pakim249CAL marked this pull request as ready for review May 2, 2025 15:57
Comment on lines -28 to -36
EigenDATypesV1.NonSignerStakesAndSignature memory nonSignerStakesAndSignature;
nonSignerStakesAndSignature.nonSignerQuorumBitmapIndices = nssas.nonSignerQuorumBitmapIndices;
nonSignerStakesAndSignature.nonSignerPubkeys = nssas.nonSignerPubkeys;
nonSignerStakesAndSignature.quorumApks = nssas.quorumApks;
nonSignerStakesAndSignature.apkG2 = nssas.apkG2;
nonSignerStakesAndSignature.sigma = nssas.sigma;
nonSignerStakesAndSignature.quorumApkIndices = nssas.quorumApkIndices;
nonSignerStakesAndSignature.totalStakeIndices = nssas.totalStakeIndices;
nonSignerStakesAndSignature.nonSignerStakeIndices = nssas.nonSignerStakeIndices;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you look carefully, you will see that none of this is used at all. Only the _nonSignerStakesAndSignature below is. Hence the deletions.

@pakim249CAL pakim249CAL requested a review from ethenotethan May 15, 2025 19:16
@pakim249CAL pakim249CAL marked this pull request as ready for review May 15, 2025 19:16
ethenotethan
ethenotethan previously approved these changes May 15, 2025
Copy link
Contributor

@ethenotethan ethenotethan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

/// @notice Check a DA cert's validity
/// @return status An enum value. Success is always mapped to 1, and other values are errors specific to each CertVerifier.
function checkDACert(bytes calldata certBytes) external view returns (uint8 status);
interface IEigenDACertVerifier is IEigenDACertVerifierBase {
Copy link
Contributor

@litt3 litt3 May 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I chatted with @samlaf about this, and thought deeper about the interface structure here. This is how I think it ought to be:

image
  1. When you call IEigenDACertVerifierRouter.getCertVerifierAt, you get back an address
  2. The address can be cast to an IVersionedCertVerifier
  3. You call IVersionedCertVerifier.getVersion
  4. Based on the version, you know what specific type of verifier you have (IEigenDACertVerifierV3 in this case), so you know what to cast the address to, specifically

And this is the current implementation, as I understand it:

image

I'm not sure what the data flow would look like here. After getting back the address from the router, you'd have to directly cast to the IEigenDACertVerifier type. But that means we're locked into that specific interface: what if we want to create an implementation of the CertVerifier which has different types of blob parameters, for example?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment on lines 15 to 16
/// @return The EigenDA signature verifier contract.
function eigenDASignatureVerifier() external view returns (IEigenDASignatureVerifier);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does this need to be exposed in the interface? Its just called under the hood when verifying the cert right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree actually. This shouldn't be here. I'll remove it.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please add commit links? Makes the reviewer's job much much easier.

import {IEigenDACertVerifierBase} from "src/periphery/cert/interfaces/IEigenDACertVerifierBase.sol";

interface IEigenDACertVerifierRouter is IEigenDACertVerifierBase {
/// @notice Returns the address for a cert verifier at a given reference block number.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// @notice Returns the address for a cert verifier at a given reference block number.
/// @notice Returns the address for the active cert verifier at a given reference block number.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prob need to mention the conditions around this. Does every RBN always return an address? Even RBN=0? Why? What about RBN=super-far-block-in-the-future? Or should this only be called with an RBN that is <= current block?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I personally think that's a bit TMI. If a reader is curious about the edge cases, they can simply read the very short router code and the comments within. But generally, I don't believe general integrators would care about these details since the router handles edge cases already by being initialized with a cert verifier.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that's completely wrong. This is just basic information that any person calling this function should know. I was wondering myself while reading this. And in fact because of this querying I realized that there was a bug where we were allowing people to call this function with an RBN in the future.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(bug being #1518 (comment))

Comment on lines +30 to +31
function getCertVerifierAt(uint32 referenceBlockNumber) public view returns (address) {
return certVerifiers[_findPrecedingRegisteredABN(referenceBlockNumber)];
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this not revert if RBN > block.number?

Copy link
Contributor Author

@pakim249CAL pakim249CAL May 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should not introduce this in this PR because the existing cert verifier does not do this check either. And the block number check seems like something that should be happening in the verifier itself, not in the router. Hence, this suggestion IMO is a suggestion of a change in verification logic

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure I'm following. Where/how does the block number check belong to verifier logic? Its purely for determining which UNIQUE certVerifier NEEDS to attest to the validity of a given cert. Without this check then the validity of a cert can change over time right? First call router with a block BN in the future - cert is valid - then a new cert verifier is activated at the block BN-1. Then check again at block BN - cert is invalid.


import {IEigenDACertVerifierBase} from "src/periphery/cert/interfaces/IEigenDACertVerifierBase.sol";

interface IEigenDACertVerifierRouter is IEigenDACertVerifierBase {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add comment describing what the purpose of this router is: proxy that holds access to past implementations, and where new implementations can only be added in the future, etc.

* @return errParams Additional error parameters
* @return confirmedQuorumsBitmap The bitmap of confirmed quorums
*/
function checkSignaturesAndBuildConfirmedQuorums(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does this say signatureS (with an s)? We're only checking a single (aggregate) signature right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is the same nomenclature as the underlying signature verifier though.

Comment on lines +250 to +261
function checkBlobQuorumsSubset(bytes memory blobQuorumNumbers, uint256 confirmedQuorumsBitmap)
internal
pure
returns (StatusCode err, bytes memory errParams, uint256 blobQuorumsBitmap)
{
blobQuorumsBitmap = BitmapUtils.orderedBytesArrayToBitmap(blobQuorumNumbers);

if (BitmapUtils.isSubsetOf(blobQuorumsBitmap, confirmedQuorumsBitmap)) {
return (StatusCode.SUCCESS, "", blobQuorumsBitmap);
} else {
return (StatusCode.BLOB_QUORUMS_NOT_SUBSET, abi.encode(blobQuorumsBitmap, confirmedQuorumsBitmap), 0);
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why don't you compute the blobQuorumsBitmap outside and then just pass both bitmaps to this function? Feels a lot more natural than having this function return a blobQuorumsBitmap, which shouldnt have anything to do with checking blobQuorumsSubset.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is out of scope of this PR since this is the same logic that was in the cert verifier before.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You've literally complained about every single thing in our current contracts' implementations though. So why does this one fall outside the purview of the refactor to make this contract more readable/understandable?

My POV is that these PRs are the only chance for reviewers to actually read the code and catch things like this. If we don't do them now these minor improvements never happen and the complexity overflows to our customers who have to read this difficult to understand code. And minor improvements compound (positively!) so I do think we should include small changes that require few lines of code to change (of course I agree things that require 50+ lines of code change should be done in separate PRs).

SUCCESS, // Verification succeeded
INVALID_INCLUSION_PROOF, // Merkle inclusion proof is invalid
SECURITY_ASSUMPTIONS_NOT_MET, // Security assumptions not met
BLOB_QUORUMS_NOT_SUBSET, // Blob quorums not a subset of confirmed quorums
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is "confirmedQuorum" something used outside of this contract? Or is it a term you invented? I think "batchSignedQuorums" might make more sense? Otherwise its unclear what/how they got confirmed, and what confirmed means

Copy link
Contributor Author

@pakim249CAL pakim249CAL May 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was the nomenclature of the verification logic previously. I did not invent it.

litt3
litt3 previously approved these changes May 19, 2025
samlaf
samlaf previously requested changes May 19, 2025
Copy link
Collaborator

@samlaf samlaf left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blocking this PR because I'm pretty unhappy with your comments addressal.

Main issue is that I think there's still a bug in the implementation: #1518 (comment)
Bug which you've completely dismissed #1518 (comment)
I might be completely wrong here, but it seems like you just dismissed this without giving it a second's thought.

In order to get this merge and keep the ball moving, I'm happy to merge after the above is fixed (unless I'm completely wrong and the bug isnt actually a bug). But I will add that I expect more of you. You haven't given commit links to addressals, so its very hard to re-review. Plus you've thumbs upped some of my requests without actually addressing them, so I have to go check one by one what is done and what is not... and I generally don't feel confident with this PR because of the bug found above. You also very easily dismiss some of my comments for better code quality like here, despite constantly arguing that our contract code is subpar. The CertVerifierV3 is supposed to be a clean slate, so I don't see why keeping around old shitty code is a valuable strategy when the refactor being asked is very simple and makes for much more readable code.

@samlaf samlaf dismissed their stale review May 19, 2025 20:22

Dismissing my previous "requested changes" review because I'm going to bed but would like this to get merged today if possible.

We synced offline, and requires changes before merging are:

  1. adding check in router that RBN cannot be in future
  2. adding IEigenDACertVerifier interface
@pakim249CAL
Copy link
Contributor Author

Adding cert verifier in future 41a28c4

ICertVerifier interface e3aa022

@samlaf @litt3 @ethenotethan

Copy link
Collaborator

@samlaf samlaf left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Comment on lines +45 to +47
// We disallow adding cert verifiers at the current block number to avoid a race condition of
// adding a cert verifier at the current block and verifying in the same block
if (activationBlockNumber <= block.number) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is actually a great catch! We want cert verification at a block number to be deterministic. That can only be the case if block numbers are activated as a precursor to a given block's execution, which is exactly what our current design does now.

Otherwise you can have in a single block:

  1. tx1 verifies against certVerifier N
  2. certVerifier N+1 gets activated
  3. tx2 verifies same cert as tx1 but against certVerifier N+1

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right! I think these checks really need to be specified up front in a spec because it is hard to know whether this is even an invariant I want to protect without that. We should not just add require statements ad hoc because we can miss interactions across different functions.


import {EigenDATypesV1 as DATypesV1} from "src/core/libraries/v1/EigenDATypesV1.sol";

interface IEigenDACertVerifier is IEigenDACertVerifierBase, IVersionedEigenDACertVerifier {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we should delay any further, but this doesn't match what we had discussed with the interface structure

I think we should do a fast follow to make it match
image

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry I didn't loop you into this convo but I brought up a concern with sam that there didn't seem to be a good place to put an IEigenDACertVerifierV3 interface. It seemed better to name it IEigenDACertVerifier instead, and as they become deprecated we can add the version number and dump it into legacy. This is because we don't want to go back to the version numbers in the main folder for periphery, and there should only be one canonical interface that outside integrators should need to refer to. Version numbers would be confusing and would bring questions about which versions they should use.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My only issue with "legacy" is it sounds like we no longer support it, whereas our clients and proxy need to be backward compatible with ALL versions >= 3 going forward, because we HAVE to assume some customer is running these versions in prod somewhere, and make sure to not break any of them. Something like "LTS" name makes more sense than "legacy" to me. But we can figure out the proper naming and place to put them later.

@pakim249CAL pakim249CAL merged commit dbc01a2 into master May 20, 2025
13 checks passed
@pakim249CAL pakim249CAL deleted the feat/cert-verifier-v3 branch May 20, 2025 18:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants