Skip to content

Commit

Permalink
payment struct and names ReservationPeriod and Salt (#965)
Browse files Browse the repository at this point in the history
  • Loading branch information
hopeyen authored Dec 11, 2024
1 parent 3eb67af commit 980a866
Show file tree
Hide file tree
Showing 31 changed files with 297 additions and 270 deletions.
17 changes: 9 additions & 8 deletions api/clients/accountant.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,11 @@ func NewAccountant(accountID string, reservation *core.ActiveReservation, onDema
// and both fields are used to create the payment header and signature
func (a *Accountant) BlobPaymentInfo(ctx context.Context, numSymbols uint64, quorumNumbers []uint8) (uint32, *big.Int, error) {
now := time.Now().Unix()
currentBinIndex := meterer.GetBinIndex(uint64(now), a.reservationWindow)
currentReservationPeriod := meterer.GetReservationPeriod(uint64(now), a.reservationWindow)

a.usageLock.Lock()
defer a.usageLock.Unlock()
relativeBinRecord := a.GetRelativeBinRecord(currentBinIndex)
relativeBinRecord := a.GetRelativeBinRecord(currentReservationPeriod)
relativeBinRecord.Usage += numSymbols

// first attempt to use the active reservation
Expand All @@ -82,17 +82,17 @@ func (a *Accountant) BlobPaymentInfo(ctx context.Context, numSymbols uint64, quo
if err := QuorumCheck(quorumNumbers, a.reservation.QuorumNumbers); err != nil {
return 0, big.NewInt(0), err
}
return currentBinIndex, big.NewInt(0), nil
return currentReservationPeriod, big.NewInt(0), nil
}

overflowBinRecord := a.GetRelativeBinRecord(currentBinIndex + 2)
overflowBinRecord := a.GetRelativeBinRecord(currentReservationPeriod + 2)
// Allow one overflow when the overflow bin is empty, the current usage and new length are both less than the limit
if overflowBinRecord.Usage == 0 && relativeBinRecord.Usage-numSymbols < binLimit && numSymbols <= binLimit {
overflowBinRecord.Usage += relativeBinRecord.Usage - binLimit
if err := QuorumCheck(quorumNumbers, a.reservation.QuorumNumbers); err != nil {
return 0, big.NewInt(0), err
}
return currentBinIndex, big.NewInt(0), nil
return currentReservationPeriod, big.NewInt(0), nil
}

// reservation not available, attempt on-demand
Expand All @@ -110,16 +110,17 @@ func (a *Accountant) BlobPaymentInfo(ctx context.Context, numSymbols uint64, quo
}

// AccountBlob accountant provides and records payment information
func (a *Accountant) AccountBlob(ctx context.Context, numSymbols uint64, quorums []uint8) (*core.PaymentMetadata, error) {
binIndex, cumulativePayment, err := a.BlobPaymentInfo(ctx, numSymbols, quorums)
func (a *Accountant) AccountBlob(ctx context.Context, numSymbols uint64, quorums []uint8, salt uint32) (*core.PaymentMetadata, error) {
reservationPeriod, cumulativePayment, err := a.BlobPaymentInfo(ctx, numSymbols, quorums)
if err != nil {
return nil, err
}

pm := &core.PaymentMetadata{
AccountID: a.accountID,
BinIndex: binIndex,
ReservationPeriod: reservationPeriod,
CumulativePayment: cumulativePayment,
Salt: salt,
}

return pm, nil
Expand Down
64 changes: 32 additions & 32 deletions api/clients/accountant_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
)

const numBins = uint32(3)
const salt = uint32(0)

func TestNewAccountant(t *testing.T) {
reservation := &core.ActiveReservation{
Expand Down Expand Up @@ -70,27 +71,27 @@ func TestAccountBlob_Reservation(t *testing.T) {
symbolLength := uint64(500)
quorums := []uint8{0, 1}

header, err := accountant.AccountBlob(ctx, symbolLength, quorums)
header, err := accountant.AccountBlob(ctx, symbolLength, quorums, salt)

assert.NoError(t, err)
assert.Equal(t, meterer.GetBinIndex(uint64(time.Now().Unix()), reservationWindow), header.BinIndex)
assert.Equal(t, meterer.GetReservationPeriod(uint64(time.Now().Unix()), reservationWindow), header.ReservationPeriod)
assert.Equal(t, big.NewInt(0), header.CumulativePayment)
assert.Equal(t, isRotation([]uint64{500, 0, 0}, mapRecordUsage(accountant.binRecords)), true)

symbolLength = uint64(700)

header, err = accountant.AccountBlob(ctx, symbolLength, quorums)
header, err = accountant.AccountBlob(ctx, symbolLength, quorums, salt)

assert.NoError(t, err)
assert.NotEqual(t, 0, header.BinIndex)
assert.NotEqual(t, 0, header.ReservationPeriod)
assert.Equal(t, big.NewInt(0), header.CumulativePayment)
assert.Equal(t, isRotation([]uint64{1200, 0, 200}, mapRecordUsage(accountant.binRecords)), true)

// Second call should use on-demand payment
header, err = accountant.AccountBlob(ctx, 300, quorums)
header, err = accountant.AccountBlob(ctx, 300, quorums, salt)

assert.NoError(t, err)
assert.Equal(t, uint32(0), header.BinIndex)
assert.Equal(t, uint32(0), header.ReservationPeriod)
assert.Equal(t, big.NewInt(300), header.CumulativePayment)
}

Expand Down Expand Up @@ -118,11 +119,11 @@ func TestAccountBlob_OnDemand(t *testing.T) {
numSymbols := uint64(1500)
quorums := []uint8{0, 1}

header, err := accountant.AccountBlob(ctx, numSymbols, quorums)
header, err := accountant.AccountBlob(ctx, numSymbols, quorums, salt)
assert.NoError(t, err)

expectedPayment := big.NewInt(int64(numSymbols * uint64(pricePerSymbol)))
assert.Equal(t, uint32(0), header.BinIndex)
assert.Equal(t, uint32(0), header.ReservationPeriod)
assert.Equal(t, expectedPayment, header.CumulativePayment)
assert.Equal(t, isRotation([]uint64{0, 0, 0}, mapRecordUsage(accountant.binRecords)), true)
assert.Equal(t, expectedPayment, accountant.cumulativePayment)
Expand All @@ -146,7 +147,7 @@ func TestAccountBlob_InsufficientOnDemand(t *testing.T) {
numSymbols := uint64(2000)
quorums := []uint8{0, 1}

_, err = accountant.AccountBlob(ctx, numSymbols, quorums)
_, err = accountant.AccountBlob(ctx, numSymbols, quorums, salt)
assert.Contains(t, err.Error(), "neither reservation nor on-demand payment is available")
}

Expand Down Expand Up @@ -175,25 +176,25 @@ func TestAccountBlobCallSeries(t *testing.T) {
now := time.Now().Unix()

// First call: Use reservation
header, err := accountant.AccountBlob(ctx, 800, quorums)
header, err := accountant.AccountBlob(ctx, 800, quorums, salt)
assert.NoError(t, err)
assert.Equal(t, meterer.GetBinIndex(uint64(now), reservationWindow), header.BinIndex)
assert.Equal(t, meterer.GetReservationPeriod(uint64(now), reservationWindow), header.ReservationPeriod)
assert.Equal(t, big.NewInt(0), header.CumulativePayment)

// Second call: Use remaining reservation + overflow
header, err = accountant.AccountBlob(ctx, 300, quorums)
header, err = accountant.AccountBlob(ctx, 300, quorums, salt)
assert.NoError(t, err)
assert.Equal(t, meterer.GetBinIndex(uint64(now), reservationWindow), header.BinIndex)
assert.Equal(t, meterer.GetReservationPeriod(uint64(now), reservationWindow), header.ReservationPeriod)
assert.Equal(t, big.NewInt(0), header.CumulativePayment)

// Third call: Use on-demand
header, err = accountant.AccountBlob(ctx, 500, quorums)
header, err = accountant.AccountBlob(ctx, 500, quorums, salt)
assert.NoError(t, err)
assert.Equal(t, uint32(0), header.BinIndex)
assert.Equal(t, uint32(0), header.ReservationPeriod)
assert.Equal(t, big.NewInt(500), header.CumulativePayment)

// Fourth call: Insufficient on-demand
_, err = accountant.AccountBlob(ctx, 600, quorums)
_, err = accountant.AccountBlob(ctx, 600, quorums, salt)
assert.Error(t, err)
assert.Contains(t, err.Error(), "neither reservation nor on-demand payment is available")
}
Expand Down Expand Up @@ -222,20 +223,20 @@ func TestAccountBlob_BinRotation(t *testing.T) {
quorums := []uint8{0, 1}

// First call
_, err = accountant.AccountBlob(ctx, 800, quorums)
_, err = accountant.AccountBlob(ctx, 800, quorums, salt)
assert.NoError(t, err)
assert.Equal(t, isRotation([]uint64{800, 0, 0}, mapRecordUsage(accountant.binRecords)), true)

// next reservation duration
time.Sleep(1000 * time.Millisecond)

// Second call
_, err = accountant.AccountBlob(ctx, 300, quorums)
_, err = accountant.AccountBlob(ctx, 300, quorums, salt)
assert.NoError(t, err)
assert.Equal(t, isRotation([]uint64{800, 300, 0}, mapRecordUsage(accountant.binRecords)), true)

// Third call
_, err = accountant.AccountBlob(ctx, 500, quorums)
_, err = accountant.AccountBlob(ctx, 500, quorums, salt)
assert.NoError(t, err)
assert.Equal(t, isRotation([]uint64{800, 800, 0}, mapRecordUsage(accountant.binRecords)), true)
}
Expand Down Expand Up @@ -269,12 +270,8 @@ func TestConcurrentBinRotationAndAccountBlob(t *testing.T) {
wg.Add(1)
go func() {
defer wg.Done()
// for j := 0; j < 5; j++ {
// fmt.Println("request ", i)
_, err := accountant.AccountBlob(ctx, 100, quorums)
_, err := accountant.AccountBlob(ctx, 100, quorums, salt)
assert.NoError(t, err)
time.Sleep(500 * time.Millisecond)
// }
}()
}

Expand Down Expand Up @@ -311,22 +308,25 @@ func TestAccountBlob_ReservationWithOneOverflow(t *testing.T) {
now := time.Now().Unix()

// Okay reservation
header, err := accountant.AccountBlob(ctx, 800, quorums)
header, err := accountant.AccountBlob(ctx, 800, quorums, salt)
assert.NoError(t, err)
assert.Equal(t, meterer.GetBinIndex(uint64(now), reservationWindow), header.BinIndex)
assert.Equal(t, salt, header.Salt)
assert.Equal(t, meterer.GetReservationPeriod(uint64(now), reservationWindow), header.ReservationPeriod)
assert.Equal(t, big.NewInt(0), header.CumulativePayment)
assert.Equal(t, isRotation([]uint64{800, 0, 0}, mapRecordUsage(accountant.binRecords)), true)

// Second call: Allow one overflow
header, err = accountant.AccountBlob(ctx, 500, quorums)
header, err = accountant.AccountBlob(ctx, 500, quorums, salt+1)
assert.NoError(t, err)
assert.Equal(t, salt+1, header.Salt)
assert.Equal(t, big.NewInt(0), header.CumulativePayment)
assert.Equal(t, isRotation([]uint64{1300, 0, 300}, mapRecordUsage(accountant.binRecords)), true)

// Third call: Should use on-demand payment
header, err = accountant.AccountBlob(ctx, 200, quorums)
header, err = accountant.AccountBlob(ctx, 200, quorums, salt+2)
assert.NoError(t, err)
assert.Equal(t, uint32(0), header.BinIndex)
assert.Equal(t, salt+2, header.Salt)
assert.Equal(t, uint32(0), header.ReservationPeriod)
assert.Equal(t, big.NewInt(200), header.CumulativePayment)
assert.Equal(t, isRotation([]uint64{1300, 0, 300}, mapRecordUsage(accountant.binRecords)), true)
}
Expand Down Expand Up @@ -355,12 +355,12 @@ func TestAccountBlob_ReservationOverflowReset(t *testing.T) {
quorums := []uint8{0, 1}

// full reservation
_, err = accountant.AccountBlob(ctx, 1000, quorums)
_, err = accountant.AccountBlob(ctx, 1000, quorums, salt)
assert.NoError(t, err)
assert.Equal(t, isRotation([]uint64{1000, 0, 0}, mapRecordUsage(accountant.binRecords)), true)

// no overflow
header, err := accountant.AccountBlob(ctx, 500, quorums)
header, err := accountant.AccountBlob(ctx, 500, quorums, salt)
assert.NoError(t, err)
assert.Equal(t, isRotation([]uint64{1000, 0, 0}, mapRecordUsage(accountant.binRecords)), true)
assert.Equal(t, big.NewInt(500), header.CumulativePayment)
Expand All @@ -369,7 +369,7 @@ func TestAccountBlob_ReservationOverflowReset(t *testing.T) {
time.Sleep(time.Duration(reservationWindow) * time.Second)

// Third call: Should use new bin and allow overflow again
_, err = accountant.AccountBlob(ctx, 500, quorums)
_, err = accountant.AccountBlob(ctx, 500, quorums, salt)
assert.NoError(t, err)
assert.Equal(t, isRotation([]uint64{1000, 500, 0}, mapRecordUsage(accountant.binRecords)), true)
}
Expand Down
5 changes: 3 additions & 2 deletions api/clients/disperser_client_v2.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ type DisperserClientV2Config struct {

type DisperserClientV2 interface {
Close() error
DisperseBlob(ctx context.Context, data []byte, blobVersion corev2.BlobVersion, quorums []core.QuorumID) (*dispv2.BlobStatus, corev2.BlobKey, error)
DisperseBlob(ctx context.Context, data []byte, blobVersion corev2.BlobVersion, quorums []core.QuorumID, salt uint32) (*dispv2.BlobStatus, corev2.BlobKey, error)
GetBlobStatus(ctx context.Context, blobKey corev2.BlobKey) (*disperser_rpc.BlobStatusReply, error)
GetBlobCommitment(ctx context.Context, data []byte) (*disperser_rpc.BlobCommitmentReply, error)
}
Expand Down Expand Up @@ -114,6 +114,7 @@ func (c *disperserClientV2) DisperseBlob(
data []byte,
blobVersion corev2.BlobVersion,
quorums []core.QuorumID,
salt uint32,
) (*dispv2.BlobStatus, corev2.BlobKey, error) {
err := c.initOnceGrpcConnection()
if err != nil {
Expand All @@ -128,7 +129,7 @@ func (c *disperserClientV2) DisperseBlob(
}

symbolLength := encoding.GetBlobLengthPowerOf2(uint(len(data)))
payment, err := c.accountant.AccountBlob(ctx, uint64(symbolLength), quorums)
payment, err := c.accountant.AccountBlob(ctx, uint64(symbolLength), quorums, salt)
if err != nil {
return nil, [32]byte{}, fmt.Errorf("error accounting blob: %w", err)
}
Expand Down
2 changes: 1 addition & 1 deletion api/docs/disperser.html
Original file line number Diff line number Diff line change
Expand Up @@ -839,7 +839,7 @@ <h3 id="disperser.DispersePaidBlobRequest">DispersePaidBlobRequest</h3>
<td>payment_header</td>
<td><a href="#common.PaymentHeader">common.PaymentHeader</a></td>
<td></td>
<td><p>Payment header contains AccountID, BinIndex, and CumulativePayment </p></td>
<td><p>Payment header contains account_id, reservation_period, cumulative_payment, and salt </p></td>
</tr>

<tr>
Expand Down
2 changes: 1 addition & 1 deletion api/docs/disperser.md
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ BlobStatusRequest is used to query the status of a blob.
| ----- | ---- | ----- | ----------- |
| data | [bytes](#bytes) | | The data to be dispersed. Same requirements as DisperseBlobRequest. |
| quorum_numbers | [uint32](#uint32) | repeated | The quorums to which the blob to be sent |
| payment_header | [common.PaymentHeader](#common-PaymentHeader) | | Payment header contains AccountID, BinIndex, and CumulativePayment |
| payment_header | [common.PaymentHeader](#common-PaymentHeader) | | Payment header contains account_id, reservation_period, cumulative_payment, and salt |
| payment_signature | [bytes](#bytes) | | signature of payment_header |


Expand Down
18 changes: 13 additions & 5 deletions api/docs/eigenda-protos.html
Original file line number Diff line number Diff line change
Expand Up @@ -949,21 +949,29 @@ <h3 id="common.PaymentHeader">PaymentHeader</h3>
<td>account_id</td>
<td><a href="#string">string</a></td>
<td></td>
<td><p> </p></td>
<td><p>The account ID of the disperser client. This should be a hex-encoded string of the ECSDA public key
corresponding to the key used by the client to sign the BlobHeader. </p></td>
</tr>

<tr>
<td>bin_index</td>
<td>reservation_period</td>
<td><a href="#uint32">uint32</a></td>
<td></td>
<td><p> </p></td>
<td><p>The reservation period of the dispersal request. </p></td>
</tr>

<tr>
<td>cumulative_payment</td>
<td><a href="#bytes">bytes</a></td>
<td></td>
<td><p> </p></td>
<td><p>The cumulative payment of the dispersal request. </p></td>
</tr>

<tr>
<td>salt</td>
<td><a href="#uint32">uint32</a></td>
<td></td>
<td><p>The salt of the disperser request. This is used to ensure that the payment header is intentionally unique. </p></td>
</tr>

</tbody>
Expand Down Expand Up @@ -1713,7 +1721,7 @@ <h3 id="disperser.DispersePaidBlobRequest">DispersePaidBlobRequest</h3>
<td>payment_header</td>
<td><a href="#common.PaymentHeader">common.PaymentHeader</a></td>
<td></td>
<td><p>Payment header contains AccountID, BinIndex, and CumulativePayment </p></td>
<td><p>Payment header contains account_id, reservation_period, cumulative_payment, and salt </p></td>
</tr>

<tr>
Expand Down
9 changes: 5 additions & 4 deletions api/docs/eigenda-protos.md
Original file line number Diff line number Diff line change
Expand Up @@ -280,9 +280,10 @@ KZG commitment, degree proof, the actual degree, and data length in number of sy

| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| account_id | [string](#string) | | |
| bin_index | [uint32](#uint32) | | |
| cumulative_payment | [bytes](#bytes) | | |
| account_id | [string](#string) | | The account ID of the disperser client. This should be a hex-encoded string of the ECSDA public key corresponding to the key used by the client to sign the BlobHeader. |
| reservation_period | [uint32](#uint32) | | The reservation period of the dispersal request. |
| cumulative_payment | [bytes](#bytes) | | The cumulative payment of the dispersal request. |
| salt | [uint32](#uint32) | | The salt of the disperser request. This is used to ensure that the payment header is intentionally unique. |



Expand Down Expand Up @@ -638,7 +639,7 @@ BlobStatusRequest is used to query the status of a blob.
| ----- | ---- | ----- | ----------- |
| data | [bytes](#bytes) | | The data to be dispersed. Same requirements as DisperseBlobRequest. |
| quorum_numbers | [uint32](#uint32) | repeated | The quorums to which the blob to be sent |
| payment_header | [common.PaymentHeader](#common-PaymentHeader) | | Payment header contains AccountID, BinIndex, and CumulativePayment |
| payment_header | [common.PaymentHeader](#common-PaymentHeader) | | Payment header contains account_id, reservation_period, cumulative_payment, and salt |
| payment_signature | [bytes](#bytes) | | signature of payment_header |


Expand Down
Loading

0 comments on commit 980a866

Please sign in to comment.