Skip to content

Commit ac12a50

Browse files
jayantkJayant KrishnamurthyJayant Krishnamurthytompntn
authored
Filter out publisher quotes with wide CIs (#166)
* add ci filter to upd_price * update logic * fix comment * update test * update test * fix tests * fix tests * Update pyth/tests/test_update_price.py accept pr comment Co-authored-by: Tom Pointon <tom@teepeestudios.net> Co-authored-by: Jayant Krishnamurthy <jkrishnamurthy@jumptrading.com> Co-authored-by: Jayant Krishnamurthy <jayant@jumpcrypto.com> Co-authored-by: Tom Pointon <tom@teepeestudios.net>
1 parent 1f35e62 commit ac12a50

File tree

5 files changed

+54
-12
lines changed

5 files changed

+54
-12
lines changed

program/src/oracle/oracle.c

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
#include "upd_aggregate.h"
77

88
// Returns the minimum number of lamports required to make an account
9-
// with dlen bytes of data rent exempt. These values were calculated
9+
// with dlen bytes of data rent exempt. These values were calculated
1010
// using the getMinimumBalanceForRentExemption RPC call, and are
1111
// guaranteed never to increase.
1212
static uint64_t rent_exempt_amount( uint64_t dlen )
@@ -561,9 +561,21 @@ static uint64_t upd_price( SolParameters *prm, SolAccountInfo *ka )
561561

562562
// update component price if required
563563
if ( cptr->cmd_ == e_cmd_upd_price || cptr->cmd_ == e_cmd_upd_price_no_fail_on_error ) {
564+
uint32_t status = cptr->status_;
565+
566+
// Set publisher's status to unknown unless their CI is sufficiently tight.
567+
int64_t threshold_conf = (cptr->price_ / PC_MAX_CI_DIVISOR);
568+
if (threshold_conf < 0) {
569+
// Safe as long as threshold_conf isn't the min int64, which it isn't as long as PC_MAX_CI_DIVISOR > 1.
570+
threshold_conf = -threshold_conf;
571+
}
572+
if ( cptr->conf_ > (uint64_t) threshold_conf ) {
573+
status = PC_STATUS_UNKNOWN;
574+
}
575+
564576
fptr->price_ = cptr->price_;
565577
fptr->conf_ = cptr->conf_;
566-
fptr->status_ = cptr->status_;
578+
fptr->status_ = status;
567579
fptr->pub_slot_ = cptr->pub_slot_;
568580
}
569581
return SUCCESS;

program/src/oracle/oracle.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ extern "C" {
2323
#define PC_MAX_NUM_DECIMALS 16
2424
#define PC_PROD_ACC_SIZE 512
2525
#define PC_EXP_DECAY -9
26+
// If ci > price / PC_MAX_CI_DIVISOR, set publisher status to unknown.
27+
// (e.g., 20 means ci must be < 5% of price)
28+
#define PC_MAX_CI_DIVISOR 20
2629

2730
#ifndef PC_HEAP_START
2831
#define PC_HEAP_START (0x300000000)

program/src/oracle/test_oracle.c

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,7 @@ Test( oracle, add_publisher ) {
303303

304304
// Now give the price account enough lamports to be rent exempt
305305
acc[1].lamports = &PRICE_ACCOUNT_LAMPORTS;
306-
306+
307307
cr_assert( SUCCESS == dispatch( &prm, acc ) );
308308
cr_assert( sptr->num_ == 1 );
309309
cr_assert( pc_pub_key_equal( &idata.pub_, &sptr->comp_[0].pub_ ) );
@@ -348,7 +348,7 @@ Test(oracle, pc_size ) {
348348
}
349349

350350
Test( oracle, upd_test ) {
351-
351+
352352
// Initialize the test account
353353
SolPubkey p_id = {.x = { 0xff, }};
354354
SolPubkey pkey = {.x = { 1, }};
@@ -416,7 +416,7 @@ Test( oracle, upd_price ) {
416416
.cmd_ = e_cmd_upd_price,
417417
.status_ = PC_STATUS_TRADING,
418418
.price_ = 42L,
419-
.conf_ = 9L,
419+
.conf_ = 2L,
420420
.pub_slot_ = 1
421421
};
422422
SolPubkey p_id = {.x = { 0xff, }};
@@ -474,7 +474,7 @@ Test( oracle, upd_price ) {
474474
};
475475
cr_assert( SUCCESS == dispatch( &prm, acc ) );
476476
cr_assert( sptr->comp_[0].latest_.price_ == 42L );
477-
cr_assert( sptr->comp_[0].latest_.conf_ == 9L );
477+
cr_assert( sptr->comp_[0].latest_.conf_ == 2L );
478478
cr_assert( sptr->comp_[0].latest_.pub_slot_ == 1 );
479479
cr_assert( sptr->agg_.pub_slot_ == 1 );
480480
cr_assert( sptr->valid_slot_ == 0 );
@@ -519,6 +519,30 @@ Test( oracle, upd_price ) {
519519
// try to publish back-in-time
520520
idata.pub_slot_ = 1;
521521
cr_assert( ERROR_INVALID_ARGUMENT == dispatch( &prm, acc ) );
522+
523+
524+
// Publishing a wide CI results in a status of unknown.
525+
526+
// check that someone doesn't accidentally break the test.
527+
cr_assert(sptr->comp_[0].latest_.status_ == PC_STATUS_TRADING);
528+
idata.pub_slot_ = 5;
529+
cvar.slot_ = 6;
530+
idata.price_ = 50;
531+
idata.conf_ = 6;
532+
cr_assert( SUCCESS == dispatch( &prm, acc ) );
533+
cr_assert( sptr->comp_[0].latest_.price_ == 50L );
534+
cr_assert( sptr->comp_[0].latest_.conf_ == 6L );
535+
cr_assert( sptr->comp_[0].latest_.status_ == PC_STATUS_UNKNOWN );
536+
cr_assert( sptr->comp_[0].latest_.pub_slot_ == 5 );
537+
cr_assert( sptr->agg_.pub_slot_ == 6 );
538+
// Aggregate is still trading because it uses price from previous slot
539+
cr_assert( sptr->agg_.status_ == PC_STATUS_TRADING );
540+
541+
// Crank one more time and aggregate should be unknown
542+
idata.pub_slot_ = 6;
543+
cvar.slot_ = 7;
544+
cr_assert( SUCCESS == dispatch( &prm, acc ) );
545+
cr_assert( sptr->agg_.status_ == PC_STATUS_UNKNOWN );
522546
}
523547

524548
Test( oracle, upd_price_no_fail_on_error ) {
@@ -544,7 +568,7 @@ Test( oracle, upd_price_no_fail_on_error ) {
544568
sptr->ptype_ = PC_PTYPE_PRICE;
545569
sptr->type_ = PC_ACCTYPE_PRICE;
546570
sptr->num_ = 1;
547-
571+
548572
SolAccountInfo acc[] = {{
549573
.key = &pkey,
550574
.lamports = &pqty,
@@ -592,7 +616,7 @@ Test( oracle, upd_price_no_fail_on_error ) {
592616
cr_assert( sptr->comp_[0].latest_.conf_ == 0L );
593617
cr_assert( sptr->comp_[0].latest_.pub_slot_ == 0 );
594618
cr_assert( sptr->agg_.pub_slot_ == 0 );
595-
cr_assert( sptr->valid_slot_ == 0 );
619+
cr_assert( sptr->valid_slot_ == 0 );
596620

597621
// Now permission the publish account for the price account.
598622
pc_pub_key_assign( &sptr->comp_[0].pub_, (pc_pub_key_t*)&pkey );
@@ -605,7 +629,7 @@ Test( oracle, upd_price_no_fail_on_error ) {
605629
cr_assert( sptr->agg_.pub_slot_ == 1 );
606630
cr_assert( sptr->valid_slot_ == 0 );
607631

608-
// Invalid updates, such as publishing an update for the current slot,
632+
// Invalid updates, such as publishing an update for the current slot,
609633
// should still fail silently and have no effect.
610634
idata.price_ = 55L;
611635
idata.conf_ = 22L;

pyth/tests/test_publish.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ def get_price_acct():
2828
cmd = [
2929
'pyth', 'upd_price_val',
3030
pyth_init_price['LTC'],
31-
'150', '10', 'trading',
31+
'150', '7', 'trading',
3232
'-r', 'localhost',
3333
'-k', pyth_dir,
3434
'-c', 'finalized',
@@ -52,5 +52,5 @@ def get_price_acct():
5252

5353
after = get_price_acct()
5454
assert after['publisher_accounts'][0]['price'] == 150
55-
assert after['publisher_accounts'][0]['conf'] == 10
55+
assert after['publisher_accounts'][0]['conf'] == 7
5656
assert after['publisher_accounts'][0]['status'] == 'trading'

pyth/tests/test_update_price.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,4 +115,7 @@ def get_publisher_acc(product_acc):
115115

116116
assert publisher_acc['price'] == new_values[product]['price']
117117
assert publisher_acc['conf'] == new_values[product]['conf']
118-
assert publisher_acc['status'] == new_values[product]['status']
118+
119+
conf_threshold = new_values[product]['price'] / 20
120+
expected_status = 'unknown' if new_values[product]['conf'] > conf_threshold else 'trading'
121+
assert publisher_acc['status'] == expected_status

0 commit comments

Comments
 (0)