@@ -444,6 +444,90 @@ 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
+ 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
+
447
531
// Create an upd_price instruction with the provided parameters
448
532
fn populate_instruction ( instruction_data : & mut [ u8 ] , price : i64 , conf : u64 , pub_slot : u64 ) {
449
533
let mut cmd = load_mut :: < UpdPriceArgs > ( instruction_data) . unwrap ( ) ;
0 commit comments