Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Filter out publisher quotes with wide CIs #166

Merged
merged 8 commits into from
Apr 29, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions program/src/oracle/oracle.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
#include "upd_aggregate.h"

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

// update component price if required
if ( cptr->cmd_ == e_cmd_upd_price || cptr->cmd_ == e_cmd_upd_price_no_fail_on_error ) {
uint32_t status = cptr->status_;

// Set publisher's status to unknown unless their CI is sufficiently tight.
int64_t threshold_conf = (cptr->price_ / PC_MAX_CI_DIVISOR);
if (threshold_conf < 0) {
// Safe as long as threshold_conf isn't the min int64, which it isn't as long as PC_MAX_CI_DIVISOR > 1.
threshold_conf = -threshold_conf;
}
if ( cptr->conf_ > (uint64_t) threshold_conf ) {
status = PC_STATUS_UNKNOWN;
}

fptr->price_ = cptr->price_;
fptr->conf_ = cptr->conf_;
fptr->status_ = cptr->status_;
fptr->status_ = status;
fptr->pub_slot_ = cptr->pub_slot_;
}
return SUCCESS;
Expand Down
3 changes: 3 additions & 0 deletions program/src/oracle/oracle.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ extern "C" {
#define PC_MAX_NUM_DECIMALS 16
#define PC_PROD_ACC_SIZE 512
#define PC_EXP_DECAY -9
// If ci > price / PC_MAX_CI_DIVISOR, set publisher status to unknown.
// (e.g., 20 means ci must be < 5% of price)
#define PC_MAX_CI_DIVISOR 20

#ifndef PC_HEAP_START
#define PC_HEAP_START (0x300000000)
Expand Down
38 changes: 31 additions & 7 deletions program/src/oracle/test_oracle.c
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ Test( oracle, add_publisher ) {

// Now give the price account enough lamports to be rent exempt
acc[1].lamports = &PRICE_ACCOUNT_LAMPORTS;

cr_assert( SUCCESS == dispatch( &prm, acc ) );
cr_assert( sptr->num_ == 1 );
cr_assert( pc_pub_key_equal( &idata.pub_, &sptr->comp_[0].pub_ ) );
Expand Down Expand Up @@ -348,7 +348,7 @@ Test(oracle, pc_size ) {
}

Test( oracle, upd_test ) {

// Initialize the test account
SolPubkey p_id = {.x = { 0xff, }};
SolPubkey pkey = {.x = { 1, }};
Expand Down Expand Up @@ -416,7 +416,7 @@ Test( oracle, upd_price ) {
.cmd_ = e_cmd_upd_price,
.status_ = PC_STATUS_TRADING,
.price_ = 42L,
.conf_ = 9L,
.conf_ = 2L,
.pub_slot_ = 1
};
SolPubkey p_id = {.x = { 0xff, }};
Expand Down Expand Up @@ -474,7 +474,7 @@ Test( oracle, upd_price ) {
};
cr_assert( SUCCESS == dispatch( &prm, acc ) );
cr_assert( sptr->comp_[0].latest_.price_ == 42L );
cr_assert( sptr->comp_[0].latest_.conf_ == 9L );
cr_assert( sptr->comp_[0].latest_.conf_ == 2L );
cr_assert( sptr->comp_[0].latest_.pub_slot_ == 1 );
cr_assert( sptr->agg_.pub_slot_ == 1 );
cr_assert( sptr->valid_slot_ == 0 );
Expand Down Expand Up @@ -519,6 +519,30 @@ Test( oracle, upd_price ) {
// try to publish back-in-time
idata.pub_slot_ = 1;
cr_assert( ERROR_INVALID_ARGUMENT == dispatch( &prm, acc ) );


// Publishing a wide CI results in a status of unknown.

// check that someone doesn't accidentally break the test.
cr_assert(sptr->comp_[0].latest_.status_ == PC_STATUS_TRADING);
idata.pub_slot_ = 5;
cvar.slot_ = 6;
idata.price_ = 50;
idata.conf_ = 6;
cr_assert( SUCCESS == dispatch( &prm, acc ) );
cr_assert( sptr->comp_[0].latest_.price_ == 50L );
cr_assert( sptr->comp_[0].latest_.conf_ == 6L );
cr_assert( sptr->comp_[0].latest_.status_ == PC_STATUS_UNKNOWN );
cr_assert( sptr->comp_[0].latest_.pub_slot_ == 5 );
cr_assert( sptr->agg_.pub_slot_ == 6 );
// Aggregate is still trading because it uses price from previous slot
cr_assert( sptr->agg_.status_ == PC_STATUS_TRADING );

// Crank one more time and aggregate should be unknown
idata.pub_slot_ = 6;
cvar.slot_ = 7;
cr_assert( SUCCESS == dispatch( &prm, acc ) );
cr_assert( sptr->agg_.status_ == PC_STATUS_UNKNOWN );
}

Test( oracle, upd_price_no_fail_on_error ) {
Expand All @@ -544,7 +568,7 @@ Test( oracle, upd_price_no_fail_on_error ) {
sptr->ptype_ = PC_PTYPE_PRICE;
sptr->type_ = PC_ACCTYPE_PRICE;
sptr->num_ = 1;

SolAccountInfo acc[] = {{
.key = &pkey,
.lamports = &pqty,
Expand Down Expand Up @@ -592,7 +616,7 @@ Test( oracle, upd_price_no_fail_on_error ) {
cr_assert( sptr->comp_[0].latest_.conf_ == 0L );
cr_assert( sptr->comp_[0].latest_.pub_slot_ == 0 );
cr_assert( sptr->agg_.pub_slot_ == 0 );
cr_assert( sptr->valid_slot_ == 0 );
cr_assert( sptr->valid_slot_ == 0 );

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

// Invalid updates, such as publishing an update for the current slot,
// Invalid updates, such as publishing an update for the current slot,
// should still fail silently and have no effect.
idata.price_ = 55L;
idata.conf_ = 22L;
Expand Down
4 changes: 2 additions & 2 deletions pyth/tests/test_publish.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ def get_price_acct():
cmd = [
'pyth', 'upd_price_val',
pyth_init_price['LTC'],
'150', '10', 'trading',
'150', '7', 'trading',
'-r', 'localhost',
'-k', pyth_dir,
'-c', 'finalized',
Expand All @@ -52,5 +52,5 @@ def get_price_acct():

after = get_price_acct()
assert after['publisher_accounts'][0]['price'] == 150
assert after['publisher_accounts'][0]['conf'] == 10
assert after['publisher_accounts'][0]['conf'] == 7
assert after['publisher_accounts'][0]['status'] == 'trading'
5 changes: 4 additions & 1 deletion pyth/tests/test_update_price.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,4 +115,7 @@ def get_publisher_acc(product_acc):

assert publisher_acc['price'] == new_values[product]['price']
assert publisher_acc['conf'] == new_values[product]['conf']
assert publisher_acc['status'] == new_values[product]['status']

conf_threshold = new_values[product]['price'] / 20
expected_status = 'unknown' if new_values[product]['conf'] > conf_threshold else 'trading'
assert publisher_acc['status'] == expected_status