@@ -13,6 +13,7 @@ use pyth_lazer_publisher_sdk::transaction::{
13
13
Ed25519SignatureData , LazerTransaction , SignatureData , SignedLazerTransaction ,
14
14
} ;
15
15
use solana_keypair:: read_keypair_file;
16
+ use std:: collections:: HashMap ;
16
17
use std:: path:: PathBuf ;
17
18
use std:: sync:: Arc ;
18
19
use std:: sync:: atomic:: AtomicBool ;
@@ -132,9 +133,10 @@ impl LazerPublisherTask {
132
133
return Ok ( ( ) ) ;
133
134
}
134
135
135
- let mut updates = self . pending_updates . drain ( ..) . collect ( ) ;
136
+ let mut updates: Vec < FeedUpdate > = self . pending_updates . drain ( ..) . collect ( ) ;
137
+ updates. sort_by_key ( |u| u. source_timestamp . as_ref ( ) . map ( |t| ( t. seconds , t. nanos ) ) ) ;
136
138
if self . config . enable_update_deduplication {
137
- deduplicate_feed_updates ( & mut updates) ;
139
+ updates = deduplicate_feed_updates ( & updates) ? ;
138
140
}
139
141
140
142
let publisher_update = PublisherUpdate {
@@ -178,9 +180,17 @@ impl LazerPublisherTask {
178
180
}
179
181
}
180
182
181
- fn deduplicate_feed_updates ( feed_updates : & mut Vec < FeedUpdate > ) {
182
- // assume that feed_updates is already sorted by timestamp for each feed_update.feed_id
183
- feed_updates. dedup_by_key ( |feed_update| ( feed_update. feed_id , feed_update. update . clone ( ) ) ) ;
183
+ /// For each feed, keep the latest data. Among updates with the same data, keep the one with the earliest timestamp.
184
+ /// Assumes the input is sorted by timestamp ascending.
185
+ fn deduplicate_feed_updates ( sorted_feed_updates : & Vec < FeedUpdate > ) -> Result < Vec < FeedUpdate > > {
186
+ let mut deduped_feed_updates = HashMap :: new ( ) ;
187
+ for update in sorted_feed_updates {
188
+ let entry = deduped_feed_updates. entry ( update. feed_id ) . or_insert ( update) ;
189
+ if entry. update != update. update {
190
+ * entry = update;
191
+ }
192
+ }
193
+ Ok ( deduped_feed_updates. into_values ( ) . cloned ( ) . collect ( ) )
184
194
}
185
195
186
196
#[ cfg( test) ]
@@ -308,25 +318,27 @@ mod tests {
308
318
// - (4, 15)
309
319
// - (5, 15)
310
320
// - (6, 10)
311
- // we should only return (1, 10), (4, 15), (6, 10)
321
+ // - (7, 10)
322
+ // we should only return (6, 10)
312
323
313
- let updates = & mut vec ! [
324
+ let updates = & vec ! [
314
325
test_feed_update( 1 , TimestampUs :: from_millis( 1 ) . unwrap( ) , 10 ) ,
315
326
test_feed_update( 1 , TimestampUs :: from_millis( 2 ) . unwrap( ) , 10 ) ,
316
327
test_feed_update( 1 , TimestampUs :: from_millis( 3 ) . unwrap( ) , 10 ) ,
317
328
test_feed_update( 1 , TimestampUs :: from_millis( 4 ) . unwrap( ) , 15 ) ,
318
329
test_feed_update( 1 , TimestampUs :: from_millis( 5 ) . unwrap( ) , 15 ) ,
319
330
test_feed_update( 1 , TimestampUs :: from_millis( 6 ) . unwrap( ) , 10 ) ,
331
+ test_feed_update( 1 , TimestampUs :: from_millis( 7 ) . unwrap( ) , 10 ) ,
320
332
] ;
321
333
322
- let expected_updates = vec ! [
323
- test_feed_update ( 1 , TimestampUs :: from_millis ( 1 ) . unwrap ( ) , 10 ) ,
324
- test_feed_update ( 1 , TimestampUs :: from_millis( 4 ) . unwrap( ) , 15 ) ,
325
- test_feed_update ( 1 , TimestampUs :: from_millis ( 6 ) . unwrap ( ) , 10 ) ,
326
- ] ;
334
+ let expected_updates = vec ! [ test_feed_update (
335
+ 1 ,
336
+ TimestampUs :: from_millis( 6 ) . unwrap( ) ,
337
+ 10 ,
338
+ ) ] ;
327
339
328
- deduplicate_feed_updates ( updates) ;
329
- assert_eq ! ( updates . to_vec ( ) , expected_updates) ;
340
+ let deduped_updates = deduplicate_feed_updates ( updates) . unwrap ( ) ;
341
+ assert_eq ! ( deduped_updates , expected_updates) ;
330
342
}
331
343
332
344
#[ test]
@@ -342,11 +354,38 @@ mod tests {
342
354
343
355
let expected_updates = vec ! [
344
356
test_feed_update( 1 , TimestampUs :: from_millis( 1 ) . unwrap( ) , 10 ) ,
357
+ test_feed_update( 2 , TimestampUs :: from_millis( 6 ) . unwrap( ) , 10 ) ,
358
+ ] ;
359
+
360
+ let mut deduped_updates = deduplicate_feed_updates ( updates) . unwrap ( ) ;
361
+ deduped_updates. sort_by_key ( |u| u. feed_id ) ;
362
+ assert_eq ! ( deduped_updates, expected_updates) ;
363
+ }
364
+
365
+ #[ test]
366
+ fn test_deduplicate_feed_updates_multiple_feeds_random_order ( ) {
367
+ let updates = & mut vec ! [
368
+ test_feed_update( 1 , TimestampUs :: from_millis( 1 ) . unwrap( ) , 10 ) ,
369
+ test_feed_update( 1 , TimestampUs :: from_millis( 2 ) . unwrap( ) , 20 ) ,
370
+ test_feed_update( 1 , TimestampUs :: from_millis( 3 ) . unwrap( ) , 10 ) ,
345
371
test_feed_update( 2 , TimestampUs :: from_millis( 4 ) . unwrap( ) , 15 ) ,
372
+ test_feed_update( 2 , TimestampUs :: from_millis( 5 ) . unwrap( ) , 15 ) ,
346
373
test_feed_update( 2 , TimestampUs :: from_millis( 6 ) . unwrap( ) , 10 ) ,
374
+ test_feed_update( 1 , TimestampUs :: from_millis( 7 ) . unwrap( ) , 20 ) ,
375
+ test_feed_update( 1 , TimestampUs :: from_millis( 8 ) . unwrap( ) , 10 ) , // last distinct update for feed 1
376
+ test_feed_update( 1 , TimestampUs :: from_millis( 9 ) . unwrap( ) , 10 ) ,
377
+ test_feed_update( 2 , TimestampUs :: from_millis( 10 ) . unwrap( ) , 15 ) ,
378
+ test_feed_update( 2 , TimestampUs :: from_millis( 11 ) . unwrap( ) , 15 ) ,
379
+ test_feed_update( 2 , TimestampUs :: from_millis( 12 ) . unwrap( ) , 10 ) , // last distinct update for feed 2
380
+ ] ;
381
+
382
+ let expected_updates = vec ! [
383
+ test_feed_update( 1 , TimestampUs :: from_millis( 8 ) . unwrap( ) , 10 ) ,
384
+ test_feed_update( 2 , TimestampUs :: from_millis( 12 ) . unwrap( ) , 10 ) ,
347
385
] ;
348
386
349
- deduplicate_feed_updates ( updates) ;
350
- assert_eq ! ( updates. to_vec( ) , expected_updates) ;
387
+ let mut deduped_updates = deduplicate_feed_updates ( updates) . unwrap ( ) ;
388
+ deduped_updates. sort_by_key ( |u| u. feed_id ) ;
389
+ assert_eq ! ( deduped_updates, expected_updates) ;
351
390
}
352
391
}
0 commit comments