diff --git a/api/clients/accountant.go b/api/clients/accountant.go
index ef76eef1d..045877bd7 100644
--- a/api/clients/accountant.go
+++ b/api/clients/accountant.go
@@ -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
@@ -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
@@ -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
diff --git a/api/clients/accountant_test.go b/api/clients/accountant_test.go
index 5c19e1592..c6dc3fa69 100644
--- a/api/clients/accountant_test.go
+++ b/api/clients/accountant_test.go
@@ -15,6 +15,7 @@ import (
)
const numBins = uint32(3)
+const salt = uint32(0)
func TestNewAccountant(t *testing.T) {
reservation := &core.ActiveReservation{
@@ -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)
}
@@ -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)
@@ -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")
}
@@ -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")
}
@@ -222,7 +223,7 @@ 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)
@@ -230,12 +231,12 @@ func TestAccountBlob_BinRotation(t *testing.T) {
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)
}
@@ -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)
- // }
}()
}
@@ -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)
}
@@ -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)
@@ -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)
}
diff --git a/api/clients/disperser_client_v2.go b/api/clients/disperser_client_v2.go
index ec3407192..635a72bc6 100644
--- a/api/clients/disperser_client_v2.go
+++ b/api/clients/disperser_client_v2.go
@@ -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)
}
@@ -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 {
@@ -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)
}
diff --git a/api/docs/disperser.html b/api/docs/disperser.html
index f3f51e9f5..fba274aa7 100644
--- a/api/docs/disperser.html
+++ b/api/docs/disperser.html
@@ -839,7 +839,7 @@
DispersePaidBlobRequest
payment_header |
common.PaymentHeader |
|
- Payment header contains AccountID, BinIndex, and CumulativePayment |
+ Payment header contains account_id, reservation_period, cumulative_payment, and salt |
diff --git a/api/docs/disperser.md b/api/docs/disperser.md
index c900aef33..39f01e439 100644
--- a/api/docs/disperser.md
+++ b/api/docs/disperser.md
@@ -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 |
diff --git a/api/docs/eigenda-protos.html b/api/docs/eigenda-protos.html
index 168b8699d..987f3250d 100644
--- a/api/docs/eigenda-protos.html
+++ b/api/docs/eigenda-protos.html
@@ -949,21 +949,29 @@
account_id |
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. |
- bin_index |
+ reservation_period |
uint32 |
|
- |
+ The reservation period of the dispersal request. |
cumulative_payment |
bytes |
|
- |
+ The cumulative payment of the dispersal request. |
+
+
+
+ salt |
+ uint32 |
+ |
+ The salt of the disperser request. This is used to ensure that the payment header is intentionally unique. |
@@ -1713,7 +1721,7 @@ DispersePaidBlobRequest
payment_header |
common.PaymentHeader |
|
- Payment header contains AccountID, BinIndex, and CumulativePayment |
+ Payment header contains account_id, reservation_period, cumulative_payment, and salt |
diff --git a/api/docs/eigenda-protos.md b/api/docs/eigenda-protos.md
index 1e9b61912..732b7dc77 100644
--- a/api/docs/eigenda-protos.md
+++ b/api/docs/eigenda-protos.md
@@ -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. |
@@ -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 |
diff --git a/api/grpc/common/common.pb.go b/api/grpc/common/common.pb.go
index cdf0f16ab..8f31656a0 100644
--- a/api/grpc/common/common.pb.go
+++ b/api/grpc/common/common.pb.go
@@ -155,9 +155,15 @@ type PaymentHeader struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
- AccountId string `protobuf:"bytes,1,opt,name=account_id,json=accountId,proto3" json:"account_id,omitempty"`
- BinIndex uint32 `protobuf:"varint,2,opt,name=bin_index,json=binIndex,proto3" json:"bin_index,omitempty"`
+ // 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.
+ AccountId string `protobuf:"bytes,1,opt,name=account_id,json=accountId,proto3" json:"account_id,omitempty"`
+ // The reservation period of the dispersal request.
+ ReservationPeriod uint32 `protobuf:"varint,2,opt,name=reservation_period,json=reservationPeriod,proto3" json:"reservation_period,omitempty"`
+ // The cumulative payment of the dispersal request.
CumulativePayment []byte `protobuf:"bytes,3,opt,name=cumulative_payment,json=cumulativePayment,proto3" json:"cumulative_payment,omitempty"`
+ // The salt of the disperser request. This is used to ensure that the payment header is intentionally unique.
+ Salt uint32 `protobuf:"varint,4,opt,name=salt,proto3" json:"salt,omitempty"`
}
func (x *PaymentHeader) Reset() {
@@ -199,9 +205,9 @@ func (x *PaymentHeader) GetAccountId() string {
return ""
}
-func (x *PaymentHeader) GetBinIndex() uint32 {
+func (x *PaymentHeader) GetReservationPeriod() uint32 {
if x != nil {
- return x.BinIndex
+ return x.ReservationPeriod
}
return 0
}
@@ -213,6 +219,13 @@ func (x *PaymentHeader) GetCumulativePayment() []byte {
return nil
}
+func (x *PaymentHeader) GetSalt() uint32 {
+ if x != nil {
+ return x.Salt
+ }
+ return 0
+}
+
var File_common_common_proto protoreflect.FileDescriptor
var file_common_common_proto_rawDesc = []byte{
@@ -230,18 +243,20 @@ var file_common_common_proto_rawDesc = []byte{
0x67, 0x74, 0x68, 0x5f, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52,
0x0b, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x12, 0x16, 0x0a, 0x06,
0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x6c, 0x65,
- 0x6e, 0x67, 0x74, 0x68, 0x22, 0x7a, 0x0a, 0x0d, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x48,
- 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x1d, 0x0a, 0x0a, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74,
- 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, 0x63, 0x63, 0x6f, 0x75,
- 0x6e, 0x74, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x62, 0x69, 0x6e, 0x5f, 0x69, 0x6e, 0x64, 0x65,
- 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x62, 0x69, 0x6e, 0x49, 0x6e, 0x64, 0x65,
- 0x78, 0x12, 0x2d, 0x0a, 0x12, 0x63, 0x75, 0x6d, 0x75, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x5f,
- 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x11, 0x63,
- 0x75, 0x6d, 0x75, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74,
- 0x42, 0x2e, 0x5a, 0x2c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x4c,
- 0x61, 0x79, 0x72, 0x2d, 0x4c, 0x61, 0x62, 0x73, 0x2f, 0x65, 0x69, 0x67, 0x65, 0x6e, 0x64, 0x61,
- 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e,
- 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+ 0x6e, 0x67, 0x74, 0x68, 0x22, 0xa0, 0x01, 0x0a, 0x0d, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74,
+ 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x1d, 0x0a, 0x0a, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e,
+ 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, 0x63, 0x63, 0x6f,
+ 0x75, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x2d, 0x0a, 0x12, 0x72, 0x65, 0x73, 0x65, 0x72, 0x76, 0x61,
+ 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28,
+ 0x0d, 0x52, 0x11, 0x72, 0x65, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x65,
+ 0x72, 0x69, 0x6f, 0x64, 0x12, 0x2d, 0x0a, 0x12, 0x63, 0x75, 0x6d, 0x75, 0x6c, 0x61, 0x74, 0x69,
+ 0x76, 0x65, 0x5f, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c,
+ 0x52, 0x11, 0x63, 0x75, 0x6d, 0x75, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x50, 0x61, 0x79, 0x6d,
+ 0x65, 0x6e, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x61, 0x6c, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28,
+ 0x0d, 0x52, 0x04, 0x73, 0x61, 0x6c, 0x74, 0x42, 0x2e, 0x5a, 0x2c, 0x67, 0x69, 0x74, 0x68, 0x75,
+ 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x4c, 0x61, 0x79, 0x72, 0x2d, 0x4c, 0x61, 0x62, 0x73, 0x2f,
+ 0x65, 0x69, 0x67, 0x65, 0x6e, 0x64, 0x61, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x67, 0x72, 0x70, 0x63,
+ 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
diff --git a/api/grpc/disperser/disperser.pb.go b/api/grpc/disperser/disperser.pb.go
index d10d4d736..47d211b77 100644
--- a/api/grpc/disperser/disperser.pb.go
+++ b/api/grpc/disperser/disperser.pb.go
@@ -458,7 +458,7 @@ type DispersePaidBlobRequest struct {
Data []byte `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"`
// The quorums to which the blob to be sent
QuorumNumbers []uint32 `protobuf:"varint,2,rep,packed,name=quorum_numbers,json=quorumNumbers,proto3" json:"quorum_numbers,omitempty"`
- // Payment header contains AccountID, BinIndex, and CumulativePayment
+ // Payment header contains account_id, reservation_period, cumulative_payment, and salt
PaymentHeader *common.PaymentHeader `protobuf:"bytes,3,opt,name=payment_header,json=paymentHeader,proto3" json:"payment_header,omitempty"`
// signature of payment_header
PaymentSignature []byte `protobuf:"bytes,4,opt,name=payment_signature,json=paymentSignature,proto3" json:"payment_signature,omitempty"`
diff --git a/api/proto/common/common.proto b/api/proto/common/common.proto
index a457652ff..a75327ed7 100644
--- a/api/proto/common/common.proto
+++ b/api/proto/common/common.proto
@@ -19,7 +19,13 @@ message BlobCommitment {
}
message PaymentHeader {
+ // 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.
string account_id = 1;
- uint32 bin_index = 2;
+ // The reservation period of the dispersal request.
+ uint32 reservation_period = 2;
+ // The cumulative payment of the dispersal request.
bytes cumulative_payment = 3;
+ // The salt of the disperser request. This is used to ensure that the payment header is intentionally unique.
+ uint32 salt = 4;
}
diff --git a/api/proto/disperser/disperser.proto b/api/proto/disperser/disperser.proto
index f4bfa1384..ee537ee15 100644
--- a/api/proto/disperser/disperser.proto
+++ b/api/proto/disperser/disperser.proto
@@ -99,7 +99,7 @@ message DispersePaidBlobRequest {
// The quorums to which the blob to be sent
repeated uint32 quorum_numbers = 2;
- // Payment header contains AccountID, BinIndex, and CumulativePayment
+ // Payment header contains account_id, reservation_period, cumulative_payment, and salt
common.PaymentHeader payment_header = 3;
// signature of payment_header
bytes payment_signature = 4;
diff --git a/core/auth/v2/auth_test.go b/core/auth/v2/auth_test.go
index e700e3b9e..fb7c60cec 100644
--- a/core/auth/v2/auth_test.go
+++ b/core/auth/v2/auth_test.go
@@ -110,7 +110,7 @@ func testHeader(t *testing.T, accountID string) *corev2.BlobHeader {
QuorumNumbers: []core.QuorumID{0, 1},
PaymentMetadata: core.PaymentMetadata{
AccountID: accountID,
- BinIndex: 5,
+ ReservationPeriod: 5,
CumulativePayment: big.NewInt(100),
},
Signature: []byte{},
diff --git a/core/data.go b/core/data.go
index 256f6f70e..adfb1509d 100644
--- a/core/data.go
+++ b/core/data.go
@@ -490,11 +490,13 @@ type PaymentMetadata struct {
// AccountID is the ETH account address for the payer
AccountID string `json:"account_id"`
- // BinIndex represents the range of time at which the dispersal is made
- BinIndex uint32 `json:"bin_index"`
+ // ReservationPeriod represents the range of time at which the dispersal is made
+ ReservationPeriod uint32 `json:"reservation_period"`
// TODO: we are thinking the contract can use uint128 for cumulative payment,
// but the definition on v2 uses uint64. Double check with team.
CumulativePayment *big.Int `json:"cumulative_payment"`
+ // Allow same blob to be dispersed multiple times within the same reservation period
+ Salt uint32 `json:"salt"`
}
// Hash returns the Keccak256 hash of the PaymentMetadata
@@ -505,13 +507,17 @@ func (pm *PaymentMetadata) Hash() ([32]byte, error) {
Type: "string",
},
{
- Name: "binIndex",
+ Name: "reservationPeriod",
Type: "uint32",
},
{
Name: "cumulativePayment",
Type: "uint256",
},
+ {
+ Name: "salt",
+ Type: "uint32",
+ },
})
if err != nil {
return [32]byte{}, err
@@ -539,11 +545,12 @@ func (pm *PaymentMetadata) Hash() ([32]byte, error) {
func (pm *PaymentMetadata) MarshalDynamoDBAttributeValue() (types.AttributeValue, error) {
return &types.AttributeValueMemberM{
Value: map[string]types.AttributeValue{
- "AccountID": &types.AttributeValueMemberS{Value: pm.AccountID},
- "BinIndex": &types.AttributeValueMemberN{Value: fmt.Sprintf("%d", pm.BinIndex)},
+ "AccountID": &types.AttributeValueMemberS{Value: pm.AccountID},
+ "ReservationPeriod": &types.AttributeValueMemberN{Value: fmt.Sprintf("%d", pm.ReservationPeriod)},
"CumulativePayment": &types.AttributeValueMemberN{
Value: pm.CumulativePayment.String(),
},
+ "Salt": &types.AttributeValueMemberN{Value: fmt.Sprintf("%d", pm.Salt)},
},
}, nil
}
@@ -554,38 +561,26 @@ func (pm *PaymentMetadata) UnmarshalDynamoDBAttributeValue(av types.AttributeVal
return fmt.Errorf("expected *types.AttributeValueMemberM, got %T", av)
}
pm.AccountID = m.Value["AccountID"].(*types.AttributeValueMemberS).Value
- binIndex, err := strconv.ParseUint(m.Value["BinIndex"].(*types.AttributeValueMemberN).Value, 10, 32)
+ reservationPeriod, err := strconv.ParseUint(m.Value["ReservationPeriod"].(*types.AttributeValueMemberN).Value, 10, 32)
if err != nil {
- return fmt.Errorf("failed to parse BinIndex: %w", err)
+ return fmt.Errorf("failed to parse ReservationPeriod: %w", err)
}
- pm.BinIndex = uint32(binIndex)
+ pm.ReservationPeriod = uint32(reservationPeriod)
pm.CumulativePayment, _ = new(big.Int).SetString(m.Value["CumulativePayment"].(*types.AttributeValueMemberN).Value, 10)
+ salt, err := strconv.ParseUint(m.Value["Salt"].(*types.AttributeValueMemberN).Value, 10, 32)
+ if err != nil {
+ return fmt.Errorf("failed to parse Salt: %w", err)
+ }
+ pm.Salt = uint32(salt)
return nil
}
func (pm *PaymentMetadata) ToProtobuf() *commonpb.PaymentHeader {
return &commonpb.PaymentHeader{
AccountId: pm.AccountID,
- BinIndex: pm.BinIndex,
- CumulativePayment: pm.CumulativePayment.Bytes(),
- }
-}
-
-// ConvertPaymentHeader converts a protobuf payment header to a PaymentMetadata
-func ConvertPaymentHeader(header *commonpb.PaymentHeader) *PaymentMetadata {
- return &PaymentMetadata{
- AccountID: header.AccountId,
- BinIndex: header.BinIndex,
- CumulativePayment: new(big.Int).SetBytes(header.CumulativePayment),
- }
-}
-
-// ConvertToProtoPaymentHeader converts a PaymentMetadata to a protobuf payment header
-func (pm *PaymentMetadata) ConvertToProtoPaymentHeader() *commonpb.PaymentHeader {
- return &commonpb.PaymentHeader{
- AccountId: pm.AccountID,
- BinIndex: pm.BinIndex,
+ ReservationPeriod: pm.ReservationPeriod,
CumulativePayment: pm.CumulativePayment.Bytes(),
+ Salt: pm.Salt,
}
}
@@ -593,8 +588,9 @@ func (pm *PaymentMetadata) ConvertToProtoPaymentHeader() *commonpb.PaymentHeader
func ConvertToPaymentMetadata(ph *commonpb.PaymentHeader) *PaymentMetadata {
return &PaymentMetadata{
AccountID: ph.AccountId,
- BinIndex: ph.BinIndex,
+ ReservationPeriod: ph.ReservationPeriod,
CumulativePayment: new(big.Int).SetBytes(ph.CumulativePayment),
+ Salt: ph.Salt,
}
}
diff --git a/core/meterer/meterer.go b/core/meterer/meterer.go
index f8d46d0b7..7195972c4 100644
--- a/core/meterer/meterer.go
+++ b/core/meterer/meterer.go
@@ -22,7 +22,7 @@ type Config struct {
}
// Meterer handles payment accounting across different accounts. Disperser API server receives requests from clients and each request contains a blob header
-// with payments information (CumulativePayments, BinIndex, and Signature). Disperser will pass the blob header to the meterer, which will check if the
+// with payments information (CumulativePayments, ReservationPeriod, Salt, and Signature). Disperser will pass the blob header to the meterer, which will check if the
// payments information is valid.
type Meterer struct {
Config
@@ -100,7 +100,7 @@ func (m *Meterer) ServeReservationRequest(ctx context.Context, header core.Payme
if err := m.ValidateQuorum(quorumNumbers, reservation.QuorumNumbers); err != nil {
return fmt.Errorf("invalid quorum for reservation: %w", err)
}
- if !m.ValidateBinIndex(header, reservation) {
+ if !m.ValidateReservationPeriod(header, reservation) {
return fmt.Errorf("invalid bin index for reservation")
}
@@ -131,13 +131,13 @@ func (m *Meterer) ValidateQuorum(headerQuorums []uint8, allowedQuorums []uint8)
return nil
}
-// ValidateBinIndex checks if the provided bin index is valid
-func (m *Meterer) ValidateBinIndex(header core.PaymentMetadata, reservation *core.ActiveReservation) bool {
+// ValidateReservationPeriod checks if the provided bin index is valid
+func (m *Meterer) ValidateReservationPeriod(header core.PaymentMetadata, reservation *core.ActiveReservation) bool {
now := uint64(time.Now().Unix())
reservationWindow := m.ChainPaymentState.GetReservationWindow()
- currentBinIndex := GetBinIndex(now, reservationWindow)
+ currentReservationPeriod := GetReservationPeriod(now, reservationWindow)
// Valid bin indexes are either the current bin or the previous bin
- if (header.BinIndex != currentBinIndex && header.BinIndex != (currentBinIndex-1)) || (GetBinIndex(reservation.StartTimestamp, reservationWindow) > header.BinIndex || header.BinIndex > GetBinIndex(reservation.EndTimestamp, reservationWindow)) {
+ if (header.ReservationPeriod != currentReservationPeriod && header.ReservationPeriod != (currentReservationPeriod-1)) || (GetReservationPeriod(reservation.StartTimestamp, reservationWindow) > header.ReservationPeriod || header.ReservationPeriod > GetReservationPeriod(reservation.EndTimestamp, reservationWindow)) {
return false
}
return true
@@ -146,7 +146,7 @@ func (m *Meterer) ValidateBinIndex(header core.PaymentMetadata, reservation *cor
// IncrementBinUsage increments the bin usage atomically and checks for overflow
func (m *Meterer) IncrementBinUsage(ctx context.Context, header core.PaymentMetadata, reservation *core.ActiveReservation, numSymbols uint) error {
symbolsCharged := m.SymbolsCharged(numSymbols)
- newUsage, err := m.OffchainStore.UpdateReservationBin(ctx, header.AccountID, uint64(header.BinIndex), uint64(symbolsCharged))
+ newUsage, err := m.OffchainStore.UpdateReservationBin(ctx, header.AccountID, uint64(header.ReservationPeriod), uint64(symbolsCharged))
if err != nil {
return fmt.Errorf("failed to increment bin usage: %w", err)
}
@@ -159,8 +159,8 @@ func (m *Meterer) IncrementBinUsage(ctx context.Context, header core.PaymentMeta
// metered usage before updating the size already exceeded the limit
return fmt.Errorf("bin has already been filled")
}
- if newUsage <= 2*usageLimit && header.BinIndex+2 <= GetBinIndex(reservation.EndTimestamp, m.ChainPaymentState.GetReservationWindow()) {
- _, err := m.OffchainStore.UpdateReservationBin(ctx, header.AccountID, uint64(header.BinIndex+2), newUsage-usageLimit)
+ if newUsage <= 2*usageLimit && header.ReservationPeriod+2 <= GetReservationPeriod(reservation.EndTimestamp, m.ChainPaymentState.GetReservationWindow()) {
+ _, err := m.OffchainStore.UpdateReservationBin(ctx, header.AccountID, uint64(header.ReservationPeriod+2), newUsage-usageLimit)
if err != nil {
return err
}
@@ -169,9 +169,9 @@ func (m *Meterer) IncrementBinUsage(ctx context.Context, header core.PaymentMeta
return fmt.Errorf("overflow usage exceeds bin limit")
}
-// GetBinIndex returns the current bin index by chunking time by the bin interval;
+// GetReservationPeriod returns the current bin index by chunking time by the bin interval;
// bin interval used by the disperser should be public information
-func GetBinIndex(timestamp uint64, binInterval uint32) uint32 {
+func GetReservationPeriod(timestamp uint64, binInterval uint32) uint32 {
return uint32(timestamp) / binInterval
}
@@ -256,16 +256,16 @@ func (m *Meterer) SymbolsCharged(numSymbols uint) uint32 {
return uint32(core.RoundUpDivide(uint(numSymbols), uint(m.ChainPaymentState.GetMinNumSymbols()))) * m.ChainPaymentState.GetMinNumSymbols()
}
-// ValidateBinIndex checks if the provided bin index is valid
-func (m *Meterer) ValidateGlobalBinIndex(header core.PaymentMetadata) (uint32, error) {
+// ValidateReservationPeriod checks if the provided bin index is valid
+func (m *Meterer) ValidateGlobalReservationPeriod(header core.PaymentMetadata) (uint32, error) {
// Deterministic function: local clock -> index (1second intervals)
- currentBinIndex := uint32(time.Now().Unix())
+ currentReservationPeriod := uint32(time.Now().Unix())
// Valid bin indexes are either the current bin or the previous bin (allow this second or prev sec)
- if header.BinIndex != currentBinIndex && header.BinIndex != (currentBinIndex-1) {
+ if header.ReservationPeriod != currentReservationPeriod && header.ReservationPeriod != (currentReservationPeriod-1) {
return 0, fmt.Errorf("invalid bin index for on-demand request")
}
- return currentBinIndex, nil
+ return currentReservationPeriod, nil
}
// IncrementBinUsage increments the bin usage atomically and checks for overflow
diff --git a/core/meterer/meterer_test.go b/core/meterer/meterer_test.go
index dfc4b5f6b..6e3f980db 100644
--- a/core/meterer/meterer_test.go
+++ b/core/meterer/meterer_test.go
@@ -174,7 +174,7 @@ func TestMetererReservations(t *testing.T) {
paymentChainState.On("GetGlobalRateBinInterval", testifymock.Anything).Return(uint64(1), nil)
paymentChainState.On("GetMinNumSymbols", testifymock.Anything).Return(uint32(3), nil)
- binIndex := meterer.GetBinIndex(uint64(time.Now().Unix()), mt.ChainPaymentState.GetReservationWindow())
+ reservationPeriod := meterer.GetReservationPeriod(uint64(time.Now().Unix()), mt.ChainPaymentState.GetReservationWindow())
quoromNumbers := []uint8{0, 1}
paymentChainState.On("GetActiveReservationByAccount", testifymock.Anything, testifymock.MatchedBy(func(account gethcommon.Address) bool {
@@ -191,11 +191,11 @@ func TestMetererReservations(t *testing.T) {
assert.ErrorContains(t, err, "quorum number mismatch")
// overwhelming bin overflow for empty bins
- header = createPaymentHeader(binIndex-1, 0, accountID2)
+ header = createPaymentHeader(reservationPeriod-1, 0, accountID2)
err = mt.MeterRequest(ctx, *header, 10, quoromNumbers)
assert.NoError(t, err)
// overwhelming bin overflow for empty bins
- header = createPaymentHeader(binIndex-1, 0, accountID2)
+ header = createPaymentHeader(reservationPeriod-1, 0, accountID2)
err = mt.MeterRequest(ctx, *header, 1000, quoromNumbers)
assert.ErrorContains(t, err, "overflow usage exceeds bin limit")
@@ -210,7 +210,7 @@ func TestMetererReservations(t *testing.T) {
assert.ErrorContains(t, err, "failed to get active reservation by account: reservation not found")
// test invalid bin index
- header = createPaymentHeader(binIndex, 0, accountID1)
+ header = createPaymentHeader(reservationPeriod, 0, accountID1)
err = mt.MeterRequest(ctx, *header, 2000, quoromNumbers)
assert.ErrorContains(t, err, "invalid bin index for reservation")
@@ -218,37 +218,37 @@ func TestMetererReservations(t *testing.T) {
symbolLength := uint(20)
requiredLength := uint(21) // 21 should be charged for length of 20 since minNumSymbols is 3
for i := 0; i < 9; i++ {
- header = createPaymentHeader(binIndex, 0, accountID2)
+ header = createPaymentHeader(reservationPeriod, 0, accountID2)
err = mt.MeterRequest(ctx, *header, symbolLength, quoromNumbers)
assert.NoError(t, err)
item, err := dynamoClient.GetItem(ctx, reservationTableName, commondynamodb.Key{
- "AccountID": &types.AttributeValueMemberS{Value: accountID2.Hex()},
- "BinIndex": &types.AttributeValueMemberN{Value: strconv.Itoa(int(binIndex))},
+ "AccountID": &types.AttributeValueMemberS{Value: accountID2.Hex()},
+ "ReservationPeriod": &types.AttributeValueMemberN{Value: strconv.Itoa(int(reservationPeriod))},
})
assert.NoError(t, err)
assert.Equal(t, accountID2.Hex(), item["AccountID"].(*types.AttributeValueMemberS).Value)
- assert.Equal(t, strconv.Itoa(int(binIndex)), item["BinIndex"].(*types.AttributeValueMemberN).Value)
+ assert.Equal(t, strconv.Itoa(int(reservationPeriod)), item["ReservationPeriod"].(*types.AttributeValueMemberN).Value)
assert.Equal(t, strconv.Itoa((i+1)*int(requiredLength)), item["BinUsage"].(*types.AttributeValueMemberN).Value)
}
// first over flow is allowed
- header = createPaymentHeader(binIndex, 0, accountID2)
+ header = createPaymentHeader(reservationPeriod, 0, accountID2)
assert.NoError(t, err)
err = mt.MeterRequest(ctx, *header, 25, quoromNumbers)
assert.NoError(t, err)
- overflowedBinIndex := binIndex + 2
+ overflowedReservationPeriod := reservationPeriod + 2
item, err := dynamoClient.GetItem(ctx, reservationTableName, commondynamodb.Key{
- "AccountID": &types.AttributeValueMemberS{Value: accountID2.Hex()},
- "BinIndex": &types.AttributeValueMemberN{Value: strconv.Itoa(int(overflowedBinIndex))},
+ "AccountID": &types.AttributeValueMemberS{Value: accountID2.Hex()},
+ "ReservationPeriod": &types.AttributeValueMemberN{Value: strconv.Itoa(int(overflowedReservationPeriod))},
})
assert.NoError(t, err)
assert.Equal(t, accountID2.Hex(), item["AccountID"].(*types.AttributeValueMemberS).Value)
- assert.Equal(t, strconv.Itoa(int(overflowedBinIndex)), item["BinIndex"].(*types.AttributeValueMemberN).Value)
+ assert.Equal(t, strconv.Itoa(int(overflowedReservationPeriod)), item["ReservationPeriod"].(*types.AttributeValueMemberN).Value)
// 25 rounded up to the nearest multiple of minNumSymbols - (200-21*9) = 16
assert.Equal(t, strconv.Itoa(int(16)), item["BinUsage"].(*types.AttributeValueMemberN).Value)
// second over flow
- header = createPaymentHeader(binIndex, 0, accountID2)
+ header = createPaymentHeader(reservationPeriod, 0, accountID2)
assert.NoError(t, err)
err = mt.MeterRequest(ctx, *header, 1, quoromNumbers)
assert.ErrorContains(t, err, "bin has already been filled")
@@ -259,7 +259,7 @@ func TestMetererOnDemand(t *testing.T) {
quorumNumbers := []uint8{0, 1}
paymentChainState.On("GetPricePerSymbol", testifymock.Anything).Return(uint32(2), nil)
paymentChainState.On("GetMinNumSymbols", testifymock.Anything).Return(uint32(3), nil)
- binIndex := uint32(0) // this field doesn't matter for on-demand payments wrt global rate limit
+ reservationPeriod := uint32(0) // this field doesn't matter for on-demand payments wrt global rate limit
paymentChainState.On("GetOnDemandPaymentByAccount", testifymock.Anything, testifymock.MatchedBy(func(account gethcommon.Address) bool {
return account == accountID1
@@ -275,18 +275,18 @@ func TestMetererOnDemand(t *testing.T) {
if err != nil {
t.Fatalf("Failed to generate key: %v", err)
}
- header := createPaymentHeader(binIndex, 2, crypto.PubkeyToAddress(unregisteredUser.PublicKey))
+ header := createPaymentHeader(reservationPeriod, 2, crypto.PubkeyToAddress(unregisteredUser.PublicKey))
assert.NoError(t, err)
err = mt.MeterRequest(ctx, *header, 1000, quorumNumbers)
assert.ErrorContains(t, err, "failed to get on-demand payment by account: payment not found")
// test invalid quorom ID
- header = createPaymentHeader(binIndex, 1, accountID1)
+ header = createPaymentHeader(reservationPeriod, 1, accountID1)
err = mt.MeterRequest(ctx, *header, 1000, []uint8{0, 1, 2})
assert.ErrorContains(t, err, "invalid quorum for On-Demand Request")
// test insufficient cumulative payment
- header = createPaymentHeader(binIndex, 1, accountID1)
+ header = createPaymentHeader(reservationPeriod, 1, accountID1)
err = mt.MeterRequest(ctx, *header, 1000, quorumNumbers)
assert.ErrorContains(t, err, "insufficient cumulative payment increment")
// No rollback after meter request
@@ -301,22 +301,22 @@ func TestMetererOnDemand(t *testing.T) {
symbolLength := uint(100)
priceCharged := mt.PaymentCharged(symbolLength)
assert.Equal(t, uint64(102*mt.ChainPaymentState.GetPricePerSymbol()), priceCharged)
- header = createPaymentHeader(binIndex, priceCharged, accountID2)
+ header = createPaymentHeader(reservationPeriod, priceCharged, accountID2)
err = mt.MeterRequest(ctx, *header, symbolLength, quorumNumbers)
assert.NoError(t, err)
- header = createPaymentHeader(binIndex, priceCharged, accountID2)
+ header = createPaymentHeader(reservationPeriod, priceCharged, accountID2)
err = mt.MeterRequest(ctx, *header, symbolLength, quorumNumbers)
assert.ErrorContains(t, err, "exact payment already exists")
// test valid payments
for i := 1; i < 9; i++ {
- header = createPaymentHeader(binIndex, uint64(priceCharged)*uint64(i+1), accountID2)
+ header = createPaymentHeader(reservationPeriod, uint64(priceCharged)*uint64(i+1), accountID2)
err = mt.MeterRequest(ctx, *header, symbolLength, quorumNumbers)
assert.NoError(t, err)
}
// test cumulative payment on-chain constraint
- header = createPaymentHeader(binIndex, 2023, accountID2)
+ header = createPaymentHeader(reservationPeriod, 2023, accountID2)
err = mt.MeterRequest(ctx, *header, 1, quorumNumbers)
assert.ErrorContains(t, err, "invalid on-demand payment: request claims a cumulative payment greater than the on-chain deposit")
@@ -324,13 +324,13 @@ func TestMetererOnDemand(t *testing.T) {
previousCumulativePayment := uint64(priceCharged) * uint64(9)
symbolLength = uint(2)
priceCharged = mt.PaymentCharged(symbolLength)
- header = createPaymentHeader(binIndex, previousCumulativePayment+priceCharged-1, accountID2)
+ header = createPaymentHeader(reservationPeriod, previousCumulativePayment+priceCharged-1, accountID2)
err = mt.MeterRequest(ctx, *header, symbolLength, quorumNumbers)
assert.ErrorContains(t, err, "invalid on-demand payment: insufficient cumulative payment increment")
previousCumulativePayment = previousCumulativePayment + priceCharged
// test cannot insert cumulative payment in out of order
- header = createPaymentHeader(binIndex, mt.PaymentCharged(50), accountID2)
+ header = createPaymentHeader(reservationPeriod, mt.PaymentCharged(50), accountID2)
err = mt.MeterRequest(ctx, *header, 50, quorumNumbers)
assert.ErrorContains(t, err, "invalid on-demand payment: breaking cumulative payment invariants")
@@ -342,7 +342,7 @@ func TestMetererOnDemand(t *testing.T) {
assert.NoError(t, err)
assert.Equal(t, numPrevRecords, len(result))
// test failed global rate limit (previously payment recorded: 2, global limit: 1009)
- header = createPaymentHeader(binIndex, previousCumulativePayment+mt.PaymentCharged(1010), accountID1)
+ header = createPaymentHeader(reservationPeriod, previousCumulativePayment+mt.PaymentCharged(1010), accountID1)
err = mt.MeterRequest(ctx, *header, 1010, quorumNumbers)
assert.ErrorContains(t, err, "failed global rate limiting")
// Correct rollback
@@ -465,10 +465,10 @@ func TestMeterer_symbolsCharged(t *testing.T) {
}
}
-func createPaymentHeader(binIndex uint32, cumulativePayment uint64, accountID gethcommon.Address) *core.PaymentMetadata {
+func createPaymentHeader(reservationPeriod uint32, cumulativePayment uint64, accountID gethcommon.Address) *core.PaymentMetadata {
return &core.PaymentMetadata{
AccountID: accountID.Hex(),
- BinIndex: binIndex,
+ ReservationPeriod: reservationPeriod,
CumulativePayment: big.NewInt(int64(cumulativePayment)),
}
}
diff --git a/core/meterer/offchain_store.go b/core/meterer/offchain_store.go
index bb5f8e185..f80ddd891 100644
--- a/core/meterer/offchain_store.go
+++ b/core/meterer/offchain_store.go
@@ -66,10 +66,10 @@ func NewOffchainStore(
}
type ReservationBin struct {
- AccountID string
- BinIndex uint32
- BinUsage uint32
- UpdatedAt time.Time
+ AccountID string
+ ReservationPeriod uint32
+ BinUsage uint32
+ UpdatedAt time.Time
}
type PaymentTuple struct {
@@ -78,15 +78,15 @@ type PaymentTuple struct {
}
type GlobalBin struct {
- BinIndex uint32
- BinUsage uint64
- UpdatedAt time.Time
+ ReservationPeriod uint32
+ BinUsage uint64
+ UpdatedAt time.Time
}
-func (s *OffchainStore) UpdateReservationBin(ctx context.Context, accountID string, binIndex uint64, size uint64) (uint64, error) {
+func (s *OffchainStore) UpdateReservationBin(ctx context.Context, accountID string, reservationPeriod uint64, size uint64) (uint64, error) {
key := map[string]types.AttributeValue{
- "AccountID": &types.AttributeValueMemberS{Value: accountID},
- "BinIndex": &types.AttributeValueMemberN{Value: strconv.FormatUint(binIndex, 10)},
+ "AccountID": &types.AttributeValueMemberS{Value: accountID},
+ "ReservationPeriod": &types.AttributeValueMemberN{Value: strconv.FormatUint(reservationPeriod, 10)},
}
res, err := s.dynamoClient.IncrementBy(ctx, s.reservationTableName, key, "BinUsage", size)
@@ -112,9 +112,9 @@ func (s *OffchainStore) UpdateReservationBin(ctx context.Context, accountID stri
return binUsageValue, nil
}
-func (s *OffchainStore) UpdateGlobalBin(ctx context.Context, binIndex uint64, size uint64) (uint64, error) {
+func (s *OffchainStore) UpdateGlobalBin(ctx context.Context, reservationPeriod uint64, size uint64) (uint64, error) {
key := map[string]types.AttributeValue{
- "BinIndex": &types.AttributeValueMemberN{Value: strconv.FormatUint(binIndex, 10)},
+ "ReservationPeriod": &types.AttributeValueMemberN{Value: strconv.FormatUint(reservationPeriod, 10)},
}
res, err := s.dynamoClient.IncrementBy(ctx, s.globalBinTableName, key, "BinUsage", size)
@@ -241,14 +241,14 @@ func (s *OffchainStore) GetRelevantOnDemandRecords(ctx context.Context, accountI
return prevPayment, nextPayment, nextDataLength, nil
}
-func (s *OffchainStore) GetBinRecords(ctx context.Context, accountID string, binIndex uint32) ([MinNumBins]*pb.BinRecord, error) {
+func (s *OffchainStore) GetBinRecords(ctx context.Context, accountID string, reservationPeriod uint32) ([MinNumBins]*pb.BinRecord, error) {
// Fetch the 3 bins start from the current bin
queryInput := &dynamodb.QueryInput{
TableName: aws.String(s.reservationTableName),
- KeyConditionExpression: aws.String("AccountID = :account AND BinIndex > :binIndex"),
+ KeyConditionExpression: aws.String("AccountID = :account AND ReservationPeriod > :reservationPeriod"),
ExpressionAttributeValues: commondynamodb.ExpressionValues{
- ":account": &types.AttributeValueMemberS{Value: accountID},
- ":binIndex": &types.AttributeValueMemberN{Value: strconv.FormatUint(uint64(binIndex), 10)},
+ ":account": &types.AttributeValueMemberS{Value: accountID},
+ ":reservationPeriod": &types.AttributeValueMemberN{Value: strconv.FormatUint(uint64(reservationPeriod), 10)},
},
ScanIndexForward: aws.Bool(true),
Limit: aws.Int32(MinNumBins),
@@ -299,19 +299,19 @@ func (s *OffchainStore) GetLargestCumulativePayment(ctx context.Context, account
}
func parseBinRecord(bin map[string]types.AttributeValue) (*pb.BinRecord, error) {
- binIndex, ok := bin["BinIndex"]
+ reservationPeriod, ok := bin["ReservationPeriod"]
if !ok {
- return nil, errors.New("BinIndex is not present in the response")
+ return nil, errors.New("ReservationPeriod is not present in the response")
}
- binIndexAttr, ok := binIndex.(*types.AttributeValueMemberN)
+ reservationPeriodAttr, ok := reservationPeriod.(*types.AttributeValueMemberN)
if !ok {
- return nil, fmt.Errorf("unexpected type for BinIndex: %T", binIndex)
+ return nil, fmt.Errorf("unexpected type for ReservationPeriod: %T", reservationPeriod)
}
- binIndexValue, err := strconv.ParseUint(binIndexAttr.Value, 10, 32)
+ reservationPeriodValue, err := strconv.ParseUint(reservationPeriodAttr.Value, 10, 32)
if err != nil {
- return nil, fmt.Errorf("failed to parse BinIndex: %w", err)
+ return nil, fmt.Errorf("failed to parse ReservationPeriod: %w", err)
}
binUsage, ok := bin["BinUsage"]
@@ -330,7 +330,7 @@ func parseBinRecord(bin map[string]types.AttributeValue) (*pb.BinRecord, error)
}
return &pb.BinRecord{
- Index: uint32(binIndexValue),
+ Index: uint32(reservationPeriodValue),
Usage: uint64(binUsageValue),
}, nil
}
diff --git a/core/meterer/offchain_store_test.go b/core/meterer/offchain_store_test.go
index 1c3351764..79963b059 100644
--- a/core/meterer/offchain_store_test.go
+++ b/core/meterer/offchain_store_test.go
@@ -21,22 +21,22 @@ func TestReservationBinsBasicOperations(t *testing.T) {
ctx := context.Background()
err = dynamoClient.PutItem(ctx, tableName,
commondynamodb.Item{
- "AccountID": &types.AttributeValueMemberS{Value: "account1"},
- "BinIndex": &types.AttributeValueMemberN{Value: "1"},
- "BinUsage": &types.AttributeValueMemberN{Value: "1000"},
- "UpdatedAt": &types.AttributeValueMemberS{Value: time.Now().Format(time.RFC3339)},
+ "AccountID": &types.AttributeValueMemberS{Value: "account1"},
+ "ReservationPeriod": &types.AttributeValueMemberN{Value: "1"},
+ "BinUsage": &types.AttributeValueMemberN{Value: "1000"},
+ "UpdatedAt": &types.AttributeValueMemberS{Value: time.Now().Format(time.RFC3339)},
},
)
assert.NoError(t, err)
item, err := dynamoClient.GetItem(ctx, tableName, commondynamodb.Key{
- "AccountID": &types.AttributeValueMemberS{Value: "account1"},
- "BinIndex": &types.AttributeValueMemberN{Value: "1"},
+ "AccountID": &types.AttributeValueMemberS{Value: "account1"},
+ "ReservationPeriod": &types.AttributeValueMemberN{Value: "1"},
})
assert.NoError(t, err)
assert.Equal(t, "account1", item["AccountID"].(*types.AttributeValueMemberS).Value)
- assert.Equal(t, "1", item["BinIndex"].(*types.AttributeValueMemberN).Value)
+ assert.Equal(t, "1", item["ReservationPeriod"].(*types.AttributeValueMemberN).Value)
assert.Equal(t, "1000", item["BinUsage"].(*types.AttributeValueMemberN).Value)
items, err := dynamoClient.Query(ctx, tableName, "AccountID = :account", commondynamodb.ExpressionValues{
@@ -51,25 +51,25 @@ func TestReservationBinsBasicOperations(t *testing.T) {
assert.Error(t, err)
_, err = dynamoClient.UpdateItem(ctx, tableName, commondynamodb.Key{
- "AccountID": &types.AttributeValueMemberS{Value: "account1"},
- "BinIndex": &types.AttributeValueMemberN{Value: "1"},
+ "AccountID": &types.AttributeValueMemberS{Value: "account1"},
+ "ReservationPeriod": &types.AttributeValueMemberN{Value: "1"},
}, commondynamodb.Item{
"BinUsage": &types.AttributeValueMemberN{Value: "2000"},
})
assert.NoError(t, err)
err = dynamoClient.PutItem(ctx, tableName,
commondynamodb.Item{
- "AccountID": &types.AttributeValueMemberS{Value: "account2"},
- "BinIndex": &types.AttributeValueMemberN{Value: "1"},
- "BinUsage": &types.AttributeValueMemberN{Value: "3000"},
- "UpdatedAt": &types.AttributeValueMemberS{Value: time.Now().Format(time.RFC3339)},
+ "AccountID": &types.AttributeValueMemberS{Value: "account2"},
+ "ReservationPeriod": &types.AttributeValueMemberN{Value: "1"},
+ "BinUsage": &types.AttributeValueMemberN{Value: "3000"},
+ "UpdatedAt": &types.AttributeValueMemberS{Value: time.Now().Format(time.RFC3339)},
},
)
assert.NoError(t, err)
item, err = dynamoClient.GetItem(ctx, tableName, commondynamodb.Key{
- "AccountID": &types.AttributeValueMemberS{Value: "account1"},
- "BinIndex": &types.AttributeValueMemberN{Value: "1"},
+ "AccountID": &types.AttributeValueMemberS{Value: "account1"},
+ "ReservationPeriod": &types.AttributeValueMemberN{Value: "1"},
})
assert.NoError(t, err)
assert.Equal(t, "2000", item["BinUsage"].(*types.AttributeValueMemberN).Value)
@@ -82,8 +82,8 @@ func TestReservationBinsBasicOperations(t *testing.T) {
assert.Equal(t, "2000", items[0]["BinUsage"].(*types.AttributeValueMemberN).Value)
item, err = dynamoClient.GetItem(ctx, tableName, commondynamodb.Key{
- "AccountID": &types.AttributeValueMemberS{Value: "account2"},
- "BinIndex": &types.AttributeValueMemberN{Value: "1"},
+ "AccountID": &types.AttributeValueMemberS{Value: "account2"},
+ "ReservationPeriod": &types.AttributeValueMemberN{Value: "1"},
})
assert.NoError(t, err)
assert.Equal(t, "3000", item["BinUsage"].(*types.AttributeValueMemberN).Value)
@@ -102,34 +102,34 @@ func TestGlobalBinsBasicOperations(t *testing.T) {
items := make([]commondynamodb.Item, numItems)
for i := 0; i < numItems; i += 1 {
items[i] = commondynamodb.Item{
- "BinIndex": &types.AttributeValueMemberN{Value: fmt.Sprintf("%d", i)},
- "BinUsage": &types.AttributeValueMemberN{Value: "1000"},
- "UpdatedAt": &types.AttributeValueMemberS{Value: time.Now().Format(time.RFC3339)},
+ "ReservationPeriod": &types.AttributeValueMemberN{Value: fmt.Sprintf("%d", i)},
+ "BinUsage": &types.AttributeValueMemberN{Value: "1000"},
+ "UpdatedAt": &types.AttributeValueMemberS{Value: time.Now().Format(time.RFC3339)},
}
}
unprocessed, err := dynamoClient.PutItems(ctx, tableName, items)
assert.NoError(t, err)
assert.Len(t, unprocessed, 0)
- queryResult, err := dynamoClient.Query(ctx, tableName, "BinIndex = :index", commondynamodb.ExpressionValues{
+ queryResult, err := dynamoClient.Query(ctx, tableName, "ReservationPeriod = :index", commondynamodb.ExpressionValues{
":index": &types.AttributeValueMemberN{
Value: "1",
}})
assert.NoError(t, err)
assert.Len(t, queryResult, 1)
- assert.Equal(t, "1", queryResult[0]["BinIndex"].(*types.AttributeValueMemberN).Value)
+ assert.Equal(t, "1", queryResult[0]["ReservationPeriod"].(*types.AttributeValueMemberN).Value)
assert.Equal(t, "1000", queryResult[0]["BinUsage"].(*types.AttributeValueMemberN).Value)
- queryResult, err = dynamoClient.Query(ctx, tableName, "BinIndex = :index", commondynamodb.ExpressionValues{
+ queryResult, err = dynamoClient.Query(ctx, tableName, "ReservationPeriod = :index", commondynamodb.ExpressionValues{
":index": &types.AttributeValueMemberN{
Value: "1",
}})
assert.NoError(t, err)
assert.Len(t, queryResult, 1)
- assert.Equal(t, "1", queryResult[0]["BinIndex"].(*types.AttributeValueMemberN).Value)
+ assert.Equal(t, "1", queryResult[0]["ReservationPeriod"].(*types.AttributeValueMemberN).Value)
assert.Equal(t, "1000", queryResult[0]["BinUsage"].(*types.AttributeValueMemberN).Value)
- queryResult, err = dynamoClient.Query(ctx, tableName, "BinIndex = :index", commondynamodb.ExpressionValues{
+ queryResult, err = dynamoClient.Query(ctx, tableName, "ReservationPeriod = :index", commondynamodb.ExpressionValues{
":index": &types.AttributeValueMemberN{
Value: "32",
}})
@@ -137,7 +137,7 @@ func TestGlobalBinsBasicOperations(t *testing.T) {
assert.Len(t, queryResult, 0)
_, err = dynamoClient.UpdateItem(ctx, tableName, commondynamodb.Key{
- "BinIndex": &types.AttributeValueMemberN{Value: "1"},
+ "ReservationPeriod": &types.AttributeValueMemberN{Value: "1"},
}, commondynamodb.Item{
"BinUsage": &types.AttributeValueMemberN{Value: "2000"},
})
@@ -145,29 +145,29 @@ func TestGlobalBinsBasicOperations(t *testing.T) {
err = dynamoClient.PutItem(ctx, tableName,
commondynamodb.Item{
- "BinIndex": &types.AttributeValueMemberN{Value: "2"},
- "BinUsage": &types.AttributeValueMemberN{Value: "3000"},
- "UpdatedAt": &types.AttributeValueMemberS{Value: time.Now().Format(time.RFC3339)},
+ "ReservationPeriod": &types.AttributeValueMemberN{Value: "2"},
+ "BinUsage": &types.AttributeValueMemberN{Value: "3000"},
+ "UpdatedAt": &types.AttributeValueMemberS{Value: time.Now().Format(time.RFC3339)},
},
)
assert.NoError(t, err)
- queryResult, err = dynamoClient.Query(ctx, tableName, "BinIndex = :index", commondynamodb.ExpressionValues{
+ queryResult, err = dynamoClient.Query(ctx, tableName, "ReservationPeriod = :index", commondynamodb.ExpressionValues{
":index": &types.AttributeValueMemberN{
Value: "1",
}})
assert.NoError(t, err)
assert.Len(t, queryResult, 1)
- assert.Equal(t, "1", queryResult[0]["BinIndex"].(*types.AttributeValueMemberN).Value)
+ assert.Equal(t, "1", queryResult[0]["ReservationPeriod"].(*types.AttributeValueMemberN).Value)
assert.Equal(t, "2000", queryResult[0]["BinUsage"].(*types.AttributeValueMemberN).Value)
- queryResult, err = dynamoClient.Query(ctx, tableName, "BinIndex = :index", commondynamodb.ExpressionValues{
+ queryResult, err = dynamoClient.Query(ctx, tableName, "ReservationPeriod = :index", commondynamodb.ExpressionValues{
":index": &types.AttributeValueMemberN{
Value: "2",
}})
assert.NoError(t, err)
assert.Len(t, queryResult, 1)
- assert.Equal(t, "2", queryResult[0]["BinIndex"].(*types.AttributeValueMemberN).Value)
+ assert.Equal(t, "2", queryResult[0]["ReservationPeriod"].(*types.AttributeValueMemberN).Value)
assert.Equal(t, "3000", queryResult[0]["BinUsage"].(*types.AttributeValueMemberN).Value)
}
diff --git a/core/meterer/util.go b/core/meterer/util.go
index 92b769370..0aa44dffd 100644
--- a/core/meterer/util.go
+++ b/core/meterer/util.go
@@ -19,7 +19,7 @@ func CreateReservationTable(clientConfig commonaws.ClientConfig, tableName strin
AttributeType: types.ScalarAttributeTypeS,
},
{
- AttributeName: aws.String("BinIndex"),
+ AttributeName: aws.String("ReservationPeriod"),
AttributeType: types.ScalarAttributeTypeN,
},
},
@@ -29,7 +29,7 @@ func CreateReservationTable(clientConfig commonaws.ClientConfig, tableName strin
KeyType: types.KeyTypeHash,
},
{
- AttributeName: aws.String("BinIndex"),
+ AttributeName: aws.String("ReservationPeriod"),
KeyType: types.KeyTypeRange,
},
},
@@ -47,22 +47,22 @@ func CreateGlobalReservationTable(clientConfig commonaws.ClientConfig, tableName
_, err := test_utils.CreateTable(ctx, clientConfig, tableName, &dynamodb.CreateTableInput{
AttributeDefinitions: []types.AttributeDefinition{
{
- AttributeName: aws.String("BinIndex"),
+ AttributeName: aws.String("ReservationPeriod"),
AttributeType: types.ScalarAttributeTypeN,
},
},
KeySchema: []types.KeySchemaElement{
{
- AttributeName: aws.String("BinIndex"),
+ AttributeName: aws.String("ReservationPeriod"),
KeyType: types.KeyTypeHash,
},
},
GlobalSecondaryIndexes: []types.GlobalSecondaryIndex{
{
- IndexName: aws.String("BinIndexIndex"),
+ IndexName: aws.String("ReservationPeriodIndex"),
KeySchema: []types.KeySchemaElement{
{
- AttributeName: aws.String("BinIndex"),
+ AttributeName: aws.String("ReservationPeriod"),
KeyType: types.KeyTypeHash,
},
},
diff --git a/core/v2/serialization_test.go b/core/v2/serialization_test.go
index 20b4d830f..78e97d190 100644
--- a/core/v2/serialization_test.go
+++ b/core/v2/serialization_test.go
@@ -23,13 +23,14 @@ func TestBlobKey(t *testing.T) {
func TestPaymentHash(t *testing.T) {
pm := core.PaymentMetadata{
AccountID: "0x123",
- BinIndex: 5,
+ ReservationPeriod: 5,
CumulativePayment: big.NewInt(100),
+ Salt: 42,
}
hash, err := pm.Hash()
assert.NoError(t, err)
- // 0xf5894a8e9281b5687c0c7757d3d45fb76152bf659e6e61b1062f4c6bcb69c449 verified in solidity
- assert.Equal(t, "f5894a8e9281b5687c0c7757d3d45fb76152bf659e6e61b1062f4c6bcb69c449", hex.EncodeToString(hash[:]))
+ // 0xd0c8a7a362a45a875d9eb78ef577d563d759e3a615a5f81f71bfc5e85f6bcf59 verified in solidity
+ assert.Equal(t, "d0c8a7a362a45a875d9eb78ef577d563d759e3a615a5f81f71bfc5e85f6bcf59", hex.EncodeToString(hash[:]))
}
func TestBlobKeyFromHeader(t *testing.T) {
@@ -45,15 +46,15 @@ func TestBlobKeyFromHeader(t *testing.T) {
QuorumNumbers: []core.QuorumID{0, 1},
PaymentMetadata: core.PaymentMetadata{
AccountID: "0x123",
- BinIndex: 5,
+ ReservationPeriod: 5,
CumulativePayment: big.NewInt(100),
},
Signature: []byte{1, 2, 3},
}
blobKey, err := bh.BlobKey()
assert.NoError(t, err)
- // 0x40efb7273649f39590b27550ea06eeb81efd6ae4d719385a302fbd93173a395d verified in solidity
- assert.Equal(t, "40efb7273649f39590b27550ea06eeb81efd6ae4d719385a302fbd93173a395d", blobKey.Hex())
+ // 0x1354b29d9dd9a332959795d17f456c219566417fdbf1a7b4f5d118f5c2a36bbd verified in solidity
+ assert.Equal(t, "1354b29d9dd9a332959795d17f456c219566417fdbf1a7b4f5d118f5c2a36bbd", blobKey.Hex())
}
func TestBatchHeaderHash(t *testing.T) {
@@ -99,7 +100,7 @@ func TestBlobCertHash(t *testing.T) {
QuorumNumbers: []core.QuorumID{0, 1},
PaymentMetadata: core.PaymentMetadata{
AccountID: "0x123",
- BinIndex: 5,
+ ReservationPeriod: 5,
CumulativePayment: big.NewInt(100),
},
Signature: []byte{1, 2, 3},
@@ -109,8 +110,8 @@ func TestBlobCertHash(t *testing.T) {
hash, err := blobCert.Hash()
assert.NoError(t, err)
- // 0x3719a91e2a294feafdd624c1c88a6f1db1a5c79ee0863b352255bc9162f02751 verified in solidity
- assert.Equal(t, "3719a91e2a294feafdd624c1c88a6f1db1a5c79ee0863b352255bc9162f02751", hex.EncodeToString(hash[:]))
+ // 0xad938e477d0bc1f9f4e8de7c5cd837560bdbb2dc7094207a7ad53e7442611a43 verified in solidity
+ assert.Equal(t, "ad938e477d0bc1f9f4e8de7c5cd837560bdbb2dc7094207a7ad53e7442611a43", hex.EncodeToString(hash[:]))
}
func TestBlobCertSerialization(t *testing.T) {
@@ -127,7 +128,7 @@ func TestBlobCertSerialization(t *testing.T) {
QuorumNumbers: []core.QuorumID{0, 1},
PaymentMetadata: core.PaymentMetadata{
AccountID: "0x123",
- BinIndex: 5,
+ ReservationPeriod: 5,
CumulativePayment: big.NewInt(100),
},
Signature: []byte{1, 2, 3},
diff --git a/core/v2/types.go b/core/v2/types.go
index cc34b8ccf..90cb5524a 100644
--- a/core/v2/types.go
+++ b/core/v2/types.go
@@ -4,7 +4,6 @@ import (
"encoding/hex"
"errors"
"fmt"
- "math/big"
"strings"
commonpb "github.com/Layr-Labs/eigenda/api/grpc/common/v2"
@@ -109,11 +108,7 @@ func BlobHeaderFromProtobuf(proto *commonpb.BlobHeader) (*BlobHeader, error) {
quorumNumbers[i] = core.QuorumID(q)
}
- paymentMetadata := core.PaymentMetadata{
- AccountID: proto.GetPaymentHeader().GetAccountId(),
- BinIndex: proto.GetPaymentHeader().GetBinIndex(),
- CumulativePayment: new(big.Int).SetBytes(proto.GetPaymentHeader().GetCumulativePayment()),
- }
+ paymentMetadata := core.ConvertToPaymentMetadata(proto.GetPaymentHeader())
return &BlobHeader{
BlobVersion: BlobVersion(proto.GetVersion()),
@@ -124,7 +119,7 @@ func BlobHeaderFromProtobuf(proto *commonpb.BlobHeader) (*BlobHeader, error) {
Length: uint(proto.GetCommitment().GetLength()),
},
QuorumNumbers: quorumNumbers,
- PaymentMetadata: paymentMetadata,
+ PaymentMetadata: *paymentMetadata,
Signature: proto.GetSignature(),
}, nil
}
diff --git a/core/v2/types_test.go b/core/v2/types_test.go
index a5e25f0d1..8647ae5b5 100644
--- a/core/v2/types_test.go
+++ b/core/v2/types_test.go
@@ -23,7 +23,7 @@ func TestConvertBatchToFromProtobuf(t *testing.T) {
QuorumNumbers: []core.QuorumID{0, 1},
PaymentMetadata: core.PaymentMetadata{
AccountID: "0x123",
- BinIndex: 5,
+ ReservationPeriod: 5,
CumulativePayment: big.NewInt(100),
},
Signature: []byte{1, 2, 3},
@@ -34,7 +34,7 @@ func TestConvertBatchToFromProtobuf(t *testing.T) {
QuorumNumbers: []core.QuorumID{0, 1},
PaymentMetadata: core.PaymentMetadata{
AccountID: "0x456",
- BinIndex: 6,
+ ReservationPeriod: 6,
CumulativePayment: big.NewInt(200),
},
Signature: []byte{1, 2, 3},
@@ -79,7 +79,7 @@ func TestConvertBlobHeaderToFromProtobuf(t *testing.T) {
QuorumNumbers: []core.QuorumID{0, 1},
PaymentMetadata: core.PaymentMetadata{
AccountID: "0x123",
- BinIndex: 5,
+ ReservationPeriod: 5,
CumulativePayment: big.NewInt(100),
},
Signature: []byte{1, 2, 3},
@@ -107,7 +107,7 @@ func TestConvertBlobCertToFromProtobuf(t *testing.T) {
QuorumNumbers: []core.QuorumID{0, 1},
PaymentMetadata: core.PaymentMetadata{
AccountID: "0x123",
- BinIndex: 5,
+ ReservationPeriod: 5,
CumulativePayment: big.NewInt(100),
},
Signature: []byte{1, 2, 3},
diff --git a/disperser/apiserver/disperse_blob_v2.go b/disperser/apiserver/disperse_blob_v2.go
index 230d2a82c..c5999a4d6 100644
--- a/disperser/apiserver/disperse_blob_v2.go
+++ b/disperser/apiserver/disperse_blob_v2.go
@@ -127,19 +127,19 @@ func (s *DispersalServerV2) validateDispersalRequest(ctx context.Context, req *p
return api.NewErrorInvalidArg(fmt.Sprintf("authentication failed: %s", err.Error()))
}
- if len(blobHeader.PaymentMetadata.AccountID) == 0 || blobHeader.PaymentMetadata.BinIndex == 0 || blobHeader.PaymentMetadata.CumulativePayment == nil {
+ if len(blobHeader.PaymentMetadata.AccountID) == 0 || blobHeader.PaymentMetadata.ReservationPeriod == 0 || blobHeader.PaymentMetadata.CumulativePayment == nil {
return api.NewErrorInvalidArg("invalid payment metadata")
}
// handle payments and check rate limits
if blobHeaderProto.GetPaymentHeader() != nil {
- binIndex := blobHeaderProto.GetPaymentHeader().GetBinIndex()
+ reservationPeriod := blobHeaderProto.GetPaymentHeader().GetReservationPeriod()
cumulativePayment := new(big.Int).SetBytes(blobHeaderProto.GetPaymentHeader().GetCumulativePayment())
accountID := blobHeaderProto.GetPaymentHeader().GetAccountId()
paymentHeader := core.PaymentMetadata{
AccountID: accountID,
- BinIndex: binIndex,
+ ReservationPeriod: reservationPeriod,
CumulativePayment: cumulativePayment,
}
diff --git a/disperser/apiserver/server_v2.go b/disperser/apiserver/server_v2.go
index 877598a3f..e808a813c 100644
--- a/disperser/apiserver/server_v2.go
+++ b/disperser/apiserver/server_v2.go
@@ -250,8 +250,8 @@ func (s *DispersalServerV2) GetPaymentState(ctx context.Context, req *pb.GetPaym
// off-chain account specific payment state
now := uint64(time.Now().Unix())
- currentBinIndex := meterer.GetBinIndex(now, reservationWindow)
- binRecords, err := s.meterer.OffchainStore.GetBinRecords(ctx, req.AccountId, currentBinIndex)
+ currentReservationPeriod := meterer.GetReservationPeriod(now, reservationWindow)
+ binRecords, err := s.meterer.OffchainStore.GetBinRecords(ctx, req.AccountId, currentReservationPeriod)
if err != nil {
return nil, api.NewErrorNotFound("failed to get active reservation")
}
@@ -280,7 +280,6 @@ func (s *DispersalServerV2) GetPaymentState(ctx context.Context, req *pb.GetPaym
for i, v := range reservation.QuorumNumbers {
quorumNumbers[i] = uint32(v)
}
-
quorumSplits := make([]uint32, len(reservation.QuorumSplits))
for i, v := range reservation.QuorumSplits {
quorumSplits[i] = uint32(v)
@@ -293,8 +292,8 @@ func (s *DispersalServerV2) GetPaymentState(ctx context.Context, req *pb.GetPaym
SymbolsPerSecond: reservation.SymbolsPerSecond,
StartTimestamp: uint32(reservation.StartTimestamp),
EndTimestamp: uint32(reservation.EndTimestamp),
- QuorumNumbers: quorumNumbers,
QuorumSplits: quorumSplits,
+ QuorumNumbers: quorumNumbers,
},
CumulativePayment: largestCumulativePayment.Bytes(),
OnchainCumulativePayment: onDemandPayment.CumulativePayment.Bytes(),
diff --git a/disperser/apiserver/server_v2_test.go b/disperser/apiserver/server_v2_test.go
index 1d9d76e4e..e0398c086 100644
--- a/disperser/apiserver/server_v2_test.go
+++ b/disperser/apiserver/server_v2_test.go
@@ -66,7 +66,7 @@ func TestV2DisperseBlob(t *testing.T) {
Commitment: commitmentProto,
PaymentHeader: &pbcommon.PaymentHeader{
AccountId: accountID,
- BinIndex: 5,
+ ReservationPeriod: 5,
CumulativePayment: big.NewInt(100).Bytes(),
},
}
@@ -124,7 +124,7 @@ func TestV2DisperseBlobRequestValidation(t *testing.T) {
QuorumNumbers: []uint32{0, 1},
PaymentHeader: &pbcommon.PaymentHeader{
AccountId: accountID,
- BinIndex: 5,
+ ReservationPeriod: 5,
CumulativePayment: big.NewInt(100).Bytes(),
},
}
@@ -143,7 +143,7 @@ func TestV2DisperseBlobRequestValidation(t *testing.T) {
Commitment: commitmentProto,
PaymentHeader: &pbcommon.PaymentHeader{
AccountId: accountID,
- BinIndex: 5,
+ ReservationPeriod: 5,
CumulativePayment: big.NewInt(100).Bytes(),
},
}
@@ -160,7 +160,7 @@ func TestV2DisperseBlobRequestValidation(t *testing.T) {
Commitment: commitmentProto,
PaymentHeader: &pbcommon.PaymentHeader{
AccountId: accountID,
- BinIndex: 5,
+ ReservationPeriod: 5,
CumulativePayment: big.NewInt(100).Bytes(),
},
}
@@ -177,7 +177,7 @@ func TestV2DisperseBlobRequestValidation(t *testing.T) {
Commitment: commitmentProto,
PaymentHeader: &pbcommon.PaymentHeader{
AccountId: accountID,
- BinIndex: 5,
+ ReservationPeriod: 5,
CumulativePayment: big.NewInt(100).Bytes(),
},
}
@@ -194,7 +194,7 @@ func TestV2DisperseBlobRequestValidation(t *testing.T) {
Commitment: commitmentProto,
PaymentHeader: &pbcommon.PaymentHeader{
AccountId: accountID,
- BinIndex: 5,
+ ReservationPeriod: 5,
CumulativePayment: big.NewInt(100).Bytes(),
},
Signature: []byte{1, 2, 3},
@@ -212,7 +212,7 @@ func TestV2DisperseBlobRequestValidation(t *testing.T) {
Commitment: commitmentProto,
PaymentHeader: &pbcommon.PaymentHeader{
AccountId: accountID,
- BinIndex: 0,
+ ReservationPeriod: 0,
CumulativePayment: big.NewInt(100).Bytes(),
},
}
@@ -237,7 +237,7 @@ func TestV2DisperseBlobRequestValidation(t *testing.T) {
Commitment: invalidCommitment,
PaymentHeader: &pbcommon.PaymentHeader{
AccountId: accountID,
- BinIndex: 5,
+ ReservationPeriod: 5,
CumulativePayment: big.NewInt(100).Bytes(),
},
}
@@ -267,7 +267,7 @@ func TestV2DisperseBlobRequestValidation(t *testing.T) {
Commitment: commitmentProto,
PaymentHeader: &pbcommon.PaymentHeader{
AccountId: accountID,
- BinIndex: 5,
+ ReservationPeriod: 5,
CumulativePayment: big.NewInt(100).Bytes(),
},
}
@@ -293,7 +293,7 @@ func TestV2GetBlobStatus(t *testing.T) {
QuorumNumbers: []core.QuorumID{0},
PaymentMetadata: core.PaymentMetadata{
AccountID: "0x1234",
- BinIndex: 0,
+ ReservationPeriod: 0,
CumulativePayment: big.NewInt(532),
},
}
diff --git a/disperser/common/v2/blobstore/dynamo_metadata_store_test.go b/disperser/common/v2/blobstore/dynamo_metadata_store_test.go
index 081b1d38d..c2887b21a 100644
--- a/disperser/common/v2/blobstore/dynamo_metadata_store_test.go
+++ b/disperser/common/v2/blobstore/dynamo_metadata_store_test.go
@@ -205,7 +205,7 @@ func TestBlobMetadataStoreCerts(t *testing.T) {
BlobCommitments: mockCommitment,
PaymentMetadata: core.PaymentMetadata{
AccountID: "0x123",
- BinIndex: uint32(i),
+ ReservationPeriod: uint32(i),
CumulativePayment: big.NewInt(321),
},
Signature: []byte("signature"),
@@ -223,14 +223,14 @@ func TestBlobMetadataStoreCerts(t *testing.T) {
assert.NoError(t, err)
assert.Len(t, certs, numCerts)
assert.Len(t, fragmentInfos, numCerts)
- binIndexes := make(map[uint32]struct{})
+ reservationPeriodes := make(map[uint32]struct{})
for i := 0; i < numCerts; i++ {
assert.Equal(t, fragmentInfos[i], fragmentInfo)
- binIndexes[certs[i].BlobHeader.PaymentMetadata.BinIndex] = struct{}{}
+ reservationPeriodes[certs[i].BlobHeader.PaymentMetadata.ReservationPeriod] = struct{}{}
}
- assert.Len(t, binIndexes, numCerts)
+ assert.Len(t, reservationPeriodes, numCerts)
for i := 0; i < numCerts; i++ {
- assert.Contains(t, binIndexes, uint32(i))
+ assert.Contains(t, reservationPeriodes, uint32(i))
}
deleteItems(t, []commondynamodb.Key{
@@ -502,7 +502,7 @@ func newBlob(t *testing.T) (corev2.BlobKey, *corev2.BlobHeader) {
_, err := rand.Read(accountBytes)
require.NoError(t, err)
accountID := hex.EncodeToString(accountBytes)
- binIndex, err := rand.Int(rand.Reader, big.NewInt(256))
+ reservationPeriod, err := rand.Int(rand.Reader, big.NewInt(256))
require.NoError(t, err)
cumulativePayment, err := rand.Int(rand.Reader, big.NewInt(1024))
require.NoError(t, err)
@@ -515,7 +515,7 @@ func newBlob(t *testing.T) (corev2.BlobKey, *corev2.BlobHeader) {
BlobCommitments: mockCommitment,
PaymentMetadata: core.PaymentMetadata{
AccountID: accountID,
- BinIndex: uint32(binIndex.Int64()),
+ ReservationPeriod: uint32(reservationPeriod.Int64()),
CumulativePayment: cumulativePayment,
},
Signature: sig,
diff --git a/disperser/controller/controller_test.go b/disperser/controller/controller_test.go
index dd1f0efa8..46954cec9 100644
--- a/disperser/controller/controller_test.go
+++ b/disperser/controller/controller_test.go
@@ -159,7 +159,7 @@ func newBlob(t *testing.T) (corev2.BlobKey, *corev2.BlobHeader) {
_, err := rand.Read(accountBytes)
require.NoError(t, err)
accountID := hex.EncodeToString(accountBytes)
- binIndex, err := rand.Int(rand.Reader, big.NewInt(256))
+ reservationPeriod, err := rand.Int(rand.Reader, big.NewInt(256))
require.NoError(t, err)
cumulativePayment, err := rand.Int(rand.Reader, big.NewInt(1024))
require.NoError(t, err)
@@ -172,7 +172,7 @@ func newBlob(t *testing.T) (corev2.BlobKey, *corev2.BlobHeader) {
BlobCommitments: mockCommitment,
PaymentMetadata: core.PaymentMetadata{
AccountID: accountID,
- BinIndex: uint32(binIndex.Int64()),
+ ReservationPeriod: uint32(reservationPeriod.Int64()),
CumulativePayment: cumulativePayment,
},
Signature: sig,
diff --git a/disperser/controller/dispatcher_test.go b/disperser/controller/dispatcher_test.go
index 84ba68198..cdc507cfd 100644
--- a/disperser/controller/dispatcher_test.go
+++ b/disperser/controller/dispatcher_test.go
@@ -203,7 +203,7 @@ func TestDispatcherBuildMerkleTree(t *testing.T) {
BlobCommitments: mockCommitment,
PaymentMetadata: core.PaymentMetadata{
AccountID: "account 1",
- BinIndex: 0,
+ ReservationPeriod: 0,
CumulativePayment: big.NewInt(532),
},
Signature: []byte("signature"),
@@ -217,7 +217,7 @@ func TestDispatcherBuildMerkleTree(t *testing.T) {
BlobCommitments: mockCommitment,
PaymentMetadata: core.PaymentMetadata{
AccountID: "account 2",
- BinIndex: 0,
+ ReservationPeriod: 0,
CumulativePayment: big.NewInt(532),
},
Signature: []byte("signature"),
diff --git a/disperser/dataapi/server_v2_test.go b/disperser/dataapi/server_v2_test.go
index 23cc9abf7..1e1da4114 100644
--- a/disperser/dataapi/server_v2_test.go
+++ b/disperser/dataapi/server_v2_test.go
@@ -132,7 +132,9 @@ func makeBlobHeaderV2(t *testing.T) *corev2.BlobHeader {
_, err := rand.Read(accountBytes)
require.NoError(t, err)
accountID := hex.EncodeToString(accountBytes)
- binIndex, err := rand.Int(rand.Reader, big.NewInt(42))
+ reservationPeriod, err := rand.Int(rand.Reader, big.NewInt(42))
+ require.NoError(t, err)
+ salt, err := rand.Int(rand.Reader, big.NewInt(1000))
require.NoError(t, err)
cumulativePayment, err := rand.Int(rand.Reader, big.NewInt(123))
require.NoError(t, err)
@@ -145,8 +147,9 @@ func makeBlobHeaderV2(t *testing.T) *corev2.BlobHeader {
BlobCommitments: makeCommitment(t),
PaymentMetadata: core.PaymentMetadata{
AccountID: accountID,
- BinIndex: uint32(binIndex.Int64()),
+ ReservationPeriod: uint32(reservationPeriod.Int64()),
CumulativePayment: cumulativePayment,
+ Salt: uint32(salt.Int64()),
},
Signature: sig,
}
@@ -190,7 +193,7 @@ func TestFetchBlobHandlerV2(t *testing.T) {
assert.Equal(t, uint8(0), response.BlobHeader.BlobVersion)
assert.Equal(t, blobHeader.Signature, response.BlobHeader.Signature)
assert.Equal(t, blobHeader.PaymentMetadata.AccountID, response.BlobHeader.PaymentMetadata.AccountID)
- assert.Equal(t, blobHeader.PaymentMetadata.BinIndex, response.BlobHeader.PaymentMetadata.BinIndex)
+ assert.Equal(t, blobHeader.PaymentMetadata.ReservationPeriod, response.BlobHeader.PaymentMetadata.ReservationPeriod)
assert.Equal(t, blobHeader.PaymentMetadata.CumulativePayment, response.BlobHeader.PaymentMetadata.CumulativePayment)
}
diff --git a/disperser/encoder/server_v2_test.go b/disperser/encoder/server_v2_test.go
index 83dcb2af1..15d13a906 100644
--- a/disperser/encoder/server_v2_test.go
+++ b/disperser/encoder/server_v2_test.go
@@ -198,7 +198,7 @@ func createTestBlobHeader(t *testing.T) *corev2.BlobHeader {
BlobCommitments: mockCommitment,
PaymentMetadata: core.PaymentMetadata{
AccountID: "0x1234",
- BinIndex: 0,
+ ReservationPeriod: 0,
CumulativePayment: big.NewInt(532),
},
}
diff --git a/node/mock/testdata.go b/node/mock/testdata.go
index ae4805142..859862782 100644
--- a/node/mock/testdata.go
+++ b/node/mock/testdata.go
@@ -21,7 +21,7 @@ func MockBatch(t *testing.T) ([]v2.BlobKey, *v2.Batch, []map[core.QuorumID]core.
QuorumNumbers: []core.QuorumID{0, 1},
PaymentMetadata: core.PaymentMetadata{
AccountID: "0x123",
- BinIndex: 5,
+ ReservationPeriod: 5,
CumulativePayment: big.NewInt(100),
},
Signature: []byte{1, 2, 3},
@@ -32,7 +32,7 @@ func MockBatch(t *testing.T) ([]v2.BlobKey, *v2.Batch, []map[core.QuorumID]core.
QuorumNumbers: []core.QuorumID{0, 1},
PaymentMetadata: core.PaymentMetadata{
AccountID: "0x456",
- BinIndex: 6,
+ ReservationPeriod: 6,
CumulativePayment: big.NewInt(200),
},
Signature: []byte{1, 2, 3},
@@ -43,7 +43,7 @@ func MockBatch(t *testing.T) ([]v2.BlobKey, *v2.Batch, []map[core.QuorumID]core.
QuorumNumbers: []core.QuorumID{1, 2},
PaymentMetadata: core.PaymentMetadata{
AccountID: "0x789",
- BinIndex: 7,
+ ReservationPeriod: 7,
CumulativePayment: big.NewInt(300),
},
Signature: []byte{1, 2, 3},
diff --git a/relay/relay_test_utils.go b/relay/relay_test_utils.go
index 28051afb2..375e823b6 100644
--- a/relay/relay_test_utils.go
+++ b/relay/relay_test_utils.go
@@ -3,6 +3,14 @@ package relay
import (
"context"
"fmt"
+ "log"
+ "math/big"
+ "os"
+ "path/filepath"
+ "runtime"
+ "strings"
+ "testing"
+
pbcommon "github.com/Layr-Labs/eigenda/api/grpc/common"
pbcommonv2 "github.com/Layr-Labs/eigenda/api/grpc/common/v2"
"github.com/Layr-Labs/eigenda/common"
@@ -27,13 +35,6 @@ import (
"github.com/ory/dockertest/v3"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
- "log"
- "math/big"
- "os"
- "path/filepath"
- "runtime"
- "strings"
- "testing"
)
var (
@@ -211,7 +212,7 @@ func randomBlob(t *testing.T) (*v2.BlobHeader, []byte) {
Commitment: commitmentProto,
PaymentHeader: &pbcommon.PaymentHeader{
AccountId: tu.RandomString(10),
- BinIndex: 5,
+ ReservationPeriod: 5,
CumulativePayment: big.NewInt(100).Bytes(),
},
}