@@ -88,6 +88,9 @@ fn test_upd_price() {
8888 assert_eq ! ( price_data. prev_price_, 0 ) ;
8989 assert_eq ! ( price_data. prev_conf_, 0 ) ;
9090 assert_eq ! ( price_data. prev_timestamp_, 0 ) ;
91+ assert_eq ! ( price_data. price_cumulative. price, 42 ) ;
92+ assert_eq ! ( price_data. price_cumulative. conf, 2 ) ;
93+ assert_eq ! ( price_data. price_cumulative. num_down_slots, 0 ) ;
9194 }
9295
9396 // add some prices for current slot - get rejected
@@ -121,6 +124,9 @@ fn test_upd_price() {
121124 assert_eq ! ( price_data. prev_price_, 0 ) ;
122125 assert_eq ! ( price_data. prev_conf_, 0 ) ;
123126 assert_eq ! ( price_data. prev_timestamp_, 0 ) ;
127+ assert_eq ! ( price_data. price_cumulative. price, 42 ) ;
128+ assert_eq ! ( price_data. price_cumulative. conf, 2 ) ;
129+ assert_eq ! ( price_data. price_cumulative. num_down_slots, 0 ) ;
124130 }
125131
126132 // update new price in new slot, aggregate should be updated and prev values should be updated
@@ -153,6 +159,9 @@ fn test_upd_price() {
153159 assert_eq ! ( price_data. prev_price_, 42 ) ;
154160 assert_eq ! ( price_data. prev_conf_, 2 ) ;
155161 assert_eq ! ( price_data. prev_timestamp_, 1 ) ;
162+ assert_eq ! ( price_data. price_cumulative. price, 42 + 2 * 81 ) ;
163+ assert_eq ! ( price_data. price_cumulative. conf, 3 * 2 ) ;
164+ assert_eq ! ( price_data. price_cumulative. num_down_slots, 0 ) ;
156165 }
157166
158167 // next price doesn't change but slot and timestamp does
@@ -186,6 +195,9 @@ fn test_upd_price() {
186195 assert_eq ! ( price_data. prev_conf_, 2 ) ;
187196 assert_eq ! ( price_data. timestamp_, 4 ) ; // We only check for timestamp_ here because test_upd_price doesn't directly update timestamp_, this is updated through c_upd_aggregate which is tested in test_upd_aggregate, but we assert here to show that in subsequent asserts for prev_timestamp_ the value should be updated to this value
188197 assert_eq ! ( price_data. prev_timestamp_, 1 ) ;
198+ assert_eq ! ( price_data. price_cumulative. price, 42 + 3 * 81 ) ;
199+ assert_eq ! ( price_data. price_cumulative. conf, 4 * 2 ) ;
200+ assert_eq ! ( price_data. price_cumulative. num_down_slots, 0 ) ;
189201 }
190202
191203 // next price doesn't change and neither does aggregate but slot does
@@ -217,6 +229,9 @@ fn test_upd_price() {
217229 assert_eq ! ( price_data. prev_price_, 81 ) ;
218230 assert_eq ! ( price_data. prev_conf_, 2 ) ;
219231 assert_eq ! ( price_data. prev_timestamp_, 4 ) ;
232+ assert_eq ! ( price_data. price_cumulative. price, 42 + 81 * 4 ) ;
233+ assert_eq ! ( price_data. price_cumulative. conf, 5 * 2 ) ;
234+ assert_eq ! ( price_data. price_cumulative. num_down_slots, 0 ) ;
220235 }
221236
222237 // try to publish back-in-time
@@ -250,6 +265,9 @@ fn test_upd_price() {
250265 assert_eq ! ( price_data. prev_price_, 81 ) ;
251266 assert_eq ! ( price_data. prev_conf_, 2 ) ;
252267 assert_eq ! ( price_data. prev_timestamp_, 4 ) ;
268+ assert_eq ! ( price_data. price_cumulative. price, 42 + 81 * 4 ) ;
269+ assert_eq ! ( price_data. price_cumulative. conf, 5 * 2 ) ;
270+ assert_eq ! ( price_data. price_cumulative. num_down_slots, 0 ) ;
253271 }
254272
255273 populate_instruction ( & mut instruction_data, 50 , 20 , 5 ) ;
@@ -289,6 +307,9 @@ fn test_upd_price() {
289307 assert_eq ! ( price_data. prev_price_, 81 ) ;
290308 assert_eq ! ( price_data. prev_conf_, 2 ) ;
291309 assert_eq ! ( price_data. prev_timestamp_, 4 ) ;
310+ assert_eq ! ( price_data. price_cumulative. price, 42 + 81 * 4 ) ;
311+ assert_eq ! ( price_data. price_cumulative. conf, 2 * 5 ) ;
312+ assert_eq ! ( price_data. price_cumulative. num_down_slots, 0 ) ;
292313 }
293314
294315 // Negative prices are accepted
@@ -320,13 +341,16 @@ fn test_upd_price() {
320341 assert_eq ! ( price_data. prev_price_, 81 ) ;
321342 assert_eq ! ( price_data. prev_conf_, 2 ) ;
322343 assert_eq ! ( price_data. prev_timestamp_, 4 ) ;
344+ assert_eq ! ( price_data. price_cumulative. price, 42 + 81 * 4 - 100 * 3 ) ;
345+ assert_eq ! ( price_data. price_cumulative. conf, 2 * 5 + 3 ) ; // 2 * 5 + 1 * 3
346+ assert_eq ! ( price_data. price_cumulative. num_down_slots, 0 ) ;
323347 }
324348
325349 // add new test for multiple publishers and ensure that agg price is not updated multiple times when program upgrade happens in the same slot after the first update
326350 let mut funding_setup_two = AccountSetup :: new_funding ( ) ;
327351 let funding_account_two = funding_setup_two. as_account_info ( ) ;
328352
329- add_publisher ( & mut price_account, funding_account_two. key , 1 ) ;
353+ add_publisher ( & mut price_account, funding_account_two. key ) ;
330354
331355 populate_instruction ( & mut instruction_data, 10 , 1 , 10 ) ;
332356 update_clock_slot ( & mut clock_account, 10 ) ;
@@ -359,7 +383,12 @@ fn test_upd_price() {
359383 assert_eq ! ( price_data. prev_timestamp_, 4 ) ;
360384 assert_eq ! ( price_data. twap_. numer_, 1677311098 ) ;
361385 assert_eq ! ( price_data. twap_. denom_, 1279419481 ) ;
362- assert_eq ! ( price_data. price_cumulative. price, 86 ) ;
386+ assert_eq ! (
387+ price_data. price_cumulative. price,
388+ 42 + 81 * 4 - 100 * 3 + 10 * 2
389+ ) ;
390+ assert_eq ! ( price_data. price_cumulative. conf, 2 * 5 + 5 ) ; // 2 * 5 + 1 * 5
391+ assert_eq ! ( price_data. price_cumulative. num_down_slots, 0 ) ;
363392 }
364393
365394 // reset twap_.denom_ to 0 to simulate program upgrade in the same slot and make sure agg_.price_ is not updated again
@@ -396,7 +425,111 @@ fn test_upd_price() {
396425 assert_eq ! ( price_data. prev_timestamp_, 4 ) ;
397426 assert_eq ! ( price_data. twap_. numer_, 1677311098 ) ; // twap_.numer_ should not be updated
398427 assert_eq ! ( price_data. twap_. denom_, 1279419481 ) ; // twap_.denom_ should not be updated
399- assert_eq ! ( price_data. price_cumulative. price, 86 ) ; // price_cumulative should not be updated
428+
429+ // price_cumulative should not be updated
430+ assert_eq ! (
431+ price_data. price_cumulative. price,
432+ 42 + 81 * 4 - 100 * 3 + 10 * 2
433+ ) ;
434+ assert_eq ! ( price_data. price_cumulative. conf, 2 * 5 + 5 ) ;
435+ assert_eq ! ( price_data. price_cumulative. num_down_slots, 0 ) ;
436+ }
437+
438+ remove_publisher ( & mut price_account) ;
439+ // Big gap
440+ populate_instruction ( & mut instruction_data, 60 , 4 , 50 ) ;
441+ update_clock_slot ( & mut clock_account, 50 ) ;
442+
443+ assert ! ( process_instruction(
444+ & program_id,
445+ & [
446+ funding_account. clone( ) ,
447+ price_account. clone( ) ,
448+ clock_account. clone( )
449+ ] ,
450+ & instruction_data
451+ )
452+ . is_ok( ) ) ;
453+
454+ {
455+ let price_data = load_checked :: < PriceAccount > ( & price_account, PC_VERSION ) . unwrap ( ) ;
456+ assert_eq ! ( price_data. comp_[ 0 ] . latest_. price_, 60 ) ;
457+ assert_eq ! ( price_data. comp_[ 0 ] . latest_. conf_, 4 ) ;
458+ assert_eq ! ( price_data. comp_[ 0 ] . latest_. pub_slot_, 50 ) ;
459+ assert_eq ! ( price_data. comp_[ 0 ] . latest_. status_, PC_STATUS_TRADING ) ;
460+ assert_eq ! ( price_data. valid_slot_, 10 ) ;
461+ assert_eq ! ( price_data. agg_. pub_slot_, 50 ) ;
462+ assert_eq ! ( price_data. agg_. price_, 60 ) ;
463+ assert_eq ! ( price_data. agg_. conf_, 4 ) ;
464+ assert_eq ! ( price_data. agg_. status_, PC_STATUS_TRADING ) ;
465+ assert_eq ! (
466+ price_data. price_cumulative. price,
467+ 42 + 81 * 4 - 100 * 3 + 10 * 2 + 60 * 40
468+ ) ;
469+ assert_eq ! ( price_data. price_cumulative. conf, 2 * 5 + 5 + 40 * 4 ) ;
470+ assert_eq ! ( price_data. price_cumulative. num_down_slots, 15 ) ;
471+ }
472+
473+ // add new test for multiple publishers and ensure that price_cumulative is updated correctly
474+ add_publisher ( & mut price_account, funding_account_two. key ) ;
475+ populate_instruction ( & mut instruction_data, 10 , 1 , 100 ) ;
476+ update_clock_slot ( & mut clock_account, 100 ) ;
477+ assert ! ( process_instruction(
478+ & program_id,
479+ & [
480+ funding_account. clone( ) ,
481+ price_account. clone( ) ,
482+ clock_account. clone( )
483+ ] ,
484+ & instruction_data
485+ )
486+ . is_ok( ) ) ;
487+
488+ populate_instruction ( & mut instruction_data, 20 , 2 , 100 ) ;
489+ assert ! ( process_instruction(
490+ & program_id,
491+ & [
492+ funding_account_two. clone( ) ,
493+ price_account. clone( ) ,
494+ clock_account. clone( )
495+ ] ,
496+ & instruction_data
497+ )
498+ . is_ok( ) ) ;
499+
500+ {
501+ let price_data = load_checked :: < PriceAccount > ( & price_account, PC_VERSION ) . unwrap ( ) ;
502+ assert_eq ! ( price_data. comp_[ 0 ] . latest_. price_, 10 ) ;
503+ assert_eq ! ( price_data. comp_[ 0 ] . latest_. conf_, 1 ) ;
504+ assert_eq ! ( price_data. comp_[ 0 ] . latest_. pub_slot_, 100 ) ;
505+ assert_eq ! ( price_data. comp_[ 0 ] . latest_. status_, PC_STATUS_TRADING ) ;
506+ assert_eq ! ( price_data. comp_[ 1 ] . latest_. price_, 20 ) ;
507+ assert_eq ! ( price_data. comp_[ 1 ] . latest_. conf_, 2 ) ;
508+ assert_eq ! ( price_data. comp_[ 1 ] . latest_. pub_slot_, 100 ) ;
509+ assert_eq ! ( price_data. comp_[ 1 ] . latest_. status_, PC_STATUS_TRADING ) ;
510+ assert_eq ! ( price_data. valid_slot_, 100 ) ;
511+ assert_eq ! ( price_data. agg_. pub_slot_, 100 ) ;
512+ assert_eq ! ( price_data. agg_. price_, 14 ) ;
513+ assert_eq ! ( price_data. agg_. conf_, 6 ) ;
514+ assert_eq ! ( price_data. agg_. status_, PC_STATUS_TRADING ) ;
515+ assert_eq ! ( price_data. prev_slot_, 50 ) ;
516+ assert_eq ! ( price_data. prev_price_, 60 ) ;
517+ assert_eq ! ( price_data. prev_conf_, 4 ) ;
518+ assert_eq ! (
519+ price_data. prev_price_cumulative. price,
520+ 42 + 81 * 4 - 100 * 3 + 10 * 2 + 60 * 40
521+ ) ;
522+ assert_eq ! ( price_data. prev_price_cumulative. conf, 2 * 5 + 5 + 40 * 4 ) ;
523+ assert_eq ! ( price_data. prev_price_cumulative. num_down_slots, 15 ) ;
524+ assert_eq ! (
525+ price_data. price_cumulative. price,
526+ 42 + 81 * 4 - 100 * 3 + 10 * 2 + 60 * 40 + 14 * 50
527+ ) ; // (42 + 81 * 4 - 100 * 3 + 10 * 2 + 60 * 40 + 55) is the price cumulative from the previous test and 14 * 49 (slot_gap) is the price cumulative from this test
528+ assert_eq ! (
529+ price_data. price_cumulative. conf,
530+ 2 * 5 + 5 + 40 * 4 + 6 * 50
531+ ) ;
532+ assert_eq ! ( price_data. price_cumulative. num_down_slots, 40 ) ; // prev num_down_slots was 15 and since pub slot is 100 and last pub slot was 50, slot_gap is 50 and default latency is 25, so num_down_slots = 50 - 25 = 25, so total num_down_slots = 15 + 25 = 40
400533 }
401534}
402535
@@ -411,8 +544,16 @@ fn populate_instruction(instruction_data: &mut [u8], price: i64, conf: u64, pub_
411544 cmd. unused_ = 0 ;
412545}
413546
414- fn add_publisher ( price_account : & mut AccountInfo , publisher_key : & Pubkey , index : usize ) {
547+ fn add_publisher ( price_account : & mut AccountInfo , publisher_key : & Pubkey ) {
415548 let mut price_data = load_checked :: < PriceAccount > ( price_account, PC_VERSION ) . unwrap ( ) ;
416- price_data . num_ = ( index + 1 ) as u32 ;
549+ let index = price_data . num_ as usize ;
417550 price_data. comp_ [ index] . pub_ = * publisher_key;
551+ price_data. num_ += 1 ;
552+ }
553+
554+ fn remove_publisher ( price_account : & mut AccountInfo ) {
555+ let mut price_data = load_checked :: < PriceAccount > ( price_account, PC_VERSION ) . unwrap ( ) ;
556+ if price_data. num_ > 0 {
557+ price_data. num_ -= 1 ;
558+ }
418559}
0 commit comments