-
Notifications
You must be signed in to change notification settings - Fork 198
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
Conversation
25199d5
to
acec203
Compare
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" |
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.
can we not have contract dependency on core data structs?
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.
can we do something 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.
what do you think about moving type ActiveReservation = paymentvault.IPaymentVaultReservation
to core/eth?
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.
How does that remove the contract dependency?
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.
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 |
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 this be initialized in updateContractBindings
?
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.
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:)
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.
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
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 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{ |
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.
would this crash if PaymentVault
is not initialized
// 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{ |
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.
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
e973ddf
to
3e3b64d
Compare
@@ -37,6 +38,7 @@ type ContractBindings struct { | |||
EigenDAServiceManager *eigendasrvmg.ContractEigenDAServiceManager | |||
EjectionManager *ejectionmg.ContractEjectionManager | |||
AVSDirectory *avsdir.ContractAVSDirectory | |||
PaymentVault *paymentvault.ContractPaymentVault |
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.
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
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.
few last comments
core/eth/reader.go
Outdated
// filter out all zero-valued reservations | ||
for accountID, reservation := range reservationsMap { | ||
if isZeroValuedReservation(*reservation) { | ||
delete(reservationsMap, accountID) | ||
} | ||
} |
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 can move this check inside the for loop above (L675) and only set the value if reservation isn't zero valued
core/eth/reader.go
Outdated
} | ||
|
||
// filter out all zero-valued payments | ||
for accountID, payment := range paymentsMap { |
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.
ditto here
core/eth/utils.go
Outdated
func isZeroValuedReservation(reservation paymentvault.IPaymentVaultReservation) bool { | ||
zeroReservation := paymentvault.IPaymentVaultReservation{} | ||
|
||
return reflect.DeepEqual(reservation, zeroReservation) |
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.
maps.Equal
for performance
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 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
?
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.
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/eth/reader.go
Outdated
if err != nil { | ||
return nil, err | ||
} | ||
if onDemandPayment == big.NewInt(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.
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
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 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 { |
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.
Don't we need rlock here? I think it can crash if a map is read at the same time it's being written
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.
oof, I added RLock and defer RUnlock
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.
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" |
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.
can we do something here?
8427c85
to
673d81c
Compare
673d81c
to
34ffa52
Compare
core/eth/reader.go
Outdated
// 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]) |
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.
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 }
?
core/eth/utils.go
Outdated
func isZeroValuedReservation(reservation paymentvault.IPaymentVaultReservation) bool { | ||
zeroReservation := paymentvault.IPaymentVaultReservation{} | ||
|
||
return reflect.DeepEqual(reservation, zeroReservation) |
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.
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" |
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.
How does that remove the contract dependency?
fc716e1
to
b585fca
Compare
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.
couple of nits, but lgtm!
core/eth/utils.go
Outdated
// 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") |
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 error message is not accurate given this is a generic util method
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.
updated to say that reservation is not a valid active reservation
core/eth/reader.go
Outdated
// 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) |
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 don't think err
is relevant 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.
you are right! removed
Why are these changes needed?
filling in the transactor functions to read the payment vault contract on-chain
Checks