@@ -444,6 +444,90 @@ 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+ println ! ( "{:} {:?}" , i, account. key) ;
476+ price_data. comp_ [ i] . pub_ = * account. key ;
477+ } ) ;
478+ }
479+
480+ let mut clock_setup = AccountSetup :: new_clock ( ) ;
481+ let mut clock_account = clock_setup. as_account_info ( ) ;
482+ clock_account. is_signer = false ;
483+ clock_account. is_writable = false ;
484+
485+ update_clock_slot ( & mut clock_account, 1 ) ;
486+
487+ // repeat 10 times to also make sure that price updates
488+ // make the publisher list sorted
489+ for slot in 1 ..10 {
490+ for ( i, publisher) in publishers. iter ( ) . enumerate ( ) {
491+ println ! ( "{:} {:?}" , i, publisher. key) ;
492+ populate_instruction ( & mut instruction_data, ( i + 100 ) as i64 , 10 , slot) ;
493+ process_instruction (
494+ & program_id,
495+ & [
496+ publisher. clone ( ) ,
497+ price_account. clone ( ) ,
498+ clock_account. clone ( ) ,
499+ ] ,
500+ & instruction_data,
501+ ) ?;
502+ }
503+
504+ update_clock_slot ( & mut clock_account, slot + 1 ) ;
505+ }
506+
507+ {
508+ let price_data = load_checked :: < PriceAccount > ( & price_account, PC_VERSION ) . unwrap ( ) ;
509+
510+ // Check publishers are sorted
511+ let price_data_pubs: Vec < _ > = price_data. comp_ [ ..20 ] . iter ( ) . map ( |c| c. pub_ ) . collect ( ) ;
512+ assert_eq ! (
513+ price_data_pubs,
514+ publishers. iter( ) . map( |p| * p. key) . collect:: <Vec <_>>( )
515+ ) ;
516+
517+ assert_eq ! ( price_data. comp_[ 0 ] . latest_. price_, 100 ) ;
518+ assert_eq ! ( price_data. comp_[ 0 ] . latest_. conf_, 10 ) ;
519+ assert_eq ! ( price_data. comp_[ 0 ] . latest_. pub_slot_, 9 ) ;
520+ assert_eq ! ( price_data. comp_[ 0 ] . latest_. status_, PC_STATUS_TRADING ) ;
521+ // aggregate is calculated at slot 9 for up to slot 8
522+ assert_eq ! ( price_data. valid_slot_, 8 ) ;
523+ assert_eq ! ( price_data. agg_. pub_slot_, 9 ) ;
524+ assert_eq ! ( price_data. agg_. price_, 109 ) ;
525+ assert_eq ! ( price_data. agg_. conf_, 8 ) ;
526+ assert_eq ! ( price_data. agg_. status_, PC_STATUS_TRADING ) ;
527+ }
528+ Ok ( ( ) )
529+ }
530+
447531// Create an upd_price instruction with the provided parameters
448532fn populate_instruction ( instruction_data : & mut [ u8 ] , price : i64 , conf : u64 , pub_slot : u64 ) {
449533 let mut cmd = load_mut :: < UpdPriceArgs > ( instruction_data) . unwrap ( ) ;
0 commit comments