@@ -444,6 +444,88 @@ fn test_upd_price_v2() -> Result<(), Box<dyn std::error::Error>> {
444
444
Ok ( ( ) )
445
445
}
446
446
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
+
447
529
// Create an upd_price instruction with the provided parameters
448
530
fn populate_instruction ( instruction_data : & mut [ u8 ] , price : i64 , conf : u64 , pub_slot : u64 ) {
449
531
let mut cmd = load_mut :: < UpdPriceArgs > ( instruction_data) . unwrap ( ) ;
0 commit comments