@@ -444,6 +444,88 @@ fn test_upd_price_v2() -> Result<(), Box<dyn std::error::Error>> {
444444 Ok ( ( ) )
445445}
446446
447+ #[ test]
448+ fn test_upd_works_with_unordered_publisher_set ( ) -> Result < ( ) , Box < dyn std:: error:: Error > > {
449+ let mut instruction_data = [ 0u8 ; size_of :: < UpdPriceArgs > ( ) ] ;
450+
451+ let program_id = Pubkey :: new_unique ( ) ;
452+
453+ let mut price_setup = AccountSetup :: new :: < PriceAccount > ( & program_id) ;
454+ let mut price_account = price_setup. as_account_info ( ) ;
455+ price_account. is_signer = false ;
456+ PriceAccount :: initialize ( & price_account, PC_VERSION ) . unwrap ( ) ;
457+
458+ let mut publishers_setup: Vec < _ > = ( 0 ..20 ) . map ( |_| AccountSetup :: new_funding ( ) ) . collect ( ) ;
459+ let mut publishers: Vec < _ > = publishers_setup
460+ . iter_mut ( )
461+ . map ( |s| s. as_account_info ( ) )
462+ . collect ( ) ;
463+
464+ publishers. sort_by_key ( |x| x. key ) ;
465+
466+ {
467+ let mut price_data = load_checked :: < PriceAccount > ( & price_account, PC_VERSION ) . unwrap ( ) ;
468+ price_data. num_ = 20 ;
469+ // Store the publishers in reverse order
470+ publishers
471+ . iter ( )
472+ . rev ( )
473+ . enumerate ( )
474+ . for_each ( |( i, account) | {
475+ price_data. comp_ [ i] . pub_ = * account. key ;
476+ } ) ;
477+ }
478+
479+ let mut clock_setup = AccountSetup :: new_clock ( ) ;
480+ let mut clock_account = clock_setup. as_account_info ( ) ;
481+ clock_account. is_signer = false ;
482+ clock_account. is_writable = false ;
483+
484+ update_clock_slot ( & mut clock_account, 1 ) ;
485+
486+ // repeat 10 times to also make sure that price updates
487+ // make the publisher list sorted
488+ for slot in 1 ..10 {
489+ for ( i, publisher) in publishers. iter ( ) . enumerate ( ) {
490+ populate_instruction ( & mut instruction_data, ( i + 100 ) as i64 , 10 , slot) ;
491+ process_instruction (
492+ & program_id,
493+ & [
494+ publisher. clone ( ) ,
495+ price_account. clone ( ) ,
496+ clock_account. clone ( ) ,
497+ ] ,
498+ & instruction_data,
499+ ) ?;
500+ }
501+
502+ update_clock_slot ( & mut clock_account, slot + 1 ) ;
503+ }
504+
505+ {
506+ let price_data = load_checked :: < PriceAccount > ( & price_account, PC_VERSION ) . unwrap ( ) ;
507+
508+ // Check publishers are sorted
509+ let price_data_pubs: Vec < _ > = price_data. comp_ [ ..20 ] . iter ( ) . map ( |c| c. pub_ ) . collect ( ) ;
510+ assert_eq ! (
511+ price_data_pubs,
512+ publishers. iter( ) . map( |p| * p. key) . collect:: <Vec <_>>( )
513+ ) ;
514+
515+ assert_eq ! ( price_data. comp_[ 0 ] . latest_. price_, 100 ) ;
516+ assert_eq ! ( price_data. comp_[ 0 ] . latest_. conf_, 10 ) ;
517+ assert_eq ! ( price_data. comp_[ 0 ] . latest_. pub_slot_, 9 ) ;
518+ assert_eq ! ( price_data. comp_[ 0 ] . latest_. status_, PC_STATUS_TRADING ) ;
519+ // aggregate is calculated at slot 9 for up to slot 8
520+ assert_eq ! ( price_data. valid_slot_, 8 ) ;
521+ assert_eq ! ( price_data. agg_. pub_slot_, 9 ) ;
522+ assert_eq ! ( price_data. agg_. price_, 109 ) ;
523+ assert_eq ! ( price_data. agg_. conf_, 8 ) ;
524+ assert_eq ! ( price_data. agg_. status_, PC_STATUS_TRADING ) ;
525+ }
526+ Ok ( ( ) )
527+ }
528+
447529// Create an upd_price instruction with the provided parameters
448530fn populate_instruction ( instruction_data : & mut [ u8 ] , price : i64 , conf : u64 , pub_slot : u64 ) {
449531 let mut cmd = load_mut :: < UpdPriceArgs > ( instruction_data) . unwrap ( ) ;
0 commit comments