@@ -13,6 +13,7 @@ use pyth_lazer_publisher_sdk::transaction::{
1313 Ed25519SignatureData , LazerTransaction , SignatureData , SignedLazerTransaction ,
1414} ;
1515use solana_keypair:: read_keypair_file;
16+ use std:: collections:: HashMap ;
1617use std:: path:: PathBuf ;
1718use std:: sync:: Arc ;
1819use std:: sync:: atomic:: AtomicBool ;
@@ -132,9 +133,10 @@ impl LazerPublisherTask {
132133 return Ok ( ( ) ) ;
133134 }
134135
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 ) ) ) ;
136138 if self . config . enable_update_deduplication {
137- deduplicate_feed_updates ( & mut updates) ;
139+ updates = deduplicate_feed_updates ( & updates) ? ;
138140 }
139141
140142 let publisher_update = PublisherUpdate {
@@ -178,9 +180,17 @@ impl LazerPublisherTask {
178180 }
179181}
180182
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 ( ) )
184194}
185195
186196#[ cfg( test) ]
@@ -308,25 +318,27 @@ mod tests {
308318 // - (4, 15)
309319 // - (5, 15)
310320 // - (6, 10)
311- // we should only return (1, 10), (4, 15), (6, 10)
321+ // - (7, 10)
322+ // we should only return (6, 10)
312323
313- let updates = & mut vec ! [
324+ let updates = & vec ! [
314325 test_feed_update( 1 , TimestampUs :: from_millis( 1 ) . unwrap( ) , 10 ) ,
315326 test_feed_update( 1 , TimestampUs :: from_millis( 2 ) . unwrap( ) , 10 ) ,
316327 test_feed_update( 1 , TimestampUs :: from_millis( 3 ) . unwrap( ) , 10 ) ,
317328 test_feed_update( 1 , TimestampUs :: from_millis( 4 ) . unwrap( ) , 15 ) ,
318329 test_feed_update( 1 , TimestampUs :: from_millis( 5 ) . unwrap( ) , 15 ) ,
319330 test_feed_update( 1 , TimestampUs :: from_millis( 6 ) . unwrap( ) , 10 ) ,
331+ test_feed_update( 1 , TimestampUs :: from_millis( 7 ) . unwrap( ) , 10 ) ,
320332 ] ;
321333
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+ ) ] ;
327339
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) ;
330342 }
331343
332344 #[ test]
@@ -342,11 +354,38 @@ mod tests {
342354
343355 let expected_updates = vec ! [
344356 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 ) ,
345371 test_feed_update( 2 , TimestampUs :: from_millis( 4 ) . unwrap( ) , 15 ) ,
372+ test_feed_update( 2 , TimestampUs :: from_millis( 5 ) . unwrap( ) , 15 ) ,
346373 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 ) ,
347385 ] ;
348386
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) ;
351390 }
352391}
0 commit comments