-
Notifications
You must be signed in to change notification settings - Fork 238
fix: period index calculation #1641
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
Changes from 4 commits
06ee3b5
ffb047a
978621c
20cd495
90617e0
dac3944
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 |
---|---|---|
|
@@ -25,7 +25,7 @@ type Accountant struct { | |
minNumSymbols uint64 | ||
|
||
// local accounting | ||
// contains 3 bins; circular wrapping of indices | ||
// contains numBins of period records; circular wrapping on period record indices | ||
periodRecords []PeriodRecord | ||
usageLock sync.Mutex | ||
cumulativePayment *big.Int | ||
|
@@ -34,8 +34,11 @@ type Accountant struct { | |
numBins uint32 | ||
} | ||
|
||
// PeriodRecord contains the index of the reservation period and the usage of the period | ||
type PeriodRecord struct { | ||
// Index is start timestamp of the period in seconds; it is always a multiple of the reservation window | ||
Index uint32 | ||
// Usage is the usage of the period in symbols | ||
Usage uint64 | ||
} | ||
|
||
|
@@ -73,13 +76,13 @@ func (a *Accountant) BlobPaymentInfo( | |
numSymbols uint64, | ||
quorumNumbers []uint8, | ||
timestamp int64) (*big.Int, error) { | ||
|
||
currentReservationPeriod := meterer.GetReservationPeriodByNanosecond(timestamp, a.reservationWindow) | ||
reservationWindow := a.reservationWindow | ||
currentReservationPeriod := meterer.GetReservationPeriodByNanosecond(timestamp, reservationWindow) | ||
symbolUsage := a.SymbolsCharged(numSymbols) | ||
|
||
a.usageLock.Lock() | ||
defer a.usageLock.Unlock() | ||
relativePeriodRecord := a.GetRelativePeriodRecord(currentReservationPeriod) | ||
relativePeriodRecord := a.GetOrRefreshRelativePeriodRecord(currentReservationPeriod, reservationWindow) | ||
relativePeriodRecord.Usage += symbolUsage | ||
|
||
// first attempt to use the active reservation | ||
|
@@ -91,7 +94,7 @@ func (a *Accountant) BlobPaymentInfo( | |
return big.NewInt(0), nil | ||
} | ||
|
||
overflowPeriodRecord := a.GetRelativePeriodRecord(currentReservationPeriod + 2) | ||
overflowPeriodRecord := a.GetOrRefreshRelativePeriodRecord(currentReservationPeriod+2*reservationWindow, reservationWindow) | ||
// Allow one overflow when the overflow bin is empty, the current usage and new length are both less than the limit | ||
if overflowPeriodRecord.Usage == 0 && relativePeriodRecord.Usage-symbolUsage < binLimit && symbolUsage <= binLimit { | ||
if err := QuorumCheck(quorumNumbers, a.reservation.QuorumNumbers); err != nil { | ||
|
@@ -116,8 +119,8 @@ func (a *Accountant) BlobPaymentInfo( | |
return a.cumulativePayment, nil | ||
} | ||
return big.NewInt(0), fmt.Errorf( | ||
"no bandwidth reservation found for account %s, and current cumulativePayment balance insufficient "+ | ||
"to make an on-demand dispersal. Consider depositing more eth to the PaymentVault contract.", a.accountID.Hex()) | ||
"invalid payments: no available bandwidth reservation found for account %s, and current cumulativePayment balance insufficient "+ | ||
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. I really feel like this function should be broken into two: a function that only checks (and updates) reservation, and IF that fails (returns nil), then its caller's job to get a cumulativePayment). This function is very hard to review because its doing too many things, and These are all questions (and many more) that are running through my brain as I'm reviewing this. We could write more documentation on the function to describe all these possible scenarios, but I feel like it would be much simpler (and self-documenting) to split into 2 functions. Can prob be done in a separate PR at a future date, but still wanted to leave this comment. 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. Seems like a good refactor, only called in one spot 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. Agreed with the reasoning. This is something I have planned in this PR. 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. Given that this is just a refactor, could you make it a separate in-between PR, to not bloat the PR with actual new features?
You already broke your PR into interface and implementation, so that's awesome. 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. Yes, I can break it up. Given this is meant to be a fix for the current accounting, I would do refactor/interface/implementation for the upcoming quorum specific accounting |
||
"to make an on-demand dispersal. Consider increasing reservation or cumulative payment on-chain. For more details, see https://docs.eigenda.xyz/core-concepts/payments#disperser-client-requirements", a.accountID.Hex()) | ||
} | ||
|
||
// AccountBlob accountant provides and records payment information | ||
|
@@ -157,9 +160,21 @@ func (a *Accountant) SymbolsCharged(numSymbols uint64) uint64 { | |
return core.RoundUpDivide(numSymbols, a.minNumSymbols) * a.minNumSymbols | ||
} | ||
|
||
// GetRelativePeriodRecord returns the period record for the given index | ||
func (a *Accountant) GetRelativePeriodRecord(index uint64) *PeriodRecord { | ||
samlaf marked this conversation as resolved.
Show resolved
Hide resolved
|
||
relativeIndex := uint32(index % uint64(a.numBins)) | ||
if a.periodRecords[relativeIndex].Index != uint32(index) { | ||
relativeIndex := uint32((index / a.reservationWindow) % uint64(a.numBins)) | ||
// Return empty record if the index is greater than the number of bins (should never happen by accountant initialization) | ||
if relativeIndex >= uint32(a.numBins) { | ||
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. Is it ever possible that a.numBins can change at runtime? 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. no we don't have mut on it, it will be fixed to the configured value 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. wdym by "have mut"? A new developer could certainly add some code that changes it (by mistake). Would that be a problem? If yes, then it should be documented in the accountant struct. 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. Speaking of which.. how should one choose numBins? There is no comment as to this effect, neither on the struct nor on the constructor.
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. added some documentation.
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.
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. Raised a similar question here #1599 (comment). Let's move the discussion to that PR? 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.
|
||
panic(fmt.Sprintf("relativeIndex %d is greater than the number of bins %d cached", relativeIndex, a.numBins)) | ||
} | ||
return &a.periodRecords[relativeIndex] | ||
} | ||
|
||
// GetOrRefreshRelativePeriodRecord returns the period record for the given index (which is in seconds and is the multiple of the reservation window), | ||
// wrapping around the circular buffer and clearing the record if the index is greater than the number of bins | ||
func (a *Accountant) GetOrRefreshRelativePeriodRecord(index uint64, reservationWindow uint64) *PeriodRecord { | ||
samlaf marked this conversation as resolved.
Show resolved
Hide resolved
|
||
relativeIndex := uint32((index / reservationWindow) % uint64(a.numBins)) | ||
if a.periodRecords[relativeIndex].Index < uint32(index) { | ||
samlaf marked this conversation as resolved.
Show resolved
Hide resolved
samlaf marked this conversation as resolved.
Show resolved
Hide resolved
|
||
a.periodRecords[relativeIndex] = PeriodRecord{ | ||
Index: uint32(index), | ||
Usage: 0, | ||
|
Uh oh!
There was an error while loading. Please reload this page.