@@ -4,16 +4,16 @@ import (
4
4
"context"
5
5
"errors"
6
6
"fmt"
7
+ "math"
7
8
"math/big"
8
9
"strconv"
10
+ "strings"
9
11
10
12
pb "github.com/Layr-Labs/eigenda/api/grpc/disperser/v2"
11
13
commonaws "github.com/Layr-Labs/eigenda/common/aws"
12
14
commondynamodb "github.com/Layr-Labs/eigenda/common/aws/dynamodb"
13
15
"github.com/Layr-Labs/eigenda/core"
14
16
"github.com/Layr-Labs/eigensdk-go/logging"
15
- "github.com/aws/aws-sdk-go-v2/aws"
16
- "github.com/aws/aws-sdk-go-v2/service/dynamodb"
17
17
"github.com/aws/aws-sdk-go-v2/service/dynamodb/types"
18
18
gethcommon "github.com/ethereum/go-ethereum/common"
19
19
)
@@ -65,7 +65,7 @@ func NewDynamoDBMeteringStore(
65
65
}
66
66
67
67
// IncrementBinUsages updates the bin usage for each quorum in quorumNumbers for a specific account and reservation period.
68
- // The key is AccountIDAndQuorum, formatted as {AccountID}:{quorumNumber}.
68
+ // The key AccountID is formatted as {AccountID}:{quorumNumber}.
69
69
func (s * DynamoDBMeteringStore ) IncrementBinUsages (ctx context.Context , accountID gethcommon.Address , quorumNumbers []core.QuorumID , reservationPeriods map [core.QuorumID ]uint64 , sizes map [core.QuorumID ]uint64 ) (map [core.QuorumID ]uint64 , error ) {
70
70
binUsages := make (map [core.QuorumID ]uint64 )
71
71
@@ -256,30 +256,53 @@ func (s *DynamoDBMeteringStore) RollbackOnDemandPayment(ctx context.Context, acc
256
256
return nil
257
257
}
258
258
259
- func (s * DynamoDBMeteringStore ) GetPeriodRecords (ctx context.Context , accountID gethcommon.Address , reservationPeriod uint64 ) ([MinNumBins ]* pb.PeriodRecord , error ) {
260
- // Fetch the 3 bins start from the current bin
261
- queryInput := & dynamodb.QueryInput {
262
- TableName : aws .String (s .reservationTableName ),
263
- KeyConditionExpression : aws .String ("AccountID = :account AND ReservationPeriod >= :reservationPeriod" ),
264
- ExpressionAttributeValues : commondynamodb.ExpressionValues {
265
- ":account" : & types.AttributeValueMemberS {Value : accountID .Hex ()},
266
- ":reservationPeriod" : & types.AttributeValueMemberN {Value : strconv .FormatUint (reservationPeriod , 10 )},
267
- },
268
- ScanIndexForward : aws .Bool (true ),
269
- Limit : aws .Int32 (MinNumBins ),
270
- }
271
- bins , err := s .dynamoClient .QueryWithInput (ctx , queryInput )
259
+ // GetPeriodRecords retrieves period records for multiple quorums efficiently.
260
+ // This function is optimized for retrieving period records for all quorums in a single database operation.
261
+ // The records start from the first reservation period for each quorum to at most numBins in length into the future.
262
+ // quorumNumbers and reservationPeriods must have the same length and the same ordering.
263
+ // Returns an array of PeriodRecords up to numBins in length, with records for each requested quorum.
264
+ func (s * DynamoDBMeteringStore ) GetPeriodRecords (
265
+ ctx context.Context ,
266
+ accountID gethcommon.Address ,
267
+ quorumNumbers []core.QuorumID ,
268
+ reservationPeriods []uint64 ,
269
+ numBins uint32 ,
270
+ ) (map [core.QuorumID ]* pb.PeriodRecords , error ) {
271
+ if len (quorumNumbers ) == 0 || len (reservationPeriods ) != len (quorumNumbers ) {
272
+ return nil , nil
273
+ }
274
+
275
+ // Prepare all keys for batch get
276
+ var keys []map [string ]types.AttributeValue
277
+ for i , quorum := range quorumNumbers {
278
+ accountIDAndQuorum := accountID .Hex () + ":" + strconv .FormatUint (uint64 (quorum ), 10 )
279
+ for j := 0 ; j < int (numBins ); j ++ {
280
+ key := map [string ]types.AttributeValue {
281
+ "AccountID" : & types.AttributeValueMemberS {Value : accountIDAndQuorum },
282
+ "ReservationPeriod" : & types.AttributeValueMemberN {Value : strconv .FormatUint (reservationPeriods [i ]+ uint64 (j ), 10 )},
283
+ }
284
+ keys = append (keys , key )
285
+ }
286
+ }
287
+
288
+ items , err := s .dynamoClient .GetItems (ctx , s .reservationTableName , keys , true )
272
289
if err != nil {
273
- return [ MinNumBins ] * pb. PeriodRecord {} , fmt .Errorf ("failed to query payments for account: %w" , err )
290
+ return nil , fmt .Errorf ("failed to batch get period records for account: %w" , err )
274
291
}
275
292
276
- records := [ MinNumBins ]* pb.PeriodRecord {}
277
- for i := 0 ; i < len ( bins ) && i < int ( MinNumBins ); i ++ {
278
- periodRecord , err := parsePeriodRecord (bins [ i ] )
293
+ records := make ( map [core. QuorumID ]* pb.PeriodRecords )
294
+ for _ , item := range items {
295
+ quorumNumber , periodRecord , err := parsePeriodRecord (item )
279
296
if err != nil {
280
- return [MinNumBins ]* pb.PeriodRecord {}, fmt .Errorf ("failed to parse bin %d record: %w" , i , err )
297
+ return nil , fmt .Errorf ("failed to parse period record: %w" , err )
298
+ }
299
+ if existingRecords , exists := records [quorumNumber ]; exists {
300
+ existingRecords .Records = append (existingRecords .Records , periodRecord )
301
+ } else {
302
+ records [quorumNumber ] = & pb.PeriodRecords {
303
+ Records : []* pb.PeriodRecord {periodRecord },
304
+ }
281
305
}
282
- records [i ] = periodRecord
283
306
}
284
307
285
308
return records , nil
@@ -321,38 +344,60 @@ func (s *DynamoDBMeteringStore) GetLargestCumulativePayment(ctx context.Context,
321
344
return payment , nil
322
345
}
323
346
324
- func parsePeriodRecord (bin map [string ]types.AttributeValue ) (* pb.PeriodRecord , error ) {
347
+ func parsePeriodRecord (bin map [string ]types.AttributeValue ) (core. QuorumID , * pb.PeriodRecord , error ) {
325
348
reservationPeriod , ok := bin ["ReservationPeriod" ]
326
349
if ! ok {
327
- return nil , errors .New ("ReservationPeriod is not present in the response" )
350
+ return 0 , nil , errors .New ("ReservationPeriod is not present in the response" )
328
351
}
329
352
330
353
reservationPeriodAttr , ok := reservationPeriod .(* types.AttributeValueMemberN )
331
354
if ! ok {
332
- return nil , fmt .Errorf ("unexpected type for ReservationPeriod: %T" , reservationPeriod )
355
+ return 0 , nil , fmt .Errorf ("unexpected type for ReservationPeriod: %T" , reservationPeriod )
333
356
}
334
357
335
358
reservationPeriodValue , err := strconv .ParseUint (reservationPeriodAttr .Value , 10 , 32 )
336
359
if err != nil {
337
- return nil , fmt .Errorf ("failed to parse ReservationPeriod: %w" , err )
360
+ return 0 , nil , fmt .Errorf ("failed to parse ReservationPeriod: %w" , err )
338
361
}
339
362
340
363
binUsage , ok := bin ["BinUsage" ]
341
364
if ! ok {
342
- return nil , errors .New ("BinUsage is not present in the response" )
365
+ return 0 , nil , errors .New ("BinUsage is not present in the response" )
343
366
}
344
367
345
368
binUsageAttr , ok := binUsage .(* types.AttributeValueMemberN )
346
369
if ! ok {
347
- return nil , fmt .Errorf ("unexpected type for BinUsage: %T" , binUsage )
370
+ return 0 , nil , fmt .Errorf ("unexpected type for BinUsage: %T" , binUsage )
348
371
}
349
372
350
373
binUsageValue , err := strconv .ParseUint (binUsageAttr .Value , 10 , 32 )
351
374
if err != nil {
352
- return nil , fmt .Errorf ("failed to parse BinUsage: %w" , err )
375
+ return 0 , nil , fmt .Errorf ("failed to parse BinUsage: %w" , err )
376
+ }
377
+ accountIDAndQuorum , ok := bin ["AccountID" ]
378
+ if ! ok {
379
+ return 0 , nil , errors .New ("AccountID is not present in the response" )
380
+ }
381
+
382
+ accountIDAndQuorumAttr , ok := accountIDAndQuorum .(* types.AttributeValueMemberS )
383
+ if ! ok {
384
+ return 0 , nil , fmt .Errorf ("unexpected type for AccountID: %T" , accountIDAndQuorum )
385
+ }
386
+
387
+ parts := strings .Split (accountIDAndQuorumAttr .Value , ":" )
388
+ if len (parts ) != 2 {
389
+ return 0 , nil , fmt .Errorf ("invalid AccountID format: %s" , accountIDAndQuorumAttr .Value )
390
+ }
391
+
392
+ quorumNumber , err := strconv .ParseUint (parts [1 ], 10 , 32 )
393
+ if err != nil {
394
+ return 0 , nil , fmt .Errorf ("failed to parse QuorumNumber: %w" , err )
395
+ }
396
+ if quorumNumber > math .MaxUint8 {
397
+ return 0 , nil , fmt .Errorf ("QuorumNumber exceeds maximum value for uint8: %d" , quorumNumber )
353
398
}
354
399
355
- return & pb.PeriodRecord {
400
+ return core . QuorumID ( quorumNumber ), & pb.PeriodRecord {
356
401
Index : uint32 (reservationPeriodValue ),
357
402
Usage : uint64 (binUsageValue ),
358
403
}, nil
0 commit comments