-
Notifications
You must be signed in to change notification settings - Fork 208
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
Cache verifier callers #1331
Cache verifier callers #1331
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,6 +3,7 @@ package verification | |
import ( | ||
"context" | ||
"fmt" | ||
"sync" | ||
"sync/atomic" | ||
"time" | ||
|
||
|
@@ -55,6 +56,8 @@ type CertVerifier struct { | |
latestBlockNumber atomic.Uint64 | ||
// atomic bool, so that only a single goroutine is polling the internal client with BlockNumber() calls at any given time | ||
pollingActive atomic.Bool | ||
// maps contract address to a ContractEigenDACertVerifierCaller object | ||
verifierCallers sync.Map | ||
} | ||
|
||
var _ ICertVerifier = &CertVerifier{} | ||
|
@@ -121,11 +124,9 @@ func (cv *CertVerifier) VerifyCertV2FromSignedBatch( | |
return fmt.Errorf("wait for block number: %w", err) | ||
} | ||
|
||
certVerifierCaller, err := verifierBindings.NewContractEigenDACertVerifierCaller( | ||
gethcommon.HexToAddress(certVerifierAddress), | ||
cv.ethClient) | ||
certVerifierCaller, err := cv.getVerifierCaller(certVerifierAddress) | ||
if err != nil { | ||
return fmt.Errorf("bind to verifier contract at %s: %w", certVerifierAddress, err) | ||
return fmt.Errorf("get verifier caller: %w", err) | ||
} | ||
|
||
err = certVerifierCaller.VerifyDACertV2FromSignedBatch( | ||
|
@@ -159,13 +160,9 @@ func (cv *CertVerifier) VerifyCertV2( | |
return fmt.Errorf("wait for block number: %w", err) | ||
} | ||
|
||
// don't try to bind to the address until AFTER waiting for the block number. if you try to bind too early, the | ||
// contract might not exist yet | ||
certVerifierCaller, err := verifierBindings.NewContractEigenDACertVerifierCaller( | ||
gethcommon.HexToAddress(certVerifierAddress), | ||
cv.ethClient) | ||
certVerifierCaller, err := cv.getVerifierCaller(certVerifierAddress) | ||
if err != nil { | ||
return fmt.Errorf("bind to verifier contract at %s: %w", certVerifierAddress, err) | ||
return fmt.Errorf("get verifier caller: %w", err) | ||
} | ||
|
||
err = certVerifierCaller.VerifyDACertV2( | ||
|
@@ -206,11 +203,9 @@ func (cv *CertVerifier) GetNonSignerStakesAndSignature( | |
return nil, fmt.Errorf("wait for block number: %w", err) | ||
} | ||
|
||
certVerifierCaller, err := verifierBindings.NewContractEigenDACertVerifierCaller( | ||
gethcommon.HexToAddress(certVerifierAddress), | ||
cv.ethClient) | ||
certVerifierCaller, err := cv.getVerifierCaller(certVerifierAddress) | ||
if err != nil { | ||
return nil, fmt.Errorf("bind to verifier contract at %s: %w", certVerifierAddress, err) | ||
return nil, fmt.Errorf("get verifier caller: %w", err) | ||
} | ||
|
||
nonSignerStakesAndSignature, err := certVerifierCaller.GetNonSignerStakesAndSignature( | ||
|
@@ -227,11 +222,9 @@ func (cv *CertVerifier) GetNonSignerStakesAndSignature( | |
// GetQuorumNumbersRequired queries the cert verifier contract for the configured set of quorum numbers that must | ||
// be set in the BlobHeader, and verified in VerifyDACertV2 and verifyDACertV2FromSignedBatch | ||
func (cv *CertVerifier) GetQuorumNumbersRequired(ctx context.Context, certVerifierAddress string) ([]uint8, error) { | ||
certVerifierCaller, err := verifierBindings.NewContractEigenDACertVerifierCaller( | ||
gethcommon.HexToAddress(certVerifierAddress), | ||
cv.ethClient) | ||
certVerifierCaller, err := cv.getVerifierCaller(certVerifierAddress) | ||
if err != nil { | ||
return nil, fmt.Errorf("bind to verifier contract at %s: %w", certVerifierAddress, err) | ||
return nil, fmt.Errorf("get verifier caller: %w", err) | ||
} | ||
|
||
quorumNumbersRequired, err := certVerifierCaller.QuorumNumbersRequiredV2(&bind.CallOpts{Context: ctx}) | ||
|
@@ -316,3 +309,26 @@ func (cv *CertVerifier) MaybeWaitForBlockNumber(ctx context.Context, targetBlock | |
} | ||
} | ||
} | ||
|
||
// getVerifierCaller returns a ContractEigenDACertVerifierCaller that corresponds to the input certVerifierAddress | ||
// | ||
// This method caches ContractEigenDACertVerifierCaller instances, since their construction requires acquiring a lock | ||
// and parsing json, and is therefore not trivially inexpensive. | ||
func (cv *CertVerifier) getVerifierCaller( | ||
certVerifierAddress string, | ||
) (*verifierBindings.ContractEigenDACertVerifierCaller, error) { | ||
|
||
existingCaller, valueExists := cv.verifierCallers.Load(certVerifierAddress) | ||
if valueExists { | ||
return existingCaller.(*verifierBindings.ContractEigenDACertVerifierCaller), nil | ||
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. any value in instead safe casting the caster to the binding type? looking at this code it should be impossible but without an invariant enforcement this does present a hypothetical panic 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. Good point, fixed in 74ec1b9e |
||
} | ||
|
||
certVerifierCaller, err := verifierBindings.NewContractEigenDACertVerifierCaller( | ||
gethcommon.HexToAddress(certVerifierAddress), cv.ethClient) | ||
if err != nil { | ||
return nil, fmt.Errorf("bind to verifier contract at %s: %w", certVerifierAddress, err) | ||
} | ||
|
||
cv.verifierCallers.Store(certVerifierAddress, certVerifierCaller) | ||
return certVerifierCaller, nil | ||
} |
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 there be a size constraint imposed on this mapping? ie if we take the design route where proxy takes in arbitrary addresses then this could present a DoS vector
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.
Valid point, but I can't think of a reason we would pursue a design route where proxy accepts arbitrary addresses: the two cases I can imagine are either cert verifier address being managed by an
EigenDACertVerifierRouter
, or a hardcoded or config value in proxy for cases where the address isn't permitted to change.Can you think of a reason we'd allow arbitrary definitions for this?
If we can't think of a potential reason here, I think it makes sense to not limit the size of the map: doing so is non-trivial in complexity and would present a cost in the standard mode of operation. Perhaps just a comment calling out the concern, so it's more likely to attract notice if it ever needs to be changed?
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.
comment makes sense!