@@ -88,6 +88,9 @@ fn test_upd_price() {
88
88
assert_eq ! ( price_data. prev_price_, 0 ) ;
89
89
assert_eq ! ( price_data. prev_conf_, 0 ) ;
90
90
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 ) ;
91
94
}
92
95
93
96
// add some prices for current slot - get rejected
@@ -121,6 +124,9 @@ fn test_upd_price() {
121
124
assert_eq ! ( price_data. prev_price_, 0 ) ;
122
125
assert_eq ! ( price_data. prev_conf_, 0 ) ;
123
126
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 ) ;
124
130
}
125
131
126
132
// update new price in new slot, aggregate should be updated and prev values should be updated
@@ -153,6 +159,9 @@ fn test_upd_price() {
153
159
assert_eq ! ( price_data. prev_price_, 42 ) ;
154
160
assert_eq ! ( price_data. prev_conf_, 2 ) ;
155
161
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 ) ;
156
165
}
157
166
158
167
// next price doesn't change but slot and timestamp does
@@ -186,6 +195,9 @@ fn test_upd_price() {
186
195
assert_eq ! ( price_data. prev_conf_, 2 ) ;
187
196
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
188
197
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 ) ;
189
201
}
190
202
191
203
// next price doesn't change and neither does aggregate but slot does
@@ -217,6 +229,9 @@ fn test_upd_price() {
217
229
assert_eq ! ( price_data. prev_price_, 81 ) ;
218
230
assert_eq ! ( price_data. prev_conf_, 2 ) ;
219
231
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 ) ;
220
235
}
221
236
222
237
// try to publish back-in-time
@@ -250,6 +265,9 @@ fn test_upd_price() {
250
265
assert_eq ! ( price_data. prev_price_, 81 ) ;
251
266
assert_eq ! ( price_data. prev_conf_, 2 ) ;
252
267
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 ) ;
253
271
}
254
272
255
273
populate_instruction ( & mut instruction_data, 50 , 20 , 5 ) ;
@@ -289,6 +307,9 @@ fn test_upd_price() {
289
307
assert_eq ! ( price_data. prev_price_, 81 ) ;
290
308
assert_eq ! ( price_data. prev_conf_, 2 ) ;
291
309
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 ) ;
292
313
}
293
314
294
315
// Negative prices are accepted
@@ -320,13 +341,16 @@ fn test_upd_price() {
320
341
assert_eq ! ( price_data. prev_price_, 81 ) ;
321
342
assert_eq ! ( price_data. prev_conf_, 2 ) ;
322
343
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 ) ;
323
347
}
324
348
325
349
// 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
326
350
let mut funding_setup_two = AccountSetup :: new_funding ( ) ;
327
351
let funding_account_two = funding_setup_two. as_account_info ( ) ;
328
352
329
- add_publisher ( & mut price_account, funding_account_two. key , 1 ) ;
353
+ add_publisher ( & mut price_account, funding_account_two. key ) ;
330
354
331
355
populate_instruction ( & mut instruction_data, 10 , 1 , 10 ) ;
332
356
update_clock_slot ( & mut clock_account, 10 ) ;
@@ -359,7 +383,12 @@ fn test_upd_price() {
359
383
assert_eq ! ( price_data. prev_timestamp_, 4 ) ;
360
384
assert_eq ! ( price_data. twap_. numer_, 1677311098 ) ;
361
385
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 ) ;
363
392
}
364
393
365
394
// 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() {
396
425
assert_eq ! ( price_data. prev_timestamp_, 4 ) ;
397
426
assert_eq ! ( price_data. twap_. numer_, 1677311098 ) ; // twap_.numer_ should not be updated
398
427
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
400
533
}
401
534
}
402
535
@@ -411,8 +544,16 @@ fn populate_instruction(instruction_data: &mut [u8], price: i64, conf: u64, pub_
411
544
cmd. unused_ = 0 ;
412
545
}
413
546
414
- fn add_publisher ( price_account : & mut AccountInfo , publisher_key : & Pubkey , index : usize ) {
547
+ fn add_publisher ( price_account : & mut AccountInfo , publisher_key : & Pubkey ) {
415
548
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 ;
417
550
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
+ }
418
559
}
0 commit comments