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

[payments] meterer core logic #790

Merged
merged 22 commits into from
Oct 22, 2024
Merged

[payments] meterer core logic #790

merged 22 commits into from
Oct 22, 2024

Conversation

hopeyen
Copy link
Contributor

@hopeyen hopeyen commented Oct 8, 2024

Why are these changes needed?

Core logic of payments metering

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 changed the title feat: meterer core logic meterer core logic Oct 8, 2024
@hopeyen hopeyen changed the title meterer core logic [payments] meterer core logic Oct 8, 2024
@hopeyen hopeyen force-pushed the hope/meterer-helpers branch 5 times, most recently from f553c37 to 6ae70ef Compare October 8, 2024 18:02
@hopeyen hopeyen force-pushed the hope/meterer-logic branch 2 times, most recently from 6092848 to 2211a82 Compare October 8, 2024 19:30
if err := m.ValidateQuorum(blobHeader, reservation.QuorumNumbers); err != nil {
return fmt.Errorf("invalid quorum for reservation: %w", err)
}
if !m.ValidateBinIndex(blobHeader, reservation) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

What do you think of the idea of adding a ReceiptTime field to the context when we receive the message and then using these field when we validate the bin index?

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 idea is similar to having disperser set the bin index of a message. The main trade-off was client cannot easily predict the ReceiptTime and the behavior of the message in the local accounting. I think this is a good idea with tolerance, something like MaxDelayReceiveTime?

return nil
}

func (m *Meterer) ValidateQuorum(blobHeader BlobHeader, allowedQuoroms []uint8) error {
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: ValidateQuorums ensures that the quorums listed in the blobHeader are present within allowedQuorums

type Config struct {
GlobalBytesPerSecond uint64 // 2^64 bytes ~= 18 exabytes per second; if we use uint32, that's ~4GB/s
PricePerChargeable uint32 // 2^64 gwei ~= 18M Eth; uint32 => ~4ETH
MinChargeableSize uint32
Copy link
Collaborator

Choose a reason for hiding this comment

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

Note: In current implementation, this should be in units of Symbols since DataLength is also in symbols. As we've discussed, this parametrization is subject to change.

Comment on lines 201 to 228
assert.Error(t, err, "invalid bin index for reservation")

// test bin usage
accountID := crypto.PubkeyToAddress(privateKey2.PublicKey).Hex()
Copy link
Collaborator

Choose a reason for hiding this comment

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

Shouldn't this bin index pass?

core/meterer/meterer_test.go Show resolved Hide resolved
header, err = meterer.ConstructPaymentMetadata(signer, binIndex, 0, 50, quorumNumbers, privateKey2)
assert.NoError(t, err)
err = mt.MeterRequest(ctx, *header)
assert.Error(t, err, "cannot insert cumulative payment in out of order")
Copy link
Collaborator

Choose a reason for hiding this comment

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

I don't completely understand how this is different from the previous check...

@hopeyen hopeyen force-pushed the hope/meterer-helpers branch 3 times, most recently from 31932db to f43e6cf Compare October 9, 2024 21:04
@hopeyen hopeyen force-pushed the hope/meterer-helpers branch 4 times, most recently from ac0c882 to fab84e3 Compare October 11, 2024 00:50
@hopeyen hopeyen force-pushed the hope/meterer-logic branch 2 times, most recently from 1bd1029 to d402849 Compare October 11, 2024 16:52
Copy link
Collaborator

@mooselumph mooselumph left a comment

Choose a reason for hiding this comment

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

looks good! A few more comments

return nil
}

// ValidateQuorums ensures that the quorums listed in the blobHeader are present within allowedQuorums
Copy link
Collaborator

Choose a reason for hiding this comment

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

Note: A reservation that does not utilize all of the allowed quorums will be accepted. However, it will still charge against all of the allowed quorums. We should make sure this is the desired UX.

assert.Equal(t, strconv.Itoa(int((i+1)*dataLength)), item["BinUsage"].(*types.AttributeValueMemberN).Value)

}
// frist over flow is allowed
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit: first

assert.ErrorContains(t, err, "bin has already been filled")

// overwhelming bin overflow for empty bins (assuming all previous requests happened within 1 reservation window)
header, err = auth.ConstructPaymentMetadata(&signer, binIndex-1, 0, 1000, quoromNumbers, privateKey2)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Shoud we also have a passing test for binIndex-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.

yep! added it and ready for review

GlobalBytesPerSecond: 1000,
ReservationWindow: 60,
ChainReadTimeout: 3 * time.Second,
PricePerSymbol: 1,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Would it be worth using some unique prime values here for different parameters (e.g. 2,3,5,7) to give better confidence that the calcualtions are being done correctly?

core/data.go Outdated
@@ -490,22 +490,24 @@ type PaymentMetadata struct {
BinIndex uint32
// TODO: we are thinking the contract can use uint128 for cumulative payment,
// but the definition on v2 uses uint64. Double check with team.
CumulativePayment uint64
CumulativePayment big.Int
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 it's common practice to use a pointer for big.Int, i.e. CumulativePayment *big.Int, as most methods consume the pointer.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

sg, updated

}
pcs.ActiveReservations = activeReservations
Copy link
Contributor

Choose a reason for hiding this comment

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

I think we should lock this method unless there is a strong reason not to, as i don't think it will cause any performance issues but there is a chance ActiveReservations and OnDemandPayments are accessed in parallel?

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.

just one comment around locking

@hopeyen hopeyen merged commit febcd95 into master Oct 22, 2024
10 checks passed
@hopeyen hopeyen deleted the hope/meterer-logic branch October 22, 2024 02:48
pcs.OnDemandPayments = onDemandPayments
pcs.OnDemandLocks.Unlock()

return nil
}

func (pcs *OnchainPaymentState) GetActiveReservations(ctx context.Context, blockNumber uint) (map[string]core.ActiveReservation, error) {
return pcs.ActiveReservations, nil
Copy link
Contributor

Choose a reason for hiding this comment

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

I think it needs to get RLock here

pcs.ReservationsLock.Lock()
pcs.ActiveReservations[accountID] = res
pcs.ReservationsLock.Unlock()
return res, nil
}

func (pcs *OnchainPaymentState) GetOnDemandPayments(ctx context.Context, blockNumber uint) (map[string]core.OnDemandPayment, error) {
return pcs.OnDemandPayments, nil
Copy link
Contributor

Choose a reason for hiding this comment

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

same here

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.

3 participants