@@ -11,7 +11,7 @@ use alloy_primitives::hex::ToHex;
11
11
use bigdecimal:: { num_bigint:: ToBigInt , ToPrimitive } ;
12
12
use sqlx:: { postgres:: types:: PgRange , types:: BigDecimal } ;
13
13
use tap_core:: {
14
- manager:: adapters:: { ReceiptDelete , ReceiptRead } ,
14
+ manager:: adapters:: { safe_truncate_receipts , ReceiptDelete , ReceiptRead } ,
15
15
receipt:: { Checking , Receipt , ReceiptWithState , SignedReceipt } ,
16
16
} ;
17
17
use thegraph:: types:: Address ;
@@ -79,29 +79,33 @@ impl ReceiptRead for TapAgentContext {
79
79
async fn retrieve_receipts_in_timestamp_range < R : RangeBounds < u64 > + Send > (
80
80
& self ,
81
81
timestamp_range_ns : R ,
82
- // TODO: Make use of this limit in this function
83
- _receipts_limit : Option < u64 > ,
82
+ receipts_limit : Option < u64 > ,
84
83
) -> Result < Vec < ReceiptWithState < Checking > > , Self :: AdapterError > {
85
84
let signers = signers_trimmed ( & self . escrow_accounts , self . sender )
86
85
. await
87
86
. map_err ( |e| AdapterError :: ReceiptRead {
88
87
error : format ! ( "{:?}." , e) ,
89
88
} ) ?;
90
89
90
+ let receipts_limit = receipts_limit. map_or ( 1000 , |limit| limit) ;
91
+
91
92
let records = sqlx:: query!(
92
93
r#"
93
94
SELECT id, signature, allocation_id, timestamp_ns, nonce, value
94
95
FROM scalar_tap_receipts
95
96
WHERE allocation_id = $1 AND signer_address IN (SELECT unnest($2::text[]))
96
- AND $3::numrange @> timestamp_ns
97
+ AND $3::numrange @> timestamp_ns
98
+ ORDER BY timestamp_ns ASC
99
+ LIMIT $4
97
100
"# ,
98
101
self . allocation_id. encode_hex:: <String >( ) ,
99
102
& signers,
100
- rangebounds_to_pgrange( timestamp_range_ns)
103
+ rangebounds_to_pgrange( timestamp_range_ns) ,
104
+ ( receipts_limit + 1 ) as i64 ,
101
105
)
102
106
. fetch_all ( & self . pgpool )
103
107
. await ?;
104
- records
108
+ let mut receipts = records
105
109
. into_iter ( )
106
110
. map ( |record| {
107
111
let signature = record. signature . as_slice ( ) . try_into ( )
@@ -148,7 +152,11 @@ impl ReceiptRead for TapAgentContext {
148
152
Ok ( ReceiptWithState :: new ( signed_receipt) )
149
153
150
154
} )
151
- . collect ( )
155
+ . collect :: < Result < Vec < ReceiptWithState < Checking > > , AdapterError > > ( ) ?;
156
+
157
+ safe_truncate_receipts ( & mut receipts, receipts_limit) ;
158
+
159
+ Ok ( receipts)
152
160
}
153
161
}
154
162
@@ -275,7 +283,6 @@ mod test {
275
283
276
284
// Retrieving receipts in timestamp range from the database, convert to json Value
277
285
let recovered_received_receipt_vec = storage_adapter
278
- // TODO: Make use of the receipt limit if it makes sense here
279
286
. retrieve_receipts_in_timestamp_range ( range, None )
280
287
. await ?
281
288
. into_iter ( )
@@ -424,6 +431,74 @@ mod test {
424
431
Ok ( ( ) )
425
432
}
426
433
434
+ #[ sqlx:: test( migrations = "../migrations" ) ]
435
+ async fn retrieve_receipts_with_limit ( pgpool : PgPool ) {
436
+ let escrow_accounts = Eventual :: from_value ( EscrowAccounts :: new (
437
+ HashMap :: from ( [ ( SENDER . 1 , 1000 . into ( ) ) ] ) ,
438
+ HashMap :: from ( [ ( SENDER . 1 , vec ! [ SIGNER . 1 ] ) ] ) ,
439
+ ) ) ;
440
+
441
+ let storage_adapter = TapAgentContext :: new (
442
+ pgpool. clone ( ) ,
443
+ * ALLOCATION_ID_0 ,
444
+ SENDER . 1 ,
445
+ escrow_accounts. clone ( ) ,
446
+ EscrowAdapter :: mock ( ) ,
447
+ ) ;
448
+
449
+ // Creating 100 receipts with timestamps 42 to 141
450
+ for i in 0 ..100 {
451
+ let receipt = create_received_receipt (
452
+ & ALLOCATION_ID_0 ,
453
+ & SIGNER . 0 ,
454
+ i + 684 ,
455
+ i + 42 ,
456
+ ( i + 124 ) . into ( ) ,
457
+ ) ;
458
+ store_receipt ( & pgpool, receipt. signed_receipt ( ) )
459
+ . await
460
+ . unwrap ( ) ;
461
+ }
462
+
463
+ let recovered_received_receipt_vec = storage_adapter
464
+ . retrieve_receipts_in_timestamp_range ( 0 ..141 , Some ( 10 ) )
465
+ . await
466
+ . unwrap ( ) ;
467
+ assert_eq ! ( recovered_received_receipt_vec. len( ) , 10 ) ;
468
+
469
+ let recovered_received_receipt_vec = storage_adapter
470
+ . retrieve_receipts_in_timestamp_range ( 0 ..141 , Some ( 50 ) )
471
+ . await
472
+ . unwrap ( ) ;
473
+ assert_eq ! ( recovered_received_receipt_vec. len( ) , 50 ) ;
474
+
475
+ // add a copy in the same timestamp
476
+ for i in 0 ..100 {
477
+ let receipt = create_received_receipt (
478
+ & ALLOCATION_ID_0 ,
479
+ & SIGNER . 0 ,
480
+ i + 684 ,
481
+ i + 43 ,
482
+ ( i + 124 ) . into ( ) ,
483
+ ) ;
484
+ store_receipt ( & pgpool, receipt. signed_receipt ( ) )
485
+ . await
486
+ . unwrap ( ) ;
487
+ }
488
+
489
+ let recovered_received_receipt_vec = storage_adapter
490
+ . retrieve_receipts_in_timestamp_range ( 0 ..141 , Some ( 10 ) )
491
+ . await
492
+ . unwrap ( ) ;
493
+ assert_eq ! ( recovered_received_receipt_vec. len( ) , 9 ) ;
494
+
495
+ let recovered_received_receipt_vec = storage_adapter
496
+ . retrieve_receipts_in_timestamp_range ( 0 ..141 , Some ( 50 ) )
497
+ . await
498
+ . unwrap ( ) ;
499
+ assert_eq ! ( recovered_received_receipt_vec. len( ) , 49 ) ;
500
+ }
501
+
427
502
#[ sqlx:: test( migrations = "../migrations" ) ]
428
503
async fn retrieve_receipts_in_timestamp_range ( pgpool : PgPool ) {
429
504
let escrow_accounts = Eventual :: from_value ( EscrowAccounts :: new (
0 commit comments