-
Notifications
You must be signed in to change notification settings - Fork 165
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
disperser meterer for payments #779
base: master
Are you sure you want to change the base?
Conversation
func (m *Meterer) ValidateBinIndex(blobHeader BlobHeader, reservation *ActiveReservation) bool { | ||
currentBinIndex := GetCurrentBinIndex() | ||
// Valid bin indexes are either the current bin or the previous bin | ||
if (blobHeader.BinIndex != currentBinIndex && blobHeader.BinIndex != (currentBinIndex-1)) || (reservation.StartEpoch > blobHeader.BinIndex || blobHeader.BinIndex > reservation.EndEpoch) { |
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.
Does it make sense for Epochs to use the same units as Bins?
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'm open to change this for easier usage. What about using start and end timestamps instead of epochs?
disperser/meterer/meterer.go
Outdated
// GetCurrentBinIndex returns the current bin index based on time | ||
func GetCurrentBinIndex() uint64 { | ||
currentTime := time.Now().Unix() | ||
binInterval := 375 // Interval that allows 3 32MB blobs at minimal throughput |
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 configuraable? What are the units?
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.
yes! changed this to use reservationWindow config and added an indication in the help string that this is in seconds
disperser/meterer/meterer.go
Outdated
return fmt.Errorf("failed to get active reservation by account: %w", err) | ||
} | ||
if newUsage <= 2*binLimit && blobHeader.BinIndex+2 <= reservation.EndEpoch { | ||
m.OffchainStore.UpdateReservationBin(ctx, blobHeader.AccountID, uint64(blobHeader.BinIndex+2), newUsage-binLimit) |
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.
Note: this is not a race condition because previous logic ensures this can only happen in a single thread.
disperser/meterer/offchain_store.go
Outdated
result, err := s.dynamoClient.QueryIndex(ctx, s.onDemandTableName, "AccountIDIndex", "AccountID = :account", commondynamodb.ExpresseionValues{ | ||
":account": &types.AttributeValueMemberS{ | ||
Value: 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.
I think we should be able to configure a sort key associated with the CumulativePayment
field and directly retrieve the records with cumulative payment above and below the provided payment.
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!
currentBinIndex := uint64(time.Now().Unix()) | ||
|
||
// Valid bin indexes are either the current bin or the previous bin (allow this second or prev sec) | ||
if blobHeader.BinIndex != currentBinIndex && blobHeader.BinIndex != (currentBinIndex-1) { |
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 global rate limit, I think we can argue that we don't need to include the BinIndex within the header, but just use the receipt time directly.
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.
makes sense, in this case we don't need to validate the bin index, maybe not even receipt time, but the time when global rate gets checked (since global rate limit check happens after payment validations, we avoid failing on cases where payment validation ever gets to more than 2 seconds)
36c729b
to
b14bf86
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.
Some more comments!
if _, ok := key[itemKey]; ok { | ||
// Cannot update the key | ||
continue | ||
} |
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 realize this is using the template above, but it's unclear to me why this is failing silently.
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.
Apparently dynamoDB doesn't let user update the primary key or sort key of an existing item, so if the current itemKey is part of the item's key, we simply move on to the next attribute in the item map. I think this is failing silently because we want to operate on other fields anyway.
some 3 alternative ways that still ensure consistency:
- a loop to check the keys (and return err) before the updating loop,
- do the same as now, but revert the changes later on if we cannot update the key
- do the same as now, and return a list of keys that couldn't get updated
common/aws/dynamodb/client.go
Outdated
// update = update.Add(expression.Name(itemKey), expression.Value(n.Value)) | ||
// update = update.Add(expression.Name(itemKey), expression.Value(n.Value)) |
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.
Remove?
return binUsageValue, nil | ||
} | ||
|
||
func (s *OffchainStore) FindReservationBin(ctx context.Context, accountID string, binIndex uint64) (*ReservationBin, error) { |
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.
Is this used?
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.
Nope atm, it was intended for an API, which i now realized I've yet to add
} | ||
|
||
// Find all reservation bins for a given account | ||
func (s *OffchainStore) FindReservationBins(ctx context.Context, accountID string) ([]ReservationBin, error) { |
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.
Is this used?
|
||
// OperatorInfo contains information about an operator which is stored on the blockchain state, | ||
// corresponding to a particular quorum | ||
type ActiveReservation struct { |
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.
Note: neeed to add QuorumNumbers
as discussed
disperser/meterer/types.go
Outdated
// Existing fields | ||
Commitment core.G1Point | ||
DataLength uint32 | ||
BlobQuorumParams []BlobQuorumParam |
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 can just be a list of QuorumNumbers, per the new header spec.
disperser/meterer/types.go
Outdated
BinIndex uint64 | ||
|
||
Signature []byte | ||
BlobSize uint32 |
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 is redundant with DataLength. We should decide on canonical naming.
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.
went with DataLength
disperser/meterer/types.go
Outdated
} | ||
|
||
// Protocol defines parameters: FixedFeePerByte; fine to leave global rate-limit offchain atm | ||
type OnDemand struct { |
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.
Is this used?
disperser/meterer/types.go
Outdated
Version uint32 | ||
AccountID string | ||
Nonce uint32 // use nonce to prevent duplicate payments in the same reservation window | ||
BinIndex uint64 |
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.
It seems like uint32
would be sufficient for this?
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 be more memory efficient; I'm assuming we don't need to worry about an index in the unit of seconds (previously global bin index is in seconds so 2^32 in unix let this go up to Jan 19, 2038, but with that being removed, uint32 is fine for reservation bin indices
I also updated start & end epochs to use uint32
, as well as PricePerChargeable
(2^64 gwei ~= 18M Eth; uint32 => ~4ETH), MinChargeableSize
(in bytes, this is ~4GB/s), and ReservationWindow
(136years but uint16 is only 18hours if we are counting in seconds; we could instead use hour as window unit and allow for 7years).
Left GlobalBytesPerSecond
with uint64
for the aspiration of supporting rate-limit greater than 4GB/s network-wide ✨
4bd5a2e
to
e1d454b
Compare
9295cbd
to
500ecc4
Compare
Why are these changes needed?
PoC inside disperser for handling payments
summary of changes
ratelimiter
that validate the requests before storing themu64
before worrying aboutu128
)unit tests
Checks