Skip to content

Commit

Permalink
chore: fix test string assertion
Browse files Browse the repository at this point in the history
  • Loading branch information
hopeyen committed Oct 8, 2024
1 parent 6351c57 commit ec28469
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 44 deletions.
21 changes: 11 additions & 10 deletions core/meterer/meterer.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ type TimeoutConfig struct {
type Config struct {
// for rate limiting 2^64 ~= 18 exabytes per second; 2^32 ~= 4GB/s
// for payments 2^64 ~= 18M Eth; 2^32 ~= 4ETH
GlobalBytesPerSecond uint64 // Global rate limit in bytes per second for on-demand payments
MinChargeableSize uint32 // Minimum size of a chargeable unit in bytes, used as a floor for on-demand payments
PricePerChargeable uint32 // Price per chargeable unit in gwei, used for on-demand payments
ReservationWindow uint32 // Duration of all reservations in seconds, used to calculate bin indices
GlobalSymbolsPerSecond uint64 // Global rate limit in symbols per second for on-demand payments
MinChargeableSize uint32 // Minimum size of a chargeable unit in symbols, used as a floor for on-demand payments
PricePerChargeable uint32 // Price per chargeable unit in gwei, used for on-demand payments
ReservationWindow uint32 // Duration of all reservations in seconds, used to calculate bin indices
}

// disperser API server will receive requests from clients. these requests will be with a PaymentMetadata with payments information (CumulativePayments, BinIndex, and Signature)
Expand Down Expand Up @@ -75,9 +75,9 @@ func NewMeterer(
// TODO: return error if there's a rejection (with reasoning) or internal error (should be very rare)
func (m *Meterer) MeterRequest(ctx context.Context, header PaymentMetadata) error {
// TODO: validate signing
// if err := m.ValidateSignature(ctx, header); err != nil {
// return fmt.Errorf("invalid signature: %w", err)
// }
if err := m.ValidateSignature(ctx, header); err != nil {
return fmt.Errorf("invalid signature: %w", err)
}

blockNumber, err := m.ChainState.GetCurrentBlockNumber(ctx)
if err != nil {
Expand Down Expand Up @@ -145,14 +145,15 @@ func (m *Meterer) ServeReservationRequest(ctx context.Context, PaymentMetadata P
return nil
}

func (m *Meterer) ValidateQuorum(PaymentMetadata PaymentMetadata, allowedQuoroms []uint8) error {
// ValidateQuorums ensures that the quorums listed in the blobHeader are present within allowedQuorums
func (m *Meterer) ValidateQuorum(PaymentMetadata PaymentMetadata, allowedQuorums []uint8) error {
if len(PaymentMetadata.QuorumNumbers) == 0 {
return fmt.Errorf("no quorum params in blob header")
}

// check that all the quorum ids are in ActiveReservation's
for _, q := range PaymentMetadata.QuorumNumbers {
if !slices.Contains(allowedQuoroms, q) {
if !slices.Contains(allowedQuorums, q) {
// fail the entire request if there's a quorum number mismatch
return fmt.Errorf("quorum number mismatch: %d", q)
}
Expand Down Expand Up @@ -286,7 +287,7 @@ func (m *Meterer) IncrementGlobalBinUsage(ctx context.Context, symbolsCharged ui
if err != nil {
return fmt.Errorf("failed to increment global bin usage: %w", err)
}
if newUsage > m.GlobalBytesPerSecond {
if newUsage > m.GlobalSymbolsPerSecond {
return fmt.Errorf("global bin usage overflows")
}
return nil
Expand Down
65 changes: 33 additions & 32 deletions core/meterer/meterer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,10 +104,10 @@ func setup(_ *testing.M) {

logger = logging.NewNoopLogger()
config := meterer.Config{
PricePerChargeable: 1,
MinChargeableSize: 1,
GlobalBytesPerSecond: 1000,
ReservationWindow: 1,
PricePerChargeable: 1,
MinChargeableSize: 1,
GlobalSymbolsPerSecond: 1000,
ReservationWindow: 1,
}

paymentChainState := meterer.NewOnchainPaymentState()
Expand Down Expand Up @@ -171,13 +171,13 @@ func TestMetererReservations(t *testing.T) {
Signature: []byte{78, 212, 55, 45, 156, 217, 21, 240, 47, 141, 18, 213, 226, 196, 4, 51, 245, 110, 20, 106, 244, 142, 142, 49, 213, 21, 34, 151, 118, 254, 46, 89, 48, 84, 250, 46, 179, 228, 46, 51, 106, 164, 122, 11, 26, 101, 10, 10, 243, 2, 30, 46, 95, 125, 189, 237, 236, 91, 130, 224, 240, 151, 106, 204, 1},
}
err := mt.MeterRequest(ctx, *invalidHeader)
assert.Error(t, err, "invalid signature: recovered address * does not match account ID *")
assert.ErrorContains(t, err, "invalid signature: recovered address")

// test invalid quorom ID
header, err := meterer.ConstructPaymentMetadata(signer, 1, 0, 1000, []uint8{0, 1, 2}, privateKey1)
assert.NoError(t, err)
err = mt.MeterRequest(ctx, *header)
assert.Error(t, err, "invalid quorum ID")
assert.ErrorContains(t, err, "quorum number mismatch")

// test non-existent account
unregisteredUser, err := crypto.GenerateKey()
Expand All @@ -187,20 +187,15 @@ func TestMetererReservations(t *testing.T) {
header, err = meterer.ConstructPaymentMetadata(signer, 1, 0, 1000, []uint8{0, 1, 2}, unregisteredUser)
assert.NoError(t, err)
err = mt.MeterRequest(ctx, *header)
assert.Error(t, err, "failed to get on-demand payment by account: reservation not found")
assert.ErrorContains(t, err, "failed to get active reservation by account: reservation not found")

// test invalid bin index
header, err = meterer.ConstructPaymentMetadata(signer, binIndex, 0, 2000, quoromNumbers, privateKey1)
assert.NoError(t, err)
err = mt.MeterRequest(ctx, *header)
assert.Error(t, err, "invalid bin index for reservation")
assert.ErrorContains(t, err, "invalid bin index for reservation")

header, err = meterer.ConstructPaymentMetadata(signer, binIndex-1, 0, 1000, quoromNumbers, privateKey2)
assert.NoError(t, err)
err = mt.MeterRequest(ctx, *header)
assert.Error(t, err, "invalid bin index for reservation")

// test bin usage
// test bin usage metering
accountID := crypto.PubkeyToAddress(privateKey2.PublicKey).Hex()
for i := 0; i < 9; i++ {
dataLength := 20
Expand Down Expand Up @@ -237,13 +232,13 @@ func TestMetererReservations(t *testing.T) {
header, err = meterer.ConstructPaymentMetadata(signer, binIndex, 0, 1, quoromNumbers, privateKey2)
assert.NoError(t, err)
err = mt.MeterRequest(ctx, *header)
assert.Error(t, err, "Bin has already been overflowed")
assert.ErrorContains(t, err, "bin has already been filled")

// overwhelming bin overflow
// overwhelming bin overflow for empty bins (assuming all previous requests happened within 1 reservation window)
header, err = meterer.ConstructPaymentMetadata(signer, binIndex-1, 0, 1000, quoromNumbers, privateKey2)
assert.NoError(t, err)
err = mt.MeterRequest(ctx, *header)
assert.Error(t, err, "Overflow usage exceeds bin limit")
assert.ErrorContains(t, err, "overflow usage exceeds bin limit")
}

func TestMetererOnDemand(t *testing.T) {
Expand All @@ -263,7 +258,7 @@ func TestMetererOnDemand(t *testing.T) {
Signature: []byte{78, 212, 55, 45, 156, 217, 21, 240, 47, 141, 18, 213, 226, 196, 4, 51, 245, 110, 20, 106, 244, 142, 142, 49, 213, 21, 34, 151, 118, 254, 46, 89, 48, 84, 250, 46, 179, 228, 46, 51, 106, 164, 122, 11, 26, 101, 10, 10, 243, 2, 30, 46, 95, 125, 189, 237, 236, 91, 130, 224, 240, 151, 106, 204, 1},
}
err := mt.MeterRequest(ctx, *invalidHeader)
assert.Error(t, err, "invalid signature: recovered address * does not match account ID *")
assert.ErrorContains(t, err, "invalid signature: recovered address")

// test unregistered account
unregisteredUser, err := crypto.GenerateKey()
Expand All @@ -273,20 +268,20 @@ func TestMetererOnDemand(t *testing.T) {
header, err := meterer.ConstructPaymentMetadata(signer, 1, 1, 1000, quorumNumbers, unregisteredUser)
assert.NoError(t, err)
err = mt.MeterRequest(ctx, *header)
assert.Error(t, err, "failed to get on-demand payment by account: payment not found")
assert.ErrorContains(t, err, "failed to get on-demand payment by account: payment not found")

// test invalid quorom ID
header, err = meterer.ConstructPaymentMetadata(signer, 1, 1, 1000, []uint8{0, 1, 2}, privateKey1)
assert.NoError(t, err)
err = mt.MeterRequest(ctx, *header)
assert.Error(t, err, "invalid quorum for On-Demand Request")
assert.ErrorContains(t, err, "invalid quorum for On-Demand Request")

// test insufficient cumulative payment
header, err = meterer.ConstructPaymentMetadata(signer, 0, 1, 2000, quorumNumbers, privateKey1)

assert.NoError(t, err)
err = mt.MeterRequest(ctx, *header)
assert.Error(t, err, "insufficient cumulative payment increment")
assert.ErrorContains(t, err, "insufficient cumulative payment increment")
// No rollback after meter request
result, err := dynamoClient.QueryIndex(ctx, "ondemand", "AccountIDIndex", "AccountID = :account", commondynamodb.ExpresseionValues{
":account": &types.AttributeValueMemberS{
Expand All @@ -301,46 +296,52 @@ func TestMetererOnDemand(t *testing.T) {
assert.NoError(t, err)
header, err = meterer.ConstructPaymentMetadata(signer, binIndex, uint64(100), 100, quorumNumbers, privateKey2)
err = mt.MeterRequest(ctx, *header)
assert.Error(t, err, "exact payment already exists")
assert.ErrorContains(t, err, "exact payment already exists")

// test valid payments
for i := 1; i < 10; i++ {
for i := 1; i < 9; i++ {
header, err = meterer.ConstructPaymentMetadata(signer, binIndex, uint64(100*(i+1)), 100, quorumNumbers, privateKey2)
err = mt.MeterRequest(ctx, *header)
assert.NoError(t, err)
}

// test insufficient remaining balance from cumulative payment
header, err = meterer.ConstructPaymentMetadata(signer, binIndex, 1, 1, quorumNumbers, privateKey2)
// test cumulative payment on-chain constraint
header, err = meterer.ConstructPaymentMetadata(signer, binIndex, 1001, 1, quorumNumbers, privateKey2)
assert.NoError(t, err)
err = mt.MeterRequest(ctx, *header)
assert.ErrorContains(t, err, "invalid on-demand payment: request claims a cumulative payment greater than the on-chain deposit")

// test insufficient increment in cumulative payment
header, err = meterer.ConstructPaymentMetadata(signer, binIndex, 901, 2, quorumNumbers, privateKey2)
assert.NoError(t, err)
err = mt.MeterRequest(ctx, *header)
assert.Error(t, err, "insufficient cumulative payment increment")
assert.ErrorContains(t, err, "invalid on-demand payment: insufficient cumulative payment increment")

// test cannot insert cumulative payment in out of order
header, err = meterer.ConstructPaymentMetadata(signer, binIndex, 0, 50, quorumNumbers, privateKey2)
header, err = meterer.ConstructPaymentMetadata(signer, binIndex, 50, 50, quorumNumbers, privateKey2)
assert.NoError(t, err)
err = mt.MeterRequest(ctx, *header)
assert.Error(t, err, "cannot insert cumulative payment in out of order")
assert.ErrorContains(t, err, "invalid on-demand payment: breaking cumulative payment invariants")

numRequest := 11
numPrevRecords := 12
result, err = dynamoClient.QueryIndex(ctx, "ondemand", "AccountIDIndex", "AccountID = :account", commondynamodb.ExpresseionValues{
":account": &types.AttributeValueMemberS{
Value: crypto.PubkeyToAddress(privateKey2.PublicKey).Hex(),
}})
assert.NoError(t, err)
assert.Equal(t, numRequest, len(result))
assert.Equal(t, numPrevRecords, len(result))
// test failed global rate limit
header, err = meterer.ConstructPaymentMetadata(signer, binIndex, 1002, 1001, quorumNumbers, privateKey1)
assert.NoError(t, err)
err = mt.MeterRequest(ctx, *header)
assert.Error(t, err, "failed global rate limiting")
assert.ErrorContains(t, err, "failed global rate limiting")
// Correct rollback
result, err = dynamoClient.QueryIndex(ctx, "ondemand", "AccountIDIndex", "AccountID = :account", commondynamodb.ExpresseionValues{
":account": &types.AttributeValueMemberS{
Value: crypto.PubkeyToAddress(privateKey2.PublicKey).Hex(),
}})
assert.NoError(t, err)
assert.Equal(t, numRequest, len(result))
assert.Equal(t, numPrevRecords, len(result))
}

func TestMeterer_paymentCharged(t *testing.T) {
Expand Down
3 changes: 1 addition & 2 deletions core/meterer/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ func NewEIP712Signer(chainID *big.Int, verifyingContract common.Address) *EIP712
{Name: "accountID", Type: "string"},
{Name: "binIndex", Type: "uint32"},
{Name: "cumulativePayment", Type: "uint64"},
{Name: "commitment", Type: "bytes"},
{Name: "dataLength", Type: "uint32"},
{Name: "quorumNumbers", Type: "uint8[]"},
},
Expand Down Expand Up @@ -176,7 +175,7 @@ func ConstructPaymentMetadata(

signature, err := signer.SignPaymentMetadata(header, privateKey)
if err != nil {
return nil, fmt.Errorf("error signing blob header: %v", err)
return nil, fmt.Errorf("error signing payment metadata: %v", err)
}

header.Signature = signature
Expand Down

0 comments on commit ec28469

Please sign in to comment.