Skip to content
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

[payment] transactor ping payment vault contract #827

Merged
merged 18 commits into from
Dec 10, 2024
Merged

Conversation

hopeyen
Copy link
Contributor

@hopeyen hopeyen commented Oct 22, 2024

Why are these changes needed?

filling in the transactor functions to read the payment vault contract on-chain

Checks

  • I've made sure the lint is passing in this PR.
  • 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 :(

@hopeyen hopeyen force-pushed the hope/payment-contract branch from 25199d5 to acec203 Compare November 22, 2024 19:31
@hopeyen hopeyen requested a review from ian-shim November 22, 2024 21:05
core/chainio.go Outdated Show resolved Hide resolved
core/chainio.go Outdated Show resolved Hide resolved
core/data.go Outdated
@@ -9,6 +9,7 @@ import (

commonpb "github.com/Layr-Labs/eigenda/api/grpc/common"
"github.com/Layr-Labs/eigenda/common"
paymentvault "github.com/Layr-Labs/eigenda/contracts/bindings/PaymentVault"
Copy link
Contributor

Choose a reason for hiding this comment

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

can we not have contract dependency on core data structs?

Copy link
Contributor

Choose a reason for hiding this comment

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

can we do something here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

what do you think about moving type ActiveReservation = paymentvault.IPaymentVaultReservation to core/eth?

Copy link
Contributor

Choose a reason for hiding this comment

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

How does that remove the contract dependency?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

core/eth already has contract dependency, so we are won't introducing it in data.go, we just need to avoid circular dependencies in this case

@@ -37,6 +38,7 @@ type ContractBindings struct {
EigenDAServiceManager *eigendasrvmg.ContractEigenDAServiceManager
EjectionManager *ejectionmg.ContractEjectionManager
AVSDirectory *avsdir.ContractAVSDirectory
PaymentVault *paymentvault.ContractPaymentVault
Copy link
Contributor

Choose a reason for hiding this comment

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

should this be initialized in updateContractBindings?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

for all the contract comments, I pinged @0x0aa0 to link payment vault to the eigenda service manager contract so that the payment vault contract addr can be queried. Will make the appropriate updates once that's in:)

Copy link
Contributor

Choose a reason for hiding this comment

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

Cool, are you planning to leave this PR open till the contract code is ready and deployed?
Maybe we should just add nil checks and proceed for now? We can update/remove the nil checks when contracts are ready

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 added nil checks before the contract calls so we can go ahead to merge! I think the payment DASM link is almost ready, can work on that as soon as that one gets merged

}

reservations_map := make(map[string]core.ActiveReservation)
reservations, err := t.bindings.PaymentVault.GetReservations(&bind.CallOpts{
Copy link
Contributor

Choose a reason for hiding this comment

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

would this crash if PaymentVault is not initialized

core/eth/reader.go Outdated Show resolved Hide resolved
core/chainio.go Outdated Show resolved Hide resolved
// contract is not implemented yet
return core.ActiveReservation{}, nil
func (t *Reader) GetActiveReservationByAccount(ctx context.Context, accountID string) (core.ActiveReservation, error) {
reservation, err := t.bindings.PaymentVault.GetReservation(&bind.CallOpts{
Copy link
Contributor

Choose a reason for hiding this comment

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

If account is not part of the mapping, contract will return zero value for the reservation instead of an error. We should probably validate that and return err here instead.

Same with other methods in this file that accesses mapping onchain

core/meterer/onchain_state.go Show resolved Hide resolved
core/meterer/onchain_state.go Outdated Show resolved Hide resolved
@ian-shim ian-shim requested a review from mooselumph December 3, 2024 23:17
core/eth/reader.go Outdated Show resolved Hide resolved
core/chainio.go Outdated Show resolved Hide resolved
core/meterer/onchain_state.go Outdated Show resolved Hide resolved
core/meterer/onchain_state.go Outdated Show resolved Hide resolved
@hopeyen hopeyen force-pushed the hope/payment-contract branch 3 times, most recently from e973ddf to 3e3b64d Compare December 5, 2024 19:00
@hopeyen hopeyen requested a review from ian-shim December 5, 2024 19:17
core/eth/reader.go Outdated Show resolved Hide resolved
core/meterer/onchain_state.go Outdated Show resolved Hide resolved
@@ -37,6 +38,7 @@ type ContractBindings struct {
EigenDAServiceManager *eigendasrvmg.ContractEigenDAServiceManager
EjectionManager *ejectionmg.ContractEjectionManager
AVSDirectory *avsdir.ContractAVSDirectory
PaymentVault *paymentvault.ContractPaymentVault
Copy link
Contributor

Choose a reason for hiding this comment

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

Cool, are you planning to leave this PR open till the contract code is ready and deployed?
Maybe we should just add nil checks and proceed for now? We can update/remove the nil checks when contracts are ready

@hopeyen hopeyen requested a review from ian-shim December 6, 2024 17:22
Copy link
Contributor

@ian-shim ian-shim left a comment

Choose a reason for hiding this comment

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

few last comments

Comment on lines 679 to 678
// filter out all zero-valued reservations
for accountID, reservation := range reservationsMap {
if isZeroValuedReservation(*reservation) {
delete(reservationsMap, accountID)
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

We can move this check inside the for loop above (L675) and only set the value if reservation isn't zero valued

}

// filter out all zero-valued payments
for accountID, payment := range paymentsMap {
Copy link
Contributor

Choose a reason for hiding this comment

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

ditto here

func isZeroValuedReservation(reservation paymentvault.IPaymentVaultReservation) bool {
zeroReservation := paymentvault.IPaymentVaultReservation{}

return reflect.DeepEqual(reservation, zeroReservation)
Copy link
Contributor

Choose a reason for hiding this comment

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

maps.Equal for performance

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 had trouble with this because IPaymentVaultReservation is not a map. is it more performant to put the struct into a map and use maps.Equal?

Copy link
Contributor

Choose a reason for hiding this comment

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

Ah it's a struct. We could compare each field individually (or i'm fine with using reflect as well).

Do you know if eth rpc will return nil vs. empty byte slice for []byte type fields?
If they return empty byte slice, this comparison will evaluate to false

if err != nil {
return nil, err
}
if onDemandPayment == big.NewInt(0) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Has this been tested? This will result in false even if onDemandPayment has value of 0 because you're comparing bigint pointers.
Use something like onDemandPayment.Cmp(big.NewInt(0)) == 0 instead

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 don't have test coverage over this. Do we have anywhere that puts tests on contract calls?
(updated to use your suggestion)

func (pcs *OnchainPaymentState) GetActiveReservationByAccount(ctx context.Context, accountID string) (core.ActiveReservation, error) {
if reservation, ok := pcs.ActiveReservations[accountID]; ok {
func (pcs *OnchainPaymentState) GetActiveReservationByAccount(ctx context.Context, accountID gethcommon.Address) (*core.ActiveReservation, error) {
if reservation, ok := (pcs.ActiveReservations)[accountID]; ok {
Copy link
Contributor

Choose a reason for hiding this comment

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

Don't we need rlock here? I think it can crash if a map is read at the same time it's being written

Copy link
Contributor Author

Choose a reason for hiding this comment

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

oof, I added RLock and defer RUnlock

Copy link
Contributor

Choose a reason for hiding this comment

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

If you defer pcs.ReservationsLock.RUnlock() it will hold the rlock until the end of the execution. Will it cause conflict with write lock in L160?

core/data.go Outdated
@@ -9,6 +9,7 @@ import (

commonpb "github.com/Layr-Labs/eigenda/api/grpc/common"
"github.com/Layr-Labs/eigenda/common"
paymentvault "github.com/Layr-Labs/eigenda/contracts/bindings/PaymentVault"
Copy link
Contributor

Choose a reason for hiding this comment

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

can we do something here?

@hopeyen hopeyen force-pushed the hope/payment-contract branch from 8427c85 to 673d81c Compare December 6, 2024 20:33
@hopeyen hopeyen force-pushed the hope/payment-contract branch from 673d81c to 34ffa52 Compare December 6, 2024 20:52
// since reservations are returned in the same order as the accountIDs, we can directly map them
for i, reservation := range reservations {
if isZeroValuedReservation(reservation) {
delete(reservationsMap, accountIDs[i])
Copy link
Contributor

Choose a reason for hiding this comment

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

If a reservation is zero, this delete would be a no-op and it would be added in L677, no?
Don't we want if !isZeroValuedReservation(reservation) { reservationsMap[accountIDs[i]] = &reservation } ?

func isZeroValuedReservation(reservation paymentvault.IPaymentVaultReservation) bool {
zeroReservation := paymentvault.IPaymentVaultReservation{}

return reflect.DeepEqual(reservation, zeroReservation)
Copy link
Contributor

Choose a reason for hiding this comment

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

Ah it's a struct. We could compare each field individually (or i'm fine with using reflect as well).

Do you know if eth rpc will return nil vs. empty byte slice for []byte type fields?
If they return empty byte slice, this comparison will evaluate to false

core/data.go Outdated
@@ -9,6 +9,7 @@ import (

commonpb "github.com/Layr-Labs/eigenda/api/grpc/common"
"github.com/Layr-Labs/eigenda/common"
paymentvault "github.com/Layr-Labs/eigenda/contracts/bindings/PaymentVault"
Copy link
Contributor

Choose a reason for hiding this comment

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

How does that remove the contract dependency?

@hopeyen hopeyen force-pushed the hope/payment-contract branch from fc716e1 to b585fca Compare December 10, 2024 20:19
Copy link
Contributor

@ian-shim ian-shim left a comment

Choose a reason for hiding this comment

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

couple of nits, but lgtm!

// Returns an error if the input reservation is zero-valued.
func ConvertToActiveReservation(reservation paymentvault.IPaymentVaultReservation) (*core.ActiveReservation, error) {
if isZeroValuedReservation(reservation) {
return nil, fmt.Errorf("reservation does not exist for given account")
Copy link
Contributor

Choose a reason for hiding this comment

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

This error message is not accurate given this is a generic util method

Copy link
Contributor Author

Choose a reason for hiding this comment

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

updated to say that reservation is not a valid active reservation

// since payments are returned in the same order as the accountIDs, we can directly map them
for i, payment := range payments {
if payment.Cmp(big.NewInt(0)) == 0 {
t.logger.Warn("failed to get on demand payment for account", "account", accountIDs[i], "err", err)
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 err is relevant here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

you are right! removed

@hopeyen hopeyen merged commit 2f5ced8 into master Dec 10, 2024
9 checks passed
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.

2 participants